From 9d07965582ae730e280b43b3a329a3417983eac8 Mon Sep 17 00:00:00 2001 From: James Lambert Date: Thu, 9 Nov 2023 21:42:50 -0700 Subject: [PATCH] translate controls menu --- Makefile | 2 +- assets/translations/extra_english.txt | Bin 434 -> 610 bytes src/font/font.c | 63 +++++++++++++++ src/font/font.h | 1 + src/menu/controls.c | 95 ++++++++++++++--------- src/menu/controls.h | 6 +- src/menu/menu.c | 2 +- src/menu/options_menu.c | 1 + tools/level_scripts/subtitle_generate.py | 21 ++++- 9 files changed, 147 insertions(+), 44 deletions(-) diff --git a/Makefile b/Makefile index f8ac3c3..7066ca9 100644 --- a/Makefile +++ b/Makefile @@ -322,7 +322,7 @@ build/src/effects/portal_trail.o: build/assets/materials/static.h build/assets/m build/src/levels/level_definition.o: build/src/audio/subtitles.h build/src/levels/level_definition.h: build/src/audio/subtitles.h build/src/locales/locales.o: build/src/audio/clips.h build/src/audio/languages.h -build/src/menu/controls.o: build/assets/materials/ui.h build/src/audio/clips.h +build/src/menu/controls.o: build/assets/materials/ui.h build/src/audio/clips.h build/src/audio/subtitles.h build/src/menu/game_menu.o: build/src/audio/clips.h build/assets/materials/ui.h build/assets/materials/images.h build/assets/test_chambers/test_chamber_00/test_chamber_00.h build/src/menu/gameplay_options.o: build/assets/materials/ui.h build/src/audio/clips.h build/src/menu/joystick_options.o: build/assets/materials/ui.h build/src/audio/clips.h diff --git a/assets/translations/extra_english.txt b/assets/translations/extra_english.txt index 09561ad4fce834cf8d04f28b57314075784a3008..bde2ce5499fce92651ae47ed98818d37187c8a6d 100644 GIT binary patch delta 191 zcmdnQ{D@`48pe7hhA@Uih8%`6hE#@l249AJFiVMnlR*iI#|7jetMdV>%V)?2ih|T3 yc(~NXGXyh~Fcbl8%4A4q$N;kA8JvK;WOEEd6c~!plqxVJfs}$(axv60fG_}A10l%( delta 14 VcmaFFvWa=a8b-ES1}=tL1^^~S1Oos7 diff --git a/src/font/font.c b/src/font/font.c index 2cb1c97..de40597 100644 --- a/src/font/font.c +++ b/src/font/font.c @@ -367,6 +367,69 @@ struct PrerenderedText* prerenderedTextNew(struct FontRenderer* renderer) { return result; } +struct PrerenderedText* prerenderedTextCopy(struct PrerenderedText* text) { + struct PrerenderedText* result = malloc(sizeof(struct PrerenderedText)); + + int imageIndex = 0; + int imageMask = text->usedImageIndices; + + while (imageMask) { + imageMask >>= 1; + ++imageIndex; + } + + result->displayLists = malloc(sizeof(Gfx*) * imageIndex); + result->usedImageIndices = text->usedImageIndices; + result->x = text->x; + result->y = text->y; + result->width = text->width; + result->height = text->height; + + imageIndex = 0; + imageMask = text->usedImageIndices; + + while (imageMask) { + if (imageMask & 0x1) { + Gfx* src = text->displayLists[imageIndex]; + + src += 2; + while (_SHIFTR(src->words.w0, 24, 8) != G_ENDDL) { + // copy image + src += 3; + } + ++src; + + int size = (src - text->displayLists[imageIndex]) * sizeof(Gfx); + + result->displayLists[imageIndex] = malloc(size); + + Gfx* dest = result->displayLists[imageIndex]; + src = text->displayLists[imageIndex]; + // copy color + *dest++ = *src++; + *dest++ = *src++; + + while (_SHIFTR(src->words.w0, 24, 8) != G_ENDDL) { + // copy image + *dest++ = *src++; + *dest++ = *src++; + *dest++ = *src++; + } + + // copy end + *dest++ = *src++; + + osWritebackDCache(result->displayLists[imageIndex], size); + } else { + result->displayLists[imageIndex] = NULL; + } + + imageMask >>= 1; + ++imageIndex; + } + return result; +} + void prerenderedTextCleanup(struct PrerenderedText* prerender) { int imageIndex = 0; int imageMask = prerender->usedImageIndices; diff --git a/src/font/font.h b/src/font/font.h index fa3ea62..cb6a0fd 100644 --- a/src/font/font.h +++ b/src/font/font.h @@ -75,6 +75,7 @@ struct PrerenderedText { void fontRendererInitPrerender(struct FontRenderer* renderer, struct PrerenderedText* prerender); struct PrerenderedText* prerenderedTextNew(struct FontRenderer* renderer); +struct PrerenderedText* prerenderedTextCopy(struct PrerenderedText* text); void prerenderedTextCleanup(struct PrerenderedText* prerender); void prerenderedTextFree(struct PrerenderedText* prerender); void prerenderedTextRelocate(struct PrerenderedText* prerender, int x, int y); diff --git a/src/menu/controls.c b/src/menu/controls.c index 9d3f6bc..e9d90d5 100644 --- a/src/menu/controls.c +++ b/src/menu/controls.c @@ -5,10 +5,12 @@ #include "../controls/controller.h" #include "../audio/soundplayer.h" #include "../util/memory.h" +#include "./translations.h" #include "../build/assets/materials/ui.h" #include "../build/src/audio/clips.h" +#include "../build/src/audio/subtitles.h" #define CONTROL_ROW_HEIGHT 14 @@ -111,25 +113,25 @@ char gControllerActionToDirectionIcon[] = { }; struct ControlActionDataRow { - char* name; + short nameId; + short headerId; enum ControllerAction action; - char* header; }; struct ControlActionDataRow gControllerDataRows[] = { - {"Move", ControllerActionMove, "Movement"}, - {"Look", ControllerActionRotate, NULL}, - {"Jump", ControllerActionJump, NULL}, - {"Duck", ControllerActionDuck, NULL}, + {VALVE_MOVE, VALVE_MOVEMENT_TITLE, ControllerActionMove}, + {VALVE_LOOK, -1, ControllerActionRotate}, + {VALVE_JUMP, -1, ControllerActionJump}, + {VALVE_DUCK, -1, ControllerActionDuck}, - {"Fire blue portal", ControllerActionOpenPortal0, "Combat"}, - {"Fire red portal", ControllerActionOpenPortal1, NULL}, - {"Use item", ControllerActionUseItem, NULL}, + {VALVE_PRIMARY_ATTACK, VALVE_COMBAT_TITLE, ControllerActionOpenPortal0}, + {VALVE_SECONDARY_ATTACK, -1, ControllerActionOpenPortal1}, + {VALVE_USE_ITEMS, -1, ControllerActionUseItem}, - {"Pause", ControllerActionPause, "Misc"}, + {VALVE_PAUSE_GAME, -1, ControllerActionPause}, - {"Look forward", ControllerActionLookForward, "Misc Movement"}, - {"Look backward", ControllerActionLookBackward, NULL}, + {VALVE_LOOK_STRAIGHT_AHEAD, VALVE_MISCELLANEOUS_KEYBOARD_KEYS_TITLE, ControllerActionLookForward}, + {VALVE_LOOK_STRAIGHT_BACK, -1, ControllerActionLookBackward}, }; int controlsMeasureIcons(enum ControllerAction action) { @@ -192,14 +194,24 @@ Gfx* controlsRenderIcons(Gfx* dl, enum ControllerAction action, int x, int y) { } void controlsLayoutRow(struct ControlsMenuRow* row, struct ControlActionDataRow* data, int x, int y) { - fontRender(&gDejaVuSansFont, data->name, x + ROW_PADDING, y, row->actionText); + struct PrerenderedText* copy = prerenderedTextCopy(row->actionText); + menuFreePrerenderedDeferred(row->actionText); + row->actionText = copy; + prerenderedTextRelocate(row->actionText, x + ROW_PADDING, y); Gfx* dl = controlsRenderIcons(row->sourceIcons, data->action, CONTROLS_X + CONTROLS_WIDTH - ROW_PADDING * 2, y); gSPEndDisplayList(dl++); row->y = y; } +void controlsLayoutHeader(struct ControlsMenuHeader* header, int x, int y) { + struct PrerenderedText* copy = prerenderedTextCopy(header->headerText); + menuFreePrerenderedDeferred(header->headerText); + header->headerText = copy; + prerenderedTextRelocate(header->headerText, x, y); +} + void controlsInitRow(struct ControlsMenuRow* row, struct ControlActionDataRow* data) { - row->actionText = menuBuildText(&gDejaVuSansFont, data->name, 0, 0); + row->actionText = menuBuildPrerenderedText(&gDejaVuSansFont, translationsGet(data->nameId), 0, 0, SCREEN_WD); Gfx* dl = row->sourceIcons; for (int i = 0; i < SOURCE_ICON_COUNT; ++i) { @@ -207,12 +219,8 @@ void controlsInitRow(struct ControlsMenuRow* row, struct ControlActionDataRow* d } } -void controlsLayoutHeader(struct ControlsMenuHeader* header, char* message, int x, int y) { - header->headerText = menuBuildText(&gDejaVuSansFont, message, x + HEADER_PADDING, y); -} - -void controlsInitHeader(struct ControlsMenuHeader* header, char* message) { - header->headerText = menuBuildText(&gDejaVuSansFont, message, 0, 0); +void controlsInitHeader(struct ControlsMenuHeader* header, int message) { + header->headerText = menuBuildPrerenderedText(&gDejaVuSansFont, translationsGet(message), 0, 0, SCREEN_WD); } void controlsLayout(struct ControlsMenu* controlsMenu) { @@ -222,9 +230,9 @@ void controlsLayout(struct ControlsMenu* controlsMenu) { Gfx* headerSeparators = controlsMenu->headerSeparators; for (int i = 0; i < ControllerActionCount; ++i) { - if (gControllerDataRows[i].header && currentHeader < MAX_CONTROLS_SECTIONS) { + if (gControllerDataRows[i].headerId != -1 && currentHeader < MAX_CONTROLS_SECTIONS) { y += TOP_PADDING; - controlsLayoutHeader(&controlsMenu->headers[currentHeader], gControllerDataRows[i].header, CONTROLS_X, y); + controlsLayoutHeader(&controlsMenu->headers[currentHeader], CONTROLS_X + 2, y); y += CONTROL_ROW_HEIGHT; if (y > CONTROLS_Y + 1 && y < CONTROLS_Y + CONTROLS_HEIGHT - 1) { @@ -242,14 +250,14 @@ void controlsLayout(struct ControlsMenu* controlsMenu) { gSPEndDisplayList(headerSeparators++); } -void controlsMenuInit(struct ControlsMenu* controlsMenu) { +void controlsMenuInitText(struct ControlsMenu* controlsMenu) { int currentHeader = 0; for (int i = 0; i < ControllerActionCount; ++i) { controlsInitRow(&controlsMenu->actionRows[i], &gControllerDataRows[i]); - if (gControllerDataRows[i].header && currentHeader < MAX_CONTROLS_SECTIONS) { - controlsInitHeader(&controlsMenu->headers[currentHeader], gControllerDataRows[i].header); + if (gControllerDataRows[i].headerId != -1 && currentHeader < MAX_CONTROLS_SECTIONS) { + controlsInitHeader(&controlsMenu->headers[currentHeader], gControllerDataRows[i].headerId); ++currentHeader; } } @@ -257,6 +265,10 @@ void controlsMenuInit(struct ControlsMenu* controlsMenu) { for (; currentHeader < MAX_CONTROLS_SECTIONS; ++currentHeader) { controlsMenu->headers[currentHeader].headerText = NULL; } +} + +void controlsMenuInit(struct ControlsMenu* controlsMenu) { + controlsMenuInitText(controlsMenu); controlsMenu->selectedRow = 0; controlsMenu->scrollOffset = 0; @@ -274,6 +286,19 @@ void controlsMenuInit(struct ControlsMenu* controlsMenu) { controlsMenu->scrollOutline = menuBuildOutline(CONTROLS_X, CONTROLS_Y, CONTROLS_WIDTH, CONTROLS_HEIGHT, 1); } +void controlsRebuildtext(struct ControlsMenu* controlsMenu) { + for (int i = 0; i < ControllerActionCount; ++i) { + prerenderedTextFree(controlsMenu->actionRows[i].actionText); + } + + for (int i = 0; i < MAX_CONTROLS_SECTIONS; ++i) { + prerenderedTextFree(controlsMenu->headers[i].headerText); + } + + controlsMenuInitText(controlsMenu); + controlsLayout(controlsMenu); +} + enum MenuDirection controlsMenuUpdate(struct ControlsMenu* controlsMenu) { if (controlsMenu->waitingForAction != ControllerActionNone) { struct ControllerSourceWithController source = controllerReadAnySource(); @@ -315,7 +340,7 @@ enum MenuDirection controlsMenuUpdate(struct ControlsMenu* controlsMenu) { int topY = selectedAction->y; int bottomY = topY + CONTROL_ROW_HEIGHT + TOP_PADDING; - if (gControllerDataRows[controlsMenu->selectedRow].header) { + if (gControllerDataRows[controlsMenu->selectedRow].headerId != -1) { topY -= CONTROL_ROW_HEIGHT + TOP_PADDING + SEPARATOR_SPACE; } @@ -418,26 +443,20 @@ void controlsMenuRender(struct ControlsMenu* controlsMenu, struct RenderState* r gDPSetEnvColor(renderState->dl++, gColorWhite.r, gColorWhite.g, gColorWhite.b, gColorWhite.a); gDPSetScissor(renderState->dl++, G_SC_NON_INTERLACE, CONTROLS_X, CONTROLS_Y, CONTROLS_X + CONTROLS_WIDTH, CONTROLS_Y + CONTROLS_HEIGHT); + struct PrerenderedTextBatch* batch = prerenderedBatchStart(); + for (int i = 0; i < ControllerActionCount; ++i) { - if (controlsMenu->selectedRow == i) { - gDPPipeSync(renderState->dl++); - gDPSetEnvColor(renderState->dl++, 0, 0, 0, 255); - } - - renderStateInlineBranch(renderState, controlsMenu->actionRows[i].actionText); - - if (controlsMenu->selectedRow == i) { - gDPPipeSync(renderState->dl++); - gDPSetEnvColor(renderState->dl++, 255, 255, 255, 255); - } + prerenderedBatchAdd(batch, controlsMenu->actionRows[i].actionText, controlsMenu->selectedRow == i ? &gColorBlack : &gColorWhite); } for (int i = 0; i < MAX_CONTROLS_SECTIONS; ++i) { if (!controlsMenu->headers[i].headerText) { break; } - renderStateInlineBranch(renderState, controlsMenu->headers[i].headerText); + prerenderedBatchAdd(batch, controlsMenu->headers[i].headerText, &gColorWhite); } + renderState->dl = prerenderedBatchFinish(batch, gDejaVuSansImages, renderState->dl); + gSPDisplayList(renderState->dl++, ui_material_revert_list[DEJAVU_SANS_0_INDEX]); gSPDisplayList(renderState->dl++, ui_material_list[BUTTON_ICONS_INDEX]); diff --git a/src/menu/controls.h b/src/menu/controls.h index ef64a28..0592c00 100644 --- a/src/menu/controls.h +++ b/src/menu/controls.h @@ -5,6 +5,7 @@ #include "../controls/controller_actions.h" #include "../graphics/graphics.h" #include "../scene/hud.h" +#include "../font/font.h" #define MAX_SOURCES_PER_ACTION 4 #define MAX_CONTROLS_SECTIONS 4 @@ -14,13 +15,13 @@ #define SOURCE_ICON_COUNT MAX_SOURCES_PER_ACTION * GFX_ENTRIES_PER_IMAGE + GFX_ENTRIES_PER_END_DL struct ControlsMenuRow { - Gfx* actionText; + struct PrerenderedText* actionText; Gfx sourceIcons[SOURCE_ICON_COUNT]; short y; }; struct ControlsMenuHeader { - Gfx* headerText; + struct PrerenderedText* headerText; }; struct ControlsMenu { @@ -39,6 +40,7 @@ struct ControlsMenu { }; void controlsMenuInit(struct ControlsMenu* controlsMenu); +void controlsRebuildtext(struct ControlsMenu* controlsMenu); enum MenuDirection controlsMenuUpdate(struct ControlsMenu* controlsMenu); void controlsMenuRender(struct ControlsMenu* controlsMenu, struct RenderState* renderState, struct GraphicsTask* task); diff --git a/src/menu/menu.c b/src/menu/menu.c index fa07e97..49b595c 100644 --- a/src/menu/menu.c +++ b/src/menu/menu.c @@ -296,7 +296,7 @@ Gfx* menuSliderRender(struct MenuSlider* slider, Gfx* dl) { return dl; } -#define MAX_DEFERRED_RELEASE_SIZE 16 +#define MAX_DEFERRED_RELEASE_SIZE 20 #define RELEASE_DEFER_COUNT 2 #define NEXT_ENTRY(curr) ((curr) + 1 == MAX_DEFERRED_RELEASE_SIZE ? 0 : (curr) + 1) diff --git a/src/menu/options_menu.c b/src/menu/options_menu.c index 0b25018..40eb7bd 100644 --- a/src/menu/options_menu.c +++ b/src/menu/options_menu.c @@ -59,6 +59,7 @@ void optionsMenuInit(struct OptionsMenu* options) { } void optionsMenuRebuildText(struct OptionsMenu* options) { + controlsRebuildtext(&options->controlsMenu); audioOptionsRebuildtext(&options->audioOptions); tabsRebuildText(&options->tabs); } diff --git a/tools/level_scripts/subtitle_generate.py b/tools/level_scripts/subtitle_generate.py index 2099d9e..9bcdb36 100644 --- a/tools/level_scripts/subtitle_generate.py +++ b/tools/level_scripts/subtitle_generate.py @@ -27,6 +27,20 @@ hl_gameui_whitelist = { portal_whitelist = { "PORTAL_CHAPTER1_TITLE", + "VALVE_PRIMARY_ATTACK", + "VALVE_SECONDARY_ATTACK", +} + +valve_whitelist = { + "VALVE_JUMP", + "VALVE_DUCK", + "VALVE_USE_ITEMS", + "VALVE_COMBAT_TITLE", + "VALVE_MOVEMENT_TITLE", + "VALVE_MISCELLANEOUS_TITLE", + "VALVE_PAUSE_GAME", + "VALVE_LOOK_STRAIGHT_AHEAD", + "VALVE_MISCELLANEOUS_KEYBOARD_KEYS_TITLE", } language_translations = { @@ -306,10 +320,13 @@ def process_all_closecaption_files(dir, language_names): portal_k, portal_v, _ = read_translation_file(f"vpk/Portal/portal/resource/portal_{language_name}.txt") portal_k, portal_v = filter_whitelist(portal_k, portal_v, portal_whitelist) + valve_k, valve_v, _ = read_translation_file(f"vpk/Portal/hl2/resource/valve_{language_name}.txt") + valve_k, valve_v = filter_whitelist(valve_k, valve_v, valve_whitelist) + extra_k, extra_v, _ = read_translation_file(f"assets/translations/extra_{language_name}.txt") - k = k + gamepad_k + portal_k + extra_k - v = v + gamepad_v + portal_v + extra_v + k = k + gamepad_k + portal_k + valve_k + extra_k + v = v + gamepad_v + portal_v + valve_v + extra_v if not key_order: header_lines = make_SubtitleKey_headerlines(k)