summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Nusinow <[email protected]>2006-09-24 21:29:21 +0000
committerDavid Nusinow <[email protected]>2006-09-24 21:29:21 +0000
commita0b2543ba165f77ed4764dd0c53956f1b2a0f92f (patch)
treea6fb278cada5b130396da8b8309ec78a42ca2199
parent387acaac6925e42f47031f26360e33a3f30e7312 (diff)
Add mesa demos
-rw-r--r--debian/changelog3
-rw-r--r--debian/control2
-rw-r--r--progs/beos/demo.cpp2
-rw-r--r--progs/demos/Makefile36
-rw-r--r--progs/demos/arbfslight.c61
-rw-r--r--progs/demos/engine.c1293
-rw-r--r--progs/demos/gloss.c75
-rwxr-xr-xprogs/demos/glslnoise.c45
-rw-r--r--progs/demos/pointblast.c5
-rw-r--r--progs/demos/readtex.c454
-rw-r--r--progs/demos/readtex.h26
-rw-r--r--progs/demos/showbuffer.c192
-rw-r--r--progs/demos/showbuffer.h36
-rw-r--r--progs/demos/spriteblast.c6
-rw-r--r--progs/demos/stex3d.c14
-rw-r--r--progs/demos/trackball.c338
-rw-r--r--progs/demos/trackball.h84
-rw-r--r--progs/demos/vao_demo.c330
-rw-r--r--progs/ggi/gears.c2
-rw-r--r--progs/osdemos/Makefile12
-rw-r--r--progs/osdemos/osdemo.c108
-rw-r--r--progs/osdemos/ostest1.c140
-rw-r--r--progs/osdemos/readtex.c454
-rw-r--r--progs/redbook/Makefile2
-rw-r--r--progs/samples/Makefile2
-rw-r--r--progs/samples/readtex.c454
-rw-r--r--progs/windml/ugldrawpix.c2
-rw-r--r--progs/windml/ugltexcyl.c2
-rw-r--r--progs/xdemos/Makefile2
-rw-r--r--progs/xdemos/glxgears2.c522
30 files changed, 4549 insertions, 155 deletions
diff --git a/debian/changelog b/debian/changelog
index e58dd19e9f9..db79d842e2a 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -1,8 +1,9 @@
mesa (6.5.1-0.1) UNRELEASED; urgency=low
* New upstream version
+ * Build-dep on x11proto-gl-dev >= 1.4.8
- -- David Nusinow <[email protected]> Sun, 24 Sep 2006 17:19:55 -0400
+ -- David Nusinow <[email protected]> Sun, 24 Sep 2006 17:23:23 -0400
mesa (6.5.0.cvs.20060524-1.1) unstable; urgency=medium
diff --git a/debian/control b/debian/control
index fd91268235b..63834ba2e0f 100644
--- a/debian/control
+++ b/debian/control
@@ -4,7 +4,7 @@ Priority: optional
Maintainer: Mesa package maintainers <[email protected]>
Uploaders: Marcelo E. Magallon <[email protected]>
Standards-Version: 3.7.2
-Build-Depends: lesstif2-dev, grep-dctrl, debhelper (>> 4), build-essential (>= 11), libdrm-dev (>> 2) [!hurd-i386], libdirectfb-dev, xutils, libexpat-dev, libxxf86vm-dev, libx11-dev, libxext-dev, pkg-config, x11proto-gl-dev, dpkg-dev (>= 1.13.19)
+Build-Depends: lesstif2-dev, grep-dctrl, debhelper (>> 4), build-essential (>= 11), libdrm-dev (>> 2) [!hurd-i386], libdirectfb-dev, xutils, libexpat-dev, libxxf86vm-dev, libx11-dev, libxext-dev, pkg-config, x11proto-gl-dev (>= 1.4.8) , dpkg-dev (>= 1.13.19)
Package: libgl1-mesa-swx11
Section: libs
diff --git a/progs/beos/demo.cpp b/progs/beos/demo.cpp
index 42f316a71f1..6b0b9576d66 100644
--- a/progs/beos/demo.cpp
+++ b/progs/beos/demo.cpp
@@ -1,4 +1,4 @@
-// $Id: demo.cpp,v 1.2 2004-08-14 09:59:16 phoudoin Exp $
+// $Id: demo.cpp,v 1.2 2004/08/14 09:59:16 phoudoin Exp $
// Simple BeOS GLView demo
// Written by Brian Paul
diff --git a/progs/demos/Makefile b/progs/demos/Makefile
index c7a4cc7b828..43d0f17c85f 100644
--- a/progs/demos/Makefile
+++ b/progs/demos/Makefile
@@ -5,13 +5,13 @@ include $(TOP)/configs/current
INCDIR = $(TOP)/include
-OSMESA_LIBS = -L$(LIB_DIR) -lglut -lOSMesa -lGLU -lGL $(APP_LIB_DEPS)
+OSMESA_LIBS = -L$(TOP)/$(LIB_DIR) -lglut -lOSMesa -lGLU -lGL $(APP_LIB_DEPS)
-OSMESA16_LIBS = -L$(LIB_DIR) -lglut -lOSMesa16 -lGLU -lGL $(APP_LIB_DEPS)
+OSMESA16_LIBS = -L$(TOP)/$(LIB_DIR) -lglut -lOSMesa16 -lGLU -lGL $(APP_LIB_DEPS)
-OSMESA32_LIBS = -L$(LIB_DIR) -lglut -lOSMesa32 -lGLU -lGL $(APP_LIB_DEPS)
+OSMESA32_LIBS = -L$(TOP)/$(LIB_DIR) -lglut -lOSMesa32 -lGLU -lGL $(APP_LIB_DEPS)
-LIB_DEP = $(LIB_DIR)/$(GL_LIB_NAME) $(LIB_DIR)/$(GLU_LIB_NAME) $(LIB_DIR)/$(GLUT_LIB_NAME)
+LIB_DEP = $(TOP)/$(LIB_DIR)/$(GL_LIB_NAME) $(TOP)/$(LIB_DIR)/$(GLU_LIB_NAME) $(TOP)/$(LIB_DIR)/$(GLUT_LIB_NAME)
PROGS = \
arbfplight \
@@ -21,6 +21,7 @@ PROGS = \
clearspd \
cubemap \
drawpix \
+ engine \
fire \
fogcoord \
fplight \
@@ -38,7 +39,6 @@ PROGS = \
lodbias \
morph3d \
multiarb \
- occlude \
paltex \
pointblast \
ray \
@@ -60,6 +60,7 @@ PROGS = \
trispd \
tunnel \
tunnel2 \
+ vao_demo \
winpos
@@ -100,6 +101,16 @@ showbuffer.o: showbuffer.c showbuffer.h
$(CC) -c -I$(INCDIR) $(CFLAGS) showbuffer.c
+trackball.c: $(TOP)/progs/util/trackball.c
+ cp $< .
+
+trackball.h: $(TOP)/progs/util/trackball.h
+ cp $< .
+
+trackball.o: trackball.c trackball.h
+ $(CC) -c -I$(INCDIR) $(CFLAGS) trackball.c
+
+
reflect: reflect.o showbuffer.o readtex.o
$(CC) -I$(INCDIR) $(CFLAGS) reflect.o showbuffer.o readtex.o $(APP_LIB_DEPS) -o $@
@@ -113,6 +124,21 @@ shadowtex: shadowtex.o showbuffer.o
shadowtex.o: shadowtex.c showbuffer.h
$(CC) -c -I$(INCDIR) $(CFLAGS) shadowtex.c
+
+gloss: gloss.o trackball.o readtex.o
+ $(CC) -I$(INCDIR) $(CFLAGS) gloss.o trackball.o readtex.o $(APP_LIB_DEPS) -o $@
+
+gloss.o: gloss.c trackball.h
+ $(CC) -c -I$(INCDIR) $(CFLAGS) gloss.c
+
+
+engine: engine.o trackball.o readtex.o
+ $(CC) -I$(INCDIR) $(CFLAGS) engine.o trackball.o readtex.o $(APP_LIB_DEPS) -o $@
+
+engine.o: engine.c trackball.h
+ $(CC) -c -I$(INCDIR) $(CFLAGS) engine.c
+
+
clean:
-rm -f $(PROGS)
-rm -f *.o *~
diff --git a/progs/demos/arbfslight.c b/progs/demos/arbfslight.c
index 30332a3f641..374de568872 100644
--- a/progs/demos/arbfslight.c
+++ b/progs/demos/arbfslight.c
@@ -16,6 +16,7 @@
#include <stdio.h>
#include <stdlib.h>
+#include <math.h>
#include <GL/gl.h>
#include <GL/glut.h>
#include <GL/glext.h>
@@ -56,7 +57,16 @@ static PFNGLATTACHOBJECTARBPROC glAttachObjectARB = NULL;
static PFNGLLINKPROGRAMARBPROC glLinkProgramARB = NULL;
static PFNGLUSEPROGRAMOBJECTARBPROC glUseProgramObjectARB = NULL;
static PFNGLGETUNIFORMLOCATIONARBPROC glGetUniformLocationARB = NULL;
-static PFNGLUNIFORM4FVARBPROC glUniform4fvARB = NULL;
+static PFNGLUNIFORM3FVARBPROC glUniform3fvARB = NULL;
+static PFNGLUNIFORM3FVARBPROC glUniform4fvARB = NULL;
+
+static void normalize (GLfloat *dst, const GLfloat *src)
+{
+ GLfloat len = sqrtf (src[0] * src[0] + src[1] * src[1] + src[2] * src[2]);
+ dst[0] = src[0] / len;
+ dst[1] = src[1] / len;
+ dst[2] = src[2] / len;
+}
static void Redisplay (void)
{
@@ -64,8 +74,11 @@ static void Redisplay (void)
if (pixelLight)
{
+ GLfloat vec[3];
+
glUseProgramObjectARB (program);
- glUniform4fvARB (uLightPos, 1, lightPos);
+ normalize (vec, lightPos);
+ glUniform3fvARB (uLightPos, 1, vec);
glDisable(GL_LIGHTING);
}
else
@@ -186,24 +199,25 @@ static void SpecialKey (int key, int x, int y)
static void Init (void)
{
- static const char *fragShaderText =
- "uniform vec4 lightPos;\n"
- "uniform vec4 diffuse;\n"
- "uniform vec4 specular;\n"
- "void main () {\n"
- " // Compute dot product of light direction and normal vector\n"
- " float dotProd;\n"
- " dotProd = clamp (dot (normalize (lightPos).xyz, normalize (gl_TexCoord[0]).xyz), 0.0, 1.0);\n"
- " // Compute diffuse and specular contributions\n"
- " gl_FragColor = diffuse * dotProd + specular * pow (dotProd, 20.0);\n"
- "}\n"
- ;
- static const char *vertShaderText =
- "void main () {\n"
- " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
- " gl_TexCoord[0] = vec4 (gl_NormalMatrix * gl_Normal, 1.0);\n"
- "}\n"
- ;
+ static const char *fragShaderText =
+ "uniform vec3 lightPos;\n"
+ "uniform vec4 diffuse;\n"
+ "uniform vec4 specular;\n"
+ "varying vec3 normal;\n"
+ "void main () {\n"
+ " // Compute dot product of light direction and normal vector\n"
+ " float dotProd = max (dot (lightPos, normalize (normal)), 0.0);\n"
+ " // Compute diffuse and specular contributions\n"
+ " gl_FragColor = diffuse * dotProd + specular * pow (dotProd, 20.0);\n"
+ "}\n"
+ ;
+ static const char *vertShaderText =
+ "varying vec3 normal;\n"
+ "void main () {\n"
+ " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
+ " normal = gl_NormalMatrix * gl_Normal;\n"
+ "}\n"
+ ;
if (!glutExtensionSupported ("GL_ARB_fragment_shader"))
{
@@ -234,7 +248,8 @@ static void Init (void)
glLinkProgramARB = (PFNGLLINKPROGRAMARBPROC) GETPROCADDRESS ("glLinkProgramARB");
glUseProgramObjectARB = (PFNGLUSEPROGRAMOBJECTARBPROC) GETPROCADDRESS ("glUseProgramObjectARB");
glGetUniformLocationARB = (PFNGLGETUNIFORMLOCATIONARBPROC) GETPROCADDRESS ("glGetUniformLocationARB");
- glUniform4fvARB = (PFNGLUNIFORM4FVARBPROC) GETPROCADDRESS ("glUniform4fvARB");
+ glUniform3fvARB = (PFNGLUNIFORM3FVARBPROC) GETPROCADDRESS ("glUniform3fvARB");
+ glUniform4fvARB = (PFNGLUNIFORM3FVARBPROC) GETPROCADDRESS ("glUniform4fvARB");
fragShader = glCreateShaderObjectARB (GL_FRAGMENT_SHADER_ARB);
glShaderSourceARB (fragShader, 1, &fragShaderText, NULL);
@@ -254,8 +269,8 @@ static void Init (void)
uDiffuse = glGetUniformLocationARB (program, "diffuse");
uSpecular = glGetUniformLocationARB (program, "specular");
- glUniform4fvARB (uDiffuse, 1, diffuse);
- glUniform4fvARB (uSpecular, 1, specular);
+ glUniform4fvARB (uDiffuse, 1, diffuse);
+ glUniform4fvARB (uSpecular, 1, specular);
glClearColor (0.3f, 0.3f, 0.3f, 0.0f);
glEnable (GL_DEPTH_TEST);
diff --git a/progs/demos/engine.c b/progs/demos/engine.c
new file mode 100644
index 00000000000..143b02a8894
--- /dev/null
+++ b/progs/demos/engine.c
@@ -0,0 +1,1293 @@
+/**
+ * Simple engine demo (crankshaft, pistons, connecting rods)
+ *
+ * Brian Paul
+ * June 2006
+ */
+
+#define GL_GLEXT_PROTOTYPES
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+#include <GL/glut.h>
+#include "readtex.h"
+#include "trackball.h"
+
+
+#define DEG_TO_RAD(DEG) ((DEG) * M_PI / 180.0)
+
+#define TEXTURE_FILE "../images/reflect.rgb"
+
+/* Target engine speed: */
+const int RPM = 100.0;
+
+
+/**
+ * Engine description.
+ */
+typedef struct
+{
+ const char *Name;
+ int Pistons;
+ int Cranks;
+ float V_Angle;
+ float PistonRadius;
+ float PistonHeight;
+ float WristPinRadius;
+ float Throw;
+ float CrankPlateThickness;
+ float CrankPinRadius;
+ float CrankJournalRadius;
+ float CrankJournalLength;
+ float ConnectingRodLength;
+ float ConnectingRodThickness;
+ /* display list IDs */
+ GLuint CrankList;
+ GLuint ConnRodList;
+ GLuint PistonList;
+ GLuint BlockList;
+} Engine;
+
+
+typedef struct
+{
+ float CurQuat[4];
+ float Distance;
+ /* When mouse is moving: */
+ GLboolean Rotating, Translating;
+ GLint StartX, StartY;
+ float StartDistance;
+} ViewInfo;
+
+
+typedef enum
+{
+ LIT,
+ WIREFRAME,
+ TEXTURED
+} RenderMode;
+
+
+typedef struct
+{
+ RenderMode Mode;
+ GLboolean Anim;
+ GLboolean Wireframe;
+ GLboolean Blend;
+ GLboolean Antialias;
+ GLboolean Texture;
+ GLboolean UseLists;
+ GLboolean DrawBox;
+ GLboolean ShowInfo;
+ GLboolean ShowBlock;
+} RenderInfo;
+
+
+static GLUquadric *Q;
+
+static GLfloat Theta = 0.0;
+
+static const GLfloat PistonColor[4] = { 1.0, 0.5, 0.5, 1.0 };
+static const GLfloat ConnRodColor[4] = { 0.7, 1.0, 0.7, 1.0 };
+static const GLfloat CrankshaftColor[4] = { 0.7, 0.7, 1.0, 1.0 };
+static const GLfloat BlockColor[4] = {0.8, 0.8, 0.8, 0.75 };
+
+static GLuint TextureObj;
+static GLint WinWidth = 800, WinHeight = 500;
+
+static ViewInfo View;
+static RenderInfo Render;
+
+#define NUM_ENGINES 3
+static Engine Engines[NUM_ENGINES] =
+{
+ {
+ "V-6",
+ 6, /* Pistons */
+ 3, /* Cranks */
+ 90.0, /* V_Angle */
+ 0.5, /* PistonRadius */
+ 0.6, /* PistonHeight */
+ 0.1, /* WristPinRadius */
+ 0.5, /* Throw */
+ 0.2, /* CrankPlateThickness */
+ 0.25, /* CrankPinRadius */
+ 0.3, /* CrankJournalRadius */
+ 0.4, /* CrankJournalLength */
+ 1.5, /* ConnectingRodLength */
+ 0.1 /* ConnectingRodThickness */
+ },
+ {
+ "Inline-4",
+ 4, /* Pistons */
+ 4, /* Cranks */
+ 0.0, /* V_Angle */
+ 0.5, /* PistonRadius */
+ 0.6, /* PistonHeight */
+ 0.1, /* WristPinRadius */
+ 0.5, /* Throw */
+ 0.2, /* CrankPlateThickness */
+ 0.25, /* CrankPinRadius */
+ 0.3, /* CrankJournalRadius */
+ 0.4, /* CrankJournalLength */
+ 1.5, /* ConnectingRodLength */
+ 0.1 /* ConnectingRodThickness */
+ },
+ {
+ "Boxer-6",
+ 6, /* Pistons */
+ 3, /* Cranks */
+ 180.0,/* V_Angle */
+ 0.5, /* PistonRadius */
+ 0.6, /* PistonHeight */
+ 0.1, /* WristPinRadius */
+ 0.5, /* Throw */
+ 0.2, /* CrankPlateThickness */
+ 0.25, /* CrankPinRadius */
+ 0.3, /* CrankJournalRadius */
+ 0.4, /* CrankJournalLength */
+ 1.5, /* ConnectingRodLength */
+ 0.1 /* ConnectingRodThickness */
+ }
+};
+
+static int CurEngine = 0;
+
+
+
+static void
+InitViewInfo(ViewInfo *view)
+{
+ view->Rotating = GL_FALSE;
+ view->Translating = GL_FALSE;
+ view->StartX = view->StartY = 0;
+ view->Distance = 12.0;
+ view->StartDistance = 0.0;
+ view->CurQuat[0] = -0.194143;
+ view->CurQuat[1] = 0.507848;
+ view->CurQuat[2] = 0.115245;
+ view->CurQuat[3] = 0.831335;
+}
+
+
+static void
+InitRenderInfo(RenderInfo *render)
+{
+ render->Mode = LIT;
+ render->Anim = GL_TRUE;
+ render->Wireframe = GL_FALSE;
+ render->Blend = GL_FALSE;
+ render->Antialias = GL_FALSE;
+ render->Texture = GL_FALSE;
+ render->DrawBox = GL_FALSE;
+ render->ShowInfo = GL_TRUE;
+ render->ShowBlock = GL_FALSE;
+ render->UseLists = GL_FALSE;
+}
+
+
+/**
+ * Set GL for given rendering mode.
+ */
+static void
+SetRenderState(RenderMode mode)
+{
+ static const GLfloat gray2[4] = { 0.2, 0.2, 0.2, 1.0 };
+ static const GLfloat gray4[4] = { 0.4, 0.4, 0.4, 1.0 };
+
+ /* defaults */
+ glDisable(GL_LIGHTING);
+ glDisable(GL_TEXTURE_2D);
+ glDisable(GL_BLEND);
+ glDisable(GL_LINE_SMOOTH);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
+ glDisable(GL_TEXTURE_GEN_S);
+ glDisable(GL_TEXTURE_GEN_T);
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, gray2);
+
+ switch (mode) {
+ case LIT:
+ glEnable(GL_LIGHTING);
+ break;
+ case WIREFRAME:
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ glEnable(GL_LINE_SMOOTH);
+ glEnable(GL_BLEND);
+ glLineWidth(1.5);
+ break;
+ case TEXTURED:
+ glEnable(GL_LIGHTING);
+ glEnable(GL_TEXTURE_2D);
+ glEnable(GL_TEXTURE_GEN_S);
+ glEnable(GL_TEXTURE_GEN_T);
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, gray4);
+ break;
+ default:
+ ;
+ }
+}
+
+
+/**
+ * Animate the engine parts.
+ */
+static void
+Idle(void)
+{
+ /* convert degrees per millisecond to RPM: */
+ const float m = 360.0 / 1000.0 / 60.0;
+ GLint t = glutGet(GLUT_ELAPSED_TIME);
+ Theta = ((int) (t * RPM * m)) % 360;
+ glutPostRedisplay();
+}
+
+
+/**
+ * Compute piston's position along its stroke.
+ */
+static float
+PistonStrokePosition(float throwDist, float crankAngle, float connRodLength)
+{
+ float x = throwDist * cos(DEG_TO_RAD(crankAngle));
+ float y = throwDist * sin(DEG_TO_RAD(crankAngle));
+ float pos = y + sqrt(connRodLength * connRodLength - x * x);
+ return pos;
+}
+
+
+/**
+ * Compute position of nth piston along the crankshaft.
+ */
+static float
+PistonShaftPosition(const Engine *eng, int piston)
+{
+ const int i = piston / (eng->Pistons / eng->Cranks);
+ float z;
+ assert(piston < eng->Pistons);
+ z = 1.5 * eng->CrankJournalLength + eng->CrankPlateThickness
+ + i * (2.0 * (eng->CrankJournalLength + eng->CrankPlateThickness));
+ if (eng->Pistons > eng->Cranks) {
+ if (piston & 1)
+ z += eng->ConnectingRodThickness;
+ else
+ z -= eng->ConnectingRodThickness;
+ }
+ return z;
+}
+
+
+/**
+ * Compute distance between two adjacent pistons
+ */
+static float
+PistonSpacing(const Engine *eng)
+{
+ const int pistonsPerCrank = eng->Pistons / eng->Cranks;
+ const float z0 = PistonShaftPosition(eng, 0);
+ const float z1 = PistonShaftPosition(eng, pistonsPerCrank);
+ return z1 - z0;
+}
+
+
+/**
+ * (x0, y0) = position of big end on crankshaft
+ * (x1, y1) = position of small end on piston
+ */
+static void
+ComputeConnectingRodPosition(float throwDist, float crankAngle,
+ float connRodLength,
+ float *x0, float *y0, float *x1, float *y1)
+{
+ *x0 = throwDist * cos(DEG_TO_RAD(crankAngle));
+ *y0 = throwDist * sin(DEG_TO_RAD(crankAngle));
+ *x1 = 0.0;
+ *y1 = PistonStrokePosition(throwDist, crankAngle, connRodLength);
+}
+
+
+/**
+ * Compute total length of the crankshaft.
+ */
+static float
+CrankshaftLength(const Engine *eng)
+{
+ float len = (eng->Cranks * 2 + 1) * eng->CrankJournalLength
+ + 2 * eng->Cranks * eng->CrankPlateThickness;
+ return len;
+}
+
+
+/**
+ * Draw a piston.
+ * Axis of piston = Z axis. Wrist pin is centered on (0, 0, 0).
+ */
+static void
+DrawPiston(const Engine *eng)
+{
+ const int slices = 30, stacks = 4, loops = 4;
+ const float innerRadius = 0.9 * eng->PistonRadius;
+ const float innerHeight = eng->PistonHeight - 0.15;
+ const float wristPinLength = 1.8 * eng->PistonRadius;
+
+ assert(Q);
+
+ glPushMatrix();
+ glTranslatef(0, 0, -1.1 * eng->WristPinRadius);
+
+ gluQuadricOrientation(Q, GLU_INSIDE);
+
+ /* bottom rim */
+ gluDisk(Q, innerRadius, eng->PistonRadius, slices, 1/*loops*/);
+
+ /* inner cylinder */
+ gluCylinder(Q, innerRadius, innerRadius, innerHeight, slices, stacks);
+
+ /* inside top */
+ glPushMatrix();
+ glTranslatef(0, 0, innerHeight);
+ gluDisk(Q, 0, innerRadius, slices, loops);
+ glPopMatrix();
+
+ gluQuadricOrientation(Q, GLU_OUTSIDE);
+
+ /* outer cylinder */
+ gluCylinder(Q, eng->PistonRadius, eng->PistonRadius, eng->PistonHeight,
+ slices, stacks);
+
+ /* top */
+ glTranslatef(0, 0, eng->PistonHeight);
+ gluDisk(Q, 0, eng->PistonRadius, slices, loops);
+
+ glPopMatrix();
+
+ /* wrist pin */
+ glPushMatrix();
+ glTranslatef(0, 0.5 * wristPinLength, 0.0);
+ glRotatef(90, 1, 0, 0);
+ gluCylinder(Q, eng->WristPinRadius, eng->WristPinRadius, wristPinLength,
+ slices, stacks);
+ glPopMatrix();
+}
+
+
+/**
+ * Draw piston at particular position.
+ */
+static void
+DrawPositionedPiston(const Engine *eng, float crankAngle)
+{
+ const float pos = PistonStrokePosition(eng->Throw, crankAngle,
+ eng->ConnectingRodLength);
+ glPushMatrix();
+ glRotatef(-90, 1, 0, 0);
+ glTranslatef(0, 0, pos);
+ DrawPiston(eng);
+ glPopMatrix();
+}
+
+
+/**
+ * Draw connector plate. Used for crankshaft and connecting rods.
+ */
+static void
+DrawConnector(float length, float thickness,
+ float bigEndRadius, float smallEndRadius)
+{
+ const float bigRadius = 1.2 * bigEndRadius;
+ const float smallRadius = 1.2 * smallEndRadius;
+ const float z0 = -0.5 * thickness, z1 = -z0;
+ GLfloat points[36][2], normals[36][2];
+ int i;
+
+ /* compute vertex locations, normals */
+ for (i = 0; i < 36; i++) {
+ const int angle = i * 10;
+ float x = cos(DEG_TO_RAD(angle));
+ float y = sin(DEG_TO_RAD(angle));
+ normals[i][0] = x;
+ normals[i][1] = y;
+ if (angle >= 0 && angle <= 180) {
+ x *= smallRadius;
+ y = y * smallRadius + length;
+ }
+ else {
+ x *= bigRadius;
+ y *= bigRadius;
+ }
+ points[i][0] = x;
+ points[i][1] = y;
+ }
+
+ /* front face */
+ glNormal3f(0, 0, 1);
+ glBegin(GL_POLYGON);
+ for (i = 0; i < 36; i++) {
+ glVertex3f(points[i][0], points[i][1], z1);
+ }
+ glEnd();
+
+ /* back face */
+ glNormal3f(0, 0, -1);
+ glBegin(GL_POLYGON);
+ for (i = 0; i < 36; i++) {
+ glVertex3f(points[35-i][0], points[35-i][1], z0);
+ }
+ glEnd();
+
+ /* edge */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= 36; i++) {
+ const int j = i % 36;
+ glNormal3f(normals[j][0], normals[j][1], 0);
+ glVertex3f(points[j][0], points[j][1], z0);
+ glVertex3f(points[j][0], points[j][1], z1);
+ }
+ glEnd();
+}
+
+
+/**
+ * Draw a crankshaft. Shaft lies along +Z axis, starting at zero.
+ */
+static void
+DrawCrankshaft(const Engine *eng)
+{
+ const int slices = 20, stacks = 2;
+ const int n = eng->Cranks * 4 + 1;
+ const float phiStep = 360 / eng->Cranks;
+ float phi = -90.0;
+ int i;
+ float z = 0.0;
+
+ for (i = 0; i < n; i++) {
+ glPushMatrix();
+ glTranslatef(0, 0, z);
+ if (i & 1) {
+ /* draw a crank plate */
+ glRotatef(phi, 0, 0, 1);
+ glTranslatef(0, 0, 0.5 * eng->CrankPlateThickness);
+ DrawConnector(eng->Throw, eng->CrankPlateThickness,
+ eng->CrankJournalRadius, eng->CrankPinRadius);
+ z += 0.2;
+ if (i % 4 == 3)
+ phi += phiStep;
+ }
+ else if (i % 4 == 0) {
+ /* draw crank journal segment */
+ gluCylinder(Q, eng->CrankJournalRadius, eng->CrankJournalRadius,
+ eng->CrankJournalLength, slices, stacks);
+ z += eng->CrankJournalLength;
+ }
+ else if (i % 4 == 2) {
+ /* draw crank pin segment */
+ glRotatef(phi, 0, 0, 1);
+ glTranslatef(0, eng->Throw, 0);
+ gluCylinder(Q, eng->CrankPinRadius, eng->CrankPinRadius,
+ eng->CrankJournalLength, slices, stacks);
+ z += eng->CrankJournalLength;
+ }
+ glPopMatrix();
+ }
+}
+
+
+/**
+ * Draw crankshaft at a particular rotation.
+ * \param crankAngle current crankshaft rotation, in radians
+ */
+static void
+DrawPositionedCrankshaft(const Engine *eng, float crankAngle)
+{
+ glPushMatrix();
+ glRotatef(crankAngle, 0, 0, 1);
+ if (eng->CrankList)
+ glCallList(eng->CrankList);
+ else
+ DrawCrankshaft(eng);
+ glPopMatrix();
+}
+
+
+/**
+ * Draw a connecting rod at particular position.
+ * \param eng description of connecting rod to draw
+ * \param crankAngle current crankshaft rotation, in radians
+ */
+static void
+DrawPositionedConnectingRod(const Engine *eng, float crankAngle)
+{
+ float x0, y0, x1, y1;
+ float d, phi;
+
+ ComputeConnectingRodPosition(eng->Throw, crankAngle,
+ eng->ConnectingRodLength,
+ &x0, &y0, &x1, &y1);
+ d = sqrt(eng->ConnectingRodLength * eng->ConnectingRodLength - x0 * x0);
+ phi = atan(x0 / d) * 180.0 / M_PI;
+
+ glPushMatrix();
+ glTranslatef(x0, y0, 0);
+ glRotatef(phi, 0, 0, 1);
+ if (eng->ConnRodList)
+ glCallList(eng->ConnRodList);
+ else
+ DrawConnector(eng->ConnectingRodLength, eng->ConnectingRodThickness,
+ eng->CrankPinRadius, eng->WristPinRadius);
+ glPopMatrix();
+}
+
+
+/**
+ * Draw a square with a hole in middle.
+ */
+static void
+SquareWithHole(float squareSize, float holeRadius)
+{
+ int i;
+ glBegin(GL_QUAD_STRIP);
+ glNormal3f(0, 0, 1);
+ for (i = 0; i <= 360; i += 5) {
+ const float x1 = holeRadius * cos(DEG_TO_RAD(i));
+ const float y1 = holeRadius * sin(DEG_TO_RAD(i));
+ float x2, y2;
+ if (i > 315 || i <= 45) {
+ x2 = squareSize;
+ y2 = squareSize * tan(DEG_TO_RAD(i));
+ }
+ else if (i > 45 && i <= 135) {
+ x2 = -squareSize * tan(DEG_TO_RAD(i - 90));
+ y2 = squareSize;
+ }
+ else if (i > 135 && i <= 225) {
+ x2 = -squareSize;
+ y2 = -squareSize * tan(DEG_TO_RAD(i-180));
+ }
+ else if (i > 225 && i <= 315) {
+ x2 = squareSize * tan(DEG_TO_RAD(i - 270));
+ y2 = -squareSize;
+ }
+ glVertex2f(x1, y1); /* inner circle */
+ glVertex2f(x2, y2); /* outer square */
+ }
+ glEnd();
+}
+
+
+/**
+ * Draw block with hole through middle.
+ * Hole is centered on Z axis.
+ * Bottom of block is at z=0, top of block is at z = blockHeight.
+ * index is in [0, count - 1] to determine which block faces are drawn.
+ */
+static void
+DrawBlockWithHole(float blockSize, float blockHeight, float holeRadius,
+ int index, int count)
+{
+ const int slices = 30, stacks = 4;
+ const float x = blockSize;
+ const float y = blockSize;
+ const float z0 = 0;
+ const float z1 = blockHeight;
+
+ assert(index < count);
+ assert(Q);
+ gluQuadricOrientation(Q, GLU_INSIDE);
+
+ glBegin(GL_QUADS);
+ /* +X face */
+ glNormal3f(1, 0, 0);
+ glVertex3f( x, -y, z0);
+ glVertex3f( x, y, z0);
+ glVertex3f( x, y, z1);
+ glVertex3f( x, -y, z1);
+ /* -X face */
+ glNormal3f(-1, 0, 0);
+ glVertex3f(-x, -y, z1);
+ glVertex3f(-x, y, z1);
+ glVertex3f(-x, y, z0);
+ glVertex3f(-x, -y, z0);
+ if (index == 0) {
+ /* +Y face */
+ glNormal3f(0, 1, 0);
+ glVertex3f(-x, y, z1);
+ glVertex3f( x, y, z1);
+ glVertex3f( x, y, z0);
+ glVertex3f(-x, y, z0);
+ }
+ if (index == count - 1) {
+ /* -Y face */
+ glNormal3f(0, -1, 0);
+ glVertex3f(-x, -y, z0);
+ glVertex3f( x, -y, z0);
+ glVertex3f( x, -y, z1);
+ glVertex3f(-x, -y, z1);
+ }
+ glEnd();
+
+ /* cylinder / hole */
+ gluCylinder(Q, holeRadius, holeRadius, blockHeight, slices, stacks);
+
+ /* face at z0 */
+ glPushMatrix();
+ glRotatef(180, 1, 0, 0);
+ SquareWithHole(blockSize, holeRadius);
+ glPopMatrix();
+
+ /* face at z1 */
+ glTranslatef(0, 0, z1);
+ SquareWithHole(blockSize, holeRadius);
+
+ gluQuadricOrientation(Q, GLU_OUTSIDE);
+}
+
+
+/**
+ * Draw the engine block.
+ */
+static void
+DrawEngineBlock(const Engine *eng)
+{
+ const float blockHeight = eng->Throw + 1.5 * eng->PistonHeight;
+ const float cylRadius = 1.01 * eng->PistonRadius;
+ const float blockSize = 0.5 * PistonSpacing(eng);
+ const int pistonsPerCrank = eng->Pistons / eng->Cranks;
+ int i;
+
+ for (i = 0; i < eng->Pistons; i++) {
+ const float z = PistonShaftPosition(eng, i);
+ const int crank = i / pistonsPerCrank;
+ int k;
+
+ glPushMatrix();
+ glTranslatef(0, 0, z);
+
+ /* additional rotation for kth piston per crank */
+ k = i % pistonsPerCrank;
+ glRotatef(k * -eng->V_Angle, 0, 0, 1);
+
+ /* the block */
+ glRotatef(-90, 1, 0, 0);
+ glTranslatef(0, 0, eng->Throw * 2);
+ DrawBlockWithHole(blockSize, blockHeight, cylRadius,
+ crank, eng->Cranks);
+ glPopMatrix();
+ }
+}
+
+
+/**
+ * Generate display lists for engine parts.
+ */
+static void
+GenerateDisplayLists(Engine *eng)
+{
+ eng->CrankList = glGenLists(1);
+ glNewList(eng->CrankList, GL_COMPILE);
+ DrawCrankshaft(eng);
+ glEndList();
+
+ eng->ConnRodList = glGenLists(1);
+ glNewList(eng->ConnRodList, GL_COMPILE);
+ DrawConnector(eng->ConnectingRodLength, eng->ConnectingRodThickness,
+ eng->CrankPinRadius, eng->WristPinRadius);
+ glEndList();
+
+ eng->PistonList = glGenLists(1);
+ glNewList(eng->PistonList, GL_COMPILE);
+ DrawPiston(eng);
+ glEndList();
+
+ eng->BlockList = glGenLists(1);
+ glNewList(eng->BlockList, GL_COMPILE);
+ DrawEngineBlock(eng);
+ glEndList();
+}
+
+
+/**
+ * Free engine display lists (render with immediate mode).
+ */
+static void
+FreeDisplayLists(Engine *eng)
+{
+ glDeleteLists(eng->CrankList, 1);
+ eng->CrankList = 0;
+ glDeleteLists(eng->ConnRodList, 1);
+ eng->ConnRodList = 0;
+ glDeleteLists(eng->PistonList, 1);
+ eng->PistonList = 0;
+ glDeleteLists(eng->BlockList, 1);
+ eng->BlockList = 0;
+}
+
+
+/**
+ * Draw complete engine.
+ * \param eng description of engine to draw
+ * \param crankAngle current crankshaft angle, in radians
+ */
+static void
+DrawEngine(const Engine *eng, float crankAngle)
+{
+ const float crankDelta = 360.0 / eng->Cranks;
+ const float crankLen = CrankshaftLength(eng);
+ const int pistonsPerCrank = eng->Pistons / eng->Cranks;
+ int i;
+
+ glPushMatrix();
+ glRotatef(eng->V_Angle * 0.5, 0, 0, 1);
+ glTranslatef(0, 0, -0.5 * crankLen);
+
+ /* crankshaft */
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, CrankshaftColor);
+ glColor4fv(CrankshaftColor);
+ DrawPositionedCrankshaft(eng, crankAngle);
+
+ for (i = 0; i < eng->Pistons; i++) {
+ const float z = PistonShaftPosition(eng, i);
+ const int crank = i / pistonsPerCrank;
+ float rot = crankAngle + crank * crankDelta;
+ int k;
+
+ glPushMatrix();
+ glTranslatef(0, 0, z);
+
+ /* additional rotation for kth piston per crank */
+ k = i % pistonsPerCrank;
+ glRotatef(k * -eng->V_Angle, 0, 0, 1);
+ rot += k * eng->V_Angle;
+
+ /* piston */
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, PistonColor);
+ glColor4fv(PistonColor);
+ DrawPositionedPiston(eng, rot);
+
+ /* connecting rod */
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, ConnRodColor);
+ glColor4fv(ConnRodColor);
+ DrawPositionedConnectingRod(eng, rot);
+ glPopMatrix();
+ }
+
+ if (Render.ShowBlock) {
+ const GLboolean blend = glIsEnabled(GL_BLEND);
+
+ glDepthMask(GL_FALSE);
+ if (!blend) {
+ glEnable(GL_BLEND);
+ }
+ glEnable(GL_CULL_FACE);
+
+ glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, BlockColor);
+ glColor4fv(BlockColor);
+ if (eng->CrankList)
+ glCallList(eng->BlockList);
+ else
+ DrawEngineBlock(eng);
+
+ glDisable(GL_CULL_FACE);
+ glDepthMask(GL_TRUE);
+ if (!blend) {
+ glDisable(GL_BLEND);
+ }
+ }
+
+ glPopMatrix();
+}
+
+
+static void
+DrawBox(void)
+{
+ const float xmin = -3.0, xmax = 3.0;
+ const float ymin = -1.0, ymax = 3.0;
+ const float zmin = -4.0, zmax = 4.0;
+ const float step = 0.5;
+ const float d = 0.01;
+ float x, y, z;
+ GLboolean lit = glIsEnabled(GL_LIGHTING);
+ GLboolean tex = glIsEnabled(GL_TEXTURE_2D);
+
+ glDisable(GL_LIGHTING);
+ glDisable(GL_TEXTURE_2D);
+
+ glColor3f(1, 1, 1);
+
+ /* Z min */
+ glBegin(GL_LINES);
+ for (x = xmin; x <= xmax; x += step) {
+ glVertex3f(x, ymin, zmin);
+ glVertex3f(x, ymax, zmin);
+ }
+ glEnd();
+ glBegin(GL_LINES);
+ for (y = ymin; y <= ymax; y += step) {
+ glVertex3f(xmin, y, zmin);
+ glVertex3f(xmax, y, zmin);
+ }
+ glEnd();
+
+ /* Y min */
+ glBegin(GL_LINES);
+ for (x = xmin; x <= xmax; x += step) {
+ glVertex3f(x, ymin, zmin);
+ glVertex3f(x, ymin, zmax);
+ }
+ glEnd();
+ glBegin(GL_LINES);
+ for (z = zmin; z <= zmax; z += step) {
+ glVertex3f(xmin, ymin, z);
+ glVertex3f(xmax, ymin, z);
+ }
+ glEnd();
+
+ /* X min */
+ glBegin(GL_LINES);
+ for (y = ymin; y <= ymax; y += step) {
+ glVertex3f(xmin, y, zmin);
+ glVertex3f(xmin, y, zmax);
+ }
+ glEnd();
+ glBegin(GL_LINES);
+ for (z = zmin; z <= zmax; z += step) {
+ glVertex3f(xmin, ymin, z);
+ glVertex3f(xmin, ymax, z);
+ }
+ glEnd();
+
+ glColor3f(0.4, 0.4, 0.6);
+ glBegin(GL_QUADS);
+ /* xmin */
+ glVertex3f(xmin-d, ymin, zmin);
+ glVertex3f(xmin-d, ymax, zmin);
+ glVertex3f(xmin-d, ymax, zmax);
+ glVertex3f(xmin-d, ymin, zmax);
+ /* ymin */
+ glVertex3f(xmin, ymin-d, zmin);
+ glVertex3f(xmax, ymin-d, zmin);
+ glVertex3f(xmax, ymin-d, zmax);
+ glVertex3f(xmin, ymin-d, zmax);
+ /* zmin */
+ glVertex3f(xmin, ymin, zmin-d);
+ glVertex3f(xmax, ymin, zmin-d);
+ glVertex3f(xmax, ymax, zmin-d);
+ glVertex3f(xmin, ymax, zmin-d);
+ glEnd();
+
+ if (lit)
+ glEnable(GL_LIGHTING);
+ if (tex)
+ glEnable(GL_TEXTURE_2D);
+}
+
+
+static void
+PrintString(const char *s)
+{
+ while (*s) {
+ glutBitmapCharacter(GLUT_BITMAP_8_BY_13, (int) *s);
+ s++;
+ }
+}
+
+
+static int
+ComputeFPS(void)
+{
+ static double t0 = -1.0;
+ static int frames = 0;
+ double t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
+ static int fps = 0;
+
+ frames++;
+
+ if (t0 < 0.0) {
+ t0 = t;
+ fps = 0;
+ }
+ else if (t - t0 >= 1.0) {
+ fps = (int) (frames / (t - t0) + 0.5);
+ t0 = t;
+ frames = 0;
+ }
+
+ return fps;
+}
+
+
+static void
+Draw(void)
+{
+ int fps;
+ GLfloat rot[4][4];
+
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+
+ glTranslatef(0.0, 0.0, -View.Distance);
+ build_rotmatrix(rot, View.CurQuat);
+ glMultMatrixf(&rot[0][0]);
+
+ glPushMatrix();
+ glTranslatef(0, -0.75, 0);
+ if (Render.DrawBox)
+ DrawBox();
+ DrawEngine(Engines + CurEngine, Theta);
+ glPopMatrix();
+
+ glPopMatrix();
+
+ fps = ComputeFPS();
+ if (Render.ShowInfo) {
+ GLboolean lit = glIsEnabled(GL_LIGHTING);
+ GLboolean tex = glIsEnabled(GL_TEXTURE_2D);
+ char s[100];
+ sprintf(s, "%s %d FPS %s", Engines[CurEngine].Name, fps,
+ Render.UseLists ? "Display Lists" : "Immediate mode");
+ glDisable(GL_LIGHTING);
+ glDisable(GL_TEXTURE_2D);
+ glColor3f(1, 1 , 1);
+ glWindowPos2iARB(10, 10);
+ PrintString(s);
+ if (lit)
+ glEnable(GL_LIGHTING);
+ if (tex)
+ glEnable(GL_TEXTURE_2D);
+ }
+
+ glutSwapBuffers();
+}
+
+
+/**
+ * Handle window resize.
+ */
+static void
+Reshape(int width, int height)
+{
+ float ar = (float) width / height;
+ float s = 0.5;
+ glViewport(0, 0, width, height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-ar * s, ar * s, -s, s, 2.0, 50.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ WinWidth = width;
+ WinHeight = height;
+}
+
+
+/**
+ * Handle mouse button.
+ */
+static void
+Mouse(int button, int state, int x, int y)
+{
+ if (button == GLUT_LEFT_BUTTON) {
+ if (state == GLUT_DOWN) {
+ View.StartX = x;
+ View.StartY = y;
+ View.Rotating = GL_TRUE;
+ }
+ else if (state == GLUT_UP) {
+ View.Rotating = GL_FALSE;
+ }
+ }
+ else if (button == GLUT_MIDDLE_BUTTON) {
+ if (state == GLUT_DOWN) {
+ View.StartX = x;
+ View.StartY = y;
+ View.StartDistance = View.Distance;
+ View.Translating = GL_TRUE;
+ }
+ else if (state == GLUT_UP) {
+ View.Translating = GL_FALSE;
+ }
+ }
+}
+
+
+/**
+ * Handle mouse motion
+ */
+static void
+Motion(int x, int y)
+{
+ int i;
+ if (View.Rotating) {
+ float x0 = (2.0 * View.StartX - WinWidth) / WinWidth;
+ float y0 = (WinHeight - 2.0 * View.StartY) / WinHeight;
+ float x1 = (2.0 * x - WinWidth) / WinWidth;
+ float y1 = (WinHeight - 2.0 * y) / WinHeight;
+ float q[4];
+
+ trackball(q, x0, y0, x1, y1);
+ View.StartX = x;
+ View.StartY = y;
+ for (i = 0; i < 1; i++)
+ add_quats(q, View.CurQuat, View.CurQuat);
+
+ glutPostRedisplay();
+ }
+ else if (View.Translating) {
+ float dz = 0.01 * (y - View.StartY);
+ View.Distance = View.StartDistance + dz;
+ glutPostRedisplay();
+ }
+}
+
+
+/**
+ ** Menu Callbacks
+ **/
+
+static void
+OptAnimation(void)
+{
+ Render.Anim = !Render.Anim;
+ if (Render.Anim)
+ glutIdleFunc(Idle);
+ else
+ glutIdleFunc(NULL);
+}
+
+static void
+OptChangeEngine(void)
+{
+ CurEngine = (CurEngine + 1) % NUM_ENGINES;
+}
+
+static void
+OptRenderMode(void)
+{
+ Render.Mode++;
+ if (Render.Mode > TEXTURED)
+ Render.Mode = 0;
+ SetRenderState(Render.Mode);
+}
+
+static void
+OptDisplayLists(void)
+{
+ int i;
+ Render.UseLists = !Render.UseLists;
+ if (Render.UseLists) {
+ for (i = 0; i < NUM_ENGINES; i++) {
+ GenerateDisplayLists(Engines + i);
+ }
+ }
+ else {
+ for (i = 0; i < NUM_ENGINES; i++) {
+ FreeDisplayLists(Engines + i);
+ }
+ }
+}
+
+static void
+OptShowBlock(void)
+{
+ Render.ShowBlock = !Render.ShowBlock;
+}
+
+static void
+OptShowInfo(void)
+{
+ Render.ShowInfo = !Render.ShowInfo;
+}
+
+static void
+OptShowBox(void)
+{
+ Render.DrawBox = !Render.DrawBox;
+}
+
+static void
+OptRotate(void)
+{
+ Theta += 5.0;
+}
+
+static void
+OptExit(void)
+{
+ exit(0);
+}
+
+
+/**
+ * Define menu entries (w/ keyboard shortcuts)
+ */
+
+typedef struct
+{
+ const char *Text;
+ const char Key;
+ void (*Function)(void);
+} MenuInfo;
+
+static const MenuInfo MenuItems[] = {
+ { "Animation", 'a', OptAnimation },
+ { "Change Engine", 'e', OptChangeEngine },
+ { "Rendering Style", 'm', OptRenderMode },
+ { "Display Lists", 'd', OptDisplayLists },
+ { "Show Block", 'b', OptShowBlock },
+ { "Show Info", 'i', OptShowInfo },
+ { "Show Box", 'x', OptShowBox },
+ { "Exit", 27, OptExit },
+ { NULL, 'r', OptRotate },
+ { NULL, 0, NULL }
+};
+
+
+/**
+ * Handle menu selection.
+ */
+static void
+MenuHandler(int entry)
+{
+ MenuItems[entry].Function();
+ glutPostRedisplay();
+}
+
+
+/**
+ * Make pop-up menu.
+ */
+static void
+MakeMenu(void)
+{
+ int i;
+ glutCreateMenu(MenuHandler);
+ for (i = 0; MenuItems[i].Text; i++) {
+ glutAddMenuEntry(MenuItems[i].Text, i);
+ }
+ glutAttachMenu(GLUT_RIGHT_BUTTON);
+}
+
+
+/**
+ * Handle keyboard event.
+ */
+static void
+Key(unsigned char key, int x, int y)
+{
+ int i;
+ (void) x; (void) y;
+ for (i = 0; MenuItems[i].Key; i++) {
+ if (MenuItems[i].Key == key) {
+ MenuItems[i].Function();
+ glutPostRedisplay();
+ break;
+ }
+ }
+}
+
+
+static
+void LoadTexture(void)
+{
+ GLboolean convolve = GL_FALSE;
+
+ glGenTextures(1, &TextureObj);
+ glBindTexture(GL_TEXTURE_2D, TextureObj);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
+ glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
+
+ if (convolve) {
+#define FILTER_SIZE 7
+ /* use convolution to blur the texture to simulate a dull finish
+ * on the object.
+ */
+ GLubyte *img;
+ GLenum format;
+ GLint w, h;
+ GLfloat filter[FILTER_SIZE][FILTER_SIZE][4];
+
+ for (h = 0; h < FILTER_SIZE; h++) {
+ for (w = 0; w < FILTER_SIZE; w++) {
+ const GLfloat k = 1.0 / (FILTER_SIZE * FILTER_SIZE);
+ filter[h][w][0] = k;
+ filter[h][w][1] = k;
+ filter[h][w][2] = k;
+ filter[h][w][3] = k;
+ }
+ }
+
+ glEnable(GL_CONVOLUTION_2D);
+ glConvolutionParameteri(GL_CONVOLUTION_2D,
+ GL_CONVOLUTION_BORDER_MODE, GL_CONSTANT_BORDER);
+ glConvolutionFilter2D(GL_CONVOLUTION_2D, GL_RGBA,
+ FILTER_SIZE, FILTER_SIZE,
+ GL_RGBA, GL_FLOAT, filter);
+
+ img = LoadRGBImage(TEXTURE_FILE, &w, &h, &format);
+ if (!img) {
+ printf("Error: couldn't load texture image file %s\n", TEXTURE_FILE);
+ exit(1);
+ }
+
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, w, h, 0,
+ format, GL_UNSIGNED_BYTE, img);
+ free(img);
+ }
+ else {
+ if (!LoadRGBMipmaps(TEXTURE_FILE, GL_RGB)) {
+ printf("Error: couldn't load texture image file %s\n", TEXTURE_FILE);
+ exit(1);
+ }
+ }
+}
+
+
+static void
+Init(void)
+{
+ const GLfloat lightColor[4] = { 0.7, 0.7, 0.7, 1.0 };
+ const GLfloat specular[4] = { 0.8, 0.8, 0.8, 1.0 };
+
+ Q = gluNewQuadric();
+ gluQuadricNormals(Q, GLU_SMOOTH);
+
+ LoadTexture();
+
+ glClearColor(0.3, 0.3, 0.3, 0.0);
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, lightColor);
+ glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 40);
+ glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
+ glEnable(GL_NORMALIZE);
+
+ glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ InitViewInfo(&View);
+ InitRenderInfo(&Render);
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ glutInit(&argc, argv);
+ glutInitWindowSize(WinWidth, WinHeight);
+ glutInitDisplayMode(GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH);
+ glutCreateWindow("OpenGL Engine Demo");
+ glutReshapeFunc(Reshape);
+ glutMouseFunc(Mouse);
+ glutMotionFunc(Motion);
+ glutKeyboardFunc(Key);
+ glutDisplayFunc(Draw);
+ MakeMenu();
+ Init();
+ if (Render.Anim)
+ glutIdleFunc(Idle);
+ glutMainLoop();
+ return 0;
+}
diff --git a/progs/demos/gloss.c b/progs/demos/gloss.c
index 0b2e7426d53..9974f0dab2e 100644
--- a/progs/demos/gloss.c
+++ b/progs/demos/gloss.c
@@ -25,6 +25,8 @@
#include <GL/glut.h>
#include "readtex.h"
+#include "trackball.h"
+
#define SPECULAR_TEXTURE_FILE "../images/reflect.rgb"
#define BASE_TEXTURE_FILE "../images/tile.rgb"
@@ -44,8 +46,7 @@ static GLuint TeapotObj = 0;
static GLuint Object = 0;
static GLboolean Animate = GL_TRUE;
-static GLfloat Xrot = 0.0, Yrot = 0.0, Zrot = 0.0;
-static GLfloat DXrot = 20.0, DYrot = 50.;
+static float CurQuat[4] = { 0, 0, 0, 1 };
static GLfloat Black[4] = { 0, 0, 0, 0 };
static GLfloat White[4] = { 1, 1, 1, 1 };
@@ -57,7 +58,6 @@ static GLboolean DoSpecTexture = GL_TRUE;
static GLboolean ButtonDown = GL_FALSE;
static GLint ButtonX, ButtonY;
-static GLfloat Xrot0, Yrot0;
/* performance info */
@@ -67,29 +67,31 @@ static GLint Frames = 0;
static void Idle( void )
{
+ static const float yAxis[3] = {0, 1, 0};
static double t0 = -1.;
+ float quat[4];
double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
if (t0 < 0.0)
t0 = t;
dt = t - t0;
t0 = t;
- if (Animate) {
- Xrot += DXrot*dt;
- Yrot += DYrot*dt;
- glutPostRedisplay();
- }
+ axis_to_quat(yAxis, 2.0 * dt, quat);
+ add_quats(quat, CurQuat, CurQuat);
+
+ glutPostRedisplay();
}
static void Display( void )
{
+ GLfloat rot[4][4];
+
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
glPushMatrix();
- glRotatef(Xrot, 1.0, 0.0, 0.0);
- glRotatef(Yrot, 0.0, 1.0, 0.0);
- glRotatef(Zrot, 0.0, 0.0, 1.0);
+ build_rotmatrix(rot, CurQuat);
+ glMultMatrixf(&rot[0][0]);
/* First pass: diffuse lighting with base texture */
glMaterialfv(GL_FRONT, GL_DIFFUSE, Diffuse);
@@ -218,39 +220,21 @@ static void Key( unsigned char key, int x, int y )
}
-static void SpecialKey( int key, int x, int y )
-{
- float step = 3.0;
- (void) x;
- (void) y;
-
- switch (key) {
- case GLUT_KEY_UP:
- Xrot += step;
- break;
- case GLUT_KEY_DOWN:
- Xrot -= step;
- break;
- case GLUT_KEY_LEFT:
- Yrot += step;
- break;
- case GLUT_KEY_RIGHT:
- Yrot -= step;
- break;
- }
- glutPostRedisplay();
-}
-
-
static void
MouseMotion(int x, int y)
{
- const float k = 300.0;
if (ButtonDown) {
- float dx = x - ButtonX;
- float dy = y - ButtonY;
- Xrot = Xrot0 + k * dy / WinWidth;
- Yrot = Yrot0 + k * dx / WinHeight;
+ float x0 = (2.0 * ButtonX - WinWidth) / WinWidth;
+ float y0 = (WinHeight - 2.0 * ButtonY) / WinHeight;
+ float x1 = (2.0 * x - WinWidth) / WinWidth;
+ float y1 = (WinHeight - 2.0 * y) / WinHeight;
+ float q[4];
+
+ trackball(q, x0, y0, x1, y1);
+ ButtonX = x;
+ ButtonY = y;
+ add_quats(q, CurQuat, CurQuat);
+
glutPostRedisplay();
}
}
@@ -263,8 +247,6 @@ MouseButton(int button, int state, int x, int y)
ButtonDown = GL_TRUE;
ButtonX = x;
ButtonY = y;
- Xrot0 = Xrot;
- Yrot0 = Yrot;
}
else if (button == GLUT_LEFT_BUTTON && state == GLUT_UP) {
ButtonDown = GL_FALSE;
@@ -453,18 +435,11 @@ static void Init( int argc, char *argv[] )
int main( int argc, char *argv[] )
{
glutInit( &argc, argv );
- glutInitWindowPosition(0, 0);
glutInitWindowSize(WinWidth, WinHeight);
-
glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
-
glutCreateWindow(argv[0] );
-
- Init(argc, argv);
-
glutReshapeFunc( Reshape );
glutKeyboardFunc( Key );
- glutSpecialFunc( SpecialKey );
glutDisplayFunc( Display );
glutMotionFunc(MouseMotion);
glutMouseFunc(MouseButton);
@@ -478,6 +453,8 @@ int main( int argc, char *argv[] )
glutAddMenuEntry("Quit", QUIT);
glutAttachMenu(GLUT_RIGHT_BUTTON);
+ Init(argc, argv);
+
glutMainLoop();
return 0;
}
diff --git a/progs/demos/glslnoise.c b/progs/demos/glslnoise.c
index 2adb114e668..4ee12928164 100755
--- a/progs/demos/glslnoise.c
+++ b/progs/demos/glslnoise.c
@@ -30,6 +30,9 @@ static GLhandleARB program;
static GLint uTime;
+static GLint t0 = 0;
+static GLint frames = 0;
+
static GLfloat u_time = 0.0f;
static PFNGLCREATESHADEROBJECTARBPROC glCreateShaderObjectARB = NULL;
@@ -44,15 +47,27 @@ static PFNGLUNIFORM1FARBPROC glUniform1fARB = NULL;
static void Redisplay (void)
{
+ GLint t;
+
glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
- glUniform1fARB (uTime, u_time);
+ glUniform1fARB (uTime, 0.5f * u_time);
glPushMatrix ();
glutSolidSphere (2.0, 20, 10);
glPopMatrix ();
glutSwapBuffers();
+ frames++;
+
+ t = glutGet (GLUT_ELAPSED_TIME);
+ if (t - t0 >= 5000) {
+ GLfloat seconds = (GLfloat) (t - t0) / 1000.0f;
+ GLfloat fps = frames / seconds;
+ printf ("%d frames in %6.3f seconds = %6.3f FPS\n", frames, seconds, fps);
+ t0 = t;
+ frames = 0;
+ }
}
static void Idle (void)
@@ -88,20 +103,20 @@ static void Key (unsigned char key, int x, int y)
static void Init (void)
{
- static const char *fragShaderText =
- "uniform float time;\n"
- "void main () {\n"
- " gl_FragColor = gl_Color * vec4 ((0.5 + 0.5 * vec3 (noise1 (\n"
- " vec4 (4.0 * gl_TexCoord[0].xyz, 0.5 * time)))), 1.0);\n"
- "}\n"
- ;
- static const char *vertShaderText =
- "void main () {\n"
- " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
- " gl_TexCoord[0] = gl_Vertex;\n"
- " gl_FrontColor = gl_Color;\n"
- "}\n"
- ;
+ static const char *fragShaderText =
+ "uniform float time;\n"
+ "varying vec3 position;\n"
+ "void main () {\n"
+ " gl_FragColor = vec4 (vec3 (0.5 + 0.5 * noise1 (vec4 (position, time))), 1.0);\n"
+ "}\n"
+ ;
+ static const char *vertShaderText =
+ "varying vec3 position;\n"
+ "void main () {\n"
+ " gl_Position = gl_ModelViewProjectionMatrix * gl_Vertex;\n"
+ " position = 4.0 * gl_Vertex.xyz;\n"
+ "}\n"
+ ;
if (!glutExtensionSupported ("GL_ARB_fragment_shader"))
{
diff --git a/progs/demos/pointblast.c b/progs/demos/pointblast.c
index 715813f1763..dbbe2f35a28 100644
--- a/progs/demos/pointblast.c
+++ b/progs/demos/pointblast.c
@@ -471,6 +471,11 @@ main(int argc, char **argv)
glutAddMenuEntry("Quit", 666);
glutAttachMenu(GLUT_RIGHT_BUTTON);
+ if (!glutExtensionSupported("GL_ARB_point_parameters")) {
+ fprintf(stderr, "Sorry, GL_ARB_point_parameters is not supported.\n");
+ return -1;
+ }
+
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_POINT_SMOOTH);
diff --git a/progs/demos/readtex.c b/progs/demos/readtex.c
new file mode 100644
index 00000000000..37d5fcd0d3a
--- /dev/null
+++ b/progs/demos/readtex.c
@@ -0,0 +1,454 @@
+/* readtex.c */
+
+/*
+ * Read an SGI .rgb image file and generate a mipmap texture set.
+ * Much of this code was borrowed from SGI's tk OpenGL toolkit.
+ */
+
+
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "readtex.h"
+
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+
+/*
+** RGB Image Structure
+*/
+
+typedef struct _TK_RGBImageRec {
+ GLint sizeX, sizeY;
+ GLint components;
+ unsigned char *data;
+} TK_RGBImageRec;
+
+
+
+/******************************************************************************/
+
+typedef struct _rawImageRec {
+ unsigned short imagic;
+ unsigned short type;
+ unsigned short dim;
+ unsigned short sizeX, sizeY, sizeZ;
+ unsigned long min, max;
+ unsigned long wasteBytes;
+ char name[80];
+ unsigned long colorMap;
+ FILE *file;
+ unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA;
+ unsigned long rleEnd;
+ GLuint *rowStart;
+ GLint *rowSize;
+} rawImageRec;
+
+/******************************************************************************/
+
+static void ConvertShort(unsigned short *array, long length)
+{
+ unsigned long b1, b2;
+ unsigned char *ptr;
+
+ ptr = (unsigned char *)array;
+ while (length--) {
+ b1 = *ptr++;
+ b2 = *ptr++;
+ *array++ = (unsigned short) ((b1 << 8) | (b2));
+ }
+}
+
+static void ConvertLong(GLuint *array, long length)
+{
+ unsigned long b1, b2, b3, b4;
+ unsigned char *ptr;
+
+ ptr = (unsigned char *)array;
+ while (length--) {
+ b1 = *ptr++;
+ b2 = *ptr++;
+ b3 = *ptr++;
+ b4 = *ptr++;
+ *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
+ }
+}
+
+static rawImageRec *RawImageOpen(const char *fileName)
+{
+ union {
+ int testWord;
+ char testByte[4];
+ } endianTest;
+ rawImageRec *raw;
+ GLenum swapFlag;
+ int x;
+
+ endianTest.testWord = 1;
+ if (endianTest.testByte[0] == 1) {
+ swapFlag = GL_TRUE;
+ } else {
+ swapFlag = GL_FALSE;
+ }
+
+ raw = (rawImageRec *)calloc(1, sizeof(rawImageRec));
+ if (raw == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+ if ((raw->file = fopen(fileName, "rb")) == NULL) {
+ perror(fileName);
+ return NULL;
+ }
+
+ fread(raw, 1, 12, raw->file);
+
+ if (swapFlag) {
+ ConvertShort(&raw->imagic, 6);
+ }
+
+ raw->tmp = (unsigned char *)malloc(raw->sizeX*256);
+ raw->tmpR = (unsigned char *)malloc(raw->sizeX*256);
+ raw->tmpG = (unsigned char *)malloc(raw->sizeX*256);
+ raw->tmpB = (unsigned char *)malloc(raw->sizeX*256);
+ if (raw->sizeZ==4) {
+ raw->tmpA = (unsigned char *)malloc(raw->sizeX*256);
+ }
+ if (raw->tmp == NULL || raw->tmpR == NULL || raw->tmpG == NULL ||
+ raw->tmpB == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+
+ if ((raw->type & 0xFF00) == 0x0100) {
+ x = raw->sizeY * raw->sizeZ * sizeof(GLuint);
+ raw->rowStart = (GLuint *)malloc(x);
+ raw->rowSize = (GLint *)malloc(x);
+ if (raw->rowStart == NULL || raw->rowSize == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+ raw->rleEnd = 512 + (2 * x);
+ fseek(raw->file, 512, SEEK_SET);
+ fread(raw->rowStart, 1, x, raw->file);
+ fread(raw->rowSize, 1, x, raw->file);
+ if (swapFlag) {
+ ConvertLong(raw->rowStart, (long) (x/sizeof(GLuint)));
+ ConvertLong((GLuint *)raw->rowSize, (long) (x/sizeof(GLint)));
+ }
+ }
+ return raw;
+}
+
+static void RawImageClose(rawImageRec *raw)
+{
+ fclose(raw->file);
+ free(raw->tmp);
+ free(raw->tmpR);
+ free(raw->tmpG);
+ free(raw->tmpB);
+ if (raw->rowStart)
+ free(raw->rowStart);
+ if (raw->rowSize)
+ free(raw->rowSize);
+ if (raw->sizeZ>3) {
+ free(raw->tmpA);
+ }
+ free(raw);
+}
+
+static void RawImageGetRow(rawImageRec *raw, unsigned char *buf, int y, int z)
+{
+ unsigned char *iPtr, *oPtr, pixel;
+ int count, done = 0;
+
+ if ((raw->type & 0xFF00) == 0x0100) {
+ fseek(raw->file, (long) raw->rowStart[y+z*raw->sizeY], SEEK_SET);
+ fread(raw->tmp, 1, (unsigned int)raw->rowSize[y+z*raw->sizeY],
+ raw->file);
+
+ iPtr = raw->tmp;
+ oPtr = buf;
+ while (!done) {
+ pixel = *iPtr++;
+ count = (int)(pixel & 0x7F);
+ if (!count) {
+ done = 1;
+ return;
+ }
+ if (pixel & 0x80) {
+ while (count--) {
+ *oPtr++ = *iPtr++;
+ }
+ } else {
+ pixel = *iPtr++;
+ while (count--) {
+ *oPtr++ = pixel;
+ }
+ }
+ }
+ } else {
+ fseek(raw->file, 512+(y*raw->sizeX)+(z*raw->sizeX*raw->sizeY),
+ SEEK_SET);
+ fread(buf, 1, raw->sizeX, raw->file);
+ }
+}
+
+
+static void RawImageGetData(rawImageRec *raw, TK_RGBImageRec *final)
+{
+ unsigned char *ptr;
+ int i, j;
+
+ final->data = (unsigned char *)malloc((raw->sizeX+1)*(raw->sizeY+1)*4);
+ if (final->data == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ }
+
+ ptr = final->data;
+ for (i = 0; i < (int)(raw->sizeY); i++) {
+ RawImageGetRow(raw, raw->tmpR, i, 0);
+ RawImageGetRow(raw, raw->tmpG, i, 1);
+ RawImageGetRow(raw, raw->tmpB, i, 2);
+ if (raw->sizeZ>3) {
+ RawImageGetRow(raw, raw->tmpA, i, 3);
+ }
+ for (j = 0; j < (int)(raw->sizeX); j++) {
+ *ptr++ = *(raw->tmpR + j);
+ *ptr++ = *(raw->tmpG + j);
+ *ptr++ = *(raw->tmpB + j);
+ if (raw->sizeZ>3) {
+ *ptr++ = *(raw->tmpA + j);
+ }
+ }
+ }
+}
+
+
+static TK_RGBImageRec *tkRGBImageLoad(const char *fileName)
+{
+ rawImageRec *raw;
+ TK_RGBImageRec *final;
+
+ raw = RawImageOpen(fileName);
+ if (!raw) {
+ fprintf(stderr, "File not found\n");
+ return NULL;
+ }
+ final = (TK_RGBImageRec *)malloc(sizeof(TK_RGBImageRec));
+ if (final == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+ final->sizeX = raw->sizeX;
+ final->sizeY = raw->sizeY;
+ final->components = raw->sizeZ;
+ RawImageGetData(raw, final);
+ RawImageClose(raw);
+ return final;
+}
+
+
+static void FreeImage( TK_RGBImageRec *image )
+{
+ free(image->data);
+ free(image);
+}
+
+
+/*
+ * Load an SGI .rgb file and generate a set of 2-D mipmaps from it.
+ * Input: imageFile - name of .rgb to read
+ * intFormat - internal texture format to use, or number of components
+ * Return: GL_TRUE if success, GL_FALSE if error.
+ */
+GLboolean LoadRGBMipmaps( const char *imageFile, GLint intFormat )
+{
+ GLint w, h;
+ return LoadRGBMipmaps2( imageFile, GL_TEXTURE_2D, intFormat, &w, &h );
+}
+
+
+
+GLboolean LoadRGBMipmaps2( const char *imageFile, GLenum target,
+ GLint intFormat, GLint *width, GLint *height )
+{
+ GLint error;
+ GLenum format;
+ TK_RGBImageRec *image;
+
+ image = tkRGBImageLoad( imageFile );
+ if (!image) {
+ return GL_FALSE;
+ }
+
+ if (image->components==3) {
+ format = GL_RGB;
+ }
+ else if (image->components==4) {
+ format = GL_RGBA;
+ }
+ else {
+ /* not implemented */
+ fprintf(stderr,
+ "Error in LoadRGBMipmaps %d-component images not implemented\n",
+ image->components );
+ return GL_FALSE;
+ }
+
+ error = gluBuild2DMipmaps( target,
+ intFormat,
+ image->sizeX, image->sizeY,
+ format,
+ GL_UNSIGNED_BYTE,
+ image->data );
+
+ *width = image->sizeX;
+ *height = image->sizeY;
+
+ FreeImage(image);
+
+ return error ? GL_FALSE : GL_TRUE;
+}
+
+
+
+/*
+ * Load an SGI .rgb file and return a pointer to the image data.
+ * Input: imageFile - name of .rgb to read
+ * Output: width - width of image
+ * height - height of image
+ * format - format of image (GL_RGB or GL_RGBA)
+ * Return: pointer to image data or NULL if error
+ */
+GLubyte *LoadRGBImage( const char *imageFile, GLint *width, GLint *height,
+ GLenum *format )
+{
+ TK_RGBImageRec *image;
+ GLint bytes;
+ GLubyte *buffer;
+
+ image = tkRGBImageLoad( imageFile );
+ if (!image) {
+ return NULL;
+ }
+
+ if (image->components==3) {
+ *format = GL_RGB;
+ }
+ else if (image->components==4) {
+ *format = GL_RGBA;
+ }
+ else {
+ /* not implemented */
+ fprintf(stderr,
+ "Error in LoadRGBImage %d-component images not implemented\n",
+ image->components );
+ return NULL;
+ }
+
+ *width = image->sizeX;
+ *height = image->sizeY;
+
+ bytes = image->sizeX * image->sizeY * image->components;
+ buffer = (GLubyte *) malloc(bytes);
+ if (!buffer)
+ return NULL;
+
+ memcpy( (void *) buffer, (void *) image->data, bytes );
+
+ FreeImage(image);
+
+ return buffer;
+}
+
+#define CLAMP( X, MIN, MAX ) ( (X)<(MIN) ? (MIN) : ((X)>(MAX) ? (MAX) : (X)) )
+
+
+static void ConvertRGBtoYUV(GLint w, GLint h, GLint texel_bytes,
+ const GLubyte *src,
+ GLushort *dest)
+{
+ GLint i, j;
+
+ for (i = 0; i < h; i++) {
+ for (j = 0; j < w; j++) {
+ const GLfloat r = (src[0]) / 255.0;
+ const GLfloat g = (src[1]) / 255.0;
+ const GLfloat b = (src[2]) / 255.0;
+ GLfloat y, cr, cb;
+ GLint iy, icr, icb;
+
+ y = r * 65.481 + g * 128.553 + b * 24.966 + 16;
+ cb = r * -37.797 + g * -74.203 + b * 112.0 + 128;
+ cr = r * 112.0 + g * -93.786 + b * -18.214 + 128;
+ /*printf("%f %f %f -> %f %f %f\n", r, g, b, y, cb, cr);*/
+ iy = (GLint) CLAMP(y, 0, 254);
+ icb = (GLint) CLAMP(cb, 0, 254);
+ icr = (GLint) CLAMP(cr, 0, 254);
+
+ if (j & 1) {
+ /* odd */
+ *dest = (iy << 8) | icr;
+ }
+ else {
+ /* even */
+ *dest = (iy << 8) | icb;
+ }
+ dest++;
+ src += texel_bytes;
+ }
+ }
+}
+
+
+/*
+ * Load an SGI .rgb file and return a pointer to the image data, converted
+ * to 422 yuv.
+ *
+ * Input: imageFile - name of .rgb to read
+ * Output: width - width of image
+ * height - height of image
+ * Return: pointer to image data or NULL if error
+ */
+GLushort *LoadYUVImage( const char *imageFile, GLint *width, GLint *height )
+{
+ TK_RGBImageRec *image;
+ GLushort *buffer;
+
+ image = tkRGBImageLoad( imageFile );
+ if (!image) {
+ return NULL;
+ }
+
+ if (image->components != 3 && image->components !=4 ) {
+ /* not implemented */
+ fprintf(stderr,
+ "Error in LoadYUVImage %d-component images not implemented\n",
+ image->components );
+ return NULL;
+ }
+
+ *width = image->sizeX;
+ *height = image->sizeY;
+
+ buffer = (GLushort *) malloc( image->sizeX * image->sizeY * 2 );
+
+ if (buffer)
+ ConvertRGBtoYUV( image->sizeX,
+ image->sizeY,
+ image->components,
+ image->data,
+ buffer );
+
+
+ FreeImage(image);
+ return buffer;
+}
+
diff --git a/progs/demos/readtex.h b/progs/demos/readtex.h
new file mode 100644
index 00000000000..6c9a3828d38
--- /dev/null
+++ b/progs/demos/readtex.h
@@ -0,0 +1,26 @@
+/* readtex.h */
+
+#ifndef READTEX_H
+#define READTEX_H
+
+
+#include <GL/gl.h>
+
+
+extern GLboolean
+LoadRGBMipmaps( const char *imageFile, GLint intFormat );
+
+
+extern GLboolean
+LoadRGBMipmaps2( const char *imageFile, GLenum target,
+ GLint intFormat, GLint *width, GLint *height );
+
+
+extern GLubyte *
+LoadRGBImage( const char *imageFile,
+ GLint *width, GLint *height, GLenum *format );
+
+extern GLushort *
+LoadYUVImage( const char *imageFile, GLint *width, GLint *height );
+
+#endif
diff --git a/progs/demos/showbuffer.c b/progs/demos/showbuffer.c
new file mode 100644
index 00000000000..17f84dc62bd
--- /dev/null
+++ b/progs/demos/showbuffer.c
@@ -0,0 +1,192 @@
+/* showbuffer.c */
+
+
+/*
+ * Copy the depth buffer to the color buffer as a grayscale image.
+ * Useful for inspecting the depth buffer values.
+ *
+ * This program is in the public domain.
+ *
+ * Brian Paul November 4, 1998
+ */
+
+
+#include <assert.h>
+#include <stdlib.h>
+#include <GL/gl.h>
+#include "showbuffer.h"
+
+
+
+/*
+ * Copy the depth buffer values into the current color buffer as a
+ * grayscale image.
+ * Input: winWidth, winHeight - size of the window
+ * zBlack - the Z value which should map to black (usually 1)
+ * zWhite - the Z value which should map to white (usually 0)
+ */
+void
+ShowDepthBuffer( GLsizei winWidth, GLsizei winHeight,
+ GLfloat zBlack, GLfloat zWhite )
+{
+ GLfloat *depthValues;
+
+ assert(zBlack >= 0.0);
+ assert(zBlack <= 1.0);
+ assert(zWhite >= 0.0);
+ assert(zWhite <= 1.0);
+ assert(zBlack != zWhite);
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+ /* Read depth values */
+ depthValues = (GLfloat *) malloc(winWidth * winHeight * sizeof(GLfloat));
+ assert(depthValues);
+ glReadPixels(0, 0, winWidth, winHeight, GL_DEPTH_COMPONENT,
+ GL_FLOAT, depthValues);
+
+ /* Map Z values from [zBlack, zWhite] to gray levels in [0, 1] */
+ /* Not using glPixelTransfer() because it's broke on some systems! */
+ if (zBlack != 0.0 || zWhite != 1.0) {
+ GLfloat scale = 1.0 / (zWhite - zBlack);
+ GLfloat bias = -zBlack * scale;
+ int n = winWidth * winHeight;
+ int i;
+ for (i = 0; i < n; i++)
+ depthValues[i] = depthValues[i] * scale + bias;
+ }
+
+ /* save GL state */
+ glPushAttrib(GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT |
+ GL_TRANSFORM_BIT | GL_VIEWPORT_BIT);
+
+ /* setup raster pos for glDrawPixels */
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glOrtho(0.0, (GLdouble) winWidth, 0.0, (GLdouble) winHeight, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glRasterPos2f(0, 0);
+
+ glDrawPixels(winWidth, winHeight, GL_LUMINANCE, GL_FLOAT, depthValues);
+
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ free(depthValues);
+
+ glPopAttrib();
+}
+
+
+
+
+/*
+ * Copy the alpha channel values into the current color buffer as a
+ * grayscale image.
+ * Input: winWidth, winHeight - size of the window
+ */
+void
+ShowAlphaBuffer( GLsizei winWidth, GLsizei winHeight )
+{
+ GLubyte *alphaValues;
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+ /* Read alpha values */
+ alphaValues = (GLubyte *) malloc(winWidth * winHeight * sizeof(GLubyte));
+ assert(alphaValues);
+ glReadPixels(0, 0, winWidth, winHeight, GL_ALPHA, GL_UNSIGNED_BYTE, alphaValues);
+
+ /* save GL state */
+ glPushAttrib(GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL |
+ GL_TRANSFORM_BIT | GL_VIEWPORT_BIT);
+
+ /* setup raster pos for glDrawPixels */
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glOrtho(0.0, (GLdouble) winWidth, 0.0, (GLdouble) winHeight, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glRasterPos2f(0, 0);
+
+ glDrawPixels(winWidth, winHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, alphaValues);
+
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ free(alphaValues);
+
+ glPopAttrib();
+}
+
+
+
+/*
+ * Copy the stencil buffer values into the current color buffer as a
+ * grayscale image.
+ * Input: winWidth, winHeight - size of the window
+ * scale, bias - scale and bias to apply to stencil values for display
+ */
+void
+ShowStencilBuffer( GLsizei winWidth, GLsizei winHeight,
+ GLfloat scale, GLfloat bias )
+{
+ GLubyte *stencilValues;
+
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+
+ /* Read stencil values */
+ stencilValues = (GLubyte *) malloc(winWidth * winHeight * sizeof(GLubyte));
+ assert(stencilValues);
+ glReadPixels(0, 0, winWidth, winHeight, GL_STENCIL_INDEX, GL_UNSIGNED_BYTE, stencilValues);
+
+ /* save GL state */
+ glPushAttrib(GL_CURRENT_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT |
+ GL_PIXEL_MODE_BIT | GL_TRANSFORM_BIT | GL_VIEWPORT_BIT);
+
+ /* setup raster pos for glDrawPixels */
+ glMatrixMode(GL_PROJECTION);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glOrtho(0.0, (GLdouble) winWidth, 0.0, (GLdouble) winHeight, -1.0, 1.0);
+ glMatrixMode(GL_MODELVIEW);
+ glPushMatrix();
+ glLoadIdentity();
+
+ glDisable(GL_STENCIL_TEST);
+ glDisable(GL_DEPTH_TEST);
+ glRasterPos2f(0, 0);
+
+ glPixelTransferf(GL_RED_SCALE, scale);
+ glPixelTransferf(GL_RED_BIAS, bias);
+ glPixelTransferf(GL_GREEN_SCALE, scale);
+ glPixelTransferf(GL_GREEN_BIAS, bias);
+ glPixelTransferf(GL_BLUE_SCALE, scale);
+ glPixelTransferf(GL_BLUE_BIAS, bias);
+
+ glDrawPixels(winWidth, winHeight, GL_LUMINANCE, GL_UNSIGNED_BYTE, stencilValues);
+
+ glPopMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glPopMatrix();
+ free(stencilValues);
+
+ glPopAttrib();
+}
diff --git a/progs/demos/showbuffer.h b/progs/demos/showbuffer.h
new file mode 100644
index 00000000000..63533d8e9b5
--- /dev/null
+++ b/progs/demos/showbuffer.h
@@ -0,0 +1,36 @@
+/* showbuffer. h*/
+
+/*
+ * Copy the depth buffer to the color buffer as a grayscale image.
+ * Useful for inspecting the depth buffer values.
+ *
+ * This program is in the public domain.
+ *
+ * Brian Paul November 4, 1998
+ */
+
+
+#ifndef SHOWBUFFER_H
+#define SHOWBUFFER_H
+
+
+#include <GL/gl.h>
+
+
+
+extern void
+ShowDepthBuffer( GLsizei winWidth, GLsizei winHeight,
+ GLfloat zBlack, GLfloat zWhite );
+
+
+extern void
+ShowAlphaBuffer( GLsizei winWidth, GLsizei winHeight );
+
+
+extern void
+ShowStencilBuffer( GLsizei winWidth, GLsizei winHeight,
+ GLfloat scale, GLfloat bias );
+
+
+
+#endif
diff --git a/progs/demos/spriteblast.c b/progs/demos/spriteblast.c
index d6e9a4de2fd..f0d3d0dfd41 100644
--- a/progs/demos/spriteblast.c
+++ b/progs/demos/spriteblast.c
@@ -537,6 +537,9 @@ main(int argc, char **argv)
glutAddMenuEntry("Quit", 666);
glutAttachMenu(GLUT_RIGHT_BUTTON);
+ makePointList();
+ makeSprite();
+
glShadeModel(GL_FLAT);
glEnable(GL_DEPTH_TEST);
glEnable(GL_POINT_SMOOTH);
@@ -546,9 +549,6 @@ main(int argc, char **argv)
glPointParameterfvARB(GL_POINT_DISTANCE_ATTENUATION_ARB, theQuad);
#endif
- makePointList();
- makeSprite();
-
glutMainLoop();
return 0; /* ANSI C requires main to return int. */
}
diff --git a/progs/demos/stex3d.c b/progs/demos/stex3d.c
index e4554d071f3..83ae3684ae2 100644
--- a/progs/demos/stex3d.c
+++ b/progs/demos/stex3d.c
@@ -342,19 +342,19 @@ parseCmdLine(int argc, char **argv)
GLint i;
for (i = 1; i < argc; i++) {
- if (strstr(argv[i], "-w") == 0) {
+ if (strcmp(argv[i], "-help") == 0) {
+ printHelp();
+ return GL_FALSE;
+ }
+ else if (strstr(argv[i], "-w") != NULL) {
tex_width = atoi((argv[i]) + 2);
}
- else if (strstr(argv[i], "-h") == 0) {
+ else if (strstr(argv[i], "-h") != NULL) {
tex_height = atoi((argv[i]) + 2);
}
- else if (strstr(argv[i], "-d") == 0) {
+ else if (strstr(argv[i], "-d") != NULL) {
tex_depth = atoi((argv[i]) + 2);
}
- else if (strcmp(argv[i], "-help") == 0) {
- printHelp();
- return GL_FALSE;
- }
else {
printf("%s (Bad option).\n", argv[i]);
printHelp();
diff --git a/progs/demos/trackball.c b/progs/demos/trackball.c
new file mode 100644
index 00000000000..a6c4c60d06b
--- /dev/null
+++ b/progs/demos/trackball.c
@@ -0,0 +1,338 @@
+#include <stdio.h>
+/*
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States. Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+/*
+ * Trackball code:
+ *
+ * Implementation of a virtual trackball.
+ * Implemented by Gavin Bell, lots of ideas from Thant Tessman and
+ * the August '88 issue of Siggraph's "Computer Graphics," pp. 121-129.
+ *
+ * Vector manip code:
+ *
+ * Original code from:
+ * David M. Ciemiewicz, Mark Grossman, Henry Moreton, and Paul Haeberli
+ *
+ * Much mucking with by:
+ * Gavin Bell
+ */
+#if defined(_WIN32)
+#pragma warning (disable:4244) /* disable bogus conversion warnings */
+#endif
+#include <math.h>
+#include "trackball.h"
+
+/*
+ * This size should really be based on the distance from the center of
+ * rotation to the point on the object underneath the mouse. That
+ * point would then track the mouse as closely as possible. This is a
+ * simple example, though, so that is left as an Exercise for the
+ * Programmer.
+ */
+#define TRACKBALLSIZE (0.8f)
+
+/*
+ * Local function prototypes (not defined in trackball.h)
+ */
+static float tb_project_to_sphere(float, float, float);
+static void normalize_quat(float [4]);
+
+static void
+vzero(float v[3])
+{
+ v[0] = 0.0;
+ v[1] = 0.0;
+ v[2] = 0.0;
+}
+
+static void
+vset(float v[3], float x, float y, float z)
+{
+ v[0] = x;
+ v[1] = y;
+ v[2] = z;
+}
+
+static void
+vsub(const float src1[3], const float src2[3], float dst[3])
+{
+ dst[0] = src1[0] - src2[0];
+ dst[1] = src1[1] - src2[1];
+ dst[2] = src1[2] - src2[2];
+}
+
+static void
+vcopy(const float v1[3], float v2[3])
+{
+ register int i;
+ for (i = 0 ; i < 3 ; i++)
+ v2[i] = v1[i];
+}
+
+static void
+vcross(const float v1[3], const float v2[3], float cross[3])
+{
+ float temp[3];
+
+ temp[0] = (v1[1] * v2[2]) - (v1[2] * v2[1]);
+ temp[1] = (v1[2] * v2[0]) - (v1[0] * v2[2]);
+ temp[2] = (v1[0] * v2[1]) - (v1[1] * v2[0]);
+ vcopy(temp, cross);
+}
+
+static float
+vlength(const float v[3])
+{
+ return sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
+}
+
+static void
+vscale(float v[3], float div)
+{
+ v[0] *= div;
+ v[1] *= div;
+ v[2] *= div;
+}
+
+static void
+vnormal(float v[3])
+{
+ vscale(v,1.0/vlength(v));
+}
+
+static float
+vdot(const float v1[3], const float v2[3])
+{
+ return v1[0]*v2[0] + v1[1]*v2[1] + v1[2]*v2[2];
+}
+
+static void
+vadd(const float src1[3], const float src2[3], float dst[3])
+{
+ dst[0] = src1[0] + src2[0];
+ dst[1] = src1[1] + src2[1];
+ dst[2] = src1[2] + src2[2];
+}
+
+/*
+ * Ok, simulate a track-ball. Project the points onto the virtual
+ * trackball, then figure out the axis of rotation, which is the cross
+ * product of P1 P2 and O P1 (O is the center of the ball, 0,0,0)
+ * Note: This is a deformed trackball-- is a trackball in the center,
+ * but is deformed into a hyperbolic sheet of rotation away from the
+ * center. This particular function was chosen after trying out
+ * several variations.
+ *
+ * It is assumed that the arguments to this routine are in the range
+ * (-1.0 ... 1.0)
+ */
+void
+trackball(float q[4], float p1x, float p1y, float p2x, float p2y)
+{
+ float a[3]; /* Axis of rotation */
+ float phi; /* how much to rotate about axis */
+ float p1[3], p2[3], d[3];
+ float t;
+
+ if (p1x == p2x && p1y == p2y) {
+ /* Zero rotation */
+ vzero(q);
+ q[3] = 1.0;
+ return;
+ }
+
+ /*
+ * First, figure out z-coordinates for projection of P1 and P2 to
+ * deformed sphere
+ */
+ vset(p1,p1x,p1y,tb_project_to_sphere(TRACKBALLSIZE,p1x,p1y));
+ vset(p2,p2x,p2y,tb_project_to_sphere(TRACKBALLSIZE,p2x,p2y));
+
+ /*
+ * Now, we want the cross product of P1 and P2
+ */
+ vcross(p2,p1,a);
+
+ /*
+ * Figure out how much to rotate around that axis.
+ */
+ vsub(p1,p2,d);
+ t = vlength(d) / (2.0*TRACKBALLSIZE);
+
+ /*
+ * Avoid problems with out-of-control values...
+ */
+ if (t > 1.0) t = 1.0;
+ if (t < -1.0) t = -1.0;
+ phi = 2.0 * asin(t);
+
+ axis_to_quat(a,phi,q);
+}
+
+/*
+ * Given an axis and angle, compute quaternion.
+ */
+void
+axis_to_quat(const float a[3], float phi, float q[4])
+{
+ vcopy(a,q);
+ vnormal(q);
+ vscale(q, sin(phi/2.0));
+ q[3] = cos(phi/2.0);
+}
+
+/*
+ * Project an x,y pair onto a sphere of radius r OR a hyperbolic sheet
+ * if we are away from the center of the sphere.
+ */
+static float
+tb_project_to_sphere(float r, float x, float y)
+{
+ float d, t, z;
+
+ d = sqrt(x*x + y*y);
+ if (d < r * 0.70710678118654752440) { /* Inside sphere */
+ z = sqrt(r*r - d*d);
+ } else { /* On hyperbola */
+ t = r / 1.41421356237309504880;
+ z = t*t / d;
+ }
+ return z;
+}
+
+/*
+ * Given two rotations, e1 and e2, expressed as quaternion rotations,
+ * figure out the equivalent single rotation and stuff it into dest.
+ *
+ * This routine also normalizes the result every RENORMCOUNT times it is
+ * called, to keep error from creeping in.
+ *
+ * NOTE: This routine is written so that q1 or q2 may be the same
+ * as dest (or each other).
+ */
+
+#define RENORMCOUNT 97
+
+void
+add_quats(const float q1[4], const float q2[4], float dest[4])
+{
+ static int count=0;
+ float t1[4], t2[4], t3[4];
+ float tf[4];
+
+#if 0
+printf("q1 = %f %f %f %f\n", q1[0], q1[1], q1[2], q1[3]);
+printf("q2 = %f %f %f %f\n", q2[0], q2[1], q2[2], q2[3]);
+#endif
+
+ vcopy(q1,t1);
+ vscale(t1,q2[3]);
+
+ vcopy(q2,t2);
+ vscale(t2,q1[3]);
+
+ vcross(q2,q1,t3);
+ vadd(t1,t2,tf);
+ vadd(t3,tf,tf);
+ tf[3] = q1[3] * q2[3] - vdot(q1,q2);
+
+#if 0
+printf("tf = %f %f %f %f\n", tf[0], tf[1], tf[2], tf[3]);
+#endif
+
+ dest[0] = tf[0];
+ dest[1] = tf[1];
+ dest[2] = tf[2];
+ dest[3] = tf[3];
+
+ if (++count > RENORMCOUNT) {
+ count = 0;
+ normalize_quat(dest);
+ }
+}
+
+/*
+ * Quaternions always obey: a^2 + b^2 + c^2 + d^2 = 1.0
+ * If they don't add up to 1.0, dividing by their magnitued will
+ * renormalize them.
+ *
+ * Note: See the following for more information on quaternions:
+ *
+ * - Shoemake, K., Animating rotation with quaternion curves, Computer
+ * Graphics 19, No 3 (Proc. SIGGRAPH'85), 245-254, 1985.
+ * - Pletinckx, D., Quaternion calculus as a basic tool in computer
+ * graphics, The Visual Computer 5, 2-13, 1989.
+ */
+static void
+normalize_quat(float q[4])
+{
+ int i;
+ float mag;
+
+ mag = sqrt(q[0]*q[0] + q[1]*q[1] + q[2]*q[2] + q[3]*q[3]);
+ for (i = 0; i < 4; i++)
+ q[i] /= mag;
+}
+
+/*
+ * Build a rotation matrix, given a quaternion rotation.
+ *
+ */
+void
+build_rotmatrix(float m[4][4], const float q[4])
+{
+ m[0][0] = 1.0 - 2.0 * (q[1] * q[1] + q[2] * q[2]);
+ m[0][1] = 2.0 * (q[0] * q[1] - q[2] * q[3]);
+ m[0][2] = 2.0 * (q[2] * q[0] + q[1] * q[3]);
+ m[0][3] = 0.0;
+
+ m[1][0] = 2.0 * (q[0] * q[1] + q[2] * q[3]);
+ m[1][1]= 1.0 - 2.0 * (q[2] * q[2] + q[0] * q[0]);
+ m[1][2] = 2.0 * (q[1] * q[2] - q[0] * q[3]);
+ m[1][3] = 0.0;
+
+ m[2][0] = 2.0 * (q[2] * q[0] - q[1] * q[3]);
+ m[2][1] = 2.0 * (q[1] * q[2] + q[0] * q[3]);
+ m[2][2] = 1.0 - 2.0 * (q[1] * q[1] + q[0] * q[0]);
+ m[2][3] = 0.0;
+
+ m[3][0] = 0.0;
+ m[3][1] = 0.0;
+ m[3][2] = 0.0;
+ m[3][3] = 1.0;
+}
+
diff --git a/progs/demos/trackball.h b/progs/demos/trackball.h
new file mode 100644
index 00000000000..9b278640e10
--- /dev/null
+++ b/progs/demos/trackball.h
@@ -0,0 +1,84 @@
+/*
+ * (c) Copyright 1993, 1994, Silicon Graphics, Inc.
+ * ALL RIGHTS RESERVED
+ * Permission to use, copy, modify, and distribute this software for
+ * any purpose and without fee is hereby granted, provided that the above
+ * copyright notice appear in all copies and that both the copyright notice
+ * and this permission notice appear in supporting documentation, and that
+ * the name of Silicon Graphics, Inc. not be used in advertising
+ * or publicity pertaining to distribution of the software without specific,
+ * written prior permission.
+ *
+ * THE MATERIAL EMBODIED ON THIS SOFTWARE IS PROVIDED TO YOU "AS-IS"
+ * AND WITHOUT WARRANTY OF ANY KIND, EXPRESS, IMPLIED OR OTHERWISE,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTY OF MERCHANTABILITY OR
+ * FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL SILICON
+ * GRAPHICS, INC. BE LIABLE TO YOU OR ANYONE ELSE FOR ANY DIRECT,
+ * SPECIAL, INCIDENTAL, INDIRECT OR CONSEQUENTIAL DAMAGES OF ANY
+ * KIND, OR ANY DAMAGES WHATSOEVER, INCLUDING WITHOUT LIMITATION,
+ * LOSS OF PROFIT, LOSS OF USE, SAVINGS OR REVENUE, OR THE CLAIMS OF
+ * THIRD PARTIES, WHETHER OR NOT SILICON GRAPHICS, INC. HAS BEEN
+ * ADVISED OF THE POSSIBILITY OF SUCH LOSS, HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, ARISING OUT OF OR IN CONNECTION WITH THE
+ * POSSESSION, USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * US Government Users Restricted Rights
+ * Use, duplication, or disclosure by the Government is subject to
+ * restrictions set forth in FAR 52.227.19(c)(2) or subparagraph
+ * (c)(1)(ii) of the Rights in Technical Data and Computer Software
+ * clause at DFARS 252.227-7013 and/or in similar or successor
+ * clauses in the FAR or the DOD or NASA FAR Supplement.
+ * Unpublished-- rights reserved under the copyright laws of the
+ * United States. Contractor/manufacturer is Silicon Graphics,
+ * Inc., 2011 N. Shoreline Blvd., Mountain View, CA 94039-7311.
+ *
+ * OpenGL(TM) is a trademark of Silicon Graphics, Inc.
+ */
+/*
+ * trackball.h
+ * A virtual trackball implementation
+ * Written by Gavin Bell for Silicon Graphics, November 1988.
+ */
+
+#ifndef TRACKBALL_H
+#define TRACKBALL_H
+
+
+/*
+ * Pass the x and y coordinates of the last and current positions of
+ * the mouse, scaled so they are from (-1.0 ... 1.0).
+ *
+ * The resulting rotation is returned as a quaternion rotation in the
+ * first paramater.
+ */
+void
+trackball(float q[4], float p1x, float p1y, float p2x, float p2y);
+
+/*
+ * Given two quaternions, add them together to get a third quaternion.
+ * Adding quaternions to get a compound rotation is analagous to adding
+ * translations to get a compound translation. When incrementally
+ * adding rotations, the first argument here should be the new
+ * rotation, the second and third the total rotation (which will be
+ * over-written with the resulting new total rotation).
+ */
+void
+add_quats(const float q1[4], const float q2[4], float dest[4]);
+
+/*
+ * A useful function, builds a rotation matrix in Matrix based on
+ * given quaternion.
+ */
+void
+build_rotmatrix(float m[4][4], const float q[4]);
+
+/*
+ * This function computes a quaternion based on an axis (defined by
+ * the given vector) and an angle about which to rotate. The angle is
+ * expressed in radians. The result is put into the third argument.
+ */
+void
+axis_to_quat(const float a[3], float phi, float q[4]);
+
+
+#endif /* TRACKBALL_H */
diff --git a/progs/demos/vao_demo.c b/progs/demos/vao_demo.c
new file mode 100644
index 00000000000..ce416712fe2
--- /dev/null
+++ b/progs/demos/vao_demo.c
@@ -0,0 +1,330 @@
+/*
+ * (C) Copyright IBM Corporation 2006
+ * All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * on the rights to use, copy, modify, merge, publish, distribute, sub
+ * license, and/or sell copies of the Software, and to permit persons to whom
+ * the Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice (including the next
+ * paragraph) shall be included in all copies or substantial portions of the
+ * Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL
+ * IBM AND/OR THEIR SUPPLIERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ */
+
+#include <assert.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <math.h>
+
+#ifdef __darwin__
+#include <GLUT/glut.h>
+
+typedef void (* PFNGLBINDVERTEXARRAYAPPLEPROC) (GLuint array);
+typedef void (* PFNGLDELETEVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays);
+typedef void (* PFNGLGENVERTEXARRAYSAPPLEPROC) (GLsizei n, const GLuint *arrays);
+typedef GLboolean (* PFNGLISVERTEXARRAYAPPLEPROC) (GLuint array);
+
+#else
+#include <GL/glut.h>
+#endif
+
+static PFNGLBINDVERTEXARRAYAPPLEPROC bind_vertex_array = NULL;
+static PFNGLGENVERTEXARRAYSAPPLEPROC gen_vertex_arrays = NULL;
+static PFNGLDELETEVERTEXARRAYSAPPLEPROC delete_vertex_arrays = NULL;
+static PFNGLISVERTEXARRAYAPPLEPROC is_vertex_array = NULL;
+
+static int Width = 400;
+static int Height = 200;
+static int Win = 0;
+static const GLfloat Near = 5.0, Far = 25.0;
+static GLfloat angle = 0.0;
+
+static GLuint cube_array_obj = 0;
+static GLuint oct_array_obj = 0;
+
+static const GLfloat cube_vert[] = {
+ -0.5, -0.5, -0.5, 1.0,
+ 0.5, -0.5, -0.5, 1.0,
+ 0.5, 0.5, -0.5, 1.0,
+ -0.5, 0.5, -0.5, 1.0,
+
+ -0.5, -0.5, 0.5, 1.0,
+ 0.5, -0.5, 0.5, 1.0,
+ 0.5, 0.5, 0.5, 1.0,
+ -0.5, 0.5, 0.5, 1.0,
+
+ -0.5, 0.5, -0.5, 1.0,
+ 0.5, 0.5, -0.5, 1.0,
+ 0.5, 0.5, 0.5, 1.0,
+ -0.5, 0.5, 0.5, 1.0,
+
+ -0.5, -0.5, -0.5, 1.0,
+ 0.5, -0.5, -0.5, 1.0,
+ 0.5, -0.5, 0.5, 1.0,
+ -0.5, -0.5, 0.5, 1.0,
+
+ 0.5, -0.5, -0.5, 1.0,
+ 0.5, -0.5, 0.5, 1.0,
+ 0.5, 0.5, 0.5, 1.0,
+ 0.5, 0.5, -0.5, 1.0,
+
+ -0.5, -0.5, -0.5, 1.0,
+ -0.5, -0.5, 0.5, 1.0,
+ -0.5, 0.5, 0.5, 1.0,
+ -0.5, 0.5, -0.5, 1.0,
+
+};
+
+static const GLfloat cube_color[] = {
+ 1.0, 0.0, 0.0, 1.0,
+ 1.0, 0.0, 0.0, 1.0,
+ 1.0, 0.0, 0.0, 1.0,
+ 1.0, 0.0, 0.0, 1.0,
+
+ 0.0, 1.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0, 1.0,
+ 0.0, 1.0, 0.0, 1.0,
+
+ 0.0, 0.0, 1.0, 1.0,
+ 0.0, 0.0, 1.0, 1.0,
+ 0.0, 0.0, 1.0, 1.0,
+ 0.0, 0.0, 1.0, 1.0,
+
+ 1.0, 0.0, 1.0, 1.0,
+ 1.0, 0.0, 1.0, 1.0,
+ 1.0, 0.0, 1.0, 1.0,
+ 1.0, 0.0, 1.0, 1.0,
+
+ 1.0, 1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0, 1.0,
+ 1.0, 1.0, 1.0, 1.0,
+
+ 0.5, 0.5, 0.5, 1.0,
+ 0.5, 0.5, 0.5, 1.0,
+ 0.5, 0.5, 0.5, 1.0,
+ 0.5, 0.5, 0.5, 1.0,
+};
+
+static const GLfloat oct_vert[] = {
+ 0.0, 0.0, 0.7071, 1.0,
+ 0.5, 0.5, 0.0, 1.0,
+ -0.5, 0.5, 0.0, 1.0,
+
+ 0.0, 0.0, 0.7071, 1.0,
+ 0.5, -0.5, 0.0, 1.0,
+ -0.5, -0.5, 0.0, 1.0,
+
+ 0.0, 0.0, 0.7071, 1.0,
+ -0.5, -0.5, 0.0, 1.0,
+ -0.5, 0.5, 0.0, 1.0,
+
+ 0.0, 0.0, 0.7071, 1.0,
+ 0.5, 0.5, 0.0, 1.0,
+ 0.5, -0.5, 0.0, 1.0,
+
+
+ 0.0, 0.0, -0.7071, 1.0,
+ 0.5, 0.5, 0.0, 1.0,
+ -0.5, 0.5, 0.0, 1.0,
+
+ 0.0, 0.0, -0.7071, 1.0,
+ 0.5, -0.5, 0.0, 1.0,
+ -0.5, -0.5, 0.0, 1.0,
+
+ 0.0, 0.0, -0.7071, 1.0,
+ -0.5, -0.5, 0.0, 1.0,
+ -0.5, 0.5, 0.0, 1.0,
+
+ 0.0, 0.0, -0.7071, 1.0,
+ 0.5, 0.5, 0.0, 1.0,
+ 0.5, -0.5, 0.0, 1.0,
+};
+
+static const GLfloat oct_color[] = {
+ 1.0, 0.64, 0.0, 1.0,
+ 1.0, 0.64, 0.0, 1.0,
+ 1.0, 0.64, 0.0, 1.0,
+
+ 0.8, 0.51, 0.0, 1.0,
+ 0.8, 0.51, 0.0, 1.0,
+ 0.8, 0.51, 0.0, 1.0,
+
+ 0.5, 0.32, 0.0, 1.0,
+ 0.5, 0.32, 0.0, 1.0,
+ 0.5, 0.32, 0.0, 1.0,
+
+ 0.2, 0.13, 0.0, 1.0,
+ 0.2, 0.13, 0.0, 1.0,
+ 0.2, 0.13, 0.0, 1.0,
+
+ 0.2, 0.13, 0.0, 1.0,
+ 0.2, 0.13, 0.0, 1.0,
+ 0.2, 0.13, 0.0, 1.0,
+
+ 0.5, 0.32, 0.0, 1.0,
+ 0.5, 0.32, 0.0, 1.0,
+ 0.5, 0.32, 0.0, 1.0,
+
+ 0.8, 0.51, 0.0, 1.0,
+ 0.8, 0.51, 0.0, 1.0,
+ 0.8, 0.51, 0.0, 1.0,
+
+ 1.0, 0.64, 0.0, 1.0,
+ 1.0, 0.64, 0.0, 1.0,
+ 1.0, 0.64, 0.0, 1.0,
+};
+
+static void Display( void )
+{
+ glClearColor(0.1, 0.1, 0.4, 0);
+ glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
+
+ glMatrixMode( GL_MODELVIEW );
+ glLoadIdentity();
+ glTranslatef( 0.0, 0.0, -15.0 );
+ glRotatef( angle, 0.0 * angle , 0.0 * angle, 1.0 );
+
+
+ (*bind_vertex_array)( cube_array_obj );
+ glPushMatrix();
+ glTranslatef(-1.5, 0, 0);
+ glRotatef( angle, 0.3 * angle , 0.8 * angle, 1.0 );
+ glDrawArrays( GL_QUADS, 0, 4 * 6 );
+ glPopMatrix();
+
+
+ (*bind_vertex_array)( oct_array_obj );
+ glPushMatrix();
+ glTranslatef(1.5, 0, 0);
+ glRotatef( angle, 0.3 * angle , 0.8 * angle, 1.0 );
+ glDrawArrays( GL_TRIANGLES, 0, 3 * 8 );
+ glPopMatrix();
+
+ glutSwapBuffers();
+}
+
+
+static void Idle( void )
+{
+ static double t0 = -1.;
+ double dt, t = glutGet(GLUT_ELAPSED_TIME) / 1000.0;
+ if (t0 < 0.0)
+ t0 = t;
+ dt = t - t0;
+ t0 = t;
+
+ angle += 70.0 * dt; /* 70 degrees per second */
+ angle = fmod(angle, 360.0); /* prevents eventual overflow */
+
+ glutPostRedisplay();
+}
+
+
+static void Visible( int vis )
+{
+ if ( vis == GLUT_VISIBLE ) {
+ glutIdleFunc( Idle );
+ }
+ else {
+ glutIdleFunc( NULL );
+ }
+}
+static void Reshape( int width, int height )
+{
+ GLfloat ar = (float) width / (float) height;
+ Width = width;
+ Height = height;
+ glViewport( 0, 0, width, height );
+ glMatrixMode( GL_PROJECTION );
+ glLoadIdentity();
+ glFrustum( -ar, ar, -1.0, 1.0, Near, Far );
+}
+
+
+static void Key( unsigned char key, int x, int y )
+{
+ (void) x;
+ (void) y;
+ switch (key) {
+ case 27:
+ glutDestroyWindow(Win);
+ exit(0);
+ break;
+ }
+ glutPostRedisplay();
+}
+
+
+static void Init( void )
+{
+ const char * const ver_string = (const char * const)
+ glGetString( GL_VERSION );
+
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", ver_string);
+
+ if ( !glutExtensionSupported("GL_APPLE_vertex_array_object") ) {
+ printf("Sorry, this program requires GL_APPLE_vertex_array_object\n");
+ exit(1);
+ }
+
+ bind_vertex_array = (PFNGLBINDVERTEXARRAYAPPLEPROC) glutGetProcAddress( "glBindVertexArrayAPPLE" );
+ gen_vertex_arrays = (PFNGLGENVERTEXARRAYSAPPLEPROC) glutGetProcAddress( "glGenVertexArraysAPPLE" );
+ delete_vertex_arrays = (PFNGLDELETEVERTEXARRAYSAPPLEPROC) glutGetProcAddress( "glDeleteVertexArraysAPPLE" );
+ is_vertex_array = (PFNGLISVERTEXARRAYAPPLEPROC) glutGetProcAddress( "glIsVertexArrayAPPLE" );
+
+ assert(bind_vertex_array);
+ assert(gen_vertex_arrays);
+ assert(delete_vertex_arrays);
+ assert(is_vertex_array);
+
+ glEnable( GL_DEPTH_TEST );
+
+ (*gen_vertex_arrays)( 1, & cube_array_obj );
+ (*bind_vertex_array)( cube_array_obj );
+ glVertexPointer( 4, GL_FLOAT, sizeof(GLfloat) * 4, cube_vert);
+ glColorPointer( 4, GL_FLOAT, sizeof(GLfloat) * 4, cube_color);
+ glEnableClientState( GL_VERTEX_ARRAY );
+ glEnableClientState( GL_COLOR_ARRAY );
+
+ (*gen_vertex_arrays)( 1, & oct_array_obj );
+ (*bind_vertex_array)( oct_array_obj );
+ glVertexPointer( 4, GL_FLOAT, sizeof(GLfloat) * 4, oct_vert);
+ glColorPointer( 4, GL_FLOAT, sizeof(GLfloat) * 4, oct_color);
+ glEnableClientState( GL_VERTEX_ARRAY );
+ glEnableClientState( GL_COLOR_ARRAY );
+
+ (*bind_vertex_array)( 0 );
+ glVertexPointer( 4, GL_FLOAT, sizeof(GLfloat) * 4, (void *) 0xDEADBEEF );
+ glColorPointer( 4, GL_FLOAT, sizeof(GLfloat) * 4, (void *) 0xBADDC0DE );
+}
+
+
+int main( int argc, char *argv[] )
+{
+ glutInit( &argc, argv );
+ glutInitWindowPosition( 0, 0 );
+ glutInitWindowSize( Width, Height );
+ glutInitDisplayMode( GLUT_RGB | GLUT_DOUBLE | GLUT_DEPTH );
+ Win = glutCreateWindow( "GL_APPLE_vertex_array_object demo" );
+ glutReshapeFunc( Reshape );
+ glutKeyboardFunc( Key );
+ glutDisplayFunc( Display );
+ glutVisibilityFunc( Visible );
+ Init();
+ glutMainLoop();
+ return 0;
+}
diff --git a/progs/ggi/gears.c b/progs/ggi/gears.c
index 56711f5d544..ac2e9f2a6ea 100644
--- a/progs/ggi/gears.c
+++ b/progs/ggi/gears.c
@@ -1,4 +1,4 @@
-/* $Id: gears.c,v 1.3 1999-08-22 08:56:50 jtaylor Exp $ */
+/* $Id: gears.c,v 1.3 1999/08/22 08:56:50 jtaylor Exp $ */
/*
* 3-D gear wheels. This program is in the public domain.
diff --git a/progs/osdemos/Makefile b/progs/osdemos/Makefile
index 7d1bc08a4e0..f8cba9ee99a 100644
--- a/progs/osdemos/Makefile
+++ b/progs/osdemos/Makefile
@@ -5,13 +5,13 @@ include $(TOP)/configs/current
INCDIR = $(TOP)/include
-OSMESA_LIBS = -L$(LIB_DIR) -lglut -lOSMesa -lGLU -lGL $(APP_LIB_DEPS)
+OSMESA_LIBS = -L$(TOP)/$(LIB_DIR) -lOSMesa $(APP_LIB_DEPS)
-OSMESA16_LIBS = -L$(LIB_DIR) -lglut -lOSMesa16 -lGLU -lGL $(APP_LIB_DEPS)
+OSMESA16_LIBS = -L$(TOP)/$(LIB_DIR) -lglut -lOSMesa16 -lGLU -lGL $(APP_LIB_DEPS)
-OSMESA32_LIBS = -L$(LIB_DIR) -lglut -lOSMesa32 -lGLU -lGL $(APP_LIB_DEPS)
+OSMESA32_LIBS = -L$(TOP)/$(LIB_DIR) -lglut -lOSMesa32 -lGLU -lGL $(APP_LIB_DEPS)
-LIB_DEP = $(LIB_DIR)/$(GL_LIB_NAME) $(LIB_DIR)/$(GLU_LIB_NAME) $(LIB_DIR)/$(GLUT_LIB_NAME)
+LIB_DEP = $(TOP)/$(LIB_DIR)/$(GL_LIB_NAME) $(TOP)/$(LIB_DIR)/$(GLU_LIB_NAME) $(TOP)/$(LIB_DIR)/$(GLUT_LIB_NAME)
PROGS = \
osdemo \
@@ -76,3 +76,7 @@ clean:
-rm -f $(PROGS)
-rm -f *.o *~
-rm -f readtex.[ch] showbuffer.[ch]
+ -rm -f *.ppm
+ -rm -f osdemo16 osdemo32
+
+
diff --git a/progs/osdemos/osdemo.c b/progs/osdemos/osdemo.c
index 95e2ff97875..f7ce121f702 100644
--- a/progs/osdemos/osdemo.c
+++ b/progs/osdemos/osdemo.c
@@ -1,4 +1,3 @@
-
/*
* Demo of off-screen Mesa rendering
*
@@ -14,31 +13,88 @@
* PPM output provided by Joerg Schmalzl.
* ASCII PPM output added by Brian Paul.
*
- * Usage: osdemo [-perf] [filename]
- *
- * -perf: Redraws the image 1000 times, displaying the FPS every 5 secs.
- * filename: file to store the TGA or PPM output
+ * Usage: osdemo [filename]
*/
+#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "GL/osmesa.h"
-#include "GL/glut.h"
+#include "GL/glu.h"
#define SAVE_TARGA
-
#define WIDTH 400
#define HEIGHT 400
-static GLint T0 = 0;
-static GLint Frames = 0;
-static int perf = 0;
-static void render_image( void )
+static void
+Sphere(float radius, int slices, int stacks)
+{
+ GLUquadric *q = gluNewQuadric();
+ gluQuadricNormals(q, GLU_SMOOTH);
+ gluSphere(q, radius, slices, stacks);
+ gluDeleteQuadric(q);
+}
+
+
+static void
+Cone(float base, float height, int slices, int stacks)
+{
+ GLUquadric *q = gluNewQuadric();
+ gluQuadricDrawStyle(q, GLU_FILL);
+ gluQuadricNormals(q, GLU_SMOOTH);
+ gluCylinder(q, base, 0.0, height, slices, stacks);
+ gluDeleteQuadric(q);
+}
+
+
+static void
+Torus(float innerRadius, float outerRadius, int sides, int rings)
+{
+ /* from GLUT... */
+ int i, j;
+ GLfloat theta, phi, theta1;
+ GLfloat cosTheta, sinTheta;
+ GLfloat cosTheta1, sinTheta1;
+ const GLfloat ringDelta = 2.0 * M_PI / rings;
+ const GLfloat sideDelta = 2.0 * M_PI / sides;
+
+ theta = 0.0;
+ cosTheta = 1.0;
+ sinTheta = 0.0;
+ for (i = rings - 1; i >= 0; i--) {
+ theta1 = theta + ringDelta;
+ cosTheta1 = cos(theta1);
+ sinTheta1 = sin(theta1);
+ glBegin(GL_QUAD_STRIP);
+ phi = 0.0;
+ for (j = sides; j >= 0; j--) {
+ GLfloat cosPhi, sinPhi, dist;
+
+ phi += sideDelta;
+ cosPhi = cos(phi);
+ sinPhi = sin(phi);
+ dist = outerRadius + innerRadius * cosPhi;
+
+ glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
+ glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, innerRadius * sinPhi);
+ glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
+ glVertex3f(cosTheta * dist, -sinTheta * dist, innerRadius * sinPhi);
+ }
+ glEnd();
+ theta = theta1;
+ cosTheta = cosTheta1;
+ sinTheta = sinTheta1;
+ }
+}
+
+
+static void
+render_image(void)
{
GLfloat light_ambient[] = { 0.0, 0.0, 0.0, 1.0 };
GLfloat light_diffuse[] = { 1.0, 1.0, 1.0, 1.0 };
@@ -72,20 +128,20 @@ static void render_image( void )
glTranslatef(-0.75, 0.5, 0.0);
glRotatef(90.0, 1.0, 0.0, 0.0);
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red_mat );
- glutSolidTorus(0.275, 0.85, 20, 20);
+ Torus(0.275, 0.85, 20, 20);
glPopMatrix();
glPushMatrix();
glTranslatef(-0.75, -0.5, 0.0);
glRotatef(270.0, 1.0, 0.0, 0.0);
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, green_mat );
- glutSolidCone(1.0, 2.0, 16, 1);
+ Cone(1.0, 2.0, 16, 1);
glPopMatrix();
glPushMatrix();
glTranslatef(0.75, 0.0, -1.0);
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue_mat );
- glutSolidSphere(1.0, 20, 20);
+ Sphere(1.0, 20, 20);
glPopMatrix();
glPopMatrix();
@@ -94,18 +150,6 @@ static void render_image( void )
* Make sure buffered commands are finished!!!
*/
glFinish();
-
- Frames++;
- if (perf) {
- GLint t = glutGet(GLUT_ELAPSED_TIME);
- if (t - T0 >= 5000) {
- GLfloat seconds = (t - T0) / 1000.0;
- GLfloat fps = Frames / seconds;
- printf("%d frames in %6.3f seconds = %6.3f FPS\n", Frames, seconds, fps);
- T0 = t;
- Frames = 0;
- }
- }
}
@@ -201,7 +245,8 @@ write_ppm(const char *filename, const GLubyte *buffer, int width, int height)
-int main( int argc, char *argv[] )
+int
+main(int argc, char *argv[])
{
void *buffer;
int i;
@@ -219,9 +264,9 @@ int main( int argc, char *argv[] )
return 0;
}
- for ( i=1; i<argc; i++ ) {
- if (argv[i][0] != '-') filename = argv[i];
- if (strcmp(argv[i], "-perf")==0) perf = 1;
+ for (i = 1; i < argc; i++) {
+ if (argv[i][0] != '-')
+ filename = argv[i];
}
/* Allocate the image buffer */
@@ -247,9 +292,6 @@ int main( int argc, char *argv[] )
}
render_image();
- if (perf)
- for(i=0; i< 1000; i++)
- render_image();
if (filename != NULL) {
#ifdef SAVE_TARGA
diff --git a/progs/osdemos/ostest1.c b/progs/osdemos/ostest1.c
index 61f0f3da29c..001e3686162 100644
--- a/progs/osdemos/ostest1.c
+++ b/progs/osdemos/ostest1.c
@@ -9,11 +9,12 @@
*/
#include <assert.h>
+#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "GL/osmesa.h"
-#include "GL/glut.h"
+#include "GL/glu.h"
#define WIDTH 600
@@ -23,6 +24,120 @@ static GLboolean WriteFiles = GL_FALSE;
static GLboolean Gradient = GL_FALSE;
+static void
+Sphere(float radius, int slices, int stacks)
+{
+ GLUquadric *q = gluNewQuadric();
+ gluQuadricNormals(q, GLU_SMOOTH);
+ gluSphere(q, radius, slices, stacks);
+ gluDeleteQuadric(q);
+}
+
+
+static void
+Cone(float base, float height, int slices, int stacks)
+{
+ GLUquadric *q = gluNewQuadric();
+ gluQuadricDrawStyle(q, GLU_FILL);
+ gluQuadricNormals(q, GLU_SMOOTH);
+ gluCylinder(q, base, 0.0, height, slices, stacks);
+ gluDeleteQuadric(q);
+}
+
+
+static void
+Torus(float innerRadius, float outerRadius, int sides, int rings)
+{
+ /* from GLUT... */
+ int i, j;
+ GLfloat theta, phi, theta1;
+ GLfloat cosTheta, sinTheta;
+ GLfloat cosTheta1, sinTheta1;
+ const GLfloat ringDelta = 2.0 * M_PI / rings;
+ const GLfloat sideDelta = 2.0 * M_PI / sides;
+
+ theta = 0.0;
+ cosTheta = 1.0;
+ sinTheta = 0.0;
+ for (i = rings - 1; i >= 0; i--) {
+ theta1 = theta + ringDelta;
+ cosTheta1 = cos(theta1);
+ sinTheta1 = sin(theta1);
+ glBegin(GL_QUAD_STRIP);
+ phi = 0.0;
+ for (j = sides; j >= 0; j--) {
+ GLfloat cosPhi, sinPhi, dist;
+
+ phi += sideDelta;
+ cosPhi = cos(phi);
+ sinPhi = sin(phi);
+ dist = outerRadius + innerRadius * cosPhi;
+
+ glNormal3f(cosTheta1 * cosPhi, -sinTheta1 * cosPhi, sinPhi);
+ glVertex3f(cosTheta1 * dist, -sinTheta1 * dist, innerRadius * sinPhi);
+ glNormal3f(cosTheta * cosPhi, -sinTheta * cosPhi, sinPhi);
+ glVertex3f(cosTheta * dist, -sinTheta * dist, innerRadius * sinPhi);
+ }
+ glEnd();
+ theta = theta1;
+ cosTheta = cosTheta1;
+ sinTheta = sinTheta1;
+ }
+}
+
+
+static void Cube(float size)
+{
+ size = 0.5 * size;
+
+ glBegin(GL_QUADS);
+ /* +X face */
+ glNormal3f(1, 0, 0);
+ glVertex3f(size, -size, size);
+ glVertex3f(size, -size, -size);
+ glVertex3f(size, size, -size);
+ glVertex3f(size, size, size);
+
+ /* -X face */
+ glNormal3f(-1, 0, 0);
+ glVertex3f(-size, size, size);
+ glVertex3f(-size, size, -size);
+ glVertex3f(-size, -size, -size);
+ glVertex3f(-size, -size, size);
+
+ /* +Y face */
+ glNormal3f(0, 1, 0);
+ glVertex3f(-size, size, size);
+ glVertex3f( size, size, size);
+ glVertex3f( size, size, -size);
+ glVertex3f(-size, size, -size);
+
+ /* -Y face */
+ glNormal3f(0, -1, 0);
+ glVertex3f(-size, -size, -size);
+ glVertex3f( size, -size, -size);
+ glVertex3f( size, -size, size);
+ glVertex3f(-size, -size, size);
+
+ /* +Z face */
+ glNormal3f(0, 0, 1);
+ glVertex3f(-size, -size, size);
+ glVertex3f( size, -size, size);
+ glVertex3f( size, size, size);
+ glVertex3f(-size, size, size);
+
+ /* -Z face */
+ glNormal3f(0, 0, -1);
+ glVertex3f(-size, size, -size);
+ glVertex3f( size, size, -size);
+ glVertex3f( size, -size, -size);
+ glVertex3f(-size, -size, -size);
+
+ glEnd();
+}
+
+
+
/**
* Draw red/green gradient across bottom of image.
* Read pixels to check deltas.
@@ -66,7 +181,9 @@ render_image(void)
static const GLfloat red_mat[4] = { 1.0, 0.2, 0.2, 1.0 };
static const GLfloat green_mat[4] = { 0.2, 1.0, 0.2, 1.0 };
static const GLfloat blue_mat[4] = { 0.2, 0.2, 1.0, 1.0 };
+#if 0
static const GLfloat yellow_mat[4] = { 0.8, 0.8, 0.0, 1.0 };
+#endif
static const GLfloat purple_mat[4] = { 0.8, 0.4, 0.8, 0.6 };
glLightfv(GL_LIGHT0, GL_AMBIENT, light_ambient);
@@ -106,36 +223,41 @@ render_image(void)
glTranslatef(-1.5, 0.5, 0.0);
glRotatef(90.0, 1.0, 0.0, 0.0);
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, red_mat );
- glutSolidTorus(0.275, 0.85, 20, 20);
+ Torus(0.275, 0.85, 20, 20);
glPopMatrix();
glPushMatrix();
glTranslatef(-1.5, -0.5, 0.0);
glRotatef(270.0, 1.0, 0.0, 0.0);
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, green_mat );
- glutSolidCone(1.0, 2.0, 16, 1);
+ Cone(1.0, 2.0, 16, 1);
glPopMatrix();
glPushMatrix();
- glTranslatef(0.75, 0.0, -1.0);
+ glTranslatef(0.95, 0.0, -0.8);
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blue_mat );
- glutSolidSphere(1.0, 20, 20);
+ glLineWidth(2.0);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
+ Sphere(1.2, 20, 20);
+ glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
glPopMatrix();
+#if 0
glPushMatrix();
glTranslatef(0.75, 0.0, 1.3);
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, yellow_mat );
glutWireTeapot(1.0);
glPopMatrix();
+#endif
glPushMatrix();
- glTranslatef(-0.5, 0.0, 2.5);
+ glTranslatef(-0.25, 0.0, 2.5);
glRotatef(40, 0, 1, 0);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glEnable(GL_BLEND);
glEnable(GL_CULL_FACE);
glMaterialfv( GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, purple_mat );
- glutSolidCube(1.0);
+ Cube(1.0);
glDisable(GL_BLEND);
glDisable(GL_CULL_FACE);
glPopMatrix();
@@ -270,6 +392,8 @@ test(GLenum type, GLint bits, const char *filename)
/* Bind the buffer to the context and make it current */
if (!OSMesaMakeCurrent( ctx, buffer, type, WIDTH, HEIGHT )) {
printf("OSMesaMakeCurrent (%d bits/channel) failed!\n", bits);
+ free(buffer);
+ OSMesaDestroyContext(ctx);
return 0;
}
@@ -320,6 +444,8 @@ test(GLenum type, GLint bits, const char *filename)
OSMesaDestroyContext(ctx);
+ free(buffer);
+
return 1;
}
diff --git a/progs/osdemos/readtex.c b/progs/osdemos/readtex.c
new file mode 100644
index 00000000000..37d5fcd0d3a
--- /dev/null
+++ b/progs/osdemos/readtex.c
@@ -0,0 +1,454 @@
+/* readtex.c */
+
+/*
+ * Read an SGI .rgb image file and generate a mipmap texture set.
+ * Much of this code was borrowed from SGI's tk OpenGL toolkit.
+ */
+
+
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "readtex.h"
+
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+
+/*
+** RGB Image Structure
+*/
+
+typedef struct _TK_RGBImageRec {
+ GLint sizeX, sizeY;
+ GLint components;
+ unsigned char *data;
+} TK_RGBImageRec;
+
+
+
+/******************************************************************************/
+
+typedef struct _rawImageRec {
+ unsigned short imagic;
+ unsigned short type;
+ unsigned short dim;
+ unsigned short sizeX, sizeY, sizeZ;
+ unsigned long min, max;
+ unsigned long wasteBytes;
+ char name[80];
+ unsigned long colorMap;
+ FILE *file;
+ unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA;
+ unsigned long rleEnd;
+ GLuint *rowStart;
+ GLint *rowSize;
+} rawImageRec;
+
+/******************************************************************************/
+
+static void ConvertShort(unsigned short *array, long length)
+{
+ unsigned long b1, b2;
+ unsigned char *ptr;
+
+ ptr = (unsigned char *)array;
+ while (length--) {
+ b1 = *ptr++;
+ b2 = *ptr++;
+ *array++ = (unsigned short) ((b1 << 8) | (b2));
+ }
+}
+
+static void ConvertLong(GLuint *array, long length)
+{
+ unsigned long b1, b2, b3, b4;
+ unsigned char *ptr;
+
+ ptr = (unsigned char *)array;
+ while (length--) {
+ b1 = *ptr++;
+ b2 = *ptr++;
+ b3 = *ptr++;
+ b4 = *ptr++;
+ *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
+ }
+}
+
+static rawImageRec *RawImageOpen(const char *fileName)
+{
+ union {
+ int testWord;
+ char testByte[4];
+ } endianTest;
+ rawImageRec *raw;
+ GLenum swapFlag;
+ int x;
+
+ endianTest.testWord = 1;
+ if (endianTest.testByte[0] == 1) {
+ swapFlag = GL_TRUE;
+ } else {
+ swapFlag = GL_FALSE;
+ }
+
+ raw = (rawImageRec *)calloc(1, sizeof(rawImageRec));
+ if (raw == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+ if ((raw->file = fopen(fileName, "rb")) == NULL) {
+ perror(fileName);
+ return NULL;
+ }
+
+ fread(raw, 1, 12, raw->file);
+
+ if (swapFlag) {
+ ConvertShort(&raw->imagic, 6);
+ }
+
+ raw->tmp = (unsigned char *)malloc(raw->sizeX*256);
+ raw->tmpR = (unsigned char *)malloc(raw->sizeX*256);
+ raw->tmpG = (unsigned char *)malloc(raw->sizeX*256);
+ raw->tmpB = (unsigned char *)malloc(raw->sizeX*256);
+ if (raw->sizeZ==4) {
+ raw->tmpA = (unsigned char *)malloc(raw->sizeX*256);
+ }
+ if (raw->tmp == NULL || raw->tmpR == NULL || raw->tmpG == NULL ||
+ raw->tmpB == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+
+ if ((raw->type & 0xFF00) == 0x0100) {
+ x = raw->sizeY * raw->sizeZ * sizeof(GLuint);
+ raw->rowStart = (GLuint *)malloc(x);
+ raw->rowSize = (GLint *)malloc(x);
+ if (raw->rowStart == NULL || raw->rowSize == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+ raw->rleEnd = 512 + (2 * x);
+ fseek(raw->file, 512, SEEK_SET);
+ fread(raw->rowStart, 1, x, raw->file);
+ fread(raw->rowSize, 1, x, raw->file);
+ if (swapFlag) {
+ ConvertLong(raw->rowStart, (long) (x/sizeof(GLuint)));
+ ConvertLong((GLuint *)raw->rowSize, (long) (x/sizeof(GLint)));
+ }
+ }
+ return raw;
+}
+
+static void RawImageClose(rawImageRec *raw)
+{
+ fclose(raw->file);
+ free(raw->tmp);
+ free(raw->tmpR);
+ free(raw->tmpG);
+ free(raw->tmpB);
+ if (raw->rowStart)
+ free(raw->rowStart);
+ if (raw->rowSize)
+ free(raw->rowSize);
+ if (raw->sizeZ>3) {
+ free(raw->tmpA);
+ }
+ free(raw);
+}
+
+static void RawImageGetRow(rawImageRec *raw, unsigned char *buf, int y, int z)
+{
+ unsigned char *iPtr, *oPtr, pixel;
+ int count, done = 0;
+
+ if ((raw->type & 0xFF00) == 0x0100) {
+ fseek(raw->file, (long) raw->rowStart[y+z*raw->sizeY], SEEK_SET);
+ fread(raw->tmp, 1, (unsigned int)raw->rowSize[y+z*raw->sizeY],
+ raw->file);
+
+ iPtr = raw->tmp;
+ oPtr = buf;
+ while (!done) {
+ pixel = *iPtr++;
+ count = (int)(pixel & 0x7F);
+ if (!count) {
+ done = 1;
+ return;
+ }
+ if (pixel & 0x80) {
+ while (count--) {
+ *oPtr++ = *iPtr++;
+ }
+ } else {
+ pixel = *iPtr++;
+ while (count--) {
+ *oPtr++ = pixel;
+ }
+ }
+ }
+ } else {
+ fseek(raw->file, 512+(y*raw->sizeX)+(z*raw->sizeX*raw->sizeY),
+ SEEK_SET);
+ fread(buf, 1, raw->sizeX, raw->file);
+ }
+}
+
+
+static void RawImageGetData(rawImageRec *raw, TK_RGBImageRec *final)
+{
+ unsigned char *ptr;
+ int i, j;
+
+ final->data = (unsigned char *)malloc((raw->sizeX+1)*(raw->sizeY+1)*4);
+ if (final->data == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ }
+
+ ptr = final->data;
+ for (i = 0; i < (int)(raw->sizeY); i++) {
+ RawImageGetRow(raw, raw->tmpR, i, 0);
+ RawImageGetRow(raw, raw->tmpG, i, 1);
+ RawImageGetRow(raw, raw->tmpB, i, 2);
+ if (raw->sizeZ>3) {
+ RawImageGetRow(raw, raw->tmpA, i, 3);
+ }
+ for (j = 0; j < (int)(raw->sizeX); j++) {
+ *ptr++ = *(raw->tmpR + j);
+ *ptr++ = *(raw->tmpG + j);
+ *ptr++ = *(raw->tmpB + j);
+ if (raw->sizeZ>3) {
+ *ptr++ = *(raw->tmpA + j);
+ }
+ }
+ }
+}
+
+
+static TK_RGBImageRec *tkRGBImageLoad(const char *fileName)
+{
+ rawImageRec *raw;
+ TK_RGBImageRec *final;
+
+ raw = RawImageOpen(fileName);
+ if (!raw) {
+ fprintf(stderr, "File not found\n");
+ return NULL;
+ }
+ final = (TK_RGBImageRec *)malloc(sizeof(TK_RGBImageRec));
+ if (final == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+ final->sizeX = raw->sizeX;
+ final->sizeY = raw->sizeY;
+ final->components = raw->sizeZ;
+ RawImageGetData(raw, final);
+ RawImageClose(raw);
+ return final;
+}
+
+
+static void FreeImage( TK_RGBImageRec *image )
+{
+ free(image->data);
+ free(image);
+}
+
+
+/*
+ * Load an SGI .rgb file and generate a set of 2-D mipmaps from it.
+ * Input: imageFile - name of .rgb to read
+ * intFormat - internal texture format to use, or number of components
+ * Return: GL_TRUE if success, GL_FALSE if error.
+ */
+GLboolean LoadRGBMipmaps( const char *imageFile, GLint intFormat )
+{
+ GLint w, h;
+ return LoadRGBMipmaps2( imageFile, GL_TEXTURE_2D, intFormat, &w, &h );
+}
+
+
+
+GLboolean LoadRGBMipmaps2( const char *imageFile, GLenum target,
+ GLint intFormat, GLint *width, GLint *height )
+{
+ GLint error;
+ GLenum format;
+ TK_RGBImageRec *image;
+
+ image = tkRGBImageLoad( imageFile );
+ if (!image) {
+ return GL_FALSE;
+ }
+
+ if (image->components==3) {
+ format = GL_RGB;
+ }
+ else if (image->components==4) {
+ format = GL_RGBA;
+ }
+ else {
+ /* not implemented */
+ fprintf(stderr,
+ "Error in LoadRGBMipmaps %d-component images not implemented\n",
+ image->components );
+ return GL_FALSE;
+ }
+
+ error = gluBuild2DMipmaps( target,
+ intFormat,
+ image->sizeX, image->sizeY,
+ format,
+ GL_UNSIGNED_BYTE,
+ image->data );
+
+ *width = image->sizeX;
+ *height = image->sizeY;
+
+ FreeImage(image);
+
+ return error ? GL_FALSE : GL_TRUE;
+}
+
+
+
+/*
+ * Load an SGI .rgb file and return a pointer to the image data.
+ * Input: imageFile - name of .rgb to read
+ * Output: width - width of image
+ * height - height of image
+ * format - format of image (GL_RGB or GL_RGBA)
+ * Return: pointer to image data or NULL if error
+ */
+GLubyte *LoadRGBImage( const char *imageFile, GLint *width, GLint *height,
+ GLenum *format )
+{
+ TK_RGBImageRec *image;
+ GLint bytes;
+ GLubyte *buffer;
+
+ image = tkRGBImageLoad( imageFile );
+ if (!image) {
+ return NULL;
+ }
+
+ if (image->components==3) {
+ *format = GL_RGB;
+ }
+ else if (image->components==4) {
+ *format = GL_RGBA;
+ }
+ else {
+ /* not implemented */
+ fprintf(stderr,
+ "Error in LoadRGBImage %d-component images not implemented\n",
+ image->components );
+ return NULL;
+ }
+
+ *width = image->sizeX;
+ *height = image->sizeY;
+
+ bytes = image->sizeX * image->sizeY * image->components;
+ buffer = (GLubyte *) malloc(bytes);
+ if (!buffer)
+ return NULL;
+
+ memcpy( (void *) buffer, (void *) image->data, bytes );
+
+ FreeImage(image);
+
+ return buffer;
+}
+
+#define CLAMP( X, MIN, MAX ) ( (X)<(MIN) ? (MIN) : ((X)>(MAX) ? (MAX) : (X)) )
+
+
+static void ConvertRGBtoYUV(GLint w, GLint h, GLint texel_bytes,
+ const GLubyte *src,
+ GLushort *dest)
+{
+ GLint i, j;
+
+ for (i = 0; i < h; i++) {
+ for (j = 0; j < w; j++) {
+ const GLfloat r = (src[0]) / 255.0;
+ const GLfloat g = (src[1]) / 255.0;
+ const GLfloat b = (src[2]) / 255.0;
+ GLfloat y, cr, cb;
+ GLint iy, icr, icb;
+
+ y = r * 65.481 + g * 128.553 + b * 24.966 + 16;
+ cb = r * -37.797 + g * -74.203 + b * 112.0 + 128;
+ cr = r * 112.0 + g * -93.786 + b * -18.214 + 128;
+ /*printf("%f %f %f -> %f %f %f\n", r, g, b, y, cb, cr);*/
+ iy = (GLint) CLAMP(y, 0, 254);
+ icb = (GLint) CLAMP(cb, 0, 254);
+ icr = (GLint) CLAMP(cr, 0, 254);
+
+ if (j & 1) {
+ /* odd */
+ *dest = (iy << 8) | icr;
+ }
+ else {
+ /* even */
+ *dest = (iy << 8) | icb;
+ }
+ dest++;
+ src += texel_bytes;
+ }
+ }
+}
+
+
+/*
+ * Load an SGI .rgb file and return a pointer to the image data, converted
+ * to 422 yuv.
+ *
+ * Input: imageFile - name of .rgb to read
+ * Output: width - width of image
+ * height - height of image
+ * Return: pointer to image data or NULL if error
+ */
+GLushort *LoadYUVImage( const char *imageFile, GLint *width, GLint *height )
+{
+ TK_RGBImageRec *image;
+ GLushort *buffer;
+
+ image = tkRGBImageLoad( imageFile );
+ if (!image) {
+ return NULL;
+ }
+
+ if (image->components != 3 && image->components !=4 ) {
+ /* not implemented */
+ fprintf(stderr,
+ "Error in LoadYUVImage %d-component images not implemented\n",
+ image->components );
+ return NULL;
+ }
+
+ *width = image->sizeX;
+ *height = image->sizeY;
+
+ buffer = (GLushort *) malloc( image->sizeX * image->sizeY * 2 );
+
+ if (buffer)
+ ConvertRGBtoYUV( image->sizeX,
+ image->sizeY,
+ image->components,
+ image->data,
+ buffer );
+
+
+ FreeImage(image);
+ return buffer;
+}
+
diff --git a/progs/redbook/Makefile b/progs/redbook/Makefile
index 4cfbb9aeacd..febc74441b9 100644
--- a/progs/redbook/Makefile
+++ b/progs/redbook/Makefile
@@ -5,7 +5,7 @@ include $(TOP)/configs/current
INCDIR = $(TOP)/include
-LIB_DEP = $(LIB_DIR)/$(GL_LIB_NAME) $(LIB_DIR)/$(GLU_LIB_NAME) $(LIB_DIR)/$(GLUT_LIB_NAME)
+LIB_DEP = $(TOP)/$(LIB_DIR)/$(GL_LIB_NAME) $(TOP)/$(LIB_DIR)/$(GLU_LIB_NAME) $(TOP)/$(LIB_DIR)/$(GLUT_LIB_NAME)
PROGS = aaindex aapoly aargb accanti accpersp alpha alpha3D anti \
bezcurve bezmesh checker clip colormat cube depthcue dof \
diff --git a/progs/samples/Makefile b/progs/samples/Makefile
index f14b7dfc009..063008dccff 100644
--- a/progs/samples/Makefile
+++ b/progs/samples/Makefile
@@ -5,7 +5,7 @@ include $(TOP)/configs/current
INCDIR = $(TOP)/include
-LIB_DEP = $(LIB_DIR)/$(GL_LIB_NAME) $(LIB_DIR)/$(GLU_LIB_NAME) $(LIB_DIR)/$(GLUT_LIB_NAME)
+LIB_DEP = $(TOP)/$(LIB_DIR)/$(GL_LIB_NAME) $(TOP)/$(LIB_DIR)/$(GLU_LIB_NAME) $(TOP)/$(LIB_DIR)/$(GLUT_LIB_NAME)
PROGS = accum bitmap1 bitmap2 blendeq blendxor copy cursor depth eval fog \
font line logo nurb olympic overlay point prim quad select \
diff --git a/progs/samples/readtex.c b/progs/samples/readtex.c
new file mode 100644
index 00000000000..37d5fcd0d3a
--- /dev/null
+++ b/progs/samples/readtex.c
@@ -0,0 +1,454 @@
+/* readtex.c */
+
+/*
+ * Read an SGI .rgb image file and generate a mipmap texture set.
+ * Much of this code was borrowed from SGI's tk OpenGL toolkit.
+ */
+
+
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "readtex.h"
+
+
+#ifndef SEEK_SET
+# define SEEK_SET 0
+#endif
+
+
+/*
+** RGB Image Structure
+*/
+
+typedef struct _TK_RGBImageRec {
+ GLint sizeX, sizeY;
+ GLint components;
+ unsigned char *data;
+} TK_RGBImageRec;
+
+
+
+/******************************************************************************/
+
+typedef struct _rawImageRec {
+ unsigned short imagic;
+ unsigned short type;
+ unsigned short dim;
+ unsigned short sizeX, sizeY, sizeZ;
+ unsigned long min, max;
+ unsigned long wasteBytes;
+ char name[80];
+ unsigned long colorMap;
+ FILE *file;
+ unsigned char *tmp, *tmpR, *tmpG, *tmpB, *tmpA;
+ unsigned long rleEnd;
+ GLuint *rowStart;
+ GLint *rowSize;
+} rawImageRec;
+
+/******************************************************************************/
+
+static void ConvertShort(unsigned short *array, long length)
+{
+ unsigned long b1, b2;
+ unsigned char *ptr;
+
+ ptr = (unsigned char *)array;
+ while (length--) {
+ b1 = *ptr++;
+ b2 = *ptr++;
+ *array++ = (unsigned short) ((b1 << 8) | (b2));
+ }
+}
+
+static void ConvertLong(GLuint *array, long length)
+{
+ unsigned long b1, b2, b3, b4;
+ unsigned char *ptr;
+
+ ptr = (unsigned char *)array;
+ while (length--) {
+ b1 = *ptr++;
+ b2 = *ptr++;
+ b3 = *ptr++;
+ b4 = *ptr++;
+ *array++ = (b1 << 24) | (b2 << 16) | (b3 << 8) | (b4);
+ }
+}
+
+static rawImageRec *RawImageOpen(const char *fileName)
+{
+ union {
+ int testWord;
+ char testByte[4];
+ } endianTest;
+ rawImageRec *raw;
+ GLenum swapFlag;
+ int x;
+
+ endianTest.testWord = 1;
+ if (endianTest.testByte[0] == 1) {
+ swapFlag = GL_TRUE;
+ } else {
+ swapFlag = GL_FALSE;
+ }
+
+ raw = (rawImageRec *)calloc(1, sizeof(rawImageRec));
+ if (raw == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+ if ((raw->file = fopen(fileName, "rb")) == NULL) {
+ perror(fileName);
+ return NULL;
+ }
+
+ fread(raw, 1, 12, raw->file);
+
+ if (swapFlag) {
+ ConvertShort(&raw->imagic, 6);
+ }
+
+ raw->tmp = (unsigned char *)malloc(raw->sizeX*256);
+ raw->tmpR = (unsigned char *)malloc(raw->sizeX*256);
+ raw->tmpG = (unsigned char *)malloc(raw->sizeX*256);
+ raw->tmpB = (unsigned char *)malloc(raw->sizeX*256);
+ if (raw->sizeZ==4) {
+ raw->tmpA = (unsigned char *)malloc(raw->sizeX*256);
+ }
+ if (raw->tmp == NULL || raw->tmpR == NULL || raw->tmpG == NULL ||
+ raw->tmpB == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+
+ if ((raw->type & 0xFF00) == 0x0100) {
+ x = raw->sizeY * raw->sizeZ * sizeof(GLuint);
+ raw->rowStart = (GLuint *)malloc(x);
+ raw->rowSize = (GLint *)malloc(x);
+ if (raw->rowStart == NULL || raw->rowSize == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+ raw->rleEnd = 512 + (2 * x);
+ fseek(raw->file, 512, SEEK_SET);
+ fread(raw->rowStart, 1, x, raw->file);
+ fread(raw->rowSize, 1, x, raw->file);
+ if (swapFlag) {
+ ConvertLong(raw->rowStart, (long) (x/sizeof(GLuint)));
+ ConvertLong((GLuint *)raw->rowSize, (long) (x/sizeof(GLint)));
+ }
+ }
+ return raw;
+}
+
+static void RawImageClose(rawImageRec *raw)
+{
+ fclose(raw->file);
+ free(raw->tmp);
+ free(raw->tmpR);
+ free(raw->tmpG);
+ free(raw->tmpB);
+ if (raw->rowStart)
+ free(raw->rowStart);
+ if (raw->rowSize)
+ free(raw->rowSize);
+ if (raw->sizeZ>3) {
+ free(raw->tmpA);
+ }
+ free(raw);
+}
+
+static void RawImageGetRow(rawImageRec *raw, unsigned char *buf, int y, int z)
+{
+ unsigned char *iPtr, *oPtr, pixel;
+ int count, done = 0;
+
+ if ((raw->type & 0xFF00) == 0x0100) {
+ fseek(raw->file, (long) raw->rowStart[y+z*raw->sizeY], SEEK_SET);
+ fread(raw->tmp, 1, (unsigned int)raw->rowSize[y+z*raw->sizeY],
+ raw->file);
+
+ iPtr = raw->tmp;
+ oPtr = buf;
+ while (!done) {
+ pixel = *iPtr++;
+ count = (int)(pixel & 0x7F);
+ if (!count) {
+ done = 1;
+ return;
+ }
+ if (pixel & 0x80) {
+ while (count--) {
+ *oPtr++ = *iPtr++;
+ }
+ } else {
+ pixel = *iPtr++;
+ while (count--) {
+ *oPtr++ = pixel;
+ }
+ }
+ }
+ } else {
+ fseek(raw->file, 512+(y*raw->sizeX)+(z*raw->sizeX*raw->sizeY),
+ SEEK_SET);
+ fread(buf, 1, raw->sizeX, raw->file);
+ }
+}
+
+
+static void RawImageGetData(rawImageRec *raw, TK_RGBImageRec *final)
+{
+ unsigned char *ptr;
+ int i, j;
+
+ final->data = (unsigned char *)malloc((raw->sizeX+1)*(raw->sizeY+1)*4);
+ if (final->data == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ }
+
+ ptr = final->data;
+ for (i = 0; i < (int)(raw->sizeY); i++) {
+ RawImageGetRow(raw, raw->tmpR, i, 0);
+ RawImageGetRow(raw, raw->tmpG, i, 1);
+ RawImageGetRow(raw, raw->tmpB, i, 2);
+ if (raw->sizeZ>3) {
+ RawImageGetRow(raw, raw->tmpA, i, 3);
+ }
+ for (j = 0; j < (int)(raw->sizeX); j++) {
+ *ptr++ = *(raw->tmpR + j);
+ *ptr++ = *(raw->tmpG + j);
+ *ptr++ = *(raw->tmpB + j);
+ if (raw->sizeZ>3) {
+ *ptr++ = *(raw->tmpA + j);
+ }
+ }
+ }
+}
+
+
+static TK_RGBImageRec *tkRGBImageLoad(const char *fileName)
+{
+ rawImageRec *raw;
+ TK_RGBImageRec *final;
+
+ raw = RawImageOpen(fileName);
+ if (!raw) {
+ fprintf(stderr, "File not found\n");
+ return NULL;
+ }
+ final = (TK_RGBImageRec *)malloc(sizeof(TK_RGBImageRec));
+ if (final == NULL) {
+ fprintf(stderr, "Out of memory!\n");
+ return NULL;
+ }
+ final->sizeX = raw->sizeX;
+ final->sizeY = raw->sizeY;
+ final->components = raw->sizeZ;
+ RawImageGetData(raw, final);
+ RawImageClose(raw);
+ return final;
+}
+
+
+static void FreeImage( TK_RGBImageRec *image )
+{
+ free(image->data);
+ free(image);
+}
+
+
+/*
+ * Load an SGI .rgb file and generate a set of 2-D mipmaps from it.
+ * Input: imageFile - name of .rgb to read
+ * intFormat - internal texture format to use, or number of components
+ * Return: GL_TRUE if success, GL_FALSE if error.
+ */
+GLboolean LoadRGBMipmaps( const char *imageFile, GLint intFormat )
+{
+ GLint w, h;
+ return LoadRGBMipmaps2( imageFile, GL_TEXTURE_2D, intFormat, &w, &h );
+}
+
+
+
+GLboolean LoadRGBMipmaps2( const char *imageFile, GLenum target,
+ GLint intFormat, GLint *width, GLint *height )
+{
+ GLint error;
+ GLenum format;
+ TK_RGBImageRec *image;
+
+ image = tkRGBImageLoad( imageFile );
+ if (!image) {
+ return GL_FALSE;
+ }
+
+ if (image->components==3) {
+ format = GL_RGB;
+ }
+ else if (image->components==4) {
+ format = GL_RGBA;
+ }
+ else {
+ /* not implemented */
+ fprintf(stderr,
+ "Error in LoadRGBMipmaps %d-component images not implemented\n",
+ image->components );
+ return GL_FALSE;
+ }
+
+ error = gluBuild2DMipmaps( target,
+ intFormat,
+ image->sizeX, image->sizeY,
+ format,
+ GL_UNSIGNED_BYTE,
+ image->data );
+
+ *width = image->sizeX;
+ *height = image->sizeY;
+
+ FreeImage(image);
+
+ return error ? GL_FALSE : GL_TRUE;
+}
+
+
+
+/*
+ * Load an SGI .rgb file and return a pointer to the image data.
+ * Input: imageFile - name of .rgb to read
+ * Output: width - width of image
+ * height - height of image
+ * format - format of image (GL_RGB or GL_RGBA)
+ * Return: pointer to image data or NULL if error
+ */
+GLubyte *LoadRGBImage( const char *imageFile, GLint *width, GLint *height,
+ GLenum *format )
+{
+ TK_RGBImageRec *image;
+ GLint bytes;
+ GLubyte *buffer;
+
+ image = tkRGBImageLoad( imageFile );
+ if (!image) {
+ return NULL;
+ }
+
+ if (image->components==3) {
+ *format = GL_RGB;
+ }
+ else if (image->components==4) {
+ *format = GL_RGBA;
+ }
+ else {
+ /* not implemented */
+ fprintf(stderr,
+ "Error in LoadRGBImage %d-component images not implemented\n",
+ image->components );
+ return NULL;
+ }
+
+ *width = image->sizeX;
+ *height = image->sizeY;
+
+ bytes = image->sizeX * image->sizeY * image->components;
+ buffer = (GLubyte *) malloc(bytes);
+ if (!buffer)
+ return NULL;
+
+ memcpy( (void *) buffer, (void *) image->data, bytes );
+
+ FreeImage(image);
+
+ return buffer;
+}
+
+#define CLAMP( X, MIN, MAX ) ( (X)<(MIN) ? (MIN) : ((X)>(MAX) ? (MAX) : (X)) )
+
+
+static void ConvertRGBtoYUV(GLint w, GLint h, GLint texel_bytes,
+ const GLubyte *src,
+ GLushort *dest)
+{
+ GLint i, j;
+
+ for (i = 0; i < h; i++) {
+ for (j = 0; j < w; j++) {
+ const GLfloat r = (src[0]) / 255.0;
+ const GLfloat g = (src[1]) / 255.0;
+ const GLfloat b = (src[2]) / 255.0;
+ GLfloat y, cr, cb;
+ GLint iy, icr, icb;
+
+ y = r * 65.481 + g * 128.553 + b * 24.966 + 16;
+ cb = r * -37.797 + g * -74.203 + b * 112.0 + 128;
+ cr = r * 112.0 + g * -93.786 + b * -18.214 + 128;
+ /*printf("%f %f %f -> %f %f %f\n", r, g, b, y, cb, cr);*/
+ iy = (GLint) CLAMP(y, 0, 254);
+ icb = (GLint) CLAMP(cb, 0, 254);
+ icr = (GLint) CLAMP(cr, 0, 254);
+
+ if (j & 1) {
+ /* odd */
+ *dest = (iy << 8) | icr;
+ }
+ else {
+ /* even */
+ *dest = (iy << 8) | icb;
+ }
+ dest++;
+ src += texel_bytes;
+ }
+ }
+}
+
+
+/*
+ * Load an SGI .rgb file and return a pointer to the image data, converted
+ * to 422 yuv.
+ *
+ * Input: imageFile - name of .rgb to read
+ * Output: width - width of image
+ * height - height of image
+ * Return: pointer to image data or NULL if error
+ */
+GLushort *LoadYUVImage( const char *imageFile, GLint *width, GLint *height )
+{
+ TK_RGBImageRec *image;
+ GLushort *buffer;
+
+ image = tkRGBImageLoad( imageFile );
+ if (!image) {
+ return NULL;
+ }
+
+ if (image->components != 3 && image->components !=4 ) {
+ /* not implemented */
+ fprintf(stderr,
+ "Error in LoadYUVImage %d-component images not implemented\n",
+ image->components );
+ return NULL;
+ }
+
+ *width = image->sizeX;
+ *height = image->sizeY;
+
+ buffer = (GLushort *) malloc( image->sizeX * image->sizeY * 2 );
+
+ if (buffer)
+ ConvertRGBtoYUV( image->sizeX,
+ image->sizeY,
+ image->components,
+ image->data,
+ buffer );
+
+
+ FreeImage(image);
+ return buffer;
+}
+
diff --git a/progs/windml/ugldrawpix.c b/progs/windml/ugldrawpix.c
index f511a92ff56..b33be2c6aee 100644
--- a/progs/windml/ugldrawpix.c
+++ b/progs/windml/ugldrawpix.c
@@ -8,7 +8,7 @@
/*
* $Log: ugldrawpix.c,v $
- * Revision 1.2 2001-09-10 19:21:13 brianp
+ * Revision 1.2 2001/09/10 19:21:13 brianp
* WindML updates (Stephane Raimbault)
*
* Revision 1.1 2001/08/20 16:07:11 brianp
diff --git a/progs/windml/ugltexcyl.c b/progs/windml/ugltexcyl.c
index cd453a3407f..d2fe687b926 100644
--- a/progs/windml/ugltexcyl.c
+++ b/progs/windml/ugltexcyl.c
@@ -8,7 +8,7 @@
/*
* $Log: ugltexcyl.c,v $
- * Revision 1.2 2001-09-10 19:21:13 brianp
+ * Revision 1.2 2001/09/10 19:21:13 brianp
* WindML updates (Stephane Raimbault)
*
* Revision 1.1 2001/08/20 16:07:11 brianp
diff --git a/progs/xdemos/Makefile b/progs/xdemos/Makefile
index 37b9504e55d..4ca8b107a24 100644
--- a/progs/xdemos/Makefile
+++ b/progs/xdemos/Makefile
@@ -6,7 +6,7 @@ include $(TOP)/configs/current
INCDIR = $(TOP)/include
-LIB_DEP = $(LIB_DIR)/$(GL_LIB_NAME) $(LIB_DIR)/$(GLU_LIB_NAME)
+LIB_DEP = $(TOP)/$(LIB_DIR)/$(GL_LIB_NAME) $(TOP)/$(LIB_DIR)/$(GLU_LIB_NAME)
PROGS = glthreads \
glxdemo \
diff --git a/progs/xdemos/glxgears2.c b/progs/xdemos/glxgears2.c
new file mode 100644
index 00000000000..5de5601240e
--- /dev/null
+++ b/progs/xdemos/glxgears2.c
@@ -0,0 +1,522 @@
+/*
+ * Copyright (C) 1999-2001 Brian Paul All Rights Reserved.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a
+ * copy of this software and associated documentation files (the "Software"),
+ * to deal in the Software without restriction, including without limitation
+ * the rights to use, copy, modify, merge, publish, distribute, sublicense,
+ * and/or sell copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included
+ * in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * BRIAN PAUL BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
+ * AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+/*
+ * This is a port of the infamous "gears" demo to straight GLX (i.e. no GLUT)
+ * Port by Brian Paul 23 March 2001
+ *
+ * Command line options:
+ * -info print GL implementation information
+ *
+ */
+
+
+#include <math.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+#include <GL/gl.h>
+#include <GL/glx.h>
+
+
+#define BENCHMARK
+
+#ifdef BENCHMARK
+
+/* XXX this probably isn't very portable */
+
+#include <sys/time.h>
+#include <unistd.h>
+
+/* return current time (in seconds) */
+static int
+current_time(void)
+{
+ struct timeval tv;
+#ifdef __VMS
+ (void) gettimeofday(&tv, NULL );
+#else
+ struct timezone tz;
+ (void) gettimeofday(&tv, &tz);
+#endif
+ return (int) tv.tv_sec;
+}
+
+#else /*BENCHMARK*/
+
+/* dummy */
+static int
+current_time(void)
+{
+ return 0;
+}
+
+#endif /*BENCHMARK*/
+
+
+
+#ifndef M_PI
+#define M_PI 3.14159265
+#endif
+
+
+static GLfloat view_rotx = 20.0, view_roty = 30.0, view_rotz = 0.0;
+static GLint gear1, gear2, gear3;
+static GLfloat angle = 0.0;
+static GLint WinWidth = 300, WinHeight = 300;
+
+/*
+ *
+ * Draw a gear wheel. You'll probably want to call this function when
+ * building a display list since we do a lot of trig here.
+ *
+ * Input: inner_radius - radius of hole at center
+ * outer_radius - radius at center of teeth
+ * width - width of gear
+ * teeth - number of teeth
+ * tooth_depth - depth of tooth
+ */
+static void
+gear(GLfloat inner_radius, GLfloat outer_radius, GLfloat width,
+ GLint teeth, GLfloat tooth_depth)
+{
+ GLint i;
+ GLfloat r0, r1, r2;
+ GLfloat angle, da;
+ GLfloat u, v, len;
+
+ r0 = inner_radius;
+ r1 = outer_radius - tooth_depth / 2.0;
+ r2 = outer_radius + tooth_depth / 2.0;
+
+ da = 2.0 * M_PI / teeth / 4.0;
+
+ glShadeModel(GL_FLAT);
+
+ glNormal3f(0.0, 0.0, 1.0);
+
+ /* draw front face */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ if (i < teeth) {
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ }
+ }
+ glEnd();
+
+ /* draw front sides of teeth */
+ glBegin(GL_QUADS);
+ da = 2.0 * M_PI / teeth / 4.0;
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ }
+ glEnd();
+
+ glNormal3f(0.0, 0.0, -1.0);
+
+ /* draw back face */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ if (i < teeth) {
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ }
+ }
+ glEnd();
+
+ /* draw back sides of teeth */
+ glBegin(GL_QUADS);
+ da = 2.0 * M_PI / teeth / 4.0;
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ -width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ }
+ glEnd();
+
+ /* draw outward faces of teeth */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i < teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), width * 0.5);
+ glVertex3f(r1 * cos(angle), r1 * sin(angle), -width * 0.5);
+ u = r2 * cos(angle + da) - r1 * cos(angle);
+ v = r2 * sin(angle + da) - r1 * sin(angle);
+ len = sqrt(u * u + v * v);
+ u /= len;
+ v /= len;
+ glNormal3f(v, -u, 0.0);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), width * 0.5);
+ glVertex3f(r2 * cos(angle + da), r2 * sin(angle + da), -width * 0.5);
+ glNormal3f(cos(angle), sin(angle), 0.0);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ width * 0.5);
+ glVertex3f(r2 * cos(angle + 2 * da), r2 * sin(angle + 2 * da),
+ -width * 0.5);
+ u = r1 * cos(angle + 3 * da) - r2 * cos(angle + 2 * da);
+ v = r1 * sin(angle + 3 * da) - r2 * sin(angle + 2 * da);
+ glNormal3f(v, -u, 0.0);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ width * 0.5);
+ glVertex3f(r1 * cos(angle + 3 * da), r1 * sin(angle + 3 * da),
+ -width * 0.5);
+ glNormal3f(cos(angle), sin(angle), 0.0);
+ }
+
+ glVertex3f(r1 * cos(0), r1 * sin(0), width * 0.5);
+ glVertex3f(r1 * cos(0), r1 * sin(0), -width * 0.5);
+
+ glEnd();
+
+ glShadeModel(GL_SMOOTH);
+
+ /* draw inside radius cylinder */
+ glBegin(GL_QUAD_STRIP);
+ for (i = 0; i <= teeth; i++) {
+ angle = i * 2.0 * M_PI / teeth;
+ glNormal3f(-cos(angle), -sin(angle), 0.0);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), -width * 0.5);
+ glVertex3f(r0 * cos(angle), r0 * sin(angle), width * 0.5);
+ }
+ glEnd();
+}
+
+
+static void
+draw(void)
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ glPushMatrix();
+ glRotatef(view_rotx, 1.0, 0.0, 0.0);
+ glRotatef(view_roty, 0.0, 1.0, 0.0);
+ glRotatef(view_rotz, 0.0, 0.0, 1.0);
+
+ glPushMatrix();
+ glTranslatef(-3.0, -2.0, 0.0);
+ glRotatef(angle, 0.0, 0.0, 1.0);
+ glCallList(gear1);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(3.1, -2.0, 0.0);
+ glRotatef(-2.0 * angle - 9.0, 0.0, 0.0, 1.0);
+ glCallList(gear2);
+ glPopMatrix();
+
+ glPushMatrix();
+ glTranslatef(-3.1, 4.2, 0.0);
+ glRotatef(-2.0 * angle - 25.0, 0.0, 0.0, 1.0);
+ glCallList(gear3);
+ glPopMatrix();
+
+ glPopMatrix();
+}
+
+
+/* new window size or exposure */
+static void
+reshape(int width, int height)
+{
+ GLfloat h = (GLfloat) height / (GLfloat) width;
+
+ glViewport(0, 0, (GLint) width, (GLint) height);
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glFrustum(-1.0, 1.0, -h, h, 5.0, 60.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+ glTranslatef(0.0, 0.0, -40.0);
+ WinWidth = width;
+ WinHeight = height;
+}
+
+
+static void
+init(void)
+{
+ static GLfloat pos[4] = { 5.0, 5.0, 10.0, 0.0 };
+ static GLfloat red[4] = { 0.8, 0.1, 0.0, 1.0 };
+ static GLfloat green[4] = { 0.0, 0.8, 0.2, 1.0 };
+ static GLfloat blue[4] = { 0.2, 0.2, 1.0, 1.0 };
+
+ glClearColor(1, 0, 0, 0);
+
+ glLightfv(GL_LIGHT0, GL_POSITION, pos);
+ glEnable(GL_CULL_FACE);
+ glEnable(GL_LIGHTING);
+ glEnable(GL_LIGHT0);
+ glEnable(GL_DEPTH_TEST);
+
+ /* make the gears */
+ gear1 = glGenLists(1);
+ glNewList(gear1, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, red);
+ gear(1.0, 4.0, 1.0, 20, 0.7);
+ glEndList();
+
+ gear2 = glGenLists(1);
+ glNewList(gear2, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, green);
+ gear(0.5, 2.0, 2.0, 10, 0.7);
+ glEndList();
+
+ gear3 = glGenLists(1);
+ glNewList(gear3, GL_COMPILE);
+ glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, blue);
+ gear(1.3, 2.0, 0.5, 10, 0.7);
+ glEndList();
+
+ glEnable(GL_NORMALIZE);
+}
+
+
+/*
+ * Create an RGB, double-buffered window.
+ * Return the window and context handles.
+ */
+static void
+make_window( Display *dpy, const char *name,
+ int x, int y, int width, int height,
+ Window *winRet, GLXContext *ctxRet)
+{
+ int attrib[] = { GLX_RGBA,
+ GLX_RED_SIZE, 1,
+ GLX_GREEN_SIZE, 1,
+ GLX_BLUE_SIZE, 1,
+ GLX_DOUBLEBUFFER,
+ GLX_DEPTH_SIZE, 1,
+ None };
+ int scrnum;
+ XSetWindowAttributes attr;
+ unsigned long mask;
+ Window root;
+ Window win;
+ GLXContext ctx;
+ XVisualInfo *visinfo;
+
+ scrnum = DefaultScreen( dpy );
+ root = RootWindow( dpy, scrnum );
+
+ visinfo = glXChooseVisual( dpy, scrnum, attrib );
+ if (!visinfo) {
+ printf("Error: couldn't get an RGB, Double-buffered visual\n");
+ exit(1);
+ }
+
+ /* window attributes */
+ attr.background_pixel = 0;
+ attr.border_pixel = 0;
+ attr.colormap = XCreateColormap( dpy, root, visinfo->visual, AllocNone);
+ attr.event_mask = StructureNotifyMask | ExposureMask | KeyPressMask;
+ mask = CWBackPixel | CWBorderPixel | CWColormap | CWEventMask;
+
+ win = XCreateWindow( dpy, root, 0, 0, width, height,
+ 0, visinfo->depth, InputOutput,
+ visinfo->visual, mask, &attr );
+
+ /* set hints and properties */
+ {
+ XSizeHints sizehints;
+ sizehints.x = x;
+ sizehints.y = y;
+ sizehints.width = width;
+ sizehints.height = height;
+ sizehints.flags = USSize | USPosition;
+ XSetNormalHints(dpy, win, &sizehints);
+ XSetStandardProperties(dpy, win, name, name,
+ None, (char **)NULL, 0, &sizehints);
+ }
+
+ ctx = glXCreateContext( dpy, visinfo, NULL, True );
+ if (!ctx) {
+ printf("Error: glXCreateContext failed\n");
+ exit(1);
+ }
+
+ XFree(visinfo);
+
+ *winRet = win;
+ *ctxRet = ctx;
+}
+
+
+static void
+event_loop(Display *dpy, Window win)
+{
+ while (1) {
+ while (XPending(dpy) > 0) {
+ XEvent event;
+ XNextEvent(dpy, &event);
+ switch (event.type) {
+ case Expose:
+ /* we'll redraw below */
+ break;
+ case ConfigureNotify:
+ reshape(event.xconfigure.width, event.xconfigure.height);
+ break;
+ case KeyPress:
+ {
+ char buffer[10];
+ int r, code;
+ code = XLookupKeysym(&event.xkey, 0);
+ if (code == XK_Left) {
+ view_roty += 5.0;
+ }
+ else if (code == XK_Right) {
+ view_roty -= 5.0;
+ }
+ else if (code == XK_Up) {
+ view_rotx += 5.0;
+ }
+ else if (code == XK_Down) {
+ view_rotx -= 5.0;
+ }
+ else {
+ r = XLookupString(&event.xkey, buffer, sizeof(buffer),
+ NULL, NULL);
+ if (buffer[0] == 27) {
+ /* escape */
+ return;
+ }
+ }
+ }
+ }
+ }
+
+ /* next frame */
+ angle += 2.0;
+
+ draw();
+
+#if 0
+ glXSwapBuffers(dpy, win);
+#else
+ {
+ GLfloat c[4];
+
+ glReadBuffer(GL_BACK);
+
+ glReadPixels(WinWidth-1, 0, 1, 1, GL_RGB, GL_FLOAT, c);
+ printf("Bottom right pixel color: %g, %g, %g\n", c[0], c[1], c[2]);
+
+ glDrawBuffer(GL_FRONT);
+ glWindowPos2iARB(0,0);
+ glCopyPixels(WinWidth/2, 0, WinWidth/2, WinHeight, GL_COLOR);
+ glDrawBuffer(GL_BACK);
+ }
+#endif
+
+ /* calc framerate */
+ {
+ static int t0 = -1;
+ static int frames = 0;
+ int t = current_time();
+
+ if (t0 < 0)
+ t0 = t;
+
+ frames++;
+
+ if (t - t0 >= 5.0) {
+ GLfloat seconds = t - t0;
+ GLfloat fps = frames / seconds;
+ printf("%d frames in %3.1f seconds = %6.3f FPS\n", frames, seconds,
+ fps);
+ t0 = t;
+ frames = 0;
+ }
+ }
+ }
+}
+
+
+int
+main(int argc, char *argv[])
+{
+ Display *dpy;
+ Window win;
+ GLXContext ctx;
+ char *dpyName = ":0";
+ GLboolean printInfo = GL_FALSE;
+ int i;
+
+ for (i = 1; i < argc; i++) {
+ if (strcmp(argv[i], "-display") == 0) {
+ dpyName = argv[i+1];
+ i++;
+ }
+ else if (strcmp(argv[i], "-info") == 0) {
+ printInfo = GL_TRUE;
+ }
+ }
+
+ dpy = XOpenDisplay(dpyName);
+ if (!dpy) {
+ printf("Error: couldn't open display %s\n", dpyName);
+ return -1;
+ }
+
+ make_window(dpy, "glxgears", 0, 0, WinWidth, WinHeight, &win, &ctx);
+ XMapWindow(dpy, win);
+ glXMakeCurrent(dpy, win, ctx);
+
+ if (printInfo) {
+ printf("GL_RENDERER = %s\n", (char *) glGetString(GL_RENDERER));
+ printf("GL_VERSION = %s\n", (char *) glGetString(GL_VERSION));
+ printf("GL_VENDOR = %s\n", (char *) glGetString(GL_VENDOR));
+ printf("GL_EXTENSIONS = %s\n", (char *) glGetString(GL_EXTENSIONS));
+ }
+
+ init();
+
+ event_loop(dpy, win);
+
+ glXDestroyContext(dpy, ctx);
+ XDestroyWindow(dpy, win);
+ XCloseDisplay(dpy);
+
+ return 0;
+}