nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // Product: OpenCTM nuclear@14: // File: openctm.c nuclear@14: // Description: API functions. nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // Copyright (c) 2009-2010 Marcus Geelnard nuclear@14: // nuclear@14: // This software is provided 'as-is', without any express or implied nuclear@14: // warranty. In no event will the authors be held liable for any damages nuclear@14: // arising from the use of this software. nuclear@14: // nuclear@14: // Permission is granted to anyone to use this software for any purpose, nuclear@14: // including commercial applications, and to alter it and redistribute it nuclear@14: // freely, subject to the following restrictions: nuclear@14: // nuclear@14: // 1. The origin of this software must not be misrepresented; you must not nuclear@14: // claim that you wrote the original software. If you use this software nuclear@14: // in a product, an acknowledgment in the product documentation would be nuclear@14: // appreciated but is not required. nuclear@14: // nuclear@14: // 2. Altered source versions must be plainly marked as such, and must not nuclear@14: // be misrepresented as being the original software. nuclear@14: // nuclear@14: // 3. This notice may not be removed or altered from any source nuclear@14: // distribution. nuclear@14: //----------------------------------------------------------------------------- nuclear@14: nuclear@14: #include nuclear@14: #include nuclear@14: #include nuclear@14: #include nuclear@14: #include "openctm.h" nuclear@14: #include "internal.h" nuclear@14: nuclear@14: nuclear@14: // The C99 macro isfinite() is not supported on all platforms (specifically, nuclear@14: // MS Visual Studio does not support C99) nuclear@14: #if !defined(isfinite) && defined(_MSC_VER) nuclear@14: #include nuclear@14: #define isfinite(x) _finite(x) nuclear@14: #endif nuclear@14: nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // _ctmFreeMapList() - Free a float map list. nuclear@14: //----------------------------------------------------------------------------- nuclear@14: static void _ctmFreeMapList(_CTMcontext * self, _CTMfloatmap * aMapList) nuclear@14: { nuclear@14: _CTMfloatmap * map, * nextMap; nuclear@14: map = aMapList; nuclear@14: while(map) nuclear@14: { nuclear@14: // Free internally allocated array (if we are in import mode) nuclear@14: if((self->mMode == CTM_IMPORT) && map->mValues) nuclear@14: free(map->mValues); nuclear@14: nuclear@14: // Free map name nuclear@14: if(map->mName) nuclear@14: free(map->mName); nuclear@14: nuclear@14: // Free file name nuclear@14: if(map->mFileName) nuclear@14: free(map->mFileName); nuclear@14: nuclear@14: nextMap = map->mNext; nuclear@14: free(map); nuclear@14: map = nextMap; nuclear@14: } nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // _ctmClearMesh() - Clear the mesh in a CTM context. nuclear@14: //----------------------------------------------------------------------------- nuclear@14: static void _ctmClearMesh(_CTMcontext * self) nuclear@14: { nuclear@14: // Free internally allocated mesh arrays nuclear@14: if(self->mMode == CTM_IMPORT) nuclear@14: { nuclear@14: if(self->mVertices) nuclear@14: free(self->mVertices); nuclear@14: if(self->mIndices) nuclear@14: free(self->mIndices); nuclear@14: if(self->mNormals) nuclear@14: free(self->mNormals); nuclear@14: } nuclear@14: nuclear@14: // Clear externally assigned mesh arrays nuclear@14: self->mVertices = (CTMfloat *) 0; nuclear@14: self->mVertexCount = 0; nuclear@14: self->mIndices = (CTMuint *) 0; nuclear@14: self->mTriangleCount = 0; nuclear@14: self->mNormals = (CTMfloat *) 0; nuclear@14: nuclear@14: // Free UV coordinate map list nuclear@14: _ctmFreeMapList(self, self->mUVMaps); nuclear@14: self->mUVMaps = (_CTMfloatmap *) 0; nuclear@14: self->mUVMapCount = 0; nuclear@14: nuclear@14: // Free attribute map list nuclear@14: _ctmFreeMapList(self, self->mAttribMaps); nuclear@14: self->mAttribMaps = (_CTMfloatmap *) 0; nuclear@14: self->mAttribMapCount = 0; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // _ctmCheckMeshIntegrity() - Check if a mesh is valid (i.e. is non-empty, and nuclear@14: // contains valid data). nuclear@14: //----------------------------------------------------------------------------- nuclear@14: nuclear@14: static CTMint _ctmCheckMeshIntegrity(_CTMcontext * self) nuclear@14: { nuclear@14: CTMuint i; nuclear@14: _CTMfloatmap * map; nuclear@14: nuclear@14: // Check that we have all the mandatory data nuclear@14: if(!self->mVertices || !self->mIndices || (self->mVertexCount < 1) || nuclear@14: (self->mTriangleCount < 1)) nuclear@14: { nuclear@14: return CTM_FALSE; nuclear@14: } nuclear@14: nuclear@14: // Check that all indices are within range nuclear@14: for(i = 0; i < (self->mTriangleCount * 3); ++ i) nuclear@14: { nuclear@14: if(self->mIndices[i] >= self->mVertexCount) nuclear@14: { nuclear@14: return CTM_FALSE; nuclear@14: } nuclear@14: } nuclear@14: nuclear@14: // Check that all vertices are finite (non-NaN, non-inf) nuclear@14: for(i = 0; i < self->mVertexCount * 3; ++ i) nuclear@14: { nuclear@14: if(!isfinite(self->mVertices[i])) nuclear@14: { nuclear@14: return CTM_FALSE; nuclear@14: } nuclear@14: } nuclear@14: nuclear@14: // Check that all normals are finite (non-NaN, non-inf) nuclear@14: if(self->mNormals) nuclear@14: { nuclear@14: for(i = 0; i < self->mVertexCount * 3; ++ i) nuclear@14: { nuclear@14: if(!isfinite(self->mNormals[i])) nuclear@14: { nuclear@14: return CTM_FALSE; nuclear@14: } nuclear@14: } nuclear@14: } nuclear@14: nuclear@14: // Check that all UV maps are finite (non-NaN, non-inf) nuclear@14: map = self->mUVMaps; nuclear@14: while(map) nuclear@14: { nuclear@14: for(i = 0; i < self->mVertexCount * 2; ++ i) nuclear@14: { nuclear@14: if(!isfinite(map->mValues[i])) nuclear@14: { nuclear@14: return CTM_FALSE; nuclear@14: } nuclear@14: } nuclear@14: map = map->mNext; nuclear@14: } nuclear@14: nuclear@14: // Check that all attribute maps are finite (non-NaN, non-inf) nuclear@14: map = self->mAttribMaps; nuclear@14: while(map) nuclear@14: { nuclear@14: for(i = 0; i < self->mVertexCount * 4; ++ i) nuclear@14: { nuclear@14: if(!isfinite(map->mValues[i])) nuclear@14: { nuclear@14: return CTM_FALSE; nuclear@14: } nuclear@14: } nuclear@14: map = map->mNext; nuclear@14: } nuclear@14: nuclear@14: return CTM_TRUE; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmNewContext() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT CTMcontext CTMCALL ctmNewContext(CTMenum aMode) nuclear@14: { nuclear@14: _CTMcontext * self; nuclear@14: nuclear@14: // Allocate memory for the new structure nuclear@14: self = (_CTMcontext *) malloc(sizeof(_CTMcontext)); nuclear@14: nuclear@14: // Initialize structure (set null pointers and zero array lengths) nuclear@14: memset(self, 0, sizeof(_CTMcontext)); nuclear@14: self->mMode = aMode; nuclear@14: self->mError = CTM_NONE; nuclear@14: self->mMethod = CTM_METHOD_MG1; nuclear@14: self->mCompressionLevel = 1; nuclear@14: self->mVertexPrecision = 1.0f / 1024.0f; nuclear@14: self->mNormalPrecision = 1.0f / 256.0f; nuclear@14: nuclear@14: return (CTMcontext) self; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmFreeContext() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT void CTMCALL ctmFreeContext(CTMcontext aContext) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: if(!self) return; nuclear@14: nuclear@14: // Free all mesh resources nuclear@14: _ctmClearMesh(self); nuclear@14: nuclear@14: // Free the file comment nuclear@14: if(self->mFileComment) nuclear@14: free(self->mFileComment); nuclear@14: nuclear@14: // Free the context nuclear@14: free(self); nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmGetError() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT CTMenum CTMCALL ctmGetError(CTMcontext aContext) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: CTMenum err; nuclear@14: nuclear@14: if(!self) return CTM_INVALID_CONTEXT; nuclear@14: nuclear@14: // Get error code and reset error state nuclear@14: err = self->mError; nuclear@14: self->mError = CTM_NONE; nuclear@14: return err; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmErrorString() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT const char * CTMCALL ctmErrorString(CTMenum aError) nuclear@14: { nuclear@14: switch(aError) nuclear@14: { nuclear@14: case CTM_INVALID_CONTEXT: nuclear@14: return "CTM_INVALID_CONTEXT"; nuclear@14: case CTM_INVALID_ARGUMENT: nuclear@14: return "CTM_INVALID_ARGUMENT"; nuclear@14: case CTM_INVALID_OPERATION: nuclear@14: return "CTM_INVALID_OPERATION"; nuclear@14: case CTM_INVALID_MESH: nuclear@14: return "CTM_INVALID_MESH"; nuclear@14: case CTM_OUT_OF_MEMORY: nuclear@14: return "CTM_OUT_OF_MEMORY"; nuclear@14: case CTM_FILE_ERROR: nuclear@14: return "CTM_FILE_ERROR"; nuclear@14: case CTM_BAD_FORMAT: nuclear@14: return "CTM_BAD_FORMAT"; nuclear@14: case CTM_LZMA_ERROR: nuclear@14: return "CTM_LZMA_ERROR"; nuclear@14: case CTM_INTERNAL_ERROR: nuclear@14: return "CTM_INTERNAL_ERROR"; nuclear@14: case CTM_UNSUPPORTED_FORMAT_VERSION: nuclear@14: return "CTM_UNSUPPORTED_FORMAT_VERSION"; nuclear@14: default: nuclear@14: return "Unknown error code"; nuclear@14: } nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmGetInteger() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT CTMuint CTMCALL ctmGetInteger(CTMcontext aContext, CTMenum aProperty) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: if(!self) return 0; nuclear@14: nuclear@14: switch(aProperty) nuclear@14: { nuclear@14: case CTM_VERTEX_COUNT: nuclear@14: return self->mVertexCount; nuclear@14: nuclear@14: case CTM_TRIANGLE_COUNT: nuclear@14: return self->mTriangleCount; nuclear@14: nuclear@14: case CTM_UV_MAP_COUNT: nuclear@14: return self->mUVMapCount; nuclear@14: nuclear@14: case CTM_ATTRIB_MAP_COUNT: nuclear@14: return self->mAttribMapCount; nuclear@14: nuclear@14: case CTM_HAS_NORMALS: nuclear@14: return self->mNormals ? CTM_TRUE : CTM_FALSE; nuclear@14: nuclear@14: case CTM_COMPRESSION_METHOD: nuclear@14: return (CTMuint) self->mMethod; nuclear@14: nuclear@14: default: nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: } nuclear@14: nuclear@14: return 0; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmGetFloat() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT CTMfloat CTMCALL ctmGetFloat(CTMcontext aContext, CTMenum aProperty) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: if(!self) return 0.0f; nuclear@14: nuclear@14: switch(aProperty) nuclear@14: { nuclear@14: case CTM_VERTEX_PRECISION: nuclear@14: return self->mVertexPrecision; nuclear@14: nuclear@14: case CTM_NORMAL_PRECISION: nuclear@14: return self->mNormalPrecision; nuclear@14: nuclear@14: default: nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: } nuclear@14: nuclear@14: return 0.0f; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmGetIntegerArray() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT const CTMuint * CTMCALL ctmGetIntegerArray(CTMcontext aContext, nuclear@14: CTMenum aProperty) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: if(!self) return (CTMuint *) 0; nuclear@14: nuclear@14: switch(aProperty) nuclear@14: { nuclear@14: case CTM_INDICES: nuclear@14: return self->mIndices; nuclear@14: nuclear@14: default: nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: } nuclear@14: nuclear@14: return (CTMuint *) 0; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmGetFloatArray() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT const CTMfloat * CTMCALL ctmGetFloatArray(CTMcontext aContext, nuclear@14: CTMenum aProperty) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: _CTMfloatmap * map; nuclear@14: CTMuint i; nuclear@14: if(!self) return (CTMfloat *) 0; nuclear@14: nuclear@14: // Did the user request a UV map? nuclear@14: if((aProperty >= CTM_UV_MAP_1) && nuclear@14: ((CTMuint)(aProperty - CTM_UV_MAP_1) < self->mUVMapCount)) nuclear@14: { nuclear@14: map = self->mUVMaps; nuclear@14: i = CTM_UV_MAP_1; nuclear@14: while(map && (i != aProperty)) nuclear@14: { nuclear@14: map = map->mNext; nuclear@14: ++ i; nuclear@14: } nuclear@14: if(!map) nuclear@14: { nuclear@14: self->mError = CTM_INTERNAL_ERROR; nuclear@14: return (CTMfloat *) 0; nuclear@14: } nuclear@14: return map->mValues; nuclear@14: } nuclear@14: nuclear@14: // Did the user request an attribute map? nuclear@14: if((aProperty >= CTM_ATTRIB_MAP_1) && nuclear@14: ((CTMuint)(aProperty - CTM_ATTRIB_MAP_1) < self->mAttribMapCount)) nuclear@14: { nuclear@14: map = self->mAttribMaps; nuclear@14: i = CTM_ATTRIB_MAP_1; nuclear@14: while(map && (i != aProperty)) nuclear@14: { nuclear@14: map = map->mNext; nuclear@14: ++ i; nuclear@14: } nuclear@14: if(!map) nuclear@14: { nuclear@14: self->mError = CTM_INTERNAL_ERROR; nuclear@14: return (CTMfloat *) 0; nuclear@14: } nuclear@14: return map->mValues; nuclear@14: } nuclear@14: nuclear@14: switch(aProperty) nuclear@14: { nuclear@14: case CTM_VERTICES: nuclear@14: return self->mVertices; nuclear@14: nuclear@14: case CTM_NORMALS: nuclear@14: return self->mNormals; nuclear@14: nuclear@14: default: nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: } nuclear@14: nuclear@14: return (CTMfloat *) 0; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmGetNamedUVMap() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT CTMenum CTMCALL ctmGetNamedUVMap(CTMcontext aContext, nuclear@14: const char * aName) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: _CTMfloatmap * map; nuclear@14: CTMuint result; nuclear@14: if(!self) return CTM_NONE; nuclear@14: nuclear@14: map = self->mUVMaps; nuclear@14: result = CTM_UV_MAP_1; nuclear@14: while(map && (strcmp(aName, map->mName) != 0)) nuclear@14: { nuclear@14: map = map->mNext; nuclear@14: ++ result; nuclear@14: } nuclear@14: if(!map) nuclear@14: { nuclear@14: return CTM_NONE; nuclear@14: } nuclear@14: return result; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmGetUVMapString() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT const char * CTMCALL ctmGetUVMapString(CTMcontext aContext, nuclear@14: CTMenum aUVMap, CTMenum aProperty) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: _CTMfloatmap * map; nuclear@14: CTMuint i; nuclear@14: if(!self) return (const char *) 0; nuclear@14: nuclear@14: // Find the indicated map nuclear@14: map = self->mUVMaps; nuclear@14: i = CTM_UV_MAP_1; nuclear@14: while(map && (i != aUVMap)) nuclear@14: { nuclear@14: ++ i; nuclear@14: map = map->mNext; nuclear@14: } nuclear@14: if(!map) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: return (const char *) 0; nuclear@14: } nuclear@14: nuclear@14: // Get the requested string nuclear@14: switch(aProperty) nuclear@14: { nuclear@14: case CTM_NAME: nuclear@14: return (const char *) map->mName; nuclear@14: nuclear@14: case CTM_FILE_NAME: nuclear@14: return (const char *) map->mFileName; nuclear@14: nuclear@14: default: nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: } nuclear@14: nuclear@14: return (const char *) 0; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmGetUVMapFloat() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT CTMfloat CTMCALL ctmGetUVMapFloat(CTMcontext aContext, nuclear@14: CTMenum aUVMap, CTMenum aProperty) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: _CTMfloatmap * map; nuclear@14: CTMuint i; nuclear@14: if(!self) return 0.0f; nuclear@14: nuclear@14: // Find the indicated map nuclear@14: map = self->mUVMaps; nuclear@14: i = CTM_UV_MAP_1; nuclear@14: while(map && (i != aUVMap)) nuclear@14: { nuclear@14: ++ i; nuclear@14: map = map->mNext; nuclear@14: } nuclear@14: if(!map) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: return 0.0f; nuclear@14: } nuclear@14: nuclear@14: // Get the requested string nuclear@14: switch(aProperty) nuclear@14: { nuclear@14: case CTM_PRECISION: nuclear@14: return map->mPrecision; nuclear@14: nuclear@14: default: nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: } nuclear@14: nuclear@14: return 0.0f; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmGetAttribMapString() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT const char * CTMCALL ctmGetAttribMapString(CTMcontext aContext, nuclear@14: CTMenum aAttribMap, CTMenum aProperty) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: _CTMfloatmap * map; nuclear@14: CTMuint i; nuclear@14: if(!self) return (const char *) 0; nuclear@14: nuclear@14: // Find the indicated map nuclear@14: map = self->mAttribMaps; nuclear@14: i = CTM_ATTRIB_MAP_1; nuclear@14: while(map && (i != aAttribMap)) nuclear@14: { nuclear@14: ++ i; nuclear@14: map = map->mNext; nuclear@14: } nuclear@14: if(!map) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: return (const char *) 0; nuclear@14: } nuclear@14: nuclear@14: // Get the requested string nuclear@14: switch(aProperty) nuclear@14: { nuclear@14: case CTM_NAME: nuclear@14: return (const char *) map->mName; nuclear@14: nuclear@14: default: nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: } nuclear@14: nuclear@14: return (const char *) 0; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmGetAttribMapFloat() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT CTMfloat CTMCALL ctmGetAttribMapFloat(CTMcontext aContext, nuclear@14: CTMenum aAttribMap, CTMenum aProperty) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: _CTMfloatmap * map; nuclear@14: CTMuint i; nuclear@14: if(!self) return 0.0f; nuclear@14: nuclear@14: // Find the indicated map nuclear@14: map = self->mAttribMaps; nuclear@14: i = CTM_ATTRIB_MAP_1; nuclear@14: while(map && (i != aAttribMap)) nuclear@14: { nuclear@14: ++ i; nuclear@14: map = map->mNext; nuclear@14: } nuclear@14: if(!map) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: return 0.0f; nuclear@14: } nuclear@14: nuclear@14: // Get the requested string nuclear@14: switch(aProperty) nuclear@14: { nuclear@14: case CTM_PRECISION: nuclear@14: return map->mPrecision; nuclear@14: nuclear@14: default: nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: } nuclear@14: nuclear@14: return 0.0f; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmGetNamedAttribMap() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT CTMenum CTMCALL ctmGetNamedAttribMap(CTMcontext aContext, nuclear@14: const char * aName) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: _CTMfloatmap * map; nuclear@14: CTMuint result; nuclear@14: if(!self) return CTM_NONE; nuclear@14: nuclear@14: map = self->mAttribMaps; nuclear@14: result = CTM_ATTRIB_MAP_1; nuclear@14: while(map && (strcmp(aName, map->mName) != 0)) nuclear@14: { nuclear@14: map = map->mNext; nuclear@14: ++ result; nuclear@14: } nuclear@14: if(!map) nuclear@14: { nuclear@14: return CTM_NONE; nuclear@14: } nuclear@14: return result; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmGetString() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT const char * CTMCALL ctmGetString(CTMcontext aContext, nuclear@14: CTMenum aProperty) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: if(!self) return 0; nuclear@14: nuclear@14: switch(aProperty) nuclear@14: { nuclear@14: case CTM_FILE_COMMENT: nuclear@14: return (const char *) self->mFileComment; nuclear@14: nuclear@14: default: nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: } nuclear@14: nuclear@14: return (const char *) 0; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmCompressionMethod() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT void CTMCALL ctmCompressionMethod(CTMcontext aContext, nuclear@14: CTMenum aMethod) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: if(!self) return; nuclear@14: nuclear@14: // You are only allowed to change compression attributes in export mode nuclear@14: if(self->mMode != CTM_EXPORT) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_OPERATION; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Check arguments nuclear@14: if((aMethod != CTM_METHOD_RAW) && (aMethod != CTM_METHOD_MG1) && nuclear@14: (aMethod != CTM_METHOD_MG2)) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Set method nuclear@14: self->mMethod = aMethod; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmCompressionLevel() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT void CTMCALL ctmCompressionLevel(CTMcontext aContext, nuclear@14: CTMuint aLevel) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: if(!self) return; nuclear@14: nuclear@14: // You are only allowed to change compression attributes in export mode nuclear@14: if(self->mMode != CTM_EXPORT) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_OPERATION; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Check arguments nuclear@14: if(aLevel > 9) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Set the compression level nuclear@14: self->mCompressionLevel = aLevel; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmVertexPrecision() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT void CTMCALL ctmVertexPrecision(CTMcontext aContext, nuclear@14: CTMfloat aPrecision) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: if(!self) return; nuclear@14: nuclear@14: // You are only allowed to change compression attributes in export mode nuclear@14: if(self->mMode != CTM_EXPORT) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_OPERATION; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Check arguments nuclear@14: if(aPrecision <= 0.0f) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Set precision nuclear@14: self->mVertexPrecision = aPrecision; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmVertexPrecisionRel() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT void CTMCALL ctmVertexPrecisionRel(CTMcontext aContext, nuclear@14: CTMfloat aRelPrecision) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: CTMfloat avgEdgeLength, * p1, * p2; nuclear@14: CTMuint edgeCount, i, j; nuclear@14: if(!self) return; nuclear@14: nuclear@14: // You are only allowed to change compression attributes in export mode nuclear@14: if(self->mMode != CTM_EXPORT) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_OPERATION; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Check arguments nuclear@14: if(aRelPrecision <= 0.0f) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Calculate the average edge length (Note: we actually sum up all the half- nuclear@14: // edges, so in a proper solid mesh all connected edges are counted twice) nuclear@14: avgEdgeLength = 0.0f; nuclear@14: edgeCount = 0; nuclear@14: for(i = 0; i < self->mTriangleCount; ++ i) nuclear@14: { nuclear@14: p1 = &self->mVertices[self->mIndices[i * 3 + 2] * 3]; nuclear@14: for(j = 0; j < 3; ++ j) nuclear@14: { nuclear@14: p2 = &self->mVertices[self->mIndices[i * 3 + j] * 3]; nuclear@14: avgEdgeLength += sqrtf((p2[0] - p1[0]) * (p2[0] - p1[0]) + nuclear@14: (p2[1] - p1[1]) * (p2[1] - p1[1]) + nuclear@14: (p2[2] - p1[2]) * (p2[2] - p1[2])); nuclear@14: p1 = p2; nuclear@14: ++ edgeCount; nuclear@14: } nuclear@14: } nuclear@14: if(edgeCount == 0) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_MESH; nuclear@14: return; nuclear@14: } nuclear@14: avgEdgeLength /= (CTMfloat) edgeCount; nuclear@14: nuclear@14: // Set precision nuclear@14: self->mVertexPrecision = aRelPrecision * avgEdgeLength; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmNormalPrecision() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT void CTMCALL ctmNormalPrecision(CTMcontext aContext, nuclear@14: CTMfloat aPrecision) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: if(!self) return; nuclear@14: nuclear@14: // You are only allowed to change compression attributes in export mode nuclear@14: if(self->mMode != CTM_EXPORT) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_OPERATION; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Check arguments nuclear@14: if(aPrecision <= 0.0f) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Set precision nuclear@14: self->mNormalPrecision = aPrecision; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmUVCoordPrecision() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT void CTMCALL ctmUVCoordPrecision(CTMcontext aContext, nuclear@14: CTMenum aUVMap, CTMfloat aPrecision) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: _CTMfloatmap * map; nuclear@14: CTMuint i; nuclear@14: if(!self) return; nuclear@14: nuclear@14: // You are only allowed to change compression attributes in export mode nuclear@14: if(self->mMode != CTM_EXPORT) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_OPERATION; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Check arguments nuclear@14: if(aPrecision <= 0.0f) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Find the indicated map nuclear@14: map = self->mUVMaps; nuclear@14: i = CTM_UV_MAP_1; nuclear@14: while(map && (i != aUVMap)) nuclear@14: { nuclear@14: ++ i; nuclear@14: map = map->mNext; nuclear@14: } nuclear@14: if(!map) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Update the precision nuclear@14: map->mPrecision = aPrecision; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmAttribPrecision() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT void CTMCALL ctmAttribPrecision(CTMcontext aContext, nuclear@14: CTMenum aAttribMap, CTMfloat aPrecision) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: _CTMfloatmap * map; nuclear@14: CTMuint i; nuclear@14: if(!self) return; nuclear@14: nuclear@14: // You are only allowed to change compression attributes in export mode nuclear@14: if(self->mMode != CTM_EXPORT) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_OPERATION; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Check arguments nuclear@14: if(aPrecision <= 0.0f) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Find the indicated map nuclear@14: map = self->mAttribMaps; nuclear@14: i = CTM_ATTRIB_MAP_1; nuclear@14: while(map && (i != aAttribMap)) nuclear@14: { nuclear@14: ++ i; nuclear@14: map = map->mNext; nuclear@14: } nuclear@14: if(!map) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Update the precision nuclear@14: map->mPrecision = aPrecision; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmFileComment() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT void CTMCALL ctmFileComment(CTMcontext aContext, nuclear@14: const char * aFileComment) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: int len; nuclear@14: if(!self) return; nuclear@14: nuclear@14: // You are only allowed to change file attributes in export mode nuclear@14: if(self->mMode != CTM_EXPORT) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_OPERATION; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Free the old comment string, if necessary nuclear@14: if(self->mFileComment) nuclear@14: { nuclear@14: free(self->mFileComment); nuclear@14: self->mFileComment = (char *) 0; nuclear@14: } nuclear@14: nuclear@14: // Get length of string (if empty, do nothing) nuclear@14: if(!aFileComment) nuclear@14: return; nuclear@14: len = strlen(aFileComment); nuclear@14: if(!len) nuclear@14: return; nuclear@14: nuclear@14: // Copy the string nuclear@14: self->mFileComment = (char *) malloc(len + 1); nuclear@14: if(!self->mFileComment) nuclear@14: { nuclear@14: self->mError = CTM_OUT_OF_MEMORY; nuclear@14: return; nuclear@14: } nuclear@14: strcpy(self->mFileComment, aFileComment); nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmDefineMesh() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT void CTMCALL ctmDefineMesh(CTMcontext aContext, nuclear@14: const CTMfloat * aVertices, CTMuint aVertexCount, const CTMuint * aIndices, nuclear@14: CTMuint aTriangleCount, const CTMfloat * aNormals) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: if(!self) return; nuclear@14: nuclear@14: // You are only allowed to (re)define the mesh in export mode nuclear@14: if(self->mMode != CTM_EXPORT) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_OPERATION; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Check arguments nuclear@14: if(!aVertices || !aIndices || !aVertexCount || !aTriangleCount) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_ARGUMENT; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Clear the old mesh, if any nuclear@14: _ctmClearMesh(self); nuclear@14: nuclear@14: // Set vertex array pointer nuclear@14: self->mVertices = (CTMfloat *) aVertices; nuclear@14: self->mVertexCount = aVertexCount; nuclear@14: nuclear@14: // Set index array pointer nuclear@14: self->mIndices = (CTMuint *) aIndices; nuclear@14: self->mTriangleCount = aTriangleCount; nuclear@14: nuclear@14: // Set normal array pointer nuclear@14: self->mNormals = (CTMfloat *) aNormals; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // _ctmAddFloatMap() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: static _CTMfloatmap * _ctmAddFloatMap(_CTMcontext * self, nuclear@14: const CTMfloat * aValues, const char * aName, const char * aFileName, nuclear@14: _CTMfloatmap ** aList) nuclear@14: { nuclear@14: _CTMfloatmap * map; nuclear@14: CTMuint len; nuclear@14: nuclear@14: // Allocate memory for a new map list item and append it to the list nuclear@14: if(!*aList) nuclear@14: { nuclear@14: *aList = (_CTMfloatmap *) malloc(sizeof(_CTMfloatmap)); nuclear@14: map = *aList; nuclear@14: } nuclear@14: else nuclear@14: { nuclear@14: map = *aList; nuclear@14: while(map->mNext) nuclear@14: map = map->mNext; nuclear@14: map->mNext = (_CTMfloatmap *) malloc(sizeof(_CTMfloatmap)); nuclear@14: map = map->mNext; nuclear@14: } nuclear@14: if(!map) nuclear@14: { nuclear@14: self->mError = CTM_OUT_OF_MEMORY; nuclear@14: return (_CTMfloatmap *) 0; nuclear@14: } nuclear@14: nuclear@14: // Init the map item nuclear@14: memset(map, 0, sizeof(_CTMfloatmap)); nuclear@14: map->mPrecision = 1.0f / 1024.0f; nuclear@14: map->mValues = (CTMfloat *) aValues; nuclear@14: nuclear@14: // Set name of the map nuclear@14: if(aName) nuclear@14: { nuclear@14: // Get length of string (if empty, do nothing) nuclear@14: len = strlen(aName); nuclear@14: if(len) nuclear@14: { nuclear@14: // Copy the string nuclear@14: map->mName = (char *) malloc(len + 1); nuclear@14: if(!map->mName) nuclear@14: { nuclear@14: self->mError = CTM_OUT_OF_MEMORY; nuclear@14: free(map); nuclear@14: return (_CTMfloatmap *) 0; nuclear@14: } nuclear@14: strcpy(map->mName, aName); nuclear@14: } nuclear@14: } nuclear@14: nuclear@14: // Set file name reference for the map nuclear@14: if(aFileName) nuclear@14: { nuclear@14: // Get length of string (if empty, do nothing) nuclear@14: len = strlen(aFileName); nuclear@14: if(len) nuclear@14: { nuclear@14: // Copy the string nuclear@14: map->mFileName = (char *) malloc(len + 1); nuclear@14: if(!map->mFileName) nuclear@14: { nuclear@14: self->mError = CTM_OUT_OF_MEMORY; nuclear@14: if(map->mName) nuclear@14: free(map->mName); nuclear@14: free(map); nuclear@14: return (_CTMfloatmap *) 0; nuclear@14: } nuclear@14: strcpy(map->mFileName, aFileName); nuclear@14: } nuclear@14: } nuclear@14: nuclear@14: return map; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmAddUVMap() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT CTMenum CTMCALL ctmAddUVMap(CTMcontext aContext, nuclear@14: const CTMfloat * aUVCoords, const char * aName, const char * aFileName) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: _CTMfloatmap * map; nuclear@14: if(!self) return CTM_NONE; nuclear@14: nuclear@14: // Add a new UV map to the UV map list nuclear@14: map = _ctmAddFloatMap(self, aUVCoords, aName, aFileName, &self->mUVMaps); nuclear@14: if(!map) nuclear@14: return CTM_NONE; nuclear@14: else nuclear@14: { nuclear@14: // The default UV coordinate precision is 2^-12 nuclear@14: map->mPrecision = 1.0f / 4096.0f; nuclear@14: ++ self->mUVMapCount; nuclear@14: return CTM_UV_MAP_1 + self->mUVMapCount - 1; nuclear@14: } nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmAddAttribMap() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT CTMenum CTMCALL ctmAddAttribMap(CTMcontext aContext, nuclear@14: const CTMfloat * aAttribValues, const char * aName) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: _CTMfloatmap * map; nuclear@14: if(!self) return CTM_NONE; nuclear@14: nuclear@14: // Add a new attribute map to the attribute map list nuclear@14: map = _ctmAddFloatMap(self, aAttribValues, aName, (const char *) 0, nuclear@14: &self->mAttribMaps); nuclear@14: if(!map) nuclear@14: return CTM_NONE; nuclear@14: else nuclear@14: { nuclear@14: // The default vertex attribute precision is 2^-8 nuclear@14: map->mPrecision = 1.0f / 256.0f; nuclear@14: ++ self->mAttribMapCount; nuclear@14: return CTM_ATTRIB_MAP_1 + self->mAttribMapCount - 1; nuclear@14: } nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // _ctmDefaultRead() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: static CTMuint CTMCALL _ctmDefaultRead(void * aBuf, CTMuint aCount, nuclear@14: void * aUserData) nuclear@14: { nuclear@14: return (CTMuint) fread(aBuf, 1, (size_t) aCount, (FILE *) aUserData); nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmLoad() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT void CTMCALL ctmLoad(CTMcontext aContext, const char * aFileName) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: FILE * f; nuclear@14: if(!self) return; nuclear@14: nuclear@14: // You are only allowed to load data in import mode nuclear@14: if(self->mMode != CTM_IMPORT) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_OPERATION; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Open file stream nuclear@14: f = fopen(aFileName, "rb"); nuclear@14: if(!f) nuclear@14: { nuclear@14: self->mError = CTM_FILE_ERROR; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Load the file nuclear@14: ctmLoadCustom(self, _ctmDefaultRead, (void *) f); nuclear@14: nuclear@14: // Close file stream nuclear@14: fclose(f); nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // _ctmAllocateFloatMaps() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: static CTMuint _ctmAllocateFloatMaps(_CTMcontext * self, nuclear@14: _CTMfloatmap ** aMapListPtr, CTMuint aCount, CTMuint aChannels) nuclear@14: { nuclear@14: _CTMfloatmap ** mapListPtr; nuclear@14: CTMuint i, size; nuclear@14: nuclear@14: mapListPtr = aMapListPtr; nuclear@14: for(i = 0; i < aCount; ++ i) nuclear@14: { nuclear@14: // Allocate & clear memory for this map nuclear@14: *mapListPtr = (_CTMfloatmap *) malloc(sizeof(_CTMfloatmap)); nuclear@14: if(!*mapListPtr) nuclear@14: { nuclear@14: self->mError = CTM_OUT_OF_MEMORY; nuclear@14: return CTM_FALSE; nuclear@14: } nuclear@14: memset(*mapListPtr, 0, sizeof(_CTMfloatmap)); nuclear@14: nuclear@14: // Allocate & clear memory for the float array nuclear@14: size = aChannels * sizeof(CTMfloat) * self->mVertexCount; nuclear@14: (*mapListPtr)->mValues = (CTMfloat *) malloc(size); nuclear@14: if(!(*mapListPtr)->mValues) nuclear@14: { nuclear@14: self->mError = CTM_OUT_OF_MEMORY; nuclear@14: return CTM_FALSE; nuclear@14: } nuclear@14: memset((*mapListPtr)->mValues, 0, size); nuclear@14: nuclear@14: // Next map... nuclear@14: mapListPtr = &(*mapListPtr)->mNext; nuclear@14: } nuclear@14: nuclear@14: return CTM_TRUE; nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmLoadCustom() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT void CTMCALL ctmLoadCustom(CTMcontext aContext, CTMreadfn aReadFn, nuclear@14: void * aUserData) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: CTMuint formatVersion, flags, method; nuclear@14: if(!self) return; nuclear@14: nuclear@14: // You are only allowed to load data in import mode nuclear@14: if(self->mMode != CTM_IMPORT) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_OPERATION; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Initialize stream nuclear@14: self->mReadFn = aReadFn; nuclear@14: self->mUserData = aUserData; nuclear@14: nuclear@14: // Clear any old mesh arrays nuclear@14: _ctmClearMesh(self); nuclear@14: nuclear@14: // Read header from stream nuclear@14: if(_ctmStreamReadUINT(self) != FOURCC("OCTM")) nuclear@14: { nuclear@14: self->mError = CTM_BAD_FORMAT; nuclear@14: return; nuclear@14: } nuclear@14: formatVersion = _ctmStreamReadUINT(self); nuclear@14: if(formatVersion != _CTM_FORMAT_VERSION) nuclear@14: { nuclear@14: self->mError = CTM_UNSUPPORTED_FORMAT_VERSION; nuclear@14: return; nuclear@14: } nuclear@14: method = _ctmStreamReadUINT(self); nuclear@14: if(method == FOURCC("RAW\0")) nuclear@14: self->mMethod = CTM_METHOD_RAW; nuclear@14: else if(method == FOURCC("MG1\0")) nuclear@14: self->mMethod = CTM_METHOD_MG1; nuclear@14: else if(method == FOURCC("MG2\0")) nuclear@14: self->mMethod = CTM_METHOD_MG2; nuclear@14: else nuclear@14: { nuclear@14: self->mError = CTM_BAD_FORMAT; nuclear@14: return; nuclear@14: } nuclear@14: self->mVertexCount = _ctmStreamReadUINT(self); nuclear@14: if(self->mVertexCount == 0) nuclear@14: { nuclear@14: self->mError = CTM_BAD_FORMAT; nuclear@14: return; nuclear@14: } nuclear@14: self->mTriangleCount = _ctmStreamReadUINT(self); nuclear@14: if(self->mTriangleCount == 0) nuclear@14: { nuclear@14: self->mError = CTM_BAD_FORMAT; nuclear@14: return; nuclear@14: } nuclear@14: self->mUVMapCount = _ctmStreamReadUINT(self); nuclear@14: self->mAttribMapCount = _ctmStreamReadUINT(self); nuclear@14: flags = _ctmStreamReadUINT(self); nuclear@14: _ctmStreamReadSTRING(self, &self->mFileComment); nuclear@14: nuclear@14: // Allocate memory for the mesh arrays nuclear@14: self->mVertices = (CTMfloat *) malloc(self->mVertexCount * sizeof(CTMfloat) * 3); nuclear@14: if(!self->mVertices) nuclear@14: { nuclear@14: self->mError = CTM_OUT_OF_MEMORY; nuclear@14: return; nuclear@14: } nuclear@14: self->mIndices = (CTMuint *) malloc(self->mTriangleCount * sizeof(CTMuint) * 3); nuclear@14: if(!self->mIndices) nuclear@14: { nuclear@14: _ctmClearMesh(self); nuclear@14: self->mError = CTM_OUT_OF_MEMORY; nuclear@14: return; nuclear@14: } nuclear@14: if(flags & _CTM_HAS_NORMALS_BIT) nuclear@14: { nuclear@14: self->mNormals = (CTMfloat *) malloc(self->mVertexCount * sizeof(CTMfloat) * 3); nuclear@14: if(!self->mNormals) nuclear@14: { nuclear@14: _ctmClearMesh(self); nuclear@14: self->mError = CTM_OUT_OF_MEMORY; nuclear@14: return; nuclear@14: } nuclear@14: } nuclear@14: nuclear@14: // Allocate memory for the UV and attribute maps (if any) nuclear@14: if(!_ctmAllocateFloatMaps(self, &self->mUVMaps, self->mUVMapCount, 2)) nuclear@14: { nuclear@14: _ctmClearMesh(self); nuclear@14: self->mError = CTM_OUT_OF_MEMORY; nuclear@14: return; nuclear@14: } nuclear@14: if(!_ctmAllocateFloatMaps(self, &self->mAttribMaps, self->mAttribMapCount, 4)) nuclear@14: { nuclear@14: _ctmClearMesh(self); nuclear@14: self->mError = CTM_OUT_OF_MEMORY; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Uncompress from stream nuclear@14: switch(self->mMethod) nuclear@14: { nuclear@14: case CTM_METHOD_RAW: nuclear@14: _ctmUncompressMesh_RAW(self); nuclear@14: break; nuclear@14: nuclear@14: case CTM_METHOD_MG1: nuclear@14: _ctmUncompressMesh_MG1(self); nuclear@14: break; nuclear@14: nuclear@14: case CTM_METHOD_MG2: nuclear@14: _ctmUncompressMesh_MG2(self); nuclear@14: break; nuclear@14: nuclear@14: default: nuclear@14: self->mError = CTM_INTERNAL_ERROR; nuclear@14: } nuclear@14: nuclear@14: // Check mesh integrity nuclear@14: if(!_ctmCheckMeshIntegrity(self)) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_MESH; nuclear@14: return; nuclear@14: } nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // _ctmDefaultWrite() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: static CTMuint CTMCALL _ctmDefaultWrite(const void * aBuf, CTMuint aCount, nuclear@14: void * aUserData) nuclear@14: { nuclear@14: return (CTMuint) fwrite(aBuf, 1, (size_t) aCount, (FILE *) aUserData); nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmSave() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: CTMEXPORT void CTMCALL ctmSave(CTMcontext aContext, const char * aFileName) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: FILE * f; nuclear@14: if(!self) return; nuclear@14: nuclear@14: // You are only allowed to save data in export mode nuclear@14: if(self->mMode != CTM_EXPORT) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_OPERATION; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Open file stream nuclear@14: f = fopen(aFileName, "wb"); nuclear@14: if(!f) nuclear@14: { nuclear@14: self->mError = CTM_FILE_ERROR; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Save the file nuclear@14: ctmSaveCustom(self, _ctmDefaultWrite, (void *) f); nuclear@14: nuclear@14: // Close file stream nuclear@14: fclose(f); nuclear@14: } nuclear@14: nuclear@14: //----------------------------------------------------------------------------- nuclear@14: // ctmSaveCustom() nuclear@14: //----------------------------------------------------------------------------- nuclear@14: void CTMCALL ctmSaveCustom(CTMcontext aContext, CTMwritefn aWriteFn, nuclear@14: void * aUserData) nuclear@14: { nuclear@14: _CTMcontext * self = (_CTMcontext *) aContext; nuclear@14: CTMuint flags; nuclear@14: if(!self) return; nuclear@14: nuclear@14: // You are only allowed to save data in export mode nuclear@14: if(self->mMode != CTM_EXPORT) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_OPERATION; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Check mesh integrity nuclear@14: if(!_ctmCheckMeshIntegrity(self)) nuclear@14: { nuclear@14: self->mError = CTM_INVALID_MESH; nuclear@14: return; nuclear@14: } nuclear@14: nuclear@14: // Initialize stream nuclear@14: self->mWriteFn = aWriteFn; nuclear@14: self->mUserData = aUserData; nuclear@14: nuclear@14: // Determine flags nuclear@14: flags = 0; nuclear@14: if(self->mNormals) nuclear@14: flags |= _CTM_HAS_NORMALS_BIT; nuclear@14: nuclear@14: // Write header to stream nuclear@14: _ctmStreamWrite(self, (void *) "OCTM", 4); nuclear@14: _ctmStreamWriteUINT(self, _CTM_FORMAT_VERSION); nuclear@14: switch(self->mMethod) nuclear@14: { nuclear@14: case CTM_METHOD_RAW: nuclear@14: _ctmStreamWrite(self, (void *) "RAW\0", 4); nuclear@14: break; nuclear@14: nuclear@14: case CTM_METHOD_MG1: nuclear@14: _ctmStreamWrite(self, (void *) "MG1\0", 4); nuclear@14: break; nuclear@14: nuclear@14: case CTM_METHOD_MG2: nuclear@14: _ctmStreamWrite(self, (void *) "MG2\0", 4); nuclear@14: break; nuclear@14: nuclear@14: default: nuclear@14: self->mError = CTM_INTERNAL_ERROR; nuclear@14: return; nuclear@14: } nuclear@14: _ctmStreamWriteUINT(self, self->mVertexCount); nuclear@14: _ctmStreamWriteUINT(self, self->mTriangleCount); nuclear@14: _ctmStreamWriteUINT(self, self->mUVMapCount); nuclear@14: _ctmStreamWriteUINT(self, self->mAttribMapCount); nuclear@14: _ctmStreamWriteUINT(self, flags); nuclear@14: _ctmStreamWriteSTRING(self, self->mFileComment); nuclear@14: nuclear@14: // Compress to stream nuclear@14: switch(self->mMethod) nuclear@14: { nuclear@14: case CTM_METHOD_RAW: nuclear@14: _ctmCompressMesh_RAW(self); nuclear@14: break; nuclear@14: nuclear@14: case CTM_METHOD_MG1: nuclear@14: _ctmCompressMesh_MG1(self); nuclear@14: break; nuclear@14: nuclear@14: case CTM_METHOD_MG2: nuclear@14: _ctmCompressMesh_MG2(self); nuclear@14: break; nuclear@14: nuclear@14: default: nuclear@14: self->mError = CTM_INTERNAL_ERROR; nuclear@14: return; nuclear@14: } nuclear@14: }