http://ftp.ksu.edu.tw/FTP/FreeBSD/distfiles/xscreensaver-4.20.tar.gz
[xscreensaver] / hacks / glx / gltrackball.c
1 /* gltrackball, Copyright (c) 2002, 2005 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 "config.h"
14 #include <stdlib.h>
15 #include <math.h>
16 #include <GL/gl.h>
17 #include "trackball.h"
18 #include "gltrackball.h"
19
20 struct trackball_state {
21   int x, y;
22   GLfloat q[4];
23 };
24
25 /* Returns a trackball_state object, which encapsulates the stuff necessary
26    to make dragging the mouse on the window of a GL program do the right thing.
27  */
28 trackball_state *
29 gltrackball_init (void)
30 {
31   trackball_state *ts = (trackball_state *) calloc (1, sizeof (*ts));
32   if (!ts) return 0;
33   trackball (ts->q, 0, 0, 0, 0);
34   return ts;
35 }
36
37 /* Begin tracking the mouse: Call this when the mouse button goes down.
38    x and y are the mouse position relative to the window.
39    w and h are the size of the window.
40  */
41 void
42 gltrackball_start (trackball_state *ts, int x, int y, int w, int h)
43 {
44   ts->x = x;
45   ts->y = y;
46 }
47
48 /* Track the mouse: Call this each time the mouse moves with the button down.
49    x and y are the new mouse position relative to the window.
50    w and h are the size of the window.
51  */
52 void
53 gltrackball_track (trackball_state *ts, int x, int y, int w, int h)
54 {
55   float q2[4];
56   trackball (q2,
57              (2.0 * ts->x - w) / w,
58              (h - 2.0 * ts->y) / h,
59              (2.0 * x - w) / w,
60              (h - 2.0 * y) / h);
61   ts->x = x;
62   ts->y = y;
63   add_quats (q2, ts->q, ts->q);
64 }
65
66 /* Execute the rotations current encapsulated in the trackball_state:
67    this does something analagous to glRotatef().
68  */
69 void
70 gltrackball_rotate (trackball_state *ts)
71 {
72   GLfloat m[4][4];
73   build_rotmatrix (m, ts->q);
74   glMultMatrixf (&m[0][0]);
75 }
76
77
78 # define Button4 4  /* X11/Xlib.h */
79 # define Button5 5
80
81 /* Call this when a mouse-wheel click is detected.
82    Clicks act like horizontal or vertical drags.
83    Percent is the length of the drag as a percentage of the screen size.
84    Button is 'Button4' or 'Button5'.
85  */
86 void
87 gltrackball_mousewheel (trackball_state *ts,
88                         int button, int percent, int horizontal_p)
89 {
90   int up_p;
91   double move;
92   switch (button) {
93     case Button4: up_p = 1; break;
94     case Button5: up_p = 0; break;
95   default: abort(); break;
96   }
97
98   if (horizontal_p) up_p = !up_p;
99
100   move = (up_p
101           ? 1.0 - (percent / 100.0)
102           : 1.0 + (percent / 100.0));
103
104   gltrackball_start (ts, 50, 50, 100, 100);
105   if (horizontal_p)
106     gltrackball_track (ts, 50*move, 50, 100, 100);
107   else
108     gltrackball_track (ts, 50, 50*move, 100, 100);
109 }