spaceball
[o2demo] / src / demo.c
index 5af3c86..2e444cf 100644 (file)
@@ -2,13 +2,20 @@
 #include <stdlib.h>
 #include <string.h>
 #include <ctype.h>
+#include <math.h>
 #include <GL/gl.h>
 #include <GL/glu.h>
 #include "demo.h"
 #include "screen.h"
 #include "cfgopt.h"
 
+static void recalc_sball_matrix(float *xform, float *inv_xform);
+
 static int console_active;
+static int sball_update_pending;
+
+static float pos[3];
+static float rot[4] = {0, 0, 0, 1};
 
 int demo_init(int argc, char **argv)
 {
@@ -28,6 +35,9 @@ int demo_init(int argc, char **argv)
        glEnable(GL_DEPTH_TEST);
        glEnable(GL_CULL_FACE);
 
+       sball_matrix[0] = sball_matrix[5] = sball_matrix[10] = sball_matrix[15] = 1.0f;
+       sball_inv_matrix[0] = sball_inv_matrix[5] = sball_inv_matrix[10] = sball_inv_matrix[15] = 1.0f;
+
        if(scr_init() == -1) {
                return -1;
        }
@@ -52,6 +62,11 @@ void demo_cleanup(void)
 
 void demo_draw(void)
 {
+       if(sball_update_pending) {
+               recalc_sball_matrix(sball_matrix, sball_inv_matrix);
+               sball_update_pending = 0;
+       }
+
        scr_update();
        scr_draw();
 }
@@ -165,3 +180,121 @@ void demo_mbutton(int bn, int pressed, int x, int y)
 void demo_mmotion(int x, int y)
 {
 }
+
+
+static void quat_rotate(float *qres, const float *q, float angle, float x, float y, float z);
+static void quat_mul(float *qres, const float *q1, const float *q2);
+static void quat_to_mat(float *res, const float *q);
+
+void demo_sball_motion(int x, int y, int z)
+{
+       pos[0] += (float)x * 0.01;
+       pos[1] += (float)y * 0.01;
+       pos[2] -= (float)z * 0.01;
+       sball_update_pending = 1;
+}
+
+void demo_sball_rotate(int x, int y, int z)
+{
+       float rx = (float)x;
+       float ry = (float)y;
+       float rz = (float)z;
+       float axis_len = sqrt(rx * rx + ry * ry + rz * rz);
+       if(axis_len > 0.0) {
+               quat_rotate(rot, rot, axis_len * 0.001, -rx / axis_len,
+                               -ry / axis_len, rz / axis_len);
+       }
+       sball_update_pending = 1;
+}
+
+void demo_sball_button(int bn, int pressed)
+{
+       if(!pressed) return;
+
+       switch(bn) {
+       case 0:
+               pos[0] = pos[1] = pos[2] = 0;
+               rot[0] = rot[1] = rot[2] = 0;
+               rot[3] = 1;
+               break;
+
+       default:
+               break;
+       }
+}
+
+static void recalc_sball_matrix(float *xform, float *inv_xform)
+{
+       float tx, ty, tz;
+
+       quat_to_mat(xform, rot);
+       xform[12] = pos[0];
+       xform[13] = pos[1];
+       xform[14] = pos[2];
+
+       inv_xform[0] = xform[0];
+       inv_xform[5] = xform[5];
+       inv_xform[10] = xform[10];
+       inv_xform[15] = 1.0f;
+
+       inv_xform[1] = xform[4];
+       inv_xform[2] = xform[8];
+       inv_xform[6] = xform[9];
+       inv_xform[4] = xform[1];
+       inv_xform[8] = xform[2];
+       inv_xform[9] = xform[6];
+
+       inv_xform[3] = inv_xform[7] = inv_xform[11] = 0.0f;
+       tx = -pos[0];
+       ty = -pos[1];
+       tz = -pos[2];
+
+       inv_xform[12] = tx * inv_xform[0] + ty * inv_xform[4] + tz * inv_xform[8];
+       inv_xform[13] = tx * inv_xform[1] + ty * inv_xform[5] + tz * inv_xform[9];
+       inv_xform[14] = tx * inv_xform[2] + ty * inv_xform[6] + tz * inv_xform[10];
+}
+
+static void quat_rotate(float *qres, const float *q, float angle, float x, float y, float z)
+{
+       float rq[4];
+       float half_angle = angle * 0.5f;
+       float sin_half = sin(half_angle);
+
+       rq[3] = cos(half_angle);
+       rq[0] = x * sin_half;
+       rq[1] = y * sin_half;
+       rq[2] = z * sin_half;
+
+       quat_mul(qres, q, rq);
+}
+
+static void quat_mul(float *qres, const float *q1, const float *q2)
+{
+       float w = q1[3] * q2[3] - (q1[0] * q2[0] + q1[1] * q2[1] + q1[2] * q2[2]);
+       float x = q2[0] * q1[3] + q1[0] * q2[3] + (q1[1] * q2[2] - q1[2] * q2[1]);
+       float y = q2[1] * q1[3] + q1[1] * q2[3] + (q1[2] * q2[0] - q1[0] * q2[2]);
+       float z = q2[2] * q1[3] + q1[2] * q2[3] + (q1[0] * q2[1] - q1[1] * q2[0]);
+       qres[0] = x;
+       qres[1] = y;
+       qres[2] = z;
+       qres[3] = w;
+}
+
+static void quat_to_mat(float *res, const float *q)
+{
+       res[0] = 1.0f - 2.0f * q[1]*q[1] - 2.0f * q[2]*q[2];
+       res[1] = 2.0f * q[0] * q[1] - 2.0f * q[3] * q[2];
+       res[2] = 2.0f * q[2] * q[0] + 2.0f * q[3] * q[1];
+       res[3] = 0.0f;
+       res[4] = 2.0f * q[0] * q[1] + 2.0f * q[3] * q[2];
+       res[5] = 1.0f - 2.0f * q[0]*q[0] - 2.0f * q[2]*q[2];
+       res[6] = 2.0f * q[1] * q[2] - 2.0f * q[3] * q[0];
+       res[7] = 0.0f;
+       res[8] = 2.0f * q[2] * q[0] - 2.0f * q[3] * q[1];
+       res[9] = 2.0f * q[1] * q[2] + 2.0f * q[3] * q[0];
+       res[10] = 1.0f - 2.0f * q[0]*q[0] - 2.0f * q[1]*q[1];
+       res[11] = 0.0f;
+       res[12] = res[13] = res[14] = 0.0f;
+       res[15] = 1.0f;
+}
+