1 /* -*- Mode: C; tab-width: 4 -*- */
2 /* pipes --- 3D selfbuiding pipe system */
5 static const char sccsid[] = "@(#)pipes.c 4.07 97/11/24 xlockmore";
9 * Permission to use, copy, modify, and distribute this software and its
10 * documentation for any purpose and without fee is hereby granted,
11 * provided that the above copyright notice appear in all copies and that
12 * both that copyright notice and this permission notice appear in
13 * supporting documentation.
15 * This file is provided AS IS with no warranties of any kind. The author
16 * shall have no liability with respect to the infringement of copyrights,
17 * trade secrets or any patents by this file or any part thereof. In no
18 * event will the author be liable for any lost revenue or profits or
19 * other special, indirect and consequential damages.
21 * This program was inspired on a WindowsNT(R)'s screen saver. It was written
22 * from scratch and it was not based on any other source code.
24 * ==========================================================================
25 * The routine myElbow is derivated from the doughnut routine from the MesaGL
26 * library (more especifically the Mesaaux library) written by Brian Paul.
27 * ==========================================================================
29 * Thanks goes to Brian Paul for making it possible and inexpensive to use
32 * Since I'm not a native English speaker, my apologies for any grammatical
35 * My e-mail address is
37 * Marcelo F. Vianna (Apr-09-1997)
40 * 24-Jun-12: Eliminate single-buffer dependency.
41 * 29-Apr-97: Factory equipment by Ed Mackey. Productive day today, eh?
42 * 29-Apr-97: Less tight turns Jeff Epler <jepler@inetnebr.com>
43 * 29-Apr-97: Efficiency speed-ups by Marcelo F. Vianna
46 /* This program was originally written to be single-buffered: it kept
47 building up new objects in the front buffer by never clearing the
48 depth or color buffers at the end of each frame. In that way, it
49 was drawing a very small number of polygons per frame. However,
50 modern systems make it difficult to live in a single-buffered world
51 like that. So I changed it to re-generate the scene at every
52 frame, which makes it vastly less efficient, but also, makes it
53 work right on modern hardware. It generates the entire system up
54 front, putting each "frame" of the animation into its own display
55 list; then it draws successively more of those display lists each
56 time the redisplay method is called. When it reaches the end,
57 it regenerates a new system and re-populates the existing display
62 # define DEFAULTS "*delay: 10000 \n" \
66 "*showFPS: False \n" \
67 "*fpsSolid: True \n" \
68 "*wireframe: False \n" \
69 "*suppressRotationAnimation: True\n" \
71 # define refresh_pipes 0
72 # include "xlockmore.h" /* from the xscreensaver distribution */
73 #else /* !STANDALONE */
74 # include "xlock.h" /* from the xlockmore distribution */
75 #endif /* !STANDALONE */
82 # include <X11/Xlib.h>
89 #endif /* HAVE_JWZGLES */
94 #include "gltrackball.h"
96 #define DEF_FACTORY "2"
97 #define DEF_FISHEYE "True"
98 #define DEF_TIGHTTURNS "False"
99 #define DEF_ROTATEPIPES "True"
100 #define NofSysTypes 3
103 static Bool fisheye, tightturns, rotatepipes;
105 static XrmOptionDescRec opts[] =
107 {"-factory", ".pipes.factory", XrmoptionSepArg, 0},
108 {"-fisheye", ".pipes.fisheye", XrmoptionNoArg, "on"},
109 {"+fisheye", ".pipes.fisheye", XrmoptionNoArg, "off"},
110 {"-tightturns", ".pipes.tightturns", XrmoptionNoArg, "on"},
111 {"+tightturns", ".pipes.tightturns", XrmoptionNoArg, "off"},
112 {"-rotatepipes", ".pipes.rotatepipes", XrmoptionNoArg, "on"},
113 {"+rotatepipes", ".pipes.rotatepipes", XrmoptionNoArg, "off"},
115 static argtype vars[] =
117 {&factory, "factory", "Factory", DEF_FACTORY, t_Int},
118 {&fisheye, "fisheye", "Fisheye", DEF_FISHEYE, t_Bool},
119 {&tightturns, "tightturns", "Tightturns", DEF_TIGHTTURNS, t_Bool},
120 {&rotatepipes, "rotatepipes", "Rotatepipes", DEF_ROTATEPIPES, t_Bool},
122 static OptionStruct desc[] =
124 {"-factory num", "how much extra equipment in pipes (0 for none)"},
125 {"-/+fisheye", "turn on/off zoomed-in view of pipes"},
126 {"-/+tightturns", "turn on/off tight turns"},
127 {"-/+rotatepipes", "turn on/off pipe system rotation per screenful"},
130 ENTRYPOINT ModeSpecOpt pipes_opts =
131 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
134 ModStruct pipes_description =
135 {"pipes", "init_pipes", "draw_pipes", "release_pipes",
137 "change_pipes", NULL, &pipes_opts,
138 1000, 2, 5, 500, 4, 1.0, "",
139 "Shows a selfbuilding pipe system", 0, NULL};
143 #define Scale4Window 0.1
145 #define one_third 0.3333333333333333333
157 #define DEFINEDCOLORS 7
158 #define elbowradius 0.5
160 /*************************************************************************/
165 int Cells[HCELLS][VCELLS][HCELLS];
166 int usedcolors[DEFINEDCOLORS];
173 int number_of_systems;
178 const float *system_color;
179 GLfloat initial_rotation;
180 GLuint valve, bolts, betweenbolts, elbowbolts, elbowcoins;
181 GLuint guagehead, guageface, guagedial, guageconnector, teapot;
183 GLXContext *glx_context;
186 trackball_state *trackball;
187 GLuint *dlists, *poly_counts;
188 int dlist_count, dlist_size;
189 int system_index, system_size;
195 extern struct lwo LWO_BigValve, LWO_PipeBetweenBolts, LWO_Bolts3D;
196 extern struct lwo LWO_GuageHead, LWO_GuageFace, LWO_GuageDial, LWO_GuageConnector;
197 extern struct lwo LWO_ElbowBolts, LWO_ElbowCoins;
199 static const float front_shininess[] = {60.0};
200 static const float front_specular[] = {0.7, 0.7, 0.7, 1.0};
201 static const float ambient0[] = {0.4, 0.4, 0.4, 1.0};
202 static const float diffuse0[] = {1.0, 1.0, 1.0, 1.0};
203 static const float ambient1[] = {0.2, 0.2, 0.2, 1.0};
204 static const float diffuse1[] = {0.5, 0.5, 0.5, 1.0};
205 static const float position0[] = {1.0, 1.0, 1.0, 0.0};
206 static const float position1[] = {-1.0, -1.0, 1.0, 0.0};
207 static const float lmodel_ambient[] = {0.5, 0.5, 0.5, 1.0};
208 static const float lmodel_twoside[] = {GL_TRUE};
210 static const float MaterialRed[] = {0.7, 0.0, 0.0, 1.0};
211 static const float MaterialGreen[] = {0.1, 0.5, 0.2, 1.0};
212 static const float MaterialBlue[] = {0.0, 0.0, 0.7, 1.0};
213 static const float MaterialCyan[] = {0.2, 0.5, 0.7, 1.0};
214 static const float MaterialYellow[] = {0.7, 0.7, 0.0, 1.0};
215 static const float MaterialMagenta[] = {0.6, 0.2, 0.5, 1.0};
216 static const float MaterialWhite[] = {0.7, 0.7, 0.7, 1.0};
217 static const float MaterialGray[] = {0.2, 0.2, 0.2, 1.0};
219 static pipesstruct *pipes = NULL;
223 MakeTube(ModeInfo *mi, int direction)
225 Bool wire = MI_IS_WIREFRAME(mi);
227 float SINan_3, COSan_3;
228 int facets = (wire ? 5 : 24);
230 /*dirUP = 00000000 */
231 /*dirDOWN = 00000001 */
232 /*dirLEFT = 00000010 */
233 /*dirRIGHT = 00000011 */
234 /*dirNEAR = 00000100 */
235 /*dirFAR = 00000101 */
237 if (!(direction & 4)) {
238 glRotatef(90.0, (direction & 2) ? 0.0 : 1.0,
239 (direction & 2) ? 1.0 : 0.0, 0.0);
241 glBegin(wire ? GL_LINE_STRIP : GL_QUAD_STRIP);
242 for (an = 0.0; an <= 2.0 * M_PI; an += M_PI * 2 / facets) {
243 glNormal3f((COSan_3 = cos(an) / 3.0), (SINan_3 = sin(an) / 3.0), 0.0);
244 glVertex3f(COSan_3, SINan_3, one_third);
245 glVertex3f(COSan_3, SINan_3, -one_third);
252 mySphere(float radius, Bool wire)
255 GLUquadricObj *quadObj;
257 quadObj = gluNewQuadric();
258 gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
259 gluSphere(quadObj, radius, 16, 16);
260 gluDeleteQuadric(quadObj);
263 glScalef (radius, radius, radius);
264 glRotatef (90, 1, 0, 0);
265 unit_sphere (16, 16, wire);
271 myElbow(ModeInfo * mi, int bolted)
273 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
274 Bool wire = MI_IS_WIREFRAME(mi);
276 int nsides = (wire ? 6 : 25);
282 GLfloat p0[3], p1[3], p2[3], p3[3];
283 GLfloat n0[3], n1[3], n2[3], n3[3];
284 GLfloat COSphi, COSphi1, COStheta, COStheta1;
285 GLfloat _SINtheta, _SINtheta1;
287 for (i = 0; i <= rings / 4; i++) {
288 GLfloat theta, theta1;
290 theta = (GLfloat) i *2.0 * M_PI / rings;
292 theta1 = (GLfloat) (i + 1) * 2.0 * M_PI / rings;
293 for (j = 0; j < nsides; j++) {
296 phi = (GLfloat) j *2.0 * M_PI / nsides;
298 phi1 = (GLfloat) (j + 1) * 2.0 * M_PI / nsides;
300 p0[0] = (COStheta = cos(theta)) * (R + r * (COSphi = cos(phi)));
301 p0[1] = (_SINtheta = -sin(theta)) * (R + r * COSphi);
303 p1[0] = (COStheta1 = cos(theta1)) * (R + r * COSphi);
304 p1[1] = (_SINtheta1 = -sin(theta1)) * (R + r * COSphi);
306 p2[0] = COStheta1 * (R + r * (COSphi1 = cos(phi1)));
307 p2[1] = _SINtheta1 * (R + r * COSphi1);
309 p3[0] = COStheta * (R + r * COSphi1);
310 p3[1] = _SINtheta * (R + r * COSphi1);
312 n0[0] = COStheta * COSphi;
313 n0[1] = _SINtheta * COSphi;
315 n1[0] = COStheta1 * COSphi;
316 n1[1] = _SINtheta1 * COSphi;
318 n2[0] = COStheta1 * COSphi1;
319 n2[1] = _SINtheta1 * COSphi1;
321 n3[0] = COStheta * COSphi1;
322 n3[1] = _SINtheta * COSphi1;
324 p0[2] = p1[2] = r * (n0[2] = n1[2] = sin(phi));
325 p2[2] = p3[2] = r * (n2[2] = n3[2] = sin(phi1));
327 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
341 if (factory > 0 && bolted) {
342 /* Bolt the elbow onto the pipe system */
345 glRotatef(90.0, 0.0, 0.0, -1.0);
346 glRotatef(90.0, 0.0, 1.0, 0.0);
347 glTranslatef(0.0, one_third, one_third);
348 glCallList(pp->elbowcoins);
349 mi->polygon_count += LWO_ElbowCoins.num_pnts/3;
350 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
351 glCallList(pp->elbowbolts);
352 mi->polygon_count += LWO_ElbowBolts.num_pnts/3;
353 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
364 FindNeighbors(ModeInfo * mi)
366 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
369 pp->directions[dirUP] = (!pp->Cells[pp->PX][pp->PY + 1][pp->PZ]) ? 1 : 0;
370 pp->ndirections += pp->directions[dirUP];
371 pp->directions[dirDOWN] = (!pp->Cells[pp->PX][pp->PY - 1][pp->PZ]) ? 1 : 0;
372 pp->ndirections += pp->directions[dirDOWN];
373 pp->directions[dirLEFT] = (!pp->Cells[pp->PX - 1][pp->PY][pp->PZ]) ? 1 : 0;
374 pp->ndirections += pp->directions[dirLEFT];
375 pp->directions[dirRIGHT] = (!pp->Cells[pp->PX + 1][pp->PY][pp->PZ]) ? 1 : 0;
376 pp->ndirections += pp->directions[dirRIGHT];
377 pp->directions[dirFAR] = (!pp->Cells[pp->PX][pp->PY][pp->PZ - 1]) ? 1 : 0;
378 pp->ndirections += pp->directions[dirFAR];
379 pp->directions[dirNEAR] = (!pp->Cells[pp->PX][pp->PY][pp->PZ + 1]) ? 1 : 0;
380 pp->ndirections += pp->directions[dirNEAR];
384 SelectNeighbor(ModeInfo * mi)
386 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
390 for (i = 0, j = 0; i < 6; i++) {
391 if (pp->directions[i]) {
397 return dirlist[NRAND(pp->ndirections)];
401 MakeValve(ModeInfo * mi, int newdir)
403 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
405 /* There is a glPopMatrix() right after this subroutine returns. */
409 glRotatef(90.0, 1.0, 0.0, 0.0);
410 glRotatef(NRAND(3) * 90.0, 0.0, 0.0, 1.0);
414 glRotatef(90.0, 0.0, -1.0, 0.0);
415 glRotatef((NRAND(3) * 90.0) - 90.0, 0.0, 0.0, 1.0);
419 glRotatef(NRAND(4) * 90.0, 0.0, 0.0, 1.0);
423 glCallList(pp->betweenbolts);
424 mi->polygon_count += LWO_PipeBetweenBolts.num_pnts/3;
425 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
426 glCallList(pp->bolts);
427 mi->polygon_count += LWO_Bolts3D.num_pnts/3;
428 if (!MI_IS_MONO(mi)) {
429 if (pp->system_color == MaterialRed) {
430 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, NRAND(2) ? MaterialYellow : MaterialBlue);
431 } else if (pp->system_color == MaterialBlue) {
432 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, NRAND(2) ? MaterialRed : MaterialYellow);
433 } else if (pp->system_color == MaterialYellow) {
434 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, NRAND(2) ? MaterialBlue : MaterialRed);
436 switch ((NRAND(3))) {
438 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
441 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialBlue);
444 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialYellow);
448 glRotatef((GLfloat) (NRAND(90)), 1.0, 0.0, 0.0);
449 glCallList(pp->valve);
450 mi->polygon_count += LWO_BigValve.num_pnts/3;
451 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
456 MakeGuage(ModeInfo * mi, int newdir)
458 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
460 /* Can't have a guage on a vertical pipe. */
461 if ((newdir == dirUP) || (newdir == dirDOWN))
464 /* Is there space above this pipe for a guage? */
465 if (!pp->directions[dirUP])
468 /* Yes! Mark the space as used. */
469 pp->Cells[pp->PX][pp->PY + 1][pp->PZ] = 1;
473 if ((newdir == dirLEFT) || (newdir == dirRIGHT))
474 glRotatef(90.0, 0.0, 1.0, 0.0);
475 glCallList(pp->betweenbolts);
476 mi->polygon_count += LWO_PipeBetweenBolts.num_pnts/3;
477 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
478 glCallList(pp->bolts);
479 mi->polygon_count += LWO_Bolts3D.num_pnts/3;
482 glCallList(pp->guageconnector);
483 mi->polygon_count += LWO_GuageConnector.num_pnts/3;
485 glTranslatef(0.0, 1.33333, 0.0);
486 /* Do not change the above to 1 + ONE_THIRD, because */
487 /* the object really is centered on 1.3333300000. */
488 glRotatef(NRAND(270) + 45.0, 0.0, 0.0, -1.0);
489 /* Random rotation for the dial. I love it. */
490 glCallList(pp->guagedial);
491 mi->polygon_count += LWO_GuageDial.num_pnts/3;
494 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
495 glCallList(pp->guagehead);
496 mi->polygon_count += LWO_GuageHead.num_pnts/3;
498 /* GuageFace is drawn last, in case of low-res depth buffers. */
499 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
500 glCallList(pp->guageface);
501 mi->polygon_count += LWO_GuageFace.num_pnts/3;
503 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
511 build_teapot(ModeInfo *mi)
513 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
514 GLuint list = glGenLists(1);
516 glNewList(list, GL_COMPILE);
517 pp->teapot_polys = unit_teapot (12, MI_IS_WIREFRAME(mi));
524 MakeTeapot(ModeInfo * mi, int newdir)
526 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
531 glRotatef(90.0, 1.0, 0.0, 0.0);
532 glRotatef(NRAND(3) * 90.0, 0.0, 0.0, 1.0);
536 glRotatef(90.0, 0.0, -1.0, 0.0);
537 glRotatef((NRAND(3) * 90.0) - 90.0, 0.0, 0.0, 1.0);
541 glRotatef(NRAND(4) * 90.0, 0.0, 0.0, 1.0);
545 glCallList(pp->teapot);
546 mi->polygon_count += pp->teapot_polys;
552 MakeShape(ModeInfo * mi, int newdir)
556 if (!MakeGuage(mi, newdir))
557 MakeTube(mi, newdir);
559 MakeValve(mi, newdir);
561 MakeTeapot(mi,newdir);
566 pinit(ModeInfo * mi, int zera)
568 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
572 pp->system_number = 1;
573 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
574 (void) memset(pp->Cells, 0, sizeof (pp->Cells));
575 for (X = 0; X < HCELLS; X++) {
576 for (Y = 0; Y < VCELLS; Y++) {
577 pp->Cells[X][Y][0] = 1;
578 pp->Cells[X][Y][HCELLS - 1] = 1;
579 pp->Cells[0][Y][X] = 1;
580 pp->Cells[HCELLS - 1][Y][X] = 1;
583 for (X = 0; X < HCELLS; X++) {
584 for (Z = 0; Z < HCELLS; Z++) {
585 pp->Cells[X][0][Z] = 1;
586 pp->Cells[X][VCELLS - 1][Z] = 1;
589 (void) memset(pp->usedcolors, 0, sizeof (pp->usedcolors));
594 if (!MI_IS_MONO(mi)) {
595 int collist[DEFINEDCOLORS];
596 int i, j, lower = 1000;
598 /* Avoid repeating colors on the same screen unless necessary */
599 for (i = 0; i < DEFINEDCOLORS; i++) {
600 if (lower > pp->usedcolors[i])
601 lower = pp->usedcolors[i];
603 for (i = 0, j = 0; i < DEFINEDCOLORS; i++) {
604 if (pp->usedcolors[i] == lower) {
609 i = collist[NRAND(j)];
613 pp->system_color = MaterialRed;
616 pp->system_color = MaterialGreen;
619 pp->system_color = MaterialBlue;
622 pp->system_color = MaterialCyan;
625 pp->system_color = MaterialYellow;
628 pp->system_color = MaterialMagenta;
631 pp->system_color = MaterialWhite;
635 pp->system_color = MaterialGray;
639 pp->PX = NRAND((HCELLS - 1)) + 1;
640 pp->PY = NRAND((VCELLS - 1)) + 1;
641 pp->PZ = NRAND((HCELLS - 1)) + 1;
642 } while (pp->Cells[pp->PX][pp->PY][pp->PZ] ||
643 (pp->Cells[pp->PX + 1][pp->PY][pp->PZ] && pp->Cells[pp->PX - 1][pp->PY][pp->PZ] &&
644 pp->Cells[pp->PX][pp->PY + 1][pp->PZ] && pp->Cells[pp->PX][pp->PY - 1][pp->PZ] &&
645 pp->Cells[pp->PX][pp->PY][pp->PZ + 1] && pp->Cells[pp->PX][pp->PY][pp->PZ - 1]));
646 pp->Cells[pp->PX][pp->PY][pp->PZ] = 1;
647 pp->olddir = dirNone;
651 pp->nowdir = SelectNeighbor(mi);
656 reshape_pipes(ModeInfo * mi, int width, int height)
658 glViewport(0, 0, width, (GLint) height);
659 glMatrixMode(GL_PROJECTION);
661 /*glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0); */
662 gluPerspective(65.0, (GLfloat) width / (GLfloat) height, 0.1, 20.0);
663 glMatrixMode(GL_MODELVIEW);
665 glClear(GL_COLOR_BUFFER_BIT);
669 pipes_handle_event (ModeInfo *mi, XEvent *event)
671 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
673 if (gltrackball_event_handler (event, pp->trackball,
674 MI_WIDTH (mi), MI_HEIGHT (mi),
677 else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
688 static void generate_system (ModeInfo *);
692 init_pipes (ModeInfo * mi)
694 int screen = MI_SCREEN(mi);
698 if ((pipes = (pipesstruct *) calloc(MI_NUM_SCREENS(mi),
699 sizeof (pipesstruct))) == NULL)
704 pp->window = MI_WINDOW(mi);
705 if ((pp->glx_context = init_GL(mi)) != NULL) {
707 reshape_pipes(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
709 pp->initial_rotation = NRAND(180); /* jwz */
711 pp->initial_rotation = -10.0;
715 pp->valve = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_BigValve);
716 pp->bolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_Bolts3D);
717 pp->betweenbolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_PipeBetweenBolts);
719 pp->elbowbolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_ElbowBolts);
720 pp->elbowcoins = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_ElbowCoins);
722 pp->guagehead = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageHead);
723 pp->guageface = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageFace);
724 pp->guagedial = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageDial);
725 pp->guageconnector = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageConnector);
726 pp->teapot = build_teapot(mi);
728 /* else they are all 0, thanks to calloc(). */
730 if (MI_COUNT(mi) < 1 || MI_COUNT(mi) > NofSysTypes + 1) {
731 pp->system_type = NRAND(NofSysTypes) + 1;
733 pp->system_type = MI_COUNT(mi);
736 if (MI_CYCLES(mi) > 0 && MI_CYCLES(mi) < 11) {
737 pp->number_of_systems = MI_CYCLES(mi);
739 pp->number_of_systems = 5;
742 if (MI_SIZE(mi) < 10) {
743 pp->system_length = 10;
744 } else if (MI_SIZE(mi) > 1000) {
745 pp->system_length = 1000;
747 pp->system_length = MI_SIZE(mi);
753 pp->trackball = gltrackball_init (True);
754 generate_system (mi);
759 get_dlist (ModeInfo *mi, int i)
761 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
762 if (i >= pp->dlist_count)
765 if (pp->dlist_count >= pp->dlist_size)
767 int s2 = (pp->dlist_size + 100) * 1.2;
768 pp->dlists = (GLuint *)
769 realloc (pp->dlists, s2 * sizeof(*pp->dlists));
770 if (! pp->dlists) abort();
771 pp->poly_counts = (GLuint *)
772 realloc (pp->poly_counts, s2 * sizeof(*pp->poly_counts));
773 if (! pp->poly_counts) abort();
776 pp->dlists [i] = glGenLists (1);
777 pp->poly_counts [i] = 0;
779 return pp->dlists[i];
785 generate_system (ModeInfo * mi)
787 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
788 Bool wire = MI_IS_WIREFRAME(mi);
793 Bool reset_p = False;
795 pp->system_index = 0;
800 glNewList (get_dlist (mi, pp->system_size++), GL_COMPILE);
801 mi->polygon_count = 0;
808 glColor4fv (pp->system_color);
810 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
812 /* If it's the begining of a system, draw a sphere */
813 if (pp->olddir == dirNone) {
815 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
819 /* Check for stop conditions */
820 if (pp->ndirections == 0 || pp->counter > pp->system_length) {
822 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
823 /* Finish the system with another sphere */
828 /* If the maximum number of system was drawn, restart (clearing the screen), */
829 /* else start a new system. */
830 if (++pp->system_number > pp->number_of_systems) {
841 /* Do will the direction change? if so, determine the new one */
843 if (!pp->directions[newdir]) { /* cannot proceed in the current direction */
844 newdir = SelectNeighbor(mi);
847 /* random change (20% chance) */
848 if ((pp->counter > 1) && (NRAND(100) < 20)) {
849 newdir = SelectNeighbor(mi);
852 /* Chance to turn increases after each length of pipe drawn */
853 if ((pp->counter > 1) && NRAND(50) < NRAND(pp->turncounter + 1)) {
854 newdir = SelectNeighbor(mi);
860 /* Has the direction changed? */
861 if (newdir == pp->nowdir) {
862 /* If not, draw the cell's center pipe */
864 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
865 /* Chance of factory shape here, if enabled. */
866 if ((pp->counter > 1) && (NRAND(100) < factory)) {
867 MakeShape(mi, newdir);
869 MakeTube(mi, newdir);
873 /* If so, draw the cell's center elbow/sphere */
874 int sysT = pp->system_type;
876 if (sysT == NofSysTypes + 1) {
877 sysT = ((pp->system_number - 1) % NofSysTypes) + 1;
883 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
884 mySphere(elbowradius, wire);
888 switch (pp->nowdir) {
892 glTranslatef((pp->PX - 16) / 3.0 * 4.0 - (one_third), (pp->PY - 12) / 3.0 * 4.0 - (one_third), (pp->PZ - 16) / 3.0 * 4.0);
893 glRotatef(180.0, 1.0, 0.0, 0.0);
896 glTranslatef((pp->PX - 16) / 3.0 * 4.0 + (one_third), (pp->PY - 12) / 3.0 * 4.0 - (one_third), (pp->PZ - 16) / 3.0 * 4.0);
897 glRotatef(180.0, 1.0, 0.0, 0.0);
898 glRotatef(180.0, 0.0, 1.0, 0.0);
901 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0 - (one_third), (pp->PZ - 16) / 3.0 * 4.0 - (one_third));
902 glRotatef(90.0, 0.0, 1.0, 0.0);
903 glRotatef(180.0, 0.0, 0.0, 1.0);
906 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0 - (one_third), (pp->PZ - 16) / 3.0 * 4.0 + (one_third));
907 glRotatef(90.0, 0.0, 1.0, 0.0);
908 glRotatef(180.0, 1.0, 0.0, 0.0);
915 glTranslatef((pp->PX - 16) / 3.0 * 4.0 - (one_third), (pp->PY - 12) / 3.0 * 4.0 + (one_third), (pp->PZ - 16) / 3.0 * 4.0);
918 glTranslatef((pp->PX - 16) / 3.0 * 4.0 + (one_third), (pp->PY - 12) / 3.0 * 4.0 + (one_third), (pp->PZ - 16) / 3.0 * 4.0);
919 glRotatef(180.0, 0.0, 1.0, 0.0);
922 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0 + (one_third), (pp->PZ - 16) / 3.0 * 4.0 - (one_third));
923 glRotatef(270.0, 0.0, 1.0, 0.0);
926 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0 + (one_third), (pp->PZ - 16) / 3.0 * 4.0 + (one_third));
927 glRotatef(90.0, 0.0, 1.0, 0.0);
934 glTranslatef((pp->PX - 16) / 3.0 * 4.0 + (one_third), (pp->PY - 12) / 3.0 * 4.0 + (one_third), (pp->PZ - 16) / 3.0 * 4.0);
935 glRotatef(180.0, 0.0, 1.0, 0.0);
938 glTranslatef((pp->PX - 16) / 3.0 * 4.0 + (one_third), (pp->PY - 12) / 3.0 * 4.0 - (one_third), (pp->PZ - 16) / 3.0 * 4.0);
939 glRotatef(180.0, 1.0, 0.0, 0.0);
940 glRotatef(180.0, 0.0, 1.0, 0.0);
943 glTranslatef((pp->PX - 16) / 3.0 * 4.0 + (one_third), (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0 - (one_third));
944 glRotatef(270.0, 1.0, 0.0, 0.0);
945 glRotatef(180.0, 0.0, 1.0, 0.0);
948 glTranslatef((pp->PX - 16) / 3.0 * 4.0 + (one_third), (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0 + (one_third));
949 glRotatef(270.0, 1.0, 0.0, 0.0);
950 glRotatef(180.0, 0.0, 0.0, 1.0);
957 glTranslatef((pp->PX - 16) / 3.0 * 4.0 - (one_third), (pp->PY - 12) / 3.0 * 4.0 + (one_third), (pp->PZ - 16) / 3.0 * 4.0);
960 glTranslatef((pp->PX - 16) / 3.0 * 4.0 - (one_third), (pp->PY - 12) / 3.0 * 4.0 - (one_third), (pp->PZ - 16) / 3.0 * 4.0);
961 glRotatef(180.0, 1.0, 0.0, 0.0);
964 glTranslatef((pp->PX - 16) / 3.0 * 4.0 - (one_third), (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0 - (one_third));
965 glRotatef(270.0, 1.0, 0.0, 0.0);
968 glTranslatef((pp->PX - 16) / 3.0 * 4.0 - (one_third), (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0 + (one_third));
969 glRotatef(90.0, 1.0, 0.0, 0.0);
976 glTranslatef((pp->PX - 16) / 3.0 * 4.0 - (one_third), (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0 - (one_third));
977 glRotatef(270.0, 1.0, 0.0, 0.0);
980 glTranslatef((pp->PX - 16) / 3.0 * 4.0 + (one_third), (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0 - (one_third));
981 glRotatef(270.0, 1.0, 0.0, 0.0);
982 glRotatef(180.0, 0.0, 1.0, 0.0);
985 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0 + (one_third), (pp->PZ - 16) / 3.0 * 4.0 - (one_third));
986 glRotatef(270.0, 0.0, 1.0, 0.0);
989 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0 - (one_third), (pp->PZ - 16) / 3.0 * 4.0 - (one_third));
990 glRotatef(90.0, 0.0, 1.0, 0.0);
991 glRotatef(180.0, 0.0, 0.0, 1.0);
998 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0 + (one_third), (pp->PZ - 16) / 3.0 * 4.0 + (one_third));
999 glRotatef(90.0, 0.0, 1.0, 0.0);
1002 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0 - (one_third), (pp->PZ - 16) / 3.0 * 4.0 + (one_third));
1003 glRotatef(90.0, 0.0, 1.0, 0.0);
1004 glRotatef(180.0, 1.0, 0.0, 0.0);
1007 glTranslatef((pp->PX - 16) / 3.0 * 4.0 - (one_third), (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0 + (one_third));
1008 glRotatef(90.0, 1.0, 0.0, 0.0);
1011 glTranslatef((pp->PX - 16) / 3.0 * 4.0 + (one_third), (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0 + (one_third));
1012 glRotatef(270.0, 1.0, 0.0, 0.0);
1013 glRotatef(180.0, 0.0, 0.0, 1.0);
1018 myElbow(mi, (sysT == 2));
1027 pp->olddir = pp->nowdir;
1028 pp->nowdir = newdir;
1029 switch (pp->nowdir) {
1049 pp->Cells[pp->PX][pp->PY][pp->PZ] = 1;
1051 /* Cells'face pipe */
1052 glTranslatef(((pp->PX + OPX) / 2.0 - 16) / 3.0 * 4.0, ((pp->PY + OPY) / 2.0 - 12) / 3.0 * 4.0, ((pp->PZ + OPZ) / 2.0 - 16) / 3.0 * 4.0);
1053 MakeTube(mi, newdir);
1058 pp->poly_counts [pp->system_size-1] = mi->polygon_count;
1067 draw_pipes (ModeInfo * mi)
1069 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
1070 Display *display = MI_DISPLAY(mi);
1071 Window window = MI_WINDOW(mi);
1072 Bool wire = MI_IS_WIREFRAME(mi);
1075 if (!pp->glx_context)
1078 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(pp->glx_context));
1079 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1081 glColor3f(1.0, 1.0, 1.0);
1083 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);
1084 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);
1085 glLightfv(GL_LIGHT0, GL_POSITION, position0);
1086 glLightfv(GL_LIGHT1, GL_AMBIENT, ambient1);
1087 glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse1);
1088 glLightfv(GL_LIGHT1, GL_POSITION, position1);
1089 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
1090 glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
1093 glDisable(GL_LIGHTING);
1096 glEnable(GL_LIGHTING);
1097 glEnable(GL_LIGHT0);
1098 /* This looks crappy. */
1099 /* glEnable(GL_LIGHT1); */
1100 glEnable(GL_DEPTH_TEST);
1101 glEnable(GL_NORMALIZE);
1102 glEnable(GL_CULL_FACE);
1105 glShadeModel(GL_SMOOTH);
1106 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
1107 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
1111 pp->initial_rotation += 0.02;
1113 glTranslatef(0.0, 0.0, fisheye ? -3.8 : -4.8);
1115 gltrackball_rotate (pp->trackball);
1118 glRotatef(pp->initial_rotation, 0.0, 1.0, 0.0);
1120 glScalef(Scale4Window, Scale4Window, Scale4Window);
1122 mi->polygon_count = 0;
1126 GLfloat s = (pp->fadeout * pp->fadeout) / 10000.0;
1128 glRotatef (90 * (1 - (pp->fadeout/100.0)), 1, 0, 0.1);
1130 if (pp->fadeout <= 0)
1133 generate_system (mi);
1136 else if (pp->system_index < pp->system_size)
1141 for (i = 0; i < pp->system_index; i++)
1143 glCallList (pp->dlists[i]);
1144 mi->polygon_count += pp->poly_counts[i];
1149 if (mi->fps_p) do_fps (mi);
1152 glXSwapBuffers(display, window);
1158 change_pipes (ModeInfo * mi)
1160 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
1162 if (!pp->glx_context)
1165 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(pp->glx_context));
1168 #endif /* !STANDALONE */
1172 release_pipes (ModeInfo * mi)
1174 if (pipes != NULL) {
1177 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1178 pipesstruct *pp = &pipes[screen];
1180 if (pp->glx_context) {
1182 /* Display lists MUST be freed while their glXContext is current. */
1183 glXMakeCurrent(MI_DISPLAY(mi), pp->window, *(pp->glx_context));
1186 glDeleteLists(pp->valve, 1);
1188 glDeleteLists(pp->bolts, 1);
1189 if (pp->betweenbolts)
1190 glDeleteLists(pp->betweenbolts, 1);
1193 glDeleteLists(pp->elbowbolts, 1);
1195 glDeleteLists(pp->elbowcoins, 1);
1198 glDeleteLists(pp->guagehead, 1);
1200 glDeleteLists(pp->guageface, 1);
1202 glDeleteLists(pp->guagedial, 1);
1203 if (pp->guageconnector)
1204 glDeleteLists(pp->guageconnector, 1);
1206 glDeleteLists(pp->teapot, 1);
1210 for (i = 0; i < pp->dlist_count; i++)
1211 glDeleteLists (pp->dlists[i], 1);
1213 free (pp->poly_counts);
1218 (void) free((void *) pipes);
1224 XSCREENSAVER_MODULE ("Pipes", pipes)