c72b788fb70ec7d76025edd7bcce781060f9c0a1
[retroray] / src / modern / main.c
1 /*
2 RetroRay - integrated standalone vintage modeller/renderer
3 Copyright (C) 2023  John Tsiombikas <nuclear@mutantstargoat.com>
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 <stdio.h>
19 #include <stdlib.h>
20 #include <assert.h>
21 #include "miniglut.h"
22 #include "app.h"
23
24 static void reshape(int x, int y);
25 static void keydown(unsigned char key, int x, int y);
26 static void keyup(unsigned char key, int x, int y);
27 static void skeydown(int key, int x, int y);
28 static void skeyup(int key, int x, int y);
29 static void mouse(int bn, int st, int x, int y);
30 static void motion(int x, int y);
31 static int translate_skey(int key);
32
33 #if defined(__unix__) || defined(unix)
34 #include <GL/glx.h>
35 static Display *xdpy;
36 static Window xwin;
37
38 static void (*glx_swap_interval_ext)();
39 static void (*glx_swap_interval_sgi)();
40 #endif
41 #ifdef _WIN32
42 #include <windows.h>
43 static PROC wgl_swap_interval_ext;
44 #endif
45
46
47
48 int main(int argc, char **argv)
49 {
50         glutInit(&argc, argv);
51         glutInitWindowSize(640, 480);
52         glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
53         glutCreateWindow("RetroRay");
54
55         glutDisplayFunc(app_display);
56         glutReshapeFunc(reshape);
57         glutKeyboardFunc(keydown);
58         glutKeyboardUpFunc(keyup);
59         glutSpecialFunc(skeydown);
60         glutSpecialUpFunc(skeyup);
61         glutMouseFunc(mouse);
62         glutMotionFunc(motion);
63         glutPassiveMotionFunc(motion);
64         glutSpaceballMotionFunc(app_sball_motion);
65         glutSpaceballRotateFunc(app_sball_rotate);
66         glutSpaceballButtonFunc(app_sball_button);
67
68 #if defined(__unix__) || defined(unix)
69         xdpy = glXGetCurrentDisplay();
70         xwin = glXGetCurrentDrawable();
71
72         if(!(glx_swap_interval_ext = glXGetProcAddress((unsigned char*)"glXSwapIntervalEXT"))) {
73                 glx_swap_interval_sgi = glXGetProcAddress((unsigned char*)"glXSwapIntervalSGI");
74         }
75 #endif
76 #ifdef _WIN32
77         wgl_swap_interval_ext = wglGetProcAddress("wglSwapIntervalEXT");
78 #endif
79
80         win_width = glutGet(GLUT_WINDOW_WIDTH);
81         win_height = glutGet(GLUT_WINDOW_HEIGHT);
82         win_aspect = (float)win_width / win_height;
83
84         if(app_init() == -1) {
85                 return 1;
86         }
87         atexit(app_shutdown);
88         glutMainLoop();
89         return 0;
90 }
91
92 long app_getmsec(void)
93 {
94         return glutGet(GLUT_ELAPSED_TIME);
95 }
96
97 void app_redisplay(void)
98 {
99         glutPostRedisplay();
100 }
101
102 void app_swap_buffers(void)
103 {
104         glMatrixMode(GL_PROJECTION);
105         glPushMatrix();
106         glLoadIdentity();
107         glMatrixMode(GL_MODELVIEW);
108         glLoadIdentity();
109
110         glRasterPos2i(-1, 1);
111         glPixelZoom(1, -1);
112         glEnable(GL_ALPHA_TEST);
113         glAlphaFunc(GL_GREATER, 0.5f);
114         glDrawPixels(win_width, win_height, GL_BGRA, GL_UNSIGNED_BYTE, framebuf);
115         glDisable(GL_ALPHA_TEST);
116
117         glMatrixMode(GL_PROJECTION);
118         glPopMatrix();
119         glMatrixMode(GL_MODELVIEW);
120
121         glutSwapBuffers();
122         assert(glGetError() == GL_NO_ERROR);
123 }
124
125 void app_quit(void)
126 {
127         exit(0);
128 }
129
130 void app_resize(int x, int y)
131 {
132         if(x == win_width && y == win_height) return;
133
134         glutReshapeWindow(x, y);
135 }
136
137 void app_fullscreen(int fs)
138 {
139         static int prev_w, prev_h;
140
141         if(fs == -1) {
142                 fs = !fullscr;
143         }
144
145         if(fs == fullscr) return;
146
147         if(fs) {
148                 prev_w = glutGet(GLUT_WINDOW_WIDTH);
149                 prev_h = glutGet(GLUT_WINDOW_HEIGHT);
150                 glutFullScreen();
151         } else {
152                 glutReshapeWindow(prev_w, prev_h);
153         }
154         fullscr = fs;
155 }
156
157 #if defined(__unix__) || defined(unix)
158 void app_vsync(int vsync)
159 {
160         vsync = vsync ? 1 : 0;
161         if(glx_swap_interval_ext) {
162                 glx_swap_interval_ext(xdpy, xwin, vsync);
163         } else if(glx_swap_interval_sgi) {
164                 glx_swap_interval_sgi(vsync);
165         }
166 }
167 #endif
168 #ifdef WIN32
169 void app_vsync(int vsync)
170 {
171         if(wgl_swap_interval_ext) {
172                 wgl_swap_interval_ext(vsync ? 1 : 0);
173         }
174 }
175 #endif
176
177
178
179 static void reshape(int x, int y)
180 {
181         app_reshape(x, y);
182 }
183
184 static void keydown(unsigned char key, int x, int y)
185 {
186         modkeys = glutGetModifiers();
187         app_keyboard(key, 1);
188 }
189
190 static void keyup(unsigned char key, int x, int y)
191 {
192         app_keyboard(key, 0);
193 }
194
195 static void skeydown(int key, int x, int y)
196 {
197         int k;
198         modkeys = glutGetModifiers();
199         if((k = translate_skey(key)) >= 0) {
200                 app_keyboard(k, 1);
201         }
202 }
203
204 static void skeyup(int key, int x, int y)
205 {
206         int k = translate_skey(key);
207         if(k >= 0) {
208                 app_keyboard(k, 0);
209         }
210 }
211
212 static void mouse(int bn, int st, int x, int y)
213 {
214         modkeys = glutGetModifiers();
215         app_mouse(bn - GLUT_LEFT_BUTTON, st == GLUT_DOWN, x, y);
216 }
217
218 static void motion(int x, int y)
219 {
220         app_motion(x, y);
221 }
222
223 static int translate_skey(int key)
224 {
225         switch(key) {
226         case GLUT_KEY_LEFT:
227                 return KEY_LEFT;
228         case GLUT_KEY_UP:
229                 return KEY_UP;
230         case GLUT_KEY_RIGHT:
231                 return KEY_RIGHT;
232         case GLUT_KEY_DOWN:
233                 return KEY_DOWN;
234         case GLUT_KEY_PAGE_UP:
235                 return KEY_PGUP;
236         case GLUT_KEY_PAGE_DOWN:
237                 return KEY_PGDOWN;
238         case GLUT_KEY_HOME:
239                 return KEY_HOME;
240         case GLUT_KEY_END:
241                 return KEY_END;
242         case GLUT_KEY_INSERT:
243                 return KEY_INS;
244         default:
245                 if(key >= GLUT_KEY_F1 && key <= GLUT_KEY_F12) {
246                         return key - GLUT_KEY_F1 + KEY_F1;
247                 }
248         }
249
250         return -1;
251 }