- pngdump tool overlay multiple images (combine spritesheets)
[gba_blender] / src / main.c
1 /*
2 blender for the Gameboy Advance
3 Copyright (C) 2021  John Tsiombikas <nuclear@member.fsf.org>
4
5 This program is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program.  If not, see <https://www.gnu.org/licenses/>.
17 */
18 #include <stdlib.h>
19 #include <string.h>
20 #include "gbaregs.h"
21 #include "timer.h"
22 #include "keyb.h"
23 #include "intr.h"
24 #include "gfx.h"
25 #include "xgl.h"
26 #include "polyfill.h"
27 #include "debug.h"
28 #include "meshdata.h"
29 #include "sprites.h"
30 #include "dma.h"
31
32 enum {
33         SIDX_DEL0, SIDX_DEL1, SIDX_DEL2,
34         SIDX_TIME,
35         SIDX_ICONS_BASE
36 };
37
38 #define SNAM_START      512
39 enum {
40         SNAM_DEL0               = SNAM_START,
41         SNAM_DEL1               = SNAM_DEL0 + 8,
42         SNAM_DEL2               = SNAM_DEL1 + 8,
43         SNAM_ICON_ZOOM  = SNAM_START + 24,
44         SNAM_ICON_PAN   = SNAM_ICON_ZOOM + 4,
45         SNAM_ICON_ORBIT = SNAM_START + 32 * 4 + 24,     /* for tiles down, 24 across */
46         SNAM_ICON_X             = SNAM_START + 32 * 8 + 26,
47         SNAM_ICON_Y             = SNAM_ICON_X + 2,
48         SNAM_ICON_Z             = SNAM_ICON_Y + 2
49 };
50
51 #define MENU_HEIGHT             17
52 #define TRACK_HEIGHT    18
53 #define VP_HEIGHT               (160 - MENU_HEIGHT - TRACK_HEIGHT)
54
55 static void handle_keys(void);
56 static void show_msgbox(int en);
57
58 extern struct { unsigned char r, g, b; } bgimg_cmap[];
59 extern unsigned char bgimg_pixels[];
60
61 static int32_t cam_theta = 0x10000, cam_phi = -0x8000;
62
63 static int show_obj = 1, show_del;
64
65 #define AXIS0   0x10000
66 #define AXIS1   0x80000
67
68 static struct xvertex gridaxes[] = {
69         {AXIS0, 0, 0,   0, 0, 0, 92},
70         {AXIS1, 0, 0,   0, 0, 0, 92},
71         {-AXIS0, 0, 0,  0, 0, 0, 92},
72         {-AXIS1, 0, 0,  0, 0, 0, 92},
73         {0, 0, AXIS0,   0, 0, 0, 93},
74         {0, 0, AXIS1,   0, 0, 0, 93},
75         {0, 0, -AXIS0,  0, 0, 0, 93},
76         {0, 0, -AXIS1,  0, 0, 0, 93},
77
78         {0, 0, 0,               0, 0, 0, 92},
79         {AXIS1, 0, 0,   0, 0, 0, 92},
80         {0, 0, 0,               0, 0, 0, 92},
81         {-AXIS1, 0, 0,  0, 0, 0, 92},
82         {0, 0, 0,               0, 0, 0, 93},
83         {0, 0, AXIS1,   0, 0, 0, 93},
84         {0, 0, -0,              0, 0, 0, 93},
85         {0, 0, -AXIS1,  0, 0, 0, 93},
86 };
87
88 #define MAX_SIDX        8
89 static uint16_t oam[4 * MAX_SIDX];
90
91
92 int main(void)
93 {
94         int i;
95         unsigned int nframes = 0, backbuf;
96         uint16_t *cptr;
97         unsigned char r, g, b;
98         unsigned char *fbptr[2], *fb;
99
100         intr_init();
101         reset_msec_timer();
102         set_intr();
103
104         /* mode 4: 240x160 8bpp */
105         REG_DISPCNT = DISPCNT_BG2 | DISPCNT_OBJ | 4;
106
107         fbptr[0] = (unsigned char*)VRAM_LFB_FB0_ADDR;
108         fbptr[1] = (unsigned char*)VRAM_LFB_FB1_ADDR;
109
110         set_bg_color(0xff, 31, 31, 31);
111
112         cptr = (uint16_t*)CRAM_BG_ADDR;
113         for(i=0; i<128; i++) {
114                 r = bgimg_cmap[i].r >> 3;
115                 g = bgimg_cmap[i].g >> 3;
116                 b = bgimg_cmap[i].b >> 3;
117                 *cptr++ = r | (g << 5) | (b << 10);
118         }
119         for(i=0; i<128; i++) {
120                 r = i / 5 + 6;
121                 *cptr++ = r | (r << 5) | (r << 10);
122         }
123         dma_copy16(3, fbptr[0], bgimg_pixels, 240 * 160 / 2, 0);
124         dma_copy16(3, fbptr[1], bgimg_pixels, 240 * 160 / 2, 0);
125
126         init_sprites();
127         REG_BLDCNT = BLDCNT_ALPHA | BLDCNT_B_BG2;
128         REG_BLDALPHA = 0x040c;
129
130         set_sprite(oam, SIDX_ICONS_BASE, SNAM_ICON_ZOOM, 213, 57, 4, SPR_SZ32);
131         set_sprite(oam, SIDX_ICONS_BASE + 1, SNAM_ICON_PAN, 213, 81, 4, SPR_SZ32);
132         set_sprite(oam, SIDX_ICONS_BASE + 2, SNAM_ICON_ORBIT, 213, 103, 4, SPR_SZ32);
133
134         xgl_init();
135         xgl_viewport(0, 0, 240, VP_HEIGHT);
136         xgl_enable(XGL_LIGHTING);
137
138         key_repeat(75, 75, KEY_LEFT | KEY_RIGHT | KEY_DOWN | KEY_UP);
139
140         /* every vblank, copy the shadow OAM automatically */
141         /*dma_copy16(3, (void*)OAM_ADDR, oam, sizeof oam / 2, DMACNT_VBLANK |
142                         DMACNT_REPEAT | DMACNT_INC_RELOAD);*/
143
144         for(;;) {
145                 handle_keys();
146
147                 backbuf = ++nframes & 1;
148
149                 fb = fbptr[backbuf] + 240 * MENU_HEIGHT;
150                 polyfill_framebuffer(fb, 240, VP_HEIGHT);
151                 //memset(fb, 14, 240 * VP_HEIGHT);
152                 dma_fill16(3, fb, 0x0e0e, 240 * VP_HEIGHT / 2);
153
154                 xgl_load_identity();
155                 xgl_translate(0, 0, 8 << 16);
156                 xgl_rotate_x(cam_phi);
157                 xgl_rotate_y(cam_theta);
158
159                 if(show_obj) {
160                         if(cam_theta < X_PI) {
161                                 xgl_draw(XGL_LINES, gridaxes + 2, 2);   /* -X */
162                         } else {
163                                 xgl_draw(XGL_LINES, gridaxes, 2);               /* +X */
164                         }
165                         if(cam_theta < X_HPI || cam_theta > (3 * X_HPI)) {
166                                 xgl_draw(XGL_LINES, gridaxes + 4, 2);   /* +Z */
167                         } else {
168                                 xgl_draw(XGL_LINES, gridaxes + 6, 2);   /* -Z */
169                         }
170                         if(show_obj == 1) {
171                                 xgl_draw(XGL_QUADS, cube, sizeof cube / sizeof *cube);
172                         } else {
173                                 xgl_draw(XGL_TRIANGLES, suzanne, sizeof suzanne / sizeof *suzanne);
174                         }
175                         if(cam_theta < X_PI) {
176                                 xgl_draw(XGL_LINES, gridaxes, 2);               /* +X */
177                         } else {
178                                 xgl_draw(XGL_LINES, gridaxes + 2, 2);   /* -X */
179                         }
180                         if(cam_theta < X_HPI || cam_theta > (3 * X_HPI)) {
181                                 xgl_draw(XGL_LINES, gridaxes + 6, 2);   /* -Z */
182                         } else {
183                                 xgl_draw(XGL_LINES, gridaxes + 4, 2);   /* +Z */
184                         }
185                 } else {
186                         xgl_draw(XGL_LINES, gridaxes + 8, 8);
187                 }
188
189                 wait_vblank();
190                 present(backbuf);
191                 dma_copy16(3, (void*)OAM_ADDR, oam, sizeof oam / 2, 0);
192         }
193
194         return 0;
195 }
196
197 static void handle_keys(void)
198 {
199         update_keyb();
200
201         if(KEYPRESS(KEY_UP)) {
202                 cam_phi += 0x2000;
203                 if(cam_phi > X_HPI) cam_phi = X_HPI;
204         }
205         if(KEYPRESS(KEY_DOWN)) {
206                 cam_phi -= 0x2000;
207                 if(cam_phi < -X_HPI) cam_phi = -X_HPI;
208         }
209         if(KEYPRESS(KEY_LEFT)) {
210                 cam_theta += 0x2000;
211                 if(cam_theta > X_2PI) cam_theta -= X_2PI;
212         }
213         if(KEYPRESS(KEY_RIGHT)) {
214                 cam_theta -= 0x2000;
215                 if(cam_theta < 0) cam_theta += X_2PI;
216         }
217         if(KEYPRESS(KEY_RT)) {
218                 if(++show_obj > 2) show_obj = 0;
219         }
220         if(KEYPRESS(KEY_LT)) {
221                 if(--show_obj < 0) show_obj = 2;
222         }
223
224         if(KEYPRESS(KEY_A)) {
225                 if(!show_del) {
226                         if(show_obj) show_del = 1;
227                 } else {
228                         show_del = 0;
229                 }
230                 show_msgbox(show_del);
231         }
232         if(KEYPRESS(KEY_B)) {
233                 if(show_del) {
234                         show_obj = 0;
235                         show_del = 0;
236                         show_msgbox(0);
237                 }
238         }
239 }
240
241 static void show_msgbox(int en)
242 {
243         int i;
244
245         if(en) {
246                 for(i=0; i<3; i++) {
247                         set_sprite(oam, SIDX_DEL0 + i, SNAM_DEL0 + i * 8, 42 + i * 64, 50, 0,
248                                         SPR_SZ64 | SPR_BLEND);
249                 }
250         } else {
251                 for(i=0; i<3; i++) {
252                         set_sprite(oam, SIDX_DEL0 + i, 0, 0, 0, 0, 0);
253                 }
254         }
255 }