starting to separate platform-specific code to facilitate a PC build
[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
8 static void display(void);
9 static void idle(void);
10 static void reshape(int x, int y);
11 static void keydown(unsigned char key, int x, int y);
12 static void keyup(unsigned char key, int x, int y);
13 static void skeydown(int key, int x, int y);
14 static void skeyup(int key, int x, int y);
15 static int translate_special(int skey);
16 static unsigned int next_pow2(unsigned int x);
17 static void set_fullscreen(int fs);
18 static void set_vsync(int vsync);
19
20 static unsigned int num_pressed;
21 static unsigned char keystate[256];
22
23 static unsigned long start_time;
24 static unsigned int modkeys;
25
26 static float win_aspect;
27 static unsigned int tex;
28
29 static int tex_xsz, tex_ysz;
30 static uint32_t convbuf[240 * 160];
31
32 #ifdef __unix__
33 #include <GL/glx.h>
34 static Display *xdpy;
35 static Window xwin;
36
37 static void (*glx_swap_interval_ext)();
38 static void (*glx_swap_interval_sgi)();
39 #endif
40 #ifdef _WIN32
41 #include <windows.h>
42 static PROC wgl_swap_interval_ext;
43 #endif
44
45 int main(int argc, char **argv)
46 {
47         glutInit(&argc, argv);
48         glutInitWindowSize(800, 600);
49         glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
50         glutCreateWindow("GBAjam22 PC build");
51
52         glutDisplayFunc(display);
53         glutIdleFunc(idle);
54         glutReshapeFunc(reshape);
55         glutKeyboardFunc(keydown);
56         glutKeyboardUpFunc(keyup);
57         glutSpecialFunc(skeydown);
58         glutSpecialUpFunc(skeyup);
59
60         glutSetCursor(GLUT_CURSOR_NONE);
61
62         glEnable(GL_TEXTURE_2D);
63         glEnable(GL_CULL_FACE);
64
65 #ifdef __unix__
66         xdpy = glXGetCurrentDisplay();
67         xwin = glXGetCurrentDrawable();
68
69         if(!(glx_swap_interval_ext = glXGetProcAddress((unsigned char*)"glXSwapIntervalEXT"))) {
70                 glx_swap_interval_sgi = glXGetProcAddress((unsigned char*)"glXSwapIntervalSGI");
71         }
72 #endif
73 #ifdef _WIN32
74         wgl_swap_interval_ext = wglGetProcAddress("wglSwapIntervalEXT");
75 #endif
76
77         glGenTextures(1, &tex);
78         glBindTexture(GL_TEXTURE_2D, tex);
79
80         tex_xsz = next_pow2(240);
81         tex_ysz = next_pow2(160);
82         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_xsz, tex_ysz, 0, GL_RGBA,
83                         GL_UNSIGNED_BYTE, 0);
84         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
85         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
86
87         glMatrixMode(GL_TEXTURE);
88         glLoadIdentity();
89         glScalef(240.0f / tex_xsz, 160.0f / tex_ysz, 1);
90
91         gamescr();
92         return 0;
93 }
94
95 void blit_frame(void *pixels, int vsync)
96 {
97         int i, npix = fb_width * fb_height;
98         uint32_t *dptr = convbuf;
99         uint16_t *sptr = pixels;
100
101         for(i=0; i<npix; i++) {
102                 int r = UNPACK_R16(*sptr);
103                 int g = UNPACK_G16(*sptr);
104                 int b = UNPACK_B16(*sptr);
105                 *dptr++ = PACK_RGB32(b, g, r);
106                 sptr++;
107         }
108
109         glBindTexture(GL_TEXTURE_2D, tex);
110         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, fb_width, fb_height, GL_RGBA,
111                         GL_UNSIGNED_BYTE, convbuf);
112
113         glMatrixMode(GL_MODELVIEW);
114         glLoadIdentity();
115         if(win_aspect >= 1.5f) {
116                 glScalef(1.5f / win_aspect, 1, 1);
117         } else {
118                 glScalef(1, win_aspect / 1.5f, 1);
119         }
120
121         glClear(GL_COLOR_BUFFER_BIT);
122
123         glBegin(GL_QUADS);
124         glTexCoord2f(0, 1);
125         glVertex2f(-1, -1);
126         glTexCoord2f(1, 1);
127         glVertex2f(1, -1);
128         glTexCoord2f(1, 0);
129         glVertex2f(1, 1);
130         glTexCoord2f(0, 0);
131         glVertex2f(-1, 1);
132         glEnd();
133
134         glutSwapBuffers();
135         assert(glGetError() == GL_NO_ERROR);
136 }
137
138 int kb_isdown(int key)
139 {
140         switch(key) {
141         case KB_ANY:
142                 return num_pressed;
143
144         case KB_ALT:
145                 return keystate[KB_LALT] + keystate[KB_RALT];
146
147         case KB_CTRL:
148                 return keystate[KB_LCTRL] + keystate[KB_RCTRL];
149         }
150
151         if(isalpha(key)) {
152                 key = tolower(key);
153         }
154         return keystate[key];
155 }
156
157 static void display(void)
158 {
159         inp_update();
160
161         time_msec = get_msec();
162         draw();
163 }
164
165 static void idle(void)
166 {
167         glutPostRedisplay();
168 }
169
170 static void reshape(int x, int y)
171 {
172         win_aspect = (float)x / (float)y;
173         glViewport(0, 0, x, y);
174 }
175
176 static void keydown(unsigned char key, int x, int y)
177 {
178         modkeys = glutGetModifiers();
179
180         if((key == '\n' || key == '\r') && (modkeys & GLUT_ACTIVE_ALT)) {
181                 opt.fullscreen ^= 1;
182                 set_fullscreen(opt.fullscreen);
183                 return;
184         }
185         keystate[key] = 1;
186         //game_key(key, 1);
187 }
188
189 static void keyup(unsigned char key, int x, int y)
190 {
191         keystate[key] = 0;
192         //game_key(key, 0);
193 }
194
195 static void skeydown(int key, int x, int y)
196 {
197         key = translate_special(key);
198         keystate[key] = 1;
199         //game_key(key, 1);
200 }
201
202 static void skeyup(int key, int x, int y)
203 {
204         key = translate_special(key);
205         keystate[key] = 0;
206         //game_key(key, 0);
207 }
208
209 static int translate_special(int skey)
210 {
211         switch(skey) {
212         case 127:
213                 return 127;
214 /*      case GLUT_KEY_LEFT:
215                 return KB_LEFT;
216         case GLUT_KEY_RIGHT:
217                 return KB_RIGHT;
218         case GLUT_KEY_UP:
219                 return KB_UP;
220         case GLUT_KEY_DOWN:
221                 return KB_DOWN;
222         case GLUT_KEY_PAGE_UP:
223                 return KB_PGUP;
224         case GLUT_KEY_PAGE_DOWN:
225                 return KB_PGDN;
226         case GLUT_KEY_HOME:
227                 return KB_HOME;
228         case GLUT_KEY_END:
229                 return KB_END;
230         default:
231                 if(skey >= GLUT_KEY_F1 && skey <= GLUT_KEY_F12) {
232                         return KB_F1 + skey - GLUT_KEY_F1;
233                 }
234                 */
235         }
236         return 0;
237 }
238
239 static unsigned int next_pow2(unsigned int x)
240 {
241         x--;
242         x |= x >> 1;
243         x |= x >> 2;
244         x |= x >> 4;
245         x |= x >> 8;
246         x |= x >> 16;
247         return x + 1;
248 }
249
250 static void set_fullscreen(int fs)
251 {
252         static int win_x, win_y;
253
254         if(fs) {
255                 if(win_x == 0) {
256                         win_x = glutGet(GLUT_WINDOW_WIDTH);
257                         win_y = glutGet(GLUT_WINDOW_HEIGHT);
258                         glutFullScreen();
259                 }
260         } else {
261                 if(win_x) {
262                         glutReshapeWindow(win_x, win_y);
263                         win_x = win_y = 0;
264                 }
265         }
266 }
267
268 #ifdef __unix__
269 static void set_vsync(int vsync)
270 {
271         vsync = vsync ? 1 : 0;
272         if(glx_swap_interval_ext) {
273                 glx_swap_interval_ext(xdpy, xwin, vsync);
274         } else if(glx_swap_interval_sgi) {
275                 glx_swap_interval_sgi(vsync);
276         }
277 }
278 #endif
279 #ifdef WIN32
280 static void set_vsync(int vsync)
281 {
282         if(wgl_swap_interval_ext) {
283                 wgl_swap_interval_ext(vsync ? 1 : 0);
284         }
285 }
286 #endif