| | |
Optimizing OpenGL (SwapBuffer being slow)
![]() |
EDIT for moderators:
Yes that "one might think that swapbuffer is slow" was me. Heh.
Could someone change the topicname to "Optimizing OpenGL"? Thanks.
Hey guys,
I'm trying to optimize this OpenGL program, so the problem isn't C, but the program is.
The program loads a vanilla WaveFront .obj file, stores all it's data in an array, creates a display list, uses glDrawElements to put it in the display list and then calls the display list as often as it can. For my test file, this "how often as it can" gives an FPS of about 37. While this is acceptable, another program that does the same manages to do it at 60 FPS.
How do I achieve that performance in this program? The bottleneck appears to be the RenderScene function. It only shows when using glFinish(), else one might think SwapBuffer() takes that amount of time (SwapBuffer waits, of course, for the videocard to finish its rendering). Anyway, from beginning RenderScene to the return of SwapBuffer takes too much time. Too much CPU time that is! My Intel blah blah dual core has once core fully eaten up by this code, and I have no clue why.
Here is the output from the sourcecode below:
How can I speed this up?
Thanks in Advance,
Nick
Code:
BowViceJet.c
loadObj.h isn't included for it doesn't matter for the rendering code and is rather long.
Yes that "one might think that swapbuffer is slow" was me. Heh.
Could someone change the topicname to "Optimizing OpenGL"? Thanks.Hey guys,
I'm trying to optimize this OpenGL program, so the problem isn't C, but the program is.
The program loads a vanilla WaveFront .obj file, stores all it's data in an array, creates a display list, uses glDrawElements to put it in the display list and then calls the display list as often as it can. For my test file, this "how often as it can" gives an FPS of about 37. While this is acceptable, another program that does the same manages to do it at 60 FPS.
How do I achieve that performance in this program? The bottleneck appears to be the RenderScene function. It only shows when using glFinish(), else one might think SwapBuffer() takes that amount of time (SwapBuffer waits, of course, for the videocard to finish its rendering). Anyway, from beginning RenderScene to the return of SwapBuffer takes too much time. Too much CPU time that is! My Intel blah blah dual core has once core fully eaten up by this code, and I have no clue why.
Here is the output from the sourcecode below:
C Syntax (Toggle Plain Text)
WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 16 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 16 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 32 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 16 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 16 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 32 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 15 WM_TIMER took: Time elapsed: 32 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 0 WM_TIMER took: Time elapsed: 16 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 16 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 16 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 31 WM_TIMER took: Time elapsed: 32 WM_TIMER took: Time elapsed: 15 WM_TIMER took: Time elapsed: 32 WM_TIMER took: Time elapsed: 31 FPS: 36
How can I speed this up?
Thanks in Advance,
Nick
Code:
BowViceJet.c
C Syntax (Toggle Plain Text)
#include <stdio.h> #include <windows.h> #include <gl/gl.h> #include <gl/glu.h> #include <gl/glext.h> #include <time.h> #include "loadObj.h" #define TIMEELAPSED {printf("\tTime elapsed: %lu\n", clock() - startTime);} int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdLine, int cmdShow); LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam); void dbgError(char *msg); void MySetPixelFormat(HDC hDC); void RenderScene(); void ChangeSize(int width, int height); int initGL(); void pressKey(WPARAM key); const static char className[] = "OpenGLClass"; const static char appName[] = "OpenGL Window"; GLfloat xRot, yRot, zRot; GLfloat xDis, yDis, zDis; float *vertices, *normals; int *triangleindex, *quadindex; unsigned int quadcount, trianglecount; int err; char *globcmdLine; unsigned int globDisplayLists = 0; char optFrontFace = 0; //CCW default void dbgError(char *msg){ fprintf(stderr, "Error @ %s. GetLastError(): %lu", msg, GetLastError()); return; } int APIENTRY WinMain(HINSTANCE instance, HINSTANCE prevInstance, LPSTR cmdLine, int cmdShow){ globcmdLine = cmdLine; MSG msg; WNDCLASS wc; HWND hWnd; wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; wc.lpfnWndProc = (WNDPROC) WndProc; wc.cbClsExtra = 0; wc.cbWndExtra = 0; wc.hInstance = instance; wc.hIcon = NULL; wc.hCursor = LoadCursor(NULL, IDC_ARROW); wc.hbrBackground = NULL; wc.lpszMenuName = NULL; wc.lpszClassName = className; if(RegisterClass(&wc) == 0){ dbgError("RegisterClass()"); return -1; } const DWORD style = WS_OVERLAPPEDWINDOW | WS_CLIPCHILDREN | WS_CLIPSIBLINGS; const int xPos = 0; const int yPos = 0; const int width = 640; const int height = 480; hWnd = CreateWindow(className, appName, style, xPos, yPos, width, height, NULL, NULL, instance, NULL); if(hWnd == NULL){ dbgError("CreateWindow()"); return -1; } ShowWindow(hWnd, SW_SHOW); UpdateWindow(hWnd); int ret; while((ret = GetMessage(&msg, NULL, 0, 0)) > 0){ TranslateMessage(&msg); DispatchMessage(&msg); } if(ret == -1){ dbgError("GetMessage()"); return -1; } printf("Exiting from WinMain! G'bye.\n"); return msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){ static HGLRC hRC = NULL; static HDC hDC = NULL; clock_t startTime; switch(msg){ case WM_TIMER: startTime = clock(); RenderScene(); xRot += 0.5; yRot += 0.5; zRot += 0.5; SwapBuffers(hDC); printf("WM_TIMER took: "); TIMEELAPSED break; case WM_CREATE: hDC = GetDC(hWnd); MySetPixelFormat(hDC); hRC = wglCreateContext(hDC); if (hRC == NULL){ unsigned long err = GetLastError(); char *msg = calloc(sizeof(char), 512); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, err, 0, msg, 512, 0); printf("wglCreateContext() failed: error nr. %lu:\n\t%s\n", err, msg); } if (wglMakeCurrent(hDC, hRC) == FALSE){ unsigned long err = GetLastError(); char *msg = calloc(sizeof(char), 512); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, err, 0, msg, 512, 0); printf("wglMakeCurrent() failed: error nr. %lu:\n\t%s\n", err, msg); } if(initGL() < 0){ printf("Error loading in model. Exiting"); exit(1); } else{ printf("Model loaded and ready to go!\n"); } //fire as often as it can SetTimer(hWnd, 0, 1, NULL); printf("Running with GL_VENDOR: %s\n", glGetString(GL_VENDOR)); break; case WM_DESTROY: wglMakeCurrent(hDC, NULL); wglDeleteContext(hRC); PostQuitMessage(0); break; case WM_PAINT: //printf("WM_PAINTING. ;-)\n"); RenderScene(); SwapBuffers(hDC); ValidateRect(hWnd, NULL); break; case WM_SIZE: ChangeSize(LOWORD(lParam), HIWORD(lParam)); break; case WM_KEYDOWN: pressKey(wParam); break; default: return (DefWindowProc(hWnd, msg, wParam, lParam)); break; } return 0; } void MySetPixelFormat(HDC hDC){ int pixelFormat; static PIXELFORMATDESCRIPTOR pfd = { sizeof(PIXELFORMATDESCRIPTOR), 1, PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER | PFD_TYPE_RGBA, 32, //depth of color 0,0,0,0,0,0,0,0,0,0,0,0,0, 16 , //depth of depthbuffer 0,0,0,0,0,0,0}; pixelFormat = ChoosePixelFormat(hDC, &pfd); if (SetPixelFormat(hDC, pixelFormat, &pfd) == FALSE){ unsigned long err = GetLastError(); char *msg = calloc(sizeof(char), 512); FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, 0, err, 0, msg, 512, 0); printf("SetPixelFormat() failed: error nr. %lu:\n\t%s\n", err, msg); } return; } void RenderScene(){ //printf("Rendering scene...\n"); static clock_t nextSecond = 0; static unsigned int framesPerSecond = 0; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); clock_t startTime = clock(); //glMatrixMode(GL_MODELVIEW); if(optFrontFace){ glFrontFace(GL_CW); } else{ glFrontFace(GL_CCW); } glPushMatrix(); glTranslatef(xDis, yDis, zDis-20); glRotatef(xRot, 1, 0, 0); glRotatef(yRot, 0, 1, 0); glRotatef(zRot, 0, 0, 1); glColor3f(.5, .6, .6); //printf("Quadindex: %p\tTriangleindex: %p\n", quadindex, triangleindex); //printf("Quadcount: %u\tTrianglecount: %u\n", quadcount, trianglecount); glCallList(globDisplayLists); glPopMatrix(); //glDisableClientState(GL_VERTEX_ARRAY); //glDisableClientState(GL_NORMAL_ARRAY); framesPerSecond++; if(clock() >= nextSecond){ nextSecond = clock() + CLOCKS_PER_SEC; printf("FPS: %u\n", framesPerSecond); framesPerSecond = 0; } return; } void ChangeSize(int width, int height){ if (height == 0) height = 1; GLfloat aspect = (GLfloat)width/(GLfloat)height; glViewport(0, 0, width, height); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluPerspective(60, aspect, 0.1, 1000); glMatrixMode(GL_MODELVIEW); glLoadIdentity(); return; } int initGL(){ xRot = yRot = zRot = 0; xDis = yDis = zDis = 0; vertices = normals = NULL; triangleindex = quadindex = NULL; quadcount = trianglecount = 0; glFrontFace(GL_CCW); glEnable(GL_DEPTH_TEST); glEnable(GL_CULL_FACE); glEnable(GL_LIGHTING); //lighting colors GLfloat ambient[] = {0.35, 0.35, 0.35, 1.0}; GLfloat diffuse[] = {0.5, 0.5, 0.5, 1.0}; //GLfloat specular[] = {1, 1, 1, 1}; GLfloat light0Pos[] = {-60, 10, 10, 1}; GLfloat light1Pos[] = {60, 10, 10, 1}; glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_AMBIENT, ambient); glLightfv(GL_LIGHT0, GL_DIFFUSE, diffuse); //glLightfv(GL_LIGHT0, GL_SPECULAR, specular); glLightfv(GL_LIGHT0, GL_POSITION, light0Pos); glEnable(GL_LIGHT0); glLightModelfv(GL_LIGHT_MODEL_AMBIENT, ambient); glLightfv(GL_LIGHT1, GL_AMBIENT, ambient); glLightfv(GL_LIGHT1, GL_DIFFUSE, diffuse); //glLightfv(GL_LIGHT1, GL_SPECULAR, specular); glLightfv(GL_LIGHT1, GL_POSITION, light1Pos); glEnable(GL_LIGHT1); glEnable(GL_COLOR_MATERIAL); glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); //GLfloat specref[] = {1, 1, 1, 1}; //glMaterialfv(GL_FRONT, GL_SPECULAR, specref); //glMateriali(GL_FRONT, GL_SHININESS, 120); glClearColor(0.0, 0.0, 0.0, 1.0); err = loadObj(globcmdLine, &vertices, &normals, &triangleindex, &quadindex, &quadcount, &trianglecount); if(err < 0){ printf("loadObj failed to load object!"); return -1; } if(vertices == NULL || normals == NULL || (triangleindex == NULL && quadindex == NULL)){ printf("Error! One of the essential pointers == NULL!"); return -1; } //printf("Enabling vertex and normal arrays..."); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); //printf("Done\n"); //printf("Vertices: %p\tNormals: %p\n", vertices, normals); glVertexPointer(3, GL_FLOAT, 0, vertices); glNormalPointer(GL_FLOAT, 0, normals); globDisplayLists = glGenLists(1); glNewList(globDisplayLists, GL_COMPILE); glDrawElements(GL_QUADS, quadcount*4, GL_UNSIGNED_INT, quadindex); glDrawElements(GL_TRIANGLES, trianglecount*3, GL_UNSIGNED_INT, triangleindex); glEndList(); return 0; } void pressKey(WPARAM key){ #define KEYPRESS(x, a, b, c){\ case x:\ a b c;\ break;\ } #define KEYPAIR(keyone, keytwo, var, val){\ KEYPRESS(keyone, var, +=, val);\ KEYPRESS(keytwo, var, -=, val);\ } #define OPTION(key, optname){\ KEYPRESS(key, optname, ^=, 1);\ } static float STRENGTH = 1; switch (key){ //rotation KEYPAIR('Q', 'E', yRot, (STRENGTH*2)); KEYPAIR('A', 'D', xRot, (STRENGTH*2)); KEYPAIR('Z', 'C', zRot, (STRENGTH*2)); //displacement KEYPAIR(VK_RIGHT, VK_LEFT, xDis, STRENGTH); KEYPAIR(VK_UP, VK_DOWN, yDis, STRENGTH); KEYPAIR(VK_CONTROL, VK_NUMPAD0, zDis, STRENGTH); //options OPTION('F', optFrontFace); //STRENGTH adjustment :D KEYPAIR('O', 'P', STRENGTH, 0.01); } printf("Strength: %f\n", STRENGTH); #define ROUNDTHREESIXTY(x) { \ if (x <= -360.0 || x >= 360.0){\ x = 0;\ }\ } ROUNDTHREESIXTY(yRot); ROUNDTHREESIXTY(xRot); ROUNDTHREESIXTY(zRot); #undef ROUNDTHREESIXTY #undef OPTION #undef KEYPAIR #undef KEYPRESS return; }
loadObj.h isn't included for it doesn't matter for the rendering code and is rather long.
Last edited by Clockowl; Jul 20th, 2008 at 8:52 pm. Reason: Wrong topic name
My only suggestion is to try a profiler so that you can see exactly where your program is spending all of its time. If you have access to the code from the other program, profiling it as well might be enlightening.
If you're using a Windows port of GCC like MinGW, you already have a profiler: gprof. Google it for details. I'm sure the Microsoft compilers come with one too, but I don't know what it is.
If you're using a Windows port of GCC like MinGW, you already have a profiler: gprof. Google it for details. I'm sure the Microsoft compilers come with one too, but I don't know what it is.
dwk
Seek and ye shall find.
"Only those who will risk going too far can possibly find out how far one can go."
-- TS Eliot.
"I have not failed. I've just found 10,000 ways that won't work."
-- Thomas Alva Edison
"The only real mistake is the one from which we learn nothing."
-- John Powell
Seek and ye shall find.
"Only those who will risk going too far can possibly find out how far one can go."
-- TS Eliot.
"I have not failed. I've just found 10,000 ways that won't work."
-- Thomas Alva Edison
"The only real mistake is the one from which we learn nothing."
-- John Powell
Gmon.out doesn't contain any useful info, all the times are zero.
I'm using it from Code::Blocks on my Windows XP x64 machine.
Like this btw:
I'm using it from Code::Blocks on my Windows XP x64 machine.Like this btw:
C Syntax (Toggle Plain Text)
Flat profile: Each sample counts as 0.01 seconds. no time accumulated % cumulative self self total time seconds seconds calls Ts/call Ts/call name 0.00 0.00 0.00 1926 0.00 0.00 _RenderScene 0.00 0.00 0.00 1 0.00 0.00 _WinMain@16 0.00 0.00 0.00 1 0.00 0.00 _initGL 0.00 0.00 0.00 1 0.00 0.00 _loadObj
Last edited by Clockowl; Jul 22nd, 2008 at 8:15 pm.
Strange, when I run Gprof from the command line, seconds do show up, but it doesn't seem to be compatible with winmain instead of main. 
Well, I was rewriting it to GLUT anyway. Thanks for the trouble. Suggestions on how to improve the above code are still welcome of course...

C Syntax (Toggle Plain Text)
Each sample counts as 0.01 seconds. % cumulative self self total time seconds seconds calls ms/call ms/call name 91.30 0.63 0.63 1 630.00 670.00 loadObj 5.80 0.67 0.04 297473 0.00 0.00 countSpaces 1.45 0.68 0.01 isspace 1.45 0.69 0.01 malloc 0.00 0.69 0.00 2093 0.00 0.00 RenderScene 0.00 0.69 0.00 1 0.00 0.00 ChangeSize 0.00 0.69 0.00 1 0.00 0.00 MySetPixelFormat 0.00 0.69 0.00 1 0.00 0.00 WinMain@16 0.00 0.69 0.00 1 0.00 670.00 initGL
Well, I was rewriting it to GLUT anyway. Thanks for the trouble. Suggestions on how to improve the above code are still welcome of course...
Last edited by Clockowl; Jul 22nd, 2008 at 8:17 pm.
>Well, I was rewriting it to GLUT anyway. Thanks for the trouble. Suggestions on how to improve the above code are still welcome of course...
Perhaps, placing all your macros definition at the top the code would make it more be neat and professional. That was from a quite glance. That’s a huge lot code!
ssharish
Perhaps, placing all your macros definition at the top the code would make it more be neat and professional. That was from a quite glance. That’s a huge lot code!
ssharish
Erm.. well now I created them right before they are used, and undefined them right after that.. That's neat I think? They are placed where they are used. That way you don't have to scroll up to view it's implementation.
Agreed nonetheless that the code is mess and it could be cleaned up more. But I don't think the macros are that disturbing.
On a sidenote: How do I get gprof to work with C++ using GLUT and threading? Hahaha.. it doesn't display times now even when I run from the console..
I'm downloading VTune as we speak, but I'd like gprof to work, being free and all.
Agreed nonetheless that the code is mess and it could be cleaned up more. But I don't think the macros are that disturbing.
On a sidenote: How do I get gprof to work with C++ using GLUT and threading? Hahaha.. it doesn't display times now even when I run from the console..
I'm downloading VTune as we speak, but I'd like gprof to work, being free and all.
Last edited by Clockowl; Jul 24th, 2008 at 6:50 pm.
Hey, of course. It's pretty straightforward tho, only loading vertices, faces and normals, but not polygons and other things (like textures for instance).
The main bottleneck is I/O: sscanf. The only way I see to speed this program up is to:
Multithread it
Store the .obj files as binary data instead of their ASCII representation, so you won't have to use scanf anymore.
loadObj.c
The main bottleneck is I/O: sscanf. The only way I see to speed this program up is to:
Multithread it
Store the .obj files as binary data instead of their ASCII representation, so you won't have to use scanf anymore.
loadObj.c
C Syntax (Toggle Plain Text)
#include <stdio.h> //obvious #include <stdlib.h> //malloc and such #include <string.h> //memory copy stuff #include <time.h> //time stuff, ofc. #include <ctype.h> //isspace, isdigit #include <math.h> //only for fabs #define TIMEELAPSED {printf("\tTime elapsed: %lu\n", (clock() - startTime)*1000 / CLOCKS_PER_SEC);} //this is in BowViceJet.c void dbgError(char *msg); int countSpaces(char *str){ int cnt = 0; while(*str != '\0'){ if(*str == ' ') cnt++; str++; } //remove trailing spaces str--; while(isspace(*str)){ if(*str == ' ') cnt--; str--; } return cnt; } int loadObj(const char const *loc,\ float **retvertices, float **retgouraudnormals,\ int **rettriangleindex, int **retquadindex,\ int *quadcount, int *trianglecount){ float *vertices, *gouraudnormals; int *triangleindex, *quadindex; float *normals, *verttext; int *trianglenormals, *quadnormals; clock_t startTime = clock(); int fileSize = 0; int n, i, j; printf("Opening file: %s\n", loc); FILE *pFile = fopen(loc, "r"); if(pFile == NULL){ dbgError("fopen()"); exit(1); } fseek(pFile, 0, SEEK_END); fileSize = ftell(pFile); rewind(pFile); char *data = (char*) calloc(sizeof(char), fileSize + 1); fread(data, 1, fileSize, pFile); if(ferror(pFile)){ dbgError("fread()"); exit(1); } fclose(pFile); printf("Done reading, parsing file now.\n"); TIMEELAPSED printf("Removing #IND if there..."); char *pIND = data; n = 0; while(1){ pIND = strstr(pIND, "#IND"); if(pIND != NULL){ memcpy(pIND, "0000", sizeof(char) * 4); n++; } else break; } printf("Removed %d #INDs\n", n); TIMEELAPSED printf("Counting lines and determining maximum length..."); int maxLen, lenCount; int lines; for (i = lines = lenCount = maxLen = 0; i <= fileSize; i++){ if (data[i] == '\n'){ lines++; lenCount++; if(lenCount > maxLen) maxLen = lenCount; lenCount = 0; } lenCount++; } printf("Counted %d lines, maximum length: %d\n", lines, maxLen); TIMEELAPSED printf("Allocating %d strings of %d chars...", lines, maxLen); char **parsedText = (char**) calloc(sizeof(char*), lines); for(n = 0; n < lines; n++){ parsedText[n] = (char*) malloc(sizeof(char) * maxLen); if (parsedText[n] == NULL){ printf("Malloc failed to allocate %d bytes for parsedText[%d].\n", maxLen, n); return -1; } } printf("Done\n"); TIMEELAPSED printf("Reading in 2D array..."); for(i = n = j = 0; n < lines; i++){ if(data[i] == '\n'){ parsedText[n][j] = '\0'; n++; j = 0; //puts(parsedText[n]); continue; } //printf("parsedText[%d][%d] = textTree[%d] = %c\n", n, j, i, data[i]); parsedText[n][j] = data[i]; j++; } printf("Done\n"); TIMEELAPSED //free the data, we don't need it anymore since it's stored in parsedText free(data); /* for(i = 0; i < lines; i++){ puts(parsedText[i]); } */ printf("Counting..."); int vertlines, normallines, facelines, texturelines; vertlines = normallines = facelines = texturelines = 0; unsigned int faceverts, maxFaceverts, trianglecnt, quadcnt; faceverts = maxFaceverts = trianglecnt = quadcnt = 0; //stores for every face line how many verts it has. int *facevertcnt = calloc(sizeof(int), lines); for(i = 0; i < lines; i++){ if(parsedText[i][0] == '#') continue; if(parsedText[i][0] == 'v' && parsedText[i][1] == ' '){ vertlines++; } else if(parsedText[i][0] == 'v' && parsedText[i][1] == 'n'){ normallines++; } else if(parsedText[i][0] == 'f' && parsedText[i][1] == ' '){ facelines++; for(n = 2; !isdigit(parsedText[i][n]); n++); faceverts = countSpaces(&parsedText[i][n]); if(faceverts == 2){ trianglecnt++; //printf("triangle: %s\n", parsedText[i]); } else if(faceverts == 3){ quadcnt++; //printf("quad: %s", parsedText[i]); } if(faceverts > maxFaceverts) maxFaceverts = faceverts; facevertcnt[i] = faceverts; //getchar(); } else if(parsedText[i][0] == 'v' && parsedText[i][1] == 't'){ texturelines++; } } int vertvals = vertlines * 3; int normalvals = normallines * 3; int texturevals = texturelines * 2; int triangleverts = trianglecnt * 3; int quadverts = quadcnt * 4; *trianglecount = trianglecnt; *quadcount = quadcnt; printf("Counted:\n\t%d vertices\n\t%d normals\n\t%d faces (%d triangles, %d quads)\n", vertlines, normallines, facelines, trianglecnt, quadcnt); TIMEELAPSED if(maxFaceverts > 4){ printf("WARNING:\n Model won't be imported correctly due to polygons with more than 4 vertices.\n"); } printf("Allocating memory for data..."); vertices = calloc(sizeof(float), vertvals); normals = calloc(sizeof(float), normalvals); verttext = calloc(sizeof(float), texturevals); triangleindex = calloc(sizeof(int), triangleverts); trianglenormals = calloc(sizeof(int), triangleverts); quadindex = calloc(sizeof(int), quadverts); quadnormals = calloc(sizeof(int), quadverts); if(vertices == NULL || normals == NULL || verttext == NULL || triangleindex == NULL || trianglenormals == NULL || quadindex == NULL || quadnormals == NULL){ printf("Failed to allocate enough memory, exiting...\n"); return -1; } int vertcount, normalcount, textcount, tricnt, quacnt; printf("Done\n"); TIMEELAPSED printf("Reading in data..."); for(vertcount = normalcount = textcount = tricnt = quacnt = i = 0; i < lines; i++){ //comment if(parsedText[i][0] == '#') continue; if(parsedText[i][0] == ' ') continue; //vertex if(vertlines) if(parsedText[i][0] == 'v' && parsedText[i][1] == ' '){ sscanf(&parsedText[i][2], "%f%f%f", (vertices+vertcount), (vertices+vertcount+1), (vertices+vertcount+2)); vertcount += 3; } //normal if(normallines) if(parsedText[i][0] == 'v' && parsedText[i][1] == 'n'){ sscanf(&parsedText[i][2], "%f%f%f", (normals+normalcount), (normals+normalcount+1), (normals+normalcount+2)); normalcount += 3; } //texture if(texturelines) if(parsedText[i][0] == 'v' && parsedText[i][1] == 't'){ sscanf(&parsedText[i][2], "%f%f", (verttext+textcount), (verttext+textcount+1)); textcount += 2; } //faces if(trianglecnt || quadcnt) if(parsedText[i][0] == 'f' && parsedText[i][1] == ' '){ if(facevertcnt[i] == 2){ //skip all leading spaces for(n = 2; isspace(parsedText[i][n]); n++); //read in the vertexnr sscanf(&parsedText[i][n], "%d", (triangleindex+tricnt)); if(normallines){ //skip 2 slashes for(; parsedText[i][n] != '/'; n++); n++; for(; parsedText[i][n] != '/'; n++); n++; //read in the normalnr sscanf(&parsedText[i][n], "%d", (trianglenormals+tricnt)); } for(;!isspace(parsedText[i][n]); n++); sscanf(&parsedText[i][n], "%d", (triangleindex+tricnt+1)); n++; if(normallines){ //skip 2 slashes for(; parsedText[i][n] != '/'; n++); n++; for(; parsedText[i][n] != '/'; n++); n++; //read in the normalnr sscanf(&parsedText[i][n], "%d", (trianglenormals+tricnt+1)); } for(;!isspace(parsedText[i][n]); n++); sscanf(&parsedText[i][n], "%d", (triangleindex+tricnt+2)); if(normallines){ //skip 2 slashes for(; parsedText[i][n] != '/'; n++); n++; for(; parsedText[i][n] != '/'; n++); n++; //read in the normalnr sscanf(&parsedText[i][n], "%d", (trianglenormals+tricnt+2)); } for(j = 0; j < 3; j++){ //-4 on line 4 becomes 0. if(triangleindex[tricnt+j] < 0){ triangleindex[tricnt+j] = i - triangleindex[tricnt+j]; } else{ triangleindex[tricnt+j]--; trianglenormals[tricnt+j]--; } } tricnt += 3; } if(facevertcnt[i] == 3){ //skip all leading spaces for(n = 2; isspace(parsedText[i][n]); n++); sscanf(&parsedText[i][n], "%d", (quadindex+quacnt)); if(normallines){ //skip 2 slashes for(; parsedText[i][n] != '/'; n++); n++; for(; parsedText[i][n] != '/'; n++); n++; //read in the normalnr sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt)); } for(;!isspace(parsedText[i][n]); n++); sscanf(&parsedText[i][n], "%d", (quadindex+quacnt+1)); n++; if(normallines){ //skip 2 slashes for(; parsedText[i][n] != '/'; n++); n++; for(; parsedText[i][n] != '/'; n++); n++; //read in the normalnr sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt+1)); } for(;!isspace(parsedText[i][n]); n++); sscanf(&parsedText[i][n], "%d", (quadindex+quacnt+2)); n++; if(normallines){ //skip 2 slashes for(; parsedText[i][n] != '/'; n++); n++; for(; parsedText[i][n] != '/'; n++); n++; //read in the normalnr sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt+2)); } for(;!isspace(parsedText[i][n]); n++); sscanf(&parsedText[i][n], "%d", (quadindex+quacnt+3)); if(normallines){ //skip 2 slashes for(; parsedText[i][n] != '/'; n++); n++; for(; parsedText[i][n] != '/'; n++); n++; //read in the normalnr sscanf(&parsedText[i][n], "%d", (quadnormals+quacnt+3)); } for(j = 0; j < 4; j++){ //-4 on line 4 becomes 0. if(quadindex[quacnt+j] < 0){ quadindex[quacnt+j] = i - quadindex[quacnt+j]; } quadindex[quacnt+j]--; quadnormals[quacnt+j]--; } quacnt += 4; } } } printf("Done\n"); TIMEELAPSED if(normallines){ printf("Calculating Gouraud normals for each vertex..."); gouraudnormals = calloc(sizeof(float), vertvals); float normalx, normaly, normalz; if(trianglecnt != 0){ //printf("::DBG:: calcing trianglenormals\n"); for(i = 0; i < triangleverts; i++){ //printf("::DBG::accessing GRnor[%d{%d}] & normals[%d]\n", triangleindex[i]*3, normalvals, trianglenormals[i]*3); normalx = normals[trianglenormals[i]*3]; normaly = normals[trianglenormals[i]*3+1]; normalz = normals[trianglenormals[i]*3+2]; gouraudnormals[triangleindex[i]*3] += normalx; gouraudnormals[triangleindex[i]*3+1] += normaly; gouraudnormals[triangleindex[i]*3+2] += normalz; } } if(quadcnt != 0){ //printf("::DBG:: calcing quadnormals\n"); for(i = 0; i < quadverts; i++){ //printf("::DBG::accessing GRnor[%d{%d}] & normals[%d]\n", quadindex[i]*3, vertvals, quadnormals[i]*3); normalx = normals[quadnormals[i]*3]; normaly = normals[quadnormals[i]*3+1]; normalz = normals[quadnormals[i]*3+2]; gouraudnormals[quadindex[i]*3] += normalx; gouraudnormals[quadindex[i]*3+1] += normaly; gouraudnormals[quadindex[i]*3+2] += normalz; } } printf("Done\n"); TIMEELAPSED printf("Normalizing normals..."); for(i = 0; i < normalvals; i += 3){ normalx = fabs(gouraudnormals[i]); normaly = fabs(gouraudnormals[i+1]); normalz = fabs(gouraudnormals[i+2]); float max = normalx; if (normaly > max) max = normaly; if (normalz > max) max = normalz; //normalize if(max != 0){ gouraudnormals[i] /= max; gouraudnormals[i+1] /= max; gouraudnormals[i+2] /= max; } } printf("Done\n"); TIMEELAPSED } else{ printf("No normals detected! This version doesn't calculate normals, too lazy. :(\n"); } /* for(n = 0; n < vertvals; n += 3){ printf("v %f %f %f\n", vertices[n], vertices[n+1], vertices[n+2]); } */ /* for(n = 0; n < normalvals; n += 3){ printf("vn[%d] %f %f %f\n", n/3, normals[n], normals[n+1], normals[n+2]); } */ /* for(n = 0; n < texturevals; n += 2){ printf("vt %f %f\n", verttext[n], verttext[n+1]); } */ /* for(n = 0; n < triangleverts; n += 3){ printf("triangle: %d %d %d\n\t" "Normals: %d %d %d\n",\ triangleindex[n], triangleindex[n+1], triangleindex[n+2],\ trianglenormals[n], trianglenormals[n+1], trianglenormals[n+2]); } */ /* for(n = 0; n < quadverts; n += 4){ printf("Quad: %d %d %d %d\n\t" "Normals: %d %d %d %d\n",\ quadindex[n], quadindex[n+1], quadindex[n+2], quadindex[n+3],\ quadnormals[n], quadnormals[n+1], quadnormals[n+2], quadnormals[n+3]); } */ /* if(normallines) for(n = 0; n < vertlines; n++){ printf("Normals for v[%d]: %f %f %f\n", n, gouraudnormals[n*3], gouraudnormals[n*3+1], gouraudnormals[n*3+2]); } */ printf("File succesfully loaded, returning.\n"); TIMEELAPSED *retvertices = vertices; *retgouraudnormals = gouraudnormals; *rettriangleindex = triangleindex; *retquadindex = quadindex; return 0; }
![]() |
Other Threads in the C Forum
- Previous Thread: /etc/resolv.conf
- Next Thread: Replace using POSIX regular expressions
| Thread Tools | Search this Thread |
* adobe ansi api array binarysearch centimeter changingto char character cm convert copyanyfile copypdffile cprogramme createcopyoffile createprocess() csyntax database directory feet fflush fgets file floatingpointvalidation fork frequency function givemetehcodez global graphics gtkgcurlcompiling gtkwinlinux highest histogram homework i/o inches infiniteloop input interest intmain() iso keyboard kilometer km linked linkedlist linux linuxsegmentationfault list locate looping lowest match meter microsoft mqqueue mysql oddnumber odf open opendocumentformat openwebfoundation owf pattern pdf performance posix power probleminc program programming pyramidusingturboccodes read recv recvblocked repetition reversing scanf scheduling segmentationfault send single socketprograming socketprogramming stack standard string suggestions systemcall unix urboc user voidmain() wab whythiscodecausesegmentationfault win32api windows.h windowsapi





