Mercurial > hg > index.fcgi > lj > lj046
comparison 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 |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:67f2bd4af9c7 |
---|---|
1 /* | |
2 | |
3 BGCTRL layout | |
4 Layer 0: Current menu | |
5 Layer 1: Menu that is fading away | |
6 Layer 2: Gradient background | |
7 | |
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 | |
18 | |
19 | |
20 */ | |
21 | |
22 #include <stdint.h> | |
23 #include <string.h> | |
24 #include "fontdraw.h" | |
25 typedef u32 TileSliver; | |
26 | |
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 | |
56 | |
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 }; | |
64 | |
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 }; | |
72 | |
73 | |
74 void vsync(void); | |
75 | |
76 static const TileSliver gradientBackgroundDelta[8] = { | |
77 0x00000000, | |
78 0x10101010, | |
79 0x00000000, | |
80 0x01010101, | |
81 0x10101010, | |
82 0x01010101, | |
83 0x11111111, | |
84 0x10101010 | |
85 }; | |
86 | |
87 /* Makes 12 gradient background tiles starting at dst. | |
88 */ | |
89 | |
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 } | |
99 | |
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 } | |
116 | |
117 | |
118 | |
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 | |
129 | |
130 This comes in both ordinary and highlighted versions. There are two copies of the highlighted text. | |
131 | |
132 */ | |
133 | |
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 }; | |
152 | |
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 } | |
161 | |
162 static const u8 buttonIntensity[8] = | |
163 {28, 31, 23, 15, 28, 19, 0, 0}; | |
164 | |
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]; | |
171 | |
172 MENU_GFX_PALETTE[192 + i] = intensity * RGB5(1, 1, 1); | |
173 } | |
174 } | |
175 | |
176 void ljmenu_setHilitePalette(int phase) { | |
177 | |
178 // generate triangle wave | |
179 phase = (phase & 0x3F) ^ 0x20; | |
180 if (phase & 0x20) { | |
181 phase ^= 0x3F; | |
182 } | |
183 | |
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; | |
193 | |
194 MENU_GFX_PALETTE[200 + i] = c; | |
195 MENU_GFX_PALETTE[208 + i] = c; | |
196 } | |
197 } | |
198 | |
199 #define TILE_HFLIP 0x0400 | |
200 | |
201 void ljmenu_hiliteButton(int l, int t, int r, int b, int hilite) { | |
202 hilite = hilite ? 0xD000 : 0xC000; | |
203 | |
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 } | |
215 | |
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); | |
223 | |
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; | |
227 | |
228 vwfPuts(&vwfLayer0, text, x, y); | |
229 ljmenu_hiliteButton(l, t, r, b, 0); | |
230 } | |
231 | |
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 } | |
242 | |
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 } | |
248 | |
249 void ljmenu_cls(void) { | |
250 vwfWinInit(&vwfLayer0); | |
251 vwfPutMap(&vwfLayer0, 2, 4, 30, 22, 0xC000); | |
252 } | |
253 | |
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 } | |
267 | |
268 void ljmenu_freeze(void) { | |
269 | |
270 // Copy background | |
271 memcpy(vwfLayer0.chrBase, vwfLayer1.chrBase, 240*160/2); | |
272 | |
273 // Copy map | |
274 memcpy(MENU_GFX_MAP[30], MENU_GFX_MAP[31], sizeof(NAMETABLE)); | |
275 } | |
276 | |
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 } | |
285 | |
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 | |
292 | |
293 void ljmenu_beginTabs(unsigned int padding) { | |
294 tabsX = TAB_LEFT; | |
295 tabsPadding = padding; | |
296 } | |
297 | |
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; | |
303 | |
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 } | |
330 | |
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 } | |
339 | |
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) | |
344 | |
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 } | |
357 | |
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; | |
365 | |
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 } | |
382 | |
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 } | |
391 | |
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 } | |
401 | |
402 void ljmenu_propPanelDrawDesc(const char *text1, const char *text2) { | |
403 ljmenu_balloon(text1, text2, TAB_LEFT, PROPPANEL_BOTTOM + 4, TAB_RIGHT); | |
404 } | |
405 | |
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 } | |
410 | |
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 } | |
425 | |
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(); | |
436 | |
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 } | |
457 | |
458 #endif |