+
+void demo_sball_motion(int x, int y, int z)
+{
+ cgm_vec3 dir;
+ dir.x = (float)x * 0.001;
+ dir.y = (float)y * 0.001;
+ dir.z = (float)-z * 0.001;
+ cgm_vadd(&obj_pos, &dir);
+
+ cgm_vrotate_quat(&dir, &cam_rot);
+ cgm_vadd(&cam_pos, &dir);
+
+ 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) {
+ cgm_quat q;
+ cgm_qrotation(&q, -axis_len * 0.001, rx / axis_len, ry / axis_len, -rz / axis_len);
+ cgm_qmul(&obj_rot, &q);
+
+ cgm_qrotation(&q, axis_len * 0.001, rx / axis_len, ry / axis_len, -rz / axis_len);
+ cgm_qmul(&cam_rot, &q);
+ }
+ sball_update_pending = 1;
+}
+
+void demo_sball_button(int bn, int pressed)
+{
+ if(!pressed) return;
+
+ switch(bn) {
+ case 0:
+ cgm_vcons(&obj_pos, 0, 0, 0);
+ cgm_vcons(&cam_pos, 0, 0, 0);
+ cgm_qcons(&obj_rot, 0, 0, 0, 1);
+ cgm_qcons(&cam_rot, 0, 0, 0, 1);
+ sball_update_pending = 1;
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+static void recalc_sball_matrix(float *objmat, float *cammat)
+{
+ float rmat[16], tmat[16];
+
+ cgm_mrotation_quat(rmat, &cam_rot);
+ cgm_mtranspose(rmat);
+
+ cgm_mtranslation(tmat, -cam_pos.x, -cam_pos.y, -cam_pos.z);
+ cgm_mcopy(cammat, tmat);
+ cgm_mmul(cammat, rmat);
+
+ cgm_mrotation_quat(rmat, &obj_rot);
+ cgm_mtranspose(rmat);
+
+ cgm_mtranslation(tmat, obj_pos.x, obj_pos.y, obj_pos.z);
+ cgm_mcopy(objmat, rmat);
+ cgm_mmul(objmat, tmat);
+}