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