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