xenocara/app/xlockmore/modes/glx/pipes.c
2006-11-26 11:07:42 +00:00

1083 lines
30 KiB
C

/* -*- Mode: C; tab-width: 4 -*- */
/* pipes --- 3D selfbuiding pipe system */
#if !defined( lint ) && !defined( SABER )
static const char sccsid[] = "@(#)pipes.c 5.00 2000/11/01 xlockmore";
#endif
/*-
* Permission to use, copy, modify, and distribute this software and its
* documentation for any purpose and without fee is hereby granted,
* provided that the above copyright notice appear in all copies and that
* both that copyright notice and this permission notice appear in
* supporting documentation.
*
* This file is provided AS IS with no warranties of any kind. The author
* shall have no liability with respect to the infringement of copyrights,
* trade secrets or any patents by this file or any part thereof. In no
* event will the author be liable for any lost revenue or profits or
* other special, indirect and consequential damages.
*
* This program was inspired on a WindowsNT(R)'s screen saver. It was written
* from scratch and it was not based on any other source code.
*
* ==========================================================================
* The routine myElbow is derivated from the doughnut routine from the MesaGL
* library (more especifically the Mesaaux library) written by Brian Paul.
* ==========================================================================
*
* Thanks goes to Brian Paul for making it possible and inexpensive to use
* OpenGL at home.
*
* Since I'm not a native English speaker, my apologies for any grammatical
* mistakes.
*
* My e-mail addresses is
* mfvianna@centroin.com.br
*
* Marcelo F. Vianna (Apr-09-1997)
*
* Revision History:
* 29-Apr-97: Factory equipment by Ed Mackey. Productive day today, eh?
* 29-Apr-97: Less tight turns Jeff Epler <jepler@inetnebr.com>
* 29-Apr-97: Efficiency speed-ups by Marcelo F. Vianna
*/
#ifdef VMS
/*-
* due to a Bug/feature in VMS X11/Intrinsic.h has to be placed before xlock.
* otherwise caddr_t is not defined correctly
*/
#include <X11/Intrinsic.h>
#endif
#ifdef STANDALONE
#define MODE_pipes
#define PROGCLASS "Pipes"
#define HACK_INIT init_pipes
#define HACK_DRAW draw_pipes
#define pipes_opts xlockmore_opts
#define DEFAULTS "*delay: 1000 \n" \
"*count: 2 \n" \
"*cycles: 5 \n" \
"*size: 500 \n" \
"*fisheye: True \n" \
"*tightturns: False \n" \
"*rotatepipes: True \n" \
"*noBuffer: True \n"
#include "xlockmore.h" /* from the xscreensaver distribution */
#else /* !STANDALONE */
#include "xlock.h" /* from the xlockmore distribution */
#include "vis.h"
#endif /* !STANDALONE */
#ifdef MODE_pipes
#include <GL/glu.h>
#include "buildlwo.h"
#define DEF_FACTORY "2"
#define DEF_FISHEYE "True"
#define DEF_TIGHTTURNS "False"
#define DEF_ROTATEPIPES "True"
#define NofSysTypes 3
static int factory;
static Bool fisheye, tightturns, rotatepipes;
static XrmOptionDescRec opts[] =
{
{(char *) "-factory", (char *) ".pipes.factory", XrmoptionSepArg, (caddr_t) NULL},
{(char *) "-fisheye", (char *) ".pipes.fisheye", XrmoptionNoArg, (caddr_t) "on"},
{(char *) "+fisheye", (char *) ".pipes.fisheye", XrmoptionNoArg, (caddr_t) "off"},
{(char *) "-tightturns", (char *) ".pipes.tightturns", XrmoptionNoArg, (caddr_t) "on"},
{(char *) "+tightturns", (char *) ".pipes.tightturns", XrmoptionNoArg, (caddr_t) "off"},
{(char *) "-rotatepipes", (char *) ".pipes.rotatepipes", XrmoptionNoArg, (caddr_t) "on"},
{(char *) "+rotatepipes", (char *) ".pipes.rotatepipes", XrmoptionNoArg, (caddr_t) "off"}
};
static argtype vars[] =
{
{(void *) & factory, (char *) "factory", (char *) "Factory", (char *) DEF_FACTORY, t_Int},
{(void *) & fisheye, (char *) "fisheye", (char *) "Fisheye", (char *) DEF_FISHEYE, t_Bool},
{(void *) & tightturns, (char *) "tightturns", (char *) "Tightturns", (char *) DEF_TIGHTTURNS, t_Bool},
{(void *) & rotatepipes, (char *) "rotatepipes", (char *) "Rotatepipes", (char *) DEF_ROTATEPIPES, t_Bool}
};
static OptionStruct desc[] =
{
{(char *) "-factory num", (char *) "how much extra equipment in pipes (0 for none)"},
{(char *) "-/+fisheye", (char *) "turn on/off zoomed-in view of pipes"},
{(char *) "-/+tightturns", (char *) "turn on/off tight turns"},
{(char *) "-/+rotatepipes", (char *) "turn on/off pipe system rotation per screenful"}
};
ModeSpecOpt pipes_opts =
{sizeof opts / sizeof opts[0], opts, sizeof vars / sizeof vars[0], vars, desc};
#ifdef USE_MODULES
ModStruct pipes_description =
{"pipes", "init_pipes", "draw_pipes", "release_pipes",
#if defined( MESA ) && defined( SLOW )
"draw_pipes",
#else
"change_pipes",
#endif
"change_pipes", (char *) NULL, &pipes_opts,
1000, 2, 5, 500, 4, 1.0, "",
"Shows a selfbuilding pipe system", 0, NULL};
#endif
#define Scale4Window 0.1
#define Scale4Iconic 0.07
#define one_third 0.3333333333333333333
#define dirNone -1
#define dirUP 0
#define dirDOWN 1
#define dirLEFT 2
#define dirRIGHT 3
#define dirNEAR 4
#define dirFAR 5
#define HCELLS 33
#define VCELLS 25
#define DEFINEDCOLORS 7
#define elbowradius 0.5
/*************************************************************************/
typedef struct {
#if defined( MESA ) && defined( SLOW )
int flip;
#endif
GLint WindH, WindW;
int Cells[HCELLS][VCELLS][HCELLS];
int usedcolors[DEFINEDCOLORS];
int directions[6];
int ndirections;
int nowdir, olddir;
int system_number;
int counter;
int PX, PY, PZ;
int number_of_systems;
int system_type;
int system_length;
int turncounter;
int factory;
Window window;
float *system_color;
GLfloat initial_rotation;
GLuint valve, bolts, betweenbolts, elbowbolts, elbowcoins;
GLuint guagehead, guageface, guagedial, guageconnector;
GLXContext *glx_context;
} pipesstruct;
extern struct lwo LWO_BigValve, LWO_PipeBetweenBolts, LWO_Bolts3D;
extern struct lwo LWO_GuageHead, LWO_GuageFace, LWO_GuageDial, LWO_GuageConnector;
extern struct lwo LWO_ElbowBolts, LWO_ElbowCoins;
static float front_shininess[] =
{60.0};
static float front_specular[] =
{0.7, 0.7, 0.7, 1.0};
static float ambient0[] =
{0.4, 0.4, 0.4, 1.0};
static float diffuse0[] =
{1.0, 1.0, 1.0, 1.0};
static float ambient1[] =
{0.2, 0.2, 0.2, 1.0};
static float diffuse1[] =
{0.5, 0.5, 0.5, 1.0};
static float position0[] =
{1.0, 1.0, 1.0, 0.0};
static float position1[] =
{-1.0, -1.0, 1.0, 0.0};
static float lmodel_ambient[] =
{0.5, 0.5, 0.5, 1.0};
static float lmodel_twoside[] =
{GL_TRUE};
static float MaterialRed[] =
{0.7, 0.0, 0.0, 1.0};
static float MaterialGreen[] =
{0.1, 0.5, 0.2, 1.0};
static float MaterialBlue[] =
{0.0, 0.0, 0.7, 1.0};
static float MaterialCyan[] =
{0.2, 0.5, 0.7, 1.0};
static float MaterialYellow[] =
{0.7, 0.7, 0.0, 1.0};
static float MaterialMagenta[] =
{0.6, 0.2, 0.5, 1.0};
static float MaterialWhite[] =
{0.7, 0.7, 0.7, 1.0};
static float MaterialGray[] =
{0.2, 0.2, 0.2, 1.0};
static pipesstruct *pipes = (pipesstruct *) NULL;
static void
MakeTube(int direction)
{
float an;
float SINan_3, COSan_3;
/*dirUP = 00000000 */
/*dirDOWN = 00000001 */
/*dirLEFT = 00000010 */
/*dirRIGHT = 00000011 */
/*dirNEAR = 00000100 */
/*dirFAR = 00000101 */
if (!(direction & 4)) {
glRotatef(90.0, (direction & 2) ? 0.0 : 1.0,
(direction & 2) ? 1.0 : 0.0, 0.0);
}
glBegin(GL_QUAD_STRIP);
for (an = 0.0; an <= 2.0 * M_PI; an += M_PI / 12.0) {
glNormal3f((COSan_3 = cos(an) / 3.0), (SINan_3 = sin(an) / 3.0), 0.0);
glVertex3f(COSan_3, SINan_3, one_third);
glVertex3f(COSan_3, SINan_3, -one_third);
}
glEnd();
}
static Bool
mySphere(float radius)
{
GLUquadricObj *quadObj;
if ((quadObj = gluNewQuadric()) == 0)
return False;
gluQuadricDrawStyle(quadObj, (GLenum) GLU_FILL);
gluSphere(quadObj, radius, 16, 16);
gluDeleteQuadric(quadObj);
return True;
}
static void
myElbow(ModeInfo * mi, int bolted)
{
#define nsides 25
#define rings 25
#define r one_third
#define R one_third
pipesstruct *pp = &pipes[MI_SCREEN(mi)];
int i, j;
GLfloat p0[3], p1[3], p2[3], p3[3];
GLfloat n0[3], n1[3], n2[3], n3[3];
GLfloat COSphi, COSphi1, COStheta, COStheta1;
GLfloat _SINtheta, _SINtheta1;
for (i = 0; i <= rings / 4; i++) {
GLfloat theta, theta1;
theta = (GLfloat) i *2.0 * M_PI / rings;
theta1 = (GLfloat) (i + 1) * 2.0 * M_PI / rings;
for (j = 0; j < nsides; j++) {
GLfloat phi, phi1;
phi = (GLfloat) j *2.0 * M_PI / nsides;
phi1 = (GLfloat) (j + 1) * 2.0 * M_PI / nsides;
p0[0] = (COStheta = cos(theta)) * (R + r * (COSphi = cos(phi)));
p0[1] = (_SINtheta = -sin(theta)) * (R + r * COSphi);
p1[0] = (COStheta1 = cos(theta1)) * (R + r * COSphi);
p1[1] = (_SINtheta1 = -sin(theta1)) * (R + r * COSphi);
p2[0] = COStheta1 * (R + r * (COSphi1 = cos(phi1)));
p2[1] = _SINtheta1 * (R + r * COSphi1);
p3[0] = COStheta * (R + r * COSphi1);
p3[1] = _SINtheta * (R + r * COSphi1);
n0[0] = COStheta * COSphi;
n0[1] = _SINtheta * COSphi;
n1[0] = COStheta1 * COSphi;
n1[1] = _SINtheta1 * COSphi;
n2[0] = COStheta1 * COSphi1;
n2[1] = _SINtheta1 * COSphi1;
n3[0] = COStheta * COSphi1;
n3[1] = _SINtheta * COSphi1;
p0[2] = p1[2] = r * (n0[2] = n1[2] = sin(phi));
p2[2] = p3[2] = r * (n2[2] = n3[2] = sin(phi1));
glBegin(GL_QUADS);
glNormal3fv(n3);
glVertex3fv(p3);
glNormal3fv(n2);
glVertex3fv(p2);
glNormal3fv(n1);
glVertex3fv(p1);
glNormal3fv(n0);
glVertex3fv(p0);
glEnd();
}
}
if (pp->factory > 0 && bolted) {
/* Bolt the elbow onto the pipe system */
glFrontFace(GL_CW);
glPushMatrix();
glRotatef(90.0, 0.0, 0.0, -1.0);
glRotatef(90.0, 0.0, 1.0, 0.0);
glTranslatef(0.0, one_third, one_third);
glCallList(pp->elbowcoins);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
glCallList(pp->elbowbolts);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
glPopMatrix();
glFrontFace(GL_CCW);
}
#undef r
#undef R
#undef nsides
#undef rings
}
static void
FindNeighbors(ModeInfo * mi)
{
pipesstruct *pp = &pipes[MI_SCREEN(mi)];
pp->ndirections = 0;
pp->directions[dirUP] = (!pp->Cells[pp->PX][pp->PY + 1][pp->PZ]) ? 1 : 0;
pp->ndirections += pp->directions[dirUP];
pp->directions[dirDOWN] = (!pp->Cells[pp->PX][pp->PY - 1][pp->PZ]) ? 1 : 0;
pp->ndirections += pp->directions[dirDOWN];
pp->directions[dirLEFT] = (!pp->Cells[pp->PX - 1][pp->PY][pp->PZ]) ? 1 : 0;
pp->ndirections += pp->directions[dirLEFT];
pp->directions[dirRIGHT] = (!pp->Cells[pp->PX + 1][pp->PY][pp->PZ]) ? 1 : 0;
pp->ndirections += pp->directions[dirRIGHT];
pp->directions[dirFAR] = (!pp->Cells[pp->PX][pp->PY][pp->PZ - 1]) ? 1 : 0;
pp->ndirections += pp->directions[dirFAR];
pp->directions[dirNEAR] = (!pp->Cells[pp->PX][pp->PY][pp->PZ + 1]) ? 1 : 0;
pp->ndirections += pp->directions[dirNEAR];
}
static int
SelectNeighbor(ModeInfo * mi)
{
pipesstruct *pp = &pipes[MI_SCREEN(mi)];
int dirlist[6];
int i, j;
for (i = 0, j = 0; i < 6; i++) {
if (pp->directions[i]) {
dirlist[j] = i;
j++;
}
}
return dirlist[NRAND(pp->ndirections)];
}
static void
MakeValve(ModeInfo * mi, int newdir)
{
pipesstruct *pp = &pipes[MI_SCREEN(mi)];
/* There is a glPopMatrix() right after this subroutine returns. */
switch (newdir) {
case dirUP:
case dirDOWN:
glRotatef(90.0, 1.0, 0.0, 0.0);
glRotatef(NRAND(3) * 90.0, 0.0, 0.0, 1.0);
break;
case dirLEFT:
case dirRIGHT:
glRotatef(90.0, 0.0, -1.0, 0.0);
glRotatef((NRAND(3) * 90.0) - 90.0, 0.0, 0.0, 1.0);
break;
case dirNEAR:
case dirFAR:
glRotatef(NRAND(4) * 90.0, 0.0, 0.0, 1.0);
break;
}
glFrontFace(GL_CW);
glCallList(pp->betweenbolts);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
glCallList(pp->bolts);
if (!MI_IS_MONO(mi)) {
if (pp->system_color == MaterialRed) {
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, NRAND(2) ? MaterialYellow : MaterialBlue);
} else if (pp->system_color == MaterialBlue) {
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, NRAND(2) ? MaterialRed : MaterialYellow);
} else if (pp->system_color == MaterialYellow) {
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, NRAND(2) ? MaterialBlue : MaterialRed);
} else {
switch ((NRAND(3))) {
case 0:
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialRed);
break;
case 1:
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialBlue);
break;
case 2:
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialYellow);
}
}
}
glRotatef((GLfloat) (NRAND(90)), 1.0, 0.0, 0.0);
glCallList(pp->valve);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
glFrontFace(GL_CCW);
}
static int
MakeGuage(ModeInfo * mi, int newdir)
{
pipesstruct *pp = &pipes[MI_SCREEN(mi)];
/* Can't have a guage on a vertical pipe. */
if ((newdir == dirUP) || (newdir == dirDOWN))
return (0);
/* Is there space above this pipe for a guage? */
if (!pp->directions[dirUP])
return (0);
/* Yes! Mark the space as used. */
pp->Cells[pp->PX][pp->PY + 1][pp->PZ] = 1;
glFrontFace(GL_CW);
glPushMatrix();
if ((newdir == dirLEFT) || (newdir == dirRIGHT))
glRotatef(90.0, 0.0, 1.0, 0.0);
glCallList(pp->betweenbolts);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialGray);
glCallList(pp->bolts);
glPopMatrix();
glCallList(pp->guageconnector);
glPushMatrix();
glTranslatef(0.0, 1.33333, 0.0);
/* Do not change the above to 1 + ONE_THIRD, because */
/* the object really is centered on 1.3333300000. */
glRotatef(NRAND(270) + 45.0, 0.0, 0.0, -1.0);
/* Random rotation for the dial. I love it. */
glCallList(pp->guagedial);
glPopMatrix();
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
glCallList(pp->guagehead);
/* GuageFace is drawn last, in case of low-res depth buffers. */
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, MaterialWhite);
glCallList(pp->guageface);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
glFrontFace(GL_CCW);
return (1);
}
static void
MakeShape(ModeInfo * mi, int newdir)
{
switch (NRAND(2)) {
case 1:
if (!MakeGuage(mi, newdir))
MakeTube(newdir);
break;
default:
MakeValve(mi, newdir);
break;
}
}
static void
reshape(ModeInfo * mi, int width, int height)
{
pipesstruct *pp = &pipes[MI_SCREEN(mi)];
glViewport(0, 0, pp->WindW = (GLint) width, pp->WindH = (GLint) height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
/*glFrustum(-1.0, 1.0, -1.0, 1.0, 5.0, 15.0); */
gluPerspective(65.0, (GLfloat) width / (GLfloat) height, 0.1, 20.0);
glMatrixMode(GL_MODELVIEW);
}
static void
pinit(ModeInfo * mi, int zera)
{
pipesstruct *pp = &pipes[MI_SCREEN(mi)];
int X, Y, Z;
glClearDepth(1.0);
glClearColor(0.0, 0.0, 0.0, 1.0);
glColor3f(1.0, 1.0, 1.0);
glLightfv(GL_LIGHT0, GL_AMBIENT, ambient0);
glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse0);
glLightfv(GL_LIGHT0, GL_POSITION, position0);
glLightfv(GL_LIGHT1, GL_AMBIENT, ambient1);
glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse1);
glLightfv(GL_LIGHT1, GL_POSITION, position1);
glLightModelfv(GL_LIGHT_MODEL_AMBIENT, lmodel_ambient);
glLightModelfv(GL_LIGHT_MODEL_TWO_SIDE, lmodel_twoside);
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
glEnable(GL_LIGHT1);
glEnable(GL_DEPTH_TEST);
glEnable(GL_NORMALIZE);
glEnable(GL_CULL_FACE);
glShadeModel(GL_SMOOTH);
glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, front_shininess);
glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, front_specular);
if (zera) {
pp->system_number = 1;
glDrawBuffer(GL_FRONT_AND_BACK);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
(void) memset(pp->Cells, 0, sizeof (pp->Cells));
for (X = 0; X < HCELLS; X++) {
for (Y = 0; Y < VCELLS; Y++) {
pp->Cells[X][Y][0] = 1;
pp->Cells[X][Y][HCELLS - 1] = 1;
pp->Cells[0][Y][X] = 1;
pp->Cells[HCELLS - 1][Y][X] = 1;
}
}
for (X = 0; X < HCELLS; X++) {
for (Z = 0; Z < HCELLS; Z++) {
pp->Cells[X][0][Z] = 1;
pp->Cells[X][VCELLS - 1][Z] = 1;
}
}
(void) memset(pp->usedcolors, 0, sizeof (pp->usedcolors));
if ((pp->initial_rotation += 10.0) > 45.0) {
pp->initial_rotation -= 90.0;
}
}
pp->counter = 0;
pp->turncounter = 0;
if (!MI_IS_MONO(mi)) {
int collist[DEFINEDCOLORS];
int i, j, lower = 1000;
/* Avoid repeating colors on the same screen unless necessary */
for (i = 0; i < DEFINEDCOLORS; i++) {
if (lower > pp->usedcolors[i])
lower = pp->usedcolors[i];
}
for (i = 0, j = 0; i < DEFINEDCOLORS; i++) {
if (pp->usedcolors[i] == lower) {
collist[j] = i;
j++;
}
}
i = collist[NRAND(j)];
pp->usedcolors[i]++;
switch (i) {
case 0:
pp->system_color = MaterialRed;
break;
case 1:
pp->system_color = MaterialGreen;
break;
case 2:
pp->system_color = MaterialBlue;
break;
case 3:
pp->system_color = MaterialCyan;
break;
case 4:
pp->system_color = MaterialYellow;
break;
case 5:
pp->system_color = MaterialMagenta;
break;
case 6:
pp->system_color = MaterialWhite;
break;
}
} else {
pp->system_color = MaterialGray;
}
do {
pp->PX = NRAND((HCELLS - 1)) + 1;
pp->PY = NRAND((VCELLS - 1)) + 1;
pp->PZ = NRAND((HCELLS - 1)) + 1;
} while (pp->Cells[pp->PX][pp->PY][pp->PZ] ||
(pp->Cells[pp->PX + 1][pp->PY][pp->PZ] && pp->Cells[pp->PX - 1][pp->PY][pp->PZ] &&
pp->Cells[pp->PX][pp->PY + 1][pp->PZ] && pp->Cells[pp->PX][pp->PY - 1][pp->PZ] &&
pp->Cells[pp->PX][pp->PY][pp->PZ + 1] && pp->Cells[pp->PX][pp->PY][pp->PZ - 1]));
pp->Cells[pp->PX][pp->PY][pp->PZ] = 1;
pp->olddir = dirNone;
FindNeighbors(mi);
pp->nowdir = SelectNeighbor(mi);
}
static void
free_factory(Display *display, pipesstruct *pp)
{
if (pp->glx_context) {
/* Display lists MUST be freed while their glXContext is current. */
glXMakeCurrent(display, pp->window, *(pp->glx_context));
if (pp->valve != 0) {
glDeleteLists(pp->valve, 1);
pp->valve = 0;
}
if (pp->bolts != 0) {
glDeleteLists(pp->bolts, 1);
pp->bolts = 0;
}
if (pp->betweenbolts != 0) {
glDeleteLists(pp->betweenbolts, 1);
pp->betweenbolts = 0;
}
if (pp->elbowbolts != 0) {
glDeleteLists(pp->elbowbolts, 1);
pp->elbowbolts = 0;
}
if (pp->elbowcoins != 0) {
glDeleteLists(pp->elbowcoins, 1);
pp->elbowcoins = 0;
}
if (pp->guagehead != 0) {
glDeleteLists(pp->guagehead, 1);
pp->guagehead = 0;
}
if (pp->guageface != 0) {
glDeleteLists(pp->guageface, 1);
pp->guageface = 0;
}
if (pp->guagedial != 0) {
glDeleteLists(pp->guagedial, 1);
pp->guagedial = 0;
}
if (pp->guageconnector != 0) {
glDeleteLists(pp->guageconnector, 1);
pp->guageconnector = 0;
}
}
}
void
release_pipes(ModeInfo * mi)
{
if (pipes != NULL) {
int screen;
for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++)
free_factory(MI_DISPLAY(mi), &pipes[screen]);
free(pipes);
pipes = (pipesstruct *) NULL;
}
FreeAllGL(mi);
}
void
init_pipes(ModeInfo * mi)
{
pipesstruct *pp;
if (pipes == NULL) {
if ((pipes = (pipesstruct *) calloc(MI_NUM_SCREENS(mi),
sizeof (pipesstruct))) == NULL)
return;
}
pp = &pipes[MI_SCREEN(mi)];
pp->window = MI_WINDOW(mi);
pp->factory = factory;
if ((pp->glx_context = init_GL(mi)) != NULL) {
reshape(mi, MI_WIDTH(mi), MI_HEIGHT(mi));
pp->initial_rotation = -10.0;
pinit(mi, 1);
if (pp->factory > 0) {
if (((pp->valve = BuildLWO(MI_IS_WIREFRAME(mi),
&LWO_BigValve)) == 0) ||
((pp->bolts = BuildLWO(MI_IS_WIREFRAME(mi),
&LWO_Bolts3D)) == 0) ||
((pp->betweenbolts = BuildLWO(MI_IS_WIREFRAME(mi),
&LWO_PipeBetweenBolts)) == 0) ||
((pp->elbowbolts = BuildLWO(MI_IS_WIREFRAME(mi),
&LWO_ElbowBolts)) == 0) ||
((pp->elbowcoins = BuildLWO(MI_IS_WIREFRAME(mi),
&LWO_ElbowCoins)) == 0) ||
((pp->guagehead = BuildLWO(MI_IS_WIREFRAME(mi),
&LWO_GuageHead)) == 0) ||
((pp->guageface = BuildLWO(MI_IS_WIREFRAME(mi),
&LWO_GuageFace)) == 0) ||
((pp->guagedial = BuildLWO(MI_IS_WIREFRAME(mi),
&LWO_GuageDial)) == 0) ||
((pp->guageconnector = BuildLWO(MI_IS_WIREFRAME(mi),
&LWO_GuageConnector)) == 0)) {
free_factory(MI_DISPLAY(mi), pp);
pp->factory = 0;
}
}
/* else they are all 0, thanks to calloc(). */
if (MI_COUNT(mi) < 1 || MI_COUNT(mi) > NofSysTypes + 1) {
pp->system_type = NRAND(NofSysTypes) + 1;
} else {
pp->system_type = MI_COUNT(mi);
}
if (MI_CYCLES(mi) > 0 && MI_CYCLES(mi) < 11) {
pp->number_of_systems = MI_CYCLES(mi);
} else {
pp->number_of_systems = 5;
}
if (MI_SIZE(mi) < 10) {
pp->system_length = 10;
} else if (MI_SIZE(mi) > 1000) {
pp->system_length = 1000;
} else {
pp->system_length = MI_SIZE(mi);
}
} else {
MI_CLEARWINDOW(mi);
}
}
void
draw_pipes(ModeInfo * mi)
{
Display *display = MI_DISPLAY(mi);
Window window = MI_WINDOW(mi);
int newdir;
int OPX, OPY, OPZ;
pipesstruct *pp;
if (pipes == NULL)
return;
pp = &pipes[MI_SCREEN(mi)];
MI_IS_DRAWN(mi) = True;
if (!pp->glx_context)
return;
glXMakeCurrent(display, window, *(pp->glx_context));
#if defined( MESA ) && defined( SLOW )
glDrawBuffer(GL_BACK);
#else
glDrawBuffer(GL_FRONT);
#endif
glPushMatrix();
glTranslatef(0.0, 0.0, fisheye ? -3.8 : -4.8);
if (rotatepipes)
glRotatef(pp->initial_rotation, 0.0, 1.0, 0.0);
if (!MI_IS_ICONIC(mi)) {
/* Width/height ratio handled by gluPerspective() now. */
glScalef(Scale4Window, Scale4Window, Scale4Window);
} else {
glScalef(Scale4Iconic, Scale4Iconic, Scale4Iconic);
}
FindNeighbors(mi);
glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, pp->system_color);
/* If it's the begining of a system, draw a sphere */
if (pp->olddir == dirNone) {
glPushMatrix();
glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
if (!mySphere(0.6)) {
release_pipes(mi);
return;
}
glPopMatrix();
}
/* Check for stop conditions */
if (pp->ndirections == 0 || pp->counter > pp->system_length) {
glPushMatrix();
glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
/* Finish the system with another sphere */
if (!mySphere(0.6)) {
release_pipes(mi);
return;
}
#if defined( MESA ) && defined( SLOW )
glXSwapBuffers(display, window);
#endif
glPopMatrix();
/* If the maximum number of system was drawn, restart (clearing the screen), */
/* else start a new system. */
if (++pp->system_number > pp->number_of_systems) {
(void) sleep(1);
pinit(mi, 1);
} else {
pinit(mi, 0);
}
glPopMatrix();
return;
}
pp->counter++;
pp->turncounter++;
/* Do will the direction change? if so, determine the new one */
newdir = pp->nowdir;
if (!pp->directions[newdir]) { /* cannot proceed in the current direction */
newdir = SelectNeighbor(mi);
} else {
if (tightturns) {
/* random change (20% chance) */
if ((pp->counter > 1) && (NRAND(100) < 20)) {
newdir = SelectNeighbor(mi);
}
} else {
/* Chance to turn increases after each length of pipe drawn */
if ((pp->counter > 1) && NRAND(50) < NRAND(pp->turncounter + 1)) {
newdir = SelectNeighbor(mi);
pp->turncounter = 0;
}
}
}
/* Has the direction changed? */
if (newdir == pp->nowdir) {
/* If not, draw the cell's center pipe */
glPushMatrix();
glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
/* Chance of factory shape here, if enabled. */
if ((pp->counter > 1) && (NRAND(100) < pp->factory)) {
MakeShape(mi, newdir);
} else {
MakeTube(newdir);
}
glPopMatrix();
} else {
/* If so, draw the cell's center elbow/sphere */
int sysT = pp->system_type;
if (sysT == NofSysTypes + 1) {
sysT = ((pp->system_number - 1) % NofSysTypes) + 1;
}
glPushMatrix();
switch (sysT) {
case 1:
glTranslatef((pp->PX - 16) / 3.0 * 4.0, (pp->PY - 12) / 3.0 * 4.0, (pp->PZ - 16) / 3.0 * 4.0);
if (!mySphere(elbowradius)) {
release_pipes(mi);
return;
}
break;
case 2:
case 3:
switch (pp->nowdir) {
case dirUP:
switch (newdir) {
case dirLEFT:
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);
glRotatef(180.0, 1.0, 0.0, 0.0);
break;
case dirRIGHT:
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);
glRotatef(180.0, 1.0, 0.0, 0.0);
glRotatef(180.0, 0.0, 1.0, 0.0);
break;
case dirFAR:
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));
glRotatef(90.0, 0.0, 1.0, 0.0);
glRotatef(180.0, 0.0, 0.0, 1.0);
break;
case dirNEAR:
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));
glRotatef(90.0, 0.0, 1.0, 0.0);
glRotatef(180.0, 1.0, 0.0, 0.0);
break;
}
break;
case dirDOWN:
switch (newdir) {
case dirLEFT:
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);
break;
case dirRIGHT:
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);
glRotatef(180.0, 0.0, 1.0, 0.0);
break;
case dirFAR:
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));
glRotatef(270.0, 0.0, 1.0, 0.0);
break;
case dirNEAR:
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));
glRotatef(90.0, 0.0, 1.0, 0.0);
break;
}
break;
case dirLEFT:
switch (newdir) {
case dirUP:
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);
glRotatef(180.0, 0.0, 1.0, 0.0);
break;
case dirDOWN:
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);
glRotatef(180.0, 1.0, 0.0, 0.0);
glRotatef(180.0, 0.0, 1.0, 0.0);
break;
case dirFAR:
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));
glRotatef(270.0, 1.0, 0.0, 0.0);
glRotatef(180.0, 0.0, 1.0, 0.0);
break;
case dirNEAR:
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));
glRotatef(270.0, 1.0, 0.0, 0.0);
glRotatef(180.0, 0.0, 0.0, 1.0);
break;
}
break;
case dirRIGHT:
switch (newdir) {
case dirUP:
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);
break;
case dirDOWN:
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);
glRotatef(180.0, 1.0, 0.0, 0.0);
break;
case dirFAR:
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));
glRotatef(270.0, 1.0, 0.0, 0.0);
break;
case dirNEAR:
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));
glRotatef(90.0, 1.0, 0.0, 0.0);
break;
}
break;
case dirNEAR:
switch (newdir) {
case dirLEFT:
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));
glRotatef(270.0, 1.0, 0.0, 0.0);
break;
case dirRIGHT:
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));
glRotatef(270.0, 1.0, 0.0, 0.0);
glRotatef(180.0, 0.0, 1.0, 0.0);
break;
case dirUP:
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));
glRotatef(270.0, 0.0, 1.0, 0.0);
break;
case dirDOWN:
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));
glRotatef(90.0, 0.0, 1.0, 0.0);
glRotatef(180.0, 0.0, 0.0, 1.0);
break;
}
break;
case dirFAR:
switch (newdir) {
case dirUP:
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));
glRotatef(90.0, 0.0, 1.0, 0.0);
break;
case dirDOWN:
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));
glRotatef(90.0, 0.0, 1.0, 0.0);
glRotatef(180.0, 1.0, 0.0, 0.0);
break;
case dirLEFT:
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));
glRotatef(90.0, 1.0, 0.0, 0.0);
break;
case dirRIGHT:
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));
glRotatef(270.0, 1.0, 0.0, 0.0);
glRotatef(180.0, 0.0, 0.0, 1.0);
break;
}
break;
}
myElbow(mi, (sysT == 2));
break;
}
glPopMatrix();
}
OPX = pp->PX;
OPY = pp->PY;
OPZ = pp->PZ;
pp->olddir = pp->nowdir;
pp->nowdir = newdir;
switch (pp->nowdir) {
case dirUP:
pp->PY++;
break;
case dirDOWN:
pp->PY--;
break;
case dirLEFT:
pp->PX--;
break;
case dirRIGHT:
pp->PX++;
break;
case dirNEAR:
pp->PZ++;
break;
case dirFAR:
pp->PZ--;
break;
}
pp->Cells[pp->PX][pp->PY][pp->PZ] = 1;
/* Cells'face pipe */
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);
MakeTube(newdir);
glPopMatrix();
glFlush();
#if defined( MESA ) && defined( SLOW )
pp->flip = !pp->flip;
if (pp->flip)
glXSwapBuffers(display, window);
#endif
}
void
change_pipes(ModeInfo * mi)
{
pipesstruct *pp;
if (pipes == NULL)
return;
pp = &pipes[MI_SCREEN(mi)];
if (!pp->glx_context)
return;
glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *(pp->glx_context));
pinit(mi, 1);
}
#endif