/* polytopes --- Shows one of the six regular polytopes rotating in 4d */
#if 0
-static const char sccsid[] = "@(#)polytopes.c 1.1 03/05/18 xlockmore";
+static const char sccsid[] = "@(#)polytopes.c 1.2 05/09/28 xlockmore";
#endif
-/* Copyright (c) 2003 Carsten Steger <carsten@mirsanmir.org>. */
+/* Copyright (c) 2003-2005 Carsten Steger <carsten@mirsanmir.org>. */
/*
* Permission to use, copy, modify, and distribute this software and its
*
* REVISION HISTORY:
* C. Steger - 03/08/10: Initial version
+ * C. Steger - 05/09/28: Added trackball support
*/
/*
#define DEF_DTHETA DTHETA_STR
#ifdef STANDALONE
-# define PROGCLASS "Polytopes"
-# define HACK_INIT init_polytopes
-# define HACK_DRAW draw_polytopes
-# define HACK_RESHAPE reshape_polytopes
-# define polytopes_opts xlockmore_opts
-# define DEFAULTS "*delay: 25000 \n" \
- "*showFPS: False \n"
+# define PROGCLASS "Polytopes"
+# define HACK_INIT init_polytopes
+# define HACK_DRAW draw_polytopes
+# define HACK_RESHAPE reshape_polytopes
+# define HACK_HANDLE_EVENT polytopes_handle_event
+# define EVENT_MASK PointerMotionMask|KeyReleaseMask
+# define polytopes_opts xlockmore_opts
+# define DEFAULTS "*delay: 25000 \n" \
+ "*showFPS: False \n"
# include "xlockmore.h" /* from the xscreensaver distribution */
#else /* !STANDALONE */
#ifdef USE_GL
+#include <X11/keysym.h>
#include <GL/gl.h>
#include <GL/glu.h>
+#include "gltrackball.h"
#ifdef USE_MODULES
static float alpha, beta, delta, zeta, eta, theta;
static float aspect;
+/* Trackball states */
+trackball_state *trackballs[2];
+int current_trackball;
+Bool button_pressed;
+
static const float offset4d[4] = { 0.0, 0.0, 0.0, 3.0 };
static const float offset3d[4] = { 0.0, 0.0, -2.0, 0.0 };
/* Compute the rotation matrix m from the rotation angles. */
-static void rotateall(float m[4][4])
+static void rotateall(float al, float be, float de, float ze, float et,
+ float th, float m[4][4])
{
int i, j;
for (i=0; i<4; i++)
for (j=0; j<4; j++)
m[i][j] = (i==j);
- rotatewx(m,alpha);
- rotatewy(m,beta);
- rotatewz(m,delta);
- rotatexy(m,zeta);
- rotatexz(m,eta);
- rotateyz(m,theta);
+ rotatewx(m,al);
+ rotatewy(m,be);
+ rotatewz(m,de);
+ rotatexy(m,ze);
+ rotatexz(m,et);
+ rotateyz(m,th);
+}
+
+
+/* Multiply two rotation matrices: o=m*n. */
+static void mult_rotmat(float m[4][4], float n[4][4], float o[4][4])
+{
+ int i, j, k;
+
+ for (i=0; i<4; i++)
+ {
+ for (j=0; j<4; j++)
+ {
+ o[i][j] = 0.0;
+ for (k=0; k<4; k++)
+ o[i][j] += m[i][k]*n[k][j];
+ }
+ }
+}
+
+
+/* Compute a 4D rotation matrix from two unit quaternions. */
+static void quats_to_rotmat(float p[4], float q[4], float m[4][4])
+{
+ double al, be, de, ze, et, th;
+ double r00, r01, r02, r12, r22;
+
+ r00 = 1.0-2.0*(p[1]*p[1]+p[2]*p[2]);
+ r01 = 2.0*(p[0]*p[1]+p[2]*p[3]);
+ r02 = 2.0*(p[2]*p[0]-p[1]*p[3]);
+ r12 = 2.0*(p[1]*p[2]+p[0]*p[3]);
+ r22 = 1.0-2.0*(p[1]*p[1]+p[0]*p[0]);
+
+ al = atan2(-r12,r22)*180.0/M_PI;
+ be = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
+ de = atan2(-r01,r00)*180.0/M_PI;
+
+ r00 = 1.0-2.0*(q[1]*q[1]+q[2]*q[2]);
+ r01 = 2.0*(q[0]*q[1]+q[2]*q[3]);
+ r02 = 2.0*(q[2]*q[0]-q[1]*q[3]);
+ r12 = 2.0*(q[1]*q[2]+q[0]*q[3]);
+ r22 = 1.0-2.0*(q[1]*q[1]+q[0]*q[0]);
+
+ ze = atan2(-r12,r22)*180.0/M_PI;
+ et = atan2(r02,sqrt(r00*r00+r01*r01))*180.0/M_PI;
+ th = atan2(-r01,r00)*180.0/M_PI;
+
+ rotateall(al,be,de,ze,et,th,m);
}
/* Project an array of vertices from 4d to 3d. */
static void project(float vert[][4], float v[][4], int num)
{
- float m[4][4], s;
+ float s, q1[4], q2[4], r1[4][4], r2[4][4], m[4][4];
int i, j, k;
- rotateall(m);
+ rotateall(alpha,beta,delta,zeta,eta,theta,r1);
+
+ gltrackball_get_quaternion(trackballs[0],q1);
+ gltrackball_get_quaternion(trackballs[1],q2);
+ quats_to_rotmat(q1,q2,r2);
+
+ mult_rotmat(r2,r1,m);
/* Project the vertices from 4d to 3d. */
for (i=0; i<num; i++)
/* Redisplay the polytopes. */
static void display_polytopes(ModeInfo *mi)
{
- alpha += speed_wx;
- if (alpha >= 360.0)
- alpha -= 360.0;
- beta += speed_wy;
- if (beta >= 360.0)
- beta -= 360.0;
- delta += speed_wz;
- if (delta >= 360.0)
- delta -= 360.0;
- zeta += speed_xy;
- if (zeta >= 360.0)
- zeta -= 360.0;
- eta += speed_xz;
- if (eta >= 360.0)
- eta -= 360.0;
- theta += speed_yz;
- if (theta >= 360.0)
- theta -= 360.0;
+ if (!button_pressed)
+ {
+ alpha += speed_wx;
+ if (alpha >= 360.0)
+ alpha -= 360.0;
+ beta += speed_wy;
+ if (beta >= 360.0)
+ beta -= 360.0;
+ delta += speed_wz;
+ if (delta >= 360.0)
+ delta -= 360.0;
+ zeta += speed_xy;
+ if (zeta >= 360.0)
+ zeta -= 360.0;
+ eta += speed_xz;
+ if (eta >= 360.0)
+ eta -= 360.0;
+ theta += speed_yz;
+ if (theta >= 360.0)
+ theta -= 360.0;
+ }
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
}
+Bool polytopes_handle_event(ModeInfo *mi, XEvent *event)
+{
+ Display *display = MI_DISPLAY(mi);
+ KeySym sym;
+
+ if (event->xany.type == ButtonPress &&
+ event->xbutton.button == Button1)
+ {
+ button_pressed = True;
+ gltrackball_start(trackballs[current_trackball],
+ event->xbutton.x, event->xbutton.y,
+ MI_WIDTH(mi), MI_HEIGHT(mi));
+ return True;
+ }
+ else if (event->xany.type == ButtonRelease &&
+ event->xbutton.button == Button1)
+ {
+ button_pressed = False;
+ return True;
+ }
+ else if (event->xany.type == KeyPress)
+ {
+ sym = XKeycodeToKeysym(display,event->xkey.keycode,0);
+ if (sym == XK_Shift_L || sym == XK_Shift_R)
+ {
+ current_trackball = 1;
+ if (button_pressed)
+ gltrackball_start(trackballs[current_trackball],
+ event->xbutton.x, event->xbutton.y,
+ MI_WIDTH(mi), MI_HEIGHT(mi));
+ return True;
+ }
+ }
+ else if (event->xany.type == KeyRelease)
+ {
+ sym = XKeycodeToKeysym(display,event->xkey.keycode,0);
+ if (sym == XK_Shift_L || sym == XK_Shift_R)
+ {
+ current_trackball = 0;
+ if (button_pressed)
+ gltrackball_start(trackballs[current_trackball],
+ event->xbutton.x, event->xbutton.y,
+ MI_WIDTH(mi), MI_HEIGHT(mi));
+ return True;
+ }
+ }
+ else if (event->xany.type == MotionNotify && button_pressed)
+ {
+ gltrackball_track(trackballs[current_trackball],
+ event->xmotion.x, event->xmotion.y,
+ MI_WIDTH(mi), MI_HEIGHT(mi));
+ return True;
+ }
+
+ return False;
+}
+
+
/*
*-----------------------------------------------------------------------------
*-----------------------------------------------------------------------------
}
hp = &poly[MI_SCREEN(mi)];
+ trackballs[0] = gltrackball_init();
+ trackballs[1] = gltrackball_init();
+ current_trackball = 0;
+ button_pressed = False;
+
if ((hp->glx_context = init_GL(mi)) != NULL)
{
reshape_polytopes(mi,MI_WIDTH(mi),MI_HEIGHT(mi));