diff --git a/src/r_translation.c b/src/r_translation.c index d86f3ad9598f258c782a0d050c89dbead64213b6..d732f6b0834360aa831c5e569c3d8603afec6194 100644 --- a/src/r_translation.c +++ b/src/r_translation.c @@ -75,8 +75,7 @@ struct PaletteRemapParseResult } tint; }; - boolean has_error; - char error[4096]; + char *error; }; void PaletteRemap_Init(void) @@ -156,14 +155,6 @@ boolean PaletteRemap_IsIdentity(remaptable_t *tr) unsigned PaletteRemap_Add(remaptable_t *tr) { -#if 0 - for (unsigned i = 0; i < numpaletteremaps; i++) - { - if (PaletteRemap_Equal(tr, paletteremaps[i])) - return i; - } -#endif - numpaletteremaps++; paletteremaps = Z_Realloc(paletteremaps, sizeof(remaptable_t *) * numpaletteremaps, PU_STATIC, NULL); paletteremaps[numpaletteremaps - 1] = tr; @@ -453,15 +444,13 @@ struct ParsedTranslation static struct ParsedTranslation *parsedTranslationListHead = NULL; static struct ParsedTranslation *parsedTranslationListTail = NULL; -static void AddParsedTranslation(unsigned id, int base_translation, struct PaletteRemapParseResult *data) +static void AddParsedTranslation(remaptable_t *remap, remaptable_t *base_translation, struct PaletteRemapParseResult *data) { struct ParsedTranslation *node = Z_Calloc(sizeof(struct ParsedTranslation), PU_STATIC, NULL); - node->remap = paletteremaps[id]; + node->remap = remap; node->data = data; - - if (base_translation != -1) - node->baseTranslation = paletteremaps[base_translation]; + node->baseTranslation = base_translation; if (parsedTranslationListHead == NULL) parsedTranslationListHead = parsedTranslationListTail = node; @@ -511,12 +500,20 @@ void R_LoadParsedTranslations(void) struct ParsedTranslation *next = node->next; remaptable_t *tr = node->remap; - PaletteRemap_SetIdentity(tr); + if (tr) + { + if (tr->num_entries == 0) + { + tr->num_entries = NUM_PALETTE_ENTRIES; - if (node->baseTranslation) - memcpy(tr, node->baseTranslation, sizeof(remaptable_t)); + PaletteRemap_SetIdentity(tr); - PaletteRemap_ApplyResult(tr, result); + if (node->baseTranslation) + memcpy(tr, node->baseTranslation, sizeof(remaptable_t)); + } + + PaletteRemap_ApplyResult(tr, result); + } Z_Free(result); Z_Free(node); @@ -553,15 +550,17 @@ static boolean ParseDecimal(tokenizer_t *sc, double *out) static struct PaletteRemapParseResult *ThrowError(const char *format, ...) { + const size_t err_size = 512 * sizeof(char); + struct PaletteRemapParseResult *err = Z_Calloc(sizeof(struct PaletteRemapParseResult), PU_STATIC, NULL); + err->error = Z_Calloc(err_size, PU_STATIC, NULL); + va_list argptr; va_start(argptr, format); - vsnprintf(err->error, sizeof err->error, format, argptr); + vsnprintf(err->error, err_size, format, argptr); va_end(argptr); - err->has_error = true; - return err; } @@ -789,15 +788,119 @@ static struct PaletteRemapParseResult *PaletteRemap_ParseTranslation(const char return result; } +static void PrintError(const char *name, const char *format, ...) +{ + char error[256]; + + va_list argptr; + va_start(argptr, format); + vsnprintf(error, sizeof error, format, argptr); + va_end(argptr); + + CONS_Alert(CONS_ERROR, "Error parsing translation '%s': %s\n", name, error); +} + #define CHECK_EOF() \ if (!tkn) \ { \ - CONS_Alert(CONS_ERROR, "Error parsing translation '%s': Unexpected EOF\n", name); \ + PrintError(name, "Unexpected EOF"); \ goto fail; \ } +struct NewTranslation +{ + int id; + char *name; + char *base_translation_name; + struct PaletteRemapParseResult **results; + size_t num_results; +}; + +static void AddNewTranslation(struct NewTranslation **list_p, size_t *num, char *name, int id, char *base_translation_name, struct PaletteRemapParseResult *parse_result) +{ + struct NewTranslation *list = *list_p; + + size_t count = *num; + + for (size_t i = 0; i < count; i++) + { + struct NewTranslation *entry = &list[i]; + if (entry->id == id && strcmp(entry->name, name) == 0) + { + if (entry->base_translation_name && base_translation_name + && strcmp(entry->base_translation_name, base_translation_name) != 0) + continue; + entry->num_results++; + entry->results = Z_Realloc(entry->results, + entry->num_results * sizeof(struct PaletteRemapParseResult **), PU_STATIC, NULL); + entry->results[entry->num_results - 1] = parse_result; + return; + } + } + + size_t i = count; + + count++; + list = Z_Realloc(list, count * sizeof(struct NewTranslation), PU_STATIC, NULL); + + struct NewTranslation *entry = &list[i]; + entry->name = name; + entry->id = id; + entry->base_translation_name = base_translation_name; + entry->num_results = 1; + entry->results = Z_Realloc(entry->results, 1 * sizeof(struct PaletteRemapParseResult **), PU_STATIC, NULL); + entry->results[0] = parse_result; + + *list_p = list; + *num = count; +} + +static void PrepareNewTranslations(struct NewTranslation *list, size_t count) +{ + if (!list) + return; + + for (size_t i = 0; i < count; i++) + { + struct NewTranslation *entry = &list[i]; + + remaptable_t *tr = R_GetTranslationByID(entry->id); + if (tr == NULL) + { + tr = PaletteRemap_New(); + R_AddCustomTranslation(entry->name, PaletteRemap_Add(tr)); + } + + remaptable_t *base_translation = NULL; + char *base_translation_name = entry->base_translation_name; + if (base_translation_name) + { + int base_translation_id = R_FindCustomTranslation(base_translation_name); + if (base_translation_id == -1) + PrintError(entry->name, "No translation named '%s'", base_translation_name); + else + base_translation = R_GetTranslationByID(base_translation_id); + } + + // The translation is not generated until later, because the palette may not have been loaded. + // We store the result for when it's needed. + for (size_t j = 0; j < entry->num_results; j++) + AddParsedTranslation(tr, base_translation, entry->results[j]); + + tr->num_entries = 0; + + Z_Free(base_translation_name); + Z_Free(entry->results); + Z_Free(entry->name); + } + + Z_Free(list); +} + void R_ParseTrnslate(INT32 wadNum, UINT16 lumpnum) { + tokenizer_t *sc = NULL; + const char *tkn = NULL; char *lumpData = (char *)W_CacheLumpNumPwad(wadNum, lumpnum, PU_STATIC); size_t lumpLength = W_LumpLengthPwad(wadNum, lumpnum); char *text = (char *)Z_Malloc((lumpLength + 1), PU_STATIC, NULL); @@ -805,14 +908,18 @@ void R_ParseTrnslate(INT32 wadNum, UINT16 lumpnum) text[lumpLength] = '\0'; Z_Free(lumpData); - tokenizer_t *sc = Tokenizer_Open(text, 1); - const char *tkn = sc->get(sc, 0); + sc = Tokenizer_Open(text, 1); + tkn = sc->get(sc, 0); + + struct NewTranslation *list = NULL; + size_t list_count = 0; + while (tkn != NULL) { - int base_translation = -1; - char *name = Z_StrDup(tkn); + char *base_translation_name = NULL; + tkn = sc->get(sc, 0); CHECK_EOF(); if (strcmp(tkn, ":") == 0) @@ -820,19 +927,15 @@ void R_ParseTrnslate(INT32 wadNum, UINT16 lumpnum) tkn = sc->get(sc, 0); CHECK_EOF(); - base_translation = R_FindCustomTranslation(tkn); - if (base_translation == -1) - { - CONS_Alert(CONS_ERROR, "Error parsing translation '%s': No translation named '%s'\n", name, tkn); - goto fail; - } + base_translation_name = Z_StrDup(tkn); tkn = sc->get(sc, 0); + CHECK_EOF(); } if (strcmp(tkn, "=") != 0) { - CONS_Alert(CONS_ERROR, "Error parsing translation '%s': Expected '=', got '%s'\n", name, tkn); + PrintError(name, "Expected '=', got '%s'", tkn); goto fail; } tkn = sc->get(sc, 0); @@ -840,52 +943,65 @@ void R_ParseTrnslate(INT32 wadNum, UINT16 lumpnum) if (strcmp(tkn, "\"") != 0) { - CONS_Alert(CONS_ERROR, "Error parsing translation '%s': Expected '=', got '%s'\n", name, tkn); + PrintError(name, "Expected '\"', got '%s'", tkn); goto fail; } tkn = sc->get(sc, 0); CHECK_EOF(); - struct PaletteRemapParseResult *result = NULL; + int existing_id = R_FindCustomTranslation(name); + + // Parse all of the translations do { - result = PaletteRemap_ParseTranslation(tkn); - if (result->has_error) + struct PaletteRemapParseResult *parse_result = PaletteRemap_ParseTranslation(tkn); + if (parse_result->error) { - CONS_Alert(CONS_ERROR, "Error parsing translation '%s': %s\n", name, result->error); - Z_Free(result); + PrintError(name, "%s", parse_result->error); + Z_Free(parse_result->error); goto fail; } + else + { + AddNewTranslation(&list, &list_count, name, existing_id, base_translation_name, parse_result); + } tkn = sc->get(sc, 0); - if (!tkn) - break; - - if (strcmp(tkn, "\"") != 0) + if (!tkn || strcmp(tkn, "\"") != 0) { - CONS_Alert(CONS_ERROR, "Error parsing translation '%s': Expected '=', got '%s'\n", name, tkn); + if (tkn) + PrintError(name, "Expected '\"', got '%s'", tkn); + else + PrintError(name, "Expected '\"', got EOF"); goto fail; } + // Get ',' or parse the next line tkn = sc->get(sc, 0); if (!tkn || strcmp(tkn, ",") != 0) break; - } while (true); - - // Allocate it and register it - remaptable_t *tr = PaletteRemap_New(); - unsigned id = PaletteRemap_Add(tr); - R_AddCustomTranslation(name, id); - // Free this, since it's no longer needed - Z_Free(name); - - // The translation is not generated until later, because the palette may not have been loaded. - // We store the result for when it's needed. - AddParsedTranslation(id, base_translation, result); + // Get '"' + tkn = sc->get(sc, 0); + if (!tkn || strcmp(tkn, "\"") != 0) + { + if (!tkn) + PrintError(name, "Expected '\"', got EOF"); + else + PrintError(name, "Expected '\"', got '%s'", tkn); + goto fail; + } + tkn = sc->get(sc, 0); + CHECK_EOF(); + } while (true); } fail: + // Now add all of the new translations + if (list) + PrepareNewTranslations(list, list_count); + Tokenizer_Close(sc); + Z_Free(text); }