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 release_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", NULL,
137 "change_pipes", "free_pipes", &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 double h = (GLfloat) height / (GLfloat) width;
661 if (width > height * 5) { /* tiny window: show middle */
662 height = width * 9/16;
664 h = height / (GLfloat) width;
666 glViewport(0, y, width, (GLint) height);
667 glMatrixMode(GL_PROJECTION);
669 /*glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0); */
670 gluPerspective(65.0, 1/h, 0.1, 20.0);
671 glMatrixMode(GL_MODELVIEW);
673 glClear(GL_COLOR_BUFFER_BIT);
677 pipes_handle_event (ModeInfo *mi, XEvent *event)
679 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
681 if (gltrackball_event_handler (event, pp->trackball,
682 MI_WIDTH (mi), MI_HEIGHT (mi),
685 else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event))
696 static void generate_system (ModeInfo *);
700 init_pipes (ModeInfo * mi)
702 int screen = MI_SCREEN(mi);
708 pp->window = MI_WINDOW(mi);
709 if ((pp->glx_context = init_GL(mi)) != NULL) {
711 reshape_pipes(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
713 pp->initial_rotation = NRAND(180); /* jwz */
715 pp->initial_rotation = -10.0;
719 pp->valve = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_BigValve);
720 pp->bolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_Bolts3D);
721 pp->betweenbolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_PipeBetweenBolts);
723 pp->elbowbolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_ElbowBolts);
724 pp->elbowcoins = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_ElbowCoins);
726 pp->guagehead = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageHead);
727 pp->guageface = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageFace);
728 pp->guagedial = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageDial);
729 pp->guageconnector = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageConnector);
730 pp->teapot = build_teapot(mi);
732 /* else they are all 0, thanks to calloc(). */
734 if (MI_COUNT(mi) < 1 || MI_COUNT(mi) > NofSysTypes + 1) {
735 pp->system_type = NRAND(NofSysTypes) + 1;
737 pp->system_type = MI_COUNT(mi);
740 if (MI_CYCLES(mi) > 0 && MI_CYCLES(mi) < 11) {
741 pp->number_of_systems = MI_CYCLES(mi);
743 pp->number_of_systems = 5;
746 if (MI_SIZE(mi) < 10) {
747 pp->system_length = 10;
748 } else if (MI_SIZE(mi) > 1000) {
749 pp->system_length = 1000;
751 pp->system_length = MI_SIZE(mi);
757 pp->trackball = gltrackball_init (True);
758 generate_system (mi);
763 get_dlist (ModeInfo *mi, int i)
765 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
766 if (i >= pp->dlist_count)
769 if (pp->dlist_count >= pp->dlist_size)
771 int s2 = (pp->dlist_size + 100) * 1.2;
772 pp->dlists = (GLuint *)
773 realloc (pp->dlists, s2 * sizeof(*pp->dlists));
774 if (! pp->dlists) abort();
775 pp->poly_counts = (GLuint *)
776 realloc (pp->poly_counts, s2 * sizeof(*pp->poly_counts));
777 if (! pp->poly_counts) abort();
780 pp->dlists [i] = glGenLists (1);
781 pp->poly_counts [i] = 0;
783 return pp->dlists[i];
789 generate_system (ModeInfo * mi)
791 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
792 Bool wire = MI_IS_WIREFRAME(mi);
797 Bool reset_p = False;
799 pp->system_index = 0;
804 glNewList (get_dlist (mi, pp->system_size++), GL_COMPILE);
805 mi->polygon_count = 0;
812 glColor4fv (pp->system_color);
814 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
816 /* If it's the begining of a system, draw a sphere */
817 if (pp->olddir == dirNone) {
819 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
823 /* Check for stop conditions */
824 if (pp->ndirections == 0 || pp->counter > pp->system_length) {
826 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
827 /* Finish the system with another sphere */
832 /* If the maximum number of system was drawn, restart (clearing the screen), */
833 /* else start a new system. */
834 if (++pp->system_number > pp->number_of_systems) {
845 /* Do will the direction change? if so, determine the new one */
847 if (!pp->directions[newdir]) { /* cannot proceed in the current direction */
848 newdir = SelectNeighbor(mi);
851 /* random change (20% chance) */
852 if ((pp->counter > 1) && (NRAND(100) < 20)) {
853 newdir = SelectNeighbor(mi);
856 /* Chance to turn increases after each length of pipe drawn */
857 if ((pp->counter > 1) && NRAND(50) < NRAND(pp->turncounter + 1)) {
858 newdir = SelectNeighbor(mi);
864 /* Has the direction changed? */
865 if (newdir == pp->nowdir) {
866 /* If not, draw the cell's center pipe */
868 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
869 /* Chance of factory shape here, if enabled. */
870 if ((pp->counter > 1) && (NRAND(100) < factory)) {
871 MakeShape(mi, newdir);
873 MakeTube(mi, newdir);
877 /* If so, draw the cell's center elbow/sphere */
878 int sysT = pp->system_type;
880 if (sysT == NofSysTypes + 1) {
881 sysT = ((pp->system_number - 1) % NofSysTypes) + 1;
887 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
888 mySphere(elbowradius, wire);
892 switch (pp->nowdir) {
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);
900 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);
901 glRotatef(180.0, 1.0, 0.0, 0.0);
902 glRotatef(180.0, 0.0, 1.0, 0.0);
905 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));
906 glRotatef(90.0, 0.0, 1.0, 0.0);
907 glRotatef(180.0, 0.0, 0.0, 1.0);
910 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));
911 glRotatef(90.0, 0.0, 1.0, 0.0);
912 glRotatef(180.0, 1.0, 0.0, 0.0);
919 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);
922 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);
923 glRotatef(180.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(270.0, 0.0, 1.0, 0.0);
930 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));
931 glRotatef(90.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, 0.0, 1.0, 0.0);
942 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);
943 glRotatef(180.0, 1.0, 0.0, 0.0);
944 glRotatef(180.0, 0.0, 1.0, 0.0);
947 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));
948 glRotatef(270.0, 1.0, 0.0, 0.0);
949 glRotatef(180.0, 0.0, 1.0, 0.0);
952 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));
953 glRotatef(270.0, 1.0, 0.0, 0.0);
954 glRotatef(180.0, 0.0, 0.0, 1.0);
961 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);
964 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);
965 glRotatef(180.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(270.0, 1.0, 0.0, 0.0);
972 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));
973 glRotatef(90.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);
984 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));
985 glRotatef(270.0, 1.0, 0.0, 0.0);
986 glRotatef(180.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(270.0, 0.0, 1.0, 0.0);
993 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));
994 glRotatef(90.0, 0.0, 1.0, 0.0);
995 glRotatef(180.0, 0.0, 0.0, 1.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);
1006 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));
1007 glRotatef(90.0, 0.0, 1.0, 0.0);
1008 glRotatef(180.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(90.0, 1.0, 0.0, 0.0);
1015 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));
1016 glRotatef(270.0, 1.0, 0.0, 0.0);
1017 glRotatef(180.0, 0.0, 0.0, 1.0);
1022 myElbow(mi, (sysT == 2));
1031 pp->olddir = pp->nowdir;
1032 pp->nowdir = newdir;
1033 switch (pp->nowdir) {
1053 pp->Cells[pp->PX][pp->PY][pp->PZ] = 1;
1055 /* Cells'face pipe */
1056 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);
1057 MakeTube(mi, newdir);
1062 pp->poly_counts [pp->system_size-1] = mi->polygon_count;
1071 draw_pipes (ModeInfo * mi)
1073 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
1074 Display *display = MI_DISPLAY(mi);
1075 Window window = MI_WINDOW(mi);
1076 Bool wire = MI_IS_WIREFRAME(mi);
1079 if (!pp->glx_context)
1082 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(pp->glx_context));
1083 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1085 glColor3f(1.0, 1.0, 1.0);
1087 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);
1088 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);
1089 glLightfv(GL_LIGHT0, GL_POSITION, position0);
1090 glLightfv(GL_LIGHT1, GL_AMBIENT, ambient1);
1091 glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse1);
1092 glLightfv(GL_LIGHT1, GL_POSITION, position1);
1093 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
1094 glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
1097 glDisable(GL_LIGHTING);
1100 glEnable(GL_LIGHTING);
1101 glEnable(GL_LIGHT0);
1102 /* This looks crappy. */
1103 /* glEnable(GL_LIGHT1); */
1104 glEnable(GL_DEPTH_TEST);
1105 glEnable(GL_NORMALIZE);
1106 glEnable(GL_CULL_FACE);
1109 glShadeModel(GL_SMOOTH);
1110 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
1111 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
1115 pp->initial_rotation += 0.02;
1117 glTranslatef(0.0, 0.0, fisheye ? -3.8 : -4.8);
1119 gltrackball_rotate (pp->trackball);
1122 glRotatef(pp->initial_rotation, 0.0, 1.0, 0.0);
1124 glScalef(Scale4Window, Scale4Window, Scale4Window);
1126 mi->polygon_count = 0;
1130 GLfloat s = (pp->fadeout * pp->fadeout) / 10000.0;
1132 glRotatef (90 * (1 - (pp->fadeout/100.0)), 1, 0, 0.1);
1134 if (pp->fadeout <= 0)
1137 generate_system (mi);
1140 else if (pp->system_index < pp->system_size)
1145 for (i = 0; i < pp->system_index; i++)
1147 glCallList (pp->dlists[i]);
1148 mi->polygon_count += pp->poly_counts[i];
1153 if (mi->fps_p) do_fps (mi);
1156 glXSwapBuffers(display, window);
1162 change_pipes (ModeInfo * mi)
1164 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
1166 if (!pp->glx_context)
1169 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(pp->glx_context));
1172 #endif /* !STANDALONE */
1176 free_pipes (ModeInfo * mi)
1178 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
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 XSCREENSAVER_MODULE ("Pipes", pipes)