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