backported fixes from deeprunner
[miniglut] / test.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <math.h>
4 #include "miniglut.h"
5
6 void idle(void);
7 void display(void);
8 void reshape(int x, int y);
9 void keypress(unsigned char key, int x, int y);
10 void mouse(int bn, int st, int x, int y);
11 void motion(int x, int y);
12 void sball_motion(int x, int y, int z);
13 void sball_rotate(int rx, int ry, int rz);
14 void sball_button(int bn, int state);
15
16 static void vcross(float *res, const float *a, const float *b);
17 static void qmul(float *a, const float *b);
18 static void qrotation(float *q, float angle, float x, float y, float z);
19 static void qrotate(float *q, float angle, float x, float y, float z);
20 static void mrotation_quat(float *m, const float *q);
21
22
23 float cam_theta, cam_phi = 25, cam_dist = 8;
24 int mouse_x, mouse_y;
25 int bnstate[8];
26 int anim;
27 float torus_pos[3], torus_rot[4] = {0, 0, 0, 1};
28 int teapot, torus, cone, sphere;
29 long nframes;
30
31 #ifndef GL_FRAMEBUFFER_SRGB
32 #define GL_FRAMEBUFFER_SRGB     0x8db9
33 #endif
34
35 #ifndef GL_MULTISAMPLE
36 #define GL_MULTISAMPLE 0x809d
37 #endif
38
39 int main(int argc, char **argv)
40 {
41         int i, test_aa = 0, test_srgb = 0;
42         unsigned int mode = GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE;
43
44         for(i=1; i<argc; i++) {
45                 if(strcmp(argv[i], "-ms") == 0) {
46                         test_aa = 1;
47                 } else if(strcmp(argv[i], "-srgb") == 0) {
48                         test_srgb = 1;
49                 }
50         }
51
52         if(test_aa) mode |= GLUT_MULTISAMPLE;
53         if(test_srgb) mode |= GLUT_SRGB;
54
55         glutInit(&argc, argv);
56         glutInitWindowSize(800, 600);
57         glutInitDisplayMode(mode);
58         glutCreateWindow("miniglut test");
59
60         glutDisplayFunc(display);
61         glutReshapeFunc(reshape);
62         glutKeyboardFunc(keypress);
63         glutMouseFunc(mouse);
64         glutMotionFunc(motion);
65         glutSpaceballMotionFunc(sball_motion);
66         glutSpaceballRotateFunc(sball_rotate);
67         glutSpaceballButtonFunc(sball_button);
68
69         glEnable(GL_DEPTH_TEST);
70         glEnable(GL_CULL_FACE);
71         glEnable(GL_LIGHTING);
72         glEnable(GL_LIGHT0);
73
74         if(test_aa) {
75                 glEnable(GL_MULTISAMPLE);
76         }
77         if(test_srgb) {
78                 glEnable(GL_FRAMEBUFFER_SRGB);
79         }
80
81         torus = glGenLists(1);
82         glNewList(torus, GL_COMPILE);
83         glutSolidTorus(0.3, 1, 16, 24);
84         glEndList();
85
86         cone = glGenLists(1);
87         glNewList(cone, GL_COMPILE);
88         glutSolidCone(1.1, 2, 16, 2);
89         glEndList();
90
91         sphere = glGenLists(1);
92         glNewList(sphere, GL_COMPILE);
93         glutSolidSphere(0.4, 16, 8);
94         glEndList();
95
96         teapot = glGenLists(1);
97         glNewList(teapot, GL_COMPILE);
98         glutSolidTeapot(1.0);
99         glEndList();
100
101         glutMainLoop();
102         return 0;
103 }
104
105 void idle(void)
106 {
107         glutPostRedisplay();
108 }
109
110 void display(void)
111 {
112         long tm;
113         float lpos[] = {-1, 2, 3, 0};
114         float sbrot_xform[16];
115
116         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
117
118         glMatrixMode(GL_MODELVIEW);
119         glLoadIdentity();
120         glTranslatef(0, 0, -cam_dist);
121         glRotatef(cam_phi, 1, 0, 0);
122         glRotatef(cam_theta, 0, 1, 0);
123
124         glLightfv(GL_LIGHT0, GL_POSITION, lpos);
125
126         glPushMatrix();
127         if(anim) {
128                 tm = glutGet(GLUT_ELAPSED_TIME);
129                 glRotatef(tm / 10.0f, 1, 0, 0);
130                 glRotatef(tm / 10.0f, 0, 1, 0);
131         }
132         glCallList(torus);
133         glPopMatrix();
134
135         glCallList(sphere);
136
137         glPushMatrix();
138         glTranslatef(torus_pos[0] - 2.5, torus_pos[1], torus_pos[2]);
139         mrotation_quat(sbrot_xform, torus_rot);
140         glMultMatrixf(sbrot_xform);
141         glutSolidCube(1.5);
142         glPopMatrix();
143
144         glPushMatrix();
145         glTranslatef(2.5, -1, 0);
146         glRotatef(-90, 1, 0, 0);
147         glCallList(cone);
148         glPopMatrix();
149
150         glPushMatrix();
151         glTranslatef(0, -0.5, 2.5);
152         glFrontFace(GL_CW);
153         glCallList(teapot);
154         glFrontFace(GL_CCW);
155         glPopMatrix();
156
157         glBegin(GL_QUADS);
158         glNormal3f(0, 1, 0);
159         glVertex3f(-5, -1.3, 5);
160         glVertex3f(5, -1.3, 5);
161         glVertex3f(5, -1.3, -5);
162         glVertex3f(-5, -1.3, -5);
163         glEnd();
164
165         glutSwapBuffers();
166         nframes++;
167 }
168
169 #define ZNEAR   0.5f
170 void reshape(int x, int y)
171 {
172         float vsz, aspect = (float)x / (float)y;
173         glViewport(0, 0, x, y);
174         glMatrixMode(GL_PROJECTION);
175         glLoadIdentity();
176         vsz = 0.4663f * ZNEAR;
177         glFrustum(-aspect * vsz, aspect * vsz, -vsz, vsz, 0.5, 500.0);
178 }
179
180 void keypress(unsigned char key, int x, int y)
181 {
182         static int fullscr;
183         static int prev_xsz, prev_ysz;
184         static long start_msec;
185
186         switch(key) {
187         case 27:
188         case 'q':
189                 glutExit();
190                 break;
191
192         case ' ':
193                 anim ^= 1;
194                 glutIdleFunc(anim ? idle : 0);
195                 glutPostRedisplay();
196
197                 if(anim) {
198                         start_msec = glutGet(GLUT_ELAPSED_TIME);
199                         nframes = 0;
200                 } else {
201                         long tm = glutGet(GLUT_ELAPSED_TIME) - start_msec;
202                         long fps = (nframes * 100000) / tm;
203                         printf("framerate: %ld.%ld fps\n", fps / 100, fps % 100);
204                 }
205                 break;
206
207         case '\n':
208         case '\r':
209                 if(!(glutGetModifiers() & GLUT_ACTIVE_ALT)) {
210                         break;
211                 }
212         case 'f':
213                 fullscr ^= 1;
214                 if(fullscr) {
215                         prev_xsz = glutGet(GLUT_WINDOW_WIDTH);
216                         prev_ysz = glutGet(GLUT_WINDOW_HEIGHT);
217                         glutFullScreen();
218                 } else {
219                         glutReshapeWindow(prev_xsz, prev_ysz);
220                 }
221                 break;
222         }
223 }
224
225 void mouse(int bn, int st, int x, int y)
226 {
227         int bidx = bn - GLUT_LEFT_BUTTON;
228         bnstate[bidx] = st == GLUT_DOWN;
229         mouse_x = x;
230         mouse_y = y;
231 }
232
233 void motion(int x, int y)
234 {
235         int dx = x - mouse_x;
236         int dy = y - mouse_y;
237         mouse_x = x;
238         mouse_y = y;
239
240         if(!(dx | dy)) return;
241
242         if(bnstate[0]) {
243                 cam_theta += dx * 0.5;
244                 cam_phi += dy * 0.5;
245                 if(cam_phi < -90) cam_phi = -90;
246                 if(cam_phi > 90) cam_phi = 90;
247                 glutPostRedisplay();
248         }
249         if(bnstate[2]) {
250                 cam_dist += dy * 0.1;
251                 if(cam_dist < 0) cam_dist = 0;
252                 glutPostRedisplay();
253         }
254 }
255
256 void sball_motion(int x, int y, int z)
257 {
258         torus_pos[0] += x * 0.001f;
259         torus_pos[1] += y * 0.001f;
260         torus_pos[2] -= z * 0.001f;
261         glutPostRedisplay();
262 }
263
264 static float rsqrt(float number)
265 {
266         int i;
267         float x2, y;
268         static const float threehalfs = 1.5f;
269
270         x2 = number * 0.5f;
271         y = number;
272         i = *(int*)&y;
273         i = 0x5f3759df - (i >> 1);
274         y = *(float*)&i;
275         y *= threehalfs - (x2 * y * y);
276         y *= threehalfs - (x2 * y * y);
277         return y;
278 }
279
280 void sball_rotate(int rx, int ry, int rz)
281 {
282         if(rx | ry | rz) {
283                 float s = (float)rsqrt(rx * rx + ry * ry + rz * rz);
284                 qrotate(torus_rot, 0.001f / s, rx * s, ry * s, -rz * s);
285                 glutPostRedisplay();
286         }
287 }
288
289 void sball_button(int bn, int state)
290 {
291         if(state == GLUT_DOWN) {
292                 torus_pos[0] = torus_pos[1] = torus_pos[2] = 0;
293                 torus_rot[0] = torus_rot[1] = torus_rot[2] = 0;
294                 torus_rot[3] = 1;
295                 glutPostRedisplay();
296         }
297 }
298
299
300 static void vcross(float *res, const float *a, const float *b)
301 {
302         res[0] = a[1] * b[2] - a[2] * b[1];
303         res[1] = a[2] * b[0] - a[0] * b[2];
304         res[2] = a[0] * b[1] - a[1] * b[0];
305 }
306
307 static void qmul(float *a, const float *b)
308 {
309         float x, y, z, dot;
310         float cross[3];
311
312         dot = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
313         vcross(cross, a, b);
314
315         x = a[3] * b[0] + b[3] * a[0] + cross[0];
316         y = a[3] * b[1] + b[3] * a[1] + cross[1];
317         z = a[3] * b[2] + b[3] * a[2] + cross[2];
318         a[3] = a[3] * b[3] - dot;
319         a[0] = x;
320         a[1] = y;
321         a[2] = z;
322 }
323
324 void mglut_sincos(float angle, float *sptr, float *cptr);
325 float mglut_tan(float x);
326
327 static void qrotation(float *q, float angle, float x, float y, float z)
328 {
329         float sa, ca;
330         mglut_sincos(angle * 0.5f, &sa, &ca);
331         q[3] = ca;
332         q[0] = x * sa;
333         q[1] = y * sa;
334         q[2] = z * sa;
335 }
336
337 static void qrotate(float *q, float angle, float x, float y, float z)
338 {
339         float qrot[4];
340         qrotation(qrot, angle, x, y, z);
341         qmul(qrot, q);
342         q[0] = qrot[0];
343         q[1] = qrot[1];
344         q[2] = qrot[2];
345         q[3] = qrot[3];
346 }
347
348 static void mrotation_quat(float *m, const float *q)
349 {
350         float xsq2 = 2.0f * q[0] * q[0];
351         float ysq2 = 2.0f * q[1] * q[1];
352         float zsq2 = 2.0f * q[2] * q[2];
353         float sx = 1.0f - ysq2 - zsq2;
354         float sy = 1.0f - xsq2 - zsq2;
355         float sz = 1.0f - xsq2 - ysq2;
356
357         m[3] = m[7] = m[11] = m[12] = m[13] = m[14] = 0.0f;
358         m[15] = 1.0f;
359
360         m[0] = sx;
361         m[1] = 2.0f * q[0] * q[1] + 2.0f * q[3] * q[2];
362         m[2] = 2.0f * q[2] * q[0] - 2.0f * q[3] * q[1];
363         m[4] = 2.0f * q[0] * q[1] - 2.0f * q[3] * q[2];
364         m[5] = sy;
365         m[6] = 2.0f * q[1] * q[2] + 2.0f * q[3] * q[0];
366         m[8] = 2.0f * q[2] * q[0] + 2.0f * q[3] * q[1];
367         m[9] = 2.0f * q[1] * q[2] - 2.0f * q[3] * q[0];
368         m[10] = sz;
369 }