From 6f0b727ccf1f3b791d38c72519a3005cf56dd2fb Mon Sep 17 00:00:00 2001 From: Kyle K Date: Sun, 3 Oct 2010 19:52:04 -0500 Subject: Initial commit --- Makefile | 31 +++ cube/.gitignore | 3 + math3d.c | 650 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ math3d.h | 130 ++++++++++++ obj.c | 92 ++++++++ obj.h | 36 ++++ objloader.c | 217 +++++++++++++++++++ 7 files changed, 1159 insertions(+) create mode 100644 Makefile create mode 100644 cube/.gitignore create mode 100644 math3d.c create mode 100644 math3d.h create mode 100644 obj.c create mode 100644 obj.h create mode 100644 objloader.c 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 +#include +#include +#include +#include +#include + +#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 +#include +#include +#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 +#include +#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 *screen; + + if (SDL_Init(SDL_INIT_VIDEO) < 0 ) + { + fprintf(stderr, "unable to init SDL: %s\n", SDL_GetError()); + exit(-1); + } + atexit(SDL_Quit); + SDL_WM_SetCaption("OBJ Loader", NULL); + + if ((screen = SDL_SetVideoMode(640, 480, 32, SDL_OPENGL | SDL_GL_DOUBLEBUFFER + | SDL_RESIZABLE)) == NULL) + { + fprintf(stderr, "unable to set video mode: %s\n", SDL_GetError()); + exit(-1); + } + + SDL_EnableUNICODE(1); + /* SDL doesn't trigger off a ResizeEvent at startup, but as we need this + * for OpenGL, we do this ourselves */ + SDL_Event resizeEvent; + resizeEvent.type = SDL_VIDEORESIZE; + resizeEvent.resize.w = 640; + resizeEvent.resize.h = 480; + SDL_PushEvent(&resizeEvent); + + /* initalize glew */ + GLenum glewerr = glewInit(); + if (GLEW_OK != glewerr) + { + fprintf(stderr, "error: %s\n", glewGetErrorString(glewerr)); + return -1; + } + else + fprintf(stdout, "status: using GLEW %s\n", glewGetString(GLEW_VERSION)); + + /* setup few stuff before rendring */ + SetupRC(); + + /* OBJ Loading */ + char *memory = NULL; + size_t bytes = ObjLoadFile("./cube/cube.obj", &memory); + + ObjModel* model = ObjLoadModel(memory, bytes); + printf("Object Model has: %d faces!\n", model->nTriangle); + + /* XXX: Insert Code Here */ + + + /* main loop */ + while (program_running) + { + processEvents(); + render(); + } + + /* might never be reached, meh */ + free(model->NormalArray); + free(model->TexCoordArray); + free(model->TriangleArray); + free(model->VertexArray); + free(model); + puts("bye!"); + + return 0; +} + -- cgit v1.2.3