backported fixes from deeprunner
[miniglut] / test.c
diff --git a/test.c b/test.c
index f57e44d..57a22e4 100644 (file)
--- a/test.c
+++ b/test.c
@@ -1,3 +1,6 @@
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
 #include "miniglut.h"
 
 void idle(void);
@@ -6,17 +9,52 @@ void reshape(int x, int y);
 void keypress(unsigned char key, int x, int y);
 void mouse(int bn, int st, int x, int y);
 void motion(int x, int y);
+void sball_motion(int x, int y, int z);
+void sball_rotate(int rx, int ry, int rz);
+void sball_button(int bn, int state);
+
+static void vcross(float *res, const float *a, const float *b);
+static void qmul(float *a, const float *b);
+static void qrotation(float *q, float angle, float x, float y, float z);
+static void qrotate(float *q, float angle, float x, float y, float z);
+static void mrotation_quat(float *m, const float *q);
+
 
 float cam_theta, cam_phi = 25, cam_dist = 8;
 int mouse_x, mouse_y;
 int bnstate[8];
 int anim;
+float torus_pos[3], torus_rot[4] = {0, 0, 0, 1};
+int teapot, torus, cone, sphere;
+long nframes;
+
+#ifndef GL_FRAMEBUFFER_SRGB
+#define GL_FRAMEBUFFER_SRGB    0x8db9
+#endif
+
+#ifndef GL_MULTISAMPLE
+#define GL_MULTISAMPLE 0x809d
+#endif
 
 int main(int argc, char **argv)
 {
+       int i, test_aa = 0, test_srgb = 0;
+       unsigned int mode = GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE;
+
+       for(i=1; i<argc; i++) {
+               if(strcmp(argv[i], "-ms") == 0) {
+                       test_aa = 1;
+               } else if(strcmp(argv[i], "-srgb") == 0) {
+                       test_srgb = 1;
+               }
+       }
+
+       if(test_aa) mode |= GLUT_MULTISAMPLE;
+       if(test_srgb) mode |= GLUT_SRGB;
+
        glutInit(&argc, argv);
-       glutInitWindowSize(1024, 768);
-       glutInitDisplayMode(GLUT_RGB | GLUT_DEPTH | GLUT_DOUBLE);
+       glutInitWindowSize(800, 600);
+       glutInitDisplayMode(mode);
        glutCreateWindow("miniglut test");
 
        glutDisplayFunc(display);
@@ -24,12 +62,42 @@ int main(int argc, char **argv)
        glutKeyboardFunc(keypress);
        glutMouseFunc(mouse);
        glutMotionFunc(motion);
+       glutSpaceballMotionFunc(sball_motion);
+       glutSpaceballRotateFunc(sball_rotate);
+       glutSpaceballButtonFunc(sball_button);
 
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);
        glEnable(GL_LIGHTING);
        glEnable(GL_LIGHT0);
 
+       if(test_aa) {
+               glEnable(GL_MULTISAMPLE);
+       }
+       if(test_srgb) {
+               glEnable(GL_FRAMEBUFFER_SRGB);
+       }
+
+       torus = glGenLists(1);
+       glNewList(torus, GL_COMPILE);
+       glutSolidTorus(0.3, 1, 16, 24);
+       glEndList();
+
+       cone = glGenLists(1);
+       glNewList(cone, GL_COMPILE);
+       glutSolidCone(1.1, 2, 16, 2);
+       glEndList();
+
+       sphere = glGenLists(1);
+       glNewList(sphere, GL_COMPILE);
+       glutSolidSphere(0.4, 16, 8);
+       glEndList();
+
+       teapot = glGenLists(1);
+       glNewList(teapot, GL_COMPILE);
+       glutSolidTeapot(1.0);
+       glEndList();
+
        glutMainLoop();
        return 0;
 }
@@ -43,8 +111,7 @@ void display(void)
 {
        long tm;
        float lpos[] = {-1, 2, 3, 0};
-
-       tm = glutGet(GLUT_ELAPSED_TIME);
+       float sbrot_xform[16];
 
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
 
@@ -58,23 +125,33 @@ void display(void)
 
        glPushMatrix();
        if(anim) {
+               tm = glutGet(GLUT_ELAPSED_TIME);
                glRotatef(tm / 10.0f, 1, 0, 0);
                glRotatef(tm / 10.0f, 0, 1, 0);
        }
-       glutSolidTorus(0.3, 1, 16, 24);
+       glCallList(torus);
        glPopMatrix();
 
-       glutSolidSphere(0.4, 16, 8);
+       glCallList(sphere);
 
        glPushMatrix();
-       glTranslatef(-2.5, 0, 0);
+       glTranslatef(torus_pos[0] - 2.5, torus_pos[1], torus_pos[2]);
+       mrotation_quat(sbrot_xform, torus_rot);
+       glMultMatrixf(sbrot_xform);
        glutSolidCube(1.5);
        glPopMatrix();
 
        glPushMatrix();
        glTranslatef(2.5, -1, 0);
        glRotatef(-90, 1, 0, 0);
-       glutSolidCone(1.1, 2, 16, 2);
+       glCallList(cone);
+       glPopMatrix();
+
+       glPushMatrix();
+       glTranslatef(0, -0.5, 2.5);
+       glFrontFace(GL_CW);
+       glCallList(teapot);
+       glFrontFace(GL_CCW);
        glPopMatrix();
 
        glBegin(GL_QUADS);
@@ -86,6 +163,7 @@ void display(void)
        glEnd();
 
        glutSwapBuffers();
+       nframes++;
 }
 
 #define ZNEAR  0.5f
@@ -102,6 +180,8 @@ void reshape(int x, int y)
 void keypress(unsigned char key, int x, int y)
 {
        static int fullscr;
+       static int prev_xsz, prev_ysz;
+       static long start_msec;
 
        switch(key) {
        case 27:
@@ -113,14 +193,30 @@ void keypress(unsigned char key, int x, int y)
                anim ^= 1;
                glutIdleFunc(anim ? idle : 0);
                glutPostRedisplay();
+
+               if(anim) {
+                       start_msec = glutGet(GLUT_ELAPSED_TIME);
+                       nframes = 0;
+               } else {
+                       long tm = glutGet(GLUT_ELAPSED_TIME) - start_msec;
+                       long fps = (nframes * 100000) / tm;
+                       printf("framerate: %ld.%ld fps\n", fps / 100, fps % 100);
+               }
                break;
 
+       case '\n':
+       case '\r':
+               if(!(glutGetModifiers() & GLUT_ACTIVE_ALT)) {
+                       break;
+               }
        case 'f':
                fullscr ^= 1;
                if(fullscr) {
+                       prev_xsz = glutGet(GLUT_WINDOW_WIDTH);
+                       prev_ysz = glutGet(GLUT_WINDOW_HEIGHT);
                        glutFullScreen();
                } else {
-                       glutPositionWindow(10, 10);
+                       glutReshapeWindow(prev_xsz, prev_ysz);
                }
                break;
        }
@@ -156,3 +252,118 @@ void motion(int x, int y)
                glutPostRedisplay();
        }
 }
+
+void sball_motion(int x, int y, int z)
+{
+       torus_pos[0] += x * 0.001f;
+       torus_pos[1] += y * 0.001f;
+       torus_pos[2] -= z * 0.001f;
+       glutPostRedisplay();
+}
+
+static float rsqrt(float number)
+{
+       int i;
+       float x2, y;
+       static const float threehalfs = 1.5f;
+
+       x2 = number * 0.5f;
+       y = number;
+       i = *(int*)&y;
+       i = 0x5f3759df - (i >> 1);
+       y = *(float*)&i;
+       y *= threehalfs - (x2 * y * y);
+       y *= threehalfs - (x2 * y * y);
+       return y;
+}
+
+void sball_rotate(int rx, int ry, int rz)
+{
+       if(rx | ry | rz) {
+               float s = (float)rsqrt(rx * rx + ry * ry + rz * rz);
+               qrotate(torus_rot, 0.001f / s, rx * s, ry * s, -rz * s);
+               glutPostRedisplay();
+       }
+}
+
+void sball_button(int bn, int state)
+{
+       if(state == GLUT_DOWN) {
+               torus_pos[0] = torus_pos[1] = torus_pos[2] = 0;
+               torus_rot[0] = torus_rot[1] = torus_rot[2] = 0;
+               torus_rot[3] = 1;
+               glutPostRedisplay();
+       }
+}
+
+
+static void vcross(float *res, const float *a, const float *b)
+{
+       res[0] = a[1] * b[2] - a[2] * b[1];
+       res[1] = a[2] * b[0] - a[0] * b[2];
+       res[2] = a[0] * b[1] - a[1] * b[0];
+}
+
+static void qmul(float *a, const float *b)
+{
+       float x, y, z, dot;
+       float cross[3];
+
+       dot = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
+       vcross(cross, a, b);
+
+       x = a[3] * b[0] + b[3] * a[0] + cross[0];
+       y = a[3] * b[1] + b[3] * a[1] + cross[1];
+       z = a[3] * b[2] + b[3] * a[2] + cross[2];
+       a[3] = a[3] * b[3] - dot;
+       a[0] = x;
+       a[1] = y;
+       a[2] = z;
+}
+
+void mglut_sincos(float angle, float *sptr, float *cptr);
+float mglut_tan(float x);
+
+static void qrotation(float *q, float angle, float x, float y, float z)
+{
+       float sa, ca;
+       mglut_sincos(angle * 0.5f, &sa, &ca);
+       q[3] = ca;
+       q[0] = x * sa;
+       q[1] = y * sa;
+       q[2] = z * sa;
+}
+
+static void qrotate(float *q, float angle, float x, float y, float z)
+{
+       float qrot[4];
+       qrotation(qrot, angle, x, y, z);
+       qmul(qrot, q);
+       q[0] = qrot[0];
+       q[1] = qrot[1];
+       q[2] = qrot[2];
+       q[3] = qrot[3];
+}
+
+static void mrotation_quat(float *m, const float *q)
+{
+       float xsq2 = 2.0f * q[0] * q[0];
+       float ysq2 = 2.0f * q[1] * q[1];
+       float zsq2 = 2.0f * q[2] * q[2];
+       float sx = 1.0f - ysq2 - zsq2;
+       float sy = 1.0f - xsq2 - zsq2;
+       float sz = 1.0f - xsq2 - ysq2;
+
+       m[3] = m[7] = m[11] = m[12] = m[13] = m[14] = 0.0f;
+       m[15] = 1.0f;
+
+       m[0] = sx;
+       m[1] = 2.0f * q[0] * q[1] + 2.0f * q[3] * q[2];
+       m[2] = 2.0f * q[2] * q[0] - 2.0f * q[3] * q[1];
+       m[4] = 2.0f * q[0] * q[1] - 2.0f * q[3] * q[2];
+       m[5] = sy;
+       m[6] = 2.0f * q[1] * q[2] + 2.0f * q[3] * q[0];
+       m[8] = 2.0f * q[2] * q[0] + 2.0f * q[3] * q[1];
+       m[9] = 2.0f * q[1] * q[2] - 2.0f * q[3] * q[0];
+       m[10] = sz;
+}