foo
[gbajam22] / src / gamescr.c
1 #include <stdlib.h>
2 #include <string.h>
3 #include "gbaregs.h"
4 #include "game.h"
5 #include "dma.h"
6 #include "util.h"
7 #include "intr.h"
8 #include "input.h"
9 #include "gba.h"
10 #include "sprite.h"
11 #include "debug.h"
12 #include "voxscape.h"
13 #include "data.h"
14
15 #define FOV             30
16 #define NEAR    2
17 #define FAR             85
18
19 static int gamescr_start(void);
20 static void gamescr_stop(void);
21 static void gamescr_frame(void);
22 static void gamescr_vblank(void);
23
24 static void update(void);
25 static void draw(void);
26
27 static struct screen gamescr = {
28         "game",
29         gamescr_start,
30         gamescr_stop,
31         gamescr_frame,
32         gamescr_vblank
33 };
34
35 static uint16_t *framebuf;
36
37 static int nframes, backbuf;
38 static uint16_t *vram[] = { gba_vram_lfb0, gba_vram_lfb1 };
39
40 static int32_t pos[2], angle, horizon = 80;
41 static struct voxscape *vox;
42
43 #define COLOR_HORIZON   192
44 #define COLOR_ZENITH    255
45
46 #define MAX_SPR         32
47 static uint16_t oam[4 * MAX_SPR];
48 static int dynspr_base, dynspr_count;
49
50 static int num_tur, total_tur;
51 static int energy;
52 #define MAX_ENERGY      5
53
54 struct screen *init_game_screen(void)
55 {
56         return &gamescr;
57 }
58
59 static int gamescr_start(void)
60 {
61         int i, sidx;
62
63         gba_setmode(4, DISPCNT_BG2 | DISPCNT_OBJ | DISPCNT_FB1);
64
65         vblperf_setcolor(0);
66
67         pos[0] = pos[1] = VOX_SZ << 15;
68
69         if(!(vox = vox_create(VOX_SZ, VOX_SZ, height_pixels, color_pixels))) {
70                 panic(get_pc(), "vox_create");
71         }
72         vox_proj(vox, FOV, NEAR, FAR);
73         vox_view(vox, pos[0], pos[1], -40, angle);
74
75         /* setup color image palette */
76         for(i=0; i<256; i++) {
77                 int r = color_cmap[i * 3];
78                 int g = color_cmap[i * 3 + 1];
79                 int b = color_cmap[i * 3 + 2];
80                 gba_bgpal[i] = (((uint16_t)b << 7) & 0x7c00) | (((uint16_t)g << 2) & 0x3e0) | (((uint16_t)r >> 3) & 0x1f);
81         }
82         /*
83         intr_disable();
84         interrupt(INTR_HBLANK, hblank);
85         REG_DISPSTAT |= DISPSTAT_IEN_HBLANK;
86         unmask(INTR_HBLANK);
87         intr_enable();
88         */
89
90         spr_setup(16, 16, spr_game_pixels, spr_game_cmap);
91         wait_vblank();
92         spr_clear();
93
94         for(i=0; i<MAX_SPR; i++) {
95                 spr_oam_clear(oam, i);
96         }
97
98         sidx = 0;
99         spr_oam(oam, sidx++, SPRID_CROSS, 120-8, 80-8, SPR_SZ16 | SPR_256COL);
100         spr_oam(oam, sidx++, SPRID_UIMID, 0, 144, SPR_VRECT | SPR_256COL);
101         spr_oam(oam, sidx++, SPRID_UIRIGHT, 48, 144, SPR_SZ16 | SPR_256COL);
102         spr_oam(oam, sidx++, SPRID_UILEFT, 168, 144, SPR_SZ16 | SPR_256COL);
103         spr_oam(oam, sidx++, SPRID_UITGT, 184, 144, SPR_SZ16 | SPR_256COL);
104         spr_oam(oam, sidx++, SPRID_UISLASH, 216, 144, SPR_VRECT | SPR_256COL);
105         dynspr_base = sidx;
106
107         wait_vblank();
108         dma_copy32(3, (void*)OAM_ADDR, oam, sidx * 2, 0);
109
110         num_tur = 0;
111         total_tur = 16;
112         energy = 5;
113
114         nframes = 0;
115         return 0;
116 }
117
118 static void gamescr_stop(void)
119 {
120         /*mask(INTR_HBLANK);*/
121 }
122
123 static void gamescr_frame(void)
124 {
125         backbuf = ++nframes & 1;
126         framebuf = vram[backbuf];
127
128         vox_framebuf(vox, 240, 160, framebuf, horizon);
129
130         update();
131         draw();
132
133         vblperf_end();
134         wait_vblank();
135         present(backbuf);
136
137         if(!(nframes & 15)) {
138                 emuprint("vbl: %d", vblperf_count);
139         }
140 #ifdef VBLBAR
141         vblperf_begin();
142 #else
143         vblperf_count = 0;
144 #endif
145 }
146
147 #define NS(x)   (SPRID_UINUM + ((x) << 1))
148 static int numspr[][2] = {
149         {NS(0),NS(0)}, {NS(0),NS(1)}, {NS(0),NS(2)}, {NS(0),NS(3)}, {NS(0),NS(4)},
150         {NS(0),NS(5)}, {NS(0),NS(6)}, {NS(0),NS(7)}, {NS(0),NS(8)}, {NS(0),NS(9)},
151         {NS(1),NS(0)}, {NS(1),NS(1)}, {NS(1),NS(2)}, {NS(1),NS(3)}, {NS(1),NS(4)},
152         {NS(1),NS(5)}, {NS(1),NS(6)}, {NS(1),NS(7)}, {NS(1),NS(8)}, {NS(1),NS(9)},
153         {NS(2),NS(0)}, {NS(2),NS(1)}, {NS(2),NS(2)}, {NS(2),NS(3)}, {NS(2),NS(4)},
154         {NS(2),NS(5)}, {NS(2),NS(6)}, {NS(2),NS(7)}, {NS(2),NS(8)}, {NS(2),NS(9)},
155         {NS(3),NS(0)}, {NS(3),NS(1)}, {NS(3),NS(2)}, {NS(3),NS(3)}, {NS(3),NS(4)},
156         {NS(3),NS(5)}, {NS(3),NS(6)}, {NS(3),NS(7)}, {NS(3),NS(8)}, {NS(3),NS(9)}
157 };
158
159 #define WALK_SPEED      0x40000
160 #define TURN_SPEED      0x200
161 #define ELEV_SPEED      8
162
163 static void update(void)
164 {
165         int32_t fwd[2], right[2];
166         int i, snum, ledspr;
167
168         update_keyb();
169
170         if(KEYPRESS(BN_SELECT)) {
171                 vox_quality ^= 1;
172         }
173
174         if(keystate) {
175                 if(keystate & BN_LEFT) {
176                         angle += TURN_SPEED;
177                 }
178                 if(keystate & BN_RIGHT) {
179                         angle -= TURN_SPEED;
180                 }
181
182                 fwd[0] = -SIN(angle);
183                 fwd[1] = COS(angle);
184                 right[0] = fwd[1];
185                 right[1] = -fwd[0];
186
187                 if(keystate & BN_A) {
188                         pos[0] += fwd[0];
189                         pos[1] += fwd[1];
190                 }
191                 /*
192                 if(keystate & BN_DOWN) {
193                         pos[0] -= fwd[0];
194                         pos[1] -= fwd[1];
195                 }
196                 */
197                 if(keystate & BN_UP) {
198                         if(horizon > 40) horizon -= ELEV_SPEED;
199                 }
200                 if(keystate & BN_DOWN) {
201                         if(horizon < 200 - ELEV_SPEED) horizon += ELEV_SPEED;
202                 }
203                 if(keystate & BN_RT) {
204                         pos[0] += right[0];
205                         pos[1] += right[1];
206                 }
207                 if(keystate & BN_LT) {
208                         pos[0] -= right[0];
209                         pos[1] -= right[1];
210                 }
211
212                 vox_view(vox, pos[0], pos[1], -40, angle);
213         }
214
215         snum = 0;
216         /* turrets number */
217         spr_oam(oam, dynspr_base + snum++, numspr[num_tur][0], 200, 144, SPR_VRECT | SPR_256COL);
218         spr_oam(oam, dynspr_base + snum++, numspr[num_tur][1], 208, 144, SPR_VRECT | SPR_256COL);
219         spr_oam(oam, dynspr_base + snum++, numspr[total_tur][0], 224, 144, SPR_VRECT | SPR_256COL);
220         spr_oam(oam, dynspr_base + snum++, numspr[total_tur][1], 232, 144, SPR_VRECT | SPR_256COL);
221         /* energy bar */
222         if(energy == MAX_ENERGY) {
223                 ledspr = SPRID_LEDBLU;
224         } else {
225                 ledspr = energy > 2 ? SPRID_LEDGRN : SPRID_LEDRED;
226         }
227         for(i=0; i<5; i++) {
228                 spr_oam(oam, dynspr_base + snum++, i >= energy ? SPRID_LEDOFF : ledspr,
229                                 8 + (i << 3), 144, SPR_VRECT | SPR_256COL);
230         }
231         /* enemy sprites */
232         spr_oam(oam, dynspr_base + snum++, SPRID_ENEMY, 50, 50, SPR_VRECT | SPR_SZ64 | SPR_256COL);
233
234         mask(INTR_VBLANK);
235         dynspr_count = snum;
236         unmask(INTR_VBLANK);
237 }
238
239 static void draw(void)
240 {
241         //dma_fill16(3, framebuf, 0, 240 * 160 / 2);
242         fillblock_16byte(framebuf, 0, 240 * 160 / 16);
243
244         vox_render(vox);
245         //vox_sky_grad(vox, COLOR_HORIZON, COLOR_ZENITH);
246         //vox_sky_solid(vox, COLOR_ZENITH);
247 }
248
249 #define OFFS(x, y)      ((y) * 128 + (x))
250 static short enemy_frame_offs[] = {
251         OFFS(0, 128), OFFS(32, 128), OFFS(64, 128), OFFS(96, 128),
252         OFFS(0, 192), OFFS(32, 192), OFFS(64, 192), OFFS(96, 192)
253 };
254
255 #define MAXBANK         0x100
256
257 ARM_IWRAM
258 static void gamescr_vblank(void)
259 {
260         static int bank, bankdir, theta, s;
261         int32_t sa, ca;
262         uint16_t *src, *dst;
263         int i;
264
265         if(!nframes) return;
266
267         /* TODO: pre-arrange sprite tiles in gba-native format, so that I can just
268          * DMA them from cartridge easily
269          */
270
271         /*
272         src = (void*)(spr_game_pixels + enemy_frame_offs[1]);
273         dst = (void*)(VRAM_LFB_OBJ_ADDR + SPRID(0, 64));
274         for(i=0; i<64; i++) {
275                 dma_copy32(3, dst, src, 32 / 4, 0);
276                 dst += 32 / 2;
277                 src += 128 / 2;
278         }
279         */
280
281         dma_copy32(3, (void*)(OAM_ADDR + dynspr_base * 8), oam + dynspr_base * 4, dynspr_count * 2, 0);
282
283         theta = -(bank << 3);
284 #if 0
285         s = 0x100000 / (MAXBANK + (abs(bank) >> 3));
286         sa = ((SIN(theta) >> 8) * s) >> 12;
287         ca = ((COS(theta) >> 8) * s) >> 12;
288 #else
289         s = (MAXBANK + (abs(bank) >> 3));
290         sa = SIN(theta) / s;
291         ca = COS(theta) / s;
292 #endif
293
294         REG_BG2X = -ca * 120 - sa * 80 + (120 << 8);
295         REG_BG2Y = sa * 120 - ca * 80 + (80 << 8);
296
297         REG_BG2PA = ca;
298         REG_BG2PB = sa;
299         REG_BG2PC = -sa;
300         REG_BG2PD = ca;
301
302         keystate = ~REG_KEYINPUT;
303
304         if((keystate & (BN_LEFT | BN_RIGHT)) == 0) {
305                 if(bank) {
306                         bank -= bankdir << 4;
307                 }
308         } else if(keystate & BN_LEFT) {
309                 bankdir = -1;
310                 if(bank > -MAXBANK) bank -= 16;
311         } else if(keystate & BN_RIGHT) {
312                 bankdir = 1;
313                 if(bank < MAXBANK) bank += 16;
314         }
315 }
316
317 /*
318 static uint16_t skygrad[] __attribute__((section(".data"))) = {
319
320         0x662a, 0x660a, 0x660a, 0x660b, 0x660b, 0x660b, 0x660b, 0x6a0b, 0x6a0c,
321         0x6a0c, 0x6a0c, 0x6a0c, 0x6a0c, 0x6a0d, 0x6a0d, 0x6a0d, 0x6a0d, 0x6a0d,
322         0x6a0d, 0x6a0e, 0x6e0e, 0x6e0e, 0x6e0e, 0x6e0e, 0x6e0f, 0x6e0f, 0x6e0f,
323         0x6e0f, 0x6e0f, 0x6e0f, 0x6e10, 0x6e10, 0x7210, 0x7210, 0x7210, 0x7211,
324         0x7211, 0x7211, 0x71f1, 0x71f1, 0x71f2, 0x71f2, 0x71f2, 0x71f2, 0x71f2,
325         0x75f2, 0x75f3, 0x75f3, 0x75f3, 0x75f3, 0x75f3, 0x75f4, 0x75f4, 0x75f4,
326         0x75f4, 0x75f4, 0x75f5, 0x79f5, 0x79f5, 0x79f5, 0x79f5, 0x79f5, 0x79f6,
327         0x79f6, 0x79f6, 0x79f6, 0x79f6, 0x79f7, 0x79f7, 0x79f7, 0x7df7, 0x7df7,
328         0x7df7, 0x7df8, 0x7df8, 0x7df8, 0x7dd8, 0x7dd8, 0x7dd9, 0x7dd9,
329
330         0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9,
331         0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9,
332         0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9,
333         0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9,
334         0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9,
335         0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9,
336         0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9,
337         0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9,
338         0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9, 0x7dd9
339 };
340
341 ARM_IWRAM
342 static void hblank(void)
343 {
344         int vcount = REG_VCOUNT;
345         gba_bgpal[255] = skygrad[vcount];
346 }
347 */