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