ftp://ftp.linux.ncsu.edu/mirror/ftp.redhat.com/pub/redhat/linux/enterprise/4/en/os...
[xscreensaver] / hacks / glx / klein.c
1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* Klein --- Klein Bottle, Moebius and other parametric surfaces
3  * visualization */
4
5 /*
6  * Revision History:
7  * 2000: written by Andrey Mirtchovski <mirtchov@cpsc.ucalgary.ca
8  *       
9  * 01-Mar-2003  mirtchov    modified as a xscreensaver hack
10  *
11  */
12
13 #ifdef STANDALONE
14 # define PROGCLASS                                      "Klein"
15 # define HACK_INIT                                      init_klein
16 # define HACK_DRAW                                      draw_klein
17 # define HACK_RESHAPE                           reshape_klein
18 # define HACK_HANDLE_EVENT                      klein_handle_event
19 # define EVENT_MASK                                     PointerMotionMask
20 # define klein_opts                                     xlockmore_opts
21
22
23 #define DEF_SPIN                                "True"
24 #define DEF_WANDER                              "False"
25 #define DEF_RANDOM                              "False"
26 #define DEF_SPEED                               "150"
27
28 # define DEFAULTS                                       "*delay:                20000   \n"                     \
29                                                                         "*showFPS:      False   \n"                     \
30                                                                         "*wireframe:    False   \n"                     \
31                                                                         "*random:          " DEF_RANDOM     "\n"        \
32                                                                         "*speed:           " DEF_SPEED     "\n" \
33                                                                         "*spin:        " DEF_SPIN      "\n" \
34                                                                         "*wander:      " DEF_WANDER    "\n" \
35
36 # include "xlockmore.h"         /* from the xscreensaver distribution */
37 #else  /* !STANDALONE */
38 # include "xlock.h"                     /* from the xlockmore distribution */
39 #endif /* !STANDALONE */
40
41 #ifdef USE_GL
42
43 #include <GL/glu.h>
44 #include "rotator.h"
45 #include "gltrackball.h"
46
47 #undef countof
48 #define countof(x) (sizeof((x))/sizeof((*x)))
49
50 /* surfaces being drawn */
51 enum { 
52         KLEIN = 0,
53         DINI,
54         ENNEPER,
55         KUEN,
56         MOEBIUS,
57         SEASHELL,
58         SWALLOWTAIL,
59         BOHEM,
60     SURFACE_LAST
61 };
62
63 /* primitives to draw with 
64  * note that we skip the polygons and
65  * triangle fans -- too slow
66  *
67  * also removed triangle_strip and quads -- 
68  * just doesn't look good enough
69  */
70 enum {
71         MY_POINTS = 0,
72         MY_LINES,
73         MY_LINE_LOOP,
74         MY_PRIM_LAST
75 };
76
77
78 static Bool rand;
79 static int render;
80 static int speed;
81 static Bool do_spin;
82 static Bool do_wander;
83
84 static XrmOptionDescRec opts[] = {
85   {"-speed",   ".speed",    XrmoptionSepArg, 0 },
86   { "-spin",   ".spin",   XrmoptionNoArg, "True" },
87   { "+spin",   ".spin",   XrmoptionNoArg, "False" },
88   { "-wander", ".wander", XrmoptionNoArg, "True" },
89   { "+wander", ".wander", XrmoptionNoArg, "False" },
90   { "-random", ".rand", XrmoptionNoArg, "True" },
91   { "+random", ".rand", XrmoptionNoArg, "False" },
92 };
93
94 static argtype vars[] = {
95   {&rand,      "rand",   "Random", DEF_RANDOM, t_Bool},
96   {&do_spin,   "spin",   "Spin",   DEF_SPIN,   t_Bool},
97   {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
98   {&speed,     "speed",  "Speed",  DEF_SPEED,  t_Int},
99 };
100
101
102 ModeSpecOpt klein_opts = {countof(opts), opts, countof(vars), vars, NULL};
103
104
105
106 typedef struct{
107   GLfloat x;
108   GLfloat y;
109   GLfloat z;
110 } GL_VECTOR;
111
112 typedef struct {
113         GLXContext *glx_context;
114         Window      window;
115         rotator    *rot;
116         trackball_state *trackball;
117         Bool              button_down_p;
118
119         int render;
120         int surface;
121
122         float du, dv;
123         float a, b, c;
124
125 } kleinstruct;
126
127 static kleinstruct *klein = NULL;
128
129
130 static void
131 draw(ModeInfo *mi)
132 {
133         kleinstruct *kp = &klein[MI_SCREEN(mi)];
134         static float step = 0.0;
135         double u, v;
136         float coord[3];
137         
138         glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
139
140         glEnable(GL_DEPTH_TEST);
141         glEnable(GL_NORMALIZE);
142         glEnable(GL_CULL_FACE);
143
144         glPushMatrix();
145
146         {
147                 double x, y, z;
148                 get_position (kp->rot, &x, &y, &z, !kp->button_down_p);
149                 glTranslatef((x - 0.5) * 10,
150                                                                  (y - 0.5) * 10,
151                                                                  (z - 0.5) * 20);
152
153                 gltrackball_rotate (kp->trackball);
154
155                 get_rotation (kp->rot, &x, &y, &z, !kp->button_down_p);
156                 glRotatef (x * 360, 1.0, 0.0, 0.0);
157                 glRotatef (y * 360, 0.0, 1.0, 0.0);
158                 glRotatef (z * 360, 0.0, 0.0, 1.0);
159         }
160
161         glScalef( 4.0, 4.0, 4.0 );
162
163         glBegin(kp->render);
164         switch(kp->surface) {
165         case KLEIN:
166                 for(u = -M_PI; u < M_PI; u+=kp->du){
167                         for(v = -M_PI; v < M_PI; v+=kp->dv){
168                                 coord[0] = cos(u)*(kp->a + sin(v)*cos(u/2) -
169                                                         sin(2*v)*sin(u/2)/2);
170                                 coord[1] = sin(u)*(kp->a + sin(v)*cos(u/2) -
171                                                         sin(2*v)*sin(u/2)/2);
172                                 coord[2] = sin(u/2)*sin(v) + cos(u/2)*sin(2*v)/2;
173                                 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
174                                 glVertex3fv(coord);
175                         }
176                 }
177                 break;
178                 case DINI:
179                         for(u = -M_PI; u < M_PI; u+=kp->du){
180                                 for(v = -M_PI; v < M_PI; v+=kp->dv){
181                                         coord[0] = kp->a*cos(u)*sin(v);
182                                         coord[1] = kp->a*sin(u)*sin(v);
183                                         coord[2] = kp->a*(cos(v) + sin(tan((v/2))))+0.2*u;
184                                         glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
185                                         glVertex3fv(coord);
186                                 }
187                         }
188                         break;
189                 case ENNEPER:
190                         for(u = -M_PI; u < M_PI; u+=kp->du){
191                                 for(v = -M_PI; v < M_PI; v+=kp->dv){
192                                         coord[0] = kp->a*(u-(u*u*u/3)+u*v*v);
193                                         coord[1] = kp->b*(v-(v*v*v/3)+u*u*v);
194                                         coord[2] = u*u-v*v;
195                                         glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
196                                         glVertex3fv(coord);
197                                 }
198                         }
199                         break;
200                 case KUEN:
201                         for(u = -M_PI; u < M_PI; u+=kp->du){
202                                 for(v = -M_PI; v < M_PI; v+=kp->dv){
203                                         coord[0] = 2*(cos(u)+u*sin(u))*sin(v)/(1+u*u*sin(v)*sin(v));
204                                         coord[1] = 2*(sin(u)-u*cos(u))*sin(v)/(1+u*u*sin(v)*sin(v));
205                                         coord[2] = sin(tan(v/2))+2*cos(v)/(1+u*u*sin(v)*sin(v));
206
207                                         glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
208                                         glVertex3fv(coord);
209                                 }
210                         }
211                         break;
212                 case MOEBIUS:
213                         for(u = -M_PI; u < M_PI; u+=kp->du){
214                                 for(v = -M_PI; v < M_PI; v+=kp->dv){
215                                         coord[0] = cos(u)+v*cos(u/2)*cos(u);
216                                         coord[1] = sin(u)+v*cos(u/2)*sin(u);
217                                         coord[2] = v*sin(u/2);
218                                         glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
219                                         glVertex3fv(coord);
220                                 }
221                         }
222                         break;
223                 case SEASHELL:
224                         for(u = 0; u < 2*M_PI; u+=kp->du){
225                                 for(v = 0; v < 2*M_PI; v+=kp->dv){
226                                         coord[0] = kp->a*(1-v/(2*M_PI))*cos(2*v)*(1+cos(u))+sin(kp->c+=0.00001)*cos(2*v);
227                                         coord[1] = kp->a*(1-v/(2*M_PI))*sin(2*v)*(1+cos(u))+cos(kp->c+=0.00001)*sin(2*v);
228                                         coord[2] = sin(kp->b+=0.00001)*v/(2*M_PI)+kp->a*(1-v/(2*M_PI))*sin(u);
229                                         glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
230                                         glVertex3fv(coord);
231                                 }
232                         }
233                         break;
234                 case SWALLOWTAIL:
235                         for(u = -M_PI; u < M_PI; u+=kp->du){
236                                 for(v = -M_PI; v < M_PI; v+=kp->dv){
237                                         coord[0] = u*pow(v,2) + 3*pow(v,4);
238                                         coord[1] = -2*u*v - 4*pow(v,3);
239                                         coord[2] = u;
240                                         glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
241                                         glVertex3fv(coord);
242                                 }
243                         }
244                         break;
245                 case BOHEM:
246                         for(u = -M_PI; u < M_PI; u+=kp->du){
247                                 for(v = -M_PI; v < M_PI; v+=kp->dv){
248                                         coord[0] = kp->a*cos(u);
249                                         coord[1] = 1.5*cos(v) + kp->a*sin(u);
250                                         coord[2] = sin(v);
251                                         glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
252                                         glVertex3fv(coord);
253                                 }
254                         }
255                         break;
256                 default:
257                         for(u = -M_PI; u < M_PI; u+=kp->du){
258                                 for(v = -M_PI; v < M_PI; v+=kp->dv){
259                                         coord[0] = sin(u)*kp->a;        
260                                         coord[1] = cos(u)*kp->a;
261                                         coord[2] = sin(u/2)*cos(v) + cos(u/2)*sin(v);
262                                         glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
263                                         glVertex3fv(coord);
264                                 }
265                         }
266                         break;
267         }
268         glEnd();
269         glPopMatrix();
270
271
272         kp->a = sin(step+=0.01);
273         kp->b = cos(step+=0.01);
274 }
275
276
277 /* new window size or exposure */
278 void
279 reshape_klein(ModeInfo *mi, int width, int height)
280 {
281         GLfloat h = (GLfloat) height / (GLfloat) width;
282
283         glViewport(0, 0, (GLint) width, (GLint) height);
284         glMatrixMode(GL_PROJECTION);
285         glLoadIdentity();
286         gluPerspective (30.0, 1/h, 1.0, 100.0);
287
288         glMatrixMode(GL_MODELVIEW);
289         glLoadIdentity();
290         gluLookAt( 0.0, 0.0, 30.0,
291                          0.0, 0.0, 0.0,
292                          0.0, 1.0, 0.0);
293         
294         glClear(GL_COLOR_BUFFER_BIT);
295 }
296
297
298 Bool
299 klein_handle_event (ModeInfo *mi, XEvent *event)
300 {
301         kleinstruct *kp = &klein[MI_SCREEN(mi)];
302
303         if (event->xany.type == ButtonPress && event->xbutton.button & Button1) {
304                         kp->button_down_p = True;
305                         gltrackball_start (kp->trackball, event->xbutton.x, event->xbutton.y, MI_WIDTH (mi), MI_HEIGHT (mi));
306                         return True;
307         } else if (event->xany.type == ButtonRelease && event->xbutton.button & Button1) {
308                         kp->button_down_p = False;
309                         return True;
310         } else if (event->xany.type == MotionNotify && kp->button_down_p) {
311                         gltrackball_track (kp->trackball, event->xmotion.x, event->xmotion.y, MI_WIDTH (mi), MI_HEIGHT (mi));
312                         return True;
313         }
314
315         return False;
316 }
317
318
319 void
320 init_klein(ModeInfo *mi)
321 {
322         int      screen = MI_SCREEN(mi);
323         kleinstruct *kp;
324
325         if (klein == NULL) {
326                 if ((klein = (kleinstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (kleinstruct))) == NULL)
327                         return;
328         }
329         kp = &klein[screen];
330
331         kp->window = MI_WINDOW(mi);
332
333         {
334                 double spin_speed        = 1.0;
335                 double wander_speed = 0.03;
336                 kp->rot = make_rotator (do_spin ? spin_speed : 0,
337                                                 do_spin ? spin_speed : 0,
338                                                 do_spin ? spin_speed : 0,
339                                                 1.0,
340                                                 do_wander ? wander_speed : 0,
341                                                 True);
342                 kp->trackball = gltrackball_init ();
343         }
344
345         if(rand) {
346                 render = random() % MY_PRIM_LAST;
347                 kp->surface = random() % SURFACE_LAST;
348         } else {
349                 render = MY_LINE_LOOP;
350                 kp->surface = KLEIN;
351         }
352
353         switch (render) {
354         case MY_POINTS: kp->render = GL_POINTS; break;
355         case MY_LINES: kp->render = GL_LINES; break;
356         case MY_LINE_LOOP: kp->render = GL_LINE_LOOP; break;
357         default:
358                         kp->render = GL_LINE_LOOP;
359         }
360 /*kp->render=GL_TRIANGLE_FAN;*/
361 /*kp->render=GL_POLYGON;*/
362
363         kp->du = 0.07;
364         kp->dv = 0.07;
365         kp->a = kp->b = 1;
366         kp->c = 0.1;
367
368
369         if ((kp->glx_context = init_GL(mi)) != NULL) {
370                 reshape_klein(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
371         } else {
372                 MI_CLEARWINDOW(mi);
373         }
374 }
375
376 void
377 draw_klein(ModeInfo * mi)
378 {
379         kleinstruct *kp = &klein[MI_SCREEN(mi)];
380         Display *display = MI_DISPLAY(mi);
381         Window  window = MI_WINDOW(mi);
382
383         if (!kp->glx_context) return;
384
385         glDrawBuffer(GL_BACK);
386
387         glXMakeCurrent(display, window, *(kp->glx_context));
388         draw(mi);
389         if (mi->fps_p) do_fps (mi);
390         glFinish();
391         glXSwapBuffers(display, window);
392 }
393
394 void
395 release_klein(ModeInfo * mi)
396 {
397         if (klein != NULL) {
398                 int      screen;
399
400                 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
401                         kleinstruct *kp = &klein[screen];
402
403                         if (kp->glx_context) {
404                                 /* Display lists MUST be freed while their glXContext is current. */
405                                 glXMakeCurrent(MI_DISPLAY(mi), kp->window, *(kp->glx_context));
406                         }
407                 }
408                 (void) free((void *) klein);
409                 klein = NULL;
410         }
411         FreeAllGL(mi);
412 }
413
414
415 /*********************************************************/
416
417 #endif