Mercurial > hg > index.fcgi > lj > lj046
view src/gbamenus.c @ 3:17286938e22a
change DS alt. rotate key to rotate twice
author | paulo@localhost |
---|---|
date | Wed, 08 Apr 2009 21:50:13 -0700 |
parents | |
children |
line source
1 /*
3 BGCTRL layout
4 Layer 0: Current menu
5 Layer 1: Menu that is fading away
6 Layer 2: Gradient background
8 VRAM layout
9 (1 map == 64 tiles)
10 Tiles 0.000-2FF: layer 0 bitmap
11 Tiles 0.300-3FF: unused
12 Tiles 2.000-2FF: layer 1 bitmap
13 Tiles 2.300-33F: unused
14 Tiles 2.340-36F: map 29 (layer 2)
15 Tiles 2.370-37F: layer 2 gradient tiles
16 Tiles 2.380-3FF: layer 0 map
17 Tiles 2.3C0-3FF: layer 1 map
20 */
22 #include <stdint.h>
23 #include <string.h>
24 #include "fontdraw.h"
25 typedef u32 TileSliver;
27 #ifdef ARM9
28 #include <nds.h>
29 #define MENU_GFX_CORE 1
30 #define MENU_GFX_VRAM(bank, tile) (TileSliver *)(BG_TILE_RAM_SUB(bank) + 32 * tile)
31 #define MENU_GFX_MAP ((NAMETABLE *)0x06200000)
32 #define MENU_GFX_BGCTRL BGCTRL_SUB
33 #define MENU_GFX_OFFSET ((bg_scroll *)(0x04001010))
34 #define HIDDEN_ROWS 0
35 #define HIDDEN_COLS 0
36 #define BG0_ON DISPLAY_BG0_ACTIVE
37 #define BG1_ON DISPLAY_BG1_ACTIVE
38 #define BG2_ON DISPLAY_BG2_ACTIVE
39 #define videoSetModeMenu(x) videoSetModeSub(x)
40 #define MENU_GFX_PALETTE BG_PALETTE_SUB
41 #define USING_TOUCH 1
42 #else
43 #include <gba.h>
44 #define MENU_GFX_CORE 0
45 #define MENU_GFX_VRAM(bank, tile) (TileSliver *)PATRAM4(bank, tile)
46 #define MENU_GFX_MAP MAP
47 #define MENU_GFX_BGCTRL BGCTRL
48 #define MENU_GFX_OFFSET BG_OFFSET
49 #define HIDDEN_ROWS 2
50 #define HIDDEN_COLS 1
51 #define videoSetModeMenu(x) (REG_DISPCNT = x)
52 #define MODE_0_2D 0
53 #define MENU_GFX_PALETTE BG_PALETTE
54 #define USING_TOUCH 0
55 #endif
57 static const VWFWindow vwfLayer0 = {
58 .left = 0, .top = 0, .width = 32, .height = 24,
59 .chrBase = MENU_GFX_VRAM(0, 0),
60 .map = 30,
61 .core = MENU_GFX_CORE,
62 .mapTileBase = 0
63 };
65 static const VWFWindow vwfLayer1 = {
66 .left = 0, .top = 0, .width = 32, .height = 24,
67 .chrBase = MENU_GFX_VRAM(2, 0),
68 .map = 31,
69 .core = MENU_GFX_CORE,
70 .mapTileBase = 0
71 };
74 void vsync(void);
76 static const TileSliver gradientBackgroundDelta[8] = {
77 0x00000000,
78 0x10101010,
79 0x00000000,
80 0x01010101,
81 0x10101010,
82 0x01010101,
83 0x11111111,
84 0x10101010
85 };
87 /* Makes 12 gradient background tiles starting at dst.
88 */
90 static void makeGradientBackgroundTiles(TileSliver *dst) {
91 for (TileSliver tile = 0x11111111;
92 tile < 0xDDDDDDDD;
93 tile += 0x11111111) {
94 for (unsigned int y = 0; y < 8; ++y) {
95 *dst++ = tile + gradientBackgroundDelta[y];
96 }
97 }
98 }
100 static void makeLayer2(void) {
101 makeGradientBackgroundTiles(MENU_GFX_VRAM(2, 0x300));
102 for (int y = 0; y < 12; ++y) {
103 for (int x = 0; x < 32; ++x) {
104 MENU_GFX_MAP[29][y][x] = 0xE300 + y;
105 }
106 }
107 for (int y = 0; y < 12; ++y) {
108 for (int x = 0; x < 32; ++x) {
109 MENU_GFX_MAP[29][y + 12][x] = 0xF300 + y;
110 }
111 }
112 MENU_GFX_BGCTRL[2] = BG_TILE_BASE(2) | BG_MAP_BASE(29);
113 MENU_GFX_OFFSET[2].x = HIDDEN_COLS * 8;
114 MENU_GFX_OFFSET[2].y = HIDDEN_ROWS * 8;
115 }
119 /*
120 Button palette:
121 0 transparent
122 1 White (button top)
123 2 Medium gray (button side)
124 3 Darkest gray (button bottom)
125 4 Light gray (button background)
126 5 Dark gray (button text aa, lower corner)
127 6 Black (button text)
128 7 Black
130 This comes in both ordinary and highlighted versions. There are two copies of the highlighted text.
132 */
134 static const TileSliver buttonSideTiles[16] = {
135 0x11111114,
136 0x11111142,
137 0x11111422,
138 0x44444222,
139 0x44444222,
140 0x44444222,
141 0x44444222,
142 0x44444222,
143 0x44444222,
144 0x44444222,
145 0x44444222,
146 0x44444222,
147 0x44444222,
148 0x33333522,
149 0x33333352,
150 0x33333335
151 };
153 static void loadButtonSideTiles(void) {
154 for (int bank = 0; bank <= 2; bank += 2) {
155 TileSliver *dst = MENU_GFX_VRAM(bank, 0x30C);
156 memcpy(dst, buttonSideTiles, 32);
157 memcpy(dst + 8, buttonSideTiles + 4, 32);
158 memcpy(dst + 16, buttonSideTiles + 8, 32);
159 }
160 }
162 static const u8 buttonIntensity[8] =
163 {28, 31, 23, 15, 28, 19, 0, 0};
165 /**
166 * Loads the unhighlighted (gray) button palette.
167 */
168 static void loadButtonPalette(void) {
169 for (int i = 0; i < 8; ++i) {
170 unsigned int intensity = buttonIntensity[i];
172 MENU_GFX_PALETTE[192 + i] = intensity * RGB5(1, 1, 1);
173 }
174 }
176 void ljmenu_setHilitePalette(int phase) {
178 // generate triangle wave
179 phase = (phase & 0x3F) ^ 0x20;
180 if (phase & 0x20) {
181 phase ^= 0x3F;
182 }
184 for (int i = 0; i < 8; ++i) {
185 int intensity = buttonIntensity[i];
186 int intensity34 = (3 * intensity) >> 2;
187 int rg = intensity34 + (phase >> 2) + 4;
188 int b = rg >> 1;
189 if (rg > 31) {
190 rg = 31;
191 }
192 unsigned int c = RGB5(1, 1, 0) * rg + RGB5(0, 0, 1) * b;
194 MENU_GFX_PALETTE[200 + i] = c;
195 MENU_GFX_PALETTE[208 + i] = c;
196 }
197 }
199 #define TILE_HFLIP 0x0400
201 void ljmenu_hiliteButton(int l, int t, int r, int b, int hilite) {
202 hilite = hilite ? 0xD000 : 0xC000;
204 /* Draw sides of button */
205 MENU_GFX_MAP[30][t][l] = 0x30C | hilite;
206 MENU_GFX_MAP[30][t][r - 1] = 0x30C | TILE_HFLIP | hilite;
207 for (int y = t + 1; y < b - 1; ++y) {
208 MENU_GFX_MAP[30][y][l] = 0x30D | hilite;
209 MENU_GFX_MAP[30][y][r - 1] = 0x30D | TILE_HFLIP | hilite;
210 }
211 MENU_GFX_MAP[30][b - 1][l] = 0x30E | hilite;
212 MENU_GFX_MAP[30][b - 1][r - 1] = 0x30E | TILE_HFLIP | hilite;
213 vwfPutMap(&vwfLayer0, l + 1, t, r - 1, b, hilite);
214 }
216 void ljmenu_drawButton(int l, int t, int r, int b, const char *text) {
217 vwfRectfill(&vwfLayer0,
218 l * 8 + 8, t * 8, r * 8 - 8, t * 8 + 3, 1);
219 vwfRectfill(&vwfLayer0,
220 l * 8 + 8, t * 8 + 3, r * 8 - 8, b * 8 - 3, 4);
221 vwfRectfill(&vwfLayer0,
222 l * 8 + 8, b * 8 - 3, r * 8 - 8, b * 8, 3);
224 int w = fontdraw_strWidth(text);
225 int x = l * 8 + (r - l) * 4 - w / 2;
226 int y = t * 8 + (b - t) * 4 - 12 / 2;
228 vwfPuts(&vwfLayer0, text, x, y);
229 ljmenu_hiliteButton(l, t, r, b, 0);
230 }
232 static void makePalettes(void) {
233 // make background layer palettes
234 for (unsigned int i = 0; i <= 12; ++i) {
235 int blue = 2 * i;
236 MENU_GFX_PALETTE[225 + i]= RGB5(0, 0, blue);
237 }
238 for (unsigned int i = 0; i <= 12; ++i) {
239 int red = ((i + 9) * 3) >> 1;
240 MENU_GFX_PALETTE[241 + i]= RGB5(red, red / 2, 0);
241 }
243 MENU_GFX_PALETTE[1] = RGB5(21,21,23);
244 MENU_GFX_PALETTE[2] = RGB5(31,31,31);
245 MENU_GFX_PALETTE[3] = RGB5(31,31,31);
246 loadButtonPalette();
247 }
249 void ljmenu_cls(void) {
250 vwfWinInit(&vwfLayer0);
251 vwfPutMap(&vwfLayer0, 2, 4, 30, 22, 0xC000);
252 }
254 void ljmenu_init(void) {
255 makeLayer2();
256 loadButtonSideTiles();
257 makePalettes();
258 ljmenu_cls();
259 MENU_GFX_BGCTRL[0] = BG_TILE_BASE(0) | BG_MAP_BASE(30);
260 MENU_GFX_OFFSET[0].x = HIDDEN_COLS * 8;
261 MENU_GFX_OFFSET[0].y = HIDDEN_ROWS * 8;
262 MENU_GFX_BGCTRL[1] = BG_TILE_BASE(2) | BG_MAP_BASE(31);
263 MENU_GFX_OFFSET[1].x = HIDDEN_COLS * 8;
264 MENU_GFX_OFFSET[1].y = HIDDEN_ROWS * 8;
265 videoSetModeMenu(MODE_0_2D | BG0_ON | BG1_ON | BG2_ON);
266 }
268 void ljmenu_freeze(void) {
270 // Copy background
271 memcpy(vwfLayer0.chrBase, vwfLayer1.chrBase, 240*160/2);
273 // Copy map
274 memcpy(MENU_GFX_MAP[30], MENU_GFX_MAP[31], sizeof(NAMETABLE));
275 }
277 void ljmenu_setTitle(const char *topLeft, const char *topRight) {
278 vwfRectfill(&vwfLayer0, 16, 16, 240, 16 + 12, 0);
279 vwfPuts(&vwfLayer0, topLeft, 16, 16);
280 if (topRight) {
281 int x = 240 - fontdraw_strWidth(topRight);
282 vwfPuts(&vwfLayer0, topRight, x, 16);
283 }
284 }
286 static unsigned short tabsX;
287 static unsigned short tabsPadding;
288 #define TAB_TOP 32
289 #define TAB_BOTTOM 44
290 #define TAB_LEFT 16
291 #define TAB_RIGHT 240
293 void ljmenu_beginTabs(unsigned int padding) {
294 tabsX = TAB_LEFT;
295 tabsPadding = padding;
296 }
298 void ljmenu_addTab(const char *text, int hilite) {
299 unsigned int bgColor = hilite ? 12 : 4;
300 unsigned int w = text ? fontdraw_strWidth(text) : 0;
301 unsigned int left = tabsX;
302 unsigned int right = left + 2 * tabsPadding + w;
304 if (right > TAB_RIGHT) {
305 return;
306 }
307 vwfRectfill(&vwfLayer0,
308 left, TAB_TOP, right, TAB_BOTTOM,
309 bgColor);
310 if (hilite) {
311 vwfHline(&vwfLayer0,
312 left, TAB_TOP, right,
313 bgColor + 1);
314 vwfVline(&vwfLayer0,
315 left, TAB_TOP, TAB_BOTTOM,
316 bgColor + 1);
317 vwfVline(&vwfLayer0,
318 right - 1, TAB_TOP, TAB_BOTTOM,
319 bgColor + 1);
320 } else {
321 vwfHline(&vwfLayer0,
322 left, TAB_BOTTOM - 1, right,
323 bgColor + 1);
324 }
325 if (text) {
326 vwfPuts(&vwfLayer0, text, left + tabsPadding, TAB_TOP);
327 }
328 tabsX = right;
329 }
331 void ljmenu_endTabs(void) {
332 vwfRectfill(&vwfLayer0,
333 tabsX, TAB_TOP, TAB_RIGHT, TAB_BOTTOM - 1,
334 4);
335 vwfHline(&vwfLayer0,
336 tabsX, TAB_BOTTOM - 1, TAB_RIGHT,
337 5);
338 }
340 #define PROPPANEL_TOP TAB_BOTTOM
341 #define PROPPANEL_HT 12
342 #define PROPPANEL_ROWS 7
343 #define PROPPANEL_BOTTOM (PROPPANEL_TOP + PROPPANEL_HT * PROPPANEL_ROWS)
345 void ljmenu_propPanelClear(unsigned int nRows) {
346 if (nRows > PROPPANEL_ROWS) {
347 nRows = PROPPANEL_ROWS;
348 }
349 int y = PROPPANEL_TOP + PROPPANEL_HT * nRows;
350 vwfRectfill(&vwfLayer0,
351 TAB_LEFT, PROPPANEL_TOP, TAB_RIGHT, y,
352 4);
353 vwfRectfill(&vwfLayer0,
354 TAB_LEFT, y, TAB_RIGHT, PROPPANEL_BOTTOM,
355 0);
356 }
358 void ljmenu_propPanelDrawRow(const char *name, const char *value,
359 unsigned int y, unsigned int hilite) {
360 if (y > PROPPANEL_ROWS) {
361 return;
362 }
363 y = PROPPANEL_TOP + PROPPANEL_HT * y;
364 unsigned int bgColor = hilite ? 12 : 4;
366 vwfRectfill(&vwfLayer0,
367 TAB_LEFT, y, TAB_RIGHT, y + PROPPANEL_HT,
368 bgColor);
369 if (hilite) {
370 vwfRect(&vwfLayer0,
371 TAB_LEFT, y, TAB_RIGHT, y + PROPPANEL_HT,
372 bgColor + 1);
373 }
374 if (name) {
375 vwfPuts(&vwfLayer0, name, TAB_LEFT + 8, y);
376 }
377 if (value) {
378 int x = TAB_RIGHT - 8 - fontdraw_strWidth(value);
379 vwfPuts(&vwfLayer0, value, x, y);
380 }
381 }
383 static void roundrect(const VWFWindow *w,
384 int l, int t, int r, int b, int c) {
385 vwfRectfill(w, l, t + 2, r, b - 2, c);
386 vwfHline(w, l + 2, t, r - 2, c);
387 vwfHline(w, l + 1, t + 1, r - 1, c);
388 vwfHline(w, l + 1, b - 2, r - 1, c);
389 vwfHline(w, l + 2, b - 1, r - 2, c);
390 }
392 static void ljmenu_balloon(const char *text1, const char *text2,
393 int l, int t, int r) {
394 int b = t + (text2 ? 24 : 12);
395 roundrect(&vwfLayer0, l, t, r, b, 4);
396 vwfPuts(&vwfLayer0, text1, l + 4, t);
397 if (text2) {
398 vwfPuts(&vwfLayer0, text2, l + 4, t + 12);
399 }
400 }
402 void ljmenu_propPanelDrawDesc(const char *text1, const char *text2) {
403 ljmenu_balloon(text1, text2, TAB_LEFT, PROPPANEL_BOTTOM + 4, TAB_RIGHT);
404 }
406 void ljmenu_propPanelDrawHelp(const char *text1, const char *text2) {
407 int y = text2 ? 176 - 24 : 176 - 12;
408 ljmenu_balloon(text1, text2, TAB_LEFT, y, TAB_RIGHT);
409 }
411 #if 0
412 static void ljmenu_pressA(void) {
413 int phase = 0;
414 while (!(REG_KEYINPUT & KEY_A)) {
415 ++phase;
416 vsync();
417 ljmenu_setHilitePalette(phase);
418 }
419 while (REG_KEYINPUT & KEY_A) {
420 ++phase;
421 vsync();
422 ljmenu_setHilitePalette(phase);
423 }
424 }
426 void ljmenuTest(void) {
427 ljmenu_init();
428 ljmenu_cls();
429 ljmenu_setTitle("LOCKJAW 0.43", "© 2008 Damian Yerrick");
430 ljmenu_drawButton(22, 18, 22 + 8, 18 + 3, "OK");
431 ljmenu_hiliteButton(22, 18, 22 + 8, 18 + 3, 1);
432 ljmenu_drawButton(13, 18, 13 + 8, 18 + 3, "Cancel");
433 ljmenu_drawButton(2, 8, 30, 11,
434 "coming soon: the new look of LOCKJAW");
435 ljmenu_pressA();
437 ljmenu_cls();
438 ljmenu_setTitle("LOCKJAW 0.43", "© 2008 Damian Yerrick");
439 ljmenu_beginTabs(4);
440 ljmenu_addTab("Game", 1);
441 ljmenu_addTab("Well", 0);
442 ljmenu_addTab("Move", 0);
443 ljmenu_addTab("Line", 0);
444 ljmenu_addTab("Ctrl", 0);
445 ljmenu_addTab("Drop", 0);
446 ljmenu_addTab("Disp", 0);
447 ljmenu_endTabs();
448 ljmenu_propPanelClear(7);
449 ljmenu_propPanelDrawRow("Gimmick", "Marathon", 0, 1);
450 ljmenu_propPanelDrawRow("Mr. Gimmick", "Halo", 1, 0);
451 ljmenu_propPanelDrawDesc("Goal or other game mode",
452 "Play until you <Ganon>DIE.</Ganon>");
453 ljmenu_propPanelDrawHelp("u d: move; l r: change; L R: page; Start: OK",
454 NULL);
455 ljmenu_pressA();
456 }
458 #endif