1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* Klein --- Klein Bottle, Moebius and other parametric surfaces
7 * 2000: written by Andrey Mirtchovski <mirtchov@cpsc.ucalgary.ca
9 * 01-Mar-2003 mirtchov modified as a xscreensaver hack
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
23 #define DEF_SPIN "True"
24 #define DEF_WANDER "False"
25 #define DEF_RANDOM "False"
26 #define DEF_SPEED "150"
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" \
36 # include "xlockmore.h" /* from the xscreensaver distribution */
37 #else /* !STANDALONE */
38 # include "xlock.h" /* from the xlockmore distribution */
39 #endif /* !STANDALONE */
45 #include "gltrackball.h"
48 #define countof(x) (sizeof((x))/sizeof((*x)))
50 /* surfaces being drawn */
63 /* primitives to draw with
64 * note that we skip the polygons and
65 * triangle fans -- too slow
67 * also removed triangle_strip and quads --
68 * just doesn't look good enough
82 static Bool do_wander;
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" },
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},
102 ModeSpecOpt klein_opts = {countof(opts), opts, countof(vars), vars, NULL};
113 GLXContext *glx_context;
116 trackball_state *trackball;
127 static kleinstruct *klein = NULL;
133 kleinstruct *kp = &klein[MI_SCREEN(mi)];
134 static float step = 0.0;
138 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
140 glEnable(GL_DEPTH_TEST);
141 glEnable(GL_NORMALIZE);
142 glEnable(GL_CULL_FACE);
148 get_position (kp->rot, &x, &y, &z, !kp->button_down_p);
149 glTranslatef((x - 0.5) * 10,
153 gltrackball_rotate (kp->trackball);
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);
161 glScalef( 4.0, 4.0, 4.0 );
164 switch(kp->surface) {
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);
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);
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);
195 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
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));
207 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
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);
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);
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);
240 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
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);
251 glColor3f(coord[0]+0.7, coord[1]+0.7, coord[2]+0.7);
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);
272 kp->a = sin(step+=0.01);
273 kp->b = cos(step+=0.01);
277 /* new window size or exposure */
279 reshape_klein(ModeInfo *mi, int width, int height)
281 GLfloat h = (GLfloat) height / (GLfloat) width;
283 glViewport(0, 0, (GLint) width, (GLint) height);
284 glMatrixMode(GL_PROJECTION);
286 gluPerspective (30.0, 1/h, 1.0, 100.0);
288 glMatrixMode(GL_MODELVIEW);
290 gluLookAt( 0.0, 0.0, 30.0,
294 glClear(GL_COLOR_BUFFER_BIT);
299 klein_handle_event (ModeInfo *mi, XEvent *event)
301 kleinstruct *kp = &klein[MI_SCREEN(mi)];
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));
307 } else if (event->xany.type == ButtonRelease && event->xbutton.button == Button1) {
308 kp->button_down_p = False;
310 } else if (event->xany.type == ButtonPress &&
311 (event->xbutton.button == Button4 ||
312 event->xbutton.button == Button5)) {
313 gltrackball_mousewheel (kp->trackball, event->xbutton.button, 10,
314 !!event->xbutton.state);
316 } else if (event->xany.type == MotionNotify && kp->button_down_p) {
317 gltrackball_track (kp->trackball, event->xmotion.x, event->xmotion.y, MI_WIDTH (mi), MI_HEIGHT (mi));
326 init_klein(ModeInfo *mi)
328 int screen = MI_SCREEN(mi);
332 if ((klein = (kleinstruct *) calloc(MI_NUM_SCREENS(mi), sizeof (kleinstruct))) == NULL)
337 kp->window = MI_WINDOW(mi);
340 double spin_speed = 1.0;
341 double wander_speed = 0.03;
342 kp->rot = make_rotator (do_spin ? spin_speed : 0,
343 do_spin ? spin_speed : 0,
344 do_spin ? spin_speed : 0,
346 do_wander ? wander_speed : 0,
348 kp->trackball = gltrackball_init ();
352 render = random() % MY_PRIM_LAST;
353 kp->surface = random() % SURFACE_LAST;
355 render = MY_LINE_LOOP;
360 case MY_POINTS: kp->render = GL_POINTS; break;
361 case MY_LINES: kp->render = GL_LINES; break;
362 case MY_LINE_LOOP: kp->render = GL_LINE_LOOP; break;
364 kp->render = GL_LINE_LOOP;
366 /*kp->render=GL_TRIANGLE_FAN;*/
367 /*kp->render=GL_POLYGON;*/
375 if ((kp->glx_context = init_GL(mi)) != NULL) {
376 reshape_klein(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
383 draw_klein(ModeInfo * mi)
385 kleinstruct *kp = &klein[MI_SCREEN(mi)];
386 Display *display = MI_DISPLAY(mi);
387 Window window = MI_WINDOW(mi);
389 if (!kp->glx_context) return;
391 glDrawBuffer(GL_BACK);
393 glXMakeCurrent(display, window, *(kp->glx_context));
395 if (mi->fps_p) do_fps (mi);
397 glXSwapBuffers(display, window);
401 release_klein(ModeInfo * mi)
406 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
407 kleinstruct *kp = &klein[screen];
409 if (kp->glx_context) {
410 /* Display lists MUST be freed while their glXContext is current. */
411 glXMakeCurrent(MI_DISPLAY(mi), kp->window, *(kp->glx_context));
414 (void) free((void *) klein);
421 /*********************************************************/