/* * Copyright (c) 2007 Gero Mueller * * This software is provided 'as-is', without any express or implied * warranty. In no event will the authors be held liable for any damages * arising from the use of this software. * * Permission is granted to anyone to use this software for any purpose, * including commercial applications, and to alter it and redistribute it * freely, subject to the following restrictions: * * 1. The origin of this software must not be misrepresented; you must not * claim that you wrote the original software. If you use this software * in a product, an acknowledgment in the product documentation would be * appreciated but is not required. * * 2. Altered source versions must be plainly marked as such, and must not be * misrepresented as being the original software. * * 3. This notice may not be removed or altered from any source * distribution. */ #include "trimeshloader.h" #include #include #include #ifdef WIN32 #define PATH_SEPARATOR '\\' #else #define PATH_SEPARATOR '/' #endif /*----------------------------------------------------------------------------*/ tlTrimesh *tlCreateTrimeshFrom3dsState( tl3dsState *state, unsigned int vertex_format ) { tlTrimesh *trimesh = NULL; unsigned int i = 0, index = 0; if( state == NULL ) return NULL; trimesh = malloc( sizeof(tlTrimesh) ); memset(trimesh, 0, sizeof(tlTrimesh)); /* objects */ trimesh->object_count = tl3dsObjectCount( state ); trimesh->objects = malloc( sizeof(tlObject) * trimesh->object_count ); for( i = 0; i < trimesh->object_count; i++ ) { size_t length = strlen( tl3dsObjectName( state, i ) ) + 1; trimesh->objects[i].name = malloc( length ); memcpy( trimesh->objects[i].name, tl3dsObjectName( state, i ), length ); trimesh->objects[i].face_index = tl3dsObjectFaceIndex( state, i ); trimesh->objects[i].face_count = tl3dsObjectFaceCount( state, i ); } /* materials */ trimesh->material_count = tl3dsMaterialCount( state ); trimesh->materials = malloc( sizeof(tlMaterial) * trimesh->material_count ); for( i = 0; i < trimesh->material_count; i++ ) { size_t length = strlen( tl3dsMaterialName( state, i ) ) + 1; trimesh->materials[i].name = malloc( length ); memcpy( trimesh->materials[i].name, tl3dsMaterialName( state, i ), length ); tl3dsGetMaterial( state, i, trimesh->materials[i].ambient, trimesh->materials[i].diffuse, trimesh->materials[i].specular, &(trimesh->materials[i].shininess)); } trimesh->material_reference_count = tl3dsMaterialReferenceCount( state ); trimesh->material_references = malloc( sizeof(tlMaterialReference) * trimesh->material_reference_count ); for( i = 0; i < trimesh->material_reference_count; i++ ) { size_t length = strlen( tl3dsMaterialReferenceName( state, i ) ) + 1; trimesh->material_references[i].name = malloc( length ); strcpy( trimesh->material_references[i].name, tl3dsMaterialReferenceName( state, i ) ); tl3dsGetMaterialReference( state, i, &(trimesh->material_references[i].face_index), &(trimesh->material_references[i].face_count)); } trimesh->face_count = tl3dsFaceCount( state ); trimesh->faces = malloc( sizeof(unsigned short) * trimesh->face_count * 3 ); for( i = 0; i < trimesh->face_count; i++ ) { unsigned int offset = i * 3; tl3dsGetFace( state, i, &trimesh->faces[offset], &trimesh->faces[offset + 1], &trimesh->faces[offset + 2] ); } trimesh->vertex_count = tl3dsVertexCount( state ); trimesh->vertex_format = vertex_format; trimesh->vertex_size = vertex_format & TL_FVF_XYZ ? 3 * sizeof(float) : 0; trimesh->vertex_size += vertex_format & TL_FVF_UV ? 2 * sizeof(float) : 0; trimesh->vertex_size += vertex_format & TL_FVF_NORMAL ? 3 * sizeof(float) : 0; trimesh->vertices = malloc( trimesh->vertex_count * trimesh->vertex_size ); index = 0; for( i = 0; i < trimesh->vertex_count; i++ ) { float *x = NULL, *y = NULL, *z = NULL; float *u = NULL, *v = NULL; float *nx = NULL, *ny = NULL, *nz = NULL; if( vertex_format & TL_FVF_XYZ ) { x = &trimesh->vertices[index++]; y = &trimesh->vertices[index++]; z = &trimesh->vertices[index++]; } if( vertex_format & TL_FVF_UV ) { u = &trimesh->vertices[index++]; v = &trimesh->vertices[index++]; } if( vertex_format & TL_FVF_NORMAL ) { nx = &trimesh->vertices[index++]; ny = &trimesh->vertices[index++]; nz = &trimesh->vertices[index++]; } tl3dsGetVertex( state, i, x, y, z, u, v, nx, ny, nz ); } return trimesh; } /*----------------------------------------------------------------------------*/ tlTrimesh *tlLoad3DS( const char *filename, unsigned int vertex_format ) { FILE *f = 0; tlTrimesh *trimesh = NULL; if( filename == NULL ) return NULL; f = fopen( filename, "r" ); if( f ) { tl3dsState *state = NULL; state = tl3dsCreateState(); if( state ) { char buffer[1024]; unsigned int size = 0; while( !feof( f ) ) { size = (unsigned int) fread( buffer, 1, sizeof(buffer), f ); tl3dsParse( state, buffer, size, size < sizeof(buffer) ? 1 : 0 ); } trimesh = tlCreateTrimeshFrom3dsState( state, vertex_format ); tl3dsDestroyState( state ); } fclose( f ); } return trimesh; } /*----------------------------------------------------------------------------*/ tlTrimesh *tlCreateTrimeshFromObjState( tlObjState *state, unsigned int vertex_format ) { tlTrimesh *trimesh = NULL; unsigned int i = 0, index = 0; if( state == NULL ) return NULL; trimesh = malloc( sizeof(tlTrimesh) ); memset(trimesh, 0, sizeof(tlTrimesh)); trimesh->object_count = tlObjObjectCount( state ); trimesh->objects = malloc( sizeof(tlObject) * trimesh->object_count ); for( i = 0; i < trimesh->object_count; i++ ) { size_t length = strlen( tlObjObjectName( state, i ) ) + 1; trimesh->objects[i].name = malloc( length ); memcpy( trimesh->objects[i].name, tlObjObjectName( state, i ), length ); trimesh->objects[i].face_index = tlObjObjectFaceIndex( state, i ); trimesh->objects[i].face_count = tlObjObjectFaceCount( state, i ); } /* materials */ trimesh->material_count = tlObjMaterialCount( state ); trimesh->materials = malloc( sizeof(tlMaterial) * trimesh->material_count ); for( i = 0; i < trimesh->material_count; i++ ) { size_t length = strlen( tlObjMaterialName( state, i ) ) + 1; trimesh->materials[i].name = malloc( length ); memcpy( trimesh->materials[i].name, tlObjMaterialName( state, i ), length ); tlObjGetMaterial( state, i, trimesh->materials[i].ambient, trimesh->materials[i].diffuse, trimesh->materials[i].specular, &(trimesh->materials[i].shininess)); } trimesh->material_reference_count = tlObjMaterialReferenceCount( state ); trimesh->material_references = malloc( sizeof(tlMaterialReference) * trimesh->material_reference_count ); for( i = 0; i < trimesh->material_reference_count; i++ ) { size_t length = strlen( tlObjMaterialReferenceName( state, i ) ) + 1; trimesh->material_references[i].name = malloc( length ); strcpy( trimesh->material_references[i].name, tlObjMaterialReferenceName( state, i ) ); tlObjGetMaterialReference( state, i, &(trimesh->material_references[i].face_index), &(trimesh->material_references[i].face_count)); } trimesh->face_count = tlObjFaceCount( state ); trimesh->faces = malloc( sizeof(unsigned short) * trimesh->face_count * 3 ); for( i = 0; i < trimesh->face_count; i++ ) { unsigned int offset = i * 3; tlObjGetFace( state, i, &trimesh->faces[offset], &trimesh->faces[offset + 1], &trimesh->faces[offset + 2] ); } trimesh->vertex_count = tlObjVertexCount( state ); trimesh->vertex_format = vertex_format; trimesh->vertex_size = vertex_format & TL_FVF_XYZ ? 3 * sizeof(float) : 0; trimesh->vertex_size += vertex_format & TL_FVF_UV ? 2 * sizeof(float) : 0; trimesh->vertex_size += vertex_format & TL_FVF_NORMAL ? 3 * sizeof(float) : 0; trimesh->vertices = malloc( trimesh->vertex_count * trimesh->vertex_size ); index = 0; for( i = 0; i < trimesh->vertex_count; i++ ) { float *x = NULL, *y = NULL, *z = NULL; float *u = NULL, *v = NULL; float *nx = NULL, *ny = NULL, *nz = NULL; if( vertex_format & TL_FVF_XYZ ) { x = &trimesh->vertices[index++]; y = &trimesh->vertices[index++]; z = &trimesh->vertices[index++]; } if( vertex_format & TL_FVF_UV ) { u = &trimesh->vertices[index++]; v = &trimesh->vertices[index++]; } if( vertex_format & TL_FVF_NORMAL ) { nx = &trimesh->vertices[index++]; ny = &trimesh->vertices[index++]; nz = &trimesh->vertices[index++]; } tlObjGetVertex( state, i, x, y, z, u, v, nx, ny, nz ); } return trimesh; } /*----------------------------------------------------------------------------*/ static char *get_dirname( const char *filename ) { char *dirname, *separator; /* find last sperator */ separator = strrchr( filename, PATH_SEPARATOR ); /* copy dirname */ if( separator && (*separator == PATH_SEPARATOR) ) { size_t length = (separator - filename); dirname = malloc( length + 1 ); strncpy( dirname, filename, length ); dirname[length] = 0; } else { dirname = malloc( 1 ); dirname[0] = '\0'; } return dirname; } /*----------------------------------------------------------------------------*/ static void parse_obj_file( tlObjState *state, const char *filename ) { FILE *file = fopen( filename, "r" ); if( file ) { char buffer[1024]; unsigned int size = 0; while( !feof( file ) ) { size = (unsigned int)fread( buffer, 1, sizeof(buffer), file ); tlObjParse( state, buffer, size, size < sizeof(buffer) ? 1 : 0 ); } fclose( file ); } } /*----------------------------------------------------------------------------*/ tlTrimesh *tlLoadOBJ( const char *filename, unsigned int vertex_format ) { tlTrimesh *trimesh = NULL; tlObjState *state = NULL; char *dirname = NULL; size_t dirname_length = 0; if( filename == NULL ) return NULL; dirname = get_dirname( filename ); dirname_length = strlen( dirname ); state = tlObjCreateState(); if( state ) { unsigned int mtlcount = 0, i; parse_obj_file( state, filename ); mtlcount = tlObjMaterialLibCount( state ); for( i = 0; i < mtlcount; i++ ) { const char *libname = tlObjMaterialLibName( state, i ); size_t path_length = dirname_length + strlen( libname ); char *path = malloc( path_length + 1 ); strcpy( path, dirname ); strcpy( path + dirname_length, libname ); parse_obj_file( state, path ); free( path ); } trimesh = tlCreateTrimeshFromObjState( state, vertex_format ); tlObjDestroyState( state ); } free( dirname ); return trimesh; } /*----------------------------------------------------------------------------*/ tlTrimesh *tlLoadTrimesh( const char* filename, unsigned int vertex_format ) { tlTrimesh *trimesh = NULL; if( tl3dsCheckFileExtension( filename ) == 0 ) trimesh = tlLoad3DS( filename, vertex_format ); else if( tlObjCheckFileExtension( filename ) == 0 ) trimesh = tlLoadOBJ( filename, vertex_format ); return trimesh; } /*----------------------------------------------------------------------------*/ void tlDeleteTrimesh( tlTrimesh *trimesh ) { unsigned int i = 0; if( trimesh == NULL ) return; for( i = 0; i < trimesh->object_count; i++ ) free( trimesh->objects[i].name ); free( trimesh->objects ); free( trimesh->faces ); free( trimesh->vertices ); free( trimesh ); }