From 2a514ab38aa53746a5b668865a362973903faf5a Mon Sep 17 00:00:00 2001 From: jpaone Date: Fri, 25 Aug 2023 14:22:02 -0600 Subject: [PATCH] Issue #7 - improving web documentation --- ModelLoader.hpp | 139 +- docs/_model_loader_8hpp_source.html | 3710 +++++++++---------- docs/class_c_s_c_i441_1_1_model_loader.html | 80 +- 3 files changed, 1968 insertions(+), 1961 deletions(-) diff --git a/ModelLoader.hpp b/ModelLoader.hpp index e66ee4c9..32ea09e1 100755 --- a/ModelLoader.hpp +++ b/ModelLoader.hpp @@ -37,106 +37,107 @@ namespace CSCI441 { - /** @class ModelLoader + /** + * @class ModelLoader * @brief Loads object models from file and renders using VBOs/VAOs */ class ModelLoader final { public: - /** @brief Creates an empty model - */ + /** + * @brief Creates an empty model + */ ModelLoader(); - /** @brief Loads a model from the given file - * @param const char* filename - file to load model from - */ - explicit ModelLoader( const char* filename ); - /** @brief Frees memory associated with model on both CPU and GPU - */ + /** + * @brief Loads a model from the given file + * @param filename file to load model from + */ + [[maybe_unused]] explicit ModelLoader( const char* filename ); + /** + * @brief Frees memory associated with model on both CPU and GPU + */ ~ModelLoader(); - /** @brief Loads a model from the given file - * @param const char* filename - file to load model from - * @param bool INFO - flag to control if informational messages should be displayed - * @param bool ERRORS - flag to control if error messages should be displayed - * @return true if load succeeded, false otherwise - */ + /** + * @brief Loads a model from the given file + * @param filename file to load model from + * @param INFO flag to control if informational messages should be displayed + * @param ERRORS flag to control if error messages should be displayed + * @return true if load succeeded, false otherwise + */ bool loadModelFile( const char* filename, bool INFO = true, bool ERRORS = true ); /** * @brief Enables VBO attribute array locations - * @param GLint positionLocation - attribute location of vertex position - * @param GLint normalLocation - attribute location of vertex normal - * @param GLint texCoordLocation - attribute location of vertex texture coordinate + * @param positionLocation attribute location of vertex position + * @param normalLocation attribute location of vertex normal + * @param texCoordLocation attribute location of vertex texture coordinate */ - void setAttributeLocations(GLint positionLocation, GLint normalLocation = -1, GLint texCoordLocation = -1) const; - - /** @brief Renders a model - * @param GLint shaderProgramHandle - shader program handle that - * @param GLint matDiffLocation - uniform location of material diffuse component - * @param GLint matSpecLocation - uniform location of material specular component - * @param GLint matShinLocation - uniform location of material shininess component - * @param GLint matAmbLocation - uniform location of material ambient component - * @param GLenum diffuseTexture - texture number to bind diffuse texture map to - * @return true if draw succeeded, false otherwise - */ - bool draw( GLuint shaderProgramHandle, + [[maybe_unused]] void setAttributeLocations(GLint positionLocation, GLint normalLocation = -1, GLint texCoordLocation = -1) const; + + /** + * @brief Renders a model + * @param shaderProgramHandle shader program handle that + * @param matDiffLocation uniform location of material diffuse component + * @param matSpecLocation uniform location of material specular component + * @param matShinLocation uniform location of material shininess component + * @param matAmbLocation uniform location of material ambient component + * @param diffuseTexture texture number to bind diffuse texture map to + * @return true if draw succeeded, false otherwise + */ + [[maybe_unused]] [[nodiscard]] bool draw( GLuint shaderProgramHandle, GLint matDiffLocation = -1, GLint matSpecLocation = -1, GLint matShinLocation = -1, GLint matAmbLocation = -1, GLenum diffuseTexture = GL_TEXTURE0 ) const; /** - * @brief Return the number of vertices the model is made up of. This value corresponds - * to the size of the Vertices, TexCoords, and Normals arrays. - * @return GLuint numVertices - the number of vertices within the model + * @brief Return the number of vertices the model is made up of. This value corresponds to the size of the Vertices, TexCoords, and Normals arrays. + * @return the number of vertices within the model */ - GLuint getNumberOfVertices() const; + [[maybe_unused]] [[nodiscard]] GLuint getNumberOfVertices() const; /** * @brief Return the vertex array that makes up the model mesh. - * For use with VBOs - * @return GLfloat* vertices - pointer to vertex array + * @return pointer to vertex array + * @note For use with VBOs */ - GLfloat* getVertices() const; + [[maybe_unused]] [[nodiscard]] GLfloat* getVertices() const; /** * @brief Return the texture coordinates array that corresponds to the model mesh. - * For use with VBOs - * @return GLfloat* texCoords - pointer to texture coordinate array + * @return pointer to texture coordinate array + * @note For use with VBOs */ - GLfloat* getTexCoords() const; + [[maybe_unused]] [[nodiscard]] GLfloat* getTexCoords() const; /** * @brief Return the normal array that corresponds to the model mesh. - * For use with VBOs - * @return GLfloat* normals - pointer to the normal array + * @return pointer to the normal array + * @note For use with VBOs */ - GLfloat* getNormals() const; + [[maybe_unused]] [[nodiscard]] GLfloat* getNormals() const; /** - * @brief Return the number of indices to draw the model. This value corresponds - * to the size of the Indices array. - * @return GLuint numIndices - the number of indices when drawing the model + * @brief Return the number of indices to draw the model. This value corresponds to the size of the Indices array. + * @return the number of indices when drawing the model */ - GLuint getNumberOfIndices() const; + [[maybe_unused]] [[nodiscard]] GLuint getNumberOfIndices() const; /** * @brief Return the index array that dictates the order to draw the model mesh. - * For use with IBOs - * @return GLuint* indices - pointer to the index array + * @return pointer to the index array + * @note For use with IBOs */ - GLuint* getIndices() const; - - /** @brief Enable autogeneration of vertex normals - * - * If an object model does not contain vertex normal data, then normals will - * be computed based on the cross product of vertex winding order. - * - * @note Must be called prior to loading in a model from file - * @note No normals are generated by default - */ - static void enableAutoGenerateNormals(); - /** @brief Disable autogeneration of vertex normals - * - * If an object model does not contain vertex normal data, then normals will - * be computed based on the cross product of vertex winding order. - * - * @note Must be called prior to loading in a model from file - * @note No normals are generated by default - */ - static void disableAutoGenerateNormals(); + [[maybe_unused]] [[nodiscard]] GLuint* getIndices() const; + + /** + * @brief Enable auto-generation of vertex normals + * @warning Must be called prior to loading in a model from file + * @note If an object model does not contain vertex normal data, then normals will be computed based on the cross product of vertex winding order. + * @note No normals are generated by default + * @note To disable, call disableAutoGenerateNormals + */ + [[maybe_unused]] static void enableAutoGenerateNormals(); + /** + * @brief Disable auto-generation of vertex normals + * @warning Must be called prior to loading in a model from file + * @note No normals are generated by default + * @note To enable, call enableAutoGenerateNormals + */ + [[maybe_unused]] static void disableAutoGenerateNormals(); private: void _init(); diff --git a/docs/_model_loader_8hpp_source.html b/docs/_model_loader_8hpp_source.html index 205faf9e..0c6301d3 100644 --- a/docs/_model_loader_8hpp_source.html +++ b/docs/_model_loader_8hpp_source.html @@ -96,1861 +96,1861 @@
37
38namespace CSCI441 {
39
-
43 class ModelLoader final {
-
44 public:
-
47 ModelLoader();
-
51 explicit ModelLoader( const char* filename );
-
54 ~ModelLoader();
-
55
-
62 bool loadModelFile( const char* filename, bool INFO = true, bool ERRORS = true );
-
63
-
70 void setAttributeLocations(GLint positionLocation, GLint normalLocation = -1, GLint texCoordLocation = -1) const;
-
71
-
81 bool draw( GLuint shaderProgramHandle,
-
82 GLint matDiffLocation = -1, GLint matSpecLocation = -1, GLint matShinLocation = -1, GLint matAmbLocation = -1,
-
83 GLenum diffuseTexture = GL_TEXTURE0 ) const;
-
84
-
90 GLuint getNumberOfVertices() const;
-
96 GLfloat* getVertices() const;
-
102 GLfloat* getTexCoords() const;
-
108 GLfloat* getNormals() const;
-
114 GLuint getNumberOfIndices() const;
-
120 GLuint* getIndices() const;
-
121
-
130 static void enableAutoGenerateNormals();
-
139 static void disableAutoGenerateNormals();
-
140
-
141 private:
-
142 void _init();
-
143 bool _loadMTLFile( const char *mtlFilename, bool INFO, bool ERRORS );
-
144 bool _loadOBJFile( bool INFO, bool ERRORS );
-
145 bool _loadOFFFile( bool INFO, bool ERRORS );
-
146 bool _loadPLYFile( bool INFO, bool ERRORS );
-
147 bool _loadSTLFile( bool INFO, bool ERRORS );
-
148 std::vector<std::string> _tokenizeString( std::string input, std::string delimiters );
-
149
-
150 char* _filename;
-
151 CSCI441_INTERNAL::MODEL_TYPE _modelType;
-
152
-
153 GLuint _vaod;
-
154 GLuint _vbods[2];
-
155
-
156 GLfloat* _vertices;
-
157 GLfloat* _texCoords;
-
158 GLfloat* _normals;
-
159 GLuint* _indices;
-
160 GLuint _uniqueIndex;
-
161 GLuint _numIndices;
-
162
-
163 std::map< std::string, CSCI441_INTERNAL::ModelMaterial* > _materials;
-
164 std::map< std::string, std::vector< std::pair< GLuint, GLuint > > > _materialIndexStartStop;
-
165
-
166 bool _hasVertexTexCoords;
-
167 bool _hasVertexNormals;
-
168
-
169 static bool _AUTO_GEN_NORMALS;
-
170 };
-
171}
-
172
-
175
-
176namespace CSCI441_INTERNAL {
-
177 unsigned char* createTransparentTexture( unsigned char *imageData, unsigned char *imageMask, int texWidth, int texHeight, int texChannels, int maskChannels );
-
178 void flipImageY( int texWidth, int texHeight, int textureChannels, unsigned char *textureData );
-
179}
-
180
-
181inline bool CSCI441::ModelLoader::_AUTO_GEN_NORMALS = false;
-
182
-
183inline CSCI441::ModelLoader::ModelLoader() {
-
184 _init();
-
185}
-
186
-
187inline CSCI441::ModelLoader::ModelLoader( const char* filename ) {
-
188 _init();
-
189 loadModelFile( filename );
-
190}
-
191
-
192inline CSCI441::ModelLoader::~ModelLoader() {
-
193 if( _vertices ) free( _vertices );
-
194 if( _texCoords ) free( _texCoords );
-
195 if( _normals ) free( _normals );
-
196 if( _indices ) free( _indices );
-
197
-
198 glDeleteBuffers( 2, _vbods );
-
199 glDeleteVertexArrays( 1, &_vaod );
-
200}
-
201
-
202inline void CSCI441::ModelLoader::_init() {
-
203 _hasVertexTexCoords = false;
-
204 _hasVertexNormals = false;
-
205
-
206 _vertices = NULL;
-
207 _texCoords = NULL;
-
208 _normals = NULL;
-
209 _indices = NULL;
-
210
-
211 glGenVertexArrays( 1, &_vaod );
-
212 glGenBuffers( 2, _vbods );
-
213}
-
214
-
215inline bool CSCI441::ModelLoader::loadModelFile( const char* filename, bool INFO, bool ERRORS ) {
-
216 bool result = true;
-
217 _filename = (char*)malloc(sizeof(char)*strlen(filename));
-
218 strcpy( _filename, filename );
-
219 if( strstr( _filename, ".obj" ) != NULL ) {
-
220 result = _loadOBJFile( INFO, ERRORS );
-
221 _modelType = CSCI441_INTERNAL::OBJ;
-
222 }
-
223 else if( strstr( _filename, ".off" ) != NULL ) {
-
224 result = _loadOFFFile( INFO, ERRORS );
-
225 _modelType = CSCI441_INTERNAL::OFF;
-
226 }
-
227 else if( strstr( _filename, ".ply" ) != NULL ) {
-
228 result = _loadPLYFile( INFO, ERRORS );
-
229 _modelType = CSCI441_INTERNAL::PLY;
-
230 }
-
231 else if( strstr( _filename, ".stl" ) != NULL ) {
-
232 result = _loadSTLFile( INFO, ERRORS );
-
233 _modelType = CSCI441_INTERNAL::STL;
-
234 }
-
235 else {
-
236 result = false;
-
237 if (ERRORS) fprintf( stderr, "[ERROR]: Unsupported file format for file: %s\n", _filename );
-
238 }
-
239
-
240 return result;
-
241}
-
242
-
243inline void CSCI441::ModelLoader::setAttributeLocations(GLint positionLocation, GLint normalLocation, GLint texCoordLocation) const {
-
244 glBindVertexArray( _vaod );
-
245 glBindBuffer( GL_ARRAY_BUFFER, _vbods[0] );
-
246
-
247 glEnableVertexAttribArray( positionLocation );
-
248 glVertexAttribPointer( positionLocation, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 );
-
249
-
250 glEnableVertexAttribArray( normalLocation );
-
251 glVertexAttribPointer( normalLocation, 3, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(GLfloat) * _uniqueIndex * 3) );
-
252
-
253 glEnableVertexAttribArray( texCoordLocation );
-
254 glVertexAttribPointer( texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(GLfloat) * _uniqueIndex * 6) );
-
255}
-
256
-
257inline bool CSCI441::ModelLoader::draw( GLuint shaderProgramHandle,
-
258 GLint matDiffLocation, GLint matSpecLocation, GLint matShinLocation, GLint matAmbLocation,
-
259 GLenum diffuseTexture ) const {
-
260 glBindVertexArray( _vaod );
-
261
-
262 bool result = true;
-
263 if( _modelType == CSCI441_INTERNAL::OBJ ) {
-
264 for( auto materialIter = _materialIndexStartStop.begin();
-
265 materialIter != _materialIndexStartStop.end();
-
266 materialIter++ ) {
-
267
-
268 std::string materialName = materialIter->first;
-
269 std::vector< std::pair< GLuint, GLuint > > indexStartStop = materialIter->second;
-
270
-
271 CSCI441_INTERNAL::ModelMaterial* material = nullptr;
-
272 if( _materials.find( materialName ) != _materials.end() )
-
273 material = _materials.find( materialName )->second;
-
274
-
275 for( std::vector< std::pair< GLuint, GLuint > >::iterator idxIter = indexStartStop.begin();
-
276 idxIter != indexStartStop.end();
-
277 idxIter++ ) {
-
278
-
279 GLuint start = idxIter->first;
-
280 GLuint end = idxIter->second;
-
281 GLuint length = end - start + 1;
-
282
-
283// printf( "rendering material %s (%u, %u) = %u\n", materialName.c_str(), start, end, length );
-
284
-
285 if( material != nullptr ) {
-
286 glProgramUniform4fv( shaderProgramHandle, matAmbLocation, 1, material->ambient );
-
287 glProgramUniform4fv( shaderProgramHandle, matDiffLocation, 1, material->diffuse );
-
288 glProgramUniform4fv( shaderProgramHandle, matSpecLocation, 1, material->specular );
-
289 glProgramUniform1f( shaderProgramHandle, matShinLocation, material->shininess );
-
290
-
291 if( material->map_Kd != -1 ) {
-
292 glActiveTexture( diffuseTexture );
-
293 glBindTexture( GL_TEXTURE_2D, material->map_Kd );
-
294 }
-
295 }
-
296
-
297 glDrawElements( GL_TRIANGLES, length, GL_UNSIGNED_INT, (void*)(sizeof(GLuint)*start) );
-
298 }
-
299 }
-
300 } else {
-
301 glDrawElements( GL_TRIANGLES, _numIndices, GL_UNSIGNED_INT, (void*)0 );
-
302 }
-
303
-
304 return result;
-
305}
-
306
-
307inline GLuint CSCI441::ModelLoader::getNumberOfVertices() const { return _uniqueIndex; }
-
308inline GLfloat* CSCI441::ModelLoader::getVertices() const { return _vertices; }
-
309inline GLfloat* CSCI441::ModelLoader::getTexCoords() const { return _texCoords; }
-
310inline GLfloat* CSCI441::ModelLoader::getNormals() const { return _normals; }
-
311inline GLuint CSCI441::ModelLoader::getNumberOfIndices() const { return _numIndices; }
-
312inline GLuint* CSCI441::ModelLoader::getIndices() const { return _indices; }
-
313
-
314// Read in a WaveFront *.obj File
-
315inline bool CSCI441::ModelLoader::_loadOBJFile( bool INFO, bool ERRORS ) {
-
316 bool result = true;
-
317
-
318 if (INFO ) printf( "[.obj]: -=-=-=-=-=-=-=- BEGIN %s Info -=-=-=-=-=-=-=- \n", _filename );
-
319
-
320 time_t start, end;
-
321 time(&start);
-
322
-
323 std::ifstream in( _filename );
-
324 if( !in.is_open() ) {
-
325 if (ERRORS) fprintf( stderr, "[.obj]: [ERROR]: Could not open \"%s\"\n", _filename );
-
326 if ( INFO ) printf( "[.obj]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=- \n", _filename );
-
327 return false;
-
328 }
-
329
-
330 GLuint numObjects = 0, numGroups = 0;
-
331 GLuint numVertices = 0, numTexCoords = 0, numNormals = 0;
-
332 GLuint numFaces = 0, numTriangles = 0;
-
333 GLfloat minX = 999999.0f, maxX = -999999.0f, minY = 999999.0f, maxY = -999999.0f, minZ = 999999.0f, maxZ = -999999.0f;
-
334 std::string line;
-
335
-
336 std::map<std::string, GLuint> uniqueCounts;
-
337 _uniqueIndex = 0;
-
338
-
339 int progressCounter = 0;
-
340
-
341 while( getline( in, line ) ) {
-
342 if( line.length() > 1 && line.at(0) == '\t' )
-
343 line = line.substr( 1 );
-
344 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
-
345
-
346 std::vector< std::string > tokens = _tokenizeString( line, " \t" );
-
347 if( tokens.size() < 1 ) continue;
-
348
-
349 //the line should have a single character that lets us know if it's a...
-
350 if( !tokens[0].compare( "#" ) || tokens[0].find_first_of("#") == 0 ) { // comment ignore
-
351 } else if( !tokens[0].compare( "o" ) ) { // object name ignore
-
352 numObjects++;
-
353 } else if( !tokens[0].compare( "g" ) ) { // polygon group name ignore
-
354 numGroups++;
-
355 } else if( !tokens[0].compare( "mtllib" ) ) { // material library
-
356 _loadMTLFile( tokens[1].c_str(), INFO, ERRORS );
-
357 } else if( !tokens[0].compare( "v" ) ) { //vertex
-
358 numVertices++;
-
359
-
360 GLfloat x = (GLfloat) atof( tokens[1].c_str() ),
-
361 y = (GLfloat) atof( tokens[2].c_str() ),
-
362 z = (GLfloat) atof( tokens[3].c_str() );
-
363
-
364 if( x < minX ) minX = x;
-
365 if( x > maxX ) maxX = x;
-
366 if( y < minY ) minY = y;
-
367 if( y > maxY ) maxY = y;
-
368 if( z < minZ ) minZ = z;
-
369 if( z > maxZ ) maxZ = z;
-
370 } else if( !tokens.at(0).compare( "vn" ) ) { //vertex normal
-
371 numNormals++;
-
372 } else if( !tokens.at(0).compare( "vt" ) ) { //vertex tex coord
-
373 numTexCoords++;
-
374 } else if( !tokens.at(0).compare( "f" ) ) { //face!
-
375
-
376 //now, faces can be either quads or triangles (or maybe more?)
-
377 //split the string on spaces to get the number of verts+attrs.
-
378 std::vector<std::string> faceTokens = _tokenizeString(line, " ");
-
379
-
380 for(GLuint i = 1; i < faceTokens.size(); i++) {
-
381 //need to use both the tokens and number of slashes to determine what info is there.
-
382 std::vector<std::string> groupTokens = _tokenizeString(faceTokens[i], "/");
-
383 int numSlashes = 0;
-
384 for( GLuint j = 0; j < faceTokens[i].length(); j++ ) {
-
385 if(faceTokens[i][j] == '/') numSlashes++;
-
386 }
-
387
-
388 std::stringstream currentFaceTokenStream;
-
389 int v = atoi(groupTokens[0].c_str());
-
390 if(v < 0)
-
391 v = numVertices + v + 1;
-
392 currentFaceTokenStream << v;
-
393
-
394 //based on combination of number of tokens and slashes, we can determine what we have.
-
395 if(groupTokens.size() == 2 && numSlashes == 1) {
-
396 _hasVertexTexCoords = true;
-
397
-
398 int vt = atoi(groupTokens[1].c_str());
-
399 if(vt < 0)
-
400 vt = numTexCoords + vt + 1;
-
401 currentFaceTokenStream << "/" << vt;
-
402 } else if(groupTokens.size() == 2 && numSlashes == 2) {
-
403 _hasVertexNormals = true;
-
404
-
405 int vn = atoi(groupTokens[1].c_str());
-
406 if(vn < 0)
-
407 vn = numNormals + vn + 1;
-
408 currentFaceTokenStream << "//" << vn;
-
409 } else if(groupTokens.size() == 3) {
-
410 _hasVertexTexCoords = true;
-
411 _hasVertexNormals = true;
-
412
-
413 int vt = atoi(groupTokens[1].c_str());
-
414 if(vt < 0)
-
415 vt = numTexCoords + vt + 1;
-
416 int vn = atoi(groupTokens[2].c_str());
-
417 if(vn < 0)
-
418 vn = numNormals + vn + 1;
-
419 currentFaceTokenStream << "/" << vt << "/" << vn;
-
420 } else if(groupTokens.size() != 1) {
-
421 if (ERRORS) fprintf(stderr, "[.obj]: [ERROR]: Malformed OBJ file, %s.\n", _filename);
-
422 return false;
-
423 }
-
424
-
425 std::string processedFaceToken = currentFaceTokenStream.str();
-
426 if( uniqueCounts.find( processedFaceToken ) == uniqueCounts.end() ) {
-
427 uniqueCounts.insert( std::pair<std::string,long int>(processedFaceToken,_uniqueIndex) );
-
428 _uniqueIndex++;
-
429 }
-
430 }
-
431
-
432 numTriangles += (faceTokens.size() - 1 - 3 + 1);
-
433
-
434 numFaces++;
-
435 } else {
-
436
-
437 }
-
438
-
439 if (INFO) {
-
440 progressCounter++;
-
441 if( progressCounter % 5000 == 0 ) {
-
442 printf("\33[2K\r");
-
443 switch( progressCounter ) {
-
444 case 5000: printf("[.obj]: scanning %s...\\", _filename); break;
-
445 case 10000: printf("[.obj]: scanning %s...|", _filename); break;
-
446 case 15000: printf("[.obj]: scanning %s.../", _filename); break;
-
447 case 20000: printf("[.obj]: scanning %s...-", _filename); break;
-
448 }
-
449 fflush(stdout);
-
450 }
-
451 if( progressCounter == 20000 )
-
452 progressCounter = 0;
-
453 }
-
454 }
-
455 in.close();
-
456
-
457 if (INFO) {
-
458 printf( "\33[2K\r" );
-
459 printf( "[.obj]: scanning %s...done!\n", _filename );
-
460 printf( "[.obj]: ------------\n" );
-
461 printf( "[.obj]: Model Stats:\n" );
-
462 printf( "[.obj]: Vertices: \t%u\tNormals: \t%u\tTex Coords:\t%u\n", numVertices, numNormals, numTexCoords );
-
463 printf( "[.obj]: Unique Verts:\t%u\n", _uniqueIndex );
-
464 printf( "[.obj]: Faces: \t%u\tTriangles:\t%u\n", numFaces, numTriangles );
-
465 printf( "[.obj]: Objects: \t%u\tGroups: \t%u\n", numObjects, numGroups );
-
466 printf( "[.obj]: Dimensions:\t(%f, %f, %f)\n", (maxX - minX), (maxY - minY), (maxZ - minZ) );
-
467 }
-
468
-
469 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
-
470 if (INFO && !_hasVertexNormals)
-
471 printf( "[.obj]: [WARN]: No vertex normals exist on model. To autogenerate vertex\n\tnormals, call CSCI441::ModelLoader::enableAutoGenerateNormals()\n\tprior to loading the model file.\n" );
-
472 _vertices = (GLfloat*)malloc(sizeof(GLfloat) * _uniqueIndex * 3);
-
473 _texCoords = (GLfloat*)malloc(sizeof(GLfloat) * _uniqueIndex * 2);
-
474 _normals = (GLfloat*)malloc(sizeof(GLfloat) * _uniqueIndex * 3);
-
475 _indices = (GLuint*)malloc(sizeof(GLuint) * numTriangles * 3);
-
476 } else {
-
477 if (INFO) printf( "[.obj]: No vertex normals exist on model, vertex normals will be autogenerated\n" );
-
478 _vertices = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 3);
-
479 _texCoords = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 2);
-
480 _normals = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 3);
-
481 _indices = (GLuint*)malloc(sizeof(GLuint) * numTriangles * 3);
-
482 }
-
483
-
484 GLfloat* v = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 3);
-
485 GLfloat* vt = (GLfloat*)malloc(sizeof(GLfloat) * numTexCoords * 2);
-
486 GLfloat* vn = (GLfloat*)malloc(sizeof(GLfloat) * numNormals * 3);
-
487
-
488 std::vector<GLfloat> vertsTemp;
-
489 std::vector<GLfloat> texCoordsTemp;
-
490
-
491 printf( "[.obj]: ------------\n" );
-
492
-
493 uniqueCounts.clear();
-
494 _uniqueIndex = 0;
-
495 _numIndices = 0;
-
496
-
497 in.open( _filename );
-
498
-
499 GLuint vSeen = 0, vtSeen = 0, vnSeen = 0, indicesSeen = 0;
-
500 GLuint uniqueV = 0;
-
501
-
502 std::string currentMaterial = "default";
-
503 _materialIndexStartStop.insert( std::pair< std::string, std::vector< std::pair< GLuint, GLuint > > >( currentMaterial, std::vector< std::pair< GLuint, GLuint > >(1) ) );
-
504 _materialIndexStartStop.find( currentMaterial )->second.back().first = indicesSeen;
-
505
-
506 while( getline( in, line ) ) {
-
507 if( line.length() > 1 && line.at(0) == '\t' )
-
508 line = line.substr( 1 );
-
509 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
-
510
-
511 std::vector< std::string > tokens = _tokenizeString( line, " \t" );
-
512 if( tokens.size() < 1 ) continue;
-
513
-
514 //the line should have a single character that lets us know if it's a...
-
515 if( !tokens[0].compare( "#" ) || tokens[0].find_first_of("#") == 0 ) { // comment ignore
-
516 } else if( !tokens[0].compare( "o" ) ) { // object name ignore
-
517
-
518 } else if( !tokens[0].compare( "g" ) ) { // polygon group name ignore
-
519
-
520 } else if( !tokens[0].compare( "mtllib" ) ) { // material library
-
521
-
522 } else if( !tokens[0].compare( "usemtl" ) ) { // use material library
-
523 if( currentMaterial == "default" && indicesSeen == 0 ) {
-
524 _materialIndexStartStop.clear();
-
525 } else {
-
526 _materialIndexStartStop.find( currentMaterial )->second.back().second = indicesSeen - 1;
-
527 }
-
528 currentMaterial = tokens[1];
-
529 if( _materialIndexStartStop.find( currentMaterial ) == _materialIndexStartStop.end() ) {
-
530 _materialIndexStartStop.insert( std::pair< std::string, std::vector< std::pair< GLuint, GLuint > > >( currentMaterial, std::vector< std::pair< GLuint, GLuint > >(1) ) );
-
531 _materialIndexStartStop.find( currentMaterial )->second.back().first = indicesSeen;
-
532 } else {
-
533 _materialIndexStartStop.find( currentMaterial )->second.push_back( std::pair< GLuint, GLuint >( indicesSeen, -1 ) );
-
534 }
-
535 } else if( !tokens[0].compare( "s" ) ) { // smooth shading
-
536
-
537 } else if( !tokens[0].compare( "v" ) ) { //vertex
-
538 GLfloat x = (GLfloat) atof( tokens[1].c_str() ),
-
539 y = (GLfloat) atof( tokens[2].c_str() ),
-
540 z = (GLfloat) atof( tokens[3].c_str() );
-
541
-
542 v[vSeen*3 + 0] = x;
-
543 v[vSeen*3 + 1] = y;
-
544 v[vSeen*3 + 2] = z;
-
545
-
546 vSeen++;
-
547 } else if( !tokens.at(0).compare( "vn" ) ) { //vertex normal
-
548 GLfloat x = (GLfloat) atof( tokens[1].c_str() ),
-
549 y = (GLfloat) atof( tokens[2].c_str() ),
-
550 z = (GLfloat) atof( tokens[3].c_str() );
-
551
-
552 vn[vnSeen*3 + 0] = x;
-
553 vn[vnSeen*3 + 1] = y;
-
554 vn[vnSeen*3 + 2] = z;
-
555
-
556 vnSeen++;
-
557 } else if( !tokens.at(0).compare( "vt" ) ) { //vertex tex coord
-
558 GLfloat s = (GLfloat) atof( tokens[1].c_str() ),
-
559 t = (GLfloat) atof( tokens[2].c_str() );
-
560
-
561 vt[vtSeen*2 + 0] = s;
-
562 vt[vtSeen*2 + 1] = t;
-
563
-
564 vtSeen++;
-
565 } else if( !tokens.at(0).compare( "f" ) ) { //face!
-
566
-
567 //now, faces can be either quads or triangles (or maybe more?)
-
568 //split the string on spaces to get the number of verts+attrs.
-
569 std::vector<std::string> faceTokens = _tokenizeString(line, " ");
-
570 std::vector<std::string> processedFaceTokens;
-
571
-
572 for(GLuint i = 1; i < faceTokens.size(); i++) {
-
573 //need to use both the tokens and number of slashes to determine what info is there.
-
574 std::vector<std::string> groupTokens = _tokenizeString(faceTokens[i], "/");
-
575 int numSlashes = 0;
-
576 for( GLuint j = 0; j < faceTokens[i].length(); j++ ) {
-
577 if(faceTokens[i][j] == '/') numSlashes++;
-
578 }
-
579
-
580 std::stringstream currentFaceTokenStream;
-
581 int vx = atoi(groupTokens[0].c_str());
-
582 if(vx < 0)
-
583 vx = vSeen + vx + 1;
-
584 currentFaceTokenStream << vx;
-
585
-
586 //based on combination of number of tokens and slashes, we can determine what we have.
-
587 if(groupTokens.size() == 2 && numSlashes == 1) {
-
588 _hasVertexTexCoords = true;
-
589
-
590 int vtx = atoi(groupTokens[1].c_str());
-
591 if(vtx < 0)
-
592 vtx = vtSeen + vtx + 1;
-
593 currentFaceTokenStream << "/" << vtx;
-
594 } else if(groupTokens.size() == 2 && numSlashes == 2) {
-
595 _hasVertexNormals = true;
-
596
-
597 int vnx = atoi(groupTokens[1].c_str());
-
598 if(vnx < 0)
-
599 vnx = vnSeen + vnx + 1;
-
600 currentFaceTokenStream << "//" << vnx;
-
601 } else if(groupTokens.size() == 3) {
-
602 _hasVertexTexCoords = true;
-
603 _hasVertexNormals = true;
-
604
-
605 int vtx = atoi(groupTokens[1].c_str());
-
606 if(vtx < 0)
-
607 vtx = vtSeen + vtx + 1;
-
608 int vnx = atoi(groupTokens[2].c_str());
-
609 if(vnx < 0)
-
610 vnx = vnSeen + vnx + 1;
-
611 currentFaceTokenStream << "/" << vtx << "/" << vnx;
-
612 } else if(groupTokens.size() != 1) {
-
613 if (ERRORS) fprintf(stderr, "[.obj]: [ERROR]: Malformed OBJ file, %s.\n", _filename);
-
614 return false;
-
615 }
-
616
-
617 std::string processedFaceToken = currentFaceTokenStream.str();
-
618 processedFaceTokens.push_back(processedFaceToken);
-
619
-
620 if( uniqueCounts.find( processedFaceToken ) == uniqueCounts.end() ) {
-
621 uniqueCounts.insert( std::pair<std::string,unsigned long int>(processedFaceToken,uniqueV) );
-
622
-
623 //need to use both the tokens and number of slashes to determine what info is there.
-
624 std::vector<std::string> groupTokens = _tokenizeString(processedFaceToken, "/");
-
625 int numSlashes = 0;
-
626 for( GLuint j = 0; j < processedFaceToken.length(); j++ ) {
-
627 if(processedFaceToken[j] == '/') numSlashes++;
-
628 }
-
629
-
630 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
-
631 //regardless, we always get a vertex index.
-
632 int vI = atoi(groupTokens[0].c_str());
-
633 if( vI < 0 )
-
634 vI = vSeen + vI + 1;
-
635
-
636 _vertices[ _uniqueIndex*3 + 0 ] = v[ ((vI - 1) * 3) + 0 ];
-
637 _vertices[ _uniqueIndex*3 + 1 ] = v[ ((vI - 1) * 3) + 1 ];
-
638 _vertices[ _uniqueIndex*3 + 2 ] = v[ ((vI - 1) * 3) + 2 ];
-
639
-
640 //based on combination of number of tokens and slashes, we can determine what we have.
-
641 if(groupTokens.size() == 2 && numSlashes == 1) {
-
642 int vtI = atoi(groupTokens[1].c_str());
-
643 if( vtI < 0 )
-
644 vtI = vtSeen + vtI + 1;
-
645
-
646 _texCoords[ _uniqueIndex*2 + 0 ] = vt[ ((vtI - 1) * 2) + 0 ];
-
647 _texCoords[ _uniqueIndex*2 + 1 ] = vt[ ((vtI - 1) * 2) + 1 ];
-
648 } else if(groupTokens.size() == 2 && numSlashes == 2) {
-
649 int vnI = atoi(groupTokens[1].c_str());
-
650 if( vnI < 0 )
-
651 vnI = vnSeen + vnI + 1;
-
652
-
653 _normals[ _uniqueIndex*3 + 0 ] = vn[ ((vnI - 1) * 3) + 0 ];
-
654 _normals[ _uniqueIndex*3 + 1 ] = vn[ ((vnI - 1) * 3) + 1 ];
-
655 _normals[ _uniqueIndex*3 + 2 ] = vn[ ((vnI - 1) * 3) + 2 ];
-
656 } else if(groupTokens.size() == 3) {
-
657 int vtI = atoi(groupTokens[1].c_str());
-
658 if( vtI < 0 )
-
659 vtI = vtSeen + vtI + 1;
-
660
-
661 _texCoords[ _uniqueIndex*2 + 0 ] = vt[ ((vtI - 1) * 2) + 0 ];
-
662 _texCoords[ _uniqueIndex*2 + 1 ] = vt[ ((vtI - 1) * 2) + 1 ];
-
663
-
664 int vnI = atoi(groupTokens[2].c_str());
-
665 if( vnI < 0 )
-
666 vnI = vnSeen + vnI + 1;
-
667
-
668 _normals[ _uniqueIndex*3 + 0 ] = vn[ ((vnI - 1) * 3) + 0 ];
-
669 _normals[ _uniqueIndex*3 + 1 ] = vn[ ((vnI - 1) * 3) + 1 ];
-
670 _normals[ _uniqueIndex*3 + 2 ] = vn[ ((vnI - 1) * 3) + 2 ];
-
671 }
-
672
-
673 _uniqueIndex++;
-
674 } else {
-
675 //regardless, we always get a vertex index.
-
676 int vI = atoi(groupTokens[0].c_str());
-
677 if( vI < 0 )
-
678 vI = vSeen + vI + 1;
-
679
-
680 vertsTemp.push_back( v[ ((vI - 1) * 3) + 0 ] );
-
681 vertsTemp.push_back( v[ ((vI - 1) * 3) + 1 ] );
-
682 vertsTemp.push_back( v[ ((vI - 1) * 3) + 2 ] );
-
683
-
684 //based on combination of number of tokens and slashes, we can determine what we have.
-
685 if(groupTokens.size() == 2 && numSlashes == 1) {
-
686 int vtI = atoi(groupTokens[1].c_str());
-
687 if( vtI < 0 )
-
688 vtI = vtSeen + vtI + 1;
-
689
-
690 texCoordsTemp.push_back( vt[ ((vtI - 1) * 2) + 0 ] );
-
691 texCoordsTemp.push_back( vt[ ((vtI - 1) * 2) + 1 ] );
-
692 } else if(groupTokens.size() == 2 && numSlashes == 2) {
-
693 // should not occur if no normals
-
694 if (ERRORS) fprintf( stderr, "[.obj]: [WARN]: no vertex normals were specified, should not be trying to access values\n" );
-
695 } else if(groupTokens.size() == 3) {
-
696 int vtI = atoi(groupTokens[1].c_str());
-
697 if( vtI < 0 )
-
698 vtI = vtSeen + vtI + 1;
-
699
-
700 texCoordsTemp.push_back( vt[ ((vtI - 1) * 2) + 0 ] );
-
701 texCoordsTemp.push_back( vt[ ((vtI - 1) * 2) + 1 ] );
-
702
-
703 // should not occur if no normals
-
704 if (ERRORS) fprintf( stderr, "[.obj]: [WARN]: no vertex normals were specified, should not be trying to access values\n" );
-
705 }
-
706 }
-
707 uniqueV++;
-
708 }
-
709 }
-
710
-
711 for(GLuint i = 1; i < processedFaceTokens.size()-1; i++) {
-
712 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
-
713 _indices[ indicesSeen++ ] = uniqueCounts.find( processedFaceTokens[0] )->second;
-
714 _indices[ indicesSeen++ ] = uniqueCounts.find( processedFaceTokens[i] )->second;
-
715 _indices[ indicesSeen++ ] = uniqueCounts.find( processedFaceTokens[i+1] )->second;
-
716
-
717 _numIndices += 3;
-
718 } else {
-
719 int aI = uniqueCounts.find( processedFaceTokens[0] )->second;
-
720 int bI = uniqueCounts.find( processedFaceTokens[i] )->second;
-
721 int cI = uniqueCounts.find( processedFaceTokens[i+1] )->second;
-
722
-
723 glm::vec3 a( vertsTemp[aI*3 + 0], vertsTemp[aI*3 + 1], vertsTemp[aI*3 + 2] );
-
724 glm::vec3 b( vertsTemp[bI*3 + 0], vertsTemp[bI*3 + 1], vertsTemp[bI*3 + 2] );
-
725 glm::vec3 c( vertsTemp[cI*3 + 0], vertsTemp[cI*3 + 1], vertsTemp[cI*3 + 2] );
-
726
-
727 glm::vec3 ab = b - a; glm::vec3 ac = c - a;
-
728 glm::vec3 ba = a - b; glm::vec3 bc = c - b;
-
729 glm::vec3 ca = a - c; glm::vec3 cb = b - c;
-
730
-
731 glm::vec3 aN = glm::normalize( glm::cross( ab, ac ) );
-
732 glm::vec3 bN = glm::normalize( glm::cross( bc, ba ) );
-
733 glm::vec3 cN = glm::normalize( glm::cross( ca, cb ) );
-
734
-
735 _vertices[ _uniqueIndex*3 + 0 ] = a.x;
-
736 _vertices[ _uniqueIndex*3 + 1 ] = a.y;
-
737 _vertices[ _uniqueIndex*3 + 2 ] = a.z;
-
738
-
739 _normals[ _uniqueIndex*3 + 0 ] = aN.x;
-
740 _normals[ _uniqueIndex*3 + 1 ] = aN.y;
-
741 _normals[ _uniqueIndex*3 + 2 ] = aN.z;
-
742
-
743 if( _hasVertexTexCoords ) {
-
744 _texCoords[ _uniqueIndex*2 + 0 ] = texCoordsTemp[ aI*2 + 0 ];
-
745 _texCoords[ _uniqueIndex*2 + 1 ] = texCoordsTemp[ aI*2 + 1 ];
-
746 }
-
747
-
748 _indices[ _numIndices++ ] = _uniqueIndex++;
-
749 indicesSeen++;
-
750
-
751 _vertices[ _uniqueIndex*3 + 0 ] = b.x;
-
752 _vertices[ _uniqueIndex*3 + 1 ] = b.y;
-
753 _vertices[ _uniqueIndex*3 + 2 ] = b.z;
-
754
-
755 _normals[ _uniqueIndex*3 + 0 ] = bN.x;
-
756 _normals[ _uniqueIndex*3 + 1 ] = bN.y;
-
757 _normals[ _uniqueIndex*3 + 2 ] = bN.z;
-
758
-
759 if( _hasVertexTexCoords ) {
-
760 _texCoords[ _uniqueIndex*2 + 0 ] = texCoordsTemp[ bI*2 + 0 ];
-
761 _texCoords[ _uniqueIndex*2 + 1 ] = texCoordsTemp[ bI*2 + 1 ];
-
762 }
-
763
-
764 _indices[ _numIndices++ ] = _uniqueIndex++;
-
765 indicesSeen++;
-
766
-
767 _vertices[ _uniqueIndex*3 + 0 ] = c.x;
-
768 _vertices[ _uniqueIndex*3 + 1 ] = c.y;
-
769 _vertices[ _uniqueIndex*3 + 2 ] = c.z;
-
770
-
771 _normals[ _uniqueIndex*3 + 0 ] = cN.x;
-
772 _normals[ _uniqueIndex*3 + 1 ] = cN.y;
-
773 _normals[ _uniqueIndex*3 + 2 ] = cN.z;
-
774
-
775 if( _hasVertexTexCoords ) {
-
776 _texCoords[ _uniqueIndex*2 + 0 ] = texCoordsTemp[ cI*2 + 0 ];
-
777 _texCoords[ _uniqueIndex*2 + 1 ] = texCoordsTemp[ cI*2 + 1 ];
-
778 }
-
779
-
780 _indices[ _numIndices++ ] = _uniqueIndex++;
-
781 indicesSeen++;
-
782 }
-
783 }
-
784
-
785 } else {
-
786 if (INFO) printf( "[.obj]: ignoring line: %s\n", line.c_str() );
-
787 }
-
788
-
789 if (INFO) {
-
790 progressCounter++;
-
791 if( progressCounter % 5000 == 0 ) {
-
792 printf("\33[2K\r");
-
793 switch( progressCounter ) {
-
794 case 5000: printf("[.obj]: parsing %s...\\", _filename); break;
-
795 case 10000: printf("[.obj]: parsing %s...|", _filename); break;
-
796 case 15000: printf("[.obj]: parsing %s.../", _filename); break;
-
797 case 20000: printf("[.obj]: parsing %s...-", _filename); break;
-
798 }
-
799 fflush(stdout);
-
800 }
-
801 if( progressCounter == 20000 )
-
802 progressCounter = 0;
-
803 }
-
804 }
-
805
-
806 in.close();
-
807
-
808 if (INFO) {
-
809 printf( "\33[2K\r" );
-
810 printf( "[.obj]: parsing %s...done!\n", _filename );
-
811 }
-
812
-
813 _materialIndexStartStop.find( currentMaterial )->second.back().second = indicesSeen - 1;
-
814
-
815 glBindVertexArray( _vaod );
-
816 glBindBuffer( GL_ARRAY_BUFFER, _vbods[0] );
-
817 glBufferData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 8, NULL, GL_STATIC_DRAW );
-
818 glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * _uniqueIndex * 3, _vertices );
-
819 glBufferSubData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 3, sizeof(GLfloat) * _uniqueIndex * 3, _normals );
-
820 glBufferSubData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 6, sizeof(GLfloat) * _uniqueIndex * 2, _texCoords );
-
821
-
822 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, _vbods[1] );
-
823 glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indicesSeen, _indices, GL_STATIC_DRAW );
-
824
-
825 time(&end);
-
826 double seconds = difftime( end, start );
-
827
-
828 if (INFO) {
-
829 printf( "[.obj]: Completed in %.3fs\n", seconds );
-
830 printf( "[.obj]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=- \n\n", _filename );
-
831 }
-
832
-
833 return result;
-
834}
-
835
-
836inline bool CSCI441::ModelLoader::_loadMTLFile( const char* mtlFilename, bool INFO, bool ERRORS ) {
-
837 bool result = true;
-
838
-
839 if (INFO) printf( "[.mtl]: -*-*-*-*-*-*-*- BEGIN %s Info -*-*-*-*-*-*-*-\n", mtlFilename );
-
840
-
841 std::string line;
-
842 std::string path;
-
843 if( strstr( _filename, "/" ) != NULL ) {
-
844 path = std::string( _filename ).substr( 0, std::string(_filename).find_last_of("/")+1 );
-
845 } else {
-
846 path = "./";
-
847 }
-
848
-
849 std::ifstream in;
-
850 in.open( mtlFilename );
-
851 if( !in.is_open() ) {
-
852 std::string folderMtlFile = path + mtlFilename;
-
853 in.open( folderMtlFile.c_str() );
-
854 if( !in.is_open() ) {
-
855 if (ERRORS) fprintf( stderr, "[.mtl]: [ERROR]: could not open material file: %s\n", mtlFilename );
-
856 if ( INFO ) printf( "[.mtl]: -*-*-*-*-*-*-*- END %s Info -*-*-*-*-*-*-*-\n", mtlFilename );
-
857 return false;
-
858 }
-
859 }
-
860
-
861 CSCI441_INTERNAL::ModelMaterial* currentMaterial = NULL;
-
862 std::string materialName;
-
863
-
864 unsigned char *textureData = NULL;
-
865 unsigned char *maskData = NULL;
-
866 unsigned char *fullData;
-
867 int texWidth, texHeight, textureChannels = 1, maskChannels = 1;
-
868 GLuint textureHandle = 0;
-
869
-
870 std::map< std::string, GLuint > imageHandles;
-
871
-
872 int numMaterials = 0;
-
873
-
874 while( getline( in, line ) ) {
-
875 if( line.length() > 1 && line.at(0) == '\t' )
-
876 line = line.substr( 1 );
-
877 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
-
878
-
879 std::vector< std::string > tokens = _tokenizeString( line, " /" );
-
880 if( tokens.size() < 1 ) continue;
-
881
-
882 //the line should have a single character that lets us know if it's a...
-
883 if( !tokens[0].compare( "#" ) ) { // comment
-
884 } else if( !tokens[0].compare( "newmtl" ) ) { //new material
-
885 if (INFO) printf( "[.mtl]: Parsing material %s properties\n", tokens[1].c_str() );
-
886 currentMaterial = new CSCI441_INTERNAL::ModelMaterial();
-
887 materialName = tokens[1];
-
888 _materials.insert( std::pair<std::string, CSCI441_INTERNAL::ModelMaterial*>( materialName, currentMaterial ) );
-
889
-
890 textureHandle = 0;
-
891 textureData = NULL;
-
892 maskData = NULL;
-
893 textureChannels = 1;
-
894 maskChannels = 1;
-
895
-
896 numMaterials++;
-
897 } else if( !tokens[0].compare( "Ka" ) ) { // ambient component
-
898 currentMaterial->ambient[0] = atof( tokens[1].c_str() );
-
899 currentMaterial->ambient[1] = atof( tokens[2].c_str() );
-
900 currentMaterial->ambient[2] = atof( tokens[3].c_str() );
-
901 } else if( !tokens[0].compare( "Kd" ) ) { // diffuse component
-
902 currentMaterial->diffuse[0] = atof( tokens[1].c_str() );
-
903 currentMaterial->diffuse[1] = atof( tokens[2].c_str() );
-
904 currentMaterial->diffuse[2] = atof( tokens[3].c_str() );
-
905 } else if( !tokens[0].compare( "Ks" ) ) { // specular component
-
906 currentMaterial->specular[0] = atof( tokens[1].c_str() );
-
907 currentMaterial->specular[1] = atof( tokens[2].c_str() );
-
908 currentMaterial->specular[2] = atof( tokens[3].c_str() );
-
909 } else if( !tokens[0].compare( "Ke" ) ) { // emissive component
-
910 currentMaterial->emissive[0] = atof( tokens[1].c_str() );
-
911 currentMaterial->emissive[1] = atof( tokens[2].c_str() );
-
912 currentMaterial->emissive[2] = atof( tokens[3].c_str() );
-
913 } else if( !tokens[0].compare( "Ns" ) ) { // shininess component
-
914 currentMaterial->shininess = atof( tokens[1].c_str() );
-
915 } else if( !tokens[0].compare( "Tr" )
-
916 || !tokens[0].compare( "d" ) ) { // transparency component - Tr or d can be used depending on the format
-
917 currentMaterial->ambient[3] = atof( tokens[1].c_str() );
-
918 currentMaterial->diffuse[3] = atof( tokens[1].c_str() );
-
919 currentMaterial->specular[3] = atof( tokens[1].c_str() );
-
920 } else if( !tokens[0].compare( "illum" ) ) { // illumination type component
-
921 // TODO ?
-
922 } else if( !tokens[0].compare( "map_Kd" ) ) { // diffuse color texture map
-
923 if( imageHandles.find( tokens[1] ) != imageHandles.end() ) {
-
924 // _textureHandles->insert( pair< string, GLuint >( materialName, imageHandles.find( tokens[1] )->second ) );
-
925 currentMaterial->map_Kd = imageHandles.find( tokens[1] )->second;
-
926 } else {
-
927 stbi_set_flip_vertically_on_load(true);
-
928 textureData = stbi_load( tokens[1].c_str(), &texWidth, &texHeight, &textureChannels, 0 );
-
929 if( !textureData ) {
-
930 std::string folderName = path + tokens[1];
-
931 textureData = stbi_load( folderName.c_str(), &texWidth, &texHeight, &textureChannels, 0 );
-
932 }
-
933
-
934 if( !textureData ) {
-
935 if (ERRORS) fprintf( stderr, "[.mtl]: [ERROR]: File Not Found: %s\n", tokens[1].c_str() );
-
936 } else {
-
937 if (INFO) printf( "[.mtl]: TextureMap:\t%s\tSize: %dx%d\tColors: %d\n", tokens[1].c_str(), texWidth, texHeight, textureChannels );
-
938
-
939 if( maskData == NULL ) {
-
940 if( textureHandle == 0 ) {
-
941 glGenTextures( 1, &textureHandle );
-
942 imageHandles.insert( std::pair<std::string, GLuint>( tokens[1], textureHandle ) );
-
943 }
-
944
-
945 glBindTexture( GL_TEXTURE_2D, textureHandle );
-
946
-
947 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-
948 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
949
-
950 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-
951 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-
952
-
953 GLenum colorSpace = GL_RGB;
-
954 if( textureChannels == 4 )
-
955 colorSpace = GL_RGBA;
-
956 glTexImage2D( GL_TEXTURE_2D, 0, colorSpace, texWidth, texHeight, 0, colorSpace, GL_UNSIGNED_BYTE, textureData );
-
957
-
958 currentMaterial->map_Kd = textureHandle;
-
959 } else {
-
960 fullData = CSCI441_INTERNAL::createTransparentTexture( textureData, maskData, texWidth, texHeight, textureChannels, maskChannels );
-
961
-
962 if( textureHandle == 0 ) {
-
963 glGenTextures( 1, &textureHandle );
-
964 imageHandles.insert( std::pair<std::string, GLuint>( tokens[1], textureHandle ) );
-
965 }
-
966
-
967 glBindTexture( GL_TEXTURE_2D, textureHandle );
-
968
-
969 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-
970 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
971
-
972 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-
973 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-
974
-
975 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, fullData );
-
976
-
977 delete fullData;
-
978
-
979 currentMaterial->map_Kd = textureHandle;
-
980 }
-
981 }
-
982 }
-
983 } else if( !tokens[0].compare( "map_d" ) ) { // alpha texture map
-
984 if( imageHandles.find( tokens[1] ) != imageHandles.end() ) {
-
985 // _textureHandles->insert( pair< string, GLuint >( materialName, imageHandles.find( tokens[1] )->second ) );
-
986 currentMaterial->map_d = imageHandles.find( tokens[1] )->second;
-
987 } else {
-
988 stbi_set_flip_vertically_on_load(true);
-
989 maskData = stbi_load( tokens[1].c_str(), &texWidth, &texHeight, &textureChannels, 0 );
-
990 if( !textureData ) {
-
991 std::string folderName = path + tokens[1];
-
992 maskData = stbi_load( folderName.c_str(), &texWidth, &texHeight, &textureChannels, 0 );
-
993 }
-
994
-
995 if( !maskData ) {
-
996 if (ERRORS) fprintf( stderr, "[.mtl]: [ERROR]: File Not Found: %s\n", tokens[1].c_str() );
-
997 } else {
-
998 if (INFO) printf( "[.mtl]: AlphaMap: \t%s\tSize: %dx%d\tColors: %d\n", tokens[1].c_str(), texWidth, texHeight, maskChannels );
-
999
-
1000 if( textureData != NULL ) {
-
1001 fullData = CSCI441_INTERNAL::createTransparentTexture( textureData, maskData, texWidth, texHeight, textureChannels, maskChannels );
-
1002
-
1003 if( textureHandle == 0 )
-
1004 glGenTextures( 1, &textureHandle );
-
1005
-
1006 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-
1007 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
-
1008
-
1009 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
-
1010 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
-
1011
-
1012 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, fullData );
-
1013
-
1014 delete fullData;
-
1015 }
-
1016 }
-
1017 }
-
1018 } else if( !tokens[0].compare( "map_Ka" ) ) { // ambient color texture map
-
1019
-
1020 } else if( !tokens[0].compare( "map_Ks" ) ) { // specular color texture map
-
1021
-
1022 } else if( !tokens[0].compare( "map_Ns" ) ) { // specular highlight map (shininess map)
-
1023
-
1024 } else if( !tokens[0].compare( "Ni" ) ) { // optical density / index of refraction
-
1025
-
1026 } else if( !tokens[0].compare( "Tf" ) ) { // transmission filter
-
1027
-
1028 } else if( !tokens[0].compare( "bump" )
-
1029 || !tokens[0].compare( "map_bump" ) ) { // bump map
-
1030
-
1031 } else {
-
1032 if (INFO) printf( "[.mtl]: ignoring line: %s\n", line.c_str() );
-
1033 }
-
1034 }
-
1035
-
1036 in.close();
-
1037
-
1038 if ( INFO ) {
-
1039 printf( "[.mtl]: Materials:\t%d\n", numMaterials );
-
1040 printf( "[.mtl]: -*-*-*-*-*-*-*- END %s Info -*-*-*-*-*-*-*-\n", mtlFilename );
-
1041 }
-
1042
-
1043 return result;
-
1044}
-
1045
-
1046inline bool CSCI441::ModelLoader::_loadOFFFile( bool INFO, bool ERRORS ) {
-
1047 bool result = true;
-
1048
-
1049 if (INFO ) printf( "[.off]: -=-=-=-=-=-=-=- BEGIN %s Info -=-=-=-=-=-=-=-\n", _filename );
-
1050
-
1051 time_t start, end;
-
1052 time(&start);
-
1053
-
1054 std::ifstream in( _filename );
-
1055 if( !in.is_open() ) {
-
1056 if (ERRORS) fprintf( stderr, "[.off]: [ERROR]: Could not open \"%s\"\n", _filename );
-
1057 if ( INFO ) printf( "[.off]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
-
1058 return false;
-
1059 }
-
1060
-
1061 GLuint numVertices = 0, numFaces = 0, numTriangles = 0;
-
1062 GLfloat minX = 999999.0f, maxX = -999999.0f, minY = 999999.0f, maxY = -999999.0f, minZ = 999999.0f, maxZ = -999999.0f;
-
1063 std::string line;
-
1064
-
1065 enum OFF_FILE_STATE { HEADER, VERTICES, FACES, DONE };
-
1066
-
1067 OFF_FILE_STATE fileState = HEADER;
-
1068
-
1069 GLuint vSeen = 0, fSeen = 0;
-
1070
-
1071 while( getline( in, line ) ) {
-
1072 if( line.length() > 1 && line.at(0) == '\t' )
-
1073 line = line.substr( 1 );
-
1074 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
-
1075
-
1076 std::vector< std::string > tokens = _tokenizeString( line, " \t" );
-
1077 if( tokens.size() < 1 ) continue;
-
1078
-
1079 //the line should have a single character that lets us know if it's a...
-
1080 if( !tokens[0].compare( "#" ) || tokens[0].find_first_of("#") == 0 ) { // comment ignore
-
1081 } else if( fileState == HEADER ) {
-
1082 if( !tokens[0].compare( "OFF" ) ) { // denotes OFF File type
-
1083 } else {
-
1084 if( tokens.size() != 3 ) {
-
1085 if (ERRORS) fprintf( stderr, "[.off]: [ERROR]: Malformed OFF file. # vertices, faces, edges not properly specified\n" );
-
1086 if ( INFO ) printf( "[.off]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
-
1087 in.close();
-
1088 return false;
-
1089 }
-
1090 // read in number of expected vertices, faces, and edges
-
1091 numVertices = atoi( tokens[0].c_str() );
-
1092 numFaces = atoi( tokens[1].c_str() );
-
1093
-
1094 // ignore tokens[2] - number of edges -- unnecessary information
-
1095 // numEdges = atoi( tokens[2].c_str() );
-
1096
-
1097 fileState = VERTICES;
-
1098 }
-
1099 } else if( fileState == VERTICES ) {
-
1100 // read in x y z vertex location
-
1101 GLfloat x = (GLfloat) atof( tokens[0].c_str() ),
-
1102 y = (GLfloat) atof( tokens[1].c_str() ),
-
1103 z = (GLfloat) atof( tokens[2].c_str() );
-
1104
-
1105 if( x < minX ) minX = x;
-
1106 if( x > maxX ) maxX = x;
-
1107 if( y < minY ) minY = y;
-
1108 if( y > maxY ) maxY = y;
-
1109 if( z < minZ ) minZ = z;
-
1110 if( z > maxZ ) maxZ = z;
-
1111
-
1112 vSeen++;
-
1113 if( vSeen == numVertices )
-
1114 fileState = FACES;
-
1115 } else if( fileState == FACES ) {
-
1116 GLuint numberOfVerticesInFace = atoi( tokens[0].c_str() );
-
1117
-
1118 numTriangles += numberOfVerticesInFace - 3 + 1;
-
1119
-
1120 if( fSeen == numFaces )
-
1121 fileState = DONE;
-
1122 } else {
-
1123 if (INFO) printf( "[.off]: unknown file state: %d\n", fileState );
-
1124 }
-
1125 }
-
1126 in.close();
-
1127
-
1128 if (INFO) {
-
1129 printf( "\33[2K\r" );
-
1130 printf( "[.off]: scanning %s...done!\n", _filename );
-
1131 printf( "[.off]: ------------\n" );
-
1132 printf( "[.off]: Model Stats:\n" );
-
1133 printf( "[.off]: Vertices: \t%u\tNormals: \t%u\tTex Coords:\t%u\n", numVertices, 0, 0 );
-
1134 printf( "[.off]: Faces: \t%u\tTriangles: \t%u\n", numFaces, numTriangles );
-
1135 printf( "[.off]: Dimensions:\t(%f, %f, %f)\n", (maxX - minX), (maxY - minY), (maxZ - minZ) );
-
1136 }
-
1137
-
1138 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
-
1139 if (INFO && !_hasVertexNormals)
-
1140 printf( "[.off]: [WARN]: No vertex normals exist on model. To autogenerate vertex\n\tnormals, call CSCI441::ModelLoader::enableAutoGenerateNormals()\n\tprior to loading the model file.\n" );
-
1141 _vertices = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 3);
-
1142 _texCoords = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 2);
-
1143 _normals = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 3);
-
1144 _indices = (GLuint*)malloc(sizeof(GLuint) * numTriangles * 3);
-
1145 } else {
-
1146 if (INFO) printf( "[.off]: No vertex normals exist on model, vertex normals will be autogenerated\n" );
-
1147 _vertices = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 3);
-
1148 _texCoords = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 2);
-
1149 _normals = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 3);
-
1150 _indices = (GLuint*)malloc(sizeof(GLuint) * numTriangles * 3);
-
1151 }
-
1152
-
1153 std::vector<GLfloat> vertsTemp;
-
1154
-
1155 if (INFO) printf( "[.off]: ------------\n" );
-
1156
-
1157 in.open( _filename );
-
1158
-
1159 _uniqueIndex = 0;
-
1160 _numIndices = 0;
-
1161 vSeen = 0;
-
1162
-
1163 fileState = HEADER;
-
1164
-
1165 int progressCounter = 0;
-
1166
-
1167 while( getline( in, line ) ) {
-
1168 if( line.length() > 1 && line.at(0) == '\t' )
-
1169 line = line.substr( 1 );
-
1170 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
-
1171
-
1172 std::vector< std::string > tokens = _tokenizeString( line, " \t" );
-
1173 if( tokens.size() < 1 ) continue;
-
1174
-
1175 //the line should have a single character that lets us know if it's a...
-
1176 if( !tokens[0].compare( "#" ) || tokens[0].find_first_of("#") == 0 ) { // comment ignore
-
1177 } else if( fileState == HEADER ) {
-
1178 if( !tokens[0].compare( "OFF" ) ) { // denotes OFF File type
-
1179 } else {
-
1180
-
1181 // end of OFF Header reached
-
1182 fileState = VERTICES;
-
1183 }
-
1184 } else if( fileState == VERTICES ) {
-
1185 // read in x y z vertex location
-
1186 GLfloat x = (GLfloat) atof( tokens[0].c_str() ),
-
1187 y = (GLfloat) atof( tokens[1].c_str() ),
-
1188 z = (GLfloat) atof( tokens[2].c_str() );
-
1189
-
1190 // check if RGB(A) color information is associated with vertex
-
1191 if( tokens.size() == 6 || tokens.size() == 7 ) {
-
1192 // TODO: handle RGBA color info
-
1193 // GLfloat r = (GLfloat) atof( tokens[3].c_str() ),
-
1194 // g = (GLfloat) atof( tokens[4].c_str() ),
-
1195 // b = (GLfloat) atof( tokens[5].c_str() ),
-
1196 // a = 1.0f;
-
1197 //
-
1198 // if( tokens.size() == 7 )
-
1199 // a = atof( tokens[6].c_str() );
-
1200 }
-
1201
-
1202 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
-
1203 _vertices[ _uniqueIndex*3 + 0 ] = x;
-
1204 _vertices[ _uniqueIndex*3 + 1 ] = y;
-
1205 _vertices[ _uniqueIndex*3 + 2 ] = z;
-
1206
-
1207 _uniqueIndex++;
-
1208 } else {
-
1209 vertsTemp.push_back( x );
-
1210 vertsTemp.push_back( y );
-
1211 vertsTemp.push_back( z );
-
1212
-
1213 vSeen++;
-
1214 }
-
1215 // if all vertices have been read in, move on to faces
-
1216 if( _uniqueIndex == numVertices || vSeen == numVertices )
-
1217 fileState = FACES;
-
1218 } else if( fileState == FACES ) {
-
1219 GLuint numberOfVerticesInFace = atoi( tokens[0].c_str() );
-
1220
-
1221 // read in each vertex index of the face
-
1222 for(GLuint i = 2; i <= numberOfVerticesInFace - 1; i++) {
-
1223 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
-
1224 int fanRoot = atoi( tokens[1].c_str() );
-
1225 int fanA = atoi( tokens[i].c_str() );
-
1226 int fanB = atoi( tokens[i+1].c_str() );
-
1227
-
1228 if( fanRoot < 0 ) fanRoot = numVertices + fanRoot + 1;
-
1229 if( fanA < 0 ) fanA = numVertices + fanA + 1;
-
1230 if( fanB < 0 ) fanB = numVertices + fanB + 1;
-
1231
-
1232 //regardless, we always get a vertex index.
-
1233 _indices[ _numIndices++ ] = fanRoot;
-
1234 _indices[ _numIndices++ ] = fanA;
-
1235 _indices[ _numIndices++ ] = fanB;
-
1236 } else {
-
1237 int aI = atoi( tokens[1].c_str() );
-
1238 int bI = atoi( tokens[i].c_str() );
-
1239 int cI = atoi( tokens[i+1].c_str() );
-
1240
-
1241 if( aI < 0 ) aI = numVertices + aI + 1;
-
1242 if( bI < 0 ) bI = numVertices + bI + 1;
-
1243 if( cI < 0 ) cI = numVertices + cI + 1;
-
1244
-
1245 glm::vec3 a( vertsTemp[aI*3 + 0], vertsTemp[aI*3 + 1], vertsTemp[aI*3 + 2] );
-
1246 glm::vec3 b( vertsTemp[bI*3 + 0], vertsTemp[bI*3 + 1], vertsTemp[bI*3 + 2] );
-
1247 glm::vec3 c( vertsTemp[cI*3 + 0], vertsTemp[cI*3 + 1], vertsTemp[cI*3 + 2] );
-
1248
-
1249 glm::vec3 ab = b - a; glm::vec3 ac = c - a;
-
1250 glm::vec3 ba = a - b; glm::vec3 bc = c - b;
-
1251 glm::vec3 ca = a - c; glm::vec3 cb = b - c;
-
1252
-
1253 glm::vec3 aN = glm::normalize( glm::cross( ab, ac ) );
-
1254 glm::vec3 bN = glm::normalize( glm::cross( bc, ba ) );
-
1255 glm::vec3 cN = glm::normalize( glm::cross( ca, cb ) );
-
1256
-
1257 _vertices[ _uniqueIndex*3 + 0 ] = a.x;
-
1258 _vertices[ _uniqueIndex*3 + 1 ] = a.y;
-
1259 _vertices[ _uniqueIndex*3 + 2 ] = a.z;
-
1260
-
1261 _normals[ _uniqueIndex*3 + 0 ] = aN.x;
-
1262 _normals[ _uniqueIndex*3 + 1 ] = aN.y;
-
1263 _normals[ _uniqueIndex*3 + 2 ] = aN.z;
-
1264
-
1265 _indices[ _numIndices++ ] = _uniqueIndex++;
-
1266
-
1267 _vertices[ _uniqueIndex*3 + 0 ] = b.x;
-
1268 _vertices[ _uniqueIndex*3 + 1 ] = b.y;
-
1269 _vertices[ _uniqueIndex*3 + 2 ] = b.z;
-
1270
-
1271 _normals[ _uniqueIndex*3 + 0 ] = bN.x;
-
1272 _normals[ _uniqueIndex*3 + 1 ] = bN.y;
-
1273 _normals[ _uniqueIndex*3 + 2 ] = bN.z;
-
1274
-
1275 _indices[ _numIndices++ ] = _uniqueIndex++;
-
1276
-
1277 _vertices[ _uniqueIndex*3 + 0 ] = c.x;
-
1278 _vertices[ _uniqueIndex*3 + 1 ] = c.y;
-
1279 _vertices[ _uniqueIndex*3 + 2 ] = c.z;
-
1280
-
1281 _normals[ _uniqueIndex*3 + 0 ] = cN.x;
-
1282 _normals[ _uniqueIndex*3 + 1 ] = cN.y;
-
1283 _normals[ _uniqueIndex*3 + 2 ] = cN.z;
-
1284
-
1285 _indices[ _numIndices++ ] = _uniqueIndex++;
-
1286 }
-
1287 }
-
1288
-
1289 // check if RGB(A) color information is associated with face
-
1290 // TODO: handle color info
-
1291 //some local variables to hold the vertex+attribute indices we read in.
-
1292 //we do it this way because we'll have to split quads into triangles ourselves.
-
1293 // GLfloat color[4] = {-1,-1,-1,1};
-
1294 // if( tokens.size() == numberOfVerticesInFace + 4 || tokens.size() == numberOfVerticesInFace + 5 ) {
-
1295 // color[0] = atof( tokens[numberOfVerticesInFace + 1].c_str() );
-
1296 // color[1] = atof( tokens[numberOfVerticesInFace + 2].c_str() );
-
1297 // color[2] = atof( tokens[numberOfVerticesInFace + 3].c_str() );
-
1298 // color[3] = 1;
-
1299 //
-
1300 // if( tokens.size() == numberOfVerticesInFace + 5 )
-
1301 // color[3] = atof( tokens[numberOfVerticesInFace + 4].c_str() );
-
1302 // }
-
1303
-
1304 } else {
-
1305
-
1306 }
-
1307
-
1308 if (INFO) {
-
1309 progressCounter++;
-
1310 if( progressCounter % 5000 == 0 ) {
-
1311 printf("\33[2K\r");
-
1312 switch( progressCounter ) {
-
1313 case 5000: printf("[.off]: parsing %s...\\", _filename); break;
-
1314 case 10000: printf("[.off]: parsing %s...|", _filename); break;
-
1315 case 15000: printf("[.off]: parsing %s.../", _filename); break;
-
1316 case 20000: printf("[.off]: parsing %s...-", _filename); break;
-
1317 }
-
1318 fflush(stdout);
-
1319 }
-
1320 if( progressCounter == 20000 )
-
1321 progressCounter = 0;
-
1322 }
-
1323 }
-
1324 in.close();
-
1325
-
1326 glBindVertexArray( _vaod );
-
1327 glBindBuffer( GL_ARRAY_BUFFER, _vbods[0] );
-
1328 glBufferData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 8, NULL, GL_STATIC_DRAW );
-
1329 glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * _uniqueIndex * 3, _vertices );
-
1330 glBufferSubData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 3, sizeof(GLfloat) * _uniqueIndex * 3, _normals );
-
1331 glBufferSubData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 6, sizeof(GLfloat) * _uniqueIndex * 2, _texCoords );
-
1332
-
1333 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, _vbods[1] );
-
1334 glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * _numIndices, _indices, GL_STATIC_DRAW );
-
1335
-
1336 time(&end);
-
1337 double seconds = difftime( end, start );
-
1338
-
1339 if (INFO) {
-
1340 printf( "\33[2K\r" );
-
1341 printf( "[.off]: parsing %s...done! (Time: %.1fs)\n", _filename, seconds );
-
1342 printf( "[.off]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
-
1343 }
-
1344
-
1345 return result;
-
1346}
-
1347
-
1348// notes on PLY format: http://paulbourke.net/dataformats/ply/
-
1349inline bool CSCI441::ModelLoader::_loadPLYFile( bool INFO, bool ERRORS ) {
-
1350 bool result = true;
-
1351
-
1352 if (INFO ) printf( "[.ply]: -=-=-=-=-=-=-=- BEGIN %s Info -=-=-=-=-=-=-=-\n", _filename );
-
1353
-
1354 time_t start, end;
-
1355 time(&start);
-
1356
-
1357 std::ifstream in( _filename );
-
1358 if( !in.is_open() ) {
-
1359 if (ERRORS) fprintf( stderr, "[.ply]: [ERROR]: Could not open \"%s\"\n", _filename );
-
1360 if ( INFO ) printf( "[.ply]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
-
1361 return false;
-
1362 }
-
1363
-
1364 GLuint numVertices = 0, numFaces = 0, numTriangles = 0, numMaterials = 0;
-
1365 GLfloat minX = 999999.0f, maxX = -999999.0f, minY = 999999.0f, maxY = -999999.0f, minZ = 999999.0f, maxZ = -999999.0f;
-
1366 std::string line;
-
1367
-
1368 enum PLY_FILE_STATE { HEADER, VERTICES, FACES, MATERIALS };
-
1369 enum PLY_ELEMENT_TYPE { NONE, VERTEX, FACE, MATERIAL };
-
1370
-
1371 PLY_FILE_STATE fileState = HEADER;
-
1372 PLY_ELEMENT_TYPE elemType = NONE;
-
1373
-
1374 GLuint progressCounter = 0;
-
1375 GLuint vSeen = 0;
-
1376
-
1377 while( getline( in, line ) ) {
-
1378 if( line.length() > 1 && line.at(0) == '\t' )
-
1379 line = line.substr( 1 );
-
1380 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
-
1381
-
1382 std::vector< std::string > tokens = _tokenizeString( line, " \t" );
-
1383
-
1384 if( tokens.size() < 1 ) continue;
-
1385
-
1386 //the line should have a single character that lets us know if it's a...
-
1387 if( !tokens[0].compare( "comment" ) ) { // comment ignore
-
1388 } else if( fileState == HEADER ) {
-
1389 if( !tokens[0].compare( "ply" ) ) { // denotes ply File type
-
1390 } else if( !tokens[0].compare( "format" ) ) {
-
1391 if( tokens[1].compare( "ascii" ) ) {
-
1392 if (ERRORS) fprintf( stderr, "[.ply]: [ERROR]: File \"%s\" not ASCII format\n", _filename );
-
1393 if ( INFO ) printf( "[.ply]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
-
1394 in.close();
-
1395 return false;
-
1396 }
-
1397 } else if( !tokens[0].compare( "element" ) ) { // an element (vertex, face, material)
-
1398 if( !tokens[1].compare( "vertex" ) ) {
-
1399 numVertices = atoi( tokens[2].c_str() );
-
1400 elemType = VERTEX;
-
1401 } else if( !tokens[1].compare( "face" ) ) {
-
1402 numFaces = atoi( tokens[2].c_str() );
-
1403 elemType = FACE;
-
1404 } else if( !tokens[1].compare( "edge" ) ) {
-
1405
-
1406 } else if( !tokens[1].compare( "material" ) ) {
-
1407 numMaterials = atoi( tokens[2].c_str() );
-
1408 elemType = MATERIAL;
-
1409 } else {
-
1410
-
1411 }
-
1412 } else if( !tokens[0].compare( "property" ) ) {
-
1413 if( elemType == VERTEX ) {
-
1414
-
1415 } else if( elemType == FACE ) {
-
1416
-
1417 } else if( elemType == MATERIAL ) {
-
1418
-
1419 }
-
1420 } else if( !tokens[0].compare( "end_header" ) ) { // end of the header section
-
1421 fileState = VERTICES;
-
1422 }
-
1423 } else if( fileState == VERTICES ) {
-
1424 // read in x y z vertex location
-
1425 GLfloat x = (GLfloat) atof( tokens[0].c_str() ),
-
1426 y = (GLfloat) atof( tokens[1].c_str() ),
-
1427 z = (GLfloat) atof( tokens[2].c_str() );
-
1428
-
1429 if( x < minX ) minX = x;
-
1430 if( x > maxX ) maxX = x;
-
1431 if( y < minY ) minY = y;
-
1432 if( y > maxY ) maxY = y;
-
1433 if( z < minZ ) minZ = z;
-
1434 if( z > maxZ ) maxZ = z;
-
1435
-
1436 vSeen++;
-
1437 // if all vertices have been read in, move on to faces
-
1438 if( vSeen == numVertices )
-
1439 fileState = FACES;
-
1440 } else if( fileState == FACES ) {
-
1441 GLuint numberOfVerticesInFace = atoi( tokens[0].c_str() );
-
1442 numTriangles += numberOfVerticesInFace - 3 + 1;
-
1443 } else {
-
1444 if (INFO) printf( "[.ply]: unknown file state: %d\n", fileState );
-
1445 }
-
1446
-
1447 if (INFO) {
-
1448 progressCounter++;
-
1449 if( progressCounter % 5000 == 0 ) {
-
1450 printf("\33[2K\r");
-
1451 switch( progressCounter ) {
-
1452 case 5000: printf("[.ply]: scanning %s...\\", _filename); break;
-
1453 case 10000: printf("[.ply]: scanning %s...|", _filename); break;
-
1454 case 15000: printf("[.ply]: scanning %s.../", _filename); break;
-
1455 case 20000: printf("[.ply]: scanning %s...-", _filename); break;
-
1456 }
-
1457 fflush(stdout);
-
1458 }
-
1459 if( progressCounter == 20000 )
-
1460 progressCounter = 0;
-
1461 }
-
1462 }
-
1463 in.close();
-
1464
-
1465 if (INFO) {
-
1466 printf( "\33[2K\r" );
-
1467 printf( "[.ply]: scanning %s...done!\n", _filename );
-
1468 printf( "[.ply]: ------------\n" );
-
1469 printf( "[.ply]: Model Stats:\n" );
-
1470 printf( "[.ply]: Vertices: \t%u\tNormals: \t%u\tTex Coords:\t%u\n", numVertices, 0, 0 );
-
1471 printf( "[.ply]: Faces: \t%u\tTriangles: \t%u\n", numFaces, numTriangles );
-
1472 printf( "[.ply]: Dimensions:\t(%f, %f, %f)\n", (maxX - minX), (maxY - minY), (maxZ - minZ) );
-
1473 }
-
1474
-
1475 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
-
1476 if (INFO && !_hasVertexNormals)
-
1477 printf( "[.ply]: [WARN]: No vertex normals exist on model. To autogenerate vertex\n\tnormals, call CSCI441::ModelLoader::enableAutoGenerateNormals()\n\tprior to loading the model file.\n" );
-
1478 _vertices = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 3);
-
1479 _texCoords = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 2);
-
1480 _normals = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 3);
-
1481 _indices = (GLuint*)malloc(sizeof(GLuint) * numTriangles * 3);
-
1482 } else {
-
1483 if (INFO) printf( "[.ply]: No vertex normals exist on model, vertex normals will be autogenerated\n" );
-
1484 _vertices = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 3);
-
1485 _texCoords = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 2);
-
1486 _normals = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 3);
-
1487 _indices = (GLuint*)malloc(sizeof(GLuint) * numTriangles * 3);
-
1488 }
-
1489
-
1490 if (INFO) printf( "[.ply]: ------------\n" );
-
1491
-
1492 std::vector<GLfloat> vertsTemp;
-
1493
-
1494 in.open( _filename );
-
1495
-
1496 _uniqueIndex = 0;
-
1497 _numIndices = 0;
-
1498
-
1499 fileState = HEADER;
-
1500 elemType = NONE;
-
1501
-
1502 progressCounter = 0;
-
1503 vSeen = 0;
-
1504
-
1505 while( getline( in, line ) ) {
-
1506 if( line.length() > 1 && line.at(0) == '\t' )
-
1507 line = line.substr( 1 );
-
1508 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
-
1509
-
1510 std::vector< std::string > tokens = _tokenizeString( line, " \t" );
-
1511
-
1512 if( tokens.size() < 1 ) continue;
-
1513
-
1514 //the line should have a single character that lets us know if it's a...
-
1515 if( !tokens[0].compare( "comment" ) ) { // comment ignore
-
1516 } else if( fileState == HEADER ) {
-
1517 if( !tokens[0].compare( "ply" ) ) { // denotes ply File type
-
1518 } else if( !tokens[0].compare( "format" ) ) {
-
1519 if( tokens[1].compare( "ascii" ) ) {
-
1520 if (ERRORS) fprintf( stderr, "[.ply]: [ERROR]: File \"%s\" not ASCII format\n", _filename );
-
1521 if ( INFO ) printf( "[.ply]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
-
1522 in.close();
-
1523 return false;
-
1524 }
-
1525 } else if( !tokens[0].compare( "element" ) ) { // an element (vertex, face, material)
-
1526 if( !tokens[1].compare( "vertex" ) ) {
-
1527 numVertices = atoi( tokens[2].c_str() );
-
1528 elemType = VERTEX;
-
1529 } else if( !tokens[1].compare( "face" ) ) {
-
1530 numFaces = atoi( tokens[2].c_str() );
-
1531 elemType = FACE;
-
1532 } else if( !tokens[1].compare( "edge" ) ) {
-
1533
-
1534 } else if( !tokens[1].compare( "material" ) ) {
-
1535 numMaterials = atoi( tokens[2].c_str() );
-
1536 elemType = MATERIAL;
-
1537 } else {
-
1538
-
1539 }
-
1540 } else if( !tokens[0].compare( "property" ) ) {
-
1541 if( elemType == VERTEX ) {
-
1542
-
1543 } else if( elemType == FACE ) {
-
1544
-
1545 } else if( elemType == MATERIAL ) {
-
1546
-
1547 }
-
1548 } else if( !tokens[0].compare( "end_header" ) ) { // end of the header section
-
1549 fileState = VERTICES;
-
1550 }
-
1551 } else if( fileState == VERTICES ) {
-
1552 // read in x y z vertex location
-
1553 GLfloat x = (GLfloat) atof( tokens[0].c_str() ),
-
1554 y = (GLfloat) atof( tokens[1].c_str() ),
-
1555 z = (GLfloat) atof( tokens[2].c_str() );
-
1556
-
1557 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
-
1558 _vertices[ _uniqueIndex*3 + 0 ] = x;
-
1559 _vertices[ _uniqueIndex*3 + 1 ] = y;
-
1560 _vertices[ _uniqueIndex*3 + 2 ] = z;
-
1561
-
1562 _uniqueIndex++;
-
1563 } else {
-
1564 vertsTemp.push_back( x );
-
1565 vertsTemp.push_back( y );
-
1566 vertsTemp.push_back( z );
-
1567
-
1568 vSeen++;
-
1569 }
-
1570 // if all vertices have been read in, move on to faces
-
1571 if( _uniqueIndex == numVertices || vSeen == numVertices )
-
1572 fileState = FACES;
-
1573 } else if( fileState == FACES ) {
-
1574 GLuint numberOfVerticesInFace = atoi( tokens[0].c_str() );
-
1575
-
1576 for( GLuint i = 2; i <= numberOfVerticesInFace - 1; i++ ) {
-
1577 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
-
1578 _indices[ _numIndices++ ] = atoi( tokens[1].c_str() );
-
1579 _indices[ _numIndices++ ] = atoi( tokens[i].c_str() );
-
1580 _indices[ _numIndices++ ] = atoi( tokens[i+1].c_str() );
-
1581 } else {
-
1582 GLuint aI = atoi( tokens[1].c_str() );
-
1583 GLuint bI = atoi( tokens[i].c_str() );
-
1584 GLuint cI = atoi( tokens[i+1].c_str() );
-
1585
-
1586 glm::vec3 a( vertsTemp[aI*3 + 0], vertsTemp[aI*3 + 1], vertsTemp[aI*3 + 2] );
-
1587 glm::vec3 b( vertsTemp[bI*3 + 0], vertsTemp[bI*3 + 1], vertsTemp[bI*3 + 2] );
-
1588 glm::vec3 c( vertsTemp[cI*3 + 0], vertsTemp[cI*3 + 1], vertsTemp[cI*3 + 2] );
-
1589
-
1590 glm::vec3 ab = b - a; glm::vec3 ac = c - a;
-
1591 glm::vec3 ba = a - b; glm::vec3 bc = c - b;
-
1592 glm::vec3 ca = a - c; glm::vec3 cb = b - c;
-
1593
-
1594 glm::vec3 aN = glm::normalize( glm::cross( ab, ac ) );
-
1595 glm::vec3 bN = glm::normalize( glm::cross( bc, ba ) );
-
1596 glm::vec3 cN = glm::normalize( glm::cross( ca, cb ) );
-
1597
-
1598 _vertices[ _uniqueIndex*3 + 0 ] = a.x;
-
1599 _vertices[ _uniqueIndex*3 + 1 ] = a.y;
-
1600 _vertices[ _uniqueIndex*3 + 2 ] = a.z;
-
1601
-
1602 _normals[ _uniqueIndex*3 + 0 ] = aN.x;
-
1603 _normals[ _uniqueIndex*3 + 1 ] = aN.y;
-
1604 _normals[ _uniqueIndex*3 + 2 ] = aN.z;
-
1605
-
1606 _indices[ _numIndices++ ] = _uniqueIndex++;
-
1607
-
1608 _vertices[ _uniqueIndex*3 + 0 ] = b.x;
-
1609 _vertices[ _uniqueIndex*3 + 1 ] = b.y;
-
1610 _vertices[ _uniqueIndex*3 + 2 ] = b.z;
-
1611
-
1612 _normals[ _uniqueIndex*3 + 0 ] = bN.x;
-
1613 _normals[ _uniqueIndex*3 + 1 ] = bN.y;
-
1614 _normals[ _uniqueIndex*3 + 2 ] = bN.z;
-
1615
-
1616 _indices[ _numIndices++ ] = _uniqueIndex++;
-
1617
-
1618 _vertices[ _uniqueIndex*3 + 0 ] = c.x;
-
1619 _vertices[ _uniqueIndex*3 + 1 ] = c.y;
-
1620 _vertices[ _uniqueIndex*3 + 2 ] = c.z;
-
1621
-
1622 _normals[ _uniqueIndex*3 + 0 ] = cN.x;
-
1623 _normals[ _uniqueIndex*3 + 1 ] = cN.y;
-
1624 _normals[ _uniqueIndex*3 + 2 ] = cN.z;
-
1625
-
1626 _indices[ _numIndices++ ] = _uniqueIndex++;
-
1627 }
-
1628 }
-
1629 } else {
-
1630 if (INFO) printf( "[.ply]: unknown file state: %d\n", fileState );
-
1631 }
-
1632
-
1633 if (INFO) {
-
1634 progressCounter++;
-
1635 if( progressCounter % 5000 == 0 ) {
-
1636 printf("\33[2K\r");
-
1637 switch( progressCounter ) {
-
1638 case 5000: printf("[.ply]: parsing %s...\\", _filename); break;
-
1639 case 10000: printf("[.ply]: parsing %s...|", _filename); break;
-
1640 case 15000: printf("[.ply]: parsing %s.../", _filename); break;
-
1641 case 20000: printf("[.ply]: parsing %s...-", _filename); break;
-
1642 }
-
1643 fflush(stdout);
-
1644 }
-
1645 if( progressCounter == 20000 )
-
1646 progressCounter = 0;
-
1647 }
-
1648 }
-
1649 in.close();
-
1650
-
1651 glBindVertexArray( _vaod );
-
1652 glBindBuffer( GL_ARRAY_BUFFER, _vbods[0] );
-
1653 glBufferData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 8, NULL, GL_STATIC_DRAW );
-
1654 glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * _uniqueIndex * 3, _vertices );
-
1655 glBufferSubData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 3, sizeof(GLfloat) * _uniqueIndex * 3, _normals );
-
1656 glBufferSubData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 6, sizeof(GLfloat) * _uniqueIndex * 2, _texCoords );
-
1657
-
1658 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, _vbods[1] );
-
1659 glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * _numIndices, _indices, GL_STATIC_DRAW );
-
1660
-
1661 time(&end);
-
1662 double seconds = difftime( end, start );
-
1663
-
1664 if (INFO) {
-
1665 printf( "\33[2K\r" );
-
1666 printf( "[.ply]: parsing %s...done!\n[.ply]: Time to complete: %.3fs\n", _filename, seconds );
-
1667 printf( "[.ply]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
-
1668 }
-
1669
-
1670 return result;
-
1671}
-
1672
-
1673inline bool CSCI441::ModelLoader::_loadSTLFile( bool INFO, bool ERRORS ) {
-
1674 bool result = true;
-
1675
-
1676 if (INFO) printf( "[.stl]: -=-=-=-=-=-=-=- BEGIN %s Info -=-=-=-=-=-=-=-\n", _filename );
-
1677
-
1678 time_t start, end;
-
1679 time(&start);
-
1680
-
1681 std::ifstream in( _filename );
-
1682 if( !in.is_open() ) {
-
1683 if (ERRORS) fprintf(stderr, "[.stl]: [ERROR]: Could not open \"%s\"\n", _filename );
-
1684 if ( INFO ) printf( "[.stl]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
-
1685 return false;
-
1686 }
-
1687
-
1688 GLuint numVertices = 0, numNormals = 0, numFaces = 0, numTriangles = 0, numVertsInLoop = 0;
-
1689 GLfloat minX = 999999.0f, maxX = -999999.0f, minY = 999999.0f, maxY = -999999.0f, minZ = 999999.0f, maxZ = -999999.0f;
-
1690 std::string line;
-
1691
-
1692 int progressCounter = 0;
-
1693 GLfloat normalVector[3] = {0,0,0};
-
1694
-
1695 while( getline( in, line ) ) {
-
1696 if( line.length() > 1 && line.at(0) == '\t' )
-
1697 line = line.substr( 1 );
-
1698 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
-
1699
-
1700 std::vector< std::string > tokens = _tokenizeString( line, " \t" );
-
1701
-
1702 if( tokens.size() < 1 ) continue;
-
1703
-
1704 //the line should have a single character that lets us know if it's a...
-
1705 if( !tokens[0].compare( "solid" ) ) {
-
1706 } else if( !tokens[0].compare( "facet" ) ) {
-
1707 /* read in x y z triangle normal */
-
1708 numNormals++;
-
1709 } else if( !tokens[0].compare( "outer" ) && !tokens[1].compare( "loop" ) ) {
-
1710 // begin a primitive
-
1711 numVertsInLoop = 0;
-
1712 } else if( !tokens[0].compare( "vertex" ) ) {
-
1713 GLfloat x = (GLfloat) atof( tokens[1].c_str() ),
-
1714 y = (GLfloat) atof( tokens[2].c_str() ),
-
1715 z = (GLfloat) atof( tokens[3].c_str() );
-
1716
-
1717 if( x < minX ) minX = x;
-
1718 if( x > maxX ) maxX = x;
-
1719 if( y < minY ) minY = y;
-
1720 if( y > maxY ) maxY = y;
-
1721 if( z < minZ ) minZ = z;
-
1722 if( z > maxZ ) maxZ = z;
-
1723
-
1724 numVertices++;
-
1725 numVertsInLoop++;
-
1726 } else if( !tokens[0].compare( "endloop" ) ) {
-
1727 // end primitive
-
1728 numTriangles += numVertsInLoop - 3 + 1;
-
1729 } else if( !tokens[0].compare( "endfacet" ) ) {
-
1730 numFaces++;
-
1731 } else if( !tokens[0].compare( "endsolid" ) ) {
-
1732
-
1733 }
-
1734 else {
-
1735 if( memchr( line.c_str(), '\0', line.length() ) != NULL ) {
-
1736 if (ERRORS) fprintf( stderr, "[.stl]: [ERROR]: Cannot read binary STL file \"%s\"\n", _filename );
-
1737 if ( INFO ) printf( "[.stl]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
-
1738 in.close();
-
1739 return false;
-
1740 } else if (INFO) printf( "[.stl]: unknown line: %s\n", line.c_str() );
-
1741 }
-
1742
-
1743 if (INFO) {
-
1744 progressCounter++;
-
1745 if( progressCounter % 5000 == 0 ) {
-
1746 printf("\33[2K\r");
-
1747 switch( progressCounter ) {
-
1748 case 5000: printf("[.stl]: scanning %s...\\", _filename); break;
-
1749 case 10000: printf("[.stl]: scanning %s...|", _filename); break;
-
1750 case 15000: printf("[.stl]: scanning %s.../", _filename); break;
-
1751 case 20000: printf("[.stl]: scanning %s...-", _filename); break;
-
1752 }
-
1753 fflush(stdout);
-
1754 }
-
1755 if( progressCounter == 20000 )
-
1756 progressCounter = 0;
-
1757 }
-
1758 }
-
1759 in.close();
-
1760
-
1761 if (INFO) {
-
1762 printf( "\33[2K\r" );
-
1763 printf( "[.stl]: scanning %s...done!\n", _filename );
-
1764 printf( "[.stl]: ------------\n" );
-
1765 printf( "[.stl]: Model Stats:\n" );
-
1766 printf( "[.stl]: Vertices: \t%u\tNormals: \t%u\tTex Coords:\t%u\n", numVertices, numNormals, 0 );
-
1767 printf( "[.stl]: Faces: \t%u\tTriangles: \t%u\n", numFaces, numTriangles );
-
1768 printf( "[.stl]: Dimensions:\t(%f, %f, %f)\n", (maxX - minX), (maxY - minY), (maxZ - minZ) );
-
1769 }
-
1770
-
1771 _vertices = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 3);
-
1772 _texCoords = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 2);
-
1773 _normals = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 3);
-
1774 _indices = (GLuint*)malloc(sizeof(GLuint) * numTriangles * 3);
-
1775
-
1776 if (INFO) printf( "[.stl]: ------------\n" );
-
1777
-
1778 in.open( _filename );
-
1779
-
1780 _uniqueIndex = 0;
-
1781 _numIndices = 0;
-
1782
-
1783 while( getline( in, line ) ) {
-
1784 if( line.length() > 1 && line.at(0) == '\t' )
-
1785 line = line.substr( 1 );
-
1786 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
-
1787
-
1788 std::vector< std::string > tokens = _tokenizeString( line, " \t" );
-
1789
-
1790 if( tokens.size() < 1 ) continue;
-
1791
-
1792 //the line should have a single character that lets us know if it's a...
-
1793 if( !tokens[0].compare( "solid" ) ) {
-
1794 } else if( !tokens[0].compare( "facet" ) ) {
-
1795 /* read in x y z triangle normal */
-
1796 normalVector[0] = atof( tokens[2].c_str() );
-
1797 normalVector[1] = atof( tokens[3].c_str() );
-
1798 normalVector[2] = atof( tokens[4].c_str() );
-
1799 } else if( !tokens[0].compare( "outer" ) && !tokens[1].compare( "loop" ) ) {
-
1800 // begin a primitive
-
1801 } else if( !tokens[0].compare( "vertex" ) ) {
-
1802 GLfloat x = (GLfloat) atof( tokens[1].c_str() ),
-
1803 y = (GLfloat) atof( tokens[2].c_str() ),
-
1804 z = (GLfloat) atof( tokens[3].c_str() );
-
1805
-
1806 _vertices[ _uniqueIndex*3 + 0 ] = x;
-
1807 _vertices[ _uniqueIndex*3 + 1 ] = y;
-
1808 _vertices[ _uniqueIndex*3 + 2 ] = z;
-
1809
-
1810 _normals[ _uniqueIndex*3 + 0 ] = normalVector[0];
-
1811 _normals[ _uniqueIndex*3 + 1 ] = normalVector[1];
-
1812 _normals[ _uniqueIndex*3 + 2 ] = normalVector[2];
-
1813
-
1814 _indices[ _numIndices++ ] = _uniqueIndex++;
-
1815 } else if( !tokens[0].compare( "endloop" ) ) {
-
1816 // end primitive
-
1817 } else if( !tokens[0].compare( "endfacet" ) ) {
-
1818
-
1819 } else if( !tokens[0].compare( "endsolid" ) ) {
-
1820
-
1821 }
-
1822 else {
-
1823
-
1824 }
-
1825
-
1826 if (INFO) {
-
1827 progressCounter++;
-
1828 if( progressCounter % 5000 == 0 ) {
-
1829 printf("\33[2K\r");
-
1830 switch( progressCounter ) {
-
1831 case 5000: printf("[.stl]: parsing %s...\\", _filename); break;
-
1832 case 10000: printf("[.stl]: parsing %s...|", _filename); break;
-
1833 case 15000: printf("[.stl]: parsing %s.../", _filename); break;
-
1834 case 20000: printf("[.stl]: parsing %s...-", _filename); break;
-
1835 }
-
1836 fflush(stdout);
-
1837 }
-
1838 if( progressCounter == 20000 )
-
1839 progressCounter = 0;
-
1840 }
-
1841 }
-
1842 in.close();
-
1843
-
1844 glBindVertexArray( _vaod );
-
1845 glBindBuffer( GL_ARRAY_BUFFER, _vbods[0] );
-
1846 glBufferData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 8, NULL, GL_STATIC_DRAW );
-
1847 glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * _uniqueIndex * 3, _vertices );
-
1848 glBufferSubData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 3, sizeof(GLfloat) * _uniqueIndex * 3, _normals );
-
1849 glBufferSubData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 6, sizeof(GLfloat) * _uniqueIndex * 2, _texCoords );
-
1850
-
1851 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, _vbods[1] );
-
1852 glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * _numIndices, _indices, GL_STATIC_DRAW );
-
1853
-
1854 time(&end);
-
1855 double seconds = difftime( end, start );
-
1856
-
1857 if (INFO) {
-
1858 printf("\33[2K\r");
-
1859 printf("[.stl]: parsing %s...done!\n[.stl]: Time to complete: %.3fs\n", _filename, seconds);
-
1860 printf( "[.stl]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
-
1861 }
-
1862
-
1863 return result;
-
1864}
-
1865
-
1866inline void CSCI441::ModelLoader::enableAutoGenerateNormals() {
-
1867 _AUTO_GEN_NORMALS = true;
-
1868}
-
1869
-
1870inline void CSCI441::ModelLoader::disableAutoGenerateNormals() {
-
1871 _AUTO_GEN_NORMALS = false;
-
1872}
-
1873
-
1874//
-
1875// vector<string> tokenizeString(string input, string delimiters)
-
1876//
-
1877// This is a helper function to break a single string into std::vector
-
1878// of strings, based on a given set of delimiter characters.
-
1879//
-
1880inline std::vector<std::string> CSCI441::ModelLoader::_tokenizeString(std::string input, std::string delimiters) {
-
1881 if(input.size() == 0)
-
1882 return std::vector<std::string>();
-
1883
-
1884 std::vector<std::string> retVec = std::vector<std::string>();
-
1885 size_t oldR = 0, r = 0;
-
1886
-
1887 //strip all delimiter characters from the front and end of the input string.
-
1888 std::string strippedInput;
-
1889 int lowerValidIndex = 0, upperValidIndex = input.size() - 1;
-
1890 while((GLuint)lowerValidIndex < input.size() && delimiters.find_first_of(input.at(lowerValidIndex), 0) != std::string::npos)
-
1891 lowerValidIndex++;
-
1892
-
1893 while(upperValidIndex >= 0 && delimiters.find_first_of(input.at(upperValidIndex), 0) != std::string::npos)
-
1894 upperValidIndex--;
-
1895
-
1896 //if the lowest valid index is higher than the highest valid index, they're all delimiters! return nothing.
-
1897 if((GLuint)lowerValidIndex >= input.size() || upperValidIndex < 0 || lowerValidIndex > upperValidIndex)
-
1898 return std::vector<std::string>();
-
1899
-
1900 //remove the delimiters from the beginning and end of the string, if any.
-
1901 strippedInput = input.substr(lowerValidIndex, upperValidIndex-lowerValidIndex+1);
-
1902
-
1903 //search for each instance of a delimiter character, and create a new token spanning
-
1904 //from the last valid character up to the delimiter character.
-
1905 while((r = strippedInput.find_first_of(delimiters, oldR)) != std::string::npos)
-
1906 {
-
1907 if(oldR != r) //but watch out for multiple consecutive delimiters!
-
1908 retVec.push_back(strippedInput.substr(oldR, r-oldR));
-
1909 oldR = r+1;
-
1910 }
-
1911 if(r != 0)
-
1912 retVec.push_back(strippedInput.substr(oldR, r-oldR));
-
1913
-
1914 return retVec;
-
1915}
-
1916
-
1917inline unsigned char* CSCI441_INTERNAL::createTransparentTexture( unsigned char *imageData, unsigned char *imageMask, int texWidth, int texHeight, int texChannels, int maskChannels ) {
-
1918 //combine the 'mask' array with the image data array into an RGBA array.
-
1919 unsigned char *fullData = new unsigned char[texWidth*texHeight*4];
-
1920
-
1921 for(int j = 0; j < texHeight; j++) {
-
1922 for(int i = 0; i < texWidth; i++) {
-
1923 if( imageData ) {
-
1924 fullData[(j*texWidth+i)*4+0] = imageData[(j*texWidth+i)*texChannels+0]; // R
-
1925 fullData[(j*texWidth+i)*4+1] = imageData[(j*texWidth+i)*texChannels+1]; // G
-
1926 fullData[(j*texWidth+i)*4+2] = imageData[(j*texWidth+i)*texChannels+2]; // B
-
1927 } else {
-
1928 fullData[(j*texWidth+i)*4+0] = 1; // R
-
1929 fullData[(j*texWidth+i)*4+1] = 1; // G
-
1930 fullData[(j*texWidth+i)*4+2] = 1; // B
-
1931 }
-
1932
-
1933 if( imageMask ) {
-
1934 fullData[(j*texWidth+i)*4+3] = imageMask[(j*texWidth+i)*maskChannels+0]; // A
-
1935 } else {
-
1936 fullData[(j*texWidth+i)*4+3] = 1; // A
-
1937 }
-
1938 }
-
1939 }
-
1940 return fullData;
-
1941}
-
1942
-
1943inline void CSCI441_INTERNAL::flipImageY( int texWidth, int texHeight, int textureChannels, unsigned char *textureData ) {
-
1944 for( int j = 0; j < texHeight / 2; j++ ) {
-
1945 for( int i = 0; i < texWidth; i++ ) {
-
1946 for( int k = 0; k < textureChannels; k++ ) {
-
1947 int top = (j*texWidth + i)*textureChannels + k;
-
1948 int bot = ((texHeight-j-1)*texWidth + i)*textureChannels + k;
-
1949
-
1950 unsigned char t = textureData[top];
-
1951 textureData[top] = textureData[bot];
-
1952 textureData[bot] = t;
-
1953
-
1954 }
-
1955 }
-
1956 }
-
1957}
-
1958
-
1959#endif // __CSCI441_MODEL_LOADER_HPP__
-
Loads object models from file and renders using VBOs/VAOs.
Definition: ModelLoader.hpp:43
-
static void enableAutoGenerateNormals()
Enable autogeneration of vertex normals.
Definition: ModelLoader.hpp:1866
-
void setAttributeLocations(GLint positionLocation, GLint normalLocation=-1, GLint texCoordLocation=-1) const
Enables VBO attribute array locations.
Definition: ModelLoader.hpp:243
-
bool loadModelFile(const char *filename, bool INFO=true, bool ERRORS=true)
Loads a model from the given file.
Definition: ModelLoader.hpp:215
-
GLuint getNumberOfIndices() const
Return the number of indices to draw the model. This value corresponds to the size of the Indices arr...
Definition: ModelLoader.hpp:311
-
GLfloat * getVertices() const
Return the vertex array that makes up the model mesh. For use with VBOs.
Definition: ModelLoader.hpp:308
-
GLfloat * getNormals() const
Return the normal array that corresponds to the model mesh. For use with VBOs.
Definition: ModelLoader.hpp:310
-
bool draw(GLuint shaderProgramHandle, GLint matDiffLocation=-1, GLint matSpecLocation=-1, GLint matShinLocation=-1, GLint matAmbLocation=-1, GLenum diffuseTexture=GL_TEXTURE0) const
Renders a model.
Definition: ModelLoader.hpp:257
-
GLuint * getIndices() const
Return the index array that dictates the order to draw the model mesh. For use with IBOs.
Definition: ModelLoader.hpp:312
-
GLfloat * getTexCoords() const
Return the texture coordinates array that corresponds to the model mesh. For use with VBOs.
Definition: ModelLoader.hpp:309
-
GLuint getNumberOfVertices() const
Return the number of vertices the model is made up of. This value corresponds to the size of the Vert...
Definition: ModelLoader.hpp:307
-
static void disableAutoGenerateNormals()
Disable autogeneration of vertex normals.
Definition: ModelLoader.hpp:1870
-
~ModelLoader()
Frees memory associated with model on both CPU and GPU.
Definition: ModelLoader.hpp:192
-
ModelLoader()
Creates an empty model.
Definition: ModelLoader.hpp:183
+
44 class ModelLoader final {
+
45 public:
+
49 ModelLoader();
+
54 [[maybe_unused]] explicit ModelLoader( const char* filename );
+
58 ~ModelLoader();
+
59
+
67 bool loadModelFile( const char* filename, bool INFO = true, bool ERRORS = true );
+
68
+
75 [[maybe_unused]] void setAttributeLocations(GLint positionLocation, GLint normalLocation = -1, GLint texCoordLocation = -1) const;
+
76
+
87 [[maybe_unused]] [[nodiscard]] bool draw( GLuint shaderProgramHandle,
+
88 GLint matDiffLocation = -1, GLint matSpecLocation = -1, GLint matShinLocation = -1, GLint matAmbLocation = -1,
+
89 GLenum diffuseTexture = GL_TEXTURE0 ) const;
+
90
+
95 [[maybe_unused]] [[nodiscard]] GLuint getNumberOfVertices() const;
+
101 [[maybe_unused]] [[nodiscard]] GLfloat* getVertices() const;
+
107 [[maybe_unused]] [[nodiscard]] GLfloat* getTexCoords() const;
+
113 [[maybe_unused]] [[nodiscard]] GLfloat* getNormals() const;
+
118 [[maybe_unused]] [[nodiscard]] GLuint getNumberOfIndices() const;
+
124 [[maybe_unused]] [[nodiscard]] GLuint* getIndices() const;
+
125
+
133 [[maybe_unused]] static void enableAutoGenerateNormals();
+
140 [[maybe_unused]] static void disableAutoGenerateNormals();
+
141
+
142 private:
+
143 void _init();
+
144 bool _loadMTLFile( const char *mtlFilename, bool INFO, bool ERRORS );
+
145 bool _loadOBJFile( bool INFO, bool ERRORS );
+
146 bool _loadOFFFile( bool INFO, bool ERRORS );
+
147 bool _loadPLYFile( bool INFO, bool ERRORS );
+
148 bool _loadSTLFile( bool INFO, bool ERRORS );
+
149 std::vector<std::string> _tokenizeString( std::string input, std::string delimiters );
+
150
+
151 char* _filename;
+
152 CSCI441_INTERNAL::MODEL_TYPE _modelType;
+
153
+
154 GLuint _vaod;
+
155 GLuint _vbods[2];
+
156
+
157 GLfloat* _vertices;
+
158 GLfloat* _texCoords;
+
159 GLfloat* _normals;
+
160 GLuint* _indices;
+
161 GLuint _uniqueIndex;
+
162 GLuint _numIndices;
+
163
+
164 std::map< std::string, CSCI441_INTERNAL::ModelMaterial* > _materials;
+
165 std::map< std::string, std::vector< std::pair< GLuint, GLuint > > > _materialIndexStartStop;
+
166
+
167 bool _hasVertexTexCoords;
+
168 bool _hasVertexNormals;
+
169
+
170 static bool _AUTO_GEN_NORMALS;
+
171 };
+
172}
+
173
+
176
+
177namespace CSCI441_INTERNAL {
+
178 unsigned char* createTransparentTexture( unsigned char *imageData, unsigned char *imageMask, int texWidth, int texHeight, int texChannels, int maskChannels );
+
179 void flipImageY( int texWidth, int texHeight, int textureChannels, unsigned char *textureData );
+
180}
+
181
+
182inline bool CSCI441::ModelLoader::_AUTO_GEN_NORMALS = false;
+
183
+
184inline CSCI441::ModelLoader::ModelLoader() {
+
185 _init();
+
186}
+
187
+
188inline CSCI441::ModelLoader::ModelLoader( const char* filename ) {
+
189 _init();
+
190 loadModelFile( filename );
+
191}
+
192
+
193inline CSCI441::ModelLoader::~ModelLoader() {
+
194 if( _vertices ) free( _vertices );
+
195 if( _texCoords ) free( _texCoords );
+
196 if( _normals ) free( _normals );
+
197 if( _indices ) free( _indices );
+
198
+
199 glDeleteBuffers( 2, _vbods );
+
200 glDeleteVertexArrays( 1, &_vaod );
+
201}
+
202
+
203inline void CSCI441::ModelLoader::_init() {
+
204 _hasVertexTexCoords = false;
+
205 _hasVertexNormals = false;
+
206
+
207 _vertices = NULL;
+
208 _texCoords = NULL;
+
209 _normals = NULL;
+
210 _indices = NULL;
+
211
+
212 glGenVertexArrays( 1, &_vaod );
+
213 glGenBuffers( 2, _vbods );
+
214}
+
215
+
216inline bool CSCI441::ModelLoader::loadModelFile( const char* filename, bool INFO, bool ERRORS ) {
+
217 bool result = true;
+
218 _filename = (char*)malloc(sizeof(char)*strlen(filename));
+
219 strcpy( _filename, filename );
+
220 if( strstr( _filename, ".obj" ) != NULL ) {
+
221 result = _loadOBJFile( INFO, ERRORS );
+
222 _modelType = CSCI441_INTERNAL::OBJ;
+
223 }
+
224 else if( strstr( _filename, ".off" ) != NULL ) {
+
225 result = _loadOFFFile( INFO, ERRORS );
+
226 _modelType = CSCI441_INTERNAL::OFF;
+
227 }
+
228 else if( strstr( _filename, ".ply" ) != NULL ) {
+
229 result = _loadPLYFile( INFO, ERRORS );
+
230 _modelType = CSCI441_INTERNAL::PLY;
+
231 }
+
232 else if( strstr( _filename, ".stl" ) != NULL ) {
+
233 result = _loadSTLFile( INFO, ERRORS );
+
234 _modelType = CSCI441_INTERNAL::STL;
+
235 }
+
236 else {
+
237 result = false;
+
238 if (ERRORS) fprintf( stderr, "[ERROR]: Unsupported file format for file: %s\n", _filename );
+
239 }
+
240
+
241 return result;
+
242}
+
243
+
244inline void CSCI441::ModelLoader::setAttributeLocations(GLint positionLocation, GLint normalLocation, GLint texCoordLocation) const {
+
245 glBindVertexArray( _vaod );
+
246 glBindBuffer( GL_ARRAY_BUFFER, _vbods[0] );
+
247
+
248 glEnableVertexAttribArray( positionLocation );
+
249 glVertexAttribPointer( positionLocation, 3, GL_FLOAT, GL_FALSE, 0, (void*)0 );
+
250
+
251 glEnableVertexAttribArray( normalLocation );
+
252 glVertexAttribPointer( normalLocation, 3, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(GLfloat) * _uniqueIndex * 3) );
+
253
+
254 glEnableVertexAttribArray( texCoordLocation );
+
255 glVertexAttribPointer( texCoordLocation, 2, GL_FLOAT, GL_FALSE, 0, (void*)(sizeof(GLfloat) * _uniqueIndex * 6) );
+
256}
+
257
+
258inline bool CSCI441::ModelLoader::draw( GLuint shaderProgramHandle,
+
259 GLint matDiffLocation, GLint matSpecLocation, GLint matShinLocation, GLint matAmbLocation,
+
260 GLenum diffuseTexture ) const {
+
261 glBindVertexArray( _vaod );
+
262
+
263 bool result = true;
+
264 if( _modelType == CSCI441_INTERNAL::OBJ ) {
+
265 for( auto materialIter = _materialIndexStartStop.begin();
+
266 materialIter != _materialIndexStartStop.end();
+
267 materialIter++ ) {
+
268
+
269 std::string materialName = materialIter->first;
+
270 std::vector< std::pair< GLuint, GLuint > > indexStartStop = materialIter->second;
+
271
+
272 CSCI441_INTERNAL::ModelMaterial* material = nullptr;
+
273 if( _materials.find( materialName ) != _materials.end() )
+
274 material = _materials.find( materialName )->second;
+
275
+
276 for( std::vector< std::pair< GLuint, GLuint > >::iterator idxIter = indexStartStop.begin();
+
277 idxIter != indexStartStop.end();
+
278 idxIter++ ) {
+
279
+
280 GLuint start = idxIter->first;
+
281 GLuint end = idxIter->second;
+
282 GLuint length = end - start + 1;
+
283
+
284// printf( "rendering material %s (%u, %u) = %u\n", materialName.c_str(), start, end, length );
+
285
+
286 if( material != nullptr ) {
+
287 glProgramUniform4fv( shaderProgramHandle, matAmbLocation, 1, material->ambient );
+
288 glProgramUniform4fv( shaderProgramHandle, matDiffLocation, 1, material->diffuse );
+
289 glProgramUniform4fv( shaderProgramHandle, matSpecLocation, 1, material->specular );
+
290 glProgramUniform1f( shaderProgramHandle, matShinLocation, material->shininess );
+
291
+
292 if( material->map_Kd != -1 ) {
+
293 glActiveTexture( diffuseTexture );
+
294 glBindTexture( GL_TEXTURE_2D, material->map_Kd );
+
295 }
+
296 }
+
297
+
298 glDrawElements( GL_TRIANGLES, length, GL_UNSIGNED_INT, (void*)(sizeof(GLuint)*start) );
+
299 }
+
300 }
+
301 } else {
+
302 glDrawElements( GL_TRIANGLES, _numIndices, GL_UNSIGNED_INT, (void*)0 );
+
303 }
+
304
+
305 return result;
+
306}
+
307
+
308inline GLuint CSCI441::ModelLoader::getNumberOfVertices() const { return _uniqueIndex; }
+
309inline GLfloat* CSCI441::ModelLoader::getVertices() const { return _vertices; }
+
310inline GLfloat* CSCI441::ModelLoader::getTexCoords() const { return _texCoords; }
+
311inline GLfloat* CSCI441::ModelLoader::getNormals() const { return _normals; }
+
312inline GLuint CSCI441::ModelLoader::getNumberOfIndices() const { return _numIndices; }
+
313inline GLuint* CSCI441::ModelLoader::getIndices() const { return _indices; }
+
314
+
315// Read in a WaveFront *.obj File
+
316inline bool CSCI441::ModelLoader::_loadOBJFile( bool INFO, bool ERRORS ) {
+
317 bool result = true;
+
318
+
319 if (INFO ) printf( "[.obj]: -=-=-=-=-=-=-=- BEGIN %s Info -=-=-=-=-=-=-=- \n", _filename );
+
320
+
321 time_t start, end;
+
322 time(&start);
+
323
+
324 std::ifstream in( _filename );
+
325 if( !in.is_open() ) {
+
326 if (ERRORS) fprintf( stderr, "[.obj]: [ERROR]: Could not open \"%s\"\n", _filename );
+
327 if ( INFO ) printf( "[.obj]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=- \n", _filename );
+
328 return false;
+
329 }
+
330
+
331 GLuint numObjects = 0, numGroups = 0;
+
332 GLuint numVertices = 0, numTexCoords = 0, numNormals = 0;
+
333 GLuint numFaces = 0, numTriangles = 0;
+
334 GLfloat minX = 999999.0f, maxX = -999999.0f, minY = 999999.0f, maxY = -999999.0f, minZ = 999999.0f, maxZ = -999999.0f;
+
335 std::string line;
+
336
+
337 std::map<std::string, GLuint> uniqueCounts;
+
338 _uniqueIndex = 0;
+
339
+
340 int progressCounter = 0;
+
341
+
342 while( getline( in, line ) ) {
+
343 if( line.length() > 1 && line.at(0) == '\t' )
+
344 line = line.substr( 1 );
+
345 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
+
346
+
347 std::vector< std::string > tokens = _tokenizeString( line, " \t" );
+
348 if( tokens.size() < 1 ) continue;
+
349
+
350 //the line should have a single character that lets us know if it's a...
+
351 if( !tokens[0].compare( "#" ) || tokens[0].find_first_of("#") == 0 ) { // comment ignore
+
352 } else if( !tokens[0].compare( "o" ) ) { // object name ignore
+
353 numObjects++;
+
354 } else if( !tokens[0].compare( "g" ) ) { // polygon group name ignore
+
355 numGroups++;
+
356 } else if( !tokens[0].compare( "mtllib" ) ) { // material library
+
357 _loadMTLFile( tokens[1].c_str(), INFO, ERRORS );
+
358 } else if( !tokens[0].compare( "v" ) ) { //vertex
+
359 numVertices++;
+
360
+
361 GLfloat x = (GLfloat) atof( tokens[1].c_str() ),
+
362 y = (GLfloat) atof( tokens[2].c_str() ),
+
363 z = (GLfloat) atof( tokens[3].c_str() );
+
364
+
365 if( x < minX ) minX = x;
+
366 if( x > maxX ) maxX = x;
+
367 if( y < minY ) minY = y;
+
368 if( y > maxY ) maxY = y;
+
369 if( z < minZ ) minZ = z;
+
370 if( z > maxZ ) maxZ = z;
+
371 } else if( !tokens.at(0).compare( "vn" ) ) { //vertex normal
+
372 numNormals++;
+
373 } else if( !tokens.at(0).compare( "vt" ) ) { //vertex tex coord
+
374 numTexCoords++;
+
375 } else if( !tokens.at(0).compare( "f" ) ) { //face!
+
376
+
377 //now, faces can be either quads or triangles (or maybe more?)
+
378 //split the string on spaces to get the number of verts+attrs.
+
379 std::vector<std::string> faceTokens = _tokenizeString(line, " ");
+
380
+
381 for(GLuint i = 1; i < faceTokens.size(); i++) {
+
382 //need to use both the tokens and number of slashes to determine what info is there.
+
383 std::vector<std::string> groupTokens = _tokenizeString(faceTokens[i], "/");
+
384 int numSlashes = 0;
+
385 for( GLuint j = 0; j < faceTokens[i].length(); j++ ) {
+
386 if(faceTokens[i][j] == '/') numSlashes++;
+
387 }
+
388
+
389 std::stringstream currentFaceTokenStream;
+
390 int v = atoi(groupTokens[0].c_str());
+
391 if(v < 0)
+
392 v = numVertices + v + 1;
+
393 currentFaceTokenStream << v;
+
394
+
395 //based on combination of number of tokens and slashes, we can determine what we have.
+
396 if(groupTokens.size() == 2 && numSlashes == 1) {
+
397 _hasVertexTexCoords = true;
+
398
+
399 int vt = atoi(groupTokens[1].c_str());
+
400 if(vt < 0)
+
401 vt = numTexCoords + vt + 1;
+
402 currentFaceTokenStream << "/" << vt;
+
403 } else if(groupTokens.size() == 2 && numSlashes == 2) {
+
404 _hasVertexNormals = true;
+
405
+
406 int vn = atoi(groupTokens[1].c_str());
+
407 if(vn < 0)
+
408 vn = numNormals + vn + 1;
+
409 currentFaceTokenStream << "//" << vn;
+
410 } else if(groupTokens.size() == 3) {
+
411 _hasVertexTexCoords = true;
+
412 _hasVertexNormals = true;
+
413
+
414 int vt = atoi(groupTokens[1].c_str());
+
415 if(vt < 0)
+
416 vt = numTexCoords + vt + 1;
+
417 int vn = atoi(groupTokens[2].c_str());
+
418 if(vn < 0)
+
419 vn = numNormals + vn + 1;
+
420 currentFaceTokenStream << "/" << vt << "/" << vn;
+
421 } else if(groupTokens.size() != 1) {
+
422 if (ERRORS) fprintf(stderr, "[.obj]: [ERROR]: Malformed OBJ file, %s.\n", _filename);
+
423 return false;
+
424 }
+
425
+
426 std::string processedFaceToken = currentFaceTokenStream.str();
+
427 if( uniqueCounts.find( processedFaceToken ) == uniqueCounts.end() ) {
+
428 uniqueCounts.insert( std::pair<std::string,long int>(processedFaceToken,_uniqueIndex) );
+
429 _uniqueIndex++;
+
430 }
+
431 }
+
432
+
433 numTriangles += (faceTokens.size() - 1 - 3 + 1);
+
434
+
435 numFaces++;
+
436 } else {
+
437
+
438 }
+
439
+
440 if (INFO) {
+
441 progressCounter++;
+
442 if( progressCounter % 5000 == 0 ) {
+
443 printf("\33[2K\r");
+
444 switch( progressCounter ) {
+
445 case 5000: printf("[.obj]: scanning %s...\\", _filename); break;
+
446 case 10000: printf("[.obj]: scanning %s...|", _filename); break;
+
447 case 15000: printf("[.obj]: scanning %s.../", _filename); break;
+
448 case 20000: printf("[.obj]: scanning %s...-", _filename); break;
+
449 }
+
450 fflush(stdout);
+
451 }
+
452 if( progressCounter == 20000 )
+
453 progressCounter = 0;
+
454 }
+
455 }
+
456 in.close();
+
457
+
458 if (INFO) {
+
459 printf( "\33[2K\r" );
+
460 printf( "[.obj]: scanning %s...done!\n", _filename );
+
461 printf( "[.obj]: ------------\n" );
+
462 printf( "[.obj]: Model Stats:\n" );
+
463 printf( "[.obj]: Vertices: \t%u\tNormals: \t%u\tTex Coords:\t%u\n", numVertices, numNormals, numTexCoords );
+
464 printf( "[.obj]: Unique Verts:\t%u\n", _uniqueIndex );
+
465 printf( "[.obj]: Faces: \t%u\tTriangles:\t%u\n", numFaces, numTriangles );
+
466 printf( "[.obj]: Objects: \t%u\tGroups: \t%u\n", numObjects, numGroups );
+
467 printf( "[.obj]: Dimensions:\t(%f, %f, %f)\n", (maxX - minX), (maxY - minY), (maxZ - minZ) );
+
468 }
+
469
+
470 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
+
471 if (INFO && !_hasVertexNormals)
+
472 printf( "[.obj]: [WARN]: No vertex normals exist on model. To autogenerate vertex\n\tnormals, call CSCI441::ModelLoader::enableAutoGenerateNormals()\n\tprior to loading the model file.\n" );
+
473 _vertices = (GLfloat*)malloc(sizeof(GLfloat) * _uniqueIndex * 3);
+
474 _texCoords = (GLfloat*)malloc(sizeof(GLfloat) * _uniqueIndex * 2);
+
475 _normals = (GLfloat*)malloc(sizeof(GLfloat) * _uniqueIndex * 3);
+
476 _indices = (GLuint*)malloc(sizeof(GLuint) * numTriangles * 3);
+
477 } else {
+
478 if (INFO) printf( "[.obj]: No vertex normals exist on model, vertex normals will be autogenerated\n" );
+
479 _vertices = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 3);
+
480 _texCoords = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 2);
+
481 _normals = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 3);
+
482 _indices = (GLuint*)malloc(sizeof(GLuint) * numTriangles * 3);
+
483 }
+
484
+
485 GLfloat* v = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 3);
+
486 GLfloat* vt = (GLfloat*)malloc(sizeof(GLfloat) * numTexCoords * 2);
+
487 GLfloat* vn = (GLfloat*)malloc(sizeof(GLfloat) * numNormals * 3);
+
488
+
489 std::vector<GLfloat> vertsTemp;
+
490 std::vector<GLfloat> texCoordsTemp;
+
491
+
492 printf( "[.obj]: ------------\n" );
+
493
+
494 uniqueCounts.clear();
+
495 _uniqueIndex = 0;
+
496 _numIndices = 0;
+
497
+
498 in.open( _filename );
+
499
+
500 GLuint vSeen = 0, vtSeen = 0, vnSeen = 0, indicesSeen = 0;
+
501 GLuint uniqueV = 0;
+
502
+
503 std::string currentMaterial = "default";
+
504 _materialIndexStartStop.insert( std::pair< std::string, std::vector< std::pair< GLuint, GLuint > > >( currentMaterial, std::vector< std::pair< GLuint, GLuint > >(1) ) );
+
505 _materialIndexStartStop.find( currentMaterial )->second.back().first = indicesSeen;
+
506
+
507 while( getline( in, line ) ) {
+
508 if( line.length() > 1 && line.at(0) == '\t' )
+
509 line = line.substr( 1 );
+
510 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
+
511
+
512 std::vector< std::string > tokens = _tokenizeString( line, " \t" );
+
513 if( tokens.size() < 1 ) continue;
+
514
+
515 //the line should have a single character that lets us know if it's a...
+
516 if( !tokens[0].compare( "#" ) || tokens[0].find_first_of("#") == 0 ) { // comment ignore
+
517 } else if( !tokens[0].compare( "o" ) ) { // object name ignore
+
518
+
519 } else if( !tokens[0].compare( "g" ) ) { // polygon group name ignore
+
520
+
521 } else if( !tokens[0].compare( "mtllib" ) ) { // material library
+
522
+
523 } else if( !tokens[0].compare( "usemtl" ) ) { // use material library
+
524 if( currentMaterial == "default" && indicesSeen == 0 ) {
+
525 _materialIndexStartStop.clear();
+
526 } else {
+
527 _materialIndexStartStop.find( currentMaterial )->second.back().second = indicesSeen - 1;
+
528 }
+
529 currentMaterial = tokens[1];
+
530 if( _materialIndexStartStop.find( currentMaterial ) == _materialIndexStartStop.end() ) {
+
531 _materialIndexStartStop.insert( std::pair< std::string, std::vector< std::pair< GLuint, GLuint > > >( currentMaterial, std::vector< std::pair< GLuint, GLuint > >(1) ) );
+
532 _materialIndexStartStop.find( currentMaterial )->second.back().first = indicesSeen;
+
533 } else {
+
534 _materialIndexStartStop.find( currentMaterial )->second.push_back( std::pair< GLuint, GLuint >( indicesSeen, -1 ) );
+
535 }
+
536 } else if( !tokens[0].compare( "s" ) ) { // smooth shading
+
537
+
538 } else if( !tokens[0].compare( "v" ) ) { //vertex
+
539 GLfloat x = (GLfloat) atof( tokens[1].c_str() ),
+
540 y = (GLfloat) atof( tokens[2].c_str() ),
+
541 z = (GLfloat) atof( tokens[3].c_str() );
+
542
+
543 v[vSeen*3 + 0] = x;
+
544 v[vSeen*3 + 1] = y;
+
545 v[vSeen*3 + 2] = z;
+
546
+
547 vSeen++;
+
548 } else if( !tokens.at(0).compare( "vn" ) ) { //vertex normal
+
549 GLfloat x = (GLfloat) atof( tokens[1].c_str() ),
+
550 y = (GLfloat) atof( tokens[2].c_str() ),
+
551 z = (GLfloat) atof( tokens[3].c_str() );
+
552
+
553 vn[vnSeen*3 + 0] = x;
+
554 vn[vnSeen*3 + 1] = y;
+
555 vn[vnSeen*3 + 2] = z;
+
556
+
557 vnSeen++;
+
558 } else if( !tokens.at(0).compare( "vt" ) ) { //vertex tex coord
+
559 GLfloat s = (GLfloat) atof( tokens[1].c_str() ),
+
560 t = (GLfloat) atof( tokens[2].c_str() );
+
561
+
562 vt[vtSeen*2 + 0] = s;
+
563 vt[vtSeen*2 + 1] = t;
+
564
+
565 vtSeen++;
+
566 } else if( !tokens.at(0).compare( "f" ) ) { //face!
+
567
+
568 //now, faces can be either quads or triangles (or maybe more?)
+
569 //split the string on spaces to get the number of verts+attrs.
+
570 std::vector<std::string> faceTokens = _tokenizeString(line, " ");
+
571 std::vector<std::string> processedFaceTokens;
+
572
+
573 for(GLuint i = 1; i < faceTokens.size(); i++) {
+
574 //need to use both the tokens and number of slashes to determine what info is there.
+
575 std::vector<std::string> groupTokens = _tokenizeString(faceTokens[i], "/");
+
576 int numSlashes = 0;
+
577 for( GLuint j = 0; j < faceTokens[i].length(); j++ ) {
+
578 if(faceTokens[i][j] == '/') numSlashes++;
+
579 }
+
580
+
581 std::stringstream currentFaceTokenStream;
+
582 int vx = atoi(groupTokens[0].c_str());
+
583 if(vx < 0)
+
584 vx = vSeen + vx + 1;
+
585 currentFaceTokenStream << vx;
+
586
+
587 //based on combination of number of tokens and slashes, we can determine what we have.
+
588 if(groupTokens.size() == 2 && numSlashes == 1) {
+
589 _hasVertexTexCoords = true;
+
590
+
591 int vtx = atoi(groupTokens[1].c_str());
+
592 if(vtx < 0)
+
593 vtx = vtSeen + vtx + 1;
+
594 currentFaceTokenStream << "/" << vtx;
+
595 } else if(groupTokens.size() == 2 && numSlashes == 2) {
+
596 _hasVertexNormals = true;
+
597
+
598 int vnx = atoi(groupTokens[1].c_str());
+
599 if(vnx < 0)
+
600 vnx = vnSeen + vnx + 1;
+
601 currentFaceTokenStream << "//" << vnx;
+
602 } else if(groupTokens.size() == 3) {
+
603 _hasVertexTexCoords = true;
+
604 _hasVertexNormals = true;
+
605
+
606 int vtx = atoi(groupTokens[1].c_str());
+
607 if(vtx < 0)
+
608 vtx = vtSeen + vtx + 1;
+
609 int vnx = atoi(groupTokens[2].c_str());
+
610 if(vnx < 0)
+
611 vnx = vnSeen + vnx + 1;
+
612 currentFaceTokenStream << "/" << vtx << "/" << vnx;
+
613 } else if(groupTokens.size() != 1) {
+
614 if (ERRORS) fprintf(stderr, "[.obj]: [ERROR]: Malformed OBJ file, %s.\n", _filename);
+
615 return false;
+
616 }
+
617
+
618 std::string processedFaceToken = currentFaceTokenStream.str();
+
619 processedFaceTokens.push_back(processedFaceToken);
+
620
+
621 if( uniqueCounts.find( processedFaceToken ) == uniqueCounts.end() ) {
+
622 uniqueCounts.insert( std::pair<std::string,unsigned long int>(processedFaceToken,uniqueV) );
+
623
+
624 //need to use both the tokens and number of slashes to determine what info is there.
+
625 std::vector<std::string> groupTokens = _tokenizeString(processedFaceToken, "/");
+
626 int numSlashes = 0;
+
627 for( GLuint j = 0; j < processedFaceToken.length(); j++ ) {
+
628 if(processedFaceToken[j] == '/') numSlashes++;
+
629 }
+
630
+
631 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
+
632 //regardless, we always get a vertex index.
+
633 int vI = atoi(groupTokens[0].c_str());
+
634 if( vI < 0 )
+
635 vI = vSeen + vI + 1;
+
636
+
637 _vertices[ _uniqueIndex*3 + 0 ] = v[ ((vI - 1) * 3) + 0 ];
+
638 _vertices[ _uniqueIndex*3 + 1 ] = v[ ((vI - 1) * 3) + 1 ];
+
639 _vertices[ _uniqueIndex*3 + 2 ] = v[ ((vI - 1) * 3) + 2 ];
+
640
+
641 //based on combination of number of tokens and slashes, we can determine what we have.
+
642 if(groupTokens.size() == 2 && numSlashes == 1) {
+
643 int vtI = atoi(groupTokens[1].c_str());
+
644 if( vtI < 0 )
+
645 vtI = vtSeen + vtI + 1;
+
646
+
647 _texCoords[ _uniqueIndex*2 + 0 ] = vt[ ((vtI - 1) * 2) + 0 ];
+
648 _texCoords[ _uniqueIndex*2 + 1 ] = vt[ ((vtI - 1) * 2) + 1 ];
+
649 } else if(groupTokens.size() == 2 && numSlashes == 2) {
+
650 int vnI = atoi(groupTokens[1].c_str());
+
651 if( vnI < 0 )
+
652 vnI = vnSeen + vnI + 1;
+
653
+
654 _normals[ _uniqueIndex*3 + 0 ] = vn[ ((vnI - 1) * 3) + 0 ];
+
655 _normals[ _uniqueIndex*3 + 1 ] = vn[ ((vnI - 1) * 3) + 1 ];
+
656 _normals[ _uniqueIndex*3 + 2 ] = vn[ ((vnI - 1) * 3) + 2 ];
+
657 } else if(groupTokens.size() == 3) {
+
658 int vtI = atoi(groupTokens[1].c_str());
+
659 if( vtI < 0 )
+
660 vtI = vtSeen + vtI + 1;
+
661
+
662 _texCoords[ _uniqueIndex*2 + 0 ] = vt[ ((vtI - 1) * 2) + 0 ];
+
663 _texCoords[ _uniqueIndex*2 + 1 ] = vt[ ((vtI - 1) * 2) + 1 ];
+
664
+
665 int vnI = atoi(groupTokens[2].c_str());
+
666 if( vnI < 0 )
+
667 vnI = vnSeen + vnI + 1;
+
668
+
669 _normals[ _uniqueIndex*3 + 0 ] = vn[ ((vnI - 1) * 3) + 0 ];
+
670 _normals[ _uniqueIndex*3 + 1 ] = vn[ ((vnI - 1) * 3) + 1 ];
+
671 _normals[ _uniqueIndex*3 + 2 ] = vn[ ((vnI - 1) * 3) + 2 ];
+
672 }
+
673
+
674 _uniqueIndex++;
+
675 } else {
+
676 //regardless, we always get a vertex index.
+
677 int vI = atoi(groupTokens[0].c_str());
+
678 if( vI < 0 )
+
679 vI = vSeen + vI + 1;
+
680
+
681 vertsTemp.push_back( v[ ((vI - 1) * 3) + 0 ] );
+
682 vertsTemp.push_back( v[ ((vI - 1) * 3) + 1 ] );
+
683 vertsTemp.push_back( v[ ((vI - 1) * 3) + 2 ] );
+
684
+
685 //based on combination of number of tokens and slashes, we can determine what we have.
+
686 if(groupTokens.size() == 2 && numSlashes == 1) {
+
687 int vtI = atoi(groupTokens[1].c_str());
+
688 if( vtI < 0 )
+
689 vtI = vtSeen + vtI + 1;
+
690
+
691 texCoordsTemp.push_back( vt[ ((vtI - 1) * 2) + 0 ] );
+
692 texCoordsTemp.push_back( vt[ ((vtI - 1) * 2) + 1 ] );
+
693 } else if(groupTokens.size() == 2 && numSlashes == 2) {
+
694 // should not occur if no normals
+
695 if (ERRORS) fprintf( stderr, "[.obj]: [WARN]: no vertex normals were specified, should not be trying to access values\n" );
+
696 } else if(groupTokens.size() == 3) {
+
697 int vtI = atoi(groupTokens[1].c_str());
+
698 if( vtI < 0 )
+
699 vtI = vtSeen + vtI + 1;
+
700
+
701 texCoordsTemp.push_back( vt[ ((vtI - 1) * 2) + 0 ] );
+
702 texCoordsTemp.push_back( vt[ ((vtI - 1) * 2) + 1 ] );
+
703
+
704 // should not occur if no normals
+
705 if (ERRORS) fprintf( stderr, "[.obj]: [WARN]: no vertex normals were specified, should not be trying to access values\n" );
+
706 }
+
707 }
+
708 uniqueV++;
+
709 }
+
710 }
+
711
+
712 for(GLuint i = 1; i < processedFaceTokens.size()-1; i++) {
+
713 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
+
714 _indices[ indicesSeen++ ] = uniqueCounts.find( processedFaceTokens[0] )->second;
+
715 _indices[ indicesSeen++ ] = uniqueCounts.find( processedFaceTokens[i] )->second;
+
716 _indices[ indicesSeen++ ] = uniqueCounts.find( processedFaceTokens[i+1] )->second;
+
717
+
718 _numIndices += 3;
+
719 } else {
+
720 int aI = uniqueCounts.find( processedFaceTokens[0] )->second;
+
721 int bI = uniqueCounts.find( processedFaceTokens[i] )->second;
+
722 int cI = uniqueCounts.find( processedFaceTokens[i+1] )->second;
+
723
+
724 glm::vec3 a( vertsTemp[aI*3 + 0], vertsTemp[aI*3 + 1], vertsTemp[aI*3 + 2] );
+
725 glm::vec3 b( vertsTemp[bI*3 + 0], vertsTemp[bI*3 + 1], vertsTemp[bI*3 + 2] );
+
726 glm::vec3 c( vertsTemp[cI*3 + 0], vertsTemp[cI*3 + 1], vertsTemp[cI*3 + 2] );
+
727
+
728 glm::vec3 ab = b - a; glm::vec3 ac = c - a;
+
729 glm::vec3 ba = a - b; glm::vec3 bc = c - b;
+
730 glm::vec3 ca = a - c; glm::vec3 cb = b - c;
+
731
+
732 glm::vec3 aN = glm::normalize( glm::cross( ab, ac ) );
+
733 glm::vec3 bN = glm::normalize( glm::cross( bc, ba ) );
+
734 glm::vec3 cN = glm::normalize( glm::cross( ca, cb ) );
+
735
+
736 _vertices[ _uniqueIndex*3 + 0 ] = a.x;
+
737 _vertices[ _uniqueIndex*3 + 1 ] = a.y;
+
738 _vertices[ _uniqueIndex*3 + 2 ] = a.z;
+
739
+
740 _normals[ _uniqueIndex*3 + 0 ] = aN.x;
+
741 _normals[ _uniqueIndex*3 + 1 ] = aN.y;
+
742 _normals[ _uniqueIndex*3 + 2 ] = aN.z;
+
743
+
744 if( _hasVertexTexCoords ) {
+
745 _texCoords[ _uniqueIndex*2 + 0 ] = texCoordsTemp[ aI*2 + 0 ];
+
746 _texCoords[ _uniqueIndex*2 + 1 ] = texCoordsTemp[ aI*2 + 1 ];
+
747 }
+
748
+
749 _indices[ _numIndices++ ] = _uniqueIndex++;
+
750 indicesSeen++;
+
751
+
752 _vertices[ _uniqueIndex*3 + 0 ] = b.x;
+
753 _vertices[ _uniqueIndex*3 + 1 ] = b.y;
+
754 _vertices[ _uniqueIndex*3 + 2 ] = b.z;
+
755
+
756 _normals[ _uniqueIndex*3 + 0 ] = bN.x;
+
757 _normals[ _uniqueIndex*3 + 1 ] = bN.y;
+
758 _normals[ _uniqueIndex*3 + 2 ] = bN.z;
+
759
+
760 if( _hasVertexTexCoords ) {
+
761 _texCoords[ _uniqueIndex*2 + 0 ] = texCoordsTemp[ bI*2 + 0 ];
+
762 _texCoords[ _uniqueIndex*2 + 1 ] = texCoordsTemp[ bI*2 + 1 ];
+
763 }
+
764
+
765 _indices[ _numIndices++ ] = _uniqueIndex++;
+
766 indicesSeen++;
+
767
+
768 _vertices[ _uniqueIndex*3 + 0 ] = c.x;
+
769 _vertices[ _uniqueIndex*3 + 1 ] = c.y;
+
770 _vertices[ _uniqueIndex*3 + 2 ] = c.z;
+
771
+
772 _normals[ _uniqueIndex*3 + 0 ] = cN.x;
+
773 _normals[ _uniqueIndex*3 + 1 ] = cN.y;
+
774 _normals[ _uniqueIndex*3 + 2 ] = cN.z;
+
775
+
776 if( _hasVertexTexCoords ) {
+
777 _texCoords[ _uniqueIndex*2 + 0 ] = texCoordsTemp[ cI*2 + 0 ];
+
778 _texCoords[ _uniqueIndex*2 + 1 ] = texCoordsTemp[ cI*2 + 1 ];
+
779 }
+
780
+
781 _indices[ _numIndices++ ] = _uniqueIndex++;
+
782 indicesSeen++;
+
783 }
+
784 }
+
785
+
786 } else {
+
787 if (INFO) printf( "[.obj]: ignoring line: %s\n", line.c_str() );
+
788 }
+
789
+
790 if (INFO) {
+
791 progressCounter++;
+
792 if( progressCounter % 5000 == 0 ) {
+
793 printf("\33[2K\r");
+
794 switch( progressCounter ) {
+
795 case 5000: printf("[.obj]: parsing %s...\\", _filename); break;
+
796 case 10000: printf("[.obj]: parsing %s...|", _filename); break;
+
797 case 15000: printf("[.obj]: parsing %s.../", _filename); break;
+
798 case 20000: printf("[.obj]: parsing %s...-", _filename); break;
+
799 }
+
800 fflush(stdout);
+
801 }
+
802 if( progressCounter == 20000 )
+
803 progressCounter = 0;
+
804 }
+
805 }
+
806
+
807 in.close();
+
808
+
809 if (INFO) {
+
810 printf( "\33[2K\r" );
+
811 printf( "[.obj]: parsing %s...done!\n", _filename );
+
812 }
+
813
+
814 _materialIndexStartStop.find( currentMaterial )->second.back().second = indicesSeen - 1;
+
815
+
816 glBindVertexArray( _vaod );
+
817 glBindBuffer( GL_ARRAY_BUFFER, _vbods[0] );
+
818 glBufferData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 8, NULL, GL_STATIC_DRAW );
+
819 glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * _uniqueIndex * 3, _vertices );
+
820 glBufferSubData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 3, sizeof(GLfloat) * _uniqueIndex * 3, _normals );
+
821 glBufferSubData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 6, sizeof(GLfloat) * _uniqueIndex * 2, _texCoords );
+
822
+
823 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, _vbods[1] );
+
824 glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * indicesSeen, _indices, GL_STATIC_DRAW );
+
825
+
826 time(&end);
+
827 double seconds = difftime( end, start );
+
828
+
829 if (INFO) {
+
830 printf( "[.obj]: Completed in %.3fs\n", seconds );
+
831 printf( "[.obj]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=- \n\n", _filename );
+
832 }
+
833
+
834 return result;
+
835}
+
836
+
837inline bool CSCI441::ModelLoader::_loadMTLFile( const char* mtlFilename, bool INFO, bool ERRORS ) {
+
838 bool result = true;
+
839
+
840 if (INFO) printf( "[.mtl]: -*-*-*-*-*-*-*- BEGIN %s Info -*-*-*-*-*-*-*-\n", mtlFilename );
+
841
+
842 std::string line;
+
843 std::string path;
+
844 if( strstr( _filename, "/" ) != NULL ) {
+
845 path = std::string( _filename ).substr( 0, std::string(_filename).find_last_of("/")+1 );
+
846 } else {
+
847 path = "./";
+
848 }
+
849
+
850 std::ifstream in;
+
851 in.open( mtlFilename );
+
852 if( !in.is_open() ) {
+
853 std::string folderMtlFile = path + mtlFilename;
+
854 in.open( folderMtlFile.c_str() );
+
855 if( !in.is_open() ) {
+
856 if (ERRORS) fprintf( stderr, "[.mtl]: [ERROR]: could not open material file: %s\n", mtlFilename );
+
857 if ( INFO ) printf( "[.mtl]: -*-*-*-*-*-*-*- END %s Info -*-*-*-*-*-*-*-\n", mtlFilename );
+
858 return false;
+
859 }
+
860 }
+
861
+
862 CSCI441_INTERNAL::ModelMaterial* currentMaterial = NULL;
+
863 std::string materialName;
+
864
+
865 unsigned char *textureData = NULL;
+
866 unsigned char *maskData = NULL;
+
867 unsigned char *fullData;
+
868 int texWidth, texHeight, textureChannels = 1, maskChannels = 1;
+
869 GLuint textureHandle = 0;
+
870
+
871 std::map< std::string, GLuint > imageHandles;
+
872
+
873 int numMaterials = 0;
+
874
+
875 while( getline( in, line ) ) {
+
876 if( line.length() > 1 && line.at(0) == '\t' )
+
877 line = line.substr( 1 );
+
878 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
+
879
+
880 std::vector< std::string > tokens = _tokenizeString( line, " /" );
+
881 if( tokens.size() < 1 ) continue;
+
882
+
883 //the line should have a single character that lets us know if it's a...
+
884 if( !tokens[0].compare( "#" ) ) { // comment
+
885 } else if( !tokens[0].compare( "newmtl" ) ) { //new material
+
886 if (INFO) printf( "[.mtl]: Parsing material %s properties\n", tokens[1].c_str() );
+
887 currentMaterial = new CSCI441_INTERNAL::ModelMaterial();
+
888 materialName = tokens[1];
+
889 _materials.insert( std::pair<std::string, CSCI441_INTERNAL::ModelMaterial*>( materialName, currentMaterial ) );
+
890
+
891 textureHandle = 0;
+
892 textureData = NULL;
+
893 maskData = NULL;
+
894 textureChannels = 1;
+
895 maskChannels = 1;
+
896
+
897 numMaterials++;
+
898 } else if( !tokens[0].compare( "Ka" ) ) { // ambient component
+
899 currentMaterial->ambient[0] = atof( tokens[1].c_str() );
+
900 currentMaterial->ambient[1] = atof( tokens[2].c_str() );
+
901 currentMaterial->ambient[2] = atof( tokens[3].c_str() );
+
902 } else if( !tokens[0].compare( "Kd" ) ) { // diffuse component
+
903 currentMaterial->diffuse[0] = atof( tokens[1].c_str() );
+
904 currentMaterial->diffuse[1] = atof( tokens[2].c_str() );
+
905 currentMaterial->diffuse[2] = atof( tokens[3].c_str() );
+
906 } else if( !tokens[0].compare( "Ks" ) ) { // specular component
+
907 currentMaterial->specular[0] = atof( tokens[1].c_str() );
+
908 currentMaterial->specular[1] = atof( tokens[2].c_str() );
+
909 currentMaterial->specular[2] = atof( tokens[3].c_str() );
+
910 } else if( !tokens[0].compare( "Ke" ) ) { // emissive component
+
911 currentMaterial->emissive[0] = atof( tokens[1].c_str() );
+
912 currentMaterial->emissive[1] = atof( tokens[2].c_str() );
+
913 currentMaterial->emissive[2] = atof( tokens[3].c_str() );
+
914 } else if( !tokens[0].compare( "Ns" ) ) { // shininess component
+
915 currentMaterial->shininess = atof( tokens[1].c_str() );
+
916 } else if( !tokens[0].compare( "Tr" )
+
917 || !tokens[0].compare( "d" ) ) { // transparency component - Tr or d can be used depending on the format
+
918 currentMaterial->ambient[3] = atof( tokens[1].c_str() );
+
919 currentMaterial->diffuse[3] = atof( tokens[1].c_str() );
+
920 currentMaterial->specular[3] = atof( tokens[1].c_str() );
+
921 } else if( !tokens[0].compare( "illum" ) ) { // illumination type component
+
922 // TODO ?
+
923 } else if( !tokens[0].compare( "map_Kd" ) ) { // diffuse color texture map
+
924 if( imageHandles.find( tokens[1] ) != imageHandles.end() ) {
+
925 // _textureHandles->insert( pair< string, GLuint >( materialName, imageHandles.find( tokens[1] )->second ) );
+
926 currentMaterial->map_Kd = imageHandles.find( tokens[1] )->second;
+
927 } else {
+
928 stbi_set_flip_vertically_on_load(true);
+
929 textureData = stbi_load( tokens[1].c_str(), &texWidth, &texHeight, &textureChannels, 0 );
+
930 if( !textureData ) {
+
931 std::string folderName = path + tokens[1];
+
932 textureData = stbi_load( folderName.c_str(), &texWidth, &texHeight, &textureChannels, 0 );
+
933 }
+
934
+
935 if( !textureData ) {
+
936 if (ERRORS) fprintf( stderr, "[.mtl]: [ERROR]: File Not Found: %s\n", tokens[1].c_str() );
+
937 } else {
+
938 if (INFO) printf( "[.mtl]: TextureMap:\t%s\tSize: %dx%d\tColors: %d\n", tokens[1].c_str(), texWidth, texHeight, textureChannels );
+
939
+
940 if( maskData == NULL ) {
+
941 if( textureHandle == 0 ) {
+
942 glGenTextures( 1, &textureHandle );
+
943 imageHandles.insert( std::pair<std::string, GLuint>( tokens[1], textureHandle ) );
+
944 }
+
945
+
946 glBindTexture( GL_TEXTURE_2D, textureHandle );
+
947
+
948 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
949 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
950
+
951 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+
952 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
953
+
954 GLenum colorSpace = GL_RGB;
+
955 if( textureChannels == 4 )
+
956 colorSpace = GL_RGBA;
+
957 glTexImage2D( GL_TEXTURE_2D, 0, colorSpace, texWidth, texHeight, 0, colorSpace, GL_UNSIGNED_BYTE, textureData );
+
958
+
959 currentMaterial->map_Kd = textureHandle;
+
960 } else {
+
961 fullData = CSCI441_INTERNAL::createTransparentTexture( textureData, maskData, texWidth, texHeight, textureChannels, maskChannels );
+
962
+
963 if( textureHandle == 0 ) {
+
964 glGenTextures( 1, &textureHandle );
+
965 imageHandles.insert( std::pair<std::string, GLuint>( tokens[1], textureHandle ) );
+
966 }
+
967
+
968 glBindTexture( GL_TEXTURE_2D, textureHandle );
+
969
+
970 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
971 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
972
+
973 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+
974 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
975
+
976 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, fullData );
+
977
+
978 delete fullData;
+
979
+
980 currentMaterial->map_Kd = textureHandle;
+
981 }
+
982 }
+
983 }
+
984 } else if( !tokens[0].compare( "map_d" ) ) { // alpha texture map
+
985 if( imageHandles.find( tokens[1] ) != imageHandles.end() ) {
+
986 // _textureHandles->insert( pair< string, GLuint >( materialName, imageHandles.find( tokens[1] )->second ) );
+
987 currentMaterial->map_d = imageHandles.find( tokens[1] )->second;
+
988 } else {
+
989 stbi_set_flip_vertically_on_load(true);
+
990 maskData = stbi_load( tokens[1].c_str(), &texWidth, &texHeight, &textureChannels, 0 );
+
991 if( !textureData ) {
+
992 std::string folderName = path + tokens[1];
+
993 maskData = stbi_load( folderName.c_str(), &texWidth, &texHeight, &textureChannels, 0 );
+
994 }
+
995
+
996 if( !maskData ) {
+
997 if (ERRORS) fprintf( stderr, "[.mtl]: [ERROR]: File Not Found: %s\n", tokens[1].c_str() );
+
998 } else {
+
999 if (INFO) printf( "[.mtl]: AlphaMap: \t%s\tSize: %dx%d\tColors: %d\n", tokens[1].c_str(), texWidth, texHeight, maskChannels );
+
1000
+
1001 if( textureData != NULL ) {
+
1002 fullData = CSCI441_INTERNAL::createTransparentTexture( textureData, maskData, texWidth, texHeight, textureChannels, maskChannels );
+
1003
+
1004 if( textureHandle == 0 )
+
1005 glGenTextures( 1, &textureHandle );
+
1006
+
1007 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+
1008 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+
1009
+
1010 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
+
1011 glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
+
1012
+
1013 glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, texWidth, texHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, fullData );
+
1014
+
1015 delete fullData;
+
1016 }
+
1017 }
+
1018 }
+
1019 } else if( !tokens[0].compare( "map_Ka" ) ) { // ambient color texture map
+
1020
+
1021 } else if( !tokens[0].compare( "map_Ks" ) ) { // specular color texture map
+
1022
+
1023 } else if( !tokens[0].compare( "map_Ns" ) ) { // specular highlight map (shininess map)
+
1024
+
1025 } else if( !tokens[0].compare( "Ni" ) ) { // optical density / index of refraction
+
1026
+
1027 } else if( !tokens[0].compare( "Tf" ) ) { // transmission filter
+
1028
+
1029 } else if( !tokens[0].compare( "bump" )
+
1030 || !tokens[0].compare( "map_bump" ) ) { // bump map
+
1031
+
1032 } else {
+
1033 if (INFO) printf( "[.mtl]: ignoring line: %s\n", line.c_str() );
+
1034 }
+
1035 }
+
1036
+
1037 in.close();
+
1038
+
1039 if ( INFO ) {
+
1040 printf( "[.mtl]: Materials:\t%d\n", numMaterials );
+
1041 printf( "[.mtl]: -*-*-*-*-*-*-*- END %s Info -*-*-*-*-*-*-*-\n", mtlFilename );
+
1042 }
+
1043
+
1044 return result;
+
1045}
+
1046
+
1047inline bool CSCI441::ModelLoader::_loadOFFFile( bool INFO, bool ERRORS ) {
+
1048 bool result = true;
+
1049
+
1050 if (INFO ) printf( "[.off]: -=-=-=-=-=-=-=- BEGIN %s Info -=-=-=-=-=-=-=-\n", _filename );
+
1051
+
1052 time_t start, end;
+
1053 time(&start);
+
1054
+
1055 std::ifstream in( _filename );
+
1056 if( !in.is_open() ) {
+
1057 if (ERRORS) fprintf( stderr, "[.off]: [ERROR]: Could not open \"%s\"\n", _filename );
+
1058 if ( INFO ) printf( "[.off]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
+
1059 return false;
+
1060 }
+
1061
+
1062 GLuint numVertices = 0, numFaces = 0, numTriangles = 0;
+
1063 GLfloat minX = 999999.0f, maxX = -999999.0f, minY = 999999.0f, maxY = -999999.0f, minZ = 999999.0f, maxZ = -999999.0f;
+
1064 std::string line;
+
1065
+
1066 enum OFF_FILE_STATE { HEADER, VERTICES, FACES, DONE };
+
1067
+
1068 OFF_FILE_STATE fileState = HEADER;
+
1069
+
1070 GLuint vSeen = 0, fSeen = 0;
+
1071
+
1072 while( getline( in, line ) ) {
+
1073 if( line.length() > 1 && line.at(0) == '\t' )
+
1074 line = line.substr( 1 );
+
1075 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
+
1076
+
1077 std::vector< std::string > tokens = _tokenizeString( line, " \t" );
+
1078 if( tokens.size() < 1 ) continue;
+
1079
+
1080 //the line should have a single character that lets us know if it's a...
+
1081 if( !tokens[0].compare( "#" ) || tokens[0].find_first_of("#") == 0 ) { // comment ignore
+
1082 } else if( fileState == HEADER ) {
+
1083 if( !tokens[0].compare( "OFF" ) ) { // denotes OFF File type
+
1084 } else {
+
1085 if( tokens.size() != 3 ) {
+
1086 if (ERRORS) fprintf( stderr, "[.off]: [ERROR]: Malformed OFF file. # vertices, faces, edges not properly specified\n" );
+
1087 if ( INFO ) printf( "[.off]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
+
1088 in.close();
+
1089 return false;
+
1090 }
+
1091 // read in number of expected vertices, faces, and edges
+
1092 numVertices = atoi( tokens[0].c_str() );
+
1093 numFaces = atoi( tokens[1].c_str() );
+
1094
+
1095 // ignore tokens[2] - number of edges -- unnecessary information
+
1096 // numEdges = atoi( tokens[2].c_str() );
+
1097
+
1098 fileState = VERTICES;
+
1099 }
+
1100 } else if( fileState == VERTICES ) {
+
1101 // read in x y z vertex location
+
1102 GLfloat x = (GLfloat) atof( tokens[0].c_str() ),
+
1103 y = (GLfloat) atof( tokens[1].c_str() ),
+
1104 z = (GLfloat) atof( tokens[2].c_str() );
+
1105
+
1106 if( x < minX ) minX = x;
+
1107 if( x > maxX ) maxX = x;
+
1108 if( y < minY ) minY = y;
+
1109 if( y > maxY ) maxY = y;
+
1110 if( z < minZ ) minZ = z;
+
1111 if( z > maxZ ) maxZ = z;
+
1112
+
1113 vSeen++;
+
1114 if( vSeen == numVertices )
+
1115 fileState = FACES;
+
1116 } else if( fileState == FACES ) {
+
1117 GLuint numberOfVerticesInFace = atoi( tokens[0].c_str() );
+
1118
+
1119 numTriangles += numberOfVerticesInFace - 3 + 1;
+
1120
+
1121 if( fSeen == numFaces )
+
1122 fileState = DONE;
+
1123 } else {
+
1124 if (INFO) printf( "[.off]: unknown file state: %d\n", fileState );
+
1125 }
+
1126 }
+
1127 in.close();
+
1128
+
1129 if (INFO) {
+
1130 printf( "\33[2K\r" );
+
1131 printf( "[.off]: scanning %s...done!\n", _filename );
+
1132 printf( "[.off]: ------------\n" );
+
1133 printf( "[.off]: Model Stats:\n" );
+
1134 printf( "[.off]: Vertices: \t%u\tNormals: \t%u\tTex Coords:\t%u\n", numVertices, 0, 0 );
+
1135 printf( "[.off]: Faces: \t%u\tTriangles: \t%u\n", numFaces, numTriangles );
+
1136 printf( "[.off]: Dimensions:\t(%f, %f, %f)\n", (maxX - minX), (maxY - minY), (maxZ - minZ) );
+
1137 }
+
1138
+
1139 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
+
1140 if (INFO && !_hasVertexNormals)
+
1141 printf( "[.off]: [WARN]: No vertex normals exist on model. To autogenerate vertex\n\tnormals, call CSCI441::ModelLoader::enableAutoGenerateNormals()\n\tprior to loading the model file.\n" );
+
1142 _vertices = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 3);
+
1143 _texCoords = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 2);
+
1144 _normals = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 3);
+
1145 _indices = (GLuint*)malloc(sizeof(GLuint) * numTriangles * 3);
+
1146 } else {
+
1147 if (INFO) printf( "[.off]: No vertex normals exist on model, vertex normals will be autogenerated\n" );
+
1148 _vertices = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 3);
+
1149 _texCoords = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 2);
+
1150 _normals = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 3);
+
1151 _indices = (GLuint*)malloc(sizeof(GLuint) * numTriangles * 3);
+
1152 }
+
1153
+
1154 std::vector<GLfloat> vertsTemp;
+
1155
+
1156 if (INFO) printf( "[.off]: ------------\n" );
+
1157
+
1158 in.open( _filename );
+
1159
+
1160 _uniqueIndex = 0;
+
1161 _numIndices = 0;
+
1162 vSeen = 0;
+
1163
+
1164 fileState = HEADER;
+
1165
+
1166 int progressCounter = 0;
+
1167
+
1168 while( getline( in, line ) ) {
+
1169 if( line.length() > 1 && line.at(0) == '\t' )
+
1170 line = line.substr( 1 );
+
1171 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
+
1172
+
1173 std::vector< std::string > tokens = _tokenizeString( line, " \t" );
+
1174 if( tokens.size() < 1 ) continue;
+
1175
+
1176 //the line should have a single character that lets us know if it's a...
+
1177 if( !tokens[0].compare( "#" ) || tokens[0].find_first_of("#") == 0 ) { // comment ignore
+
1178 } else if( fileState == HEADER ) {
+
1179 if( !tokens[0].compare( "OFF" ) ) { // denotes OFF File type
+
1180 } else {
+
1181
+
1182 // end of OFF Header reached
+
1183 fileState = VERTICES;
+
1184 }
+
1185 } else if( fileState == VERTICES ) {
+
1186 // read in x y z vertex location
+
1187 GLfloat x = (GLfloat) atof( tokens[0].c_str() ),
+
1188 y = (GLfloat) atof( tokens[1].c_str() ),
+
1189 z = (GLfloat) atof( tokens[2].c_str() );
+
1190
+
1191 // check if RGB(A) color information is associated with vertex
+
1192 if( tokens.size() == 6 || tokens.size() == 7 ) {
+
1193 // TODO: handle RGBA color info
+
1194 // GLfloat r = (GLfloat) atof( tokens[3].c_str() ),
+
1195 // g = (GLfloat) atof( tokens[4].c_str() ),
+
1196 // b = (GLfloat) atof( tokens[5].c_str() ),
+
1197 // a = 1.0f;
+
1198 //
+
1199 // if( tokens.size() == 7 )
+
1200 // a = atof( tokens[6].c_str() );
+
1201 }
+
1202
+
1203 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
+
1204 _vertices[ _uniqueIndex*3 + 0 ] = x;
+
1205 _vertices[ _uniqueIndex*3 + 1 ] = y;
+
1206 _vertices[ _uniqueIndex*3 + 2 ] = z;
+
1207
+
1208 _uniqueIndex++;
+
1209 } else {
+
1210 vertsTemp.push_back( x );
+
1211 vertsTemp.push_back( y );
+
1212 vertsTemp.push_back( z );
+
1213
+
1214 vSeen++;
+
1215 }
+
1216 // if all vertices have been read in, move on to faces
+
1217 if( _uniqueIndex == numVertices || vSeen == numVertices )
+
1218 fileState = FACES;
+
1219 } else if( fileState == FACES ) {
+
1220 GLuint numberOfVerticesInFace = atoi( tokens[0].c_str() );
+
1221
+
1222 // read in each vertex index of the face
+
1223 for(GLuint i = 2; i <= numberOfVerticesInFace - 1; i++) {
+
1224 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
+
1225 int fanRoot = atoi( tokens[1].c_str() );
+
1226 int fanA = atoi( tokens[i].c_str() );
+
1227 int fanB = atoi( tokens[i+1].c_str() );
+
1228
+
1229 if( fanRoot < 0 ) fanRoot = numVertices + fanRoot + 1;
+
1230 if( fanA < 0 ) fanA = numVertices + fanA + 1;
+
1231 if( fanB < 0 ) fanB = numVertices + fanB + 1;
+
1232
+
1233 //regardless, we always get a vertex index.
+
1234 _indices[ _numIndices++ ] = fanRoot;
+
1235 _indices[ _numIndices++ ] = fanA;
+
1236 _indices[ _numIndices++ ] = fanB;
+
1237 } else {
+
1238 int aI = atoi( tokens[1].c_str() );
+
1239 int bI = atoi( tokens[i].c_str() );
+
1240 int cI = atoi( tokens[i+1].c_str() );
+
1241
+
1242 if( aI < 0 ) aI = numVertices + aI + 1;
+
1243 if( bI < 0 ) bI = numVertices + bI + 1;
+
1244 if( cI < 0 ) cI = numVertices + cI + 1;
+
1245
+
1246 glm::vec3 a( vertsTemp[aI*3 + 0], vertsTemp[aI*3 + 1], vertsTemp[aI*3 + 2] );
+
1247 glm::vec3 b( vertsTemp[bI*3 + 0], vertsTemp[bI*3 + 1], vertsTemp[bI*3 + 2] );
+
1248 glm::vec3 c( vertsTemp[cI*3 + 0], vertsTemp[cI*3 + 1], vertsTemp[cI*3 + 2] );
+
1249
+
1250 glm::vec3 ab = b - a; glm::vec3 ac = c - a;
+
1251 glm::vec3 ba = a - b; glm::vec3 bc = c - b;
+
1252 glm::vec3 ca = a - c; glm::vec3 cb = b - c;
+
1253
+
1254 glm::vec3 aN = glm::normalize( glm::cross( ab, ac ) );
+
1255 glm::vec3 bN = glm::normalize( glm::cross( bc, ba ) );
+
1256 glm::vec3 cN = glm::normalize( glm::cross( ca, cb ) );
+
1257
+
1258 _vertices[ _uniqueIndex*3 + 0 ] = a.x;
+
1259 _vertices[ _uniqueIndex*3 + 1 ] = a.y;
+
1260 _vertices[ _uniqueIndex*3 + 2 ] = a.z;
+
1261
+
1262 _normals[ _uniqueIndex*3 + 0 ] = aN.x;
+
1263 _normals[ _uniqueIndex*3 + 1 ] = aN.y;
+
1264 _normals[ _uniqueIndex*3 + 2 ] = aN.z;
+
1265
+
1266 _indices[ _numIndices++ ] = _uniqueIndex++;
+
1267
+
1268 _vertices[ _uniqueIndex*3 + 0 ] = b.x;
+
1269 _vertices[ _uniqueIndex*3 + 1 ] = b.y;
+
1270 _vertices[ _uniqueIndex*3 + 2 ] = b.z;
+
1271
+
1272 _normals[ _uniqueIndex*3 + 0 ] = bN.x;
+
1273 _normals[ _uniqueIndex*3 + 1 ] = bN.y;
+
1274 _normals[ _uniqueIndex*3 + 2 ] = bN.z;
+
1275
+
1276 _indices[ _numIndices++ ] = _uniqueIndex++;
+
1277
+
1278 _vertices[ _uniqueIndex*3 + 0 ] = c.x;
+
1279 _vertices[ _uniqueIndex*3 + 1 ] = c.y;
+
1280 _vertices[ _uniqueIndex*3 + 2 ] = c.z;
+
1281
+
1282 _normals[ _uniqueIndex*3 + 0 ] = cN.x;
+
1283 _normals[ _uniqueIndex*3 + 1 ] = cN.y;
+
1284 _normals[ _uniqueIndex*3 + 2 ] = cN.z;
+
1285
+
1286 _indices[ _numIndices++ ] = _uniqueIndex++;
+
1287 }
+
1288 }
+
1289
+
1290 // check if RGB(A) color information is associated with face
+
1291 // TODO: handle color info
+
1292 //some local variables to hold the vertex+attribute indices we read in.
+
1293 //we do it this way because we'll have to split quads into triangles ourselves.
+
1294 // GLfloat color[4] = {-1,-1,-1,1};
+
1295 // if( tokens.size() == numberOfVerticesInFace + 4 || tokens.size() == numberOfVerticesInFace + 5 ) {
+
1296 // color[0] = atof( tokens[numberOfVerticesInFace + 1].c_str() );
+
1297 // color[1] = atof( tokens[numberOfVerticesInFace + 2].c_str() );
+
1298 // color[2] = atof( tokens[numberOfVerticesInFace + 3].c_str() );
+
1299 // color[3] = 1;
+
1300 //
+
1301 // if( tokens.size() == numberOfVerticesInFace + 5 )
+
1302 // color[3] = atof( tokens[numberOfVerticesInFace + 4].c_str() );
+
1303 // }
+
1304
+
1305 } else {
+
1306
+
1307 }
+
1308
+
1309 if (INFO) {
+
1310 progressCounter++;
+
1311 if( progressCounter % 5000 == 0 ) {
+
1312 printf("\33[2K\r");
+
1313 switch( progressCounter ) {
+
1314 case 5000: printf("[.off]: parsing %s...\\", _filename); break;
+
1315 case 10000: printf("[.off]: parsing %s...|", _filename); break;
+
1316 case 15000: printf("[.off]: parsing %s.../", _filename); break;
+
1317 case 20000: printf("[.off]: parsing %s...-", _filename); break;
+
1318 }
+
1319 fflush(stdout);
+
1320 }
+
1321 if( progressCounter == 20000 )
+
1322 progressCounter = 0;
+
1323 }
+
1324 }
+
1325 in.close();
+
1326
+
1327 glBindVertexArray( _vaod );
+
1328 glBindBuffer( GL_ARRAY_BUFFER, _vbods[0] );
+
1329 glBufferData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 8, NULL, GL_STATIC_DRAW );
+
1330 glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * _uniqueIndex * 3, _vertices );
+
1331 glBufferSubData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 3, sizeof(GLfloat) * _uniqueIndex * 3, _normals );
+
1332 glBufferSubData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 6, sizeof(GLfloat) * _uniqueIndex * 2, _texCoords );
+
1333
+
1334 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, _vbods[1] );
+
1335 glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * _numIndices, _indices, GL_STATIC_DRAW );
+
1336
+
1337 time(&end);
+
1338 double seconds = difftime( end, start );
+
1339
+
1340 if (INFO) {
+
1341 printf( "\33[2K\r" );
+
1342 printf( "[.off]: parsing %s...done! (Time: %.1fs)\n", _filename, seconds );
+
1343 printf( "[.off]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
+
1344 }
+
1345
+
1346 return result;
+
1347}
+
1348
+
1349// notes on PLY format: http://paulbourke.net/dataformats/ply/
+
1350inline bool CSCI441::ModelLoader::_loadPLYFile( bool INFO, bool ERRORS ) {
+
1351 bool result = true;
+
1352
+
1353 if (INFO ) printf( "[.ply]: -=-=-=-=-=-=-=- BEGIN %s Info -=-=-=-=-=-=-=-\n", _filename );
+
1354
+
1355 time_t start, end;
+
1356 time(&start);
+
1357
+
1358 std::ifstream in( _filename );
+
1359 if( !in.is_open() ) {
+
1360 if (ERRORS) fprintf( stderr, "[.ply]: [ERROR]: Could not open \"%s\"\n", _filename );
+
1361 if ( INFO ) printf( "[.ply]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
+
1362 return false;
+
1363 }
+
1364
+
1365 GLuint numVertices = 0, numFaces = 0, numTriangles = 0, numMaterials = 0;
+
1366 GLfloat minX = 999999.0f, maxX = -999999.0f, minY = 999999.0f, maxY = -999999.0f, minZ = 999999.0f, maxZ = -999999.0f;
+
1367 std::string line;
+
1368
+
1369 enum PLY_FILE_STATE { HEADER, VERTICES, FACES, MATERIALS };
+
1370 enum PLY_ELEMENT_TYPE { NONE, VERTEX, FACE, MATERIAL };
+
1371
+
1372 PLY_FILE_STATE fileState = HEADER;
+
1373 PLY_ELEMENT_TYPE elemType = NONE;
+
1374
+
1375 GLuint progressCounter = 0;
+
1376 GLuint vSeen = 0;
+
1377
+
1378 while( getline( in, line ) ) {
+
1379 if( line.length() > 1 && line.at(0) == '\t' )
+
1380 line = line.substr( 1 );
+
1381 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
+
1382
+
1383 std::vector< std::string > tokens = _tokenizeString( line, " \t" );
+
1384
+
1385 if( tokens.size() < 1 ) continue;
+
1386
+
1387 //the line should have a single character that lets us know if it's a...
+
1388 if( !tokens[0].compare( "comment" ) ) { // comment ignore
+
1389 } else if( fileState == HEADER ) {
+
1390 if( !tokens[0].compare( "ply" ) ) { // denotes ply File type
+
1391 } else if( !tokens[0].compare( "format" ) ) {
+
1392 if( tokens[1].compare( "ascii" ) ) {
+
1393 if (ERRORS) fprintf( stderr, "[.ply]: [ERROR]: File \"%s\" not ASCII format\n", _filename );
+
1394 if ( INFO ) printf( "[.ply]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
+
1395 in.close();
+
1396 return false;
+
1397 }
+
1398 } else if( !tokens[0].compare( "element" ) ) { // an element (vertex, face, material)
+
1399 if( !tokens[1].compare( "vertex" ) ) {
+
1400 numVertices = atoi( tokens[2].c_str() );
+
1401 elemType = VERTEX;
+
1402 } else if( !tokens[1].compare( "face" ) ) {
+
1403 numFaces = atoi( tokens[2].c_str() );
+
1404 elemType = FACE;
+
1405 } else if( !tokens[1].compare( "edge" ) ) {
+
1406
+
1407 } else if( !tokens[1].compare( "material" ) ) {
+
1408 numMaterials = atoi( tokens[2].c_str() );
+
1409 elemType = MATERIAL;
+
1410 } else {
+
1411
+
1412 }
+
1413 } else if( !tokens[0].compare( "property" ) ) {
+
1414 if( elemType == VERTEX ) {
+
1415
+
1416 } else if( elemType == FACE ) {
+
1417
+
1418 } else if( elemType == MATERIAL ) {
+
1419
+
1420 }
+
1421 } else if( !tokens[0].compare( "end_header" ) ) { // end of the header section
+
1422 fileState = VERTICES;
+
1423 }
+
1424 } else if( fileState == VERTICES ) {
+
1425 // read in x y z vertex location
+
1426 GLfloat x = (GLfloat) atof( tokens[0].c_str() ),
+
1427 y = (GLfloat) atof( tokens[1].c_str() ),
+
1428 z = (GLfloat) atof( tokens[2].c_str() );
+
1429
+
1430 if( x < minX ) minX = x;
+
1431 if( x > maxX ) maxX = x;
+
1432 if( y < minY ) minY = y;
+
1433 if( y > maxY ) maxY = y;
+
1434 if( z < minZ ) minZ = z;
+
1435 if( z > maxZ ) maxZ = z;
+
1436
+
1437 vSeen++;
+
1438 // if all vertices have been read in, move on to faces
+
1439 if( vSeen == numVertices )
+
1440 fileState = FACES;
+
1441 } else if( fileState == FACES ) {
+
1442 GLuint numberOfVerticesInFace = atoi( tokens[0].c_str() );
+
1443 numTriangles += numberOfVerticesInFace - 3 + 1;
+
1444 } else {
+
1445 if (INFO) printf( "[.ply]: unknown file state: %d\n", fileState );
+
1446 }
+
1447
+
1448 if (INFO) {
+
1449 progressCounter++;
+
1450 if( progressCounter % 5000 == 0 ) {
+
1451 printf("\33[2K\r");
+
1452 switch( progressCounter ) {
+
1453 case 5000: printf("[.ply]: scanning %s...\\", _filename); break;
+
1454 case 10000: printf("[.ply]: scanning %s...|", _filename); break;
+
1455 case 15000: printf("[.ply]: scanning %s.../", _filename); break;
+
1456 case 20000: printf("[.ply]: scanning %s...-", _filename); break;
+
1457 }
+
1458 fflush(stdout);
+
1459 }
+
1460 if( progressCounter == 20000 )
+
1461 progressCounter = 0;
+
1462 }
+
1463 }
+
1464 in.close();
+
1465
+
1466 if (INFO) {
+
1467 printf( "\33[2K\r" );
+
1468 printf( "[.ply]: scanning %s...done!\n", _filename );
+
1469 printf( "[.ply]: ------------\n" );
+
1470 printf( "[.ply]: Model Stats:\n" );
+
1471 printf( "[.ply]: Vertices: \t%u\tNormals: \t%u\tTex Coords:\t%u\n", numVertices, 0, 0 );
+
1472 printf( "[.ply]: Faces: \t%u\tTriangles: \t%u\n", numFaces, numTriangles );
+
1473 printf( "[.ply]: Dimensions:\t(%f, %f, %f)\n", (maxX - minX), (maxY - minY), (maxZ - minZ) );
+
1474 }
+
1475
+
1476 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
+
1477 if (INFO && !_hasVertexNormals)
+
1478 printf( "[.ply]: [WARN]: No vertex normals exist on model. To autogenerate vertex\n\tnormals, call CSCI441::ModelLoader::enableAutoGenerateNormals()\n\tprior to loading the model file.\n" );
+
1479 _vertices = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 3);
+
1480 _texCoords = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 2);
+
1481 _normals = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 3);
+
1482 _indices = (GLuint*)malloc(sizeof(GLuint) * numTriangles * 3);
+
1483 } else {
+
1484 if (INFO) printf( "[.ply]: No vertex normals exist on model, vertex normals will be autogenerated\n" );
+
1485 _vertices = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 3);
+
1486 _texCoords = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 2);
+
1487 _normals = (GLfloat*)malloc(sizeof(GLfloat) * numTriangles * 3 * 3);
+
1488 _indices = (GLuint*)malloc(sizeof(GLuint) * numTriangles * 3);
+
1489 }
+
1490
+
1491 if (INFO) printf( "[.ply]: ------------\n" );
+
1492
+
1493 std::vector<GLfloat> vertsTemp;
+
1494
+
1495 in.open( _filename );
+
1496
+
1497 _uniqueIndex = 0;
+
1498 _numIndices = 0;
+
1499
+
1500 fileState = HEADER;
+
1501 elemType = NONE;
+
1502
+
1503 progressCounter = 0;
+
1504 vSeen = 0;
+
1505
+
1506 while( getline( in, line ) ) {
+
1507 if( line.length() > 1 && line.at(0) == '\t' )
+
1508 line = line.substr( 1 );
+
1509 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
+
1510
+
1511 std::vector< std::string > tokens = _tokenizeString( line, " \t" );
+
1512
+
1513 if( tokens.size() < 1 ) continue;
+
1514
+
1515 //the line should have a single character that lets us know if it's a...
+
1516 if( !tokens[0].compare( "comment" ) ) { // comment ignore
+
1517 } else if( fileState == HEADER ) {
+
1518 if( !tokens[0].compare( "ply" ) ) { // denotes ply File type
+
1519 } else if( !tokens[0].compare( "format" ) ) {
+
1520 if( tokens[1].compare( "ascii" ) ) {
+
1521 if (ERRORS) fprintf( stderr, "[.ply]: [ERROR]: File \"%s\" not ASCII format\n", _filename );
+
1522 if ( INFO ) printf( "[.ply]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
+
1523 in.close();
+
1524 return false;
+
1525 }
+
1526 } else if( !tokens[0].compare( "element" ) ) { // an element (vertex, face, material)
+
1527 if( !tokens[1].compare( "vertex" ) ) {
+
1528 numVertices = atoi( tokens[2].c_str() );
+
1529 elemType = VERTEX;
+
1530 } else if( !tokens[1].compare( "face" ) ) {
+
1531 numFaces = atoi( tokens[2].c_str() );
+
1532 elemType = FACE;
+
1533 } else if( !tokens[1].compare( "edge" ) ) {
+
1534
+
1535 } else if( !tokens[1].compare( "material" ) ) {
+
1536 numMaterials = atoi( tokens[2].c_str() );
+
1537 elemType = MATERIAL;
+
1538 } else {
+
1539
+
1540 }
+
1541 } else if( !tokens[0].compare( "property" ) ) {
+
1542 if( elemType == VERTEX ) {
+
1543
+
1544 } else if( elemType == FACE ) {
+
1545
+
1546 } else if( elemType == MATERIAL ) {
+
1547
+
1548 }
+
1549 } else if( !tokens[0].compare( "end_header" ) ) { // end of the header section
+
1550 fileState = VERTICES;
+
1551 }
+
1552 } else if( fileState == VERTICES ) {
+
1553 // read in x y z vertex location
+
1554 GLfloat x = (GLfloat) atof( tokens[0].c_str() ),
+
1555 y = (GLfloat) atof( tokens[1].c_str() ),
+
1556 z = (GLfloat) atof( tokens[2].c_str() );
+
1557
+
1558 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
+
1559 _vertices[ _uniqueIndex*3 + 0 ] = x;
+
1560 _vertices[ _uniqueIndex*3 + 1 ] = y;
+
1561 _vertices[ _uniqueIndex*3 + 2 ] = z;
+
1562
+
1563 _uniqueIndex++;
+
1564 } else {
+
1565 vertsTemp.push_back( x );
+
1566 vertsTemp.push_back( y );
+
1567 vertsTemp.push_back( z );
+
1568
+
1569 vSeen++;
+
1570 }
+
1571 // if all vertices have been read in, move on to faces
+
1572 if( _uniqueIndex == numVertices || vSeen == numVertices )
+
1573 fileState = FACES;
+
1574 } else if( fileState == FACES ) {
+
1575 GLuint numberOfVerticesInFace = atoi( tokens[0].c_str() );
+
1576
+
1577 for( GLuint i = 2; i <= numberOfVerticesInFace - 1; i++ ) {
+
1578 if( _hasVertexNormals || !_AUTO_GEN_NORMALS ) {
+
1579 _indices[ _numIndices++ ] = atoi( tokens[1].c_str() );
+
1580 _indices[ _numIndices++ ] = atoi( tokens[i].c_str() );
+
1581 _indices[ _numIndices++ ] = atoi( tokens[i+1].c_str() );
+
1582 } else {
+
1583 GLuint aI = atoi( tokens[1].c_str() );
+
1584 GLuint bI = atoi( tokens[i].c_str() );
+
1585 GLuint cI = atoi( tokens[i+1].c_str() );
+
1586
+
1587 glm::vec3 a( vertsTemp[aI*3 + 0], vertsTemp[aI*3 + 1], vertsTemp[aI*3 + 2] );
+
1588 glm::vec3 b( vertsTemp[bI*3 + 0], vertsTemp[bI*3 + 1], vertsTemp[bI*3 + 2] );
+
1589 glm::vec3 c( vertsTemp[cI*3 + 0], vertsTemp[cI*3 + 1], vertsTemp[cI*3 + 2] );
+
1590
+
1591 glm::vec3 ab = b - a; glm::vec3 ac = c - a;
+
1592 glm::vec3 ba = a - b; glm::vec3 bc = c - b;
+
1593 glm::vec3 ca = a - c; glm::vec3 cb = b - c;
+
1594
+
1595 glm::vec3 aN = glm::normalize( glm::cross( ab, ac ) );
+
1596 glm::vec3 bN = glm::normalize( glm::cross( bc, ba ) );
+
1597 glm::vec3 cN = glm::normalize( glm::cross( ca, cb ) );
+
1598
+
1599 _vertices[ _uniqueIndex*3 + 0 ] = a.x;
+
1600 _vertices[ _uniqueIndex*3 + 1 ] = a.y;
+
1601 _vertices[ _uniqueIndex*3 + 2 ] = a.z;
+
1602
+
1603 _normals[ _uniqueIndex*3 + 0 ] = aN.x;
+
1604 _normals[ _uniqueIndex*3 + 1 ] = aN.y;
+
1605 _normals[ _uniqueIndex*3 + 2 ] = aN.z;
+
1606
+
1607 _indices[ _numIndices++ ] = _uniqueIndex++;
+
1608
+
1609 _vertices[ _uniqueIndex*3 + 0 ] = b.x;
+
1610 _vertices[ _uniqueIndex*3 + 1 ] = b.y;
+
1611 _vertices[ _uniqueIndex*3 + 2 ] = b.z;
+
1612
+
1613 _normals[ _uniqueIndex*3 + 0 ] = bN.x;
+
1614 _normals[ _uniqueIndex*3 + 1 ] = bN.y;
+
1615 _normals[ _uniqueIndex*3 + 2 ] = bN.z;
+
1616
+
1617 _indices[ _numIndices++ ] = _uniqueIndex++;
+
1618
+
1619 _vertices[ _uniqueIndex*3 + 0 ] = c.x;
+
1620 _vertices[ _uniqueIndex*3 + 1 ] = c.y;
+
1621 _vertices[ _uniqueIndex*3 + 2 ] = c.z;
+
1622
+
1623 _normals[ _uniqueIndex*3 + 0 ] = cN.x;
+
1624 _normals[ _uniqueIndex*3 + 1 ] = cN.y;
+
1625 _normals[ _uniqueIndex*3 + 2 ] = cN.z;
+
1626
+
1627 _indices[ _numIndices++ ] = _uniqueIndex++;
+
1628 }
+
1629 }
+
1630 } else {
+
1631 if (INFO) printf( "[.ply]: unknown file state: %d\n", fileState );
+
1632 }
+
1633
+
1634 if (INFO) {
+
1635 progressCounter++;
+
1636 if( progressCounter % 5000 == 0 ) {
+
1637 printf("\33[2K\r");
+
1638 switch( progressCounter ) {
+
1639 case 5000: printf("[.ply]: parsing %s...\\", _filename); break;
+
1640 case 10000: printf("[.ply]: parsing %s...|", _filename); break;
+
1641 case 15000: printf("[.ply]: parsing %s.../", _filename); break;
+
1642 case 20000: printf("[.ply]: parsing %s...-", _filename); break;
+
1643 }
+
1644 fflush(stdout);
+
1645 }
+
1646 if( progressCounter == 20000 )
+
1647 progressCounter = 0;
+
1648 }
+
1649 }
+
1650 in.close();
+
1651
+
1652 glBindVertexArray( _vaod );
+
1653 glBindBuffer( GL_ARRAY_BUFFER, _vbods[0] );
+
1654 glBufferData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 8, NULL, GL_STATIC_DRAW );
+
1655 glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * _uniqueIndex * 3, _vertices );
+
1656 glBufferSubData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 3, sizeof(GLfloat) * _uniqueIndex * 3, _normals );
+
1657 glBufferSubData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 6, sizeof(GLfloat) * _uniqueIndex * 2, _texCoords );
+
1658
+
1659 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, _vbods[1] );
+
1660 glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * _numIndices, _indices, GL_STATIC_DRAW );
+
1661
+
1662 time(&end);
+
1663 double seconds = difftime( end, start );
+
1664
+
1665 if (INFO) {
+
1666 printf( "\33[2K\r" );
+
1667 printf( "[.ply]: parsing %s...done!\n[.ply]: Time to complete: %.3fs\n", _filename, seconds );
+
1668 printf( "[.ply]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
+
1669 }
+
1670
+
1671 return result;
+
1672}
+
1673
+
1674inline bool CSCI441::ModelLoader::_loadSTLFile( bool INFO, bool ERRORS ) {
+
1675 bool result = true;
+
1676
+
1677 if (INFO) printf( "[.stl]: -=-=-=-=-=-=-=- BEGIN %s Info -=-=-=-=-=-=-=-\n", _filename );
+
1678
+
1679 time_t start, end;
+
1680 time(&start);
+
1681
+
1682 std::ifstream in( _filename );
+
1683 if( !in.is_open() ) {
+
1684 if (ERRORS) fprintf(stderr, "[.stl]: [ERROR]: Could not open \"%s\"\n", _filename );
+
1685 if ( INFO ) printf( "[.stl]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
+
1686 return false;
+
1687 }
+
1688
+
1689 GLuint numVertices = 0, numNormals = 0, numFaces = 0, numTriangles = 0, numVertsInLoop = 0;
+
1690 GLfloat minX = 999999.0f, maxX = -999999.0f, minY = 999999.0f, maxY = -999999.0f, minZ = 999999.0f, maxZ = -999999.0f;
+
1691 std::string line;
+
1692
+
1693 int progressCounter = 0;
+
1694 GLfloat normalVector[3] = {0,0,0};
+
1695
+
1696 while( getline( in, line ) ) {
+
1697 if( line.length() > 1 && line.at(0) == '\t' )
+
1698 line = line.substr( 1 );
+
1699 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
+
1700
+
1701 std::vector< std::string > tokens = _tokenizeString( line, " \t" );
+
1702
+
1703 if( tokens.size() < 1 ) continue;
+
1704
+
1705 //the line should have a single character that lets us know if it's a...
+
1706 if( !tokens[0].compare( "solid" ) ) {
+
1707 } else if( !tokens[0].compare( "facet" ) ) {
+
1708 /* read in x y z triangle normal */
+
1709 numNormals++;
+
1710 } else if( !tokens[0].compare( "outer" ) && !tokens[1].compare( "loop" ) ) {
+
1711 // begin a primitive
+
1712 numVertsInLoop = 0;
+
1713 } else if( !tokens[0].compare( "vertex" ) ) {
+
1714 GLfloat x = (GLfloat) atof( tokens[1].c_str() ),
+
1715 y = (GLfloat) atof( tokens[2].c_str() ),
+
1716 z = (GLfloat) atof( tokens[3].c_str() );
+
1717
+
1718 if( x < minX ) minX = x;
+
1719 if( x > maxX ) maxX = x;
+
1720 if( y < minY ) minY = y;
+
1721 if( y > maxY ) maxY = y;
+
1722 if( z < minZ ) minZ = z;
+
1723 if( z > maxZ ) maxZ = z;
+
1724
+
1725 numVertices++;
+
1726 numVertsInLoop++;
+
1727 } else if( !tokens[0].compare( "endloop" ) ) {
+
1728 // end primitive
+
1729 numTriangles += numVertsInLoop - 3 + 1;
+
1730 } else if( !tokens[0].compare( "endfacet" ) ) {
+
1731 numFaces++;
+
1732 } else if( !tokens[0].compare( "endsolid" ) ) {
+
1733
+
1734 }
+
1735 else {
+
1736 if( memchr( line.c_str(), '\0', line.length() ) != NULL ) {
+
1737 if (ERRORS) fprintf( stderr, "[.stl]: [ERROR]: Cannot read binary STL file \"%s\"\n", _filename );
+
1738 if ( INFO ) printf( "[.stl]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
+
1739 in.close();
+
1740 return false;
+
1741 } else if (INFO) printf( "[.stl]: unknown line: %s\n", line.c_str() );
+
1742 }
+
1743
+
1744 if (INFO) {
+
1745 progressCounter++;
+
1746 if( progressCounter % 5000 == 0 ) {
+
1747 printf("\33[2K\r");
+
1748 switch( progressCounter ) {
+
1749 case 5000: printf("[.stl]: scanning %s...\\", _filename); break;
+
1750 case 10000: printf("[.stl]: scanning %s...|", _filename); break;
+
1751 case 15000: printf("[.stl]: scanning %s.../", _filename); break;
+
1752 case 20000: printf("[.stl]: scanning %s...-", _filename); break;
+
1753 }
+
1754 fflush(stdout);
+
1755 }
+
1756 if( progressCounter == 20000 )
+
1757 progressCounter = 0;
+
1758 }
+
1759 }
+
1760 in.close();
+
1761
+
1762 if (INFO) {
+
1763 printf( "\33[2K\r" );
+
1764 printf( "[.stl]: scanning %s...done!\n", _filename );
+
1765 printf( "[.stl]: ------------\n" );
+
1766 printf( "[.stl]: Model Stats:\n" );
+
1767 printf( "[.stl]: Vertices: \t%u\tNormals: \t%u\tTex Coords:\t%u\n", numVertices, numNormals, 0 );
+
1768 printf( "[.stl]: Faces: \t%u\tTriangles: \t%u\n", numFaces, numTriangles );
+
1769 printf( "[.stl]: Dimensions:\t(%f, %f, %f)\n", (maxX - minX), (maxY - minY), (maxZ - minZ) );
+
1770 }
+
1771
+
1772 _vertices = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 3);
+
1773 _texCoords = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 2);
+
1774 _normals = (GLfloat*)malloc(sizeof(GLfloat) * numVertices * 3);
+
1775 _indices = (GLuint*)malloc(sizeof(GLuint) * numTriangles * 3);
+
1776
+
1777 if (INFO) printf( "[.stl]: ------------\n" );
+
1778
+
1779 in.open( _filename );
+
1780
+
1781 _uniqueIndex = 0;
+
1782 _numIndices = 0;
+
1783
+
1784 while( getline( in, line ) ) {
+
1785 if( line.length() > 1 && line.at(0) == '\t' )
+
1786 line = line.substr( 1 );
+
1787 line.erase( line.find_last_not_of( " \n\r\t" ) + 1 );
+
1788
+
1789 std::vector< std::string > tokens = _tokenizeString( line, " \t" );
+
1790
+
1791 if( tokens.size() < 1 ) continue;
+
1792
+
1793 //the line should have a single character that lets us know if it's a...
+
1794 if( !tokens[0].compare( "solid" ) ) {
+
1795 } else if( !tokens[0].compare( "facet" ) ) {
+
1796 /* read in x y z triangle normal */
+
1797 normalVector[0] = atof( tokens[2].c_str() );
+
1798 normalVector[1] = atof( tokens[3].c_str() );
+
1799 normalVector[2] = atof( tokens[4].c_str() );
+
1800 } else if( !tokens[0].compare( "outer" ) && !tokens[1].compare( "loop" ) ) {
+
1801 // begin a primitive
+
1802 } else if( !tokens[0].compare( "vertex" ) ) {
+
1803 GLfloat x = (GLfloat) atof( tokens[1].c_str() ),
+
1804 y = (GLfloat) atof( tokens[2].c_str() ),
+
1805 z = (GLfloat) atof( tokens[3].c_str() );
+
1806
+
1807 _vertices[ _uniqueIndex*3 + 0 ] = x;
+
1808 _vertices[ _uniqueIndex*3 + 1 ] = y;
+
1809 _vertices[ _uniqueIndex*3 + 2 ] = z;
+
1810
+
1811 _normals[ _uniqueIndex*3 + 0 ] = normalVector[0];
+
1812 _normals[ _uniqueIndex*3 + 1 ] = normalVector[1];
+
1813 _normals[ _uniqueIndex*3 + 2 ] = normalVector[2];
+
1814
+
1815 _indices[ _numIndices++ ] = _uniqueIndex++;
+
1816 } else if( !tokens[0].compare( "endloop" ) ) {
+
1817 // end primitive
+
1818 } else if( !tokens[0].compare( "endfacet" ) ) {
+
1819
+
1820 } else if( !tokens[0].compare( "endsolid" ) ) {
+
1821
+
1822 }
+
1823 else {
+
1824
+
1825 }
+
1826
+
1827 if (INFO) {
+
1828 progressCounter++;
+
1829 if( progressCounter % 5000 == 0 ) {
+
1830 printf("\33[2K\r");
+
1831 switch( progressCounter ) {
+
1832 case 5000: printf("[.stl]: parsing %s...\\", _filename); break;
+
1833 case 10000: printf("[.stl]: parsing %s...|", _filename); break;
+
1834 case 15000: printf("[.stl]: parsing %s.../", _filename); break;
+
1835 case 20000: printf("[.stl]: parsing %s...-", _filename); break;
+
1836 }
+
1837 fflush(stdout);
+
1838 }
+
1839 if( progressCounter == 20000 )
+
1840 progressCounter = 0;
+
1841 }
+
1842 }
+
1843 in.close();
+
1844
+
1845 glBindVertexArray( _vaod );
+
1846 glBindBuffer( GL_ARRAY_BUFFER, _vbods[0] );
+
1847 glBufferData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 8, NULL, GL_STATIC_DRAW );
+
1848 glBufferSubData( GL_ARRAY_BUFFER, 0, sizeof(GLfloat) * _uniqueIndex * 3, _vertices );
+
1849 glBufferSubData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 3, sizeof(GLfloat) * _uniqueIndex * 3, _normals );
+
1850 glBufferSubData( GL_ARRAY_BUFFER, sizeof(GLfloat) * _uniqueIndex * 6, sizeof(GLfloat) * _uniqueIndex * 2, _texCoords );
+
1851
+
1852 glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, _vbods[1] );
+
1853 glBufferData( GL_ELEMENT_ARRAY_BUFFER, sizeof(GLuint) * _numIndices, _indices, GL_STATIC_DRAW );
+
1854
+
1855 time(&end);
+
1856 double seconds = difftime( end, start );
+
1857
+
1858 if (INFO) {
+
1859 printf("\33[2K\r");
+
1860 printf("[.stl]: parsing %s...done!\n[.stl]: Time to complete: %.3fs\n", _filename, seconds);
+
1861 printf( "[.stl]: -=-=-=-=-=-=-=- END %s Info -=-=-=-=-=-=-=-\n\n", _filename );
+
1862 }
+
1863
+
1864 return result;
+
1865}
+
1866
+
1867inline void CSCI441::ModelLoader::enableAutoGenerateNormals() {
+
1868 _AUTO_GEN_NORMALS = true;
+
1869}
+
1870
+
1871inline void CSCI441::ModelLoader::disableAutoGenerateNormals() {
+
1872 _AUTO_GEN_NORMALS = false;
+
1873}
+
1874
+
1875//
+
1876// vector<string> tokenizeString(string input, string delimiters)
+
1877//
+
1878// This is a helper function to break a single string into std::vector
+
1879// of strings, based on a given set of delimiter characters.
+
1880//
+
1881inline std::vector<std::string> CSCI441::ModelLoader::_tokenizeString(std::string input, std::string delimiters) {
+
1882 if(input.size() == 0)
+
1883 return std::vector<std::string>();
+
1884
+
1885 std::vector<std::string> retVec = std::vector<std::string>();
+
1886 size_t oldR = 0, r = 0;
+
1887
+
1888 //strip all delimiter characters from the front and end of the input string.
+
1889 std::string strippedInput;
+
1890 int lowerValidIndex = 0, upperValidIndex = input.size() - 1;
+
1891 while((GLuint)lowerValidIndex < input.size() && delimiters.find_first_of(input.at(lowerValidIndex), 0) != std::string::npos)
+
1892 lowerValidIndex++;
+
1893
+
1894 while(upperValidIndex >= 0 && delimiters.find_first_of(input.at(upperValidIndex), 0) != std::string::npos)
+
1895 upperValidIndex--;
+
1896
+
1897 //if the lowest valid index is higher than the highest valid index, they're all delimiters! return nothing.
+
1898 if((GLuint)lowerValidIndex >= input.size() || upperValidIndex < 0 || lowerValidIndex > upperValidIndex)
+
1899 return std::vector<std::string>();
+
1900
+
1901 //remove the delimiters from the beginning and end of the string, if any.
+
1902 strippedInput = input.substr(lowerValidIndex, upperValidIndex-lowerValidIndex+1);
+
1903
+
1904 //search for each instance of a delimiter character, and create a new token spanning
+
1905 //from the last valid character up to the delimiter character.
+
1906 while((r = strippedInput.find_first_of(delimiters, oldR)) != std::string::npos)
+
1907 {
+
1908 if(oldR != r) //but watch out for multiple consecutive delimiters!
+
1909 retVec.push_back(strippedInput.substr(oldR, r-oldR));
+
1910 oldR = r+1;
+
1911 }
+
1912 if(r != 0)
+
1913 retVec.push_back(strippedInput.substr(oldR, r-oldR));
+
1914
+
1915 return retVec;
+
1916}
+
1917
+
1918inline unsigned char* CSCI441_INTERNAL::createTransparentTexture( unsigned char *imageData, unsigned char *imageMask, int texWidth, int texHeight, int texChannels, int maskChannels ) {
+
1919 //combine the 'mask' array with the image data array into an RGBA array.
+
1920 unsigned char *fullData = new unsigned char[texWidth*texHeight*4];
+
1921
+
1922 for(int j = 0; j < texHeight; j++) {
+
1923 for(int i = 0; i < texWidth; i++) {
+
1924 if( imageData ) {
+
1925 fullData[(j*texWidth+i)*4+0] = imageData[(j*texWidth+i)*texChannels+0]; // R
+
1926 fullData[(j*texWidth+i)*4+1] = imageData[(j*texWidth+i)*texChannels+1]; // G
+
1927 fullData[(j*texWidth+i)*4+2] = imageData[(j*texWidth+i)*texChannels+2]; // B
+
1928 } else {
+
1929 fullData[(j*texWidth+i)*4+0] = 1; // R
+
1930 fullData[(j*texWidth+i)*4+1] = 1; // G
+
1931 fullData[(j*texWidth+i)*4+2] = 1; // B
+
1932 }
+
1933
+
1934 if( imageMask ) {
+
1935 fullData[(j*texWidth+i)*4+3] = imageMask[(j*texWidth+i)*maskChannels+0]; // A
+
1936 } else {
+
1937 fullData[(j*texWidth+i)*4+3] = 1; // A
+
1938 }
+
1939 }
+
1940 }
+
1941 return fullData;
+
1942}
+
1943
+
1944inline void CSCI441_INTERNAL::flipImageY( int texWidth, int texHeight, int textureChannels, unsigned char *textureData ) {
+
1945 for( int j = 0; j < texHeight / 2; j++ ) {
+
1946 for( int i = 0; i < texWidth; i++ ) {
+
1947 for( int k = 0; k < textureChannels; k++ ) {
+
1948 int top = (j*texWidth + i)*textureChannels + k;
+
1949 int bot = ((texHeight-j-1)*texWidth + i)*textureChannels + k;
+
1950
+
1951 unsigned char t = textureData[top];
+
1952 textureData[top] = textureData[bot];
+
1953 textureData[bot] = t;
+
1954
+
1955 }
+
1956 }
+
1957 }
+
1958}
+
1959
+
1960#endif // __CSCI441_MODEL_LOADER_HPP__
+
Loads object models from file and renders using VBOs/VAOs.
Definition: ModelLoader.hpp:44
+
static void enableAutoGenerateNormals()
Enable auto-generation of vertex normals.
Definition: ModelLoader.hpp:1867
+
void setAttributeLocations(GLint positionLocation, GLint normalLocation=-1, GLint texCoordLocation=-1) const
Enables VBO attribute array locations.
Definition: ModelLoader.hpp:244
+
bool loadModelFile(const char *filename, bool INFO=true, bool ERRORS=true)
Loads a model from the given file.
Definition: ModelLoader.hpp:216
+
GLuint getNumberOfIndices() const
Return the number of indices to draw the model. This value corresponds to the size of the Indices arr...
Definition: ModelLoader.hpp:312
+
GLfloat * getVertices() const
Return the vertex array that makes up the model mesh.
Definition: ModelLoader.hpp:309
+
GLfloat * getNormals() const
Return the normal array that corresponds to the model mesh.
Definition: ModelLoader.hpp:311
+
bool draw(GLuint shaderProgramHandle, GLint matDiffLocation=-1, GLint matSpecLocation=-1, GLint matShinLocation=-1, GLint matAmbLocation=-1, GLenum diffuseTexture=GL_TEXTURE0) const
Renders a model.
Definition: ModelLoader.hpp:258
+
GLuint * getIndices() const
Return the index array that dictates the order to draw the model mesh.
Definition: ModelLoader.hpp:313
+
GLfloat * getTexCoords() const
Return the texture coordinates array that corresponds to the model mesh.
Definition: ModelLoader.hpp:310
+
GLuint getNumberOfVertices() const
Return the number of vertices the model is made up of. This value corresponds to the size of the Vert...
Definition: ModelLoader.hpp:308
+
static void disableAutoGenerateNormals()
Disable auto-generation of vertex normals.
Definition: ModelLoader.hpp:1871
+
~ModelLoader()
Frees memory associated with model on both CPU and GPU.
Definition: ModelLoader.hpp:193
+
ModelLoader()
Creates an empty model.
Definition: ModelLoader.hpp:184
CSCI441 Helper Functions for OpenGL.
Definition: ArcballCam.hpp:17
diff --git a/docs/class_c_s_c_i441_1_1_model_loader.html b/docs/class_c_s_c_i441_1_1_model_loader.html index 610d05dc..e28b7d96 100644 --- a/docs/class_c_s_c_i441_1_1_model_loader.html +++ b/docs/class_c_s_c_i441_1_1_model_loader.html @@ -113,28 +113,28 @@  Return the number of vertices the model is made up of. This value corresponds to the size of the Vertices, TexCoords, and Normals arrays.
  GLfloat * getVertices () const - Return the vertex array that makes up the model mesh. For use with VBOs.
+ Return the vertex array that makes up the model mesh.
  GLfloat * getTexCoords () const - Return the texture coordinates array that corresponds to the model mesh. For use with VBOs.
+ Return the texture coordinates array that corresponds to the model mesh.
  GLfloat * getNormals () const - Return the normal array that corresponds to the model mesh. For use with VBOs.
+ Return the normal array that corresponds to the model mesh.
  GLuint getNumberOfIndices () const  Return the number of indices to draw the model. This value corresponds to the size of the Indices array.
  GLuint * getIndices () const - Return the index array that dictates the order to draw the model mesh. For use with IBOs.
+ Return the index array that dictates the order to draw the model mesh.
  - + - +

Static Public Member Functions

static void enableAutoGenerateNormals ()
 Enable autogeneration of vertex normals.
 Enable auto-generation of vertex normals.
 
static void disableAutoGenerateNormals ()
 Disable autogeneration of vertex normals.
 Disable auto-generation of vertex normals.
 

Detailed Description

@@ -167,7 +167,7 @@

Parameters
- +
constchar* filename - file to load model from
filenamefile to load model from
@@ -198,11 +198,11 @@

-

Disable autogeneration of vertex normals.

-

If an object model does not contain vertex normal data, then normals will be computed based on the cross product of vertex winding order.

-
Note
Must be called prior to loading in a model from file
+

Disable auto-generation of vertex normals.

+
Warning
Must be called prior to loading in a model from file
+
Note
No normals are generated by default
-No normals are generated by default
+To enable, call enableAutoGenerateNormals
@@ -267,12 +267,12 @@

Parameters
- - - - - - + + + + + +
GLintshaderProgramHandle - shader program handle that
GLintmatDiffLocation - uniform location of material diffuse component
GLintmatSpecLocation - uniform location of material specular component
GLintmatShinLocation - uniform location of material shininess component
GLintmatAmbLocation - uniform location of material ambient component
GLenumdiffuseTexture - texture number to bind diffuse texture map to
shaderProgramHandleshader program handle that
matDiffLocationuniform location of material diffuse component
matSpecLocationuniform location of material specular component
matShinLocationuniform location of material shininess component
matAmbLocationuniform location of material ambient component
diffuseTexturetexture number to bind diffuse texture map to
@@ -303,11 +303,13 @@

-

Enable autogeneration of vertex normals.

-

If an object model does not contain vertex normal data, then normals will be computed based on the cross product of vertex winding order.

-
Note
Must be called prior to loading in a model from file
+

Enable auto-generation of vertex normals.

+
Warning
Must be called prior to loading in a model from file
+
Note
If an object model does not contain vertex normal data, then normals will be computed based on the cross product of vertex winding order.
-No normals are generated by default
+No normals are generated by default +
+To disable, call disableAutoGenerateNormals
@@ -334,8 +336,9 @@

-

Return the index array that dictates the order to draw the model mesh. For use with IBOs.

-
Returns
GLuint* indices - pointer to the index array
+

Return the index array that dictates the order to draw the model mesh.

+
Returns
pointer to the index array
+
Note
For use with IBOs
@@ -362,8 +365,9 @@

-

Return the normal array that corresponds to the model mesh. For use with VBOs.

-
Returns
GLfloat* normals - pointer to the normal array
+

Return the normal array that corresponds to the model mesh.

+
Returns
pointer to the normal array
+
Note
For use with VBOs
@@ -391,7 +395,7 @@

Return the number of indices to draw the model. This value corresponds to the size of the Indices array.

-
Returns
GLuint numIndices - the number of indices when drawing the model
+
Returns
the number of indices when drawing the model
@@ -419,7 +423,7 @@

Return the number of vertices the model is made up of. This value corresponds to the size of the Vertices, TexCoords, and Normals arrays.

-
Returns
GLuint numVertices - the number of vertices within the model
+
Returns
the number of vertices within the model
@@ -446,8 +450,9 @@

-

Return the texture coordinates array that corresponds to the model mesh. For use with VBOs.

-
Returns
GLfloat* texCoords - pointer to texture coordinate array
+

Return the texture coordinates array that corresponds to the model mesh.

+
Returns
pointer to texture coordinate array
+
Note
For use with VBOs
@@ -474,8 +479,9 @@

-

Return the vertex array that makes up the model mesh. For use with VBOs.

-
Returns
GLfloat* vertices - pointer to vertex array
+

Return the vertex array that makes up the model mesh.

+
Returns
pointer to vertex array
+
Note
For use with VBOs
@@ -522,9 +528,9 @@

Parameters
- - - + + +
constchar* filename - file to load model from
boolINFO - flag to control if informational messages should be displayed
boolERRORS - flag to control if error messages should be displayed
filenamefile to load model from
INFOflag to control if informational messages should be displayed
ERRORSflag to control if error messages should be displayed
@@ -575,9 +581,9 @@

Parameters
- - - + + +
GLintpositionLocation - attribute location of vertex position
GLintnormalLocation - attribute location of vertex normal
GLinttexCoordLocation - attribute location of vertex texture coordinate
positionLocationattribute location of vertex position
normalLocationattribute location of vertex normal
texCoordLocationattribute location of vertex texture coordinate