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
14 #include <X11/Intrinsic.h>
18 extern XtAppContext app;
20 #define PROGCLASS "Blocktube"
21 #define HACK_INIT init_blocktube
22 #define HACK_DRAW draw_blocktube
23 #define HACK_RESHAPE reshape_blocktube
24 #define EVENT_MASK PointerMotionMask
25 #define blocktube_opts xlockmore_opts
27 #define DEF_HOLDTIME "1000"
28 #define DEF_CHANGETIME "200"
29 #define MAX_ENTITIES 1000
30 #define DEF_TEXTURE "True"
31 #define DEF_FOG "True"
33 #define DEFAULTS "*delay: 40000 \n" \
34 "*holdtime: " DEF_HOLDTIME "\n" \
35 "*changetime: " DEF_CHANGETIME "\n" \
36 "*wireframe: False \n" \
37 "*texture: " DEF_TEXTURE "\n" \
38 "*fog: " DEF_FOG "\n" \
39 "*showFPS: False \n" \
42 #define countof(x) (sizeof((x))/sizeof((*x)))
44 #include "xlockmore.h"
49 #ifdef USE_GL /* whole file */
53 #if defined( USE_XPM ) || defined( USE_XPMINC ) || defined( HAVE_XPM )
54 /* USE_XPM & USE_XPMINC in xlock mode ; HAVE_XPM in xscreensaver mode */
55 #include "xpm-ximage.h"
58 #include "../images/blocktube.xpm"
62 GLXContext *glx_context;
64 } blocktube_configuration;
66 static int nextID = 1;
67 static blocktube_configuration *lps = NULL;
76 GLfloat angularVelocity;
79 static entity entities[MAX_ENTITIES];
80 static float targetR, targetG, targetB,
81 currentR, currentG, currentB,
82 deltaR, deltaG, deltaB;
83 static GLint holdtime;
84 static GLint changetime;
85 static int counter = 0;
86 static int changing = 0;
87 static GLfloat zoom = 30.0f;
88 static GLfloat tilt = 4.5f;
90 static GLuint envTexture;
92 static int do_texture;
95 GLfloat tunnelLength=200;
96 GLfloat tunnelWidth=5;
98 static XrmOptionDescRec opts[] = {
99 { "-holdtime", ".holdtime", XrmoptionSepArg, 0 },
100 { "-changetime", ".changetime", XrmoptionSepArg, 0 },
101 {"-texture", ".texture", XrmoptionNoArg, "True" },
102 {"+texture", ".texture", XrmoptionNoArg, "False" },
103 {"-fog", ".fog", XrmoptionNoArg, "True" },
104 {"+fog", ".fog", XrmoptionNoArg, "False" },
107 static argtype vars[] = {
108 {&holdtime, "holdtime", "Hold Time", DEF_HOLDTIME, t_Int},
109 {&changetime, "changetime", "Change Time", DEF_CHANGETIME, \
111 {&do_texture, "texture", "Texture", DEF_TEXTURE, t_Bool},
112 {&do_fog, "fog", "Fog", DEF_FOG, t_Bool},
115 static OptionStruct desc[] = {
116 {"-holdtime", "how long to stay on the same color"},
117 {"-changetime", "how long it takes to fade to a new color"},
120 ModeSpecOpt blocktube_opts = {countof(opts), opts, countof(vars), vars, desc};
123 ModStruct blocktube_description =
124 {"blocktube", "init_blocktube", "draw_blocktube", "release_blocktube",
125 "draw_blocktube", "init_blocktube", (char *)NULL, &blocktube_opts,
126 40000, 30, 1, 1, 64, 1.0, "",
127 "A shifting tunnel of reflective blocks", 0, NULL};
128 #endif /* USE_MODULES */
130 #if defined( I_HAVE_XPM )
131 static Bool LoadGLTextures(ModeInfo *mi)
136 glGenTextures(1, &envTexture);
137 glBindTexture(GL_TEXTURE_2D, envTexture);
138 texti = xpm_to_ximage(MI_DISPLAY(mi), MI_VISUAL(mi), MI_COLORMAP(mi),
143 glPixelStorei(GL_UNPACK_ALIGNMENT,1);
144 glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texti->width, texti->height, 0,
145 GL_RGBA, GL_UNSIGNED_INT_8_8_8_8_REV, texti->data);
146 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
147 glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
148 glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
149 glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
155 static void newTargetColor(void)
159 while (luminance <= 150) {
160 targetR = random() % 256;
161 targetG = random() % 256;
162 targetB = random() % 256;
163 deltaR = (targetR - currentR) / changetime;
164 deltaG = (targetG - currentG) / changetime;
165 deltaB = (targetB - currentB) / changetime;
166 luminance = 0.3 * targetR + 0.59 * targetG + 0.11 * targetB;
170 static void randomize_entity (entity *ent)
173 ent->tVal = 1 - ((float)random() / RAND_MAX / 1.5);
176 ent->angle = random() % 360;
177 ent->angularVelocity = 0.5-((float)(random()) / RAND_MAX);
178 ent->position[0] = (float)(random()) / RAND_MAX + tunnelWidth;
179 ent->position[1] = (float)(random()) / RAND_MAX * 2;
180 ent->position[2] = -(float)(random()) / RAND_MAX * tunnelLength;
183 static void entityTick(entity *ent)
185 ent->angle += ent->angularVelocity;
186 ent->position[2] += 0.1;
187 if (ent->position[2] > zoom) {
188 ent->position[2] = -tunnelLength + ((float)(random()) / RAND_MAX) * 20;
193 static void tick(void)
199 counter = changetime;
203 changing = (!changing);
213 static void cube_vertices(float x, float y, float z, int wire);
215 void init_blocktube (ModeInfo *mi)
217 GLfloat fogColor[4] = {0,0,0,1};
218 blocktube_configuration *lp;
219 int wire = MI_IS_WIREFRAME(mi);
222 lps = (blocktube_configuration *)
223 calloc (MI_NUM_SCREENS(mi), sizeof (blocktube_configuration));
225 fprintf(stderr, "%s: out of memory\n", progname);
228 lp = &lps[MI_SCREEN(mi)];
231 lp = &lps[MI_SCREEN(mi)];
232 lp->glx_context = init_GL(mi);
240 lp->block_dlist = glGenLists (1);
241 glNewList (lp->block_dlist, GL_COMPILE);
242 cube_vertices(0.15, 1.2, 5.25, wire);
245 #if defined( I_HAVE_XPM )
247 if (!LoadGLTextures(mi)) {
248 fprintf(stderr, "%s: can't load textures!\n", progname);
251 glEnable(GL_TEXTURE_2D);
255 /* kick on the fog machine */
258 glFogi(GL_FOG_MODE, GL_LINEAR);
259 glHint(GL_FOG_HINT, GL_NICEST);
260 glFogf(GL_FOG_START, 0);
261 glFogf(GL_FOG_END, tunnelLength/1.8);
262 glFogfv(GL_FOG_COLOR, fogColor);
263 glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);
265 glShadeModel(GL_SMOOTH);
266 glEnable(GL_DEPTH_TEST);
267 glEnable(GL_CULL_FACE);
268 glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
271 if (!do_texture && !wire) {
272 /* If there is no texture, the boxes don't show up without a light.
273 Though I don't understand why all the blocks come out gray.
275 GLfloat pos[4] = {0.0, 1.0, 1.0, 0.0};
276 GLfloat amb[4] = {0.2, 0.2, 0.2, 1.0};
277 GLfloat dif[4] = {1.0, 1.0, 1.0, 1.0};
278 GLfloat spc[4] = {1.0, 1.0, 1.0, 1.0};
279 glLightfv(GL_LIGHT0, GL_POSITION, pos);
280 glLightfv(GL_LIGHT0, GL_AMBIENT, amb);
281 glLightfv(GL_LIGHT0, GL_DIFFUSE, dif);
282 glLightfv(GL_LIGHT0, GL_SPECULAR, spc);
283 glEnable(GL_LIGHTING);
288 currentR = random() % 256;
289 currentG = random() % 256;
290 currentB = random() % 256;
292 for (loop = 0; loop < MAX_ENTITIES; loop++)
294 randomize_entity(&entities[loop]);
296 reshape_blocktube(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
300 void release_blocktube (ModeInfo *mi)
302 #if defined ( I_HAVE_XPM )
303 glDeleteTextures(1, &envTexture);
304 XDestroyImage(texti);
308 void reshape_blocktube (ModeInfo *mi, int width, int height)
310 GLfloat h = (GLfloat) height / (GLfloat) width;
312 glViewport(0, 0, (GLint) width, (GLint) height);
313 glMatrixMode(GL_PROJECTION);
315 gluPerspective(45.0, 1/h, 1.0, 100.0);
316 glMatrixMode(GL_MODELVIEW);
319 static void cube_vertices(float x, float y, float z, int wire)
321 float x2, y2, z2, nv = 0.7;
328 glNormal3f(0, 0, nv);
329 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
330 glTexCoord2f(0.0, 0.0); glVertex3f(-x2, y2, z2);
331 glTexCoord2f(1.0, 0.0); glVertex3f( x2, y2, z2);
332 glTexCoord2f(1.0, 1.0); glVertex3f( x2, -y2, z2);
333 glTexCoord2f(0.0, 1.0); glVertex3f(-x2, -y2, z2);
336 glNormal3f(0, 0, -nv);
337 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
338 glTexCoord2f(1.0, 0.0); glVertex3f(-x2, -y2, -z2);
339 glTexCoord2f(1.0, 1.0); glVertex3f( x2, -y2, -z2);
340 glTexCoord2f(0.0, 1.0); glVertex3f( x2, y2, -z2);
341 glTexCoord2f(0.0, 0.0); glVertex3f(-x2, y2, -z2);
344 glNormal3f(0, nv, 0);
345 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
346 glTexCoord2f(0.0, 1.0); glVertex3f(-x2, y2, -z2);
347 glTexCoord2f(0.0, 0.0); glVertex3f( x2, y2, -z2);
348 glTexCoord2f(1.0, 0.0); glVertex3f( x2, y2, z2);
349 glTexCoord2f(1.0, 1.0); glVertex3f(-x2, y2, z2);
352 glNormal3f(0, -nv, 0);
353 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
354 glTexCoord2f(1.0, 1.0); glVertex3f(-x2, -y2, -z2);
355 glTexCoord2f(0.0, 1.0); glVertex3f(-x2, -y2, z2);
356 glTexCoord2f(0.0, 0.0); glVertex3f( x2, -y2, z2);
357 glTexCoord2f(1.0, 0.0); glVertex3f( x2, -y2, -z2);
362 glNormal3f(nv, 0, 0);
363 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
364 glTexCoord2f(1.0, 0.0); glVertex3f( x2, -y2, -z2);
365 glTexCoord2f(1.0, 1.0); glVertex3f( x2, -y2, z2);
366 glTexCoord2f(0.0, 1.0); glVertex3f( x2, y2, z2);
367 glTexCoord2f(0.0, 0.0); glVertex3f( x2, y2, -z2);
370 glNormal3f(-nv, 0, 0);
371 glBegin (wire ? GL_LINE_LOOP : GL_QUADS);
372 glTexCoord2f(0.0, 0.0); glVertex3f(-x2, -y2, -z2);
373 glTexCoord2f(1.0, 0.0); glVertex3f(-x2, y2, -z2);
374 glTexCoord2f(1.0, 1.0); glVertex3f(-x2, y2, z2);
375 glTexCoord2f(0.0, 1.0); glVertex3f(-x2, -y2, z2);
379 static void draw_block(ModeInfo *mi, entity *ent)
381 blocktube_configuration *lp = &lps[MI_SCREEN(mi)];
382 glCallList (lp->block_dlist);
386 draw_blocktube (ModeInfo *mi)
388 blocktube_configuration *lp = &lps[MI_SCREEN(mi)];
389 Display *dpy = MI_DISPLAY(mi);
390 Window window = MI_WINDOW(mi);
394 if (!lp->glx_context)
397 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
400 glEnable(GL_TEXTURE_GEN_S);
401 glEnable(GL_TEXTURE_GEN_T);
402 glBindTexture(GL_TEXTURE_2D, envTexture);
405 for (loop = 0; loop < MAX_ENTITIES; loop++) {
406 cEnt = &entities[loop];
409 glTranslatef(0.0f, 0.0f, zoom);
410 glRotatef(tilt, 1.0f, 0.0f, 0.0f);
411 glRotatef(cEnt->angle, 0.0f, 0.0f, 1.0f);
412 glTranslatef(cEnt->position[0], cEnt->position[1], cEnt->position[2]);
413 glColor4ub((int)(currentR * cEnt->tVal),
414 (int)(currentG * cEnt->tVal),
415 (int)(currentB * cEnt->tVal), 255);
416 draw_block(mi, cEnt);
421 if (mi->fps_p) do_fps (mi);
423 glXSwapBuffers(dpy, window);