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