paulo@0: /* paulo@0: paulo@0: BGCTRL layout paulo@0: Layer 0: Current menu paulo@0: Layer 1: Menu that is fading away paulo@0: Layer 2: Gradient background paulo@0: paulo@0: VRAM layout paulo@0: (1 map == 64 tiles) paulo@0: Tiles 0.000-2FF: layer 0 bitmap paulo@0: Tiles 0.300-3FF: unused paulo@0: Tiles 2.000-2FF: layer 1 bitmap paulo@0: Tiles 2.300-33F: unused paulo@0: Tiles 2.340-36F: map 29 (layer 2) paulo@0: Tiles 2.370-37F: layer 2 gradient tiles paulo@0: Tiles 2.380-3FF: layer 0 map paulo@0: Tiles 2.3C0-3FF: layer 1 map paulo@0: paulo@0: paulo@0: */ paulo@0: paulo@0: #include paulo@0: #include paulo@0: #include "fontdraw.h" paulo@0: typedef u32 TileSliver; paulo@0: paulo@0: #ifdef ARM9 paulo@0: #include paulo@0: #define MENU_GFX_CORE 1 paulo@0: #define MENU_GFX_VRAM(bank, tile) (TileSliver *)(BG_TILE_RAM_SUB(bank) + 32 * tile) paulo@0: #define MENU_GFX_MAP ((NAMETABLE *)0x06200000) paulo@0: #define MENU_GFX_BGCTRL BGCTRL_SUB paulo@0: #define MENU_GFX_OFFSET ((bg_scroll *)(0x04001010)) paulo@0: #define HIDDEN_ROWS 0 paulo@0: #define HIDDEN_COLS 0 paulo@0: #define BG0_ON DISPLAY_BG0_ACTIVE paulo@0: #define BG1_ON DISPLAY_BG1_ACTIVE paulo@0: #define BG2_ON DISPLAY_BG2_ACTIVE paulo@0: #define videoSetModeMenu(x) videoSetModeSub(x) paulo@0: #define MENU_GFX_PALETTE BG_PALETTE_SUB paulo@0: #define USING_TOUCH 1 paulo@0: #else paulo@0: #include paulo@0: #define MENU_GFX_CORE 0 paulo@0: #define MENU_GFX_VRAM(bank, tile) (TileSliver *)PATRAM4(bank, tile) paulo@0: #define MENU_GFX_MAP MAP paulo@0: #define MENU_GFX_BGCTRL BGCTRL paulo@0: #define MENU_GFX_OFFSET BG_OFFSET paulo@0: #define HIDDEN_ROWS 2 paulo@0: #define HIDDEN_COLS 1 paulo@0: #define videoSetModeMenu(x) (REG_DISPCNT = x) paulo@0: #define MODE_0_2D 0 paulo@0: #define MENU_GFX_PALETTE BG_PALETTE paulo@0: #define USING_TOUCH 0 paulo@0: #endif paulo@0: paulo@0: static const VWFWindow vwfLayer0 = { paulo@0: .left = 0, .top = 0, .width = 32, .height = 24, paulo@0: .chrBase = MENU_GFX_VRAM(0, 0), paulo@0: .map = 30, paulo@0: .core = MENU_GFX_CORE, paulo@0: .mapTileBase = 0 paulo@0: }; paulo@0: paulo@0: static const VWFWindow vwfLayer1 = { paulo@0: .left = 0, .top = 0, .width = 32, .height = 24, paulo@0: .chrBase = MENU_GFX_VRAM(2, 0), paulo@0: .map = 31, paulo@0: .core = MENU_GFX_CORE, paulo@0: .mapTileBase = 0 paulo@0: }; paulo@0: paulo@0: paulo@0: void vsync(void); paulo@0: paulo@0: static const TileSliver gradientBackgroundDelta[8] = { paulo@0: 0x00000000, paulo@0: 0x10101010, paulo@0: 0x00000000, paulo@0: 0x01010101, paulo@0: 0x10101010, paulo@0: 0x01010101, paulo@0: 0x11111111, paulo@0: 0x10101010 paulo@0: }; paulo@0: paulo@0: /* Makes 12 gradient background tiles starting at dst. paulo@0: */ paulo@0: paulo@0: static void makeGradientBackgroundTiles(TileSliver *dst) { paulo@0: for (TileSliver tile = 0x11111111; paulo@0: tile < 0xDDDDDDDD; paulo@0: tile += 0x11111111) { paulo@0: for (unsigned int y = 0; y < 8; ++y) { paulo@0: *dst++ = tile + gradientBackgroundDelta[y]; paulo@0: } paulo@0: } paulo@0: } paulo@0: paulo@0: static void makeLayer2(void) { paulo@0: makeGradientBackgroundTiles(MENU_GFX_VRAM(2, 0x300)); paulo@0: for (int y = 0; y < 12; ++y) { paulo@0: for (int x = 0; x < 32; ++x) { paulo@0: MENU_GFX_MAP[29][y][x] = 0xE300 + y; paulo@0: } paulo@0: } paulo@0: for (int y = 0; y < 12; ++y) { paulo@0: for (int x = 0; x < 32; ++x) { paulo@0: MENU_GFX_MAP[29][y + 12][x] = 0xF300 + y; paulo@0: } paulo@0: } paulo@0: MENU_GFX_BGCTRL[2] = BG_TILE_BASE(2) | BG_MAP_BASE(29); paulo@0: MENU_GFX_OFFSET[2].x = HIDDEN_COLS * 8; paulo@0: MENU_GFX_OFFSET[2].y = HIDDEN_ROWS * 8; paulo@0: } paulo@0: paulo@0: paulo@0: paulo@0: /* paulo@0: Button palette: paulo@0: 0 transparent paulo@0: 1 White (button top) paulo@0: 2 Medium gray (button side) paulo@0: 3 Darkest gray (button bottom) paulo@0: 4 Light gray (button background) paulo@0: 5 Dark gray (button text aa, lower corner) paulo@0: 6 Black (button text) paulo@0: 7 Black paulo@0: paulo@0: This comes in both ordinary and highlighted versions. There are two copies of the highlighted text. paulo@0: paulo@0: */ paulo@0: paulo@0: static const TileSliver buttonSideTiles[16] = { paulo@0: 0x11111114, paulo@0: 0x11111142, paulo@0: 0x11111422, paulo@0: 0x44444222, paulo@0: 0x44444222, paulo@0: 0x44444222, paulo@0: 0x44444222, paulo@0: 0x44444222, paulo@0: 0x44444222, paulo@0: 0x44444222, paulo@0: 0x44444222, paulo@0: 0x44444222, paulo@0: 0x44444222, paulo@0: 0x33333522, paulo@0: 0x33333352, paulo@0: 0x33333335 paulo@0: }; paulo@0: paulo@0: static void loadButtonSideTiles(void) { paulo@0: for (int bank = 0; bank <= 2; bank += 2) { paulo@0: TileSliver *dst = MENU_GFX_VRAM(bank, 0x30C); paulo@0: memcpy(dst, buttonSideTiles, 32); paulo@0: memcpy(dst + 8, buttonSideTiles + 4, 32); paulo@0: memcpy(dst + 16, buttonSideTiles + 8, 32); paulo@0: } paulo@0: } paulo@0: paulo@0: static const u8 buttonIntensity[8] = paulo@0: {28, 31, 23, 15, 28, 19, 0, 0}; paulo@0: paulo@0: /** paulo@0: * Loads the unhighlighted (gray) button palette. paulo@0: */ paulo@0: static void loadButtonPalette(void) { paulo@0: for (int i = 0; i < 8; ++i) { paulo@0: unsigned int intensity = buttonIntensity[i]; paulo@0: paulo@0: MENU_GFX_PALETTE[192 + i] = intensity * RGB5(1, 1, 1); paulo@0: } paulo@0: } paulo@0: paulo@0: void ljmenu_setHilitePalette(int phase) { paulo@0: paulo@0: // generate triangle wave paulo@0: phase = (phase & 0x3F) ^ 0x20; paulo@0: if (phase & 0x20) { paulo@0: phase ^= 0x3F; paulo@0: } paulo@0: paulo@0: for (int i = 0; i < 8; ++i) { paulo@0: int intensity = buttonIntensity[i]; paulo@0: int intensity34 = (3 * intensity) >> 2; paulo@0: int rg = intensity34 + (phase >> 2) + 4; paulo@0: int b = rg >> 1; paulo@0: if (rg > 31) { paulo@0: rg = 31; paulo@0: } paulo@0: unsigned int c = RGB5(1, 1, 0) * rg + RGB5(0, 0, 1) * b; paulo@0: paulo@0: MENU_GFX_PALETTE[200 + i] = c; paulo@0: MENU_GFX_PALETTE[208 + i] = c; paulo@0: } paulo@0: } paulo@0: paulo@0: #define TILE_HFLIP 0x0400 paulo@0: paulo@0: void ljmenu_hiliteButton(int l, int t, int r, int b, int hilite) { paulo@0: hilite = hilite ? 0xD000 : 0xC000; paulo@0: paulo@0: /* Draw sides of button */ paulo@0: MENU_GFX_MAP[30][t][l] = 0x30C | hilite; paulo@0: MENU_GFX_MAP[30][t][r - 1] = 0x30C | TILE_HFLIP | hilite; paulo@0: for (int y = t + 1; y < b - 1; ++y) { paulo@0: MENU_GFX_MAP[30][y][l] = 0x30D | hilite; paulo@0: MENU_GFX_MAP[30][y][r - 1] = 0x30D | TILE_HFLIP | hilite; paulo@0: } paulo@0: MENU_GFX_MAP[30][b - 1][l] = 0x30E | hilite; paulo@0: MENU_GFX_MAP[30][b - 1][r - 1] = 0x30E | TILE_HFLIP | hilite; paulo@0: vwfPutMap(&vwfLayer0, l + 1, t, r - 1, b, hilite); paulo@0: } paulo@0: paulo@0: void ljmenu_drawButton(int l, int t, int r, int b, const char *text) { paulo@0: vwfRectfill(&vwfLayer0, paulo@0: l * 8 + 8, t * 8, r * 8 - 8, t * 8 + 3, 1); paulo@0: vwfRectfill(&vwfLayer0, paulo@0: l * 8 + 8, t * 8 + 3, r * 8 - 8, b * 8 - 3, 4); paulo@0: vwfRectfill(&vwfLayer0, paulo@0: l * 8 + 8, b * 8 - 3, r * 8 - 8, b * 8, 3); paulo@0: paulo@0: int w = fontdraw_strWidth(text); paulo@0: int x = l * 8 + (r - l) * 4 - w / 2; paulo@0: int y = t * 8 + (b - t) * 4 - 12 / 2; paulo@0: paulo@0: vwfPuts(&vwfLayer0, text, x, y); paulo@0: ljmenu_hiliteButton(l, t, r, b, 0); paulo@0: } paulo@0: paulo@0: static void makePalettes(void) { paulo@0: // make background layer palettes paulo@0: for (unsigned int i = 0; i <= 12; ++i) { paulo@0: int blue = 2 * i; paulo@0: MENU_GFX_PALETTE[225 + i]= RGB5(0, 0, blue); paulo@0: } paulo@0: for (unsigned int i = 0; i <= 12; ++i) { paulo@0: int red = ((i + 9) * 3) >> 1; paulo@0: MENU_GFX_PALETTE[241 + i]= RGB5(red, red / 2, 0); paulo@0: } paulo@0: paulo@0: MENU_GFX_PALETTE[1] = RGB5(21,21,23); paulo@0: MENU_GFX_PALETTE[2] = RGB5(31,31,31); paulo@0: MENU_GFX_PALETTE[3] = RGB5(31,31,31); paulo@0: loadButtonPalette(); paulo@0: } paulo@0: paulo@0: void ljmenu_cls(void) { paulo@0: vwfWinInit(&vwfLayer0); paulo@0: vwfPutMap(&vwfLayer0, 2, 4, 30, 22, 0xC000); paulo@0: } paulo@0: paulo@0: void ljmenu_init(void) { paulo@0: makeLayer2(); paulo@0: loadButtonSideTiles(); paulo@0: makePalettes(); paulo@0: ljmenu_cls(); paulo@0: MENU_GFX_BGCTRL[0] = BG_TILE_BASE(0) | BG_MAP_BASE(30); paulo@0: MENU_GFX_OFFSET[0].x = HIDDEN_COLS * 8; paulo@0: MENU_GFX_OFFSET[0].y = HIDDEN_ROWS * 8; paulo@0: MENU_GFX_BGCTRL[1] = BG_TILE_BASE(2) | BG_MAP_BASE(31); paulo@0: MENU_GFX_OFFSET[1].x = HIDDEN_COLS * 8; paulo@0: MENU_GFX_OFFSET[1].y = HIDDEN_ROWS * 8; paulo@0: videoSetModeMenu(MODE_0_2D | BG0_ON | BG1_ON | BG2_ON); paulo@0: } paulo@0: paulo@0: void ljmenu_freeze(void) { paulo@0: paulo@0: // Copy background paulo@0: memcpy(vwfLayer0.chrBase, vwfLayer1.chrBase, 240*160/2); paulo@0: paulo@0: // Copy map paulo@0: memcpy(MENU_GFX_MAP[30], MENU_GFX_MAP[31], sizeof(NAMETABLE)); paulo@0: } paulo@0: paulo@0: void ljmenu_setTitle(const char *topLeft, const char *topRight) { paulo@0: vwfRectfill(&vwfLayer0, 16, 16, 240, 16 + 12, 0); paulo@0: vwfPuts(&vwfLayer0, topLeft, 16, 16); paulo@0: if (topRight) { paulo@0: int x = 240 - fontdraw_strWidth(topRight); paulo@0: vwfPuts(&vwfLayer0, topRight, x, 16); paulo@0: } paulo@0: } paulo@0: paulo@0: static unsigned short tabsX; paulo@0: static unsigned short tabsPadding; paulo@0: #define TAB_TOP 32 paulo@0: #define TAB_BOTTOM 44 paulo@0: #define TAB_LEFT 16 paulo@0: #define TAB_RIGHT 240 paulo@0: paulo@0: void ljmenu_beginTabs(unsigned int padding) { paulo@0: tabsX = TAB_LEFT; paulo@0: tabsPadding = padding; paulo@0: } paulo@0: paulo@0: void ljmenu_addTab(const char *text, int hilite) { paulo@0: unsigned int bgColor = hilite ? 12 : 4; paulo@0: unsigned int w = text ? fontdraw_strWidth(text) : 0; paulo@0: unsigned int left = tabsX; paulo@0: unsigned int right = left + 2 * tabsPadding + w; paulo@0: paulo@0: if (right > TAB_RIGHT) { paulo@0: return; paulo@0: } paulo@0: vwfRectfill(&vwfLayer0, paulo@0: left, TAB_TOP, right, TAB_BOTTOM, paulo@0: bgColor); paulo@0: if (hilite) { paulo@0: vwfHline(&vwfLayer0, paulo@0: left, TAB_TOP, right, paulo@0: bgColor + 1); paulo@0: vwfVline(&vwfLayer0, paulo@0: left, TAB_TOP, TAB_BOTTOM, paulo@0: bgColor + 1); paulo@0: vwfVline(&vwfLayer0, paulo@0: right - 1, TAB_TOP, TAB_BOTTOM, paulo@0: bgColor + 1); paulo@0: } else { paulo@0: vwfHline(&vwfLayer0, paulo@0: left, TAB_BOTTOM - 1, right, paulo@0: bgColor + 1); paulo@0: } paulo@0: if (text) { paulo@0: vwfPuts(&vwfLayer0, text, left + tabsPadding, TAB_TOP); paulo@0: } paulo@0: tabsX = right; paulo@0: } paulo@0: paulo@0: void ljmenu_endTabs(void) { paulo@0: vwfRectfill(&vwfLayer0, paulo@0: tabsX, TAB_TOP, TAB_RIGHT, TAB_BOTTOM - 1, paulo@0: 4); paulo@0: vwfHline(&vwfLayer0, paulo@0: tabsX, TAB_BOTTOM - 1, TAB_RIGHT, paulo@0: 5); paulo@0: } paulo@0: paulo@0: #define PROPPANEL_TOP TAB_BOTTOM paulo@0: #define PROPPANEL_HT 12 paulo@0: #define PROPPANEL_ROWS 7 paulo@0: #define PROPPANEL_BOTTOM (PROPPANEL_TOP + PROPPANEL_HT * PROPPANEL_ROWS) paulo@0: paulo@0: void ljmenu_propPanelClear(unsigned int nRows) { paulo@0: if (nRows > PROPPANEL_ROWS) { paulo@0: nRows = PROPPANEL_ROWS; paulo@0: } paulo@0: int y = PROPPANEL_TOP + PROPPANEL_HT * nRows; paulo@0: vwfRectfill(&vwfLayer0, paulo@0: TAB_LEFT, PROPPANEL_TOP, TAB_RIGHT, y, paulo@0: 4); paulo@0: vwfRectfill(&vwfLayer0, paulo@0: TAB_LEFT, y, TAB_RIGHT, PROPPANEL_BOTTOM, paulo@0: 0); paulo@0: } paulo@0: paulo@0: void ljmenu_propPanelDrawRow(const char *name, const char *value, paulo@0: unsigned int y, unsigned int hilite) { paulo@0: if (y > PROPPANEL_ROWS) { paulo@0: return; paulo@0: } paulo@0: y = PROPPANEL_TOP + PROPPANEL_HT * y; paulo@0: unsigned int bgColor = hilite ? 12 : 4; paulo@0: paulo@0: vwfRectfill(&vwfLayer0, paulo@0: TAB_LEFT, y, TAB_RIGHT, y + PROPPANEL_HT, paulo@0: bgColor); paulo@0: if (hilite) { paulo@0: vwfRect(&vwfLayer0, paulo@0: TAB_LEFT, y, TAB_RIGHT, y + PROPPANEL_HT, paulo@0: bgColor + 1); paulo@0: } paulo@0: if (name) { paulo@0: vwfPuts(&vwfLayer0, name, TAB_LEFT + 8, y); paulo@0: } paulo@0: if (value) { paulo@0: int x = TAB_RIGHT - 8 - fontdraw_strWidth(value); paulo@0: vwfPuts(&vwfLayer0, value, x, y); paulo@0: } paulo@0: } paulo@0: paulo@0: static void roundrect(const VWFWindow *w, paulo@0: int l, int t, int r, int b, int c) { paulo@0: vwfRectfill(w, l, t + 2, r, b - 2, c); paulo@0: vwfHline(w, l + 2, t, r - 2, c); paulo@0: vwfHline(w, l + 1, t + 1, r - 1, c); paulo@0: vwfHline(w, l + 1, b - 2, r - 1, c); paulo@0: vwfHline(w, l + 2, b - 1, r - 2, c); paulo@0: } paulo@0: paulo@0: static void ljmenu_balloon(const char *text1, const char *text2, paulo@0: int l, int t, int r) { paulo@0: int b = t + (text2 ? 24 : 12); paulo@0: roundrect(&vwfLayer0, l, t, r, b, 4); paulo@0: vwfPuts(&vwfLayer0, text1, l + 4, t); paulo@0: if (text2) { paulo@0: vwfPuts(&vwfLayer0, text2, l + 4, t + 12); paulo@0: } paulo@0: } paulo@0: paulo@0: void ljmenu_propPanelDrawDesc(const char *text1, const char *text2) { paulo@0: ljmenu_balloon(text1, text2, TAB_LEFT, PROPPANEL_BOTTOM + 4, TAB_RIGHT); paulo@0: } paulo@0: paulo@0: void ljmenu_propPanelDrawHelp(const char *text1, const char *text2) { paulo@0: int y = text2 ? 176 - 24 : 176 - 12; paulo@0: ljmenu_balloon(text1, text2, TAB_LEFT, y, TAB_RIGHT); paulo@0: } paulo@0: paulo@0: #if 0 paulo@0: static void ljmenu_pressA(void) { paulo@0: int phase = 0; paulo@0: while (!(REG_KEYINPUT & KEY_A)) { paulo@0: ++phase; paulo@0: vsync(); paulo@0: ljmenu_setHilitePalette(phase); paulo@0: } paulo@0: while (REG_KEYINPUT & KEY_A) { paulo@0: ++phase; paulo@0: vsync(); paulo@0: ljmenu_setHilitePalette(phase); paulo@0: } paulo@0: } paulo@0: paulo@0: void ljmenuTest(void) { paulo@0: ljmenu_init(); paulo@0: ljmenu_cls(); paulo@0: ljmenu_setTitle("LOCKJAW 0.43", "© 2008 Damian Yerrick"); paulo@0: ljmenu_drawButton(22, 18, 22 + 8, 18 + 3, "OK"); paulo@0: ljmenu_hiliteButton(22, 18, 22 + 8, 18 + 3, 1); paulo@0: ljmenu_drawButton(13, 18, 13 + 8, 18 + 3, "Cancel"); paulo@0: ljmenu_drawButton(2, 8, 30, 11, paulo@0: "coming soon: the new look of LOCKJAW"); paulo@0: ljmenu_pressA(); paulo@0: paulo@0: ljmenu_cls(); paulo@0: ljmenu_setTitle("LOCKJAW 0.43", "© 2008 Damian Yerrick"); paulo@0: ljmenu_beginTabs(4); paulo@0: ljmenu_addTab("Game", 1); paulo@0: ljmenu_addTab("Well", 0); paulo@0: ljmenu_addTab("Move", 0); paulo@0: ljmenu_addTab("Line", 0); paulo@0: ljmenu_addTab("Ctrl", 0); paulo@0: ljmenu_addTab("Drop", 0); paulo@0: ljmenu_addTab("Disp", 0); paulo@0: ljmenu_endTabs(); paulo@0: ljmenu_propPanelClear(7); paulo@0: ljmenu_propPanelDrawRow("Gimmick", "Marathon", 0, 1); paulo@0: ljmenu_propPanelDrawRow("Mr. Gimmick", "Halo", 1, 0); paulo@0: ljmenu_propPanelDrawDesc("Goal or other game mode", paulo@0: "Play until you DIE."); paulo@0: ljmenu_propPanelDrawHelp("u d: move; l r: change; L R: page; Start: OK", paulo@0: NULL); paulo@0: ljmenu_pressA(); paulo@0: } paulo@0: paulo@0: #endif