1 /* -*- Mode: C; tab-width: 4 -*- */
\r
2 /* Klein --- Klein Bottle, Moebius and other parametric surfaces
\r
7 * 2000: written by Andrey Mirtchovski <mirtchov@cpsc.ucalgary.ca
\r
9 * 01-Mar-2003 mirtchov modified as a xscreensaver hack
\r
14 * due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
\r
15 * otherwise caddr_t is not defined correctly
\r
18 #include <X11/Intrinsic.h>
\r
21 # define PROGCLASS "Klein"
\r
22 # define HACK_INIT init_klein
\r
23 # define HACK_DRAW draw_klein
\r
24 # define HACK_RESHAPE reshape_klein
\r
25 # define HACK_HANDLE_EVENT klein_handle_event
\r
26 # define EVENT_MASK PointerMotionMask
\r
27 # define klein_opts xlockmore_opts
\r
30 #define DEF_SPIN "True"
\r
31 #define DEF_WANDER "False"
\r
32 #define DEF_RANDOM "False"
\r
33 #define DEF_SPEED "150"
\r
35 # define DEFAULTS "*delay: 20000 \n" \
\r
36 "*showFPS: False \n" \
\r
37 "*wireframe: False \n" \
\r
38 "*random: " DEF_RANDOM "\n" \
\r
39 "*speed: " DEF_SPEED "\n" \
\r
40 "*spin: " DEF_SPIN "\n" \
\r
41 "*wander: " DEF_WANDER "\n" \
\r
43 # include "xlockmore.h" /* from the xscreensaver distribution */
\r
44 #else /* !STANDALONE */
\r
45 # include "xlock.h" /* from the xlockmore distribution */
\r
46 #endif /* !STANDALONE */
\r
51 #include "rotator.h"
\r
52 #include "gltrackball.h"
\r
55 #define countof(x) (sizeof((x))/sizeof((*x)))
\r
57 /* surfaces being drawn */
\r
70 /* primitives to draw with
\r
71 * note that we skip the polygons and
\r
72 * triangle fans -- too slow
\r
74 * also removed triangle_strip and quads --
\r
75 * just doesn't look good enough
\r
88 static Bool do_spin;
\r
89 static Bool do_wander;
\r
91 static XrmOptionDescRec opts[] = {
\r
92 {"-speed", ".speed", XrmoptionSepArg, (caddr_t) 0 },
\r
93 { "-spin", ".spin", XrmoptionNoArg, "True" },
\r
94 { "+spin", ".spin", XrmoptionNoArg, "False" },
\r
95 { "-wander", ".wander", XrmoptionNoArg, "True" },
\r
96 { "+wander", ".wander", XrmoptionNoArg, "False" },
\r
97 { "-random", ".rand", XrmoptionNoArg, "True" },
\r
98 { "+random", ".rand", XrmoptionNoArg, "False" },
\r
101 static argtype vars[] = {
\r
102 {(caddr_t *) &rand, "rand", "Random", DEF_RANDOM, t_Bool},
\r
103 {(caddr_t *) &do_spin, "spin", "Spin", DEF_SPIN, t_Bool},
\r
104 {(caddr_t *) &do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
\r
105 {(caddr_t *) &speed, "speed", "Speed", DEF_SPEED, t_Int},
\r
109 ModeSpecOpt klein_opts = {countof(opts), opts, countof(vars), vars, NULL};
\r
120 GLXContext *glx_context;
\r
123 trackball_state *trackball;
\r
124 Bool button_down_p;
\r
134 static kleinstruct *klein = NULL;
\r
140 kleinstruct *kp = &klein[MI_SCREEN(mi)];
\r
141 static float step = 0.0;
\r
145 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
\r
147 glEnable(GL_DEPTH_TEST);
\r
148 glEnable(GL_NORMALIZE);
\r
149 glEnable(GL_CULL_FACE);
\r
155 get_position (kp->rot, &x, &y, &z, !kp->button_down_p);
\r
156 glTranslatef((x - 0.5) * 10,
\r
160 gltrackball_rotate (kp->trackball);
\r
162 get_rotation (kp->rot, &x, &y, &z, !kp->button_down_p);
\r
163 glRotatef (x * 360, 1.0, 0.0, 0.0);
\r
164 glRotatef (y * 360, 0.0, 1.0, 0.0);
\r
165 glRotatef (z * 360, 0.0, 0.0, 1.0);
\r
168 glScalef( 4.0, 4.0, 4.0 );
\r
170 glBegin(kp->render);
\r
171 switch(kp->surface) {
\r
173 for(u = -M_PI; u < M_PI; u+=kp->du){
\r
174 for(v = -M_PI; v < M_PI; v+=kp->dv){
\r
175 coord[0] = cos(u)*(kp->a + sin(v)*cos(u/2) -
\r
176 sin(2*v)*sin(u/2)/2);
\r
177 coord[1] = sin(u)*(kp->a + sin(v)*cos(u/2) -
\r
178 sin(2*v)*sin(u/2)/2);
\r
179 coord[2] = sin(u/2)*sin(v) + cos(u/2)*sin(2*v)/2;
\r
180 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
\r
181 glVertex3fv(coord);
\r
186 for(u = -M_PI; u < M_PI; u+=kp->du){
\r
187 for(v = -M_PI; v < M_PI; v+=kp->dv){
\r
188 coord[0] = kp->a*cos(u)*sin(v);
\r
189 coord[1] = kp->a*sin(u)*sin(v);
\r
190 coord[2] = kp->a*(cos(v) + sin(tan((v/2))))+0.2*u;
\r
191 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
\r
192 glVertex3fv(coord);
\r
197 for(u = -M_PI; u < M_PI; u+=kp->du){
\r
198 for(v = -M_PI; v < M_PI; v+=kp->dv){
\r
199 coord[0] = kp->a*(u-(u*u*u/3)+u*v*v);
\r
200 coord[1] = kp->b*(v-(v*v*v/3)+u*u*v);
\r
201 coord[2] = u*u-v*v;
\r
202 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
\r
203 glVertex3fv(coord);
\r
208 for(u = -M_PI; u < M_PI; u+=kp->du){
\r
209 for(v = -M_PI; v < M_PI; v+=kp->dv){
\r
210 coord[0] = 2*(cos(u)+u*sin(u))*sin(v)/(1+u*u*sin(v)*sin(v));
\r
211 coord[1] = 2*(sin(u)-u*cos(u))*sin(v)/(1+u*u*sin(v)*sin(v));
\r
212 coord[2] = sin(tan(v/2))+2*cos(v)/(1+u*u*sin(v)*sin(v));
\r
214 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
\r
215 glVertex3fv(coord);
\r
220 for(u = -M_PI; u < M_PI; u+=kp->du){
\r
221 for(v = -M_PI; v < M_PI; v+=kp->dv){
\r
222 coord[0] = cos(u)+v*cos(u/2)*cos(u);
\r
223 coord[1] = sin(u)+v*cos(u/2)*sin(u);
\r
224 coord[2] = v*sin(u/2);
\r
225 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
\r
226 glVertex3fv(coord);
\r
231 for(u = 0; u < 2*M_PI; u+=kp->du){
\r
232 for(v = 0; v < 2*M_PI; v+=kp->dv){
\r
233 coord[0] = kp->a*(1-v/(2*M_PI))*cos(2*v)*(1+cos(u))+sin(kp->c+=0.00001)*cos(2*v);
\r
234 coord[1] = kp->a*(1-v/(2*M_PI))*sin(2*v)*(1+cos(u))+cos(kp->c+=0.00001)*sin(2*v);
\r
235 coord[2] = sin(kp->b+=0.00001)*v/(2*M_PI)+kp->a*(1-v/(2*M_PI))*sin(u);
\r
236 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
\r
237 glVertex3fv(coord);
\r
242 for(u = -M_PI; u < M_PI; u+=kp->du){
\r
243 for(v = -M_PI; v < M_PI; v+=kp->dv){
\r
244 coord[0] = u*pow(v,2) + 3*pow(v,4);
\r
245 coord[1] = -2*u*v - 4*pow(v,3);
\r
247 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
\r
248 glVertex3fv(coord);
\r
253 for(u = -M_PI; u < M_PI; u+=kp->du){
\r
254 for(v = -M_PI; v < M_PI; v+=kp->dv){
\r
255 coord[0] = kp->a*cos(u);
\r
256 coord[1] = 1.5*cos(v) + kp->a*sin(u);
\r
258 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
\r
259 glVertex3fv(coord);
\r
264 for(u = -M_PI; u < M_PI; u+=kp->du){
\r
265 for(v = -M_PI; v < M_PI; v+=kp->dv){
\r
266 coord[0] = sin(u)*kp->a;
\r
267 coord[1] = cos(u)*kp->a;
\r
268 coord[2] = sin(u/2)*cos(v) + cos(u/2)*sin(v);
\r
269 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
\r
270 glVertex3fv(coord);
\r
279 kp->a = sin(step+=0.01);
\r
280 kp->b = cos(step+=0.01);
\r
284 /* new window size or exposure */
\r
286 reshape_klein(ModeInfo *mi, int width, int height)
\r
288 GLfloat h = (GLfloat) height / (GLfloat) width;
\r
290 glViewport(0, 0, (GLint) width, (GLint) height);
\r
291 glMatrixMode(GL_PROJECTION);
\r
293 gluPerspective (30.0, 1/h, 1.0, 100.0);
\r
295 glMatrixMode(GL_MODELVIEW);
\r
297 gluLookAt( 0.0, 0.0, 30.0,
\r
301 glClear(GL_COLOR_BUFFER_BIT);
\r
306 klein_handle_event (ModeInfo *mi, XEvent *event)
\r
308 kleinstruct *kp = &klein[MI_SCREEN(mi)];
\r
310 if (event->xany.type == ButtonPress && event->xbutton.button & Button1) {
\r
311 kp->button_down_p = True;
\r
312 gltrackball_start (kp->trackball, event->xbutton.x, event->xbutton.y, MI_WIDTH (mi), MI_HEIGHT (mi));
\r
314 } else if (event->xany.type == ButtonRelease && event->xbutton.button & Button1) {
\r
315 kp->button_down_p = False;
\r
317 } else if (event->xany.type == MotionNotify && kp->button_down_p) {
\r
318 gltrackball_track (kp->trackball, event->xmotion.x, event->xmotion.y, MI_WIDTH (mi), MI_HEIGHT (mi));
\r
327 init_klein(ModeInfo *mi)
\r
329 int screen = MI_SCREEN(mi);
\r
332 if (klein == NULL) {
\r
333 if ((klein = (kleinstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (kleinstruct))) == NULL)
\r
336 kp = &klein[screen];
\r
338 kp->window = MI_WINDOW(mi);
\r
341 double spin_speed = 1.0;
\r
342 double wander_speed = 0.03;
\r
343 kp->rot = make_rotator (do_spin ? spin_speed : 0,
\r
344 do_spin ? spin_speed : 0,
\r
345 do_spin ? spin_speed : 0,
\r
347 do_wander ? wander_speed : 0,
\r
349 kp->trackball = gltrackball_init ();
\r
353 render = random() % MY_PRIM_LAST;
\r
354 kp->surface = random() % SURFACE_LAST;
\r
356 render = MY_LINE_LOOP;
\r
357 kp->surface = KLEIN;
\r
361 case MY_POINTS: kp->render = GL_POINTS; break;
\r
362 case MY_LINES: kp->render = GL_LINES; break;
\r
363 case MY_LINE_LOOP: kp->render = GL_LINE_LOOP; break;
\r
365 kp->render = GL_LINE_LOOP;
\r
367 /*kp->render=GL_TRIANGLE_FAN;*/
\r
368 /*kp->render=GL_POLYGON;*/
\r
376 if ((kp->glx_context = init_GL(mi)) != NULL) {
\r
377 reshape_klein(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
\r
379 MI_CLEARWINDOW(mi);
\r
384 draw_klein(ModeInfo * mi)
\r
386 kleinstruct *kp = &klein[MI_SCREEN(mi)];
\r
387 Display *display = MI_DISPLAY(mi);
\r
388 Window window = MI_WINDOW(mi);
\r
390 if (!kp->glx_context) return;
\r
392 glDrawBuffer(GL_BACK);
\r
394 glXMakeCurrent(display, window, *(kp->glx_context));
\r
396 if (mi->fps_p) do_fps (mi);
\r
398 glXSwapBuffers(display, window);
\r
402 release_klein(ModeInfo * mi)
\r
404 if (klein != NULL) {
\r
407 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
\r
408 kleinstruct *kp = &klein[screen];
\r
410 if (kp->glx_context) {
\r
411 /* Display lists MUST be freed while their glXContext is current. */
\r
412 glXMakeCurrent(MI_DISPLAY(mi), kp->window, *(kp->glx_context));
\r
415 (void) free((void *) klein);
\r
422 /*********************************************************/
\r