6a5202190d9e0aeefde7f74226ccb405361984cc
[dosdemo] / src / sdl / main.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <math.h>
4 #include <limits.h>
5 #include <SDL/SDL.h>
6 #include "demo.h"
7 #include "tinyfps.h"
8 #include "timer.h"
9 #include "cfgopt.h"
10 #include "sball.h"
11 #include "vmath.h"
12
13 static void handle_event(SDL_Event *ev);
14 static void toggle_fullscreen(void);
15
16 static int handle_sball_event(sball_event *ev);
17 static void recalc_sball_matrix(float *xform);
18
19
20 static int quit;
21 static SDL_Surface *fbsurf;
22
23 static int fbscale = 2;
24 static int xsz, ysz;
25 static unsigned int sdl_flags = SDL_SWSURFACE;
26
27 static int use_sball;
28 static vec3_t pos = {0, 0, 0};
29 static quat_t rot = {0, 0, 0, 1};
30
31
32 int main(int argc, char **argv)
33 {
34         int s, i, j;
35         char *env;
36         unsigned short *sptr, *dptr;
37
38         if((env = getenv("FBSCALE")) && (s = atoi(env))) {
39                 fbscale = s;
40                 printf("Framebuffer scaling x%d\n", fbscale);
41         }
42
43         xsz = fb_width * fbscale;
44         ysz = fb_height * fbscale;
45
46         /* allocate 1 extra row as a guard band, until we fucking fix the rasterizer */
47         if(!(fb_pixels = malloc(fb_width * (fb_height + 1) * fb_bpp / CHAR_BIT))) {
48                 fprintf(stderr, "failed to allocate virtual framebuffer\n");
49                 return 1;
50         }
51         vmem = fb_pixels;
52
53         SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER | SDL_INIT_NOPARACHUTE);
54         if(!(fbsurf = SDL_SetVideoMode(xsz, ysz, fb_bpp, sdl_flags))) {
55                 fprintf(stderr, "failed to set video mode %dx%d %dbpp\n", fb_width, fb_height, fb_bpp);
56                 free(fb_pixels);
57                 SDL_Quit();
58                 return 1;
59         }
60         SDL_WM_SetCaption("dosdemo/SDL", 0);
61         SDL_ShowCursor(0);
62
63         time_msec = 0;
64         if(demo_init(argc, argv) == -1) {
65                 free(fb_pixels);
66                 SDL_Quit();
67                 return 1;
68         }
69
70         if(opt.sball && sball_init() == 0) {
71                 use_sball = 1;
72         }
73
74         reset_timer();
75
76         while(!quit) {
77                 SDL_Event ev;
78                 while(SDL_PollEvent(&ev)) {
79                         handle_event(&ev);
80                         if(quit) goto break_evloop;
81                 }
82
83                 if(use_sball) {
84                         while(sball_pending()) {
85                                 sball_event ev;
86                                 sball_getevent(&ev);
87                                 handle_sball_event(&ev);
88                         }
89                         recalc_sball_matrix(sball_matrix);
90                 }
91
92                 time_msec = get_msec();
93                 demo_draw();
94                 drawFps(fb_pixels);
95
96                 if(SDL_MUSTLOCK(fbsurf)) {
97                         SDL_LockSurface(fbsurf);
98                 }
99
100                 sptr = fb_pixels;
101                 dptr = (unsigned short*)fbsurf->pixels + (fbsurf->w - xsz) / 2;
102                 for(i=0; i<fb_height; i++) {
103                         for(j=0; j<fb_width; j++) {
104                                 int x, y;
105                                 unsigned short pixel = *sptr++;
106
107                                 for(y=0; y<fbscale; y++) {
108                                         for(x=0; x<fbscale; x++) {
109                                                 dptr[y * fbsurf->w + x] = pixel;
110                                         }
111                                 }
112                                 dptr += fbscale;
113                         }
114                         dptr += (fbsurf->w - fb_width) * fbscale;
115                 }
116
117                 if(SDL_MUSTLOCK(fbsurf)) {
118                         SDL_UnlockSurface(fbsurf);
119                 }
120                 SDL_Flip(fbsurf);
121         }
122
123 break_evloop:
124         demo_cleanup();
125         SDL_Quit();
126         return 0;
127 }
128
129 void demo_quit(void)
130 {
131         quit = 1;
132 }
133
134 void wait_vsync(void)
135 {
136         unsigned long start = SDL_GetTicks();
137         unsigned long until = (start | 0xf) + 1;
138         while(SDL_GetTicks() <= until);
139 }
140
141 void swap_buffers(void *pixels)
142 {
143         /* do nothing, all pointers point to the same buffer */
144         if(opt.vsync) {
145                 wait_vsync();
146         }
147 }
148
149 static int bnmask(int sdlbn)
150 {
151         switch(sdlbn) {
152         case SDL_BUTTON_LEFT:
153                 return MOUSE_BN_LEFT;
154         case SDL_BUTTON_RIGHT:
155                 return MOUSE_BN_RIGHT;
156         case SDL_BUTTON_MIDDLE:
157                 return MOUSE_BN_MIDDLE;
158         default:
159                 break;
160         }
161         return 0;
162 }
163
164 static void handle_event(SDL_Event *ev)
165 {
166         switch(ev->type) {
167         case SDL_QUIT:
168                 quit = 1;
169                 break;
170
171         case SDL_KEYDOWN:
172         case SDL_KEYUP:
173                 if(ev->key.keysym.sym == SDLK_RETURN && (SDL_GetModState() & KMOD_ALT) &&
174                                 ev->key.state == SDL_PRESSED) {
175                         toggle_fullscreen();
176                         break;
177                 }
178                 demo_keyboard(ev->key.keysym.sym, ev->key.state == SDL_PRESSED ? 1 : 0);
179                 break;
180
181         case SDL_MOUSEMOTION:
182                 mouse_x = ev->motion.x / fbscale;
183                 mouse_y = ev->motion.y / fbscale;
184                 break;
185
186         case SDL_MOUSEBUTTONDOWN:
187                 mouse_bmask |= bnmask(ev->button.button);
188                 if(0) {
189         case SDL_MOUSEBUTTONUP:
190                         mouse_bmask &= ~bnmask(ev->button.button);
191                 }
192                 mouse_x = ev->button.x / fbscale;
193                 mouse_y = ev->button.y / fbscale;
194                 break;
195
196         default:
197                 break;
198         }
199 }
200
201 static void toggle_fullscreen(void)
202 {
203         SDL_Surface *newsurf;
204         unsigned int newflags = sdl_flags ^ SDL_FULLSCREEN;
205
206         if(!(newsurf = SDL_SetVideoMode(xsz, ysz, fb_bpp, newflags))) {
207                 fprintf(stderr, "failed to go %s\n", newflags & SDL_FULLSCREEN ? "fullscreen" : "windowed");
208                 return;
209         }
210
211         fbsurf = newsurf;
212         sdl_flags = newflags;
213 }
214
215
216
217 #define TX(ev)  ((ev)->motion.motion[0])
218 #define TY(ev)  ((ev)->motion.motion[1])
219 #define TZ(ev)  ((ev)->motion.motion[2])
220 #define RX(ev)  ((ev)->motion.motion[3])
221 #define RY(ev)  ((ev)->motion.motion[4])
222 #define RZ(ev)  ((ev)->motion.motion[5])
223
224 static int handle_sball_event(sball_event *ev)
225 {
226         switch(ev->type) {
227         case SBALL_EV_MOTION:
228                 if(RX(ev) | RY(ev) | RZ(ev)) {
229                         float rx = (float)RX(ev);
230                         float ry = (float)RY(ev);
231                         float rz = (float)RZ(ev);
232                         float axis_len = sqrt(rx * rx + ry * ry + rz * rz);
233                         if(axis_len > 0.0) {
234                                 rot = quat_rotate(rot, axis_len * 0.001, -rx / axis_len,
235                                                 -ry / axis_len, -rz / axis_len);
236                         }
237                 }
238
239                 pos.x += TX(ev) * 0.001;
240                 pos.y += TY(ev) * 0.001;
241                 pos.z += TZ(ev) * 0.001;
242                 break;
243
244         case SBALL_EV_BUTTON:
245                 if(ev->button.pressed) {
246                         pos = v3_cons(0, 0, 0);
247                         rot = quat_cons(1, 0, 0, 0);
248                 }
249                 break;
250         }
251
252         return 0;
253 }
254
255 void recalc_sball_matrix(float *xform)
256 {
257         quat_to_mat(xform, rot);
258         xform[12] = pos.x;
259         xform[13] = pos.y;
260         xform[14] = pos.z;
261 }