spaceball
[o2demo] / src / demo.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #include <ctype.h>
5 #include <math.h>
6 #include <GL/gl.h>
7 #include <GL/glu.h>
8 #include "demo.h"
9 #include "screen.h"
10 #include "cfgopt.h"
11
12 static void recalc_sball_matrix(float *xform, float *inv_xform);
13
14 static int console_active;
15 static int sball_update_pending;
16
17 static float pos[3];
18 static float rot[4] = {0, 0, 0, 1};
19
20 int demo_init(int argc, char **argv)
21 {
22         struct screen *scr;
23         char *env;
24
25         if(load_config("demo.cfg") == -1) {
26                 return -1;
27         }
28         if((env = getenv("START_SCR"))) {
29                 opt.start_scr = env;
30         }
31         if(parse_args(argc, argv) == -1) {
32                 return -1;
33         }
34
35         glEnable(GL_DEPTH_TEST);
36         glEnable(GL_CULL_FACE);
37
38         sball_matrix[0] = sball_matrix[5] = sball_matrix[10] = sball_matrix[15] = 1.0f;
39         sball_inv_matrix[0] = sball_inv_matrix[5] = sball_inv_matrix[10] = sball_inv_matrix[15] = 1.0f;
40
41         if(scr_init() == -1) {
42                 return -1;
43         }
44         if(opt.start_scr) {
45                 scr = scr_lookup(opt.start_scr);
46         } else {
47                 scr = scr_screen(0);
48         }
49
50         if(!scr || scr_change(scr, 4000) == -1) {
51                 fprintf(stderr, "screen %s not found\n", opt.start_scr ? opt.start_scr : "0");
52                 return -1;
53         }
54
55         return 0;
56 }
57
58 void demo_cleanup(void)
59 {
60         scr_shutdown();
61 }
62
63 void demo_draw(void)
64 {
65         if(sball_update_pending) {
66                 recalc_sball_matrix(sball_matrix, sball_inv_matrix);
67                 sball_update_pending = 0;
68         }
69
70         scr_update();
71         scr_draw();
72 }
73
74 void demo_reshape(int x, int y)
75 {
76         glViewport(0, 0, x, y);
77
78         glMatrixMode(GL_PROJECTION);
79         glLoadIdentity();
80         gluPerspective(50.0, win_aspect, 0.5, 500.0);
81 }
82
83 static void change_screen(int idx)
84 {
85         printf("change screen %d\n", idx);
86         scr_change(scr_screen(idx), 4000);
87 }
88
89 #define CBUF_SIZE       64
90 #define CBUF_MASK       (CBUF_SIZE - 1)
91 void demo_keyboard(int key, int pressed)
92 {
93         static char cbuf[CBUF_SIZE];
94         static int rd, wr;
95         char inp[CBUF_SIZE + 1], *dptr;
96         int i, nscr;
97
98         if(pressed) {
99                 switch(key) {
100                 case 27:
101                         demo_quit();
102                         break;
103
104                 case '`':
105                         console_active = !console_active;
106                         if(console_active) {
107                                 printf("> ");
108                                 fflush(stdout);
109                         } else {
110                                 putchar('\n');
111                         }
112                         return;
113
114                 case '\b':
115                         if(console_active) {
116                                 if(wr != rd) {
117                                         printf("\b \b");
118                                         fflush(stdout);
119                                         wr = (wr + CBUF_SIZE - 1) & CBUF_MASK;
120                                 }
121                                 return;
122                         }
123                         break;
124
125                 case '\n':
126                 case '\r':
127                         if(console_active) {
128                                 dptr = inp;
129                                 while(rd != wr) {
130                                         *dptr++ = cbuf[rd];
131                                         rd = (rd + 1) & CBUF_MASK;
132                                 }
133                                 *dptr = 0;
134                                 if(inp[0]) {
135                                         printf("\ntrying to match: %s\n", inp);
136                                         nscr = scr_num_screens();
137                                         for(i=0; i<nscr; i++) {
138                                                 if(strstr(scr_screen(i)->name, inp)) {
139                                                         change_screen(i);
140                                                         break;
141                                                 }
142                                         }
143                                 }
144                                 console_active = 0;
145                                 return;
146                         }
147                         break;
148
149                 default:
150                         if(key >= '1' && key <= '9' && key <= '1' + scr_num_screens()) {
151                                 change_screen(key - '1');
152                         } else if(key == '0' && scr_num_screens() >= 10) {
153                                 change_screen(9);
154                         }
155
156                         if(console_active) {
157                                 if(key < 256 && isprint(key)) {
158                                         putchar(key);
159                                         fflush(stdout);
160
161                                         cbuf[wr] = key;
162                                         wr = (wr + 1) & CBUF_MASK;
163                                         if(wr == rd) { /* overflow */
164                                                 rd = (rd + 1) & CBUF_MASK;
165                                         }
166                                 }
167                                 return;
168                         }
169                         break;
170                 }
171
172                 scr_keypress(key);
173         }
174 }
175
176 void demo_mbutton(int bn, int pressed, int x, int y)
177 {
178 }
179
180 void demo_mmotion(int x, int y)
181 {
182 }
183
184
185 static void quat_rotate(float *qres, const float *q, float angle, float x, float y, float z);
186 static void quat_mul(float *qres, const float *q1, const float *q2);
187 static void quat_to_mat(float *res, const float *q);
188
189 void demo_sball_motion(int x, int y, int z)
190 {
191         pos[0] += (float)x * 0.01;
192         pos[1] += (float)y * 0.01;
193         pos[2] -= (float)z * 0.01;
194         sball_update_pending = 1;
195 }
196
197 void demo_sball_rotate(int x, int y, int z)
198 {
199         float rx = (float)x;
200         float ry = (float)y;
201         float rz = (float)z;
202         float axis_len = sqrt(rx * rx + ry * ry + rz * rz);
203         if(axis_len > 0.0) {
204                 quat_rotate(rot, rot, axis_len * 0.001, -rx / axis_len,
205                                 -ry / axis_len, rz / axis_len);
206         }
207         sball_update_pending = 1;
208 }
209
210 void demo_sball_button(int bn, int pressed)
211 {
212         if(!pressed) return;
213
214         switch(bn) {
215         case 0:
216                 pos[0] = pos[1] = pos[2] = 0;
217                 rot[0] = rot[1] = rot[2] = 0;
218                 rot[3] = 1;
219                 break;
220
221         default:
222                 break;
223         }
224 }
225
226 static void recalc_sball_matrix(float *xform, float *inv_xform)
227 {
228         float tx, ty, tz;
229
230         quat_to_mat(xform, rot);
231         xform[12] = pos[0];
232         xform[13] = pos[1];
233         xform[14] = pos[2];
234
235         inv_xform[0] = xform[0];
236         inv_xform[5] = xform[5];
237         inv_xform[10] = xform[10];
238         inv_xform[15] = 1.0f;
239
240         inv_xform[1] = xform[4];
241         inv_xform[2] = xform[8];
242         inv_xform[6] = xform[9];
243         inv_xform[4] = xform[1];
244         inv_xform[8] = xform[2];
245         inv_xform[9] = xform[6];
246
247         inv_xform[3] = inv_xform[7] = inv_xform[11] = 0.0f;
248         tx = -pos[0];
249         ty = -pos[1];
250         tz = -pos[2];
251
252         inv_xform[12] = tx * inv_xform[0] + ty * inv_xform[4] + tz * inv_xform[8];
253         inv_xform[13] = tx * inv_xform[1] + ty * inv_xform[5] + tz * inv_xform[9];
254         inv_xform[14] = tx * inv_xform[2] + ty * inv_xform[6] + tz * inv_xform[10];
255 }
256
257 static void quat_rotate(float *qres, const float *q, float angle, float x, float y, float z)
258 {
259         float rq[4];
260         float half_angle = angle * 0.5f;
261         float sin_half = sin(half_angle);
262
263         rq[3] = cos(half_angle);
264         rq[0] = x * sin_half;
265         rq[1] = y * sin_half;
266         rq[2] = z * sin_half;
267
268         quat_mul(qres, q, rq);
269 }
270
271 static void quat_mul(float *qres, const float *q1, const float *q2)
272 {
273         float w = q1[3] * q2[3] - (q1[0] * q2[0] + q1[1] * q2[1] + q1[2] * q2[2]);
274         float x = q2[0] * q1[3] + q1[0] * q2[3] + (q1[1] * q2[2] - q1[2] * q2[1]);
275         float y = q2[1] * q1[3] + q1[1] * q2[3] + (q1[2] * q2[0] - q1[0] * q2[2]);
276         float z = q2[2] * q1[3] + q1[2] * q2[3] + (q1[0] * q2[1] - q1[1] * q2[0]);
277         qres[0] = x;
278         qres[1] = y;
279         qres[2] = z;
280         qres[3] = w;
281 }
282
283 static void quat_to_mat(float *res, const float *q)
284 {
285         res[0] = 1.0f - 2.0f * q[1]*q[1] - 2.0f * q[2]*q[2];
286         res[1] = 2.0f * q[0] * q[1] - 2.0f * q[3] * q[2];
287         res[2] = 2.0f * q[2] * q[0] + 2.0f * q[3] * q[1];
288         res[3] = 0.0f;
289         res[4] = 2.0f * q[0] * q[1] + 2.0f * q[3] * q[2];
290         res[5] = 1.0f - 2.0f * q[0]*q[0] - 2.0f * q[2]*q[2];
291         res[6] = 2.0f * q[1] * q[2] - 2.0f * q[3] * q[0];
292         res[7] = 0.0f;
293         res[8] = 2.0f * q[2] * q[0] - 2.0f * q[3] * q[1];
294         res[9] = 2.0f * q[1] * q[2] + 2.0f * q[3] * q[0];
295         res[10] = 1.0f - 2.0f * q[0]*q[0] - 2.0f * q[1]*q[1];
296         res[11] = 0.0f;
297         res[12] = res[13] = res[14] = 0.0f;
298         res[15] = 1.0f;
299 }
300