rename to molten metal
[metatoy] / src / nondos / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <stdarg.h>
4 #include <assert.h>
5 #include "miniglut.h"
6 #include "game.h"
7 #include "kern/keyb.h"
8
9 static void swap_interval(int vsync);
10 static void idle(void);
11 static void reshape(int x, int y);
12 static void keydown(unsigned char key, int x, int y);
13 static void keyup(unsigned char key, int x, int y);
14 static void skeydown(int key, int x, int y);
15 static void skeyup(int key, int x, int y);
16 static void mouse(int bn, int st, int x, int y);
17 static void motion(int x, int y);
18 static int translate_skey(int key);
19 static unsigned int next_pow2(unsigned int x);
20
21 #if defined(__unix__) || defined(unix)
22 #include <GL/glx.h>
23 static Display *xdpy;
24 static Window xwin;
25
26 static void (*glx_swap_interval_ext)();
27 static void (*glx_swap_interval_sgi)();
28 #endif
29 #ifdef _WIN32
30 #include <windows.h>
31 static PROC wgl_swap_interval_ext;
32 #endif
33
34 #ifndef GL_BGRA
35 #define GL_BGRA 0x80e1
36 #endif
37 #ifndef GL_CLAMP_TO_EDGE
38 #define GL_CLAMP_TO_EDGE        0x812f
39 #endif
40
41 unsigned char *framebuf;
42 static unsigned int tex;
43 static int tex_xsz, tex_ysz;
44
45 static int win_width, win_height;
46 static float win_aspect;
47 static float scale = 3;
48 static unsigned long start_time;
49 static uint32_t cmap[256];
50
51 int main(int argc, char **argv)
52 {
53         glutInit(&argc, argv);
54
55         glutInitWindowSize(FB_WIDTH * scale, FB_HEIGHT * scale);
56         glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE);
57         glutCreateWindow("Molten Metal");
58
59         glutDisplayFunc(game_draw);
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         glutPassiveMotionFunc(motion);
69
70 #if defined(__unix__) || defined(unix)
71         xdpy = glXGetCurrentDisplay();
72         xwin = glXGetCurrentDrawable();
73
74         if(!(glx_swap_interval_ext = glXGetProcAddress((unsigned char*)"glXSwapIntervalEXT"))) {
75                 glx_swap_interval_sgi = glXGetProcAddress((unsigned char*)"glXSwapIntervalSGI");
76         }
77 #endif
78 #ifdef _WIN32
79         wgl_swap_interval_ext = wglGetProcAddress("wglSwapIntervalEXT");
80 #endif
81         swap_interval(1);
82
83         if(!(framebuf = malloc(FB_WIDTH * FB_HEIGHT))) {
84                 fprintf(stderr, "failed to allocate framebuffer\n");
85                 return 1;
86         }
87
88         glGenTextures(1, &tex);
89         glBindTexture(GL_TEXTURE_2D, tex);
90         tex_xsz = next_pow2(FB_WIDTH);
91         tex_ysz = next_pow2(FB_HEIGHT);
92         glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex_xsz, tex_ysz, 0, GL_RGBA,
93                         GL_UNSIGNED_BYTE, 0);
94         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
95         glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
96         glMatrixMode(GL_TEXTURE);
97         glLoadIdentity();
98         glScalef((float)FB_WIDTH / tex_xsz, (float)FB_HEIGHT / tex_ysz, 1);
99         glEnable(GL_TEXTURE_2D);
100
101         if(game_init() == -1) {
102                 return 1;
103         }
104         atexit(game_shutdown);
105
106         start_time = glutGet(GLUT_ELAPSED_TIME);
107         glutMainLoop();
108         return 0;
109 }
110
111 unsigned long game_getmsec(void)
112 {
113         return (unsigned long)glutGet(GLUT_ELAPSED_TIME) - start_time;
114 }
115
116 void game_quit(void)
117 {
118         exit(0);
119 }
120
121 #define FB_ASPECT       ((float)FB_WIDTH / (float)FB_HEIGHT)
122
123 void game_swap_buffers(void)
124 {
125         int i;
126         static uint32_t fbrgba[FB_WIDTH * FB_HEIGHT * 4];
127
128         for(i=0; i<FB_WIDTH * FB_HEIGHT; i++) {
129                 int cidx = framebuf[i];
130                 fbrgba[i] = cmap[cidx];
131         }
132
133         glBindTexture(GL_TEXTURE_2D, tex);
134         glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, FB_WIDTH, FB_HEIGHT, GL_RGBA,
135                         GL_UNSIGNED_BYTE, fbrgba);
136
137         glMatrixMode(GL_MODELVIEW);
138         glLoadIdentity();
139         if(win_aspect >= FB_ASPECT) {
140                 glScalef(FB_ASPECT / win_aspect, 1, 1);
141         } else {
142                 glScalef(1, win_aspect / FB_ASPECT, 1);
143         }
144
145         glClear(GL_COLOR_BUFFER_BIT);
146
147         glBegin(GL_QUADS);
148         glTexCoord2f(0, 1);
149         glVertex2f(-1, -1);
150         glTexCoord2f(1, 1);
151         glVertex2f(1, -1);
152         glTexCoord2f(1, 0);
153         glVertex2f(1, 1);
154         glTexCoord2f(0, 0);
155         glVertex2f(-1, 1);
156         glEnd();
157
158         glutSwapBuffers();
159         assert(glGetError() == GL_NO_ERROR);
160 }
161
162 void vga_setpalent(int idx, int r, int g, int b)
163 {
164         cmap[idx] = (b << 16) | (g << 8) | r;
165 }
166
167 void vga_setpal(int startidx, int count, unsigned char *col)
168 {
169         int i, idx = startidx;
170         for(i=0; i<count; i++) {
171                 vga_setpalent(idx++, col[0], col[1], col[2]);
172                 col += 3;
173         }
174 }
175
176 void panic(const char *fmt, ...)
177 {
178         va_list ap;
179
180         va_start(ap, fmt);
181         vfprintf(stderr, fmt, ap);
182         va_end(ap);
183 }
184
185 #if defined(__unix__) || defined(unix)
186 static void swap_interval(int vsync)
187 {
188         vsync = vsync ? 1 : 0;
189         if(glx_swap_interval_ext) {
190                 glx_swap_interval_ext(xdpy, xwin, vsync);
191         } else if(glx_swap_interval_sgi) {
192                 glx_swap_interval_sgi(vsync);
193         }
194 }
195 #endif
196 #ifdef WIN32
197 static void swap_interval(int vsync)
198 {
199         if(wgl_swap_interval_ext) {
200                 wgl_swap_interval_ext(vsync ? 1 : 0);
201         }
202 }
203 #endif
204
205 static void idle(void)
206 {
207         glutPostRedisplay();
208 }
209
210 static void reshape(int x, int y)
211 {
212         win_width = x;
213         win_height = y;
214         win_aspect = (float)x / (float)y;
215         glViewport(0, 0, x, y);
216 }
217
218 static void keydown(unsigned char key, int x, int y)
219 {
220         /*modkeys = glutGetModifiers();*/
221         game_keyboard(key, 1);
222 }
223
224 static void keyup(unsigned char key, int x, int y)
225 {
226         game_keyboard(key, 0);
227 }
228
229 static void skeydown(int key, int x, int y)
230 {
231         int k;
232         /*modkeys = glutGetModifiers();*/
233         if((k = translate_skey(key)) >= 0) {
234                 game_keyboard(k, 1);
235         }
236 }
237
238 static void skeyup(int key, int x, int y)
239 {
240         int k = translate_skey(key);
241         if(k >= 0) {
242                 game_keyboard(k, 0);
243         }
244 }
245
246 static void mouse(int bn, int st, int x, int y)
247 {
248         /*modkeys = glutGetModifiers();*/
249         game_mouse(bn - GLUT_LEFT_BUTTON, st == GLUT_DOWN, x / scale, y / scale);
250 }
251
252 static void motion(int x, int y)
253 {
254         game_motion(x / scale, y / scale);
255 }
256
257 static int translate_skey(int key)
258 {
259         switch(key) {
260         case GLUT_KEY_LEFT:
261                 return KB_LEFT;
262         case GLUT_KEY_UP:
263                 return KB_UP;
264         case GLUT_KEY_RIGHT:
265                 return KB_RIGHT;
266         case GLUT_KEY_DOWN:
267                 return KB_DOWN;
268         case GLUT_KEY_PAGE_UP:
269                 return KB_PGUP;
270         case GLUT_KEY_PAGE_DOWN:
271                 return KB_PGDN;
272         case GLUT_KEY_HOME:
273                 return KB_HOME;
274         case GLUT_KEY_END:
275                 return KB_END;
276         case GLUT_KEY_INSERT:
277                 return KB_INSERT;
278         default:
279                 if(key >= GLUT_KEY_F1 && key <= GLUT_KEY_F12) {
280                         return key - GLUT_KEY_F1 + KB_F1;
281                 }
282         }
283
284         return -1;
285 }
286
287 static unsigned int next_pow2(unsigned int x)
288 {
289         x--;
290         x |= x >> 1;
291         x |= x >> 2;
292         x |= x >> 4;
293         x |= x >> 8;
294         x |= x >> 16;
295         return x + 1;
296 }
297