1 /* cubestack, Copyright (c) 2016 Jamie Zawinski <jwz@jwz.org>
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation. No representations are made about the suitability of this
8 * software for any purpose. It is provided "as is" without express or
12 #define DEFAULTS "*delay: 30000 \n" \
13 "*showFPS: False \n" \
14 "*wireframe: False \n" \
15 "*suppressRotationAnimation: True\n" \
17 # define refresh_cube 0
18 # define release_cube 0
20 #define countof(x) (sizeof((x))/sizeof((*x)))
22 #include "xlockmore.h"
25 #include "gltrackball.h"
28 #ifdef USE_GL /* whole file */
31 #define DEF_WANDER "True"
32 #define DEF_SPEED "1.0"
33 #define DEF_THICKNESS "0.13"
34 #define DEF_OPACITY "0.7"
37 GLXContext *glx_context;
39 trackball_state *trackball;
49 static cube_configuration *bps = NULL;
52 static GLfloat thickness;
53 static GLfloat opacity;
54 static Bool do_wander;
56 static XrmOptionDescRec opts[] = {
57 { "-wander", ".wander", XrmoptionNoArg, "True" },
58 { "+wander", ".wander", XrmoptionNoArg, "False" },
59 { "-speed", ".speed", XrmoptionSepArg, 0 },
60 { "-thickness", ".thickness", XrmoptionSepArg, 0 },
61 { "-opacity", ".opacity", XrmoptionSepArg, 0 },
64 static argtype vars[] = {
65 {&do_wander, "wander", "Wander", DEF_WANDER, t_Bool},
66 {&speed, "speed", "Speed", DEF_SPEED, t_Float},
67 {&thickness, "thickness", "Thickness", DEF_THICKNESS, t_Float},
68 {&opacity, "opacity", "Opacity", DEF_OPACITY, t_Float},
71 ENTRYPOINT ModeSpecOpt cube_opts = {countof(opts), opts, countof(vars), vars, NULL};
75 draw_strut (ModeInfo *mi)
77 int wire = MI_IS_WIREFRAME(mi);
83 glNormal3f (0, 0, -1);
84 glTranslatef (-0.5, -0.5, 0);
85 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLE_FAN);
88 glVertex3f (1 - thickness, thickness, 0);
89 glVertex3f (thickness, thickness, 0);
96 glBegin (wire ? GL_LINE_LOOP : GL_TRIANGLE_FAN);
97 glVertex3f (0.5, 0.5, 0);
98 glVertex3f (0.5 - thickness/2, 0.5 - thickness/2, 0);
99 glVertex3f (0.5 - thickness/2, 0.5 - h/2, 0);
100 glVertex3f (0.5 + thickness/2, 0.5 - h/2, 0);
101 glVertex3f (0.5 + thickness/2, 0.5 - thickness/2, 0);
113 draw_face (ModeInfo *mi)
117 for (i = 0; i < 4; i++)
119 polys += draw_strut (mi);
120 glRotatef (90, 0, 0, 1);
129 return cos ((r/2 + 1) * M_PI) + 1; /* Smooth curve up, end at slope 1. */
134 ease_ratio (GLfloat r)
137 if (r <= 0) return 0;
138 else if (r >= 1) return 1;
139 else if (r <= ease) return ease * ease_fn (r / ease);
140 else if (r > 1-ease) return 1 - ease * ease_fn ((1 - r) / ease);
146 draw_cube_1 (ModeInfo *mi, GLfloat state, GLfloat color[4], Bool bottom_p)
150 GLfloat r = state - istate;
151 GLfloat a = color[3];
155 # define COLORIZE(R) \
157 glMaterialfv (GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, color); \
162 GLfloat r2 = (state < 0 ? 1 + state : 1);
164 polys += draw_face (mi); /* Bottom */
167 if (state >= 0) /* Left */
169 GLfloat r2 = (istate == 0 ? r : 1);
172 glTranslatef (-0.5, 0.5, 0);
173 glRotatef (-r2 * 90, 0, 1, 0);
174 glTranslatef (0.5, -0.5, 0);
175 polys += draw_face (mi);
179 if (state >= 1) /* Back */
181 GLfloat r2 = (istate == 1 ? r : 1);
184 glTranslatef (-0.5, 0.5, 0);
185 glRotatef ( 90, 0, 1, 0);
186 glRotatef (-90, 0, 0, 1);
187 glRotatef (-r2 * 90, 0, 1, 0);
188 glTranslatef (0.5, -0.5, 0);
189 polys += draw_face (mi);
193 if (state >= 2) /* Right */
195 GLfloat r2 = (istate == 2 ? r : 1);
198 glTranslatef (0.5, 0.5, 0);
199 glRotatef ( 90, 0, 1, 0);
200 glRotatef (-90, 0, 0, 1);
201 glRotatef (-90, 0, 1, 0);
202 glRotatef (-r2 * 90, 0, 1, 0);
203 glTranslatef (-0.5, -0.5, 0);
204 polys += draw_face (mi);
208 if (state >= 3) /* Front */
210 GLfloat r2 = (istate == 3 ? r : 1);
213 glTranslatef (0.5, 0.5, 0);
214 glRotatef ( 90, 0, 1, 0);
215 glRotatef (-90, 0, 0, 1);
216 glRotatef (-180, 0, 1, 0);
217 glTranslatef (-1, 0, 0);
218 glRotatef (-r2 * 90, 0, 1, 0);
219 glTranslatef (0.5, -0.5, 0);
220 polys += draw_face (mi);
224 if (state >= 4) /* Top */
226 GLfloat r2 = (istate == 4 ? r : 1);
229 glTranslatef (0, 0, 1);
230 glRotatef (-90, 0, 0, 1);
231 glTranslatef (0.5, 0.5, 0);
232 glRotatef (-90, 0, 1, 0);
233 glRotatef (r2 * 90, 0, 1, 0);
234 glTranslatef (-0.5, -0.5, 0);
235 polys += draw_face (mi);
244 draw_cubes (ModeInfo *mi)
246 cube_configuration *bp = &bps[MI_SCREEN(mi)];
248 GLfloat z = bp->state / 6;
252 GLfloat alpha = opacity;
255 glTranslatef (0, 0, -1.5 - z);
257 glTranslatef (0, 0, -bp->length);
258 for (i = bp->length-1; i >= 0; i--)
261 if (c1 < 0) c1 += bp->ncolors;
262 c[0] = bp->colors[c1].red / 65536.0;
263 c[1] = bp->colors[c1].green / 65536.0;
264 c[2] = bp->colors[c1].blue / 65536.0;
267 glTranslatef (0, 0, 1);
268 polys += draw_cube_1 (mi, 5, c, i == bp->length - 1);
271 c[0] = bp->colors[c0].red / 65536.0;
272 c[1] = bp->colors[c0].green / 65536.0;
273 c[2] = bp->colors[c0].blue / 65536.0;
275 glTranslatef (0, 0, 1);
276 polys += draw_cube_1 (mi, bp->state, c, bp->length == 0);
284 /* Window management, etc
287 reshape_cube (ModeInfo *mi, int width, int height)
289 GLfloat h = (GLfloat) height / (GLfloat) width;
291 glViewport (0, 0, (GLint) width, (GLint) height);
293 glMatrixMode(GL_PROJECTION);
295 gluPerspective (30.0, 1/h, 1.0, 100.0);
297 glMatrixMode(GL_MODELVIEW);
299 gluLookAt( 0.0, 0.0, 30.0,
303 # ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
305 int o = (int) current_device_rotation();
306 if (o != 0 && o != 180 && o != -180)
307 glScalef (1/h, 1/h, 1/h);
311 glClear(GL_COLOR_BUFFER_BIT);
316 cube_handle_event (ModeInfo *mi, XEvent *event)
318 cube_configuration *bp = &bps[MI_SCREEN(mi)];
320 if (gltrackball_event_handler (event, bp->trackball,
321 MI_WIDTH (mi), MI_HEIGHT (mi),
324 else if (event->xany.type == KeyPress)
328 XLookupString (&event->xkey, &c, 1, &keysym, 0);
329 if (c == ' ' || c == '\t')
332 make_smooth_colormap (0, 0, 0,
333 bp->colors, &bp->ncolors,
345 init_cube (ModeInfo *mi)
347 cube_configuration *bp;
348 int wire = MI_IS_WIREFRAME(mi);
350 MI_INIT (mi, bps, NULL);
352 bp = &bps[MI_SCREEN(mi)];
354 bp->glx_context = init_GL(mi);
356 reshape_cube (mi, MI_WIDTH(mi), MI_HEIGHT(mi));
360 glDisable (GL_LIGHTING);
361 glEnable(GL_DEPTH_TEST);
362 glShadeModel (GL_SMOOTH);
363 glEnable (GL_NORMALIZE);
364 glDisable (GL_CULL_FACE);
366 glDisable (GL_DEPTH_TEST);
367 glBlendFunc (GL_SRC_ALPHA, GL_ONE);
371 double wander_speed = 0.005;
372 bp->rot = make_rotator (0, 0, 0, 0,
373 do_wander ? wander_speed : 0,
375 bp->trackball = gltrackball_init (True);
380 if (thickness < 0.001)
384 bp->colors = (XColor *) calloc(bp->ncolors, sizeof(XColor));
385 make_smooth_colormap (0, 0, 0,
386 bp->colors, &bp->ncolors,
393 draw_cube (ModeInfo *mi)
395 cube_configuration *bp = &bps[MI_SCREEN(mi)];
396 Display *dpy = MI_DISPLAY(mi);
397 Window window = MI_WINDOW(mi);
399 if (!bp->glx_context)
402 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(bp->glx_context));
403 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
409 get_position (bp->rot, &x, &y, &z, !bp->button_down_p);
410 glTranslatef((x - 0.5) * 4,
414 gltrackball_rotate (bp->trackball);
417 mi->polygon_count = 0;
420 glRotatef (-45, 1, 0, 0);
421 glRotatef (20, 0, 0, 1);
422 glRotatef (bp->r, 0, 0, 1);
424 mi->polygon_count = draw_cubes (mi);
427 if (!bp->button_down_p)
430 bp->state += speed * 0.015;
431 bp->r += speed * 0.05;
434 while (bp->state > max)
439 if (bp->ccolor > bp->ncolors)
447 if (mi->fps_p) do_fps (mi);
450 glXSwapBuffers(dpy, window);
453 XSCREENSAVER_MODULE_2 ("CubeStack", cubestack, cube)