fixed 8bit writes to vmem, unaligned data buffers, and started on
[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 #define MENU_HEIGHT             17
33 #define TRACK_HEIGHT    18
34 #define VP_HEIGHT               (160 - MENU_HEIGHT - TRACK_HEIGHT)
35
36 static void handle_keys(void);
37
38 extern struct { unsigned char r, g, b; } bgimg_cmap[];
39 extern unsigned char bgimg_pixels[];
40
41 static int32_t cam_theta = 0x10000, cam_phi = -0x8000;
42
43 static int show_obj = 1, show_del;
44
45 #define AXIS0   0x10000
46 #define AXIS1   0x80000
47
48 static struct xvertex gridaxes[] = {
49         {AXIS0, 0, 0,   0, 0, 0, 92},
50         {AXIS1, 0, 0,   0, 0, 0, 92},
51         {-AXIS0, 0, 0,  0, 0, 0, 92},
52         {-AXIS1, 0, 0,  0, 0, 0, 92},
53         {0, 0, AXIS0,   0, 0, 0, 93},
54         {0, 0, AXIS1,   0, 0, 0, 93},
55         {0, 0, -AXIS0,  0, 0, 0, 93},
56         {0, 0, -AXIS1,  0, 0, 0, 93},
57
58         {0, 0, 0,               0, 0, 0, 92},
59         {AXIS1, 0, 0,   0, 0, 0, 92},
60         {0, 0, 0,               0, 0, 0, 92},
61         {-AXIS1, 0, 0,  0, 0, 0, 92},
62         {0, 0, 0,               0, 0, 0, 93},
63         {0, 0, AXIS1,   0, 0, 0, 93},
64         {0, 0, -0,              0, 0, 0, 93},
65         {0, 0, -AXIS1,  0, 0, 0, 93},
66 };
67
68 int main(void)
69 {
70         int i;
71         unsigned int nframes = 0, backbuf;
72         uint16_t *cptr;
73         unsigned char r, g, b;
74         unsigned char *fbptr[2], *fb;
75
76         intr_init();
77         reset_msec_timer();
78         set_intr();
79
80         /* mode 4: 240x160 8bpp */
81         REG_DISPCNT = DISPCNT_BG2 | DISPCNT_OBJ | 4;
82
83         fbptr[0] = (unsigned char*)VRAM_LFB_FB0_ADDR;
84         fbptr[1] = (unsigned char*)VRAM_LFB_FB1_ADDR;
85
86         set_bg_color(0xff, 31, 31, 31);
87
88         cptr = (uint16_t*)CRAM_BG_ADDR;
89         for(i=0; i<128; i++) {
90                 r = bgimg_cmap[i].r >> 3;
91                 g = bgimg_cmap[i].g >> 3;
92                 b = bgimg_cmap[i].b >> 3;
93                 *cptr++ = r | (g << 5) | (b << 10);
94         }
95         for(i=0; i<128; i++) {
96                 r = i / 5 + 6;
97                 *cptr++ = r | (r << 5) | (r << 10);
98         }
99         dma_copy16(3, fbptr[0], bgimg_pixels, 240 * 160 / 2);
100         dma_copy16(3, fbptr[1], bgimg_pixels, 240 * 160 / 2);
101
102         init_sprites();
103         set_sprite(0, 0, 512, 42, 42, 0, SPR_SZ64);
104
105         xgl_init();
106         xgl_viewport(0, 0, 240, VP_HEIGHT);
107         xgl_enable(XGL_LIGHTING);
108
109         key_repeat(75, 75, KEY_LEFT | KEY_RIGHT | KEY_DOWN | KEY_UP);
110
111         for(;;) {
112                 handle_keys();
113
114                 backbuf = ++nframes & 1;
115
116                 fb = fbptr[backbuf] + 240 * MENU_HEIGHT;
117                 polyfill_framebuffer(fb, 240, VP_HEIGHT);
118                 memset(fb, 14, 240 * VP_HEIGHT);
119
120                 xgl_load_identity();
121                 xgl_translate(0, 0, 8 << 16);
122                 xgl_rotate_x(cam_phi);
123                 xgl_rotate_y(cam_theta);
124
125                 if(show_obj) {
126                         if(cam_theta < X_PI) {
127                                 xgl_draw(XGL_LINES, gridaxes + 2, 2);   /* -X */
128                         } else {
129                                 xgl_draw(XGL_LINES, gridaxes, 2);               /* +X */
130                         }
131                         if(cam_theta < X_HPI || cam_theta > (3 * X_HPI)) {
132                                 xgl_draw(XGL_LINES, gridaxes + 4, 2);   /* +Z */
133                         } else {
134                                 xgl_draw(XGL_LINES, gridaxes + 6, 2);   /* -Z */
135                         }
136                         if(show_obj == 1) {
137                                 xgl_draw(XGL_QUADS, cube, sizeof cube / sizeof *cube);
138                         } else {
139                                 xgl_draw(XGL_TRIANGLES, suzanne, sizeof suzanne / sizeof *suzanne);
140                         }
141                         if(cam_theta < X_PI) {
142                                 xgl_draw(XGL_LINES, gridaxes, 2);               /* +X */
143                         } else {
144                                 xgl_draw(XGL_LINES, gridaxes + 2, 2);   /* -X */
145                         }
146                         if(cam_theta < X_HPI || cam_theta > (3 * X_HPI)) {
147                                 xgl_draw(XGL_LINES, gridaxes + 6, 2);   /* -Z */
148                         } else {
149                                 xgl_draw(XGL_LINES, gridaxes + 4, 2);   /* +Z */
150                         }
151                 } else {
152                         xgl_draw(XGL_LINES, gridaxes + 8, 8);
153                 }
154
155                 wait_vblank();
156                 present(backbuf);
157         }
158
159         return 0;
160 }
161
162 static void handle_keys(void)
163 {
164         update_keyb();
165
166         if(KEYPRESS(KEY_UP)) {
167                 cam_phi += 0x2000;
168                 if(cam_phi > X_HPI) cam_phi = X_HPI;
169         }
170         if(KEYPRESS(KEY_DOWN)) {
171                 cam_phi -= 0x2000;
172                 if(cam_phi < -X_HPI) cam_phi = -X_HPI;
173         }
174         if(KEYPRESS(KEY_LEFT)) {
175                 cam_theta += 0x2000;
176                 if(cam_theta > X_2PI) cam_theta -= X_2PI;
177         }
178         if(KEYPRESS(KEY_RIGHT)) {
179                 cam_theta -= 0x2000;
180                 if(cam_theta < 0) cam_theta += X_2PI;
181         }
182         if(KEYPRESS(KEY_RT)) {
183                 if(++show_obj > 2) show_obj = 0;
184         }
185         if(KEYPRESS(KEY_LT)) {
186                 if(--show_obj < 0) show_obj = 2;
187         }
188
189         if(KEYPRESS(KEY_A)) {
190                 show_del ^= 1;
191         }
192         if(KEYPRESS(KEY_B)) {
193                 if(show_del) {
194                         show_obj = 0;
195                         show_del = 0;
196                 }
197         }
198 }