cf6ffec1dee2c1852a4bdc17fe96c5cb200ba589
[gbajam22] / src / pc / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <ctype.h>
4 #include <assert.h>
5 #include "miniglut.h"
6 #include "game.h"
7 #include "gba.h"
8 #include "input.h"
9 #include "debug.h"
10
11 static void display(void);
12 static void vblank(void);
13 static void idle(void);
14 static void reshape(int x, int y);
15 static void keydown(unsigned char key, int x, int y);
16 static void keyup(unsigned char key, int x, int y);
17 static void skeydown(int key, int x, int y);
18 static void skeyup(int key, int x, int y);
19 static void mouse(int bn, int st, int x, int y);
20 static void motion(int x, int y);
21 static unsigned int next_pow2(unsigned int x);
22 static void set_fullscreen(int fs);
23 static void set_vsync(int vsync);
24
25 static unsigned int num_pressed;
26 static unsigned char keystate[256];
27
28 static unsigned long start_time;
29 static unsigned int modkeys;
30
31 static uint16_t bnstate, bnmask;
32
33 static float win_aspect;
34 static unsigned int tex;
35
36 static int tex_xsz, tex_ysz;
37 static uint32_t convbuf[240 * 160];
38
39 #ifdef __unix__
40 #include <GL/glx.h>
41 static Display *xdpy;
42 static Window xwin;
43
44 static void (*glx_swap_interval_ext)();
45 static void (*glx_swap_interval_sgi)();
46 #endif
47 #ifdef _WIN32
48 #include <windows.h>
49 static PROC wgl_swap_interval_ext;
50 #endif
51
52 int main(int argc, char **argv)
53 {
54         glutInit(&argc, argv);
55         glutInitWindowSize(960, 640);
56         glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
57         glutCreateWindow("GBAjam22 PC build");
58
59         glutDisplayFunc(display);
60         glutIdleFunc(idle);
61         glutReshapeFunc(reshape);
62         glutKeyboardFunc(keydown);
63         glutKeyboardUpFunc(keyup);
64         glutSpecialFunc(skeydown);
65         glutSpecialUpFunc(skeyup);
66         glutMouseFunc(mouse);
67         glutMotionFunc(motion);
68
69         glEnable(GL_TEXTURE_2D);
70         glEnable(GL_CULL_FACE);
71
72 #ifdef __unix__
73         xdpy = glXGetCurrentDisplay();
74         xwin = glXGetCurrentDrawable();
75
76         if(!(glx_swap_interval_ext = glXGetProcAddress((unsigned char*)"glXSwapIntervalEXT"))) {
77                 glx_swap_interval_sgi = glXGetProcAddress((unsigned char*)"glXSwapIntervalSGI");
78         }
79 #endif
80 #ifdef _WIN32
81         wgl_swap_interval_ext = wglGetProcAddress("wglSwapIntervalEXT");
82 #endif
83
84         glGenTextures(1, &tex);
85         glBindTexture(GL_TEXTURE_2D, tex);
86
87         tex_xsz = next_pow2(240);
88         tex_ysz = next_pow2(160);
89         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_xsz, tex_ysz, 0, GL_RGBA,
90                         GL_UNSIGNED_BYTE, 0);
91         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
92         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
93
94         glMatrixMode(GL_TEXTURE);
95         glLoadIdentity();
96         glScalef(240.0f / tex_xsz, 160.0f / tex_ysz, 1);
97
98         intr_disable();
99         interrupt(INTR_VBLANK, vblank);
100         unmask(INTR_VBLANK);
101         intr_enable();
102
103         if(init_screens() == -1) {
104                 fprintf(stderr, "failed to initialize screens");
105                 return 1;
106         }
107
108         if(change_screen(find_screen("game")) == -1) {
109                 fprintf(stderr, "failed to find game screen");
110                 return 1;
111         }
112
113         glutMainLoop();
114         return 0;
115 }
116
117 void select_input(uint16_t bmask)
118 {
119         bnstate = 0;
120         bnmask = bmask;
121 }
122
123 uint16_t get_input(void)
124 {
125         uint16_t s = bnstate;
126         bnstate = 0;
127         return s;
128 }
129
130 #define PACK_RGB32(r, g, b) \
131         ((((r) & 0xff) << 16) | (((g) & 0xff) << 8) | ((b) & 0xff) | 0xff000000)
132
133 #define UNPACK_R16(c)   (((c) >> 9) & 0xf8)
134 #define UNPACK_G16(c)   (((c) >> 3) & 0xf8)
135 #define UNPACK_B16(c)   (((c) << 3) & 0xf8)
136
137 void present(int buf)
138 {
139         int i, npix = 240 * 160;
140         uint32_t *dptr = convbuf;
141         uint8_t *sptr = buf ? gba_vram_lfb1 : gba_vram_lfb0;
142
143         for(i=0; i<npix; i++) {
144                 int idx = *sptr++;
145                 int r = UNPACK_R16(gba_bgpal[idx]);
146                 int g = UNPACK_G16(gba_bgpal[idx]);
147                 int b = UNPACK_B16(gba_bgpal[idx]);
148                 *dptr++ = PACK_RGB32(b, g, r);
149         }
150
151         glBindTexture(GL_TEXTURE_2D, tex);
152         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 240, 160, GL_RGBA,
153                         GL_UNSIGNED_BYTE, convbuf);
154
155         glMatrixMode(GL_MODELVIEW);
156         glLoadIdentity();
157         if(win_aspect >= 1.5f) {
158                 glScalef(1.5f / win_aspect, 1, 1);
159         } else {
160                 glScalef(1, win_aspect / 1.5f, 1);
161         }
162
163         glClear(GL_COLOR_BUFFER_BIT);
164
165         glBegin(GL_QUADS);
166         glTexCoord2f(0, 1);
167         glVertex2f(-1, -1);
168         glTexCoord2f(1, 1);
169         glVertex2f(1, -1);
170         glTexCoord2f(1, 0);
171         glVertex2f(1, 1);
172         glTexCoord2f(0, 0);
173         glVertex2f(-1, 1);
174         glEnd();
175
176         glutSwapBuffers();
177         assert(glGetError() == GL_NO_ERROR);
178 }
179
180 static void display(void)
181 {
182         if(curscr) {
183                 curscr->frame();
184         }
185 }
186
187 static void vblank(void)
188 {
189         vblperf_count++;
190
191         if(curscr && curscr->vblank) {
192                 curscr->vblank();
193         }
194 }
195
196 static void idle(void)
197 {
198         glutPostRedisplay();
199 }
200
201 static void reshape(int x, int y)
202 {
203         win_aspect = (float)x / (float)y;
204         glViewport(0, 0, x, y);
205 }
206
207 static int bnmap(int key)
208 {
209         switch(key) {
210         case GLUT_KEY_LEFT:
211                 return BN_LEFT;
212         case GLUT_KEY_RIGHT:
213                 return BN_RIGHT;
214         case GLUT_KEY_UP:
215                 return BN_UP;
216         case GLUT_KEY_DOWN:
217                 return BN_DOWN;
218         case 'x':
219                 return BN_A;
220         case 'z':
221                 return BN_B;
222         case 'a':
223                 return BN_LT;
224                 break;
225         case 's':
226                 return BN_RT;
227         case ' ':
228                 return BN_SELECT;
229         case '\n':
230                 return BN_START;
231         default:
232                 break;
233         }
234         return -1;
235 }
236
237 static void keydown(unsigned char key, int x, int y)
238 {
239         int bn = bnmap(key);
240         if(bn != -1) {
241                 bnstate |= bn;
242         }
243
244         if(key == 27) {
245                 exit(0);
246         }
247 }
248
249 static void keyup(unsigned char key, int x, int y)
250 {
251         int bn = bnmap(key);
252         if(bn != -1) {
253                 bnstate &= ~bn;
254         }
255 }
256
257 static void skeydown(int key, int x, int y)
258 {
259         int bn = bnmap(key);
260         if(bn != -1) {
261                 bnstate |= bn;
262         }
263 }
264
265 static void skeyup(int key, int x, int y)
266 {
267         int bn = bnmap(key);
268         if(bn != -1) {
269                 bnstate &= ~bn;
270         }
271 }
272
273 static int mbstate[3];
274 static int prev_x, prev_y;
275
276 static void mouse(int bn, int st, int x, int y)
277 {
278         int bidx = bn - GLUT_LEFT_BUTTON;
279         int press = st == GLUT_DOWN ? 1 : 0;
280
281         if(bidx < 3) {
282                 mbstate[bidx] = press;
283         }
284         prev_x = x;
285         prev_y = y;
286 }
287
288 static void motion(int x, int y)
289 {
290         int dx, dy;
291
292         dx = x - prev_x;
293         dy = y - prev_y;
294         prev_x = x;
295         prev_y = y;
296
297         if(!(dx | dy)) return;
298
299         if(mbstate[0]) {
300                 view_dtheta -= dx * 0x100;
301                 view_dphi -= dy * 0x100;
302         }
303         if(mbstate[2]) {
304                 view_zoom += dy * 0x100;
305                 if(view_zoom < 0) view_zoom = 0;
306         }
307 }
308
309 static unsigned int next_pow2(unsigned int x)
310 {
311         x--;
312         x |= x >> 1;
313         x |= x >> 2;
314         x |= x >> 4;
315         x |= x >> 8;
316         x |= x >> 16;
317         return x + 1;
318 }
319
320 static void set_fullscreen(int fs)
321 {
322         static int win_x, win_y;
323
324         if(fs) {
325                 if(win_x == 0) {
326                         win_x = glutGet(GLUT_WINDOW_WIDTH);
327                         win_y = glutGet(GLUT_WINDOW_HEIGHT);
328                         glutFullScreen();
329                 }
330         } else {
331                 if(win_x) {
332                         glutReshapeWindow(win_x, win_y);
333                         win_x = win_y = 0;
334                 }
335         }
336 }
337
338 #ifdef __unix__
339 static void set_vsync(int vsync)
340 {
341         vsync = vsync ? 1 : 0;
342         if(glx_swap_interval_ext) {
343                 glx_swap_interval_ext(xdpy, xwin, vsync);
344         } else if(glx_swap_interval_sgi) {
345                 glx_swap_interval_sgi(vsync);
346         }
347 }
348 #endif
349 #ifdef WIN32
350 static void set_vsync(int vsync)
351 {
352         if(wgl_swap_interval_ext) {
353                 wgl_swap_interval_ext(vsync ? 1 : 0);
354         }
355 }
356 #endif