Allow tabs to grow wider than the screen

This commit is contained in:
James Lambert 2023-11-06 21:37:03 -07:00
parent eeb0bf572d
commit b3674c6845
6 changed files with 114 additions and 51 deletions

View file

@ -326,6 +326,8 @@ void fontRendererInitPrerender(struct FontRenderer* renderer, struct Prerendered
prerender->displayLists = malloc(sizeof(Gfx*) * imageIndex);
prerender->usedImageIndices = renderer->usedImageIndices;
prerender->x = 0;
prerender->y = 0;
imageMask = renderer->usedImageIndices;
imageIndex = 0;
@ -385,6 +387,46 @@ void prerenderedTextFree(struct PrerenderedText* prerender) {
free(prerender);
}
void prerenderShiftSingleSymbol(Gfx* gfx, int xOffset, int yOffset) {
int x = _SHIFTR(gfx->words.w0, 12, 12) + xOffset;
int y = _SHIFTL(gfx->words.w0, 0, 12) + yOffset;
gfx->words.w0 = _SHIFTL(G_TEXRECT, 24, 8) | _SHIFTL(x, 12, 12) | _SHIFTL(y, 0, 12);
x = _SHIFTR(gfx->words.w1, 12, 12) + xOffset;
y = _SHIFTL(gfx->words.w1, 0, 12) + yOffset;
gfx->words.w1 = _SHIFTL(G_TX_RENDERTILE, 24, 3) | _SHIFTL(x, 12, 12) | _SHIFTL(y, 0, 12);
}
void prerenderedTextRelocate(struct PrerenderedText* prerender, int x, int y) {
int imageIndex = 0;
int imageMask = prerender->usedImageIndices;
int xOffset = (x - prerender->x) << 2;
int yOffset = (y - prerender->y) << 2;
while (imageMask) {
if (imageMask & 0x1) {
Gfx* gfx = prerender->displayLists[imageIndex];
// skip color
gfx += 2;
while (_SHIFTR(gfx->words.w0, 24, 8) != G_ENDDL) {
prerenderShiftSingleSymbol(gfx, xOffset, yOffset);
gfx += 3;
}
osWritebackDCache(prerender->displayLists[imageIndex], (int)gfx - (int)prerender->displayLists[imageIndex]);
}
imageMask >>= 1;
++imageIndex;
}
prerender->x = x;
prerender->y = y;
}
void prerenderedTextRecolor(struct PrerenderedText* prerender, struct Coloru8* color) {
int imageIndex = 0;
int imageMask = prerender->usedImageIndices;
@ -413,6 +455,9 @@ void fontRendererFillPrerender(struct FontRenderer* renderer, struct Prerendered
int imageIndex = 0;
int imageMask = renderer->usedImageIndices & prerender->usedImageIndices;
prerender->x = x;
prerender->y = y;
while (imageMask) {
if (imageMask & 0x1) {
Gfx* gfx = prerender->displayLists[imageIndex];

View file

@ -67,12 +67,15 @@ Gfx* fontRendererBuildGfx(struct FontRenderer* renderer, Gfx** fontImages, int x
struct PrerenderedText {
Gfx** displayLists;
short usedImageIndices;
short x;
short y;
};
void fontRendererInitPrerender(struct FontRenderer* renderer, struct PrerenderedText* prerender);
struct PrerenderedText* prerenderedTextNew(struct FontRenderer* renderer);
void prerenderedTextCleanup(struct PrerenderedText* prerender);
void prerenderedTextFree(struct PrerenderedText* prerender);
void prerenderedTextRelocate(struct PrerenderedText* prerender, int x, int y);
void prerenderedTextRecolor(struct PrerenderedText* prerender, struct Coloru8* color);
void fontRendererFillPrerender(struct FontRenderer* renderer, struct PrerenderedText* prerender, int x, int y, struct Coloru8* color);

View file

@ -21,6 +21,9 @@ struct Tab gOptionTabs[] = {
{
.message = "Audio",
},
{
.message = "Video",
},
{
.message = "Gameplay",
},
@ -59,32 +62,27 @@ void optionsMenuRebuildText(struct OptionsMenu* options) {
}
enum MenuDirection optionsMenuUpdate(struct OptionsMenu* options) {
enum MenuDirection menuDirection = MenuDirectionStay;
if(menuDirection == MenuDirectionStay)
{
switch (options->tabs.selectedTab) {
case OptionsMenuTabsControlMapping:
menuDirection = controlsMenuUpdate(&options->controlsMenu);
controlsMenuUpdate(&options->controlsMenu);
break;
case OptionsMenuTabsControlJoystick:
menuDirection = joystickOptionsUpdate(&options->joystickOptions);
joystickOptionsUpdate(&options->joystickOptions);
break;
case OptionsMenuTabsAudio:
menuDirection = audioOptionsUpdate(&options->audioOptions);
audioOptionsUpdate(&options->audioOptions);
break;
case OptionsMenuTabsGameplay:
menuDirection = gameplayOptionsUpdate(&options->gameplayOptions);
gameplayOptionsUpdate(&options->gameplayOptions);
break;
}
}
if (menuDirection == MenuDirectionUp) {
if (controllerGetButtonDown(0, B_BUTTON)) {
savefileSave();
return MenuDirectionUp;
}
if (menuDirection == MenuDirectionLeft) {
if (controllerGetButtonDown(0, Z_TRIG | L_TRIG)) {
if (options->tabs.selectedTab == 0) {
tabsSetSelectedTab(&options->tabs, OptionsMenuTabsCount - 1);
} else {
@ -95,7 +93,7 @@ enum MenuDirection optionsMenuUpdate(struct OptionsMenu* options) {
soundPlayerPlay(SOUNDS_BUTTONROLLOVER, 1.0f, 0.5f, NULL, NULL, SoundTypeAll);
}
if (menuDirection == MenuDirectionRight) {
if (controllerGetButtonDown(0, R_TRIG)) {
if (options->tabs.selectedTab == OptionsMenuTabsCount - 1) {
tabsSetSelectedTab(&options->tabs, 0);
} else {
@ -119,14 +117,29 @@ void optionsMenuRender(struct OptionsMenu* options, struct RenderState* renderSt
gSPDisplayList(renderState->dl++, options->menuOutline);
gSPDisplayList(renderState->dl++, ui_material_revert_list[ROUNDED_CORNERS_INDEX]);
gDPSetScissor(renderState->dl++,
G_SC_NON_INTERLACE,
MENU_LEFT + OPTIONS_PADDING,
0,
MENU_LEFT + MENU_WIDTH - OPTIONS_PADDING,
SCREEN_HT
);
gSPDisplayList(renderState->dl++, ui_material_list[SOLID_ENV_INDEX]);
gSPDisplayList(renderState->dl++, options->tabs.tabOutline);
gSPDisplayList(renderState->dl++, ui_material_revert_list[SOLID_ENV_INDEX]);
gSPDisplayList(renderState->dl++, ui_material_list[DEJAVU_SANS_0_INDEX]);
renderState->dl = tabsRenderText(&options->tabs, renderState->dl);
struct PrerenderedTextBatch* batch = prerenderedBatchStart();
tabsRenderText(&options->tabs, batch);
renderState->dl = prerenderedBatchFinish(batch, gDejaVuSansImages, renderState->dl);
gSPDisplayList(renderState->dl++, ui_material_revert_list[DEJAVU_SANS_0_INDEX]);
gDPSetScissor(renderState->dl++,
G_SC_NON_INTERLACE,
0, 0,
SCREEN_WD, SCREEN_HT
);
switch (options->tabs.selectedTab) {
case OptionsMenuTabsControlMapping:
controlsMenuRender(&options->controlsMenu, renderState, task);

View file

@ -13,6 +13,7 @@ enum OptionsMenuTabs {
OptionsMenuTabsControlMapping,
OptionsMenuTabsControlJoystick,
OptionsMenuTabsAudio,
OptionsMenuTabsVideo,
OptionsMenuTabsGameplay,
OptionsMenuTabsCount,

View file

@ -23,13 +23,26 @@ void tabsSetSelectedTab(struct Tabs* tabs, int index) {
gDPFillRectangle(dl++, tabs->x, tabs->y + tabs->height - 1, tabs->x + tabs->width, tabs->y + tabs->height);
gDPFillRectangle(dl++, tabs->x + tabs->width - 1, tabs->y + TAB_HEIGHT, tabs->x + tabs->width, tabs->y + tabs->height);
int tabOffset = 0;
struct TabRenderData* rightVisibleTab = &tabs->tabRenderData[tabs->selectedTab];
if (tabs->selectedTab + 1 < tabs->tabCount) {
++rightVisibleTab;
}
if (rightVisibleTab->x + rightVisibleTab->width >= tabs->x + tabs->width) {
tabOffset = (tabs->x + tabs->width) - (rightVisibleTab->x + rightVisibleTab->width) + 1;
}
for (int i = 0; i < tabs->tabCount; ++i) {
struct TabRenderData* tab = &tabs->tabRenderData[i];
int tabTop = (i == tabs->selectedTab) ? tabs->y : (tabs->y + 1);
int tabLeft = tab->x + tabOffset;
gDPFillRectangle(dl++, tab->x + tab->width - 2, tabTop, tab->x + tab->width - 1, tabs->y + TAB_HEIGHT);
gDPFillRectangle(dl++, tabLeft + tab->width - 2, tabTop, tabLeft + tab->width - 1, tabs->y + TAB_HEIGHT);
fontRender(tabs->font, tabs->tabs[i].message, tab->x + LEFT_TEXT_PADDING, tabTop + TOP_TEXT_PADDING, tab->text);
prerenderedTextRelocate(tab->text, tabLeft + LEFT_TEXT_PADDING, tabTop + TOP_TEXT_PADDING);
}
gDPPipeSync(dl++);
@ -39,19 +52,22 @@ void tabsSetSelectedTab(struct Tabs* tabs, int index) {
for (int i = 0; i < tabs->tabCount; ++i) {
struct TabRenderData* tab = &tabs->tabRenderData[i];
int tabTop = (i == tabs->selectedTab) ? tabs->y : (tabs->y + 1);
int tabLeft = tab->x + tabOffset;
gDPFillRectangle(dl++, tab->x, tabTop, tab->x + 1, tabs->y + TAB_HEIGHT);
gDPFillRectangle(dl++, tab->x, tabTop, tab->x + tab->width - 2, tabTop + 1);
gDPFillRectangle(dl++, tabLeft, tabTop, tabLeft + 1, tabs->y + TAB_HEIGHT);
gDPFillRectangle(dl++, tabLeft, tabTop, tabLeft + tab->width - 2, tabTop + 1);
}
struct TabRenderData* selectedTab = tabs->selectedTab < tabs->tabCount ? &tabs->tabRenderData[tabs->selectedTab] : NULL;
if (selectedTab) {
gDPFillRectangle(dl++, tabs->x, tabs->y + TAB_HEIGHT, selectedTab->x, tabs->y + TAB_HEIGHT + 1);
gDPFillRectangle(dl++, selectedTab->x + selectedTab->width, tabs->y + TAB_HEIGHT, tabs->x + tabs->width, tabs->y + TAB_HEIGHT + 1);
gDPFillRectangle(dl++, tabs->x, tabs->y + TAB_HEIGHT, selectedTab->x + tabOffset, tabs->y + TAB_HEIGHT + 1);
gDPFillRectangle(dl++, selectedTab->x + tabOffset + selectedTab->width, tabs->y + TAB_HEIGHT, tabs->x + tabs->width, tabs->y + TAB_HEIGHT + 1);
}
gSPEndDisplayList(dl++);
tabs->prevOffset = tabOffset;
}
void tabsInit(struct Tabs* tabs, struct Tab* tabList, int tabCount, struct Font* font, int x, int y, int width, int height) {
@ -62,6 +78,7 @@ void tabsInit(struct Tabs* tabs, struct Tab* tabList, int tabCount, struct Font*
tabs->height = height;
tabs->x = x;
tabs->y = y;
tabs->prevOffset = 0;
tabs->tabOutline = malloc(sizeof(Gfx) * (10 + 3 * tabCount));
tabs->tabRenderData = malloc(sizeof(struct TabRenderData) * tabCount);
@ -70,7 +87,7 @@ void tabsInit(struct Tabs* tabs, struct Tab* tabList, int tabCount, struct Font*
for (int i = 0; i < tabCount; ++i) {
struct Vector2s16 textSize = fontMeasure(font, tabList[i].message);
tabs->tabRenderData[i].text = menuBuildText(font, tabList[i].message, currentX + LEFT_TEXT_PADDING, y + TOP_TEXT_PADDING);
tabs->tabRenderData[i].text = menuBuildPrerenderedText(font, tabList[i].message, currentX + LEFT_TEXT_PADDING, y + TOP_TEXT_PADDING);
tabs->tabRenderData[i].width = textSize.x + LEFT_TEXT_PADDING + RIGHT_TEXT_PADDING;
tabs->tabRenderData[i].x = currentX;
@ -81,25 +98,8 @@ void tabsInit(struct Tabs* tabs, struct Tab* tabList, int tabCount, struct Font*
tabsSetSelectedTab(tabs, 0);
}
Gfx* tabsRenderText(struct Tabs* tabs, Gfx* dl) {
gDPPipeSync(dl++);
gDPSetEnvColor(dl++, gSelectionGray.r, gSelectionGray.g, gSelectionGray.b, gSelectionGray.a);
void tabsRenderText(struct Tabs* tabs, struct PrerenderedTextBatch* batch) {
for (int i = 0; i < tabs->tabCount; ++i) {
if (i == tabs->selectedTab) {
gDPSetEnvColor(dl++, gColorWhite.r, gColorWhite.g, gColorWhite.b, gColorWhite.a);
}
gSPDisplayList(dl++, tabs->tabRenderData[i].text);
if (i == tabs->selectedTab) {
gDPPipeSync(dl++);
gDPSetEnvColor(dl++, gSelectionGray.r, gSelectionGray.g, gSelectionGray.b, gSelectionGray.a);
prerenderedBatchAdd(batch, tabs->tabRenderData[i].text, i == tabs->selectedTab ? &gColorWhite : &gSelectionGray);
}
}
gDPPipeSync(dl++);
gDPSetEnvColor(dl++, gColorWhite.r, gColorWhite.g, gColorWhite.b, gColorWhite.a);
return dl;
}

View file

@ -9,7 +9,7 @@ struct Tab {
};
struct TabRenderData {
Gfx* text;
struct PrerenderedText* text;
short width;
short x;
};
@ -23,12 +23,13 @@ struct Tabs {
short selectedTab;
short x;
short y;
short prevOffset;
Gfx* tabOutline;
struct TabRenderData* tabRenderData;
};
void tabsInit(struct Tabs* tabs, struct Tab* tabList, int tabCount, struct Font* font, int x, int y, int width, int height);
void tabsSetSelectedTab(struct Tabs* tabs, int index);
Gfx* tabsRenderText(struct Tabs* tabs, Gfx* dl);
void tabsRenderText(struct Tabs* tabs, struct PrerenderedTextBatch* batch);
#endif