summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKyle K <kylek389@gmail.com>2010-10-03 19:52:04 -0500
committerKamil Kaminski <kamilkss@gmail.com>2010-10-03 19:52:04 -0500
commit6f0b727ccf1f3b791d38c72519a3005cf56dd2fb (patch)
tree56e09780e8d17a61222a9e674214dd5a304af71a
downloadOBJLoader-6f0b727ccf1f3b791d38c72519a3005cf56dd2fb.tar.gz
OBJLoader-6f0b727ccf1f3b791d38c72519a3005cf56dd2fb.tar.bz2
OBJLoader-6f0b727ccf1f3b791d38c72519a3005cf56dd2fb.zip
Initial commit
-rw-r--r--Makefile31
-rw-r--r--cube/.gitignore3
-rw-r--r--math3d.c650
-rw-r--r--math3d.h130
-rw-r--r--obj.c92
-rw-r--r--obj.h36
-rw-r--r--objloader.c217
7 files changed, 1159 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..21509c3
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,31 @@
+PROG = objloader
+OBJS = $(PROG).o obj.o
+CC = gcc
+DBGFLAGS = -g -O0
+ifdef DEBUG
+ CFLAGS = $(DBGFLAGS) -Wall -std=c99
+else
+ CFLAGS = -Wall -std=c99 -O2 -march=native -mtune=native
+endif
+LDFLAGS = -lGLEW -lGL -lGLU -lm -lglut
+SDL_CFLAGS := $(shell sdl-config --cflags)
+SDL_LDFLAGS := $(shell sdl-config --libs)
+SDL_image_CFLAGS := $(shell pkg-config --cflags SDL_image)
+SDL_image_LDFLAGS := $(shell pkg-config --libs SDL_image)
+
+$(PROG): $(OBJS)
+ $(CC) $(LDFLAGS) $(SDL_LDFLAGS) $(SDL_image_LDFLAGS) $(OBJS) -o $(PROG)
+
+$(PROG).o: $(PROG).c math3d.h
+ $(CC) -c $(CFLAGS) $(SDL_CFLAGS) $(SDL_image_CFLAGS) $(PROG).c
+
+math3d.o: math3d.c math3d.h
+ $(CC) -c $(CFLAGS) math3d.c
+
+obj.o: obj.c obj.h
+ $(CC) -c $(CFLAGS) obj.c
+
+.PHONY: clean
+
+clean:
+ rm -f *.o ./$(PROG)
diff --git a/cube/.gitignore b/cube/.gitignore
new file mode 100644
index 0000000..8c33f0b
--- /dev/null
+++ b/cube/.gitignore
@@ -0,0 +1,3 @@
+cube.mtl
+cube.obj
+Map__1_Noise.tga
diff --git a/math3d.c b/math3d.c
new file mode 100644
index 0000000..8e3aa50
--- /dev/null
+++ b/math3d.c
@@ -0,0 +1,650 @@
+/* revision 5 */
+
+/* @2009 Kamil Kaminski
+ *
+ * this code is not yet endian aware
+ * the style of the syntax is original k&r except there's \n
+ * after the opening { and extra space after if statement,
+ * and for/while loops
+ */
+
+#include "math3d.h"
+
+void m3dFindNormal(M3DVector3f result, const M3DVector3f point1,
+ const M3DVector3f point2, const M3DVector3f point3)
+{
+ M3DVector3f v1, v2;
+
+ /* calculate two vectors from the three points, assumes
+ * counter clockwise winding
+ */
+ v1[0] = point1[0] - point2[0];
+ v1[1] = point1[1] - point2[1];
+ v1[2] = point1[2] - point2[2];
+
+ v2[0] = point2[0] - point3[0];
+ v2[1] = point2[1] - point3[1];
+ v2[2] = point2[2] - point3[2];
+
+ /* take the cross product of the two vectors to get the normal vector */
+ m3dCrossProduct(result, v1, v2);
+}
+
+void m3dLoadIdentity44(M3DMatrix44f m) /* 4x4 float */
+{
+ /* don't be fooled, this is still column major */
+ static M3DMatrix44f identity = { 1.0f, 0.0f, 0.0f, 0.0f,
+ 0.0f, 1.0f, 0.0f, 0.0f,
+ 0.0f, 0.0f, 1.0f, 0.0f,
+ 0.0f, 0.0f, 0.0f, 1.0f };
+
+ memcpy(m, identity, sizeof(M3DMatrix44f));
+}
+
+/* creates a 4x4 rotation matrix, takes radians not degrees */
+void m3dRotationMatrix44(M3DMatrix44f m, float angle, float x, float y, float z)
+{
+ float mag, s, c;
+ float xx, yy, zz, xy, yz, zx, xs, ys, zs, one_c;
+
+ s = (float) (sin(angle));
+ c = (float) (cos(angle));
+
+ mag = (float) (sqrt(x*x + y*y + z*z));
+
+ /* identity matrix */
+ if (mag == 0.0f)
+ {
+ m3dLoadIdentity44(m);
+ return;
+ }
+
+ /* rotation matrix is normalized */
+ x /= mag;
+ y /= mag;
+ z /= mag;
+
+ #define M(row,col) m[col*4+row]
+
+ xx = x * x;
+ yy = y * y;
+ zz = z * z;
+ xy = x * y;
+ yz = y * z;
+ zx = z * x;
+
+ xs = x * s;
+ ys = y * s;
+ zs = z * s;
+ one_c = 1.0f - c;
+
+ M(0,0) = (one_c * xx) + c;
+ M(0,1) = (one_c * xy) - zs;
+ M(0,2) = (one_c * zx) + ys;
+ M(0,3) = 0.0f;
+
+ M(1,0) = (one_c * xy) + zs;
+ M(1,1) = (one_c * yy) + c;
+ M(1,2) = (one_c * yz) - xs;
+ M(1,3) = 0.0f;
+
+ M(2,0) = (one_c * zx) - ys;
+ M(2,1) = (one_c * yz) + xs;
+ M(2,2) = (one_c * zz) + c;
+ M(2,3) = 0.0f;
+
+ M(3,0) = 0.0f;
+ M(3,1) = 0.0f;
+ M(3,2) = 0.0f;
+ M(3,3) = 1.0f;
+
+ #undef M
+}
+
+/* draw a torus (doughnut), using the current 1d texture for light shading */
+/* this funct accepts 4x4 trans matrix to be applied to the vertices */
+void gltDrawTorus(GLfloat majorRadius, GLfloat minorRadius, GLint numMajor,
+ GLint numMinor)
+{
+ M3DVector3f vNormal;
+ double majorStep = 2.0f * M3D_PI / numMajor;
+ double minorStep = 2.0f * M3D_PI / numMinor;
+ int i, j;
+
+ for (i = 0; i < numMajor; ++i)
+ {
+ double a0 = i * majorStep;
+ double a1 = a0 + majorStep;
+ GLfloat x0 = (GLfloat) cos(a0);
+ GLfloat y0 = (GLfloat) sin(a0);
+ GLfloat x1 = (GLfloat) cos(a1);
+ GLfloat y1 = (GLfloat) sin(a1);
+
+ glBegin(GL_TRIANGLE_STRIP);
+ for (j = 0; j <= numMinor; ++j)
+ {
+ double b = j * minorStep;
+ GLfloat c = (GLfloat) cos(b);
+ GLfloat r = minorRadius * c + majorRadius;
+ GLfloat z = minorRadius * (GLfloat) sin(b);
+
+ glTexCoord2f((float) (i) / (float) (numMajor), (float) (j) \
+ / (float) (numMinor));
+ vNormal[0] = x0 * c;
+ vNormal[1] = y0 * c;
+ vNormal[2] = z / minorRadius;
+ m3dNormalizeVector(vNormal);
+ glNormal3fv(vNormal);
+ glVertex3f(x0 * r, y0 * r, z);
+
+ glTexCoord2f((float) (i + 1) / (float) (numMajor), (float) (j) \
+ / (float) (numMinor));
+ vNormal[0] = x1 * c;
+ vNormal[1] = y1 * c;
+ vNormal[2] = z / minorRadius;
+ m3dNormalizeVector(vNormal);
+ glNormal3fv(vNormal);
+ glVertex3f(x1 * r, y1 * r, z);
+ }
+ glEnd();
+ }
+}
+
+/* this function just specifically draws the jet */
+/* FIXME needs to accepts parameters of location and lightning */
+void DrawJet(int nShadow)
+{
+ M3DVector3f vNormal;
+
+ /* nose cone, set material color, note we only have to set to black
+ * for the shadow once
+ */
+ if (nShadow == 0)
+ glColor3ub(128, 128, 128);
+ else
+ glColor3ub(0, 0, 0);
+
+ /* nose cone, points straight down, set material color */
+ /* follow few lines use manual approach */
+ glBegin(GL_TRIANGLES);
+ glNormal3f(0.0f, -1.0f, 0.0f);
+ glNormal3f(0.0f, -1.0f, 0.0f);
+ glVertex3f(0.0f, 0.0f, 60.0f);
+ glVertex3f(-15.0f, 0.0f, 30.0f);
+ glVertex3f(15.0f, 0.0f, 30.0f);
+
+ /* verticies for this panel */
+ {
+ M3DVector3f vPoints[3] = { {15.0f, 0.0f, 30.0f}
+ ,
+ {0.0f, 15.0f, 30.0f}
+ ,
+ {0.0f, 0.0f, 60.0f}
+ };
+
+ /* calculate the normal for the plane */
+ m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
+ glNormal3fv(vNormal);
+ glVertex3fv(vPoints[0]);
+ glVertex3fv(vPoints[1]);
+ glVertex3fv(vPoints[2]);
+ }
+
+ {
+ M3DVector3f vPoints[3] = { {0.0f, 0.0f, 60.0f}
+ ,
+ {0.0f, 15.0f, 30.0f}
+ ,
+ {-15.0f, 0.0f, 30.0f}
+ };
+
+ m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
+ glNormal3fv(vNormal);
+ glVertex3fv(vPoints[0]);
+ glVertex3fv(vPoints[1]);
+ glVertex3fv(vPoints[2]);
+ }
+
+ /* body of the plane */
+ {
+ M3DVector3f vPoints[3] = { {-15.0f, 0.0f, 30.0f}
+ ,
+ {0.0f, 15.0f, 30.0f}
+ ,
+ {0.0f, 0.0f, -56.0f}
+ };
+
+ m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
+ glNormal3fv(vNormal);
+ glVertex3fv(vPoints[0]);
+ glVertex3fv(vPoints[1]);
+ glVertex3fv(vPoints[2]);
+ }
+
+ {
+ M3DVector3f vPoints[3] = { {0.0f, 0.0f, -56.0f}
+ ,
+ {0.0f, 15.0f, 30.0f}
+ ,
+ {15.0f, 0.0f, 30.0f}
+ };
+
+ m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
+ glNormal3fv(vNormal);
+ glVertex3fv(vPoints[0]);
+ glVertex3fv(vPoints[1]);
+ glVertex3fv(vPoints[2]);
+ }
+
+ glNormal3f(0.0f, -1.0f, 0.0f);
+ glVertex3f(15.0f, 0.0f, 30.0f);
+ glVertex3f(-15.0f, 0.0f, 30.0f);
+ glVertex3f(0.0f, 0.0f, -56.0f);
+
+ /* left wing, large triangle for bottom of wing */
+ {
+ M3DVector3f vPoints[3] = { {0.0f, 2.0f, 27.0f}
+ ,
+ {-60.0f, 2.0f, -8.0f}
+ ,
+ {60.0f, 2.0f, -8.0f}
+ };
+
+ m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
+ glNormal3fv(vNormal);
+ glVertex3fv(vPoints[0]);
+ glVertex3fv(vPoints[1]);
+ glVertex3fv(vPoints[2]);
+ }
+
+ {
+ M3DVector3f vPoints[3] = { {60.0f, 2.0f, -8.0f}
+ ,
+ {0.0f, 7.0f, -8.0f}
+ ,
+ {0.0f, 2.0f, 27.0f}
+ };
+
+ m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
+ glNormal3fv(vNormal);
+ glVertex3fv(vPoints[0]);
+ glVertex3fv(vPoints[1]);
+ glVertex3fv(vPoints[2]);
+ }
+
+ {
+ M3DVector3f vPoints[3] = { {60.0f, 2.0f, -8.0f}
+ ,
+ {-60.0f, 2.0f, -8.0f}
+ ,
+ {0.0f, 7.0f, -8.0f}
+ };
+
+ m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
+ glNormal3fv(vNormal);
+ glVertex3fv(vPoints[0]);
+ glVertex3fv(vPoints[1]);
+ glVertex3fv(vPoints[2]);
+ }
+
+ {
+ M3DVector3f vPoints[3] = { {0.0f, 2.0f, 27.0f}
+ ,
+ {0.0f, 7.0f, -8.0f}
+ ,
+ {-60.0f, 2.0f, -8.0f}
+ };
+
+ m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
+ glNormal3fv(vNormal);
+ glVertex3fv(vPoints[0]);
+ glVertex3fv(vPoints[1]);
+ glVertex3fv(vPoints[2]);
+ }
+
+ /* tail section */
+ /* bottom of back fin */
+ glNormal3f(0.0f, -1.0f, 0.0f);
+ glVertex3f(-30.0f, -0.50f, -57.0f);
+ glVertex3f(30.0f, -0.50f, -57.0f);
+ glVertex3f(0.0f, -0.50f, -40.0f);
+
+ {
+ M3DVector3f vPoints[3] = { {0.0f, -0.5f, -40.0f}
+ ,
+ {30.0f, -0.5f, -57.0f}
+ ,
+ {0.0f, 4.0f, -57.0f}
+ };
+
+ m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
+ glNormal3fv(vNormal);
+ glVertex3fv(vPoints[0]);
+ glVertex3fv(vPoints[1]);
+ glVertex3fv(vPoints[2]);
+ }
+
+ {
+ M3DVector3f vPoints[3] = { {0.0f, 4.0f, -57.0f}
+ ,
+ {-30.0f, -0.5f, -57.0f}
+ ,
+ {0.0f, -0.5f, -40.0f}
+ };
+
+ m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
+ glNormal3fv(vNormal);
+ glVertex3fv(vPoints[0]);
+ glVertex3fv(vPoints[1]);
+ glVertex3fv(vPoints[2]);
+ }
+
+ {
+ M3DVector3f vPoints[3] = { {30.0f, -0.5f, -57.0f}
+ ,
+ {-30.0f, -0.5f, -57.0f}
+ ,
+ {0.0f, 4.0f, -57.0f}
+ };
+
+ m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
+ glNormal3fv(vNormal);
+ glVertex3fv(vPoints[0]);
+ glVertex3fv(vPoints[1]);
+ glVertex3fv(vPoints[2]);
+ }
+
+ {
+ M3DVector3f vPoints[3] = { {0.0f, 0.5f, -40.0f}
+ ,
+ {3.0f, 0.5f, -57.0f}
+ ,
+ {0.0f, 25.0f, -65.0f}
+ };
+
+ m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
+ glNormal3fv(vNormal);
+ glVertex3fv(vPoints[0]);
+ glVertex3fv(vPoints[1]);
+ glVertex3fv(vPoints[2]);
+ }
+
+ {
+ M3DVector3f vPoints[3] = { {0.0f, 25.0f, -65.0f}
+ ,
+ {-3.0f, 0.5f, -57.0f}
+ ,
+ {0.0f, 0.5f, -40.0f}
+ };
+
+ m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
+ glNormal3fv(vNormal);
+ glVertex3fv(vPoints[0]);
+ glVertex3fv(vPoints[1]);
+ glVertex3fv(vPoints[2]);
+ }
+
+ {
+ M3DVector3f vPoints[3] = { {3.0f, 0.5f, -57.0f}
+ ,
+ {-3.0f, 0.5f, -57.0f}
+ ,
+ {0.0f, 25.0f, -65.0f}
+ };
+
+ m3dFindNormal(vNormal, vPoints[0], vPoints[1], vPoints[2]);
+ glNormal3fv(vNormal);
+ glVertex3fv(vPoints[0]);
+ glVertex3fv(vPoints[1]);
+ glVertex3fv(vPoints[2]);
+ }
+
+ glEnd();
+}
+
+void gltDrawUnitAxes(void)
+{
+ GLUquadricObj *pObj; /* temporary, used for quadrics */
+
+ /* measurements */
+ float fAxisRadius = 0.025f;
+ float fAxisHeight = 1.0f;
+ float fArrowRadius = 0.06f;
+ float fArrowHeight = 0.1f;
+
+ /* setup the quadric object */
+ pObj = gluNewQuadric();
+ gluQuadricDrawStyle(pObj, GLU_FILL);
+ gluQuadricNormals(pObj, GLU_SMOOTH);
+ gluQuadricOrientation(pObj, GLU_OUTSIDE);
+ gluQuadricTexture(pObj, GLU_FALSE);
+
+ /* draw the blue z axis first with arrowed head */
+ glColor3f(0.0f, 0.0f, 1.0f);
+ gluCylinder(pObj, fAxisRadius, fAxisRadius, fAxisHeight, 10, 1);
+ glPushMatrix();
+ glTranslatef(0.0f, 0.0f, 1.0f);
+ gluCylinder(pObj, fArrowRadius, 0.0f, fArrowHeight, 10, 1);
+ glRotatef(180.0f, 1.0f, 0.0f, 0.0f);
+ gluDisk(pObj, fAxisRadius, fArrowRadius, 10, 1);
+ glPopMatrix();
+
+ /* draw the red x axis 2nd with arrowed head */
+ glColor3f(1.0f, 0.0f, 0.0f);
+ glPushMatrix();
+ glRotatef(90.0f, 0.0f, 1.0f, 0.0f);
+ gluCylinder(pObj, fAxisRadius, fAxisRadius, fAxisHeight, 10, 1);
+ glPushMatrix();
+ glTranslatef(0.0f, 0.0f, 1.0f);
+ gluCylinder(pObj, fArrowRadius, 0.0f, fArrowHeight, 10, 1);
+ glRotatef(180.0f, 0.0f, 1.0f, 0.0f);
+ gluDisk(pObj, fAxisRadius, fArrowRadius, 10, 1);
+ glPopMatrix();
+ glPopMatrix();
+
+ /* draw the green y axis 3rd with arrowed head */
+ glColor3f(0.0f, 1.0f, 0.0f);
+ glPushMatrix();
+ glRotatef(-90.0f, 1.0f, 0.0f, 0.0f);
+ gluCylinder(pObj, fAxisRadius, fAxisRadius, fAxisHeight, 10, 1);
+ glPushMatrix();
+ glTranslatef(0.0f, 0.0f, 1.0f);
+ gluCylinder(pObj, fArrowRadius, 0.0f, fArrowHeight, 10, 1);
+ glRotatef(180.0f, 1.0f, 0.0f, 0.0f);
+ gluDisk(pObj, fAxisRadius, fArrowRadius, 10, 1);
+ glPopMatrix();
+ glPopMatrix();
+
+ /* white sphere at origin */
+ glColor3f(1.0f, 1.0f, 1.0f);
+ gluSphere(pObj, 0.05f, 15, 15);
+
+ /* delete the quadric */
+ gluDeleteQuadric(pObj);
+}
+
+#define A(row,col) a[(col<<2)+row]
+#define B(row,col) b[(col<<2)+row]
+#define P(row,col) product[(col<<2)+row]
+
+void m3dMatrixMultiply44(M3DMatrix44f product, const M3DMatrix44f a,
+ const M3DMatrix44f b)
+{
+ int i;
+ for (i = 0; i < 4; i++)
+ {
+ float ai0 = A(i, 0), ai1 = A(i, 1), ai2 = A(i, 2), ai3 = A(i, 3);
+ P(i, 0) = ai0 * B(0, 0) + ai1 * B(1, 0) + ai2 * B(2, 0) + ai3 * B(3, 0);
+ P(i, 1) = ai0 * B(0, 1) + ai1 * B(1, 1) + ai2 * B(2, 1) + ai3 * B(3, 1);
+ P(i, 2) = ai0 * B(0, 2) + ai1 * B(1, 2) + ai2 * B(2, 2) + ai3 * B(3, 2);
+ P(i, 3) = ai0 * B(0, 3) + ai1 * B(1, 3) + ai2 * B(2, 3) + ai3 * B(3, 3);
+ }
+}
+
+#undef A
+#undef B
+#undef P
+
+
+/*************************************************************/
+/* unrelated functions that do not have much to do with math */
+/* */
+/*************************************************************/
+
+GLint gltWriteTGA(const char *szFileName)
+{
+ FILE *pFile; /* file pointer */
+ TGAHEADER tgaHeader; /* tga file header */
+ unsigned long lImageSize; /* size in bytes of image */
+ GLbyte *pBits = NULL; /* pointer to bits */
+ GLint iViewport[4]; /* viewport in pixels */
+ GLenum lastBuffer; /* storage for the current read buffer setting */
+
+ /* get the viewport dimensions */
+ glGetIntegerv(GL_VIEWPORT, iViewport);
+
+ /* how big is the image going to be (targas are tightly packed) */
+ lImageSize = iViewport[2] * 3 * iViewport[3];
+
+ /* allocate block, if this doesn't work, go home */
+ pBits = (GLbyte *) malloc(lImageSize);
+ if (pBits == NULL)
+ {
+ perror("malloc");
+ return 0;
+ }
+
+ /* read bits from color buffer */
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ glPixelStorei(GL_PACK_ROW_LENGTH, 0);
+ glPixelStorei(GL_PACK_SKIP_ROWS, 0);
+ glPixelStorei(GL_PACK_SKIP_PIXELS, 0);
+
+ /* get the current read buffer setting and save it, switch to
+ * the front buffer and do the read operation, finally, restore
+ * the read buffer state
+ */
+ glGetIntegerv(GL_READ_BUFFER, (GLint *) &lastBuffer);
+ glReadBuffer(GL_FRONT);
+ glReadPixels(0, 0, iViewport[2], iViewport[3], GL_BGR_EXT,
+ GL_UNSIGNED_BYTE, pBits);
+ glReadBuffer(lastBuffer);
+
+ /* initialize the targa header */
+ tgaHeader.identsize = 0;
+ tgaHeader.colorMapType = 0;
+ tgaHeader.imageType = 2;
+ tgaHeader.colorMapStart = 0;
+ tgaHeader.colorMapLength = 0;
+ tgaHeader.colorMapBits = 0;
+ tgaHeader.xstart = 0;
+ tgaHeader.ystart = 0;
+ tgaHeader.width = iViewport[2];
+ tgaHeader.height = iViewport[3];
+ tgaHeader.bits = 24;
+ tgaHeader.descriptor = 0;
+
+ /* attempt to open the file */
+ pFile = fopen(szFileName, "wb");
+ if (pFile == NULL)
+ {
+ perror("fopen");
+ free(pBits); /* free buffer and return error */
+ return 0;
+ }
+
+ /* write the header */
+ fwrite(&tgaHeader, sizeof(TGAHEADER), 1, pFile);
+
+ /* write the image data */
+ fwrite(pBits, lImageSize, 1, pFile);
+
+ /* free temporary buffer and close the file */
+ free(pBits);
+ fclose(pFile);
+
+ return 1;
+}
+
+GLbyte *gltLoadTGA(const char *szFileName, GLint *iWidth, GLint *iHeight,
+ GLint *iComponents, GLenum *eFormat)
+{
+ FILE *pFile; /* file pointer */
+ TGAHEADER tgaHeader; /* TGA file header */
+ unsigned long lImageSize; /* size in bytes of image */
+ short sDepth; /* pixel depth; */
+ GLbyte *pBits = NULL; /* pointer to bits */
+
+ /* default/failed values */
+ *iWidth = 0;
+ *iHeight = 0;
+ *eFormat = GL_BGR_EXT;
+ *iComponents = GL_RGB8;
+
+ /* attempt to open the file */
+ pFile = fopen(szFileName, "rb");
+ if (pFile == NULL)
+ {
+ perror("fopen");
+ return 0;
+ }
+
+ /* read in header (binary) */
+ fread(&tgaHeader, 18 /* sizeof(TGAHEADER) */, 1, pFile);
+
+ /* get width, height, and depth of texture */
+ *iWidth = tgaHeader.width;
+ *iHeight = tgaHeader.height;
+ sDepth = tgaHeader.bits / 8;
+
+ /* put some validity checks here, very simply, i only understand
+ * or care about 8, 24, or 32 bit targas
+ */
+ if (tgaHeader.bits != 8 && tgaHeader.bits != 24 && tgaHeader.bits != 32)
+ return NULL;
+
+ /* calculate size of image buffer */
+ lImageSize = tgaHeader.width * tgaHeader.height * sDepth;
+
+ /* allocate memory and check for success */
+ pBits = (GLbyte *) malloc(lImageSize * sizeof(GLbyte));
+ if (pBits == NULL)
+ {
+ perror("malloc");
+ return NULL;
+ }
+
+ /* read in the bits */
+ /* check for read error, this should catch rle or other */
+ /* weird formats that i don't want to recognize */
+ if (fread(pBits, lImageSize, 1, pFile) != 1)
+ {
+ perror("fread");
+ free(pBits);
+ return NULL;
+ }
+
+ /* set opengl format expected */
+ switch (sDepth)
+ {
+ case 3: /* most likely case */
+ *eFormat = GL_BGR_EXT;
+ *iComponents = GL_RGB8;
+ break;
+ case 4:
+ *eFormat = GL_BGRA_EXT;
+ *iComponents = GL_RGBA8;
+ break;
+ case 1:
+ *eFormat = GL_LUMINANCE;
+ *iComponents = GL_LUMINANCE8;
+ break;
+ }
+
+ /* done with file */
+ fclose(pFile);
+
+ /* return pointer to image data */
+ return pBits;
+}
+
diff --git a/math3d.h b/math3d.h
new file mode 100644
index 0000000..e33b387
--- /dev/null
+++ b/math3d.h
@@ -0,0 +1,130 @@
+#ifndef _MATH3D_H_
+#define _MATH3D_H_
+
+#include <GL/glew.h>
+#include <GL/freeglut.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <math.h>
+
+#define M3D_PI (3.14159265358979323846)
+#define M3D_PI_DIV_180 (0.017453292519943296)
+#define M3D_INV_PI_DIV_180 (57.2957795130823229)
+
+#define m3dDegToRad(x) ((x)*M3D_PI_DIV_180)
+#define m3dRadToDeg(x) ((x)*M3D_INV_PI_DIV_180)
+
+typedef float M3DMatrix44f[16]; /* 4x4 matrix */
+typedef float M3DVector3f[3]; /* vector of 3 floats */
+typedef float M3DVector2f[2]; /* vector of 2 floats */
+
+/* this is the targa header, pragmas are needed to do the voodoo magic */
+/* http://gcc.gnu.org/onlinedocs/gcc-4.4.0/gcc/ */
+#pragma pack(1)
+typedef struct
+{
+ GLbyte identsize; /* Size of id field that follows header (0) */
+ GLbyte imageType; /* 0 = none, 1 = indexed, 2 = rgb, 3 = grey, +8 = rle */
+ GLbyte colorMapType; /* 0 = none, 1 = paletted */
+ unsigned short colorMapStart; /* first colour map entry */
+ unsigned short colorMapLength; /* number of colors */
+ unsigned char colorMapBits; /* bits per palette entry */
+ unsigned short xstart; /* image x origin */
+ unsigned short ystart; /* image y origin */
+ unsigned short width; /* width in pixels */
+ unsigned short height; /* height in pixels */
+ GLbyte bits; /* bits per pixel (8 16, 24, 32) */
+ GLbyte descriptor; /* image descriptor */
+} TGAHEADER;
+#pragma pack(1)
+
+/* math function prototypes */
+void m3dFindNormal(M3DVector3f, const M3DVector3f, const M3DVector3f,
+ const M3DVector3f);
+void m3dLoadIdentity44(M3DMatrix44f);
+void m3dRotationMatrix44(M3DMatrix44f, float, float, float, float);
+void gltDrawTorus(GLfloat, GLfloat, GLint, GLint);
+void DrawJet(int);
+void gltDrawUnitAxes(void);
+void m3dMatrixMultiply44(M3DMatrix44f, const M3DMatrix44f, const M3DMatrix44f);
+
+/* other function prototypes */
+GLint gltWriteTGA(const char *);
+GLbyte *gltLoadTGA(const char *, GLint *, GLint *, GLint *, GLenum *);
+
+static inline void m3dCrossProduct(M3DVector3f result, const M3DVector3f u,
+ const M3DVector3f v)
+{
+ result[0] = u[1] * v[2] - v[1] * u[2];
+ result[1] = -u[0] * v[2] + v[0] * u[2];
+ result[2] = u[0] * v[1] - v[0] * u[1];
+}
+
+static inline void m3dTransformVector3(M3DVector3f vOut, const M3DVector3f v,
+ const M3DMatrix44f m)
+{
+ vOut[0] = m[0] * v[0] + m[4] * v[1] + m[8] * v[2] + m[12]; /* * v[3]; */
+ vOut[1] = m[1] * v[0] + m[5] * v[1] + m[9] * v[2] + m[13]; /* * v[3]; */
+ vOut[2] = m[2] * v[0] + m[6] * v[1] + m[10] * v[2] + m[14]; /* * v[3]; */
+ /* vOut[3] = m[3] * v[0] + m[7] * v[1] + m[11] * v[2] + m[15] * v[3]; */
+}
+
+static inline void m3dScaleVector3(M3DVector3f v, float scale)
+{
+ v[0] *= scale;
+ v[1] *= scale;
+ v[2] *= scale;
+}
+
+static inline float m3dGetVectorLengthSquared(const M3DVector3f u)
+{
+ return (u[0] * u[0]) + (u[1] * u[1]) + (u[2] * u[2]);
+}
+
+static inline float m3dGetVectorLength(const M3DVector3f u)
+{
+ return (float) (sqrt((double) (m3dGetVectorLengthSquared(u))));
+}
+
+static inline void m3dNormalizeVector(M3DVector3f u)
+{
+ m3dScaleVector3(u, 1.0f / m3dGetVectorLength(u));
+}
+
+static inline void m3dTranslateMatrix44(M3DMatrix44f m, float x, float y,
+ float z)
+{
+ m[12] += x;
+ m[13] += y;
+ m[14] += z;
+}
+
+static inline void m3dScaleMatrix44(M3DMatrix44f m, float x, float y, float z)
+{
+ m[0] *= x;
+ m[5] *= y;
+ m[10] *= z;
+}
+
+/* transpose / invert, only 4x4 matricies supported */
+#define TRANSPOSE44(dst, src) \
+{ \
+ int i, j; \
+ for (j = 0; j < 4; j++) \
+ { \
+ for (i = 0; i < 4; i++) \
+ { \
+ dst[(j*4)+i] = src[(i*4)+j]; \
+ } \
+ } \
+}
+
+static inline void m3dTransposeMatrix44(M3DMatrix44f dst,
+ const M3DMatrix44f src)
+{
+ TRANSPOSE44(dst, src);
+}
+
+#endif
+
diff --git a/obj.c b/obj.c
new file mode 100644
index 0000000..e871fda
--- /dev/null
+++ b/obj.c
@@ -0,0 +1,92 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <memory.h>
+#include "obj.h"
+
+ObjModel* ObjLoadModel(char *memory, size_t size)
+{
+ char *p = NULL, *e = NULL;
+ ObjModel *ret = (ObjModel *) calloc(1, sizeof(ObjModel));
+ memset(ret, 0, sizeof(ObjModel));
+
+ p = memory;
+ e = memory + size;
+
+ while (p != e)
+ {
+ if (memcmp(p, "vn", 2) == 0) ret->nNormal++;
+ else if (memcmp(p, "vt", 2) == 0) ret->nTexCoord++;
+ else if (memcmp(p, "v", 1) == 0) ret->nVertex++;
+ else if (memcmp(p, "f", 1) == 0) ret->nTriangle++;
+
+ while (*p++ != (char) 0x0A);
+ }
+
+ ret->VertexArray = (ObjVertex *) malloc(sizeof(ObjVertex) * ret->nVertex);
+ ret->NormalArray = (ObjNormal *) malloc(sizeof(ObjNormal) * ret->nNormal);
+ ret->TexCoordArray = (ObjTexCoord *) malloc(sizeof(ObjTexCoord) * ret->nTexCoord);
+ ret->TriangleArray = (ObjTriangle *) malloc(sizeof(ObjTriangle) * ret->nTriangle);
+
+ p = memory;
+
+ int nV = 0, nN = 0, nT = 0, nF = 0;
+
+ while (p != e)
+ {
+ if (memcmp(p, "vn", 2) == 0)
+ {
+ sscanf(p, "vn %f %f %f", &ret->NormalArray[nN].x,
+ &ret->NormalArray[nN].y,
+ &ret->NormalArray[nN].z);
+ nN++;
+ }
+ else if (memcmp(p, "vt", 2) == 0)
+ {
+ sscanf(p, "vt %f %f", &ret->TexCoordArray[nT].u,
+ &ret->TexCoordArray[nT].v);
+ nT++;
+ }
+ else if (memcmp(p, "v", 1) == 0) /* or *p == 'v' */
+ {
+ sscanf(p, "v %f %f %f", &ret->VertexArray[nV].x,
+ &ret->VertexArray[nV].y,
+ &ret->VertexArray[nV].z);
+ nV++;
+ }
+ else if (memcmp(p, "f", 1) == 0) /* or *p == 'f' */
+ {
+ sscanf(p, "f %d/%d/%d %d/%d/%d %d/%d/%d", &ret->TriangleArray[nF].Vertex[0],
+ &ret->TriangleArray[nF].TexCoord[0],
+ &ret->TriangleArray[nF].Normal[0],
+ &ret->TriangleArray[nF].Vertex[1],
+ &ret->TriangleArray[nF].TexCoord[1],
+ &ret->TriangleArray[nF].Normal[1],
+ &ret->TriangleArray[nF].Vertex[2],
+ &ret->TriangleArray[nF].TexCoord[2],
+ &ret->TriangleArray[nF].Normal[2]);
+ nF++;
+ }
+ while (*p++ != (char) 0x0A);
+ }
+ return ret;
+}
+
+size_t ObjLoadFile(char *szFileName, char **memory)
+{
+ size_t bytes = 0;
+ FILE *file = fopen(szFileName, "rt");
+
+ if (file != NULL)
+ {
+ fseek(file, 0, SEEK_END);
+ size_t end = ftell(file);
+ fseek(file, 0, SEEK_SET);
+
+ *memory = (char *) malloc(end);
+ bytes = fread(*memory, sizeof(char), end, file);
+
+ fclose(file);
+ }
+ return bytes;
+}
+
diff --git a/obj.h b/obj.h
new file mode 100644
index 0000000..962d325
--- /dev/null
+++ b/obj.h
@@ -0,0 +1,36 @@
+#ifndef OBJ_H
+#define OBJ_H
+
+typedef struct
+{
+ float x, y, z;
+} ObjVertex;
+typedef ObjVertex ObjNormal;
+
+typedef struct
+{
+ float u, v;
+} ObjTexCoord;
+
+typedef struct
+{
+ int Vertex[3];
+ int Normal[3];
+ int TexCoord[3];
+} ObjTriangle;
+
+typedef struct
+{
+ int nVertex, nNormal, nTexCoord, nTriangle;
+
+ ObjVertex *VertexArray;
+ ObjNormal *NormalArray;
+ ObjTexCoord *TexCoordArray;
+ ObjTriangle *TriangleArray;
+} ObjModel;
+
+ObjModel *ObjLoadModel(char *, size_t);
+size_t ObjLoadFile(char *, char **);
+
+#endif
+
diff --git a/objloader.c b/objloader.c
new file mode 100644
index 0000000..c0b4ddd
--- /dev/null
+++ b/objloader.c
@@ -0,0 +1,217 @@
+/*
+ * Kamil Kaminski
+ * kamilkss@gmail.com
+ *
+ * OBJ Loader
+ * Look at line 194
+ */
+
+#include <SDL/SDL.h>
+#include <SDL/SDL_image.h>
+#include "math3d.h"
+
+#include "obj.h"
+
+/* global */
+int program_running = 1;
+
+static void resize(int w, int h)
+{
+ printf("window: resizing to %dx%d\n", w, h);
+ GLfloat fAspect = (GLfloat) w / (GLfloat) h;
+ if (h == 0)
+ h = 1;
+ glViewport(0, 0, w, h);
+
+ /* reset coordinate system */
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+
+ /* produce the perspective projection */
+ gluPerspective(40.0f, fAspect, 1.0, 40.0);
+
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ /* this needs to be ran again, glut does it for you I suppose */
+ SDL_SetVideoMode(w, h, 32, SDL_OPENGL | SDL_GL_DOUBLEBUFFER | SDL_RESIZABLE);
+}
+
+static void SetupRC()
+{
+ /* light values and coordinates */
+ GLfloat whiteLight[] = { 0.05f, 0.05f, 0.05f, 1.0f };
+ GLfloat sourceLight[] = { 0.75f, 0.75f, 0.75f, 1.0f };
+ GLfloat lightPos[] = { -10.f, 5.0f, 5.0f, 1.0f };
+
+ glEnable(GL_DEPTH_TEST); /* hidden surface removal */
+ glFrontFace(GL_CCW); /* counter clock-wise polygons face out */
+ glEnable(GL_CULL_FACE); /* do not calculate inside of a pyramid */
+
+ /* enable lighting */
+ glEnable(GL_LIGHTING);
+
+ /* setup and enable light 0 */
+ glLightModelfv(GL_LIGHT_MODEL_AMBIENT, whiteLight);
+ glLightfv(GL_LIGHT0, GL_AMBIENT, sourceLight);
+ glLightfv(GL_LIGHT0, GL_DIFFUSE, sourceLight);
+ glLightfv(GL_LIGHT0, GL_POSITION, lightPos);
+ glEnable(GL_LIGHT0);
+
+ /* enable color tracking */
+ glEnable(GL_COLOR_MATERIAL);
+
+ /* set Material properties to follow glColor values */
+ glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
+
+ /* gray background */
+ glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
+
+#if 0
+ /* example of loading a targa file, note: RLE compression is not supported */
+ GLbyte *pBytes;
+ GLint iWidth, iHeight, iComponents;
+ GLenum eFormat;
+
+ /* load texture */
+ glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
+ pBytes = gltLoadTGA("stone.tga", &iWidth, &iHeight, &iComponents, &eFormat);
+ if (!pBytes)
+ fprintf(stderr, "gltLoadTGA: failed to load texture!\n");
+
+ /* load texture image */
+ glTexImage2D(GL_TEXTURE_2D, 0, iComponents, iWidth, iHeight, 0, eFormat,
+ GL_UNSIGNED_BYTE, pBytes);
+ free(pBytes);
+
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+
+ glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
+ glEnable(GL_TEXTURE_2D);
+#endif
+}
+
+/* process SDL events */
+void processEvents()
+{
+ SDL_Event event;
+ SDLKey sym;
+
+ while (SDL_PollEvent(&event))
+ {
+ sym = event.key.keysym.sym;
+ switch (event.type)
+ {
+ case SDL_KEYDOWN:
+ {
+ if (sym == SDLK_ESCAPE) program_running = 0;
+ break;
+ }
+ case SDL_VIDEORESIZE: { resize(event.resize.w, event.resize.h); break; }
+ case SDL_QUIT: { program_running = 0; break; }
+ default: break;
+ }
+ }
+}
+
+static void draw_ground(void)
+{
+ GLfloat fExtent = 20.0f;
+ GLfloat fStep = 0.5f;
+ GLfloat y = -0.4f;
+ GLfloat iLine;
+
+ glBegin(GL_LINES);
+ for (iLine = -fExtent; iLine <= fExtent; iLine += fStep)
+ {
+ glVertex3f(iLine, y, fExtent);
+ glVertex3f(iLine, y, -fExtent);
+ glVertex3f(fExtent, y, iLine);
+ glVertex3f(-fExtent, y, iLine);
+ }
+ glEnd();
+}
+
+void render()
+{
+ /* clear the window with current clearing color */
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+
+ draw_ground();
+
+ /* buffer swap */
+ SDL_GL_SwapBuffers();
+}
+
+int main(void)
+{
+ SDL_Surface *sc