/* * Kamil Kaminski * kamilkss@gmail.com * * OBJ Loader * * Code: * http://www.gamedev.net/community/forums/topic.asp?topic_id=312335 * * todo: move obj files and texures into folder named e.g. "obj", or find some way * of figuring out the current directory, hmm, could modify a path string, e.g. * "./cube/cube.obj" -> "/cube/X", I would need to loop for last occurence of "/" * */ #include #include #include #include #include "math3d.h" #include "obj.h" /* function prototypes */ static void resize(int, int); static void setup_opengl(ObjModel *); static void process_events(void); static void draw_ground(void); static void render(ObjModel *); /* 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(45.0f, fAspect, 1.0, 300.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_RESIZABLE); } static void setup_opengl(ObjModel *model) { /* 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); /* example of loading a targa file, note: RLE compression is not supported */ GLbyte *pBytes; GLint iWidth, iHeight, iComponents; GLenum eFormat; /* get the texture filename from obj */ char *fname = ObjGetPath(model->mtl->map_Ka); /* ambient texture map */ if (model->mtl != NULL) { printf("ambient texture map: %s\n", model->mtl->map_Ka); /* load texture */ glPixelStorei(GL_UNPACK_ALIGNMENT, 1); pBytes = gltLoadTGA(fname, &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); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_BORDER); glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); glEnable(GL_TEXTURE_2D); } } /* process SDL events */ static void process_events(void) { 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(); } static void render(ObjModel *model) { /* clear the window with current clearing color */ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); draw_ground(); glPushMatrix(); glScalef(0.1f, 0.1f, 0.1f); glTranslatef(5.0f, 0.0f, -150.0f); glBegin(GL_QUADS); ObjSubmitGLCommandsQuad(model); glEnd(); /* ObjSubmitIndexedVertexArrayQuad(model); */ glPopMatrix(); /* buffer swap */ SDL_GL_SwapBuffers(); } int main(int argc, char **argv) { if (argc != 2) { fprintf(stderr, "da fuck think you're doing?\n"); exit(-1); } 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); SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 8); SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 16); if ((screen = SDL_SetVideoMode(640, 480, 32, SDL_OPENGL | 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)); /* OBJ Loading */ char *memory = NULL; /* size_t bytes = ObjLoadFile("./cube/cube.obj", &memory); */ size_t bytes = ObjLoadFile(argv[1], &memory); ObjModel *model = ObjLoadModel(memory, bytes); if (!bytes || model == NULL) { fprintf(stderr, "obj file could not be loaded!\n"); exit(-1); } /* setup few stuff before rendering */ setup_opengl(model); /* main loop */ while (program_running) { process_events(); render(model); } /* free up the resources */ ObjFree(model); puts("bye!"); return 0; }