diff options
Diffstat (limited to 'hacks/glx/glhanoi.c')
| -rw-r--r-- | hacks/glx/glhanoi.c | 2091 |
1 files changed, 0 insertions, 2091 deletions
diff --git a/hacks/glx/glhanoi.c b/hacks/glx/glhanoi.c deleted file mode 100644 index b544283..0000000 --- a/hacks/glx/glhanoi.c +++ /dev/null @@ -1,2091 +0,0 @@ -/* -*- Mode: C; tab-width: 4 -*- */ -/* glhanoi, Copyright (c) 2005, 2009 Dave Atkinson <da@davea.org.uk> - * except noise function code Copyright (c) 2002 Ken Perlin - * Modified by Lars Huttar (c) 2010, to generalize to 4 or more poles - * - * Permission to use, copy, modify, distribute, and sell this software and its - * documentation for any purpose is hereby granted without fee, provided that - * the above copyright notice appear in all copies and that both that - * copyright notice and this permission notice appear in supporting - * documentation. No representations are made about the suitability of this - * software for any purpose. It is provided "as is" without express or - * implied warranty. - */ - -#include <assert.h> - -#include "rotator.h" - -#define DEF_LIGHT "True" -#define DEF_FOG "False" -#define DEF_TEXTURE "True" -#define DEF_POLES "0" /* choose random value */ -#define DEF_SPEED "1" -#define DEF_TRAILS "2" - -#define DEFAULTS "*delay: 15000\n" \ - "*count: 0\n" \ - "*showFPS: False\n" \ - "*wireframe: False\n" - -# define release_glhanoi 0 - -/* polygon resolution of poles and disks */ -#define NSLICE 32 -#define NLOOPS 1 - -/* How long to wait at start and finish (seconds). */ -#define START_DURATION 1.0 -#define FINISH_DURATION 1.0 -#define BASE_LENGTH 30.0 -#define BOARD_SQUARES 8 - -/* Don't draw trail lines till they're this old (sec). - Helps trails not be "attached" to the disks. */ -#define TRAIL_START_DELAY 0.1 - -#define MAX_CAMERA_RADIUS 250.0 -#define MIN_CAMERA_RADIUS 75.0 - -#define MARBLE_SCALE 1.01 - -#undef BELLRAND -/* Return a double precision number in [0...n], with bell curve distribution. */ -#define BELLRAND(n) ((frand((n)) + frand((n)) + frand((n))) / 3) - -enum { - MARBLE_TEXURE, - N_TEXTURES -}; - -#define MARBLE_TEXTURE_SIZE 256 - -#include <math.h> -#include "xlockmore.h" - -#ifdef USE_GL /* whole file */ - -typedef struct timeval glhtime; - -static double getTime(void) -{ - struct timeval t; -#ifdef GETTIMEOFDAY_TWO_ARGS - gettimeofday(&t, NULL); -#else /* !GETTIMEOFDAY_TWO_ARGS */ - gettimeofday(&t); -#endif /* !GETTIMEOFDAY_TWO_ARGS */ - return t.tv_sec + t.tv_usec / 1000000.0; -} - -typedef enum { - START, - MOVE_DISK, - MOVE_FINISHED, - FINISHED, - MONEY_SHOT, - INVALID = -1 -} State; - -typedef struct { - int id; - GLuint displayList; - GLfloat position[3]; - GLfloat rotation[3]; - GLfloat color[4]; - GLfloat base0; - GLfloat base1; - GLfloat height; - GLfloat xmin, xmax, ymin, zmin, zmax; - GLfloat u1, u2; - GLfloat t1, t2; - GLfloat ucostheta, usintheta; - GLfloat dx, dz; - GLdouble rotAngle; /* degree of "flipping" so far, during travel */ - GLdouble phi; /* angle of motion in xz plane */ - GLfloat speed; - int polys; -} Disk; - -typedef struct { - Disk **data; - int count; - int size; - GLfloat position[3]; -} Pole; - -/* A SubProblem is a recursive subdivision of the problem, and means - "Move nDisks disks from src pole to dst pole, using the poles indicated in 'available'." */ -typedef struct { - int nDisks; - int src, dst; - unsigned long available; /* a bitmask of poles that have no smaller disks on them */ -} SubProblem; - -typedef struct { - GLfloat position[3]; - double startTime, endTime; - Bool isEnd; -} TrailPoint; - -typedef struct { - GLXContext *glx_context; - State state; - Bool wire; - Bool fog; - Bool light; - Bool layoutLinear; - GLfloat trailDuration; - double startTime; - double lastTime; - double duration; - int numberOfDisks; - int numberOfPoles; - int numberOfMoves; - int maxDiskIdx; - int magicNumber; - Disk *currentDisk; - int move; - /* src, tmp, dst: index of pole that is source / storage / destination for - current move */ - int src; - int tmp; - int dst; - int oldsrc; - int oldtmp; - int olddst; - GLfloat speed; /* coefficient for how fast the disks move */ - SubProblem *solveStack; - int solveStackSize, solveStackIdx; - Pole *pole; - float boardSize; - float baseLength; - float baseWidth; - float baseHeight; - float poleRadius; - float poleHeight; - float poleOffset; - float poleDist; /* distance of poles from center, for round layout */ - float diskHeight; - float maxDiskRadius; - float *diskPos; /* pre-computed disk positions on rods */ - Disk *disk; - GLint floorList; - GLint baseList; - GLint poleList; - int floorpolys, basepolys, polepolys; - int trailQSize; - TrailPoint *trailQ; - int trailQFront, trailQBack; - GLfloat camera[3]; - GLfloat centre[3]; - rotator *the_rotator; - Bool button_down_p; - Bool texture; - GLuint textureNames[N_TEXTURES]; - int drag_x; - int drag_y; - int noise_initted; - int p[512]; -} glhcfg; - -static glhcfg *glhanoi_cfg = NULL; -static Bool fog; -static Bool light; -static Bool texture; -static GLfloat trails; -static int poles; -static GLfloat speed; - -static XrmOptionDescRec opts[] = { - {"-light", ".glhanoi.light", XrmoptionNoArg, "true"}, - {"+light", ".glhanoi.light", XrmoptionNoArg, "false"}, - {"-fog", ".glhanoi.fog", XrmoptionNoArg, "true"}, - {"+fog", ".glhanoi.fog", XrmoptionNoArg, "false"}, - {"-texture", ".glhanoi.texture", XrmoptionNoArg, "true"}, - {"+texture", ".glhanoi.texture", XrmoptionNoArg, "false"}, - {"-trails", ".glhanoi.trails", XrmoptionSepArg, 0}, - {"-poles", ".glhanoi.poles", XrmoptionSepArg, 0 }, - {"-speed", ".glhanoi.speed", XrmoptionSepArg, 0 } -}; - -static argtype vars[] = { - {&light, "light", "Light", DEF_LIGHT, t_Bool}, - {&fog, "fog", "Fog", DEF_FOG, t_Bool}, - {&texture, "texture", "Texture", DEF_TEXTURE, t_Bool}, - {&trails, "trails", "Trails", DEF_TRAILS, t_Float}, - {&poles, "poles", "Poles", DEF_POLES, t_Int}, - {&speed, "speed", "Speed", DEF_SPEED, t_Float} -}; - -static OptionStruct desc[] = { - {"+/-light", "whether to light the scene"}, - {"+/-fog", "whether to apply fog to the scene"}, - {"+/-texture", "whether to apply texture to the scene"}, - {"-trails t", "how long of disk trails to show (sec.)"}, - {"-poles r", "number of poles to move disks between"}, - {"-speed s", "speed multiplier"} -}; - -ENTRYPOINT ModeSpecOpt glhanoi_opts = { countof(opts), opts, countof(vars), vars, desc }; - -#ifdef USE_MODULES - -ModStruct glhanoi_description = { - "glhanoi", "init_glhanoi", "draw_glhanoi", NULL, - "draw_glhanoi", "init_glhanoi", "free_glhanoi", &glhanoi_opts, - 1000, 1, 2, 1, 4, 1.0, "", - "Towers of Hanoi", 0, NULL -}; - -#endif - -static const GLfloat cBlack[] = { 0.0, 0.0, 0.0, 1.0 }; -static const GLfloat cWhite[] = { 1.0, 1.0, 1.0, 1.0 }; -static const GLfloat poleColor[] = { 0.545, 0.137, 0.137 }; -static const GLfloat baseColor[] = { 0.34, 0.34, 0.48 }; -/* static const GLfloat baseColor[] = { 0.545, 0.137, 0.137 }; */ -static const GLfloat fogcolor[] = { 0.5, 0.5, 0.5 }; -static GLfloat trailColor[] = { 1.0, 1.0, 1.0, 0.5 }; - -static const float left[] = { 1.0, 0.0, 0.0 }; -static const float up[] = { 0.0, 1.0, 0.0 }; -static const float front[] = { 0.0, 0.0, 1.0 }; -static const float right[] = { -1.0, 0.0, 0.0 }; -static const float down[] = { 0.0, -1.0, 0.0 }; -static const float back[] = { 0.0, 0.0, -1.0 }; - -static const GLfloat pos0[4] = { 50.0, 50.0, 50.0, 0.0 }; -static const GLfloat amb0[4] = { 0.0, 0.0, 0.0, 1.0 }; -static const GLfloat dif0[4] = { 1.0, 1.0, 1.0, 1.0 }; -static const GLfloat spc0[4] = { 0.0, 1.0, 1.0, 1.0 }; - -static const GLfloat pos1[4] = { -50.0, 50.0, -50.0, 0.0 }; -static const GLfloat amb1[4] = { 0.0, 0.0, 0.0, 1.0 }; -static const GLfloat dif1[4] = { 1.0, 1.0, 1.0, 1.0 }; -static const GLfloat spc1[4] = { 1.0, 1.0, 1.0, 1.0 }; - -static float g = 3.0 * 9.80665; /* hmm, looks like we need more gravity, Scotty... */ - -static void checkAllocAndExit(Bool item, char *descr) { - if (!item) { - fprintf(stderr, "%s: unable to allocate memory for %s\n", - progname, descr); - exit(EXIT_FAILURE); - } -} - -#define DOPUSH(X, Y) (((X)->count) >= ((X)->size)) ? NULL : ((X)->data[(X)->count++] = (Y)) -#define DOPOP(X) (X)->count <= 0 ? NULL : ((X)->data[--((X)->count)]) - -/* push disk d onto pole idx */ -static Disk *push(glhcfg *glhanoi, int idx, Disk * d) -{ - return DOPUSH(&glhanoi->pole[idx], d); -} - -/* pop the top disk from pole idx */ -static Disk *pop(glhcfg *glhanoi, int idx) -{ - return DOPOP(&glhanoi->pole[idx]); -} - -static inline void swap(int *x, int *y) -{ - *x = *x ^ *y; - *y = *x ^ *y; - *x = *x ^ *y; -} - -/* - * magic - it's magic... - * Return 1 if the number of trailing zeroes on i is even, unless i is 1 or 0. - */ -static int magic(int i) -{ - int count = 0; - if(i <= 1) - return 0; - while((i & 0x01) == 0) { - i >>= 1; - count++; - } - return count % 2 == 0; -} - -static float distance(float *p0, float *p1) -{ - float x, y, z; - x = p1[0] - p0[0]; - y = p1[1] - p0[1]; - z = p1[2] - p0[2]; - return (float)sqrt(x * x + y * y + z * z); -} - -/* What is this for? - = c / (a b - 0.25 (a^2 + 2 a b + b^2) ) - = c / (-0.25 (a^2 - 2 a b + b^2) ) - = c / (-0.25 ((a - b)(a - b))) - = -4 c / (a - b)^2 -static GLfloat A(GLfloat a, GLfloat b, GLfloat c) -{ - GLfloat sum = a + b; - return c / (a * b - 0.25 * sum * sum); -} -*/ - -static void moveSetup(glhcfg *glhanoi, Disk * disk) -{ - float h, ymax; - float u; - int src = glhanoi->src; - int dst = glhanoi->dst; - GLfloat theta; - GLfloat sintheta, costheta; - double dh; - double dx, dz; /* total x and z distances from src to dst */ - Pole *poleSrc, *poleDst; - - poleSrc = &(glhanoi->pole[src]); - poleDst = &(glhanoi->pole[dst]); - - disk->xmin = poleSrc->position[0]; - /* glhanoi->poleOffset * (src - (glhanoi->numberOfPoles - 1.0f) * 0.5); */ - disk->xmax = poleDst->position[0]; - /* disk->xmax = glhanoi->poleOffset * (dst - (glhanoi->numberOfPoles - 1.0f) * 0.5); */ - disk->ymin = glhanoi->poleHeight; - disk->zmin = poleSrc->position[2]; - disk->zmax = poleDst->position[2]; - - dx = disk->xmax - disk->xmin; - dz = disk->zmax - disk->zmin; - - if(glhanoi->state != FINISHED) { - double xxx = ((dx < 0) ? 180.0 : -180.0); - if(random() % 6 == 0) { - disk->rotAngle = xxx * (2 - 2 * random() % 2) * (random() % 3 + 1); - } else { - disk->rotAngle = xxx; - } - if(random() % 4 == 0) { - /* Backflip */ - disk->rotAngle = -disk->rotAngle; - } - } else { - disk->rotAngle = -180.0; - } - - disk->base0 = glhanoi->diskPos[poleSrc->count]; - disk->base1 = (glhanoi->state == FINISHED) ? - disk->base0 : glhanoi->diskPos[poleDst->count]; - - /* horizontal distance to travel? */ - /* was: absx = sqrt(disk->xmax - disk->xmin); */ - dh = distance(poleSrc->position, poleDst->position); - /* absx = sqrt(dh); */ - ymax = glhanoi->poleHeight + dh; - if(glhanoi->state == FINISHED) { - ymax += dh * (double)(glhanoi->numberOfDisks - disk->id); - } - h = ymax - disk->ymin; - /* A(a, b, c) = -4 c / (a - b)^2 */ - /* theta = atan(4 h / (b - a)) */ - theta = atan(4 * h / dh); - if(theta < 0.0) - theta += M_PI; - costheta = cos(theta); - sintheta = sin(theta); - u = (float) - sqrt(fabs - (-g / - /* (2.0 * A(disk->xmin, disk->xmax, h) * costheta * costheta))); */ - (2.0 * -4 * h / (dh * dh) * costheta * costheta))); - disk->usintheta = u * sintheta; - disk->ucostheta = u * costheta; - /* Not to be confused: disk->dx is the per-time-unit portion of dx */ - disk->dx = disk->ucostheta * dx / dh; - disk->dz = disk->ucostheta * dz / dh; - disk->t1 = - (-u + sqrt(u * u + 2.0 * g * fabs(disk->ymin - disk->base0))) / g; - disk->u1 = u + g * disk->t1; - disk->t2 = 2.0 * disk->usintheta / g; - disk->u2 = disk->usintheta - g * disk->t2; - - /* Compute direction of travel, in the XZ plane. */ - disk->phi = atan(dz / dx); - disk->phi *= 180.0 / M_PI; /* convert radians to degrees */ -} - -/* For debugging: show a value as a string of ones and zeroes -static const char *byteToBinary(int x) { - static char b[9]; - int i, z; - - for (z = 128, i = 0; z > 0; z >>= 1, i++) { - b[i] = ((x & z) == z) ? '1' : '0'; - } - b[i] = '\0'; - - return b; -} -*/ - -static void pushMove(glhcfg *glhanoi, int n, int src, int dst, int avail) { - SubProblem *sp = &(glhanoi->solveStack[glhanoi->solveStackIdx++]); - - if (glhanoi->solveStackIdx > glhanoi->solveStackSize) { - fprintf(stderr, "solveStack overflow: pushed index %d: %d from %d to %d, using %d\n", - glhanoi->solveStackIdx, n, src, dst, avail); - exit(EXIT_FAILURE); - } - - sp->nDisks = n; - sp->src = src; - sp->dst = dst; - sp->available = avail & ~((unsigned long)(1 << src)) - & ~((unsigned long)(1 << dst)); - /* - fprintf(stderr, "Debug: > pushed solveStack %d: %d from %d to %d, using %s\n", - glhanoi->solveStackIdx - 1, n, src, dst, byteToBinary(sp->available)); - */ -} - -static Bool solveStackEmpty(glhcfg *glhanoi) { - return (glhanoi->solveStackIdx < 1); -} - -static SubProblem *popMove(glhcfg *glhanoi) { - SubProblem *sp; - if (solveStackEmpty(glhanoi)) return (SubProblem *)NULL; - sp = &(glhanoi->solveStack[--glhanoi->solveStackIdx]); - /* fprintf(stderr, "Debug: < popped solveStack %d: %d from %d to %d, using %s\n", - glhanoi->solveStackIdx, sp->nDisks, sp->src, sp->dst, byteToBinary(sp->available)); */ - return sp; -} - -/* Return number of bits set in b */ -static int numBits(unsigned long b) { - int count = 0; - while (b) { - count += b & 0x1u; - b >>= 1; - } - return count; -} - -/* Return index (power of 2) of least significant 1 bit. */ -static int bitScan(unsigned long b) { - int count; - for (count = 0; b; count++, b >>= 1) { - if (b & 0x1u) return count; - } - return -1; -} - -/* A bit pattern representing all poles */ -#define ALL_POLES ((1 << glhanoi->numberOfPoles) - 1) - -#define REMOVE_BIT(a, b) ((a) & ~(1 << (b))) -#define ADD_BIT(a, b) ((a) | (1 << (b))) - -static void makeMove(glhcfg *glhanoi) -{ - if (glhanoi->numberOfPoles == 3) { - int fudge = glhanoi->move + 2; - int magicNumber = magic(fudge); - - - glhanoi->currentDisk = pop(glhanoi, glhanoi->src); - moveSetup(glhanoi, glhanoi->currentDisk); - push(glhanoi, glhanoi->dst, glhanoi->currentDisk); - - fudge = fudge % 2; - - if(fudge == 1 || magicNumber) { - swap(&glhanoi->src, &glhanoi->tmp); - } - if(fudge == 0 || glhanoi->magicNumber) { - swap(&glhanoi->dst, &glhanoi->tmp); - } - glhanoi->magicNumber = magicNumber; - } else { - SubProblem sp; - int tmp = 0; - - if (glhanoi->move == 0) { - /* Initialize the solution stack. Original problem: - move all disks from pole 0 to furthest pole, - using all other poles. */ - pushMove(glhanoi, glhanoi->numberOfDisks, 0, - glhanoi->numberOfPoles - 1, - REMOVE_BIT(REMOVE_BIT(ALL_POLES, 0), glhanoi->numberOfPoles - 1)); - } - - while (!solveStackEmpty(glhanoi)) { - int k, numAvail; - sp = *popMove(glhanoi); - - if (sp.nDisks == 1) { - /* We have a single, concrete move to do. */ - /* moveSetup uses glhanoi->src, dst. */ - glhanoi->src = sp.src; - glhanoi->dst = sp.dst; - glhanoi->tmp = tmp; /* Probably unnecessary */ - - glhanoi->currentDisk = pop(glhanoi, sp.src); - moveSetup(glhanoi, glhanoi->currentDisk); - push(glhanoi, sp.dst, glhanoi->currentDisk); - - return; - } else { - /* Divide and conquer, using Frame-Stewart algorithm, until we get to base case */ - if (sp.nDisks == 1) break; - - numAvail = numBits(sp.available); - if (numAvail < 2) k = sp.nDisks - 1; - else if(numAvail >= sp.nDisks - 2) k = 1; - /* heuristic for optimal k: sqrt(2n) (see http://www.cs.wm.edu/~pkstoc/boca.pdf) */ - else k = (int)(sqrt(2 * sp.nDisks)); - - if (k >= sp.nDisks) k = sp.nDisks - 1; - else if (k < 1) k = 1; - - tmp = bitScan(sp.available); - /* fprintf(stderr, "Debug: k is %d, tmp is %d\n", k, tmp); */ - if (tmp == -1) { - fprintf(stderr, "Error: n > 1 (%d) and no poles available\n", - sp.nDisks); - } - - /* Push on moves in reverse order, since this is a stack. */ - pushMove(glhanoi, k, tmp, sp.dst, - REMOVE_BIT(ADD_BIT(sp.available, sp.src), tmp)); - pushMove(glhanoi, sp.nDisks - k, sp.src, sp.dst, - REMOVE_BIT(sp.available, tmp)); - pushMove(glhanoi, k, sp.src, tmp, - REMOVE_BIT(ADD_BIT(sp.available, sp.dst), tmp)); - - /* Repeat until we've found a move we can make. */ - } - } - } -} - -static double lerp(double alpha, double start, double end) -{ - return start + alpha * (end - start); -} - -static void upfunc(GLdouble t, Disk * d) -{ - d->position[0] = d->xmin; - d->position[1] = d->base0 + (d->u1 - 0.5 * g * t) * t; - d->position[2] = d->zmin; - - d->rotation[1] = 0.0; -} - -static void parafunc(GLdouble t, Disk * d) -{ - /* ##was: d->position[0] = d->xmin + d->ucostheta * t; */ - d->position[0] = d->xmin + d->dx * t; - d->position[2] = d->zmin + d->dz * t; - d->position[1] = d->ymin + (d->usintheta - 0.5 * g * t) * t; - - d->rotation[1] = d->rotAngle * t / d->t2; - /* d->rotAngle * (d->position[0] - d->xmin) / (d->xmax - d->xmin); */ -} - -static void downfunc(GLdouble t, Disk * d) -{ - d->position[0] = d->xmax; - d->position[1] = d->ymin + (d->u2 - 0.5 * g * t) * t; - d->position[2] = d->zmax; - - d->rotation[1] = 0.0; -} - -#define normalizeQ(i) ((i) >= glhanoi->trailQSize ? (i) - glhanoi->trailQSize : (i)) -#define normalizeQNeg(i) ((i) < 0 ? (i) + glhanoi->trailQSize : (i)) - -/* Add trail point at position posn at time t onto back of trail queue. - Removes old trails if necessary to make room. */ -static void enQTrail(glhcfg *glhanoi, GLfloat *posn) -{ - if (glhanoi->trailQSize && glhanoi->state != MONEY_SHOT) { - TrailPoint *tp = &(glhanoi->trailQ[glhanoi->trailQBack]); - double t = getTime(); - - tp->position[0] = posn[0]; - tp->position[1] = posn[1] + glhanoi->diskHeight; - /* Slight jitter to prevent clashing with other trails */ - tp->position[2] = posn[2] + (glhanoi->move % 23) * 0.01; - tp->startTime = t + TRAIL_START_DELAY; - tp->endTime = t + TRAIL_START_DELAY + glhanoi->trailDuration; - tp->isEnd = False; - - /* Update queue back/front indices */ - glhanoi->trailQBack = normalizeQ(glhanoi->trailQBack + 1); - if (glhanoi->trailQBack == glhanoi->trailQFront) - glhanoi->trailQFront = normalizeQ(glhanoi->trailQFront + 1); - } -} - -/* Mark last trailpoint in queue as the end of a trail. */ -/* was: #define endTrail(glh) ((glh)->trailQ[(glh)->trailQBack].isEnd = True) */ -static void endTrail(glhcfg *glhanoi) { - if (glhanoi->trailQSize) - glhanoi->trailQ[normalizeQNeg(glhanoi->trailQBack - 1)].isEnd = True; -} - -/* Update disk d's position and rotation based on time t. - Returns true iff move is finished. */ -static Bool computePosition(glhcfg *glhanoi, GLfloat t, Disk * d) -{ - Bool finished = False; - - if(t < d->t1) { - upfunc(t, d); - } else if(t < d->t1 + d->t2) { - parafunc(t - d->t1, d); - enQTrail(glhanoi, d->position); - } else { - downfunc(t - d->t1 - d->t2, d); - if(d->position[1] <= d->base1) { - d->position[1] = d->base1; - finished = True; - endTrail(glhanoi); - } - } - return finished; -} - -static void updateView(glhcfg *glhanoi) -{ - double longitude, latitude, radius; - double a, b, c, A, B; - - get_position(glhanoi->the_rotator, NULL, NULL, &radius, - !glhanoi->button_down_p); - get_rotation(glhanoi->the_rotator, &longitude, &latitude, NULL, - !glhanoi->button_down_p); - longitude += glhanoi->camera[0]; - latitude += glhanoi->camera[1]; - radius += glhanoi->camera[2]; - /* FUTURE: tweak this to be smooth: */ - longitude = longitude - floor(longitude); - latitude = latitude - floor(latitude); - radius = radius - floor(radius); - if(latitude > 0.5) { - latitude = 1.0 - latitude; - } - if(radius > 0.5) { - radius = 1.0 - radius; - } - - b = glhanoi->centre[1]; - c = (MIN_CAMERA_RADIUS + - radius * (MAX_CAMERA_RADIUS - MIN_CAMERA_RADIUS)); - A = M_PI / 4.0 * (1.0 - latitude); - a = sqrt(b * b + c * c - 2.0 * b * c * cos(A)); - B = asin(sin(A) * b / a); - glRotatef(-B * 180 / M_PI, 1.0, 0.0, 0.0); - - glTranslatef(0.0f, 0.0f, - -(MIN_CAMERA_RADIUS + - radius * (MAX_CAMERA_RADIUS - MIN_CAMERA_RADIUS))); - glRotatef(longitude * 360.0, 0.0f, 1.0f, 0.0f); - glRotatef(latitude * 180.0, cos(longitude * 2.0 * M_PI), 0.0, - sin(longitude * 2.0 * M_PI)); -} - -static void changeState(glhcfg *glhanoi, State state) -{ - glhanoi->state = state; - glhanoi->startTime = getTime(); -} - -static Bool finishedHanoi(glhcfg *glhanoi) { - /* use different criteria depending on algorithm */ - return (glhanoi->numberOfPoles == 3 ? - glhanoi->move >= glhanoi->numberOfMoves : - solveStackEmpty(glhanoi)); -} - -static void update_glhanoi(glhcfg *glhanoi) -{ - double t = getTime() - glhanoi->startTime; - int i; - Bool done; - - switch (glhanoi->state) { - case START: - if(t < glhanoi->duration) { - break; - } - glhanoi->move = 0; - if(glhanoi->numberOfDisks % 2 == 0) { - swap(&glhanoi->tmp, &glhanoi->dst); - } - glhanoi->magicNumber = 1; - makeMove(glhanoi); - changeState(glhanoi, MOVE_DISK); - break; - - case MOVE_DISK: - if(computePosition(glhanoi, t * glhanoi->currentDisk->speed, glhanoi->currentDisk)) { - changeState(glhanoi, MOVE_FINISHED); - } - break; - - case MOVE_FINISHED: - ++glhanoi->move; - if(!finishedHanoi(glhanoi)) { - makeMove(glhanoi); - changeState(glhanoi, MOVE_DISK); - } else { - glhanoi->duration = FINISH_DURATION; - changeState(glhanoi, FINISHED); - } - break; - - case FINISHED: - if (t < glhanoi->duration) - break; - glhanoi->src = glhanoi->olddst; - glhanoi->dst = glhanoi->oldsrc; - for(i = 0; i < glhanoi->numberOfDisks; ++i) { - Disk *disk = pop(glhanoi, glhanoi->src); - assert(disk != NULL); - moveSetup(glhanoi, disk); - } - for(i = glhanoi->maxDiskIdx; i >= 0; --i) { - push(glhanoi, glhanoi->dst, &glhanoi->disk[i]); - } - changeState(glhanoi, MONEY_SHOT); - break; - - case MONEY_SHOT: - done = True; - for(i = glhanoi->maxDiskIdx; i >= 0; --i) { - double delay = 0.25 * i; - int finished; - - if(t - delay < 0) { - done = False; - continue; - } - - finished = computePosition(glhanoi, t - delay, &glhanoi->disk[i]); - glhanoi->disk[i].rotation[1] = 0.0; - - if(!finished) { - done = False; - } - } - if(done) { - glhanoi->src = glhanoi->oldsrc; - glhanoi->tmp = glhanoi->oldtmp; - glhanoi->dst = glhanoi->olddst; - changeState(glhanoi, START); - } - break; - - case INVALID: - default: - fprintf(stderr, "Invalid state\n"); - break; - } -} - -static void HSVtoRGBf(GLfloat h, GLfloat s, GLfloat v, - GLfloat * r, GLfloat * g, GLfloat * b) -{ - if(s == 0.0) { - *r = v; - *g = v; - *b = v; - } else { - GLfloat i, f, p, q, t; - if(h >= 360.0) { - h = 0.0; - } - h /= 60.0; /* h now in [0,6). */ - i = floor((double)h); /* i now largest integer <= h */ - f = h - i; /* f is no fractional part of h */ - p = v * (1.0 - s); - q = v * (1.0 - (s * f)); - t = v * (1.0 - (s * (1.0 - f))); - switch ((int)i) { - case 0: - *r = v; - *g = t; - *b = p; - break; - case 1: - *r = q; - *g = v; - *b = p; - break; - case 2: - *r = p; - *g = v; - *b = t; - break; - case 3: - *r = p; - *g = q; - *b = v; - break; - case 4: - *r = t; - *g = p; - *b = v; - break; - case 5: - *r = v; - *g = p; - *b = q; - break; - } - } -} - -static void HSVtoRGBv(GLfloat * hsv, GLfloat * rgb) -{ - HSVtoRGBf(hsv[0], hsv[1], hsv[2], &rgb[0], &rgb[1], &rgb[2]); -} - -static void setMaterial(const GLfloat color[3], const GLfloat hlite[3], int shininess) -{ - glColor3fv(color); - glMaterialfv(GL_FRONT, GL_SPECULAR, hlite); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, color); - glMateriali(GL_FRONT, GL_SHININESS, shininess); /* [0,128] */ -} - -/* - * drawTube: I know all this stuff is available in gluQuadrics - * but I'd originally intended to texture the poles with a 3D wood - * texture, but I was having difficulty getting wood... what? Why - * are all you Amercians laughing..? Anyway, I don't know if enough - * people's hardware supports 3D textures, so I didn't bother (xorg - * ATI server doesn't :-( ) - */ -static int drawTube(GLdouble bottomRadius, GLdouble topRadius, - GLdouble bottomThickness, GLdouble topThickness, - GLdouble height, GLuint nSlice, GLuint nLoop) -{ - int polys = 0; - GLfloat y; - GLfloat *cosCache = malloc(sizeof(GLfloat) * nSlice); - GLfloat *sinCache = malloc(sizeof(GLfloat) * nSlice); - GLint slice; - GLuint loop; - GLint lastSlice = nSlice - 1; - GLfloat radius; - GLfloat innerRadius; - - if(bottomThickness > bottomRadius) { - bottomThickness = bottomRadius; - } - if(topThickness > topRadius) { - topThickness = topRadius; - } - if(bottomThickness < 0.0) { - bottomThickness = 0.0; - } - if(topThickness < 0.0) { - topThickness = 0.0; - } -/* if(topRadius >= bottomRadius) { - maxRadius = topRadius; - } else { - maxRadius = bottomRadius; - } */ - - /* bottom */ - y = 0.0; - radius = bottomRadius; - innerRadius = bottomRadius - bottomThickness; - /* innerTexCoordSize = texCoordSize * innerRadius / maxRadius; */ - /* outerTexCoordSize = texCoordSize * radius / maxRadius; */ - /* yTexCoord = minTexCoord; */ - - glBegin(GL_QUAD_STRIP); - - glNormal3f(0.0, -1.0, 0.0); - - /* glTexCoord3f(midTexCoord, yTexCoord, midTexCoord + innerTexCoordSize); */ - glVertex3f(0.0, y, innerRadius); - - /* glTexCoord3f(midTexCoord, yTexCoord, midTexCoord + outerTexCoordSize); */ - glVertex3f(0.0, y, radius); - - for(slice = lastSlice; slice >= 0; --slice) { - GLfloat theta = 2.0 * M_PI * (double)slice / nSlice; - - cosCache[slice] = cos(theta); - sinCache[slice] = sin(theta); - - /* glTexCoord3f(midTexCoord + sinCache[slice] * innerTexCoordSize, */ - /* yTexCoord, */ - /* midTexCoord + cosCache[slice] * innerTexCoordSize); */ - glVertex3f(innerRadius * sinCache[slice], y, - innerRadius * cosCache[slice]); - /* glTexCoord3f(midTexCoord + sinCache[slice] * outerTexCoordSize, */ - /* yTexCoord, */ - /* midTexCoord + cosCache[slice] * outerTexCoordSize); */ - glVertex3f(radius * sinCache[slice], y, radius * cosCache[slice]); - polys++; - } - glEnd(); - - /* middle */ - for(loop = 0; loop < nLoop; ++loop) { - GLfloat lowerRadius = - bottomRadius + (topRadius - - bottomRadius) * (float)loop / (nLoop); - GLfloat upperRadius = - bottomRadius + (topRadius - bottomRadius) * (float)(loop + - 1) / - (nLoop); - GLfloat lowerY = height * (float)loop / (nLoop); - GLfloat upperY = height * (float)(loop + 1) / (nLoop); - GLfloat factor = (topRadius - topThickness) - - (bottomRadius - bottomThickness); - - /* outside */ - glBegin(GL_QUAD_STRIP); - for(slice = 0; slice < nSlice; ++slice) { - glNormal3f(sinCache[slice], 0.0, cosCache[slice]); - glVertex3f(upperRadius * sinCache[slice], upperY, - upperRadius * cosCache[slice]); - glVertex3f(lowerRadius * sinCache[slice], lowerY, - lowerRadius * cosCache[slice]); - polys++; - } - glNormal3f(0.0, 0.0, 1.0); - glVertex3f(0.0, upperY, upperRadius); - glVertex3f(0.0, lowerY, lowerRadius); - polys++; - glEnd(); - - /* inside */ - lowerRadius = bottomRadius - bottomThickness + - factor * (float)loop / (nLoop); - upperRadius = bottomRadius - bottomThickness + - factor * (float)(loop + 1) / (nLoop); - - glBegin(GL_QUAD_STRIP); - glNormal3f(0.0, 0.0, -1.0); - glVertex3f(0.0, upperY, upperRadius); - glVertex3f(0.0, lowerY, lowerRadius); - for(slice = lastSlice; slice >= 0; --slice) { - glNormal3f(-sinCache[slice], 0.0, -cosCache[slice]); - glVertex3f(upperRadius * sinCache[slice], upperY, - upperRadius * cosCache[slice]); - glVertex3f(lowerRadius * sinCache[slice], lowerY, - lowerRadius * cosCache[slice]); - polys++; - } - glEnd(); - } - - /* top */ - y = height; - radius = topRadius; - innerRadius = topRadius - topThickness; - - glBegin(GL_QUAD_STRIP); - glNormal3f(0.0, 1.0, 0.0); - for(slice = 0; slice < nSlice; ++slice) { - glVertex3f(innerRadius * sinCache[slice], y, - innerRadius * cosCache[slice]); - - glVertex3f(radius * sinCache[slice], y, radius * cosCache[slice]); - polys++; - } - glVertex3f(0.0, y, innerRadius); - glVertex3f(0.0, y, radius); - glEnd(); - free (cosCache); - free (sinCache); - return polys; -} - -static int drawPole(GLfloat radius, GLfloat length) -{ - return drawTube(radius, radius, radius, radius, length, NSLICE, NLOOPS); -} - -static int drawDisk3D(GLdouble inner_radius, GLdouble outer_radius, - GLdouble height) -{ - return drawTube(outer_radius, outer_radius, outer_radius - inner_radius, - outer_radius - inner_radius, height, NSLICE, NLOOPS); -} - -/* used for drawing base */ -static int drawCuboid(GLfloat length, GLfloat width, GLfloat height) -{ - GLfloat xmin = -length / 2.0f; - GLfloat xmax = length / 2.0f; - GLfloat zmin = -width / 2.0f; - GLfloat zmax = width / 2.0f; - GLfloat ymin = 0.0f; - GLfloat ymax = height; - int polys = 0; - - glBegin(GL_QUADS); - /* front */ - glNormal3fv(front); - glVertex3f(xmin, ymin, zmax); /* 0 */ - glVertex3f(xmax, ymin, zmax); /* 1 */ - glVertex3f(xmax, ymax, zmax); /* 2 */ - glVertex3f(xmin, ymax, zmax); /* 3 */ - polys++; - /* right */ - glNormal3fv(right); - glVertex3f(xmax, ymin, zmax); /* 1 */ - glVertex3f(xmax, ymin, zmin); /* 5 */ - glVertex3f(xmax, ymax, zmin); /* 6 */ - glVertex3f(xmax, ymax, zmax); /* 2 */ - polys++; - /* back */ - glNormal3fv(back); - glVertex3f(xmax, ymin, zmin); /* 5 */ - glVertex3f(xmin, ymin, zmin); /* 4 */ - glVertex3f(xmin, ymax, zmin); /* 7 */ - glVertex3f(xmax, ymax, zmin); /* 6 */ - polys++; - /* left */ - glNormal3fv(left); - glVertex3f(xmin, ymin, zmin); /* 4 */ - glVertex3f(xmin, ymin, zmax); /* 0 */ - glVertex3f(xmin, ymax, zmax); /* 3 */ - glVertex3f(xmin, ymax, zmin); /* 7 */ - polys++; - /* top */ - glNormal3fv(up); - glVertex3f(xmin, ymax, zmax); /* 3 */ - glVertex3f(xmax, ymax, zmax); /* 2 */ - glVertex3f(xmax, ymax, zmin); /* 6 */ - glVertex3f(xmin, ymax, zmin); /* 7 */ - polys++; - /* bottom */ - glNormal3fv(down); - glVertex3f(xmin, ymin, zmin); /* 4 */ - glVertex3f(xmax, ymin, zmin); /* 5 */ - glVertex3f(xmax, ymin, zmax); /* 1 */ - glVertex3f(xmin, ymin, zmax); /* 0 */ - polys++; - glEnd(); - return polys; -} - -/* Set normal vector in xz plane, based on rotation around center. */ -static void setNormalV(glhcfg *glhanoi, GLfloat theta, int y1, int y2, int r1) { - if (y1 == y2) /* up/down */ - glNormal3f(0.0, y1 ? 1.0 : -1.0, 0.0); - else if (!r1) /* inward */ - glNormal3f(-cos(theta), 0.0, -sin(theta)); - else /* outward */ - glNormal3f(cos(theta), 0.0, sin(theta)); -} - -/* y1, r1, y2, r2 are indices into y, r, beg, end */ -static int drawBaseStrip(glhcfg *glhanoi, int y1, int r1, int y2, int r2, - GLfloat y[2], GLfloat r[2], GLfloat beg[2][2], GLfloat end[2][2]) { - int i; - GLfloat theta, costh, sinth, x[2], z[2]; - GLfloat theta1 = (M_PI * 2) / (glhanoi->numberOfPoles + 1); - - glBegin(GL_QUAD_STRIP); - - /* beginning edge */ - glVertex3f(beg[r1][0], y[y1], beg[r1][1]); - glVertex3f(beg[r2][0], y[y2], beg[r2][1]); - setNormalV(glhanoi, theta1, y1, y2, r1); - - for (i = 1; i < glhanoi->numberOfPoles; i++) { - theta = theta1 * (i + 0.5); - costh = cos(theta); - sinth = sin(theta); - x[0] = costh * r[0]; - x[1] = costh * r[1]; - z[0] = sinth * r[0]; - z[1] = sinth * r[1]; - - glVertex3f(x[r1], y[y1], z[r1]); - glVertex3f(x[r2], y[y2], z[r2]); - - setNormalV(glhanoi, theta1 * (i + 1), y1, y2, r1); - } - - /* end edge */ - glVertex3f(end[r1][0], y[y1], end[r1][1]); - glVertex3f(end[r2][0], y[y2], end[r2][1]); - setNormalV(glhanoi, glhanoi->numberOfPoles, y1, y2, r1); - - glEnd(); - return glhanoi->numberOfPoles; -} - -/* Draw base such that poles are distributed around a regular polygon. */ -static int drawRoundBase(glhcfg *glhanoi) { - int polys = 0; - GLfloat theta, sinth, costh; - - /* - r[0] = (minimum) inner radius of base at vertices - r[1] = (minimum) outer radius of base at vertices - y[0] = bottom of base - y[1] = top of base */ - GLfloat r[2], y[2]; - /* positions of end points: beginning, end. - beg[0] is inner corner of beginning of base, beg[1] is outer corner. - beg[i][0] is x, [i][1] is z. */ - GLfloat beg[2][2], end[2][2], begNorm, endNorm; - /* ratio of radius at base vertices to ratio at poles */ - GLfloat longer = 1.0 / cos(M_PI / (glhanoi->numberOfPoles + 1)); - - r[0] = (glhanoi->poleDist - glhanoi->maxDiskRadius) * longer; - r[1] = (glhanoi->poleDist + glhanoi->maxDiskRadius) * longer; - y[0] = 0; - y[1] = glhanoi->baseHeight; - - /* compute beg, end. Make the ends square. */ - theta = M_PI * 2 / (glhanoi->numberOfPoles + 1); - - costh = cos(theta); - sinth = sin(theta); - beg[0][0] = (glhanoi->poleDist - glhanoi->maxDiskRadius) * costh + - glhanoi->maxDiskRadius * sinth; - beg[1][0] = (glhanoi->poleDist + glhanoi->maxDiskRadius) * costh + - glhanoi->maxDiskRadius * sinth; - beg[0][1] = (glhanoi->poleDist - glhanoi->maxDiskRadius) * sinth - - glhanoi->maxDiskRadius * costh; - beg[1][1] = (glhanoi->poleDist + glhanoi->maxDiskRadius) * sinth - - glhanoi->maxDiskRadius * costh; - begNorm = theta - M_PI * 0.5; - - theta = M_PI * 2 * glhanoi->numberOfPoles / (glhanoi->numberOfPoles + 1); - - costh = cos(theta); - sinth = sin(theta); - end[0][0] = (glhanoi->poleDist - glhanoi->maxDiskRadius) * costh - - glhanoi->maxDiskRadius * sinth; - end[1][0] = (glhanoi->poleDist + glhanoi->maxDiskRadius) * costh - - glhanoi->maxDiskRadius * sinth; - end[0][1] = (glhanoi->poleDist - glhanoi->maxDiskRadius) * sinth + - glhanoi->maxDiskRadius * costh; - end[1][1] = (glhanoi->poleDist + glhanoi->maxDiskRadius) * sinth + - glhanoi->maxDiskRadius * costh; - endNorm = theta + M_PI * 0.5; - - /* bottom: never seen - polys = drawBaseStrip(glhanoi, 0, 0, 0, 1, y, r, beg, end); */ - /* outside edge */ - polys += drawBaseStrip(glhanoi, 0, 1, 1, 1, y, r, beg, end); - /* top */ - polys += drawBaseStrip(glhanoi, 1, 1, 1, 0, y, r, beg, end); - /* inside edge */ - polys += drawBaseStrip(glhanoi, 1, 0, 0, 0, y, r, beg, end); - - /* Draw ends */ - glBegin(GL_QUADS); - - glVertex3f(beg[0][0], y[1], beg[0][1]); - glVertex3f(beg[1][0], y[1], beg[1][1]); - glVertex3f(beg[1][0], y[0], beg[1][1]); - glVertex3f(beg[0][0], y[0], beg[0][1]); - glNormal3f(cos(begNorm), 0, sin(begNorm)); - - glVertex3f(end[0][0], y[0], end[0][1]); - glVertex3f(end[1][0], y[0], end[1][1]); - glVertex3f(end[1][0], y[1], end[1][1]); - glVertex3f(end[0][0], y[1], end[0][1]); - glNormal3f(cos(endNorm), 0, sin(endNorm)); - - polys += 2; - - glEnd(); - - return polys; -} - -static int drawDisks(glhcfg *glhanoi) -{ - int i; - int polys = 0; - - glPushMatrix(); - glTranslatef(0.0f, glhanoi->baseHeight, 0.0f); - for(i = glhanoi->maxDiskIdx; i >= 0; i--) { - Disk *disk = &glhanoi->disk[i]; - GLfloat *pos = disk->position; - GLfloat *rot = disk->rotation; - - glPushMatrix(); - glTranslatef(pos[0], pos[1], pos[2]); - if(rot[1] != 0.0) { - glTranslatef(0.0, glhanoi->diskHeight / 2.0, 0.0); - /* rotate around different axis depending on phi */ - if (disk->phi != 0.0) - glRotatef(-disk->phi, 0.0, 1.0, 0.0); - glRotatef(rot[1], 0.0, 0.0, 1.0); - if (disk->phi != 0.0) - glRotatef(disk->phi, 0.0, 1.0, 0.0); - glTranslatef(0.0, -glhanoi->diskHeight / 2.0, 0.0); - } - glCallList(disk->displayList); - polys += disk->polys; - glPopMatrix(); - } - glPopMatrix(); - return polys; -} - -static GLfloat getDiskRadius(glhcfg *glhanoi, int i) -{ - GLfloat retVal = glhanoi->maxDiskRadius * - ((GLfloat) i + 3.0) / (glhanoi->numberOfDisks + 3.0); - return retVal; -} - -static void initData(glhcfg *glhanoi) -{ - int i; - GLfloat sinPiOverNP; - - glhanoi->baseLength = BASE_LENGTH; - if (glhanoi->layoutLinear) { - glhanoi->maxDiskRadius = glhanoi->baseLength / - (2 * 0.95 * glhanoi->numberOfPoles); - } else { - sinPiOverNP = sin(M_PI / (glhanoi->numberOfPoles + 1)); - glhanoi->maxDiskRadius = (sinPiOverNP * glhanoi->baseLength * 0.5 * 0.95) / (1 + sinPiOverNP); - } - - glhanoi->poleDist = glhanoi->baseLength * 0.5 - glhanoi->maxDiskRadius; - glhanoi->poleRadius = glhanoi->maxDiskRadius / (glhanoi->numberOfDisks + 3.0); - /* fprintf(stderr, "Debug: baseL = %f, maxDiskR = %f, poleR = %f\n", - glhanoi->baseLength, glhanoi->maxDiskRadius, glhanoi->poleRadius); */ - glhanoi->baseWidth = 2.0 * glhanoi->maxDiskRadius; - glhanoi->poleOffset = 2.0 * getDiskRadius(glhanoi, glhanoi->maxDiskIdx); - glhanoi->diskHeight = 2.0 * glhanoi->poleRadius; - glhanoi->baseHeight = 2.0 * glhanoi->poleRadius; - glhanoi->poleHeight = glhanoi->numberOfDisks * - glhanoi->diskHeight + glhanoi->poleRadius; - /* numberOfMoves only applies if numberOfPoles = 3 */ - glhanoi->numberOfMoves = (1 << glhanoi->numberOfDisks) - 1; - /* use golden ratio */ - glhanoi->boardSize = glhanoi->baseLength * 0.5 * (1.0 + sqrt(5.0)); - - glhanoi->pole = (Pole *)calloc(glhanoi->numberOfPoles, sizeof(Pole)); - checkAllocAndExit(!!glhanoi->pole, "poles"); - - for(i = 0; i < glhanoi->numberOfPoles; i++) { - checkAllocAndExit( - !!(glhanoi->pole[i].data = calloc(glhanoi->numberOfDisks, sizeof(Disk *))), - "disk stack"); - glhanoi->pole[i].size = glhanoi->numberOfDisks; - } - checkAllocAndExit( - !!(glhanoi->diskPos = calloc(glhanoi->numberOfDisks, sizeof(float))), - "diskPos"); - - if (glhanoi->trailQSize) { - glhanoi->trailQ = (TrailPoint *)calloc(glhanoi->trailQSize, sizeof(TrailPoint)); - checkAllocAndExit(!!glhanoi->trailQ, "trail queue"); - } else glhanoi->trailQ = (TrailPoint *)NULL; - glhanoi->trailQFront = glhanoi->trailQBack = 0; - - glhanoi->the_rotator = make_rotator(0.1, 0.025, 0, 1, 0.005, False); - /* or glhanoi->the_rotator = make_rotator(0.025, 0.025, 0.025, 0.5, 0.005, False); */ - glhanoi->button_down_p = False; - - glhanoi->src = glhanoi->oldsrc = 0; - glhanoi->tmp = glhanoi->oldtmp = 1; - glhanoi->dst = glhanoi->olddst = glhanoi->numberOfPoles - 1; - - if (glhanoi->numberOfPoles > 3) { - glhanoi->solveStackSize = glhanoi->numberOfDisks + 2; - glhanoi->solveStack = (SubProblem *)calloc(glhanoi->solveStackSize, sizeof(SubProblem)); - checkAllocAndExit(!!glhanoi->solveStack, "solving stack"); - glhanoi->solveStackIdx = 0; - } -} - -static void initView(glhcfg *glhanoi) -{ - glhanoi->camera[0] = 0.0; - glhanoi->camera[1] = 0.0; - glhanoi->camera[2] = 0.0; - glhanoi->centre[0] = 0.0; - glhanoi->centre[1] = glhanoi->poleHeight * 3.0; - glhanoi->centre[2] = 0.0; -} - -/* - * noise_improved.c - based on ImprovedNoise.java - * JAVA REFERENCE IMPLEMENTATION OF IMPROVED NOISE - COPYRIGHT 2002 KEN PERLIN. - */ -static double fade(double t) -{ - return t * t * t * (t * (t * 6 - 15) + 10); -} - -static double grad(int hash, double x, double y, double z) -{ - int h = hash & 15; /* CONVERT LO 4 BITS OF HASH CODE */ - double u = h < 8 ? x : y, /* INTO 12 GRADIENT DIRECTIONS. */ - v = h < 4 ? y : h == 12 || h == 14 ? x : z; - return ((h & 1) == 0 ? u : -u) + ((h & 2) == 0 ? v : -v); -} - -static const int permutation[] = { 151, 160, 137, 91, 90, 15, - 131, 13, 201, 95, 96, 53, 194, 233, 7, 225, 140, 36, 103, 30, 69, 142, - 8, 99, 37, 240, 21, 10, 23, 190, 6, 148, 247, 120, 234, 75, 0, 26, - 197, 62, 94, 252, 219, 203, 117, 35, 11, 32, 57, 177, 33, 88, 237, - 149, 56, 87, 174, 20, 125, 136, 171, 168, 68, 175, 74, 165, 71, - 134, 139, 48, 27, 166, 77, 146, 158, 231, 83, 111, 229, 122, 60, - 211, 133, 230, 220, 105, 92, 41, 55, 46, 245, 40, 244, 102, 143, - 54, 65, 25, 63, 161, 1, 216, 80, 73, 209, 76, 132, 187, 208, 89, - 18, 169, 200, 196, 135, 130, 116, 188, 159, 86, 164, 100, 109, 198, - 173, 186, 3, 64, 52, 217, 226, 250, 124, 123, 5, 202, 38, 147, 118, - 126, 255, 82, 85, 212, 207, 206, 59, 227, 47, 16, 58, 17, 182, 189, - 28, 42, 223, 183, 170, 213, 119, 248, 152, 2, 44, 154, 163, 70, - 221, 153, 101, 155, 167, 43, 172, 9, 129, 22, 39, 253, 19, 98, 108, - 110, 79, 113, 224, 232, 178, 185, 112, 104, 218, 246, 97, 228, 251, - 34, 242, 193, 238, 210, 144, 12, 191, 179, 162, 241, 81, 51, 145, - 235, 249, 14, 239, 107, 49, 192, 214, 31, 181, 199, 106, 157, 184, - 84, 204, 176, 115, 121, 50, 45, 127, 4, 150, 254, 138, 236, 205, - 93, 222, 114, 67, 29, 24, 72, 243, 141, 128, 195, 78, 66, 215, 61, - 156, 180 -}; - -static void initNoise(glhcfg *glhanoi) -{ - int i; - for(i = 0; i < 256; i++) - glhanoi->p[256 + i] = glhanoi->p[i] = permutation[i]; -} - -static double improved_noise(glhcfg *glhanoi, double x, double y, double z) -{ - double u, v, w; - int A, AA, AB, B, BA, BB; - int X = (int)floor(x) & 255, /* FIND UNIT CUBE THAT */ - Y = (int)floor(y) & 255, /* CONTAINS POINT. */ - Z = (int)floor(z) & 255; - if(!glhanoi->noise_initted) { - initNoise(glhanoi); - glhanoi->noise_initted = 1; - } - x -= floor(x); /* FIND RELATIVE X,Y,Z */ - y -= floor(y); /* OF POINT IN CUBE. */ - z -= floor(z); - u = fade(x), /* COMPUTE FADE CURVES */ - v = fade(y), /* FOR EACH OF X,Y,Z. */ - w = fade(z); - A = glhanoi->p[X] + Y; - AA = glhanoi->p[A] + Z; - AB = glhanoi->p[A + 1] + Z, /* HASH COORDINATES OF */ - B = glhanoi->p[X + 1] + Y; - BA = glhanoi->p[B] + Z; - BB = glhanoi->p[B + 1] + Z; /* THE 8 CUBE CORNERS, */ - return lerp(w, lerp(v, lerp(u, grad(glhanoi->p[AA], x, y, z),/* AND ADD */ - grad(glhanoi->p[BA], x - 1, y, z)),/* BLENDED */ - lerp(u, grad(glhanoi->p[AB], x, y - 1, z),/* RESULTS */ - grad(glhanoi->p[BB], x - 1, y - 1, z))),/* FROM 8 CORNERS */ - lerp(v, lerp(u, grad(glhanoi->p[AA + 1], x, y, z - 1), grad(glhanoi->p[BA + 1], x - 1, y, z - 1)), /* OF CUBE */ - lerp(u, grad(glhanoi->p[AB + 1], x, y - 1, z - 1), - grad(glhanoi->p[BB + 1], x - 1, y - 1, z - 1)))); -} - -/* - * end noise_improved.c - based on ImprovedNoise.java - */ - -struct tex_col_t { - GLuint *colours; - /* GLfloat *points; */ - unsigned int ncols; -}; -typedef struct tex_col_t tex_col_t; - -static GLubyte *makeTexture(glhcfg *glhanoi, int x_size, int y_size, int z_size, - GLuint(*texFunc) (glhcfg *, double, double, double, - tex_col_t *), tex_col_t * colours) -{ - int i, j, k; - GLuint *textureData; - GLuint *texturePtr; - double x, y, z; - double xi, yi, zi; - - /* As we use GL_RGBA format, we must assign 4 bytes per element */ - if((textureData = - calloc(x_size * y_size * z_size, sizeof(*texturePtr))) == NULL) { - return NULL; - } - - xi = 1.0 / x_size; - yi = 1.0 / y_size; - zi = 1.0 / z_size; - - z = 0.0; - texturePtr = textureData; - for(k = 0; k < z_size; k++, z += zi) { - y = 0.0; - for(j = 0; j < y_size; j++, y += yi) { - x = 0.0; - for(i = 0; i < x_size; i++, x += xi) { - *texturePtr = texFunc(glhanoi, x, y, z, colours); - ++texturePtr; - } - } - } - return (GLubyte *)textureData; -} - -static void freeTexCols(tex_col_t*p) -{ - free(p->colours); - free(p); -} - -static tex_col_t *makeMarbleColours(void) -{ - tex_col_t *marbleColours; - int ncols = 2; - - marbleColours = malloc(sizeof(tex_col_t)); - if(marbleColours == NULL) return NULL; - marbleColours->colours = calloc(sizeof(GLuint), ncols); - if(marbleColours->colours == NULL) return NULL; - marbleColours->ncols = ncols; - - marbleColours->colours[0] = 0x3f3f3f3f; - marbleColours->colours[1] = 0xffffffff; - - return marbleColours; -} - -static double turb(glhcfg *glhanoi, double x, double y, double z, int octaves) -{ - int oct, freq = 1; - double r = 0.0; - - for(oct = 0; oct < octaves; ++oct) { - r += fabs(improved_noise(glhanoi, freq * x, freq * y, freq * z)) / freq; - freq <<= 1; - } - return r / 2.0; -} - -static void perturb(glhcfg *glhanoi, double *x, double *y, double *z, double scale) -{ - double t = scale * turb(glhanoi, *x, *y, *z, 4); - *x += t; - *y += t; - *z += t; -} - -static double f_m(double x, double y, double z) -{ - return sin(3.0 * M_PI * x); -} - -static GLuint C_m(double x, const tex_col_t * tex_cols) -{ - int r = tex_cols->colours[0] & 0xff; - int g = tex_cols->colours[0] >> 8 & 0xff; - int b = tex_cols->colours[0] >> 16 & 0xff; - double factor; - int r1, g1, b1; - x = x - floor(x); - - factor = (1.0 + sin(2.0 * M_PI * x)) / 2.0; - - r1 = (tex_cols->colours[1] & 0xff); - g1 = (tex_cols->colours[1] >> 8 & 0xff); - b1 = (tex_cols->colours[1] >> 16 & 0xff); - - r += (int)(factor * (r1 - r)); - g += (int)(factor * (g1 - g)); - b += (int)(factor * (b1 - b)); - - return 0xff000000 | (b << 16) | (g << 8) | r; -} - - -static GLuint makeMarbleTexture(glhcfg *glhanoi, double x, double y, double z, tex_col_t * colours) -{ - perturb(glhanoi, &x, &y, &z, MARBLE_SCALE); - return C_m(f_m(x, y, z), colours); -} - -static void setTexture(glhcfg *glhanoi, int n) -{ - glBindTexture(GL_TEXTURE_2D, glhanoi->textureNames[n]); -} - -/* returns 1 on failure, 0 on success */ -static int makeTextures(glhcfg *glhanoi) -{ - GLubyte *marbleTexture; - tex_col_t *marbleColours; - - glGenTextures(N_TEXTURES, glhanoi->textureNames); - - if((marbleColours = makeMarbleColours()) == NULL) { - return 1; - } - if((marbleTexture = - makeTexture(glhanoi, MARBLE_TEXTURE_SIZE, MARBLE_TEXTURE_SIZE, 1, - makeMarbleTexture, marbleColours)) == NULL) { - return 1; - } - - glBindTexture(GL_TEXTURE_2D, glhanoi->textureNames[0]); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, - MARBLE_TEXTURE_SIZE, MARBLE_TEXTURE_SIZE, 0, - GL_RGBA, GL_UNSIGNED_BYTE, marbleTexture); - free(marbleTexture); - freeTexCols(marbleColours); - - return 0; -} - -static void initFloor(glhcfg *glhanoi) -{ - int i, j; - float tileSize = glhanoi->boardSize / BOARD_SQUARES; - float x0, x1, z0, z1; - float tx0, tx1, tz0, tz1; - const float *col = cWhite; - float texIncr = 1.0 / BOARD_SQUARES; - - glhanoi->floorpolys = 0; - checkAllocAndExit(!!(glhanoi->floorList = glGenLists(1)), "floor display list"); - glNewList(glhanoi->floorList, GL_COMPILE); - x0 = -glhanoi->boardSize / 2.0; - tx0 = 0.0f; - setMaterial(col, cWhite, 128); - setTexture(glhanoi, 0); - glNormal3fv(up); - for(i = 0; i < BOARD_SQUARES; i++, x0 += tileSize, tx0 += texIncr) { - x1 = x0 + tileSize; - tx1 = tx0 + texIncr; - z0 = -glhanoi->boardSize / 2.0; - tz0 = 0.0f; - for(j = 0; j < BOARD_SQUARES; j++, z0 += tileSize, tz0 += texIncr) { - int colIndex = (i + j) & 0x1; - - z1 = z0 + tileSize; - tz1 = tz0 + texIncr; - - if(colIndex) - col = cWhite; - else - col = cBlack; - - setMaterial(col, cWhite, 100); - - glBegin(GL_QUADS); - - glTexCoord2d(tx0, tz0); - glVertex3f(x0, 0.0, z0); - - glTexCoord2d(tx0, tz1); - glVertex3f(x0, 0.0, z1); - - glTexCoord2d(tx1, tz1); - glVertex3f(x1, 0.0, z1); - - glTexCoord2d(tx1, tz0); - glVertex3f(x1, 0.0, z0); - glhanoi->floorpolys++; - glEnd(); - } - } - glEndList(); -} - -static void initBase(glhcfg *glhanoi) -{ - checkAllocAndExit(!!(glhanoi->baseList = glGenLists(1)), "tower bases display list"); - - glNewList(glhanoi->baseList, GL_COMPILE); - setMaterial(baseColor, cWhite, 50); - if (glhanoi->layoutLinear) { - glhanoi->basepolys = drawCuboid(glhanoi->baseLength, glhanoi->baseWidth, - glhanoi->baseHeight); - } else { - glhanoi->basepolys = drawRoundBase(glhanoi); - } - glEndList(); -} - -static void initTowers(glhcfg *glhanoi) -{ - int i; - - checkAllocAndExit(!!(glhanoi->poleList = glGenLists(1)), "poles display list\n"); - - glNewList(glhanoi->poleList, GL_COMPILE); - /* glTranslatef(-glhanoi->poleOffset * (glhanoi->numberOfPoles - 1.0f) * 0.5f, glhanoi->baseHeight, 0.0f); */ - setMaterial(poleColor, cWhite, 50); - for (i = 0; i < glhanoi->numberOfPoles; i++) { - GLfloat *p = glhanoi->pole[i].position; - GLfloat rad = (M_PI * 2.0 * (i + 1)) / (glhanoi->numberOfPoles + 1); - - p[1] = glhanoi->baseHeight; - - if (glhanoi->layoutLinear) { - /* Linear: */ - p[0] = -glhanoi->poleOffset * ((glhanoi->numberOfPoles - 1) * 0.5f - i); - p[2] = 0.0f; - } else { - /* Circular layout: */ - p[0] = cos(rad) * glhanoi->poleDist; - p[2] = sin(rad) * glhanoi->poleDist; - } - - glPushMatrix(); - glTranslatef(p[0], p[1], p[2]); - glhanoi->polepolys = drawPole(glhanoi->poleRadius, glhanoi->poleHeight); - glPopMatrix(); - - } - glEndList(); -} - -/* Parameterized hue based on input 0.0 - 1.0. */ -static double cfunc(double x) -{ -#define COMP < - if(x < 2.0 / 7.0) { - return (1.0 / 12.0) / (1.0 / 7.0) * x; - } - if(x < 3.0 / 7.0) { - /* (7x - 1) / 6 */ - return (1.0 + 1.0 / 6.0) * x - 1.0 / 6.0; - } - if(x < 4.0 / 7.0) { - return (2.0 + 1.0 / 3.0) * x - 2.0 / 3.0; - } - if(x < 5.0 / 7.0) { - return (1.0 / 12.0) / (1.0 / 7.0) * x + 1.0 / 3.0; - } - return (1.0 / 12.0) / (1.0 / 7.0) * x + 1.0 / 3.0; -} - -static void initDisks(glhcfg *glhanoi) -{ - int i; - glhanoi->disk = (Disk *) calloc(glhanoi->numberOfDisks, sizeof(Disk)); - checkAllocAndExit(!!glhanoi->disk, "disks"); - - for(i = glhanoi->maxDiskIdx; i >= 0; i--) { - GLfloat height = (GLfloat) (glhanoi->maxDiskIdx - i); - double f = cfunc((GLfloat) i / (GLfloat) glhanoi->numberOfDisks); - GLfloat diskColor = f * 360.0; - GLfloat color[3]; - Disk *disk = &glhanoi->disk[i]; - - disk->id = i; - disk->position[0] = glhanoi->pole[0].position[0]; /* -glhanoi->poleOffset * (glhanoi->numberOfPoles - 1.0f) * 0.5; */ - disk->position[1] = glhanoi->diskHeight * height; - disk->position[2] = glhanoi->pole[0].position[2]; - disk->rotation[0] = 0.0; - disk->rotation[1] = 0.0; - disk->rotation[2] = 0.0; - disk->polys = 0; - - /* make smaller disks move faster */ - disk->speed = lerp(((double)glhanoi->numberOfDisks - i) / glhanoi->numberOfDisks, - 1.0, glhanoi->speed); - /* fprintf(stderr, "disk id: %d, alpha: %0.2f, speed: %0.2f\n", disk->id, - ((double)(glhanoi->maxDiskIdx - i)) / glhanoi->numberOfDisks, disk->speed); */ - - color[0] = diskColor; - color[1] = 1.0f; - color[2] = 1.0f; - HSVtoRGBv(color, color); - - checkAllocAndExit(!!(disk->displayList = glGenLists(1)), "disk display list"); - glNewList(disk->displayList, GL_COMPILE); - setMaterial(color, cWhite, 100.0); - disk->polys += drawDisk3D(glhanoi->poleRadius, - getDiskRadius(glhanoi, i), - glhanoi->diskHeight); - /*fprintf(stderr, "Debug: disk %d has radius %f\n", i, - getDiskRadius(glhanoi, i)); */ - glEndList(); - } - for(i = glhanoi->maxDiskIdx; i >= 0; --i) { - GLfloat height = (GLfloat) (glhanoi->maxDiskIdx - i); - int h = glhanoi->maxDiskIdx - i; - glhanoi->diskPos[h] = glhanoi->diskHeight * height; - push(glhanoi, glhanoi->src, &glhanoi->disk[i]); - } -} - -static void initLights(Bool state) -{ - if(state) { - glLightfv(GL_LIGHT0, GL_POSITION, pos0); - glLightfv(GL_LIGHT0, GL_AMBIENT, amb0); - glLightfv(GL_LIGHT0, GL_DIFFUSE, dif0); - glLightfv(GL_LIGHT0, GL_SPECULAR, spc0); - - glLightfv(GL_LIGHT1, GL_POSITION, pos1); - glLightfv(GL_LIGHT1, GL_AMBIENT, amb1); - glLightfv(GL_LIGHT1, GL_DIFFUSE, dif1); - glLightfv(GL_LIGHT1, GL_SPECULAR, spc1); - - glEnable(GL_LIGHTING); - glEnable(GL_LIGHT0); - glEnable(GL_LIGHT1); - } else { - glDisable(GL_LIGHTING); - } -} - -static int drawFloor(glhcfg *glhanoi) -{ - glCallList(glhanoi->floorList); - return glhanoi->floorpolys; -} - -static int drawTowers(glhcfg *glhanoi) -{ - glCallList(glhanoi->baseList); - glCallList(glhanoi->poleList); - return glhanoi->basepolys + glhanoi->polepolys; -} - -static int drawTrails1(glhcfg *glhanoi, double t, double thickness, double alpha) { - int i, prev = -1, lines = 0; - Bool fresh = False; - GLfloat trailDurInv = 1.0f / glhanoi->trailDuration; - - glLineWidth(thickness); - - glBegin(GL_LINES); - - for (i = glhanoi->trailQFront; - i != glhanoi->trailQBack; - i = normalizeQ(i + 1)) { - TrailPoint *tqi = &(glhanoi->trailQ[i]); - - if (!fresh && t > tqi->endTime) { - glhanoi->trailQFront = normalizeQ(i + 1); - } else { - if (tqi->startTime > t) break; - /* Found trails that haven't timed out. */ - if (!fresh) fresh = True; - if (prev > -1) { - /* Fade to invisible with age */ - trailColor[3] = alpha * (tqi->endTime - t) * trailDurInv; - /* Can't use setMaterial(trailColor, cBlack, 0) because our color needs an alpha value. */ - glColor4fv(trailColor); - glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, trailColor); - /* FUTURE: to really do this right, trails should be drawn in back-to-front - order, so that blending is done correctly. - Currently it looks poor when a faded trail is in front of, or coincident with, - a bright trail but is drawn first. - I think for now it's good enough to recommend shorter trails so they - never/rarely overlap. - A jitter per trail arc would also mitigate this problem, to a lesser degree. */ - glVertex3fv(glhanoi->trailQ[prev].position); - glVertex3fv(glhanoi->trailQ[i].position); - lines++; - } - if (glhanoi->trailQ[i].isEnd) - prev = -1; - else - prev = i; - } - } - - glEnd(); - - return lines; -} - -static int drawTrails(glhcfg *glhanoi) { - int lines = 0; - double t = getTime(); - - glEnable (GL_BLEND); - glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glMaterialfv(GL_FRONT, GL_SPECULAR, cBlack); - glMateriali(GL_FRONT, GL_SHININESS, 0); - - /* Draw them twice, with different widths and opacities, to make them smoother. */ - lines = drawTrails1(glhanoi, t, 1.0, 0.75); - lines += drawTrails1(glhanoi, t, 2.5, 0.5); - - glDisable (GL_BLEND); - - /* fprintf(stderr, "Drew trails: %d lines\n", lines); */ - return lines; -} - -/* Window management, etc - */ -ENTRYPOINT void reshape_glhanoi(ModeInfo * mi, int width, int height) -{ - glhcfg *glhanoi = &glhanoi_cfg[MI_SCREEN(mi)]; - double h = (GLfloat) height / (GLfloat) width; - int y = 0; - - if (width > height * 5) { /* tiny window: show middle */ - height = width * 9/16; - y = -height/2; - h = height / (GLfloat) width; - } - - glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *glhanoi->glx_context); - - glViewport(0, y, (GLint) width, (GLint) height); - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - gluPerspective(30.0, 1/h, 1.0, - 2 * MAX_CAMERA_RADIUS); - - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glClear(GL_COLOR_BUFFER_BIT); -} - -ENTRYPOINT void init_glhanoi(ModeInfo * mi) -{ - glhcfg *glhanoi; - MI_INIT(mi, glhanoi_cfg); - - glhanoi = &glhanoi_cfg[MI_SCREEN(mi)]; - glhanoi->glx_context = init_GL(mi); - glhanoi->numberOfDisks = MI_BATCHCOUNT(mi); - - if (glhanoi->numberOfDisks <= 1) - glhanoi->numberOfDisks = 3 + (int) BELLRAND(9); - - /* magicnumber is a bitfield, so we can't have more than 31 discs - on a system with 4-byte ints. */ - if (glhanoi->numberOfDisks >= 8 * sizeof(int)) - glhanoi->numberOfDisks = (8 * sizeof(int)) - 1; - - glhanoi->maxDiskIdx = glhanoi->numberOfDisks - 1; - - glhanoi->numberOfPoles = get_integer_resource(MI_DISPLAY(mi), "poles", "Integer"); - /* Set a number of poles from 3 to numberOfDisks + 1, biased toward lower values, - with probability decreasing linearly. */ - if (glhanoi->numberOfPoles <= 2) - glhanoi->numberOfPoles = 3 + - (int)((1 - sqrt(frand(1.0))) * (glhanoi->numberOfDisks - 1)); - - glhanoi->wire = MI_IS_WIREFRAME(mi); - -# ifdef HAVE_JWZGLES /* #### glPolygonMode other than GL_FILL unimplemented */ - glhanoi->wire = 0; -# endif - - glhanoi->light = light; - glhanoi->fog = fog; - glhanoi->texture = texture; - glhanoi->speed = speed; - glhanoi->trailDuration = trails; - /* set trailQSize based on 60 fps (a maximum, more or less) */ - /* FUTURE: Should clamp framerate to 60 fps? See flurry.c's draw_flurry(). - The only bad effect if we don't is that trail-ends could - show "unnatural" pauses at high fps. */ - glhanoi->trailQSize = (int)(trails * 60.0); - - reshape_glhanoi(mi, MI_WIDTH(mi), MI_HEIGHT(mi)); - - if(glhanoi->wire) { - glhanoi->light = False; - glhanoi->fog = False; - glhanoi->texture = False; - } - - initLights(!glhanoi->wire && glhanoi->light); - checkAllocAndExit(!makeTextures(glhanoi), "textures\n"); - - /* Choose linear or circular layout. Could make this a user option. */ - glhanoi->layoutLinear = (glhanoi->numberOfPoles == 3); - - initData(glhanoi); - initView(glhanoi); - initFloor(glhanoi); - initBase(glhanoi); - initTowers(glhanoi); - initDisks(glhanoi); - - glEnable(GL_DEPTH_TEST); - glEnable(GL_NORMALIZE); - glEnable(GL_CULL_FACE); - glShadeModel(GL_SMOOTH); - if(glhanoi->fog) { - glClearColor(fogcolor[0], fogcolor[1], fogcolor[2], 1.0); - glFogi(GL_FOG_MODE, GL_LINEAR); - glFogfv(GL_FOG_COLOR, fogcolor); - glFogf(GL_FOG_DENSITY, 0.35f); - glHint(GL_FOG_HINT, GL_NICEST); - glFogf(GL_FOG_START, MIN_CAMERA_RADIUS); - glFogf(GL_FOG_END, MAX_CAMERA_RADIUS / 1.9); - glEnable(GL_FOG); - } - - glhanoi->duration = START_DURATION; - changeState(glhanoi, START); -} - -ENTRYPOINT void draw_glhanoi(ModeInfo * mi) -{ - glhcfg *glhanoi = &glhanoi_cfg[MI_SCREEN(mi)]; - Display *dpy = MI_DISPLAY(mi); - Window window = MI_WINDOW(mi); - - if(!glhanoi->glx_context) - return; - - glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *glhanoi->glx_context); - - glPolygonMode(GL_FRONT, glhanoi->wire ? GL_LINE : GL_FILL); - - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - mi->polygon_count = 0; - - glLoadIdentity(); - glRotatef(current_device_rotation(), 0, 0, 1); - - update_glhanoi(glhanoi); - updateView(glhanoi); - - { - GLfloat s = (MI_WIDTH(mi) < MI_HEIGHT(mi) - ? (MI_WIDTH(mi) / (GLfloat) MI_HEIGHT(mi)) - : 1); - glScalef (s, s, s); - } - - if(!glhanoi->wire && glhanoi->texture) { - glEnable(GL_TEXTURE_2D); - } - mi->polygon_count += drawFloor(glhanoi); - glDisable(GL_TEXTURE_2D); - - mi->polygon_count += drawTowers(glhanoi); - mi->polygon_count += drawDisks(glhanoi); - - if (glhanoi->trailQSize) { - /* No polygons, just lines. So ignore the return count. */ - (void)drawTrails(glhanoi); - } - - if(mi->fps_p) { - do_fps(mi); - } - glFinish(); - - glXSwapBuffers(dpy, window); -} - -ENTRYPOINT Bool glhanoi_handle_event(ModeInfo * mi, XEvent * event) -{ - glhcfg *glhanoi = &glhanoi_cfg[MI_SCREEN(mi)]; - - /* #### this is all wrong on iOS -- should be using gltrackball. */ - - if(event->xany.type == ButtonPress && event->xbutton.button == Button1) { - glhanoi->button_down_p = True; - glhanoi->drag_x = event->xbutton.x; - glhanoi->drag_y = event->xbutton.y; - return True; - } else if(event->xany.type == ButtonRelease - && event->xbutton.button == Button1) { - glhanoi->button_down_p = False; - return True; - } else if(event->xany.type == ButtonPress && - (event->xbutton.button == Button4 - || event->xbutton.button == Button5)) { - switch (event->xbutton.button) { - case Button4: - glhanoi->camera[2] += 0.01; - break; - case Button5: - glhanoi->camera[2] -= 0.01; - break; - default: - fprintf(stderr, - "glhanoi: unknown button in mousewheel handler\n"); - } - return True; - } else if(event->xany.type == MotionNotify - && glhanoi_cfg->button_down_p) { - int x_diff, y_diff; - - x_diff = event->xbutton.x - glhanoi->drag_x; - y_diff = event->xbutton.y - glhanoi->drag_y; - - glhanoi->camera[0] = (float)x_diff / (float)MI_WIDTH(mi); - glhanoi->camera[1] = (float)y_diff / (float)MI_HEIGHT(mi); - - return True; - } -#if 0 /* #### doesn't work */ - else if (screenhack_event_helper (MI_DISPLAY(mi), MI_WINDOW(mi), event)) - { - changeState(glhanoi, START); - return True; - } -#endif - return False; -} - -ENTRYPOINT void free_glhanoi(ModeInfo * mi) -{ - glhcfg *glh = &glhanoi_cfg[MI_SCREEN(mi)]; - int i; - int j; - - if (!glh->glx_context) return; - glXMakeCurrent(MI_DISPLAY(mi), MI_WINDOW(mi), *glh->glx_context); - - free_rotator (glh->the_rotator); - if (glh->pole) { - for (i = 0; i < glh->numberOfPoles; i++) - if (glh->pole[i].data) free (glh->pole[i].data); - free (glh->pole); - } - if (glh->diskPos) free (glh->diskPos); - if (glh->trailQ) free (glh->trailQ); - if (glh->solveStack) free (glh->solveStack); - - glDeleteLists(glh->floorList, 1); - glDeleteLists(glh->baseList, 1); - glDeleteLists(glh->poleList, 1); - glDeleteLists(glh->textureNames[0], 2); - for(j = 0; j < glh->numberOfDisks; ++j) { - glDeleteLists(glh->disk[j].displayList, 1); - } - free(glh->disk); - glDeleteTextures (N_TEXTURES, glh->textureNames); -} - -XSCREENSAVER_MODULE ("GLHanoi", glhanoi) - -#endif /* USE_GL */ |
