diff src/gbamenus.c @ 0:c84446dfb3f5

initial add
author paulo@localhost
date Fri, 13 Mar 2009 00:39:12 -0700
parents
children
line diff
     1.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     1.2 +++ b/src/gbamenus.c	Fri Mar 13 00:39:12 2009 -0700
     1.3 @@ -0,0 +1,458 @@
     1.4 +/*
     1.5 +
     1.6 +BGCTRL layout
     1.7 +Layer 0: Current menu
     1.8 +Layer 1: Menu that is fading away
     1.9 +Layer 2: Gradient background
    1.10 +
    1.11 +VRAM layout
    1.12 +(1 map == 64 tiles)
    1.13 +Tiles 0.000-2FF: layer 0 bitmap
    1.14 +Tiles 0.300-3FF: unused
    1.15 +Tiles 2.000-2FF: layer 1 bitmap
    1.16 +Tiles 2.300-33F: unused
    1.17 +Tiles 2.340-36F: map 29 (layer 2)
    1.18 +Tiles 2.370-37F: layer 2 gradient tiles
    1.19 +Tiles 2.380-3FF: layer 0 map
    1.20 +Tiles 2.3C0-3FF: layer 1 map
    1.21 +
    1.22 +
    1.23 +*/
    1.24 +
    1.25 +#include <stdint.h>
    1.26 +#include <string.h>
    1.27 +#include "fontdraw.h"
    1.28 +typedef u32 TileSliver;
    1.29 +
    1.30 +#ifdef ARM9
    1.31 +#include <nds.h>
    1.32 +#define MENU_GFX_CORE 1
    1.33 +#define MENU_GFX_VRAM(bank, tile) (TileSliver *)(BG_TILE_RAM_SUB(bank) + 32 * tile)
    1.34 +#define MENU_GFX_MAP ((NAMETABLE *)0x06200000)
    1.35 +#define MENU_GFX_BGCTRL BGCTRL_SUB
    1.36 +#define MENU_GFX_OFFSET ((bg_scroll *)(0x04001010))
    1.37 +#define HIDDEN_ROWS 0
    1.38 +#define HIDDEN_COLS 0
    1.39 +#define BG0_ON DISPLAY_BG0_ACTIVE
    1.40 +#define BG1_ON DISPLAY_BG1_ACTIVE
    1.41 +#define BG2_ON DISPLAY_BG2_ACTIVE
    1.42 +#define videoSetModeMenu(x) videoSetModeSub(x)
    1.43 +#define MENU_GFX_PALETTE BG_PALETTE_SUB
    1.44 +#define USING_TOUCH 1
    1.45 +#else
    1.46 +#include <gba.h>
    1.47 +#define MENU_GFX_CORE 0
    1.48 +#define MENU_GFX_VRAM(bank, tile) (TileSliver *)PATRAM4(bank, tile)
    1.49 +#define MENU_GFX_MAP MAP
    1.50 +#define MENU_GFX_BGCTRL BGCTRL
    1.51 +#define MENU_GFX_OFFSET BG_OFFSET
    1.52 +#define HIDDEN_ROWS 2
    1.53 +#define HIDDEN_COLS 1
    1.54 +#define videoSetModeMenu(x) (REG_DISPCNT = x)
    1.55 +#define MODE_0_2D 0
    1.56 +#define MENU_GFX_PALETTE BG_PALETTE
    1.57 +#define USING_TOUCH 0
    1.58 +#endif
    1.59 +
    1.60 +static const VWFWindow vwfLayer0 = {
    1.61 +  .left = 0, .top = 0, .width = 32, .height = 24,
    1.62 +  .chrBase = MENU_GFX_VRAM(0, 0),
    1.63 +  .map = 30,
    1.64 +  .core = MENU_GFX_CORE,
    1.65 +  .mapTileBase = 0
    1.66 +};
    1.67 +
    1.68 +static const VWFWindow vwfLayer1 = {
    1.69 +  .left = 0, .top = 0, .width = 32, .height = 24,
    1.70 +  .chrBase = MENU_GFX_VRAM(2, 0),
    1.71 +  .map = 31,
    1.72 +  .core = MENU_GFX_CORE,
    1.73 +  .mapTileBase = 0
    1.74 +};
    1.75 +
    1.76 +
    1.77 +void vsync(void);
    1.78 +
    1.79 +static const TileSliver gradientBackgroundDelta[8] = {
    1.80 +  0x00000000,
    1.81 +  0x10101010,
    1.82 +  0x00000000,
    1.83 +  0x01010101,
    1.84 +  0x10101010,
    1.85 +  0x01010101,
    1.86 +  0x11111111,
    1.87 +  0x10101010
    1.88 +};
    1.89 +
    1.90 +/*  Makes 12 gradient background tiles starting at dst.
    1.91 +*/
    1.92 +
    1.93 +static void makeGradientBackgroundTiles(TileSliver *dst) {
    1.94 +  for (TileSliver tile = 0x11111111;
    1.95 +       tile < 0xDDDDDDDD;
    1.96 +       tile += 0x11111111) {
    1.97 +    for (unsigned int y = 0; y < 8; ++y) {
    1.98 +      *dst++ = tile + gradientBackgroundDelta[y];
    1.99 +    }
   1.100 +  }
   1.101 +}
   1.102 +
   1.103 +static void makeLayer2(void) {
   1.104 +  makeGradientBackgroundTiles(MENU_GFX_VRAM(2, 0x300));
   1.105 +  for (int y = 0; y < 12; ++y) {
   1.106 +    for (int x = 0; x < 32; ++x) {
   1.107 +      MENU_GFX_MAP[29][y][x] = 0xE300 + y;
   1.108 +    }
   1.109 +  }
   1.110 +  for (int y = 0; y < 12; ++y) {
   1.111 +    for (int x = 0; x < 32; ++x) {
   1.112 +      MENU_GFX_MAP[29][y + 12][x] = 0xF300 + y;
   1.113 +    }
   1.114 +  }
   1.115 +  MENU_GFX_BGCTRL[2] = BG_TILE_BASE(2) | BG_MAP_BASE(29);
   1.116 +  MENU_GFX_OFFSET[2].x = HIDDEN_COLS * 8;
   1.117 +  MENU_GFX_OFFSET[2].y = HIDDEN_ROWS * 8;
   1.118 +}
   1.119 +
   1.120 +
   1.121 +
   1.122 +/*
   1.123 +Button palette:
   1.124 +0 transparent
   1.125 +1 White (button top)
   1.126 +2 Medium gray (button side)
   1.127 +3 Darkest gray (button bottom)
   1.128 +4 Light gray (button background)
   1.129 +5 Dark gray (button text aa, lower corner)
   1.130 +6 Black (button text)
   1.131 +7 Black
   1.132 +
   1.133 +This comes in both ordinary and highlighted versions.  There are two copies of the highlighted text.
   1.134 +
   1.135 +*/
   1.136 +
   1.137 +static const TileSliver buttonSideTiles[16] = {
   1.138 +  0x11111114,
   1.139 +  0x11111142,
   1.140 +  0x11111422,
   1.141 +  0x44444222,
   1.142 +  0x44444222,
   1.143 +  0x44444222,
   1.144 +  0x44444222,
   1.145 +  0x44444222,
   1.146 +  0x44444222,
   1.147 +  0x44444222,
   1.148 +  0x44444222,
   1.149 +  0x44444222,
   1.150 +  0x44444222,
   1.151 +  0x33333522,
   1.152 +  0x33333352,
   1.153 +  0x33333335
   1.154 +};
   1.155 +
   1.156 +static void loadButtonSideTiles(void) {
   1.157 +  for (int bank = 0; bank <= 2; bank += 2) {
   1.158 +    TileSliver *dst = MENU_GFX_VRAM(bank, 0x30C);
   1.159 +    memcpy(dst, buttonSideTiles, 32);
   1.160 +    memcpy(dst + 8, buttonSideTiles + 4, 32);
   1.161 +    memcpy(dst + 16, buttonSideTiles + 8, 32);
   1.162 +  }
   1.163 +}
   1.164 +
   1.165 +static const u8 buttonIntensity[8] =
   1.166 +  {28, 31, 23, 15, 28, 19, 0, 0};
   1.167 +
   1.168 +/**
   1.169 + * Loads the unhighlighted (gray) button palette.
   1.170 + */
   1.171 +static void loadButtonPalette(void) {
   1.172 +  for (int i = 0; i < 8; ++i) {
   1.173 +    unsigned int intensity = buttonIntensity[i];
   1.174 +
   1.175 +    MENU_GFX_PALETTE[192 + i] = intensity * RGB5(1, 1, 1);
   1.176 +  }
   1.177 +}
   1.178 +
   1.179 +void ljmenu_setHilitePalette(int phase) {
   1.180 +
   1.181 +  // generate triangle wave
   1.182 +  phase = (phase & 0x3F) ^ 0x20;
   1.183 +  if (phase & 0x20) {
   1.184 +    phase ^= 0x3F;
   1.185 +  }
   1.186 +
   1.187 +  for (int i = 0; i < 8; ++i) {
   1.188 +    int intensity = buttonIntensity[i];
   1.189 +    int intensity34 = (3 * intensity) >> 2;
   1.190 +    int rg = intensity34 + (phase >> 2) + 4;
   1.191 +    int b = rg >> 1;
   1.192 +    if (rg > 31) {
   1.193 +      rg = 31;
   1.194 +    }
   1.195 +    unsigned int c = RGB5(1, 1, 0) * rg + RGB5(0, 0, 1) * b;
   1.196 +
   1.197 +    MENU_GFX_PALETTE[200 + i] = c;
   1.198 +    MENU_GFX_PALETTE[208 + i] = c;
   1.199 +  }
   1.200 +}
   1.201 +
   1.202 +#define TILE_HFLIP 0x0400
   1.203 +
   1.204 +void ljmenu_hiliteButton(int l, int t, int r, int b, int hilite) {
   1.205 +  hilite = hilite ? 0xD000 : 0xC000;
   1.206 +
   1.207 +  /* Draw sides of button */
   1.208 +  MENU_GFX_MAP[30][t][l] = 0x30C | hilite;
   1.209 +  MENU_GFX_MAP[30][t][r - 1] = 0x30C | TILE_HFLIP | hilite;
   1.210 +  for (int y = t + 1; y < b - 1; ++y) {
   1.211 +    MENU_GFX_MAP[30][y][l] = 0x30D | hilite;
   1.212 +    MENU_GFX_MAP[30][y][r - 1] = 0x30D | TILE_HFLIP | hilite;
   1.213 +  }
   1.214 +  MENU_GFX_MAP[30][b - 1][l] = 0x30E | hilite;
   1.215 +  MENU_GFX_MAP[30][b - 1][r - 1] = 0x30E | TILE_HFLIP | hilite;
   1.216 +  vwfPutMap(&vwfLayer0, l + 1, t, r - 1, b, hilite);
   1.217 +}
   1.218 +
   1.219 +void ljmenu_drawButton(int l, int t, int r, int b, const char *text) {
   1.220 +  vwfRectfill(&vwfLayer0,
   1.221 +              l * 8 + 8, t * 8, r * 8 - 8, t * 8 + 3, 1);
   1.222 +  vwfRectfill(&vwfLayer0,
   1.223 +              l * 8 + 8, t * 8 + 3, r * 8 - 8, b * 8 - 3, 4);
   1.224 +  vwfRectfill(&vwfLayer0,
   1.225 +              l * 8 + 8, b * 8 - 3, r * 8 - 8, b * 8, 3);
   1.226 +
   1.227 +  int w = fontdraw_strWidth(text);
   1.228 +  int x = l * 8 + (r - l) * 4 - w / 2;
   1.229 +  int y = t * 8 + (b - t) * 4 - 12 / 2;
   1.230 +
   1.231 +  vwfPuts(&vwfLayer0, text, x, y);
   1.232 +  ljmenu_hiliteButton(l, t, r, b, 0);
   1.233 +}
   1.234 +
   1.235 +static void makePalettes(void) {
   1.236 +  // make background layer palettes
   1.237 +  for (unsigned int i = 0; i <= 12; ++i) {
   1.238 +    int blue = 2 * i;
   1.239 +    MENU_GFX_PALETTE[225 + i]= RGB5(0, 0, blue);
   1.240 +  }
   1.241 +  for (unsigned int i = 0; i <= 12; ++i) {
   1.242 +    int red = ((i + 9) * 3) >> 1;
   1.243 +    MENU_GFX_PALETTE[241 + i]= RGB5(red, red / 2, 0);
   1.244 +  }
   1.245 +  
   1.246 +  MENU_GFX_PALETTE[1] = RGB5(21,21,23);
   1.247 +  MENU_GFX_PALETTE[2] = RGB5(31,31,31);
   1.248 +  MENU_GFX_PALETTE[3] = RGB5(31,31,31);
   1.249 +  loadButtonPalette();
   1.250 +}
   1.251 +
   1.252 +void ljmenu_cls(void) {
   1.253 +  vwfWinInit(&vwfLayer0);
   1.254 +  vwfPutMap(&vwfLayer0, 2, 4, 30, 22, 0xC000);
   1.255 +}
   1.256 +
   1.257 +void ljmenu_init(void) {
   1.258 +  makeLayer2();
   1.259 +  loadButtonSideTiles();
   1.260 +  makePalettes();
   1.261 +  ljmenu_cls();
   1.262 +  MENU_GFX_BGCTRL[0] = BG_TILE_BASE(0) | BG_MAP_BASE(30);
   1.263 +  MENU_GFX_OFFSET[0].x = HIDDEN_COLS * 8;
   1.264 +  MENU_GFX_OFFSET[0].y = HIDDEN_ROWS * 8;
   1.265 +  MENU_GFX_BGCTRL[1] = BG_TILE_BASE(2) | BG_MAP_BASE(31);
   1.266 +  MENU_GFX_OFFSET[1].x = HIDDEN_COLS * 8;
   1.267 +  MENU_GFX_OFFSET[1].y = HIDDEN_ROWS * 8;
   1.268 +  videoSetModeMenu(MODE_0_2D | BG0_ON | BG1_ON | BG2_ON);
   1.269 +}
   1.270 +
   1.271 +void ljmenu_freeze(void) {
   1.272 +
   1.273 +  // Copy background
   1.274 +  memcpy(vwfLayer0.chrBase, vwfLayer1.chrBase, 240*160/2);
   1.275 +
   1.276 +  // Copy map
   1.277 +  memcpy(MENU_GFX_MAP[30], MENU_GFX_MAP[31], sizeof(NAMETABLE));
   1.278 +}
   1.279 +
   1.280 +void ljmenu_setTitle(const char *topLeft, const char *topRight) {
   1.281 +  vwfRectfill(&vwfLayer0, 16, 16, 240, 16 + 12, 0);
   1.282 +  vwfPuts(&vwfLayer0, topLeft, 16, 16);
   1.283 +  if (topRight) {
   1.284 +    int x = 240 - fontdraw_strWidth(topRight);
   1.285 +    vwfPuts(&vwfLayer0, topRight, x, 16);
   1.286 +  }
   1.287 +}
   1.288 +
   1.289 +static unsigned short tabsX;
   1.290 +static unsigned short tabsPadding;
   1.291 +#define TAB_TOP 32
   1.292 +#define TAB_BOTTOM 44
   1.293 +#define TAB_LEFT 16
   1.294 +#define TAB_RIGHT 240
   1.295 +
   1.296 +void ljmenu_beginTabs(unsigned int padding) {
   1.297 +  tabsX = TAB_LEFT;
   1.298 +  tabsPadding = padding;
   1.299 +}
   1.300 +
   1.301 +void ljmenu_addTab(const char *text, int hilite) {
   1.302 +  unsigned int bgColor = hilite ? 12 : 4;
   1.303 +  unsigned int w = text ? fontdraw_strWidth(text) : 0;
   1.304 +  unsigned int left = tabsX;
   1.305 +  unsigned int right = left + 2 * tabsPadding + w;
   1.306 +  
   1.307 +  if (right > TAB_RIGHT) {
   1.308 +    return;
   1.309 +  }
   1.310 +  vwfRectfill(&vwfLayer0,
   1.311 +              left, TAB_TOP, right, TAB_BOTTOM,
   1.312 +              bgColor);
   1.313 +  if (hilite) {
   1.314 +    vwfHline(&vwfLayer0,
   1.315 +             left, TAB_TOP, right,
   1.316 +             bgColor + 1);
   1.317 +    vwfVline(&vwfLayer0,
   1.318 +             left, TAB_TOP, TAB_BOTTOM,
   1.319 +             bgColor + 1);
   1.320 +    vwfVline(&vwfLayer0,
   1.321 +             right - 1, TAB_TOP, TAB_BOTTOM,
   1.322 +             bgColor + 1);
   1.323 +  } else {
   1.324 +    vwfHline(&vwfLayer0,
   1.325 +             left, TAB_BOTTOM - 1, right,
   1.326 +             bgColor + 1);
   1.327 +  }
   1.328 +  if (text) {
   1.329 +    vwfPuts(&vwfLayer0, text, left + tabsPadding, TAB_TOP);
   1.330 +  }
   1.331 +  tabsX = right;
   1.332 +}
   1.333 +
   1.334 +void ljmenu_endTabs(void) {
   1.335 +  vwfRectfill(&vwfLayer0,
   1.336 +              tabsX, TAB_TOP, TAB_RIGHT, TAB_BOTTOM - 1,
   1.337 +              4);
   1.338 +  vwfHline(&vwfLayer0,
   1.339 +           tabsX, TAB_BOTTOM - 1, TAB_RIGHT,
   1.340 +           5);
   1.341 +}
   1.342 +
   1.343 +#define PROPPANEL_TOP TAB_BOTTOM
   1.344 +#define PROPPANEL_HT 12
   1.345 +#define PROPPANEL_ROWS 7
   1.346 +#define PROPPANEL_BOTTOM (PROPPANEL_TOP + PROPPANEL_HT * PROPPANEL_ROWS)
   1.347 +
   1.348 +void ljmenu_propPanelClear(unsigned int nRows) {
   1.349 +  if (nRows > PROPPANEL_ROWS) {
   1.350 +    nRows = PROPPANEL_ROWS;
   1.351 +  }
   1.352 +  int y = PROPPANEL_TOP + PROPPANEL_HT * nRows;
   1.353 +  vwfRectfill(&vwfLayer0,
   1.354 +              TAB_LEFT, PROPPANEL_TOP, TAB_RIGHT, y,
   1.355 +              4);
   1.356 +  vwfRectfill(&vwfLayer0,
   1.357 +              TAB_LEFT, y, TAB_RIGHT, PROPPANEL_BOTTOM,
   1.358 +              0);
   1.359 +}
   1.360 +
   1.361 +void ljmenu_propPanelDrawRow(const char *name, const char *value,
   1.362 +                             unsigned int y, unsigned int hilite) {
   1.363 +  if (y > PROPPANEL_ROWS) {
   1.364 +    return;
   1.365 +  }
   1.366 +  y = PROPPANEL_TOP + PROPPANEL_HT * y;
   1.367 +  unsigned int bgColor = hilite ? 12 : 4;
   1.368 +  
   1.369 +  vwfRectfill(&vwfLayer0,
   1.370 +              TAB_LEFT, y, TAB_RIGHT, y + PROPPANEL_HT,
   1.371 +              bgColor);
   1.372 +  if (hilite) {
   1.373 +    vwfRect(&vwfLayer0,
   1.374 +            TAB_LEFT, y, TAB_RIGHT, y + PROPPANEL_HT,
   1.375 +            bgColor + 1);
   1.376 +  }
   1.377 +  if (name) {
   1.378 +    vwfPuts(&vwfLayer0, name, TAB_LEFT + 8, y);
   1.379 +  }
   1.380 +  if (value) {
   1.381 +    int x = TAB_RIGHT - 8 - fontdraw_strWidth(value);
   1.382 +    vwfPuts(&vwfLayer0, value, x, y);
   1.383 +  }
   1.384 +}
   1.385 +
   1.386 +static void roundrect(const VWFWindow *w,
   1.387 +                      int l, int t, int r, int b, int c) {
   1.388 +  vwfRectfill(w, l, t + 2, r, b - 2, c);
   1.389 +  vwfHline(w, l + 2, t, r - 2, c);
   1.390 +  vwfHline(w, l + 1, t + 1, r - 1, c);
   1.391 +  vwfHline(w, l + 1, b - 2, r - 1, c);
   1.392 +  vwfHline(w, l + 2, b - 1, r - 2, c);
   1.393 +}
   1.394 +
   1.395 +static void ljmenu_balloon(const char *text1, const char *text2,
   1.396 +                           int l, int t, int r) {
   1.397 +  int b = t + (text2 ? 24 : 12);
   1.398 +  roundrect(&vwfLayer0, l, t, r, b, 4);
   1.399 +  vwfPuts(&vwfLayer0, text1, l + 4, t);
   1.400 +  if (text2) {
   1.401 +    vwfPuts(&vwfLayer0, text2, l + 4, t + 12);
   1.402 +  }
   1.403 +}
   1.404 +
   1.405 +void ljmenu_propPanelDrawDesc(const char *text1, const char *text2) {
   1.406 +  ljmenu_balloon(text1, text2, TAB_LEFT, PROPPANEL_BOTTOM + 4, TAB_RIGHT);
   1.407 +}
   1.408 +
   1.409 +void ljmenu_propPanelDrawHelp(const char *text1, const char *text2) {
   1.410 +  int y = text2 ? 176 - 24 : 176 - 12;
   1.411 +  ljmenu_balloon(text1, text2, TAB_LEFT, y, TAB_RIGHT);
   1.412 +}
   1.413 +
   1.414 +#if 0
   1.415 +static void ljmenu_pressA(void) {
   1.416 +  int phase = 0;
   1.417 +  while (!(REG_KEYINPUT & KEY_A)) {
   1.418 +    ++phase;
   1.419 +    vsync();
   1.420 +    ljmenu_setHilitePalette(phase);
   1.421 +  }
   1.422 +  while (REG_KEYINPUT & KEY_A) {
   1.423 +    ++phase;
   1.424 +    vsync();
   1.425 +    ljmenu_setHilitePalette(phase);
   1.426 +  }
   1.427 +}
   1.428 +
   1.429 +void ljmenuTest(void) {
   1.430 +  ljmenu_init();
   1.431 +  ljmenu_cls();
   1.432 +  ljmenu_setTitle("LOCKJAW 0.43", "© 2008 Damian Yerrick");
   1.433 +  ljmenu_drawButton(22, 18, 22 + 8, 18 + 3, "OK");
   1.434 +  ljmenu_hiliteButton(22, 18, 22 + 8, 18 + 3, 1);
   1.435 +  ljmenu_drawButton(13, 18, 13 + 8, 18 + 3, "Cancel");
   1.436 +  ljmenu_drawButton(2, 8, 30, 11,
   1.437 +                    "coming soon: the new look of LOCKJAW");
   1.438 +  ljmenu_pressA();
   1.439 +  
   1.440 +  ljmenu_cls();
   1.441 +  ljmenu_setTitle("LOCKJAW 0.43", "© 2008 Damian Yerrick");
   1.442 +  ljmenu_beginTabs(4);
   1.443 +  ljmenu_addTab("Game", 1);
   1.444 +  ljmenu_addTab("Well", 0);
   1.445 +  ljmenu_addTab("Move", 0);
   1.446 +  ljmenu_addTab("Line", 0);
   1.447 +  ljmenu_addTab("Ctrl", 0);
   1.448 +  ljmenu_addTab("Drop", 0);
   1.449 +  ljmenu_addTab("Disp", 0);
   1.450 +  ljmenu_endTabs();
   1.451 +  ljmenu_propPanelClear(7);
   1.452 +  ljmenu_propPanelDrawRow("Gimmick", "Marathon", 0, 1);
   1.453 +  ljmenu_propPanelDrawRow("Mr. Gimmick", "Halo", 1, 0);
   1.454 +  ljmenu_propPanelDrawDesc("Goal or other game mode",
   1.455 +                           "Play until you <Ganon>DIE.</Ganon>");
   1.456 +  ljmenu_propPanelDrawHelp("u d: move; l r: change; L R: page; Start: OK",
   1.457 +                           NULL);
   1.458 +  ljmenu_pressA();
   1.459 +}
   1.460 +
   1.461 +#endif