1 /* blocktube, Copyright (c) 2003 Lars Damerow <lars@oddment.org>
3 * Based on Jamie Zawinski's original dangerball code.
5 * Permission to use, copy, modify, distribute, and sell this software and its
6 * documentation for any purpose is hereby granted without fee, provided that
7 * the above copyright notice appear in all copies and that both that
8 * copyright notice and this permission notice appear in supporting
9 * documentation. No representations are made about the suitability of this
10 * software for any purpose. It is provided "as is" without express or
16 #define DEFAULTS "*delay: 40000 \n" \
17 "*wireframe: False \n" \
18 "*showFPS: False \n" \
19 "*suppressRotationAnimation: True\n" \
21 # define refresh_blocktube 0
22 # define release_blocktube 0
23 # define blocktube_handle_event 0
25 #define countof(x) (sizeof((x))/sizeof((*x)))
27 #include "xlockmore.h"
32 #ifdef USE_GL /* whole file */
34 #define DEF_HOLDTIME "1000"
35 #define DEF_CHANGETIME "200"
36 #define MAX_ENTITIES 1000
37 #define DEF_TEXTURE "True"
38 #define DEF_FOG "True"
40 #if defined(USE_XPM) || defined(USE_XPMINC) || defined(STANDALONE)
41 /* USE_XPM & USE_XPMINC in xlock mode ; HAVE_XPM in xscreensaver mode */
42 #include "xpm-ximage.h"
45 #include "../images/blocktube.xpm"
55 GLfloat angularVelocity;
59 GLXContext *glx_context;
63 entity entities[MAX_ENTITIES];
64 float targetR, targetG, targetB,
65 currentR, currentG, currentB,
66 deltaR, deltaG, deltaB;
78 } blocktube_configuration;
80 static blocktube_configuration *lps = NULL;
82 static GLint holdtime;
83 static GLint changetime;
84 static int do_texture;
87 static XrmOptionDescRec opts[] = {
88 { "-holdtime", ".holdtime", XrmoptionSepArg, 0 },
89 { "-changetime", ".changetime", XrmoptionSepArg, 0 },
90 {"-texture", ".texture", XrmoptionNoArg, "True" },
91 {"+texture", ".texture", XrmoptionNoArg, "False" },
92 {"-fog", ".fog", XrmoptionNoArg, "True" },
93 {"+fog", ".fog", XrmoptionNoArg, "False" },
96 static argtype vars[] = {
97 {&holdtime, "holdtime", "Hold Time", DEF_HOLDTIME, t_Int},
98 {&changetime, "changetime", "Change Time", DEF_CHANGETIME, \
100 {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
101 {&do_fog, "fog", "Fog", DEF_FOG, t_Bool},
104 static OptionStruct desc[] = {
105 {"-holdtime", "how long to stay on the same color"},
106 {"-changetime", "how long it takes to fade to a new color"},
109 ENTRYPOINT ModeSpecOpt blocktube_opts = {countof(opts), opts, countof(vars), vars, desc};
112 ModStruct blocktube_description =
113 {"blocktube", "init_blocktube", "draw_blocktube", (char *)NULL,
114 "draw_blocktube", "init_blocktube", (char *)NULL, &blocktube_opts,
115 40000, 30, 1, 1, 64, 1.0, "",
116 "A shifting tunnel of reflective blocks", 0, NULL};
117 #endif /* USE_MODULES */
119 #if defined( I_HAVE_XPM )
120 static Bool LoadGLTextures(ModeInfo *mi)
122 blocktube_configuration *lp = &lps[MI_SCREEN(mi)];
126 glGenTextures(1, &lp->envTexture);
127 glBindTexture(GL_TEXTURE_2D, lp->envTexture);
128 lp->texti = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi), MI_COLORMAP(mi),
133 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
134 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, lp->texti->width, lp->texti->height, 0,
135 GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, lp->texti->data);
136 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
137 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
138 # ifndef HAVE_JWZGLES /* #### Sphere maps unimplemented */
139 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
140 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
147 static void newTargetColor(blocktube_configuration *lp)
151 while (luminance <= 150) {
152 lp->targetR = random() % 256;
153 lp->targetG = random() % 256;
154 lp->targetB = random() % 256;
155 lp->deltaR = (lp->targetR - lp->currentR) / changetime;
156 lp->deltaG = (lp->targetG - lp->currentG) / changetime;
157 lp->deltaB = (lp->targetB - lp->currentB) / changetime;
158 luminance = 0.3 * lp->targetR + 0.59 * lp->targetG + 0.11 * lp->targetB;
162 static void randomize_entity (blocktube_configuration *lp, entity *ent)
164 ent->id = lp->nextID++;
165 ent->tVal = 1 - ((float)random() / RAND_MAX / 1.5);
168 ent->angle = random() % 360;
169 ent->angularVelocity = 0.5-((float)(random()) / RAND_MAX);
170 ent->position[0] = (float)(random()) / RAND_MAX + lp->tunnelWidth;
171 ent->position[1] = (float)(random()) / RAND_MAX * 2;
172 ent->position[2] = -(float)(random()) / RAND_MAX * lp->tunnelLength;
175 static void entityTick(blocktube_configuration *lp, entity *ent)
177 ent->angle += ent->angularVelocity;
178 ent->position[2] += 0.1;
179 if (ent->position[2] > lp->zoom) {
180 ent->position[2] = -lp->tunnelLength + ((float)(random()) / RAND_MAX) * 20;
185 static void tick(blocktube_configuration *lp)
191 lp->counter = changetime;
193 lp->counter = holdtime;
195 lp->changing = (!lp->changing);
198 lp->currentR += lp->deltaR;
199 lp->currentG += lp->deltaG;
200 lp->currentB += lp->deltaB;
205 static int cube_vertices(float x, float y, float z, int wire);
207 ENTRYPOINT void reshape_blocktube (ModeInfo *mi, int width, int height);
208 static void free_blocktube (ModeInfo *mi);
210 ENTRYPOINT void init_blocktube (ModeInfo *mi)
213 GLfloat fogColor[4] = {0,0,0,1};
214 blocktube_configuration *lp;
215 int wire = MI_IS_WIREFRAME(mi);
217 MI_INIT(mi, lps, free_blocktube);
219 lp = &lps[MI_SCREEN(mi)];
220 lp->glx_context = init_GL(mi);
224 lp->tunnelLength = 200;
233 lp->block_dlist = glGenLists (1);
234 glNewList (lp->block_dlist, GL_COMPILE);
235 lp->polys = cube_vertices(0.15, 1.2, 5.25, wire);
238 #if defined( I_HAVE_XPM )
240 if (!LoadGLTextures(mi)) {
241 fprintf(stderr, "%s: can't load textures!\n", progname);
244 glEnable(GL_TEXTURE_2D);
248 /* kick on the fog machine */
251 glFogi(GL_FOG_MODE, GL_LINEAR);
252 glHint(GL_FOG_HINT, GL_NICEST);
253 glFogf(GL_FOG_START, 0);
254 glFogf(GL_FOG_END, lp->tunnelLength/1.8);
255 glFogfv(GL_FOG_COLOR, fogColor);
256 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
258 glShadeModel(GL_SMOOTH);
259 glEnable(GL_DEPTH_TEST);
260 glEnable(GL_CULL_FACE);
263 if (!do_texture && !wire) {
264 /* If there is no texture, the boxes don't show up without a light.
265 Though I don't understand why all the blocks come out gray.
267 GLfloat pos[4] = {0.0, 1.0, 1.0, 0.0};
268 GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0};
269 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
270 GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0};
271 glLightfv(GL_LIGHT0, GL_POSITION, pos);
272 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
273 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
274 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
275 glEnable(GL_LIGHTING);
279 lp->counter = holdtime;
280 lp->currentR = random() % 256;
281 lp->currentG = random() % 256;
282 lp->currentB = random() % 256;
284 for (loop = 0; loop < MAX_ENTITIES; loop++)
286 randomize_entity(lp, &lp->entities[loop]);
288 reshape_blocktube(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
292 static void free_blocktube (ModeInfo *mi)
294 blocktube_configuration *lp = &lps[MI_SCREEN(mi)];
295 # if defined ( I_HAVE_XPM )
296 if (lp->glx_context) {
297 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(lp->glx_context));
300 glDeleteTextures(1, &lp->envTexture);
302 XDestroyImage(lp->texti);
307 ENTRYPOINT void reshape_blocktube (ModeInfo *mi, int width, int height)
309 blocktube_configuration *lp = &lps[MI_SCREEN(mi)];
310 GLfloat h = (GLfloat) height / (GLfloat) width;
312 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(lp->glx_context));
314 glViewport(0, 0, (GLint) width, (GLint) height);
315 glMatrixMode(GL_PROJECTION);
317 gluPerspective(45.0, 1/h, 1.0, 100.0);
318 glMatrixMode(GL_MODELVIEW);
320 # ifdef HAVE_MOBILE /* Keep it the same relative size when rotated. */
322 int o = (int) current_device_rotation();
323 if (o != 0 && o != 180 && o != -180)
324 glScalef (1/h, 1/h, 1/h);
329 static int cube_vertices(float x, float y, float z, int wire)
331 int polygon_count = 0;
332 float x2, y2, z2, nv = 0.7;
339 glNormal3f(0, 0, nv);
340 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
341 glTexCoord2f(0.0, 0.0); glVertex3f(-x2, y2, z2);
342 glTexCoord2f(1.0, 0.0); glVertex3f( x2, y2, z2);
343 glTexCoord2f(1.0, 1.0); glVertex3f( x2, -y2, z2);
344 glTexCoord2f(0.0, 1.0); glVertex3f(-x2, -y2, z2);
348 glNormal3f(0, 0, -nv);
349 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
350 glTexCoord2f(1.0, 0.0); glVertex3f(-x2, -y2, -z2);
351 glTexCoord2f(1.0, 1.0); glVertex3f( x2, -y2, -z2);
352 glTexCoord2f(0.0, 1.0); glVertex3f( x2, y2, -z2);
353 glTexCoord2f(0.0, 0.0); glVertex3f(-x2, y2, -z2);
357 glNormal3f(0, nv, 0);
358 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
359 glTexCoord2f(0.0, 1.0); glVertex3f(-x2, y2, -z2);
360 glTexCoord2f(0.0, 0.0); glVertex3f( x2, y2, -z2);
361 glTexCoord2f(1.0, 0.0); glVertex3f( x2, y2, z2);
362 glTexCoord2f(1.0, 1.0); glVertex3f(-x2, y2, z2);
366 glNormal3f(0, -nv, 0);
367 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
368 glTexCoord2f(1.0, 1.0); glVertex3f(-x2, -y2, -z2);
369 glTexCoord2f(0.0, 1.0); glVertex3f(-x2, -y2, z2);
370 glTexCoord2f(0.0, 0.0); glVertex3f( x2, -y2, z2);
371 glTexCoord2f(1.0, 0.0); glVertex3f( x2, -y2, -z2);
375 if (wire) return polygon_count;
377 glNormal3f(nv, 0, 0);
378 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
379 glTexCoord2f(1.0, 0.0); glVertex3f( x2, -y2, -z2);
380 glTexCoord2f(1.0, 1.0); glVertex3f( x2, -y2, z2);
381 glTexCoord2f(0.0, 1.0); glVertex3f( x2, y2, z2);
382 glTexCoord2f(0.0, 0.0); glVertex3f( x2, y2, -z2);
386 glNormal3f(-nv, 0, 0);
387 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
388 glTexCoord2f(0.0, 0.0); glVertex3f(-x2, -y2, -z2);
389 glTexCoord2f(1.0, 0.0); glVertex3f(-x2, y2, -z2);
390 glTexCoord2f(1.0, 1.0); glVertex3f(-x2, y2, z2);
391 glTexCoord2f(0.0, 1.0); glVertex3f(-x2, -y2, z2);
395 return polygon_count;
398 static void draw_block(ModeInfo *mi, entity *ent)
400 blocktube_configuration *lp = &lps[MI_SCREEN(mi)];
401 glCallList (lp->block_dlist);
402 mi->polygon_count += lp->polys;
406 draw_blocktube (ModeInfo *mi)
408 blocktube_configuration *lp = &lps[MI_SCREEN(mi)];
409 Display *dpy = MI_DISPLAY(mi);
410 Window window = MI_WINDOW(mi);
414 if (!lp->glx_context)
417 mi->polygon_count = 0;
419 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(lp->glx_context));
421 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
424 glEnable(GL_TEXTURE_GEN_S);
425 glEnable(GL_TEXTURE_GEN_T);
426 glBindTexture(GL_TEXTURE_2D, lp->envTexture);
429 for (loop = 0; loop < MAX_ENTITIES; loop++) {
430 cEnt = &lp->entities[loop];
433 glTranslatef(0.0f, 0.0f, lp->zoom);
434 glRotatef(lp->tilt, 1.0f, 0.0f, 0.0f);
435 glRotatef(cEnt->angle, 0.0f, 0.0f, 1.0f);
436 glTranslatef(cEnt->position[0], cEnt->position[1], cEnt->position[2]);
437 glColor4ub((int)(lp->currentR * cEnt->tVal),
438 (int)(lp->currentG * cEnt->tVal),
439 (int)(lp->currentB * cEnt->tVal), 255);
440 draw_block(mi, cEnt);
441 entityTick(lp, cEnt);
445 if (mi->fps_p) do_fps (mi);
447 glXSwapBuffers(dpy, window);
450 XSCREENSAVER_MODULE ("BlockTube", blocktube)