b0fc2e82679fffacbc46cca9989e69e6bda571d9
[retroray] / src / app.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 "config.h"
19
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include <string.h>
23 #include <time.h>
24 #include "gaw/gaw.h"
25 #include "app.h"
26 #include "timer.h"
27 #include "rend.h"
28 #include "options.h"
29 #include "font.h"
30 #include "util.h"
31 #include "rtk.h"
32
33 #ifdef GFX_SW
34 #include "gaw/gaw_sw.h"
35 #endif
36
37 static void gui_fill(rtk_rect *rect, uint32_t color);
38 static void gui_blit(int x, int y, rtk_icon *icon);
39 static void gui_drawtext(int x, int y, const char *str);
40 static void gui_textrect(const char *str, rtk_rect *rect);
41
42 int mouse_x, mouse_y, mouse_state[3];
43 unsigned int modkeys;
44 int win_width, win_height;
45 float win_aspect;
46 int fullscr;
47
48 long time_msec;
49
50 struct app_screen *cur_scr;
51
52 struct font *uifont;
53
54 uint32_t *framebuf;
55
56 struct scene *scn;
57
58 /* available screens */
59 #define MAX_SCREENS     8
60 static struct app_screen *screens[MAX_SCREENS];
61 static int num_screens;
62
63
64 int app_init(void)
65 {
66         int i;
67         char *start_scr_name;
68         static rtk_draw_ops guigfx = {gui_fill, gui_blit, gui_drawtext, gui_textrect};
69
70 #if !defined(NDEBUG) && defined(DBG_FPEXCEPT)
71         infomsg("floating point exceptions enabled\n");
72         enable_fpexcept();
73 #endif
74
75 #ifdef GFX_SW
76         gaw_sw_init();
77 #endif
78         rend_init();
79
80         load_options("retroray.cfg");
81         app_resize(opt.xres, opt.yres);
82         app_vsync(opt.vsync);
83         if(opt.fullscreen) {
84                 app_fullscreen(1);
85         }
86
87         /*dtx_target_user(txdraw, 0);*/
88         dtx_target_raster((unsigned char*)framebuf, win_width, win_height);
89         dtx_set(DTX_RASTER_THRESHOLD, 127);
90
91         uifont = malloc_nf(sizeof *uifont);
92         if(load_font(uifont, "data/uifont14.gmp") == -1) {
93                 free(uifont);
94                 return -1;
95         }
96
97         rtk_setup(&guigfx);
98
99         if(!(scn = create_scene())) {
100                 return -1;
101         }
102
103         /* initialize screens */
104         screens[num_screens++] = &scr_model;
105         screens[num_screens++] = &scr_rend;
106
107         start_scr_name = getenv("START_SCREEN");
108
109         for(i=0; i<num_screens; i++) {
110                 if(screens[i]->init() == -1) {
111                         return -1;
112                 }
113         }
114
115         time_msec = get_msec();
116
117         for(i=0; i<num_screens; i++) {
118                 if(screens[i]->name && start_scr_name && strcmp(screens[i]->name, start_scr_name) == 0) {
119                         app_chscr(screens[i]);
120                         break;
121                 }
122         }
123         if(!cur_scr) {
124                 app_chscr(&scr_model);
125         }
126
127         return 0;
128 }
129
130 void app_shutdown(void)
131 {
132         int i;
133
134         putchar('\n');
135
136         save_options("retroray.cfg");
137
138         for(i=0; i<num_screens; i++) {
139                 if(screens[i]->destroy) {
140                         screens[i]->destroy();
141                 }
142         }
143
144         destroy_font(uifont);
145         free(uifont);
146
147 #ifdef GFX_SW
148         gaw_sw_destroy();
149 #endif
150
151         free_scene(scn);
152
153         cleanup_logger();
154 }
155
156 void app_display(void)
157 {
158         time_msec = get_msec();
159
160         cur_scr->display();
161 }
162
163 void app_reshape(int x, int y)
164 {
165         int numpix = x * y;
166         int prev_numpix = win_width * win_height;
167
168         dbgmsg("reshape(%d, %d)\n", x, y);
169
170         if(!framebuf || numpix > prev_numpix) {
171                 void *tmp;
172                 if(!(tmp = realloc(framebuf, numpix * sizeof *framebuf))) {
173                         errormsg("failed to resize framebuffer to %dx%d\n", x, y);
174                         return;
175                 }
176                 framebuf = tmp;
177         }
178 #ifdef GFX_SW
179         gaw_sw_framebuffer(x, y, framebuf);
180 #endif
181         dtx_target_raster((unsigned char*)framebuf, x, y);
182
183         win_width = x;
184         win_height = y;
185         win_aspect = (float)x / (float)y;
186         gaw_viewport(0, 0, x, y);
187
188         if(cur_scr && cur_scr->reshape) {
189                 cur_scr->reshape(x, y);
190         }
191 }
192
193 void app_keyboard(int key, int press)
194 {
195         long msec;
196         static long prev_esc;
197
198         if(press) {
199                 switch(key) {
200 #ifdef DBG_ESCQUIT
201                 case 27:
202                         msec = get_msec();
203                         if(msec - prev_esc < 1000) {
204                                 app_quit();
205                         }
206                         prev_esc = msec;
207                         return;
208 #endif
209
210                 case 'q':
211                         if(modkeys & KEY_MOD_CTRL) {
212                                 app_quit();
213                                 return;
214                         }
215                         break;
216
217                 case '\n':
218                 case '\r':
219                         if(modkeys & KEY_MOD_ALT) {
220                 case KEY_F11:
221                                 app_fullscreen(-1);
222                                 return;
223                         }
224                         break;
225                 }
226         }
227
228         if(cur_scr && cur_scr->keyboard) {
229                 cur_scr->keyboard(key, press);
230         }
231 }
232
233 void app_mouse(int bn, int st, int x, int y)
234 {
235         mouse_x = x;
236         mouse_y = y;
237         if(bn < 3) {
238                 mouse_state[bn] = st;
239         }
240
241         if(cur_scr && cur_scr->mouse) {
242                 cur_scr->mouse(bn, st, x, y);
243         }
244 }
245
246 void app_motion(int x, int y)
247 {
248         if(cur_scr && cur_scr->motion) {
249                 cur_scr->motion(x, y);
250         }
251         mouse_x = x;
252         mouse_y = y;
253 }
254
255 void app_sball_motion(int x, int y, int z)
256 {
257         if(cur_scr->sball_motion) {
258                 cur_scr->sball_motion(x, y, z);
259         }
260 }
261
262 void app_sball_rotate(int x, int y, int z)
263 {
264         if(cur_scr->sball_rotate) {
265                 cur_scr->sball_rotate(x, y, z);
266         }
267 }
268
269 void app_sball_button(int bn, int st)
270 {
271         if(cur_scr->sball_button) {
272                 cur_scr->sball_button(bn, st);
273         }
274 }
275
276 void app_chscr(struct app_screen *scr)
277 {
278         struct app_screen *prev = cur_scr;
279
280         if(!scr) return;
281
282         if(scr->start && scr->start() == -1) {
283                 return;
284         }
285         if(scr->reshape) {
286                 scr->reshape(win_width, win_height);
287         }
288
289         if(prev && prev->stop) {
290                 prev->stop();
291         }
292         cur_scr = scr;
293 }
294
295 static void gui_fill(rtk_rect *rect, uint32_t color)
296 {
297         int i, j;
298         uint32_t *fb = framebuf + rect->y * win_width + rect->x;
299
300         for(i=0; i<rect->height; i++) {
301                 for(j=0; j<rect->width; j++) {
302                         fb[j] = color;
303                 }
304                 fb += win_width;
305         }
306 }
307
308 static void gui_blit(int x, int y, rtk_icon *icon)
309 {
310         int i, j;
311         uint32_t *dest, *src;
312
313         dest = framebuf + y * win_width + x;
314         src = icon->pixels;
315
316         for(i=0; i<icon->height; i++) {
317                 for(j=0; j<icon->width; j++) {
318                         int r = src[j] & 0xff;
319                         int g = (src[j] >> 8) & 0xff;
320                         int b = (src[j] >> 16) & 0xff;
321                         dest[j] = 0xff000000 | (r << 16) | (g << 8) | b;
322                 }
323                 dest += win_width;
324                 src += icon->scanlen;
325         }
326 }
327
328 static void gui_drawtext(int x, int y, const char *str)
329 {
330 }
331
332 static void gui_textrect(const char *str, rtk_rect *rect)
333 {
334         rect->x = rect->y = 0;
335         rect->width = 20;
336         rect->height = 10;/* TODO */
337 }