/
redgpu
/
GDMagArchive
Обзор
Документация
Войти
/
redgpu
/
GDMagArchive
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
jul00/lander/Muscles/LoadOBJ.cpp
376 строк
13 KB
Don Williamson
first commit
31 окт 2016, 17:03
31 окт 2016, 17:03
c823e7b
Код
Авторство
О чём код?
/////////////////////////////////////////////////////////////////////////////// // // LoadOBJ.cpp : implementation file // // Purpose: Implementation of OpenGL Window of OBJ Loader // // Created: // JL 9/23/98 // // Notes: This version doesn't used shared vertices in a vertex array. That // would be a faster way of doing things. This creates 3 vertices per // triangle. /////////////////////////////////////////////////////////////////////////////// // // Copyright 1998 Jeff Lander, All Rights Reserved. // For educational purposes only. // Please do not republish in electronic or print form without permission // Thanks - jeffl@darwin3d.com // /////////////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include <GL/gl.h> #include <GL/glu.h> #include "loadOBJ.h" /////////////////////////////////////////////////////////////////////////////// // Function: ParseString // Purpose: Actually breaks a string of words into individual pieces // Arguments: Source string in, array to put the words and the count /////////////////////////////////////////////////////////////////////////////// void ParseString(char *buffer,CStringArray *words,int *cnt) { /// Local Variables /////////////////////////////////////////////////////////// CString in = buffer, temp; /////////////////////////////////////////////////////////////////////////////// in.TrimLeft(); in.TrimRight(); *cnt = 0; do { temp = in.SpanExcluding(" \t"); // GET UP TO THE NEXT SPACE OR TAB words->Add(temp); if (temp == in) break; in = in.Right(in.GetLength() - temp.GetLength()); in.TrimLeft(); *cnt = *cnt + 1; } while (1); *cnt = *cnt + 1; } //// ParseString ////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Procedure: LoadMaterialLib // Purpose: Handles the Loading of a Material library // Arguments: Name of the Material Library /////////////////////////////////////////////////////////////////////////////// void LoadMaterialLib(CString name,t_Visual *visual) { /// Local Variables /////////////////////////////////////////////////////////// int cnt; char buffer[MAX_STRINGLENGTH]; CStringArray words; CString temp; FILE *fp; /////////////////////////////////////////////////////////////////////////////// strcpy(visual->map,""); fp = fopen((LPCTSTR)name,"r"); if (fp != NULL) { // FIRST PASS SETS UP THE NUMBER OF OBJECTS IN THE FILE while (!feof(fp)) { fgets(buffer,MAX_STRINGLENGTH,fp); // GET A STRING FROM THE FILE ParseString(buffer,&words,&cnt); // BREAK THE STRING INTO cnt WORDS if (cnt > 0) // MAKE SURE SOME WORDS ARE THERE { temp = words.GetAt(0); // CHECK THE FIRST WORK if (temp.GetLength() > 0) { if (temp == "Ka") // AMBIENT { visual->Ka.r = (float)atof(words.GetAt(1)); visual->Ka.g = (float)atof(words.GetAt(2)); visual->Ka.b = (float)atof(words.GetAt(3)); } else if (temp == "Kd") // DIFFUSE COLOR { visual->Kd.r = (float)atof(words.GetAt(1)); visual->Kd.g = (float)atof(words.GetAt(2)); visual->Kd.b = (float)atof(words.GetAt(3)); } else if (temp == "Ks") // SPECULAR COLOR { visual->Ks.r = (float)atof(words.GetAt(1)); visual->Ks.g = (float)atof(words.GetAt(2)); visual->Ks.b = (float)atof(words.GetAt(3)); } else if (temp == "Ns") // SPECULAR COEFFICIENT { visual->Ns = (float)atof(words.GetAt(1)); } else if (temp == "map_Kd") // TEXTURE MAP NAME { strcpy(visual->map,(LPCTSTR)words.GetAt(1)); } } } words.RemoveAll(); // CLEAR WORD BUFFER } fclose(fp); } } /////////////////////////////////////////////////////////////////////////////// // Procedure: HandleFace // Purpose: Handles the Face Line in an OBJ file. Extracts index info to // a face Structure // Arguments: Array of words from the face line, place to put the data // Notes: Not an Official OBJ loader as it doesn't handle anything other than // 3-4 vertex polygons. /////////////////////////////////////////////////////////////////////////////// void HandleFace(CStringArray *words,t_faceIndex *face) { /// Local Variables /////////////////////////////////////////////////////////// int loop,loopcnt; CString temp; CString vStr,nStr,tStr; // HOLD POINTERS TO ELEMENT POINTERS int nPos,tPos; /////////////////////////////////////////////////////////////////////////////// loopcnt = words->GetSize(); // LOOP THROUGH THE 3 - 4 WORDS OF THE FACELIST LINE, WORD 0 HAS 'f' for (loop = 1; loop < loopcnt; loop++) { temp = words->GetAt(loop); // GRAB THE NEXT WORD // FACE DATA IS IN THE FORMAT vertex/texture/normal tPos = temp.Find('/'); // FIND THE '/' SEPARATING VERTEX AND TEXTURE vStr = temp.Left(tPos); // GET THE VERTEX NUMBER temp.SetAt(tPos,' '); // CHANGE THE '/' TO A SPACE SO I CAN TRY AGAIN nPos = temp.Find('/'); // FIND THE '/' SEPARATING TEXTURE AND NORMAL tStr = temp.Mid(tPos + 1, nPos - tPos - 1); // GET THE TEXTURE NUMBER nStr = temp.Right(temp.GetLength() - nPos - 1); // GET THE NORMAL NUMBER face->v[loop - 1] = atoi(vStr); // STORE OFF THE INDEX FOR THE VERTEX face->t[loop - 1] = atoi(tStr); // STORE OFF THE INDEX FOR THE TEXTURE face->n[loop - 1] = atoi(nStr); // STORE OFF THE INDEX FOR THE NORMAL } face->flags = 0; if (tStr.GetLength() > 0) face->flags |= FACE_TYPE_TEXTURE; if (nStr.GetLength() > 0) face->flags |= FACE_TYPE_NORMAL; if (loopcnt == 4) face->flags |= FACE_TYPE_TRI; else if (loopcnt == 5) face->flags |= FACE_TYPE_QUAD; else { ::MessageBox(NULL,"Face found larger then a Quad\nSubstituting a Tri","ERROR",MB_OK); face->flags |= FACE_TYPE_TRI; } } ///// HandleFace ////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////////////////// // Procedure: LoadOBJ // Purpose: Load an OBJ file into the current bone visual // Arguments: Name of 0BJ file and pointer to bone, flags of what to load // Notes: Not an Official OBJ loader as it doesn't handle more then // 3 vertex polygons or multiple objects per file. // Current flags are only (NULL, LOADOBJ_VERTEXONLY,LOADOBJ_REUSEVERTICES) /////////////////////////////////////////////////////////////////////////////// BOOL LoadOBJ(char *filename,t_Visual *visual, int flags) { /// Local Variables /////////////////////////////////////////////////////////// int loop,loop2,cnt; char buffer[MAX_STRINGLENGTH]; CStringArray words; CString temp; FILE *fp; long vCnt = 0, nCnt = 0, tCnt = 0, fCnt = 0; long vPos = 0, nPos = 0, tPos = 0, fPos = 0; tVector *vertex = NULL,*normal = NULL,*texture = NULL; t_faceIndex *face = NULL; float *data; unsigned short *indexData; /////////////////////////////////////////////////////////////////////////////// fp = fopen(filename,"r"); if (fp != NULL) { // FIRST PASS SETS UP THE NUMBER OF OBJECTS IN THE FILE while (!feof(fp)) { fgets(buffer,MAX_STRINGLENGTH,fp); // GET A STRING FROM THE FILE ParseString(buffer,&words,&cnt); // BREAK THE STRING INTO cnt WORDS if (cnt > 0) // MAKE SURE SOME WORDS ARE THERE { temp = words.GetAt(0); // CHECK THE FIRST WORK if (temp.GetLength() > 0) { if (temp[0] == 'v') // ONLY LOOK AT WORDS THAT START WITH v { if (temp.GetLength() > 1 && temp[1] == 'n') // vn IS A NORMAL nCnt++; else if (temp.GetLength() > 1 && temp[1] == 't') // vt IS A TEXTURE tCnt++; else vCnt++; // v IS A VERTEX } else if (temp[0] == 'f') fCnt++; // f IS A FACE } } words.RemoveAll(); // CLEAR WORD BUFFER } // NOW THAT I KNOW HOW MANY, ALLOCATE ROOM FOR IT if (vCnt > 0) { vertex = (tVector *)malloc(vCnt * sizeof(tVector)); if (nCnt > 0) normal = (tVector *)malloc(nCnt * sizeof(tVector)); if (tCnt > 0) texture = (tVector *)malloc(tCnt * sizeof(tVector)); if (fCnt > 0) face = (t_faceIndex *)malloc(fCnt * sizeof(t_faceIndex)); fseek(fp,0,SEEK_SET); // NOW THAT IT IS ALL ALLOC'ED. GRAB THE REAL DATA while (!feof(fp)) { fgets(buffer,MAX_STRINGLENGTH,fp); ParseString(buffer,&words,&cnt); if (cnt > 0) { temp = words.GetAt(0); if (temp.GetLength() > 0) { if (temp[0] == 'v') // WORDS STARTING WITH v { if (temp.GetLength() > 1 && temp[1] == 'n') // vn NORMALS { normal[nPos].x = (float)atof(words.GetAt(1)); normal[nPos].y = (float)atof(words.GetAt(2)); normal[nPos].z = (float)atof(words.GetAt(3)); nPos++; } else if (temp.GetLength() > 1 && temp[1] == 't') // vt TEXTURES { texture[tPos].u = (float)atof(words.GetAt(1)); texture[tPos].v = (float)atof(words.GetAt(2)); tPos++; } else // VERTICES { vertex[vPos].x = (float)atof(words.GetAt(1)); vertex[vPos].y = (float)atof(words.GetAt(2)); vertex[vPos].z = (float)atof(words.GetAt(3)); vPos++; } } else if (temp[0] == 'f') // f v/t/n v/t/n v/t/n FACE LINE { if (words.GetSize() > 5) { sprintf(buffer,"Face %d has more than 4 vertices",fPos); MessageBox(NULL,buffer,"ERROR",MB_OK); } HandleFace(&words,&face[fPos]); fPos++; } else if (temp == "mtllib") // HANDLE THE MATERIAL LIBRARY { LoadMaterialLib(words.GetAt(1),visual); } } } words.RemoveAll(); // CLEAR WORD BUFFER } // THIS IS BAD. THINGS RUN NICER IF ALL THE POLYGONS HAVE THE SAME VERTEX COUNTS // ASSUME ALL HAVE THE SAME AS THE FIRST. IT SHOULD TESSELATE QUADS TO TRIS IF // THERE ARE SOME TRIS, BUT I KNOW MY DATABASE SO I MAKE MY LIFE EASIER if ((face[0].flags & FACE_TYPE_TRI)> 0) visual->vPerFace = 3; else visual->vPerFace = 4; if (nCnt > 0 && (flags & LOADOBJ_VERTEXONLY) == 0) { if (tCnt > 0) { visual->dataFormat = GL_T2F_N3F_V3F; visual->vSize = 8; // 2 texture, 3 normal, 3 vertex } else { visual->dataFormat = GL_N3F_V3F; visual->vSize = 6; // 3 floats for normal, 3 for vertex } } else { visual->dataFormat = GL_V3F; visual->vSize = 3; // 3 floats for vertex } visual->faceCnt = fPos; if ((flags & LOADOBJ_REUSEVERTICES) > 0) { visual->reuseVertices = TRUE; visual->vertexData = (float *)malloc(sizeof(float) * visual->vSize * vPos); visual->vertexCnt = vPos; visual->faceIndex = (unsigned short *)malloc(sizeof(unsigned short) * fPos * visual->vPerFace); if ((flags & LOADOBJ_VERTEXONLY) > 0) // COPY VERTEX DATA { memcpy(visual->vertexData,vertex,sizeof(float) * visual->vSize * vPos); } else // SHOULD HANDLE CASE WHERE THERE IS NORMALS AND TEXTURE COORDS { visual->vertexData = NULL; // TODO: I DON'T WANT TO DEAL WITH IT } } else { visual->reuseVertices = FALSE; visual->vertexData = (float *)malloc(sizeof(float) * visual->vSize * fPos * visual->vPerFace); visual->vertexCnt = fPos * visual->vPerFace; visual->faceIndex = NULL; } data = visual->vertexData; indexData = visual->faceIndex; for (loop = 0; loop < fPos; loop++) { // ERROR CHECKING TO MAKE SURE if ((face[loop].flags & FACE_TYPE_TRI)> 0 && visual->vPerFace == 4) ::MessageBox(NULL,"Face Vertex Count does not match","ERROR",MB_OK); if ((face[loop].flags & FACE_TYPE_QUAD)> 0 && visual->vPerFace == 3) ::MessageBox(NULL,"Face Vertex Count does not match","ERROR",MB_OK); for (loop2 = 0; loop2 < visual->vPerFace; loop2++) { // IF I DON'T WANT TO REUSE VERTICES, FILL IT ALL OUT if ((flags & LOADOBJ_REUSEVERTICES) == 0) { // ALL FACE INDICES ARE 1 BASED INSTEAD OF 0 if (tCnt > 0) // IF TEXTURE COORDS WRITE OUT THOSE { *data++ = texture[face[loop].t[loop2] - 1].u; *data++ = texture[face[loop].t[loop2] - 1].v; } if (nCnt > 0) // IF THERE ARE NORMALS WRITE THOSE OUT { *data++ = normal[face[loop].n[loop2] - 1].x; *data++ = normal[face[loop].n[loop2] - 1].y; *data++ = normal[face[loop].n[loop2] - 1].z; } *data++ = vertex[face[loop].v[loop2] - 1].x; // SAVE OUT VERTICES *data++ = vertex[face[loop].v[loop2] - 1].y; *data++ = vertex[face[loop].v[loop2] - 1].z; } else // REUSE VERTICES SO JUST FILL OUT THE INDEX STRUCTURE { *indexData++ = face[loop].v[loop2] - 1; } } } if (vertex) free(vertex); if (normal) free(normal); if (texture) free(texture); if (face) free(face); } fclose(fp); } else return FALSE; return TRUE; }