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