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"
70 # define refresh_pipes 0
71 # include "xlockmore.h" /* from the xscreensaver distribution */
72 #else /* !STANDALONE */
73 # include "xlock.h" /* from the xlockmore distribution */
74 #endif /* !STANDALONE */
81 # include <X11/Xlib.h>
88 #endif /* HAVE_JWZGLES */
93 #include "gltrackball.h"
95 #define DEF_FACTORY "2"
96 #define DEF_FISHEYE "True"
97 #define DEF_TIGHTTURNS "False"
98 #define DEF_ROTATEPIPES "True"
102 static Bool fisheye, tightturns, rotatepipes;
104 static XrmOptionDescRec opts[] =
106 {"-factory", ".pipes.factory", XrmoptionSepArg, 0},
107 {"-fisheye", ".pipes.fisheye", XrmoptionNoArg, "on"},
108 {"+fisheye", ".pipes.fisheye", XrmoptionNoArg, "off"},
109 {"-tightturns", ".pipes.tightturns", XrmoptionNoArg, "on"},
110 {"+tightturns", ".pipes.tightturns", XrmoptionNoArg, "off"},
111 {"-rotatepipes", ".pipes.rotatepipes", XrmoptionNoArg, "on"},
112 {"+rotatepipes", ".pipes.rotatepipes", XrmoptionNoArg, "off"},
114 static argtype vars[] =
116 {&factory, "factory", "Factory", DEF_FACTORY, t_Int},
117 {&fisheye, "fisheye", "Fisheye", DEF_FISHEYE, t_Bool},
118 {&tightturns, "tightturns", "Tightturns", DEF_TIGHTTURNS, t_Bool},
119 {&rotatepipes, "rotatepipes", "Rotatepipes", DEF_ROTATEPIPES, t_Bool},
121 static OptionStruct desc[] =
123 {"-factory num", "how much extra equipment in pipes (0 for none)"},
124 {"-/+fisheye", "turn on/off zoomed-in view of pipes"},
125 {"-/+tightturns", "turn on/off tight turns"},
126 {"-/+rotatepipes", "turn on/off pipe system rotation per screenful"},
129 ENTRYPOINT ModeSpecOpt pipes_opts =
130 {sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
133 ModStruct pipes_description =
134 {"pipes", "init_pipes", "draw_pipes", "release_pipes",
136 "change_pipes", NULL, &pipes_opts,
137 1000, 2, 5, 500, 4, 1.0, "",
138 "Shows a selfbuilding pipe system", 0, NULL};
142 #define Scale4Window 0.1
144 #define one_third 0.3333333333333333333
156 #define DEFINEDCOLORS 7
157 #define elbowradius 0.5
159 /*************************************************************************/
164 int Cells[HCELLS][VCELLS][HCELLS];
165 int usedcolors[DEFINEDCOLORS];
172 int number_of_systems;
177 const float *system_color;
178 GLfloat initial_rotation;
179 GLuint valve, bolts, betweenbolts, elbowbolts, elbowcoins;
180 GLuint guagehead, guageface, guagedial, guageconnector, teapot;
182 GLXContext *glx_context;
185 trackball_state *trackball;
186 GLuint *dlists, *poly_counts;
187 int dlist_count, dlist_size;
188 int system_index, system_size;
194 extern struct lwo LWO_BigValve, LWO_PipeBetweenBolts, LWO_Bolts3D;
195 extern struct lwo LWO_GuageHead, LWO_GuageFace, LWO_GuageDial, LWO_GuageConnector;
196 extern struct lwo LWO_ElbowBolts, LWO_ElbowCoins;
198 static const float front_shininess[] = {60.0};
199 static const float front_specular[] = {0.7, 0.7, 0.7, 1.0};
200 static const float ambient0[] = {0.4, 0.4, 0.4, 1.0};
201 static const float diffuse0[] = {1.0, 1.0, 1.0, 1.0};
202 static const float ambient1[] = {0.2, 0.2, 0.2, 1.0};
203 static const float diffuse1[] = {0.5, 0.5, 0.5, 1.0};
204 static const float position0[] = {1.0, 1.0, 1.0, 0.0};
205 static const float position1[] = {-1.0, -1.0, 1.0, 0.0};
206 static const float lmodel_ambient[] = {0.5, 0.5, 0.5, 1.0};
207 static const float lmodel_twoside[] = {GL_TRUE};
209 static const float MaterialRed[] = {0.7, 0.0, 0.0, 1.0};
210 static const float MaterialGreen[] = {0.1, 0.5, 0.2, 1.0};
211 static const float MaterialBlue[] = {0.0, 0.0, 0.7, 1.0};
212 static const float MaterialCyan[] = {0.2, 0.5, 0.7, 1.0};
213 static const float MaterialYellow[] = {0.7, 0.7, 0.0, 1.0};
214 static const float MaterialMagenta[] = {0.6, 0.2, 0.5, 1.0};
215 static const float MaterialWhite[] = {0.7, 0.7, 0.7, 1.0};
216 static const float MaterialGray[] = {0.2, 0.2, 0.2, 1.0};
218 static pipesstruct *pipes = NULL;
222 MakeTube(ModeInfo *mi, int direction)
224 Bool wire = MI_IS_WIREFRAME(mi);
226 float SINan_3, COSan_3;
227 int facets = (wire ? 5 : 24);
229 /*dirUP = 00000000 */
230 /*dirDOWN = 00000001 */
231 /*dirLEFT = 00000010 */
232 /*dirRIGHT = 00000011 */
233 /*dirNEAR = 00000100 */
234 /*dirFAR = 00000101 */
236 if (!(direction & 4)) {
237 glRotatef(90.0, (direction & 2) ? 0.0 : 1.0,
238 (direction & 2) ? 1.0 : 0.0, 0.0);
240 glBegin(wire ? GL_LINE_STRIP : GL_QUAD_STRIP);
241 for (an = 0.0; an <= 2.0 * M_PI; an += M_PI * 2 / facets) {
242 glNormal3f((COSan_3 = cos(an) / 3.0), (SINan_3 = sin(an) / 3.0), 0.0);
243 glVertex3f(COSan_3, SINan_3, one_third);
244 glVertex3f(COSan_3, SINan_3, -one_third);
251 mySphere(float radius, Bool wire)
254 GLUquadricObj *quadObj;
256 quadObj = gluNewQuadric();
257 gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
258 gluSphere(quadObj, radius, 16, 16);
259 gluDeleteQuadric(quadObj);
262 glScalef (radius, radius, radius);
263 glRotatef (90, 1, 0, 0);
264 unit_sphere (16, 16, wire);
270 myElbow(ModeInfo * mi, int bolted)
272 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
273 Bool wire = MI_IS_WIREFRAME(mi);
275 int nsides = (wire ? 6 : 25);
281 GLfloat p0[3], p1[3], p2[3], p3[3];
282 GLfloat n0[3], n1[3], n2[3], n3[3];
283 GLfloat COSphi, COSphi1, COStheta, COStheta1;
284 GLfloat _SINtheta, _SINtheta1;
286 for (i = 0; i <= rings / 4; i++) {
287 GLfloat theta, theta1;
289 theta = (GLfloat) i *2.0 * M_PI / rings;
291 theta1 = (GLfloat) (i + 1) * 2.0 * M_PI / rings;
292 for (j = 0; j < nsides; j++) {
295 phi = (GLfloat) j *2.0 * M_PI / nsides;
297 phi1 = (GLfloat) (j + 1) * 2.0 * M_PI / nsides;
299 p0[0] = (COStheta = cos(theta)) * (R + r * (COSphi = cos(phi)));
300 p0[1] = (_SINtheta = -sin(theta)) * (R + r * COSphi);
302 p1[0] = (COStheta1 = cos(theta1)) * (R + r * COSphi);
303 p1[1] = (_SINtheta1 = -sin(theta1)) * (R + r * COSphi);
305 p2[0] = COStheta1 * (R + r * (COSphi1 = cos(phi1)));
306 p2[1] = _SINtheta1 * (R + r * COSphi1);
308 p3[0] = COStheta * (R + r * COSphi1);
309 p3[1] = _SINtheta * (R + r * COSphi1);
311 n0[0] = COStheta * COSphi;
312 n0[1] = _SINtheta * COSphi;
314 n1[0] = COStheta1 * COSphi;
315 n1[1] = _SINtheta1 * COSphi;
317 n2[0] = COStheta1 * COSphi1;
318 n2[1] = _SINtheta1 * COSphi1;
320 n3[0] = COStheta * COSphi1;
321 n3[1] = _SINtheta * COSphi1;
323 p0[2] = p1[2] = r * (n0[2] = n1[2] = sin(phi));
324 p2[2] = p3[2] = r * (n2[2] = n3[2] = sin(phi1));
326 glBegin(wire ? GL_LINE_LOOP : GL_QUADS);
340 if (factory > 0 && bolted) {
341 /* Bolt the elbow onto the pipe system */
344 glRotatef(90.0, 0.0, 0.0, -1.0);
345 glRotatef(90.0, 0.0, 1.0, 0.0);
346 glTranslatef(0.0, one_third, one_third);
347 glCallList(pp->elbowcoins);
348 mi->polygon_count += LWO_ElbowCoins.num_pnts/3;
349 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
350 glCallList(pp->elbowbolts);
351 mi->polygon_count += LWO_ElbowBolts.num_pnts/3;
352 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
363 FindNeighbors(ModeInfo * mi)
365 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
368 pp->directions[dirUP] = (!pp->Cells[pp->PX][pp->PY + 1][pp->PZ]) ? 1 : 0;
369 pp->ndirections += pp->directions[dirUP];
370 pp->directions[dirDOWN] = (!pp->Cells[pp->PX][pp->PY - 1][pp->PZ]) ? 1 : 0;
371 pp->ndirections += pp->directions[dirDOWN];
372 pp->directions[dirLEFT] = (!pp->Cells[pp->PX - 1][pp->PY][pp->PZ]) ? 1 : 0;
373 pp->ndirections += pp->directions[dirLEFT];
374 pp->directions[dirRIGHT] = (!pp->Cells[pp->PX + 1][pp->PY][pp->PZ]) ? 1 : 0;
375 pp->ndirections += pp->directions[dirRIGHT];
376 pp->directions[dirFAR] = (!pp->Cells[pp->PX][pp->PY][pp->PZ - 1]) ? 1 : 0;
377 pp->ndirections += pp->directions[dirFAR];
378 pp->directions[dirNEAR] = (!pp->Cells[pp->PX][pp->PY][pp->PZ + 1]) ? 1 : 0;
379 pp->ndirections += pp->directions[dirNEAR];
383 SelectNeighbor(ModeInfo * mi)
385 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
389 for (i = 0, j = 0; i < 6; i++) {
390 if (pp->directions[i]) {
396 return dirlist[NRAND(pp->ndirections)];
400 MakeValve(ModeInfo * mi, int newdir)
402 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
404 /* There is a glPopMatrix() right after this subroutine returns. */
408 glRotatef(90.0, 1.0, 0.0, 0.0);
409 glRotatef(NRAND(3) * 90.0, 0.0, 0.0, 1.0);
413 glRotatef(90.0, 0.0, -1.0, 0.0);
414 glRotatef((NRAND(3) * 90.0) - 90.0, 0.0, 0.0, 1.0);
418 glRotatef(NRAND(4) * 90.0, 0.0, 0.0, 1.0);
422 glCallList(pp->betweenbolts);
423 mi->polygon_count += LWO_PipeBetweenBolts.num_pnts/3;
424 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
425 glCallList(pp->bolts);
426 mi->polygon_count += LWO_Bolts3D.num_pnts/3;
427 if (!MI_IS_MONO(mi)) {
428 if (pp->system_color == MaterialRed) {
429 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, NRAND(2) ? MaterialYellow : MaterialBlue);
430 } else if (pp->system_color == MaterialBlue) {
431 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, NRAND(2) ? MaterialRed : MaterialYellow);
432 } else if (pp->system_color == MaterialYellow) {
433 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, NRAND(2) ? MaterialBlue : MaterialRed);
435 switch ((NRAND(3))) {
437 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
440 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialBlue);
443 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialYellow);
447 glRotatef((GLfloat) (NRAND(90)), 1.0, 0.0, 0.0);
448 glCallList(pp->valve);
449 mi->polygon_count += LWO_BigValve.num_pnts/3;
450 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
455 MakeGuage(ModeInfo * mi, int newdir)
457 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
459 /* Can't have a guage on a vertical pipe. */
460 if ((newdir == dirUP) || (newdir == dirDOWN))
463 /* Is there space above this pipe for a guage? */
464 if (!pp->directions[dirUP])
467 /* Yes! Mark the space as used. */
468 pp->Cells[pp->PX][pp->PY + 1][pp->PZ] = 1;
472 if ((newdir == dirLEFT) || (newdir == dirRIGHT))
473 glRotatef(90.0, 0.0, 1.0, 0.0);
474 glCallList(pp->betweenbolts);
475 mi->polygon_count += LWO_PipeBetweenBolts.num_pnts/3;
476 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
477 glCallList(pp->bolts);
478 mi->polygon_count += LWO_Bolts3D.num_pnts/3;
481 glCallList(pp->guageconnector);
482 mi->polygon_count += LWO_GuageConnector.num_pnts/3;
484 glTranslatef(0.0, 1.33333, 0.0);
485 /* Do not change the above to 1 + ONE_THIRD, because */
486 /* the object really is centered on 1.3333300000. */
487 glRotatef(NRAND(270) + 45.0, 0.0, 0.0, -1.0);
488 /* Random rotation for the dial. I love it. */
489 glCallList(pp->guagedial);
490 mi->polygon_count += LWO_GuageDial.num_pnts/3;
493 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
494 glCallList(pp->guagehead);
495 mi->polygon_count += LWO_GuageHead.num_pnts/3;
497 /* GuageFace is drawn last, in case of low-res depth buffers. */
498 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
499 glCallList(pp->guageface);
500 mi->polygon_count += LWO_GuageFace.num_pnts/3;
502 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
510 build_teapot(ModeInfo *mi)
512 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
513 GLuint list = glGenLists(1);
515 glNewList(list, GL_COMPILE);
516 pp->teapot_polys = unit_teapot (12, MI_IS_WIREFRAME(mi));
523 MakeTeapot(ModeInfo * mi, int newdir)
525 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
530 glRotatef(90.0, 1.0, 0.0, 0.0);
531 glRotatef(NRAND(3) * 90.0, 0.0, 0.0, 1.0);
535 glRotatef(90.0, 0.0, -1.0, 0.0);
536 glRotatef((NRAND(3) * 90.0) - 90.0, 0.0, 0.0, 1.0);
540 glRotatef(NRAND(4) * 90.0, 0.0, 0.0, 1.0);
544 glCallList(pp->teapot);
545 mi->polygon_count += pp->teapot_polys;
551 MakeShape(ModeInfo * mi, int newdir)
555 if (!MakeGuage(mi, newdir))
556 MakeTube(mi, newdir);
558 MakeValve(mi, newdir);
560 MakeTeapot(mi,newdir);
565 pinit(ModeInfo * mi, int zera)
567 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
571 pp->system_number = 1;
572 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
573 (void) memset(pp->Cells, 0, sizeof (pp->Cells));
574 for (X = 0; X < HCELLS; X++) {
575 for (Y = 0; Y < VCELLS; Y++) {
576 pp->Cells[X][Y][0] = 1;
577 pp->Cells[X][Y][HCELLS - 1] = 1;
578 pp->Cells[0][Y][X] = 1;
579 pp->Cells[HCELLS - 1][Y][X] = 1;
582 for (X = 0; X < HCELLS; X++) {
583 for (Z = 0; Z < HCELLS; Z++) {
584 pp->Cells[X][0][Z] = 1;
585 pp->Cells[X][VCELLS - 1][Z] = 1;
588 (void) memset(pp->usedcolors, 0, sizeof (pp->usedcolors));
593 if (!MI_IS_MONO(mi)) {
594 int collist[DEFINEDCOLORS];
595 int i, j, lower = 1000;
597 /* Avoid repeating colors on the same screen unless necessary */
598 for (i = 0; i < DEFINEDCOLORS; i++) {
599 if (lower > pp->usedcolors[i])
600 lower = pp->usedcolors[i];
602 for (i = 0, j = 0; i < DEFINEDCOLORS; i++) {
603 if (pp->usedcolors[i] == lower) {
608 i = collist[NRAND(j)];
612 pp->system_color = MaterialRed;
615 pp->system_color = MaterialGreen;
618 pp->system_color = MaterialBlue;
621 pp->system_color = MaterialCyan;
624 pp->system_color = MaterialYellow;
627 pp->system_color = MaterialMagenta;
630 pp->system_color = MaterialWhite;
634 pp->system_color = MaterialGray;
638 pp->PX = NRAND((HCELLS - 1)) + 1;
639 pp->PY = NRAND((VCELLS - 1)) + 1;
640 pp->PZ = NRAND((HCELLS - 1)) + 1;
641 } while (pp->Cells[pp->PX][pp->PY][pp->PZ] ||
642 (pp->Cells[pp->PX + 1][pp->PY][pp->PZ] && pp->Cells[pp->PX - 1][pp->PY][pp->PZ] &&
643 pp->Cells[pp->PX][pp->PY + 1][pp->PZ] && pp->Cells[pp->PX][pp->PY - 1][pp->PZ] &&
644 pp->Cells[pp->PX][pp->PY][pp->PZ + 1] && pp->Cells[pp->PX][pp->PY][pp->PZ - 1]));
645 pp->Cells[pp->PX][pp->PY][pp->PZ] = 1;
646 pp->olddir = dirNone;
650 pp->nowdir = SelectNeighbor(mi);
655 reshape_pipes(ModeInfo * mi, int width, int height)
657 glViewport(0, 0, width, (GLint) height);
658 glMatrixMode(GL_PROJECTION);
660 /*glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0); */
661 gluPerspective(65.0, (GLfloat) width / (GLfloat) height, 0.1, 20.0);
662 glMatrixMode(GL_MODELVIEW);
664 glClear(GL_COLOR_BUFFER_BIT);
668 pipes_handle_event (ModeInfo *mi, XEvent *event)
670 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
672 if (event->xany.type == ButtonPress &&
673 event->xbutton.button == Button1)
675 pp->button_down_p = True;
676 gltrackball_start (pp->trackball,
677 event->xbutton.x, event->xbutton.y,
678 MI_WIDTH (mi), MI_HEIGHT (mi));
681 else if (event->xany.type == ButtonRelease &&
682 event->xbutton.button == Button1)
684 pp->button_down_p = False;
687 else if (event->xany.type == ButtonPress &&
688 (event->xbutton.button == Button4 ||
689 event->xbutton.button == Button5 ||
690 event->xbutton.button == Button6 ||
691 event->xbutton.button == Button7))
693 gltrackball_mousewheel (pp->trackball, event->xbutton.button, 10,
694 !!event->xbutton.state);
697 else if (event->xany.type == MotionNotify &&
700 gltrackball_track (pp->trackball,
701 event->xmotion.x, event->xmotion.y,
702 MI_WIDTH (mi), MI_HEIGHT (mi));
711 static void generate_system (ModeInfo *);
715 init_pipes (ModeInfo * mi)
717 int screen = MI_SCREEN(mi);
721 if ((pipes = (pipesstruct *) calloc(MI_NUM_SCREENS(mi),
722 sizeof (pipesstruct))) == NULL)
727 pp->window = MI_WINDOW(mi);
728 if ((pp->glx_context = init_GL(mi)) != NULL) {
730 reshape_pipes(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
732 pp->initial_rotation = NRAND(180); /* jwz */
734 pp->initial_rotation = -10.0;
738 pp->valve = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_BigValve);
739 pp->bolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_Bolts3D);
740 pp->betweenbolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_PipeBetweenBolts);
742 pp->elbowbolts = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_ElbowBolts);
743 pp->elbowcoins = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_ElbowCoins);
745 pp->guagehead = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageHead);
746 pp->guageface = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageFace);
747 pp->guagedial = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageDial);
748 pp->guageconnector = BuildLWO(MI_IS_WIREFRAME(mi), &LWO_GuageConnector);
749 pp->teapot = build_teapot(mi);
751 /* else they are all 0, thanks to calloc(). */
753 if (MI_COUNT(mi) < 1 || MI_COUNT(mi) > NofSysTypes + 1) {
754 pp->system_type = NRAND(NofSysTypes) + 1;
756 pp->system_type = MI_COUNT(mi);
759 if (MI_CYCLES(mi) > 0 && MI_CYCLES(mi) < 11) {
760 pp->number_of_systems = MI_CYCLES(mi);
762 pp->number_of_systems = 5;
765 if (MI_SIZE(mi) < 10) {
766 pp->system_length = 10;
767 } else if (MI_SIZE(mi) > 1000) {
768 pp->system_length = 1000;
770 pp->system_length = MI_SIZE(mi);
776 pp->trackball = gltrackball_init ();
777 generate_system (mi);
782 get_dlist (ModeInfo *mi, int i)
784 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
785 if (i >= pp->dlist_count)
788 if (pp->dlist_count >= pp->dlist_size)
790 int s2 = (pp->dlist_size + 100) * 1.2;
791 pp->dlists = (GLuint *)
792 realloc (pp->dlists, s2 * sizeof(*pp->dlists));
793 if (! pp->dlists) abort();
794 pp->poly_counts = (GLuint *)
795 realloc (pp->poly_counts, s2 * sizeof(*pp->poly_counts));
796 if (! pp->poly_counts) abort();
799 pp->dlists [i] = glGenLists (1);
800 pp->poly_counts [i] = 0;
802 return pp->dlists[i];
808 generate_system (ModeInfo * mi)
810 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
811 Bool wire = MI_IS_WIREFRAME(mi);
816 Bool reset_p = False;
818 pp->system_index = 0;
823 glNewList (get_dlist (mi, pp->system_size++), GL_COMPILE);
824 mi->polygon_count = 0;
831 glColor4fv (pp->system_color);
833 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
835 /* If it's the begining of a system, draw a sphere */
836 if (pp->olddir == dirNone) {
838 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
842 /* Check for stop conditions */
843 if (pp->ndirections == 0 || pp->counter > pp->system_length) {
845 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
846 /* Finish the system with another sphere */
851 /* If the maximum number of system was drawn, restart (clearing the screen), */
852 /* else start a new system. */
853 if (++pp->system_number > pp->number_of_systems) {
864 /* Do will the direction change? if so, determine the new one */
866 if (!pp->directions[newdir]) { /* cannot proceed in the current direction */
867 newdir = SelectNeighbor(mi);
870 /* random change (20% chance) */
871 if ((pp->counter > 1) && (NRAND(100) < 20)) {
872 newdir = SelectNeighbor(mi);
875 /* Chance to turn increases after each length of pipe drawn */
876 if ((pp->counter > 1) && NRAND(50) < NRAND(pp->turncounter + 1)) {
877 newdir = SelectNeighbor(mi);
883 /* Has the direction changed? */
884 if (newdir == pp->nowdir) {
885 /* If not, draw the cell's center pipe */
887 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
888 /* Chance of factory shape here, if enabled. */
889 if ((pp->counter > 1) && (NRAND(100) < factory)) {
890 MakeShape(mi, newdir);
892 MakeTube(mi, newdir);
896 /* If so, draw the cell's center elbow/sphere */
897 int sysT = pp->system_type;
899 if (sysT == NofSysTypes + 1) {
900 sysT = ((pp->system_number - 1) % NofSysTypes) + 1;
906 glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
907 mySphere(elbowradius, wire);
911 switch (pp->nowdir) {
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);
916 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);
920 glRotatef(180.0, 1.0, 0.0, 0.0);
921 glRotatef(180.0, 0.0, 1.0, 0.0);
924 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));
925 glRotatef(90.0, 0.0, 1.0, 0.0);
926 glRotatef(180.0, 0.0, 0.0, 1.0);
929 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));
930 glRotatef(90.0, 0.0, 1.0, 0.0);
931 glRotatef(180.0, 1.0, 0.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);
941 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);
942 glRotatef(180.0, 0.0, 1.0, 0.0);
945 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));
946 glRotatef(270.0, 0.0, 1.0, 0.0);
949 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));
950 glRotatef(90.0, 0.0, 1.0, 0.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);
958 glRotatef(180.0, 0.0, 1.0, 0.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);
962 glRotatef(180.0, 1.0, 0.0, 0.0);
963 glRotatef(180.0, 0.0, 1.0, 0.0);
966 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));
967 glRotatef(270.0, 1.0, 0.0, 0.0);
968 glRotatef(180.0, 0.0, 1.0, 0.0);
971 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));
972 glRotatef(270.0, 1.0, 0.0, 0.0);
973 glRotatef(180.0, 0.0, 0.0, 1.0);
980 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);
983 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);
984 glRotatef(180.0, 1.0, 0.0, 0.0);
987 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));
988 glRotatef(270.0, 1.0, 0.0, 0.0);
991 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));
992 glRotatef(90.0, 1.0, 0.0, 0.0);
999 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));
1000 glRotatef(270.0, 1.0, 0.0, 0.0);
1003 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));
1004 glRotatef(270.0, 1.0, 0.0, 0.0);
1005 glRotatef(180.0, 0.0, 1.0, 0.0);
1008 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));
1009 glRotatef(270.0, 0.0, 1.0, 0.0);
1012 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));
1013 glRotatef(90.0, 0.0, 1.0, 0.0);
1014 glRotatef(180.0, 0.0, 0.0, 1.0);
1021 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));
1022 glRotatef(90.0, 0.0, 1.0, 0.0);
1025 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));
1026 glRotatef(90.0, 0.0, 1.0, 0.0);
1027 glRotatef(180.0, 1.0, 0.0, 0.0);
1030 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));
1031 glRotatef(90.0, 1.0, 0.0, 0.0);
1034 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));
1035 glRotatef(270.0, 1.0, 0.0, 0.0);
1036 glRotatef(180.0, 0.0, 0.0, 1.0);
1041 myElbow(mi, (sysT == 2));
1050 pp->olddir = pp->nowdir;
1051 pp->nowdir = newdir;
1052 switch (pp->nowdir) {
1072 pp->Cells[pp->PX][pp->PY][pp->PZ] = 1;
1074 /* Cells'face pipe */
1075 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);
1076 MakeTube(mi, newdir);
1081 pp->poly_counts [pp->system_size-1] = mi->polygon_count;
1090 draw_pipes (ModeInfo * mi)
1092 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
1093 Display *display = MI_DISPLAY(mi);
1094 Window window = MI_WINDOW(mi);
1095 Bool wire = MI_IS_WIREFRAME(mi);
1098 if (!pp->glx_context)
1101 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(pp->glx_context));
1102 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
1104 glColor3f(1.0, 1.0, 1.0);
1106 glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);
1107 glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);
1108 glLightfv(GL_LIGHT0, GL_POSITION, position0);
1109 glLightfv(GL_LIGHT1, GL_AMBIENT, ambient1);
1110 glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse1);
1111 glLightfv(GL_LIGHT1, GL_POSITION, position1);
1112 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
1113 glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
1116 glDisable(GL_LIGHTING);
1119 glEnable(GL_LIGHTING);
1120 glEnable(GL_LIGHT0);
1121 /* This looks crappy. */
1122 /* glEnable(GL_LIGHT1); */
1123 glEnable(GL_DEPTH_TEST);
1124 glEnable(GL_NORMALIZE);
1125 glEnable(GL_CULL_FACE);
1128 glShadeModel(GL_SMOOTH);
1129 glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
1130 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
1134 pp->initial_rotation += 0.02;
1136 glTranslatef(0.0, 0.0, fisheye ? -3.8 : -4.8);
1138 /* Do it twice because we don't track the device's orientation. */
1139 glRotatef( current_device_rotation(), 0, 0, 1);
1140 gltrackball_rotate (pp->trackball);
1141 glRotatef(-current_device_rotation(), 0, 0, 1);
1144 glRotatef(pp->initial_rotation, 0.0, 1.0, 0.0);
1146 glScalef(Scale4Window, Scale4Window, Scale4Window);
1148 mi->polygon_count = 0;
1152 GLfloat s = (pp->fadeout * pp->fadeout) / 10000.0;
1154 glRotatef (90 * (1 - (pp->fadeout/100.0)), 1, 0, 0.1);
1156 if (pp->fadeout <= 0)
1159 generate_system (mi);
1162 else if (pp->system_index < pp->system_size)
1167 for (i = 0; i < pp->system_index; i++)
1169 glCallList (pp->dlists[i]);
1170 mi->polygon_count += pp->poly_counts[i];
1175 if (mi->fps_p) do_fps (mi);
1178 glXSwapBuffers(display, window);
1184 change_pipes (ModeInfo * mi)
1186 pipesstruct *pp = &pipes[MI_SCREEN(mi)];
1188 if (!pp->glx_context)
1191 glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(pp->glx_context));
1194 #endif /* !STANDALONE */
1198 release_pipes (ModeInfo * mi)
1200 if (pipes != NULL) {
1203 for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
1204 pipesstruct *pp = &pipes[screen];
1206 if (pp->glx_context) {
1208 /* Display lists MUST be freed while their glXContext is current. */
1209 glXMakeCurrent(MI_DISPLAY(mi), pp->window, *(pp->glx_context));
1212 glDeleteLists(pp->valve, 1);
1214 glDeleteLists(pp->bolts, 1);
1215 if (pp->betweenbolts)
1216 glDeleteLists(pp->betweenbolts, 1);
1219 glDeleteLists(pp->elbowbolts, 1);
1221 glDeleteLists(pp->elbowcoins, 1);
1224 glDeleteLists(pp->guagehead, 1);
1226 glDeleteLists(pp->guageface, 1);
1228 glDeleteLists(pp->guagedial, 1);
1229 if (pp->guageconnector)
1230 glDeleteLists(pp->guageconnector, 1);
1232 glDeleteLists(pp->teapot, 1);
1236 for (i = 0; i < pp->dlist_count; i++)
1237 glDeleteLists (pp->dlists[i], 1);
1239 free (pp->poly_counts);
1244 (void) free((void *) pipes);
1250 XSCREENSAVER_MODULE ("Pipes", pipes)