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