http://www.tienza.es/crux/src/www.jwz.org/xscreensaver/xscreensaver-5.05.tar.gz
[xscreensaver] / hacks / glx / gltrackball.c
1 /* gltrackball, Copyright (c) 2002-2008 Jamie Zawinski <jwz@jwz.org>
2  * GL-flavored wrapper for trackball.c
3  *
4  * Permission to use, copy, modify, distribute, and sell this software and its
5  * documentation for any purpose is hereby granted without fee, provided that
6  * the above copyright notice appear in all copies and that both that
7  * copyright notice and this permission notice appear in supporting
8  * documentation.  No representations are made about the suitability of this
9  * software for any purpose.  It is provided "as is" without express or 
10  * implied warranty.
11  */
12
13 #include <math.h>
14 #include <stdlib.h>
15
16 #ifdef HAVE_CONFIG_H
17 # include "config.h"
18 #endif
19
20 #ifdef HAVE_COCOA
21 # include <OpenGL/gl.h>
22 #else
23 # include <GL/gl.h>
24 #endif
25
26 #include "trackball.h"
27 #include "gltrackball.h"
28
29 struct trackball_state {
30   int x, y;
31   GLfloat q[4];
32 };
33
34 /* Returns a trackball_state object, which encapsulates the stuff necessary
35    to make dragging the mouse on the window of a GL program do the right thing.
36  */
37 trackball_state *
38 gltrackball_init (void)
39 {
40   trackball_state *ts = (trackball_state *) calloc (1, sizeof (*ts));
41   if (!ts) return 0;
42   trackball (ts->q, 0, 0, 0, 0);
43   return ts;
44 }
45
46 /* Begin tracking the mouse: Call this when the mouse button goes down.
47    x and y are the mouse position relative to the window.
48    w and h are the size of the window.
49  */
50 void
51 gltrackball_start (trackball_state *ts, int x, int y, int w, int h)
52 {
53   ts->x = x;
54   ts->y = y;
55 }
56
57 /* Track the mouse: Call this each time the mouse moves with the button down.
58    x and y are the new mouse position relative to the window.
59    w and h are the size of the window.
60  */
61 void
62 gltrackball_track (trackball_state *ts, int x, int y, int w, int h)
63 {
64   float q2[4];
65   trackball (q2,
66              (2.0 * ts->x - w) / w,
67              (h - 2.0 * ts->y) / h,
68              (2.0 * x - w) / w,
69              (h - 2.0 * y) / h);
70   ts->x = x;
71   ts->y = y;
72   add_quats (q2, ts->q, ts->q);
73 }
74
75 /* Execute the rotations current encapsulated in the trackball_state:
76    this does something analagous to glRotatef().
77  */
78 void
79 gltrackball_rotate (trackball_state *ts)
80 {
81   GLfloat m[4][4];
82   build_rotmatrix (m, ts->q);
83   glMultMatrixf (&m[0][0]);
84 }
85
86
87 # define Button4 4  /* X11/Xlib.h */
88 # define Button5 5
89 # define Button6 6
90 # define Button7 7
91
92 /* Call this when a mouse-wheel click is detected.
93    Clicks act like horizontal or vertical drags.
94    Percent is the length of the drag as a percentage of the screen size.
95    Button is 'Button4' or 'Button5' (for the vertical wheel)
96    or 'Button5' or 'Button6' (for the horizontal wheel).
97    If `flip_p' is true, swap the horizontal and vertical axes.
98  */
99 void
100 gltrackball_mousewheel (trackball_state *ts,
101                         int button, int percent, int flip_p)
102 {
103   int up_p;
104   double move;
105   int horizontal_p;
106
107 #ifdef HAVE_COCOA
108   flip_p = 0;      /* MacOS has already handled this. */
109 #endif
110
111   switch (button) {
112   case Button4: up_p = 1; horizontal_p = 0; break;
113   case Button5: up_p = 0; horizontal_p = 0; break;
114   case Button6: up_p = 1; horizontal_p = 1; break;
115   case Button7: up_p = 0; horizontal_p = 1; break;
116   default: abort(); break;
117   }
118
119   if (flip_p)
120     {
121       horizontal_p = !horizontal_p;
122       up_p = !up_p;
123     }
124
125   move = (up_p
126           ? 1.0 - (percent / 100.0)
127           : 1.0 + (percent / 100.0));
128
129   gltrackball_start (ts, 50, 50, 100, 100);
130   if (horizontal_p)
131     gltrackball_track (ts, 50*move, 50, 100, 100);
132   else
133     gltrackball_track (ts, 50, 50*move, 100, 100);
134 }
135
136 void
137 gltrackball_get_quaternion (trackball_state *ts, float q[4])
138 {
139   int i;
140   for (i=0; i<4; i++)
141     q[i] = ts->q[i];
142 }