goat3d
diff libs/openctm/openctm.c @ 14:188c697b3b49
- added a document describing the goat3d file format chunk hierarchy
- started an alternative XML-based file format
- added the openctm library
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 26 Sep 2013 04:47:05 +0300 |
parents | |
children | 21319e71117f |
line diff
1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/libs/openctm/openctm.c Thu Sep 26 04:47:05 2013 +0300 1.3 @@ -0,0 +1,1423 @@ 1.4 +//----------------------------------------------------------------------------- 1.5 +// Product: OpenCTM 1.6 +// File: openctm.c 1.7 +// Description: API functions. 1.8 +//----------------------------------------------------------------------------- 1.9 +// Copyright (c) 2009-2010 Marcus Geelnard 1.10 +// 1.11 +// This software is provided 'as-is', without any express or implied 1.12 +// warranty. In no event will the authors be held liable for any damages 1.13 +// arising from the use of this software. 1.14 +// 1.15 +// Permission is granted to anyone to use this software for any purpose, 1.16 +// including commercial applications, and to alter it and redistribute it 1.17 +// freely, subject to the following restrictions: 1.18 +// 1.19 +// 1. The origin of this software must not be misrepresented; you must not 1.20 +// claim that you wrote the original software. If you use this software 1.21 +// in a product, an acknowledgment in the product documentation would be 1.22 +// appreciated but is not required. 1.23 +// 1.24 +// 2. Altered source versions must be plainly marked as such, and must not 1.25 +// be misrepresented as being the original software. 1.26 +// 1.27 +// 3. This notice may not be removed or altered from any source 1.28 +// distribution. 1.29 +//----------------------------------------------------------------------------- 1.30 + 1.31 +#include <stdlib.h> 1.32 +#include <string.h> 1.33 +#include <stdio.h> 1.34 +#include <math.h> 1.35 +#include "openctm.h" 1.36 +#include "internal.h" 1.37 + 1.38 + 1.39 +// The C99 macro isfinite() is not supported on all platforms (specifically, 1.40 +// MS Visual Studio does not support C99) 1.41 +#if !defined(isfinite) && defined(_MSC_VER) 1.42 + #include <float.h> 1.43 + #define isfinite(x) _finite(x) 1.44 +#endif 1.45 + 1.46 + 1.47 +//----------------------------------------------------------------------------- 1.48 +// _ctmFreeMapList() - Free a float map list. 1.49 +//----------------------------------------------------------------------------- 1.50 +static void _ctmFreeMapList(_CTMcontext * self, _CTMfloatmap * aMapList) 1.51 +{ 1.52 + _CTMfloatmap * map, * nextMap; 1.53 + map = aMapList; 1.54 + while(map) 1.55 + { 1.56 + // Free internally allocated array (if we are in import mode) 1.57 + if((self->mMode == CTM_IMPORT) && map->mValues) 1.58 + free(map->mValues); 1.59 + 1.60 + // Free map name 1.61 + if(map->mName) 1.62 + free(map->mName); 1.63 + 1.64 + // Free file name 1.65 + if(map->mFileName) 1.66 + free(map->mFileName); 1.67 + 1.68 + nextMap = map->mNext; 1.69 + free(map); 1.70 + map = nextMap; 1.71 + } 1.72 +} 1.73 + 1.74 +//----------------------------------------------------------------------------- 1.75 +// _ctmClearMesh() - Clear the mesh in a CTM context. 1.76 +//----------------------------------------------------------------------------- 1.77 +static void _ctmClearMesh(_CTMcontext * self) 1.78 +{ 1.79 + // Free internally allocated mesh arrays 1.80 + if(self->mMode == CTM_IMPORT) 1.81 + { 1.82 + if(self->mVertices) 1.83 + free(self->mVertices); 1.84 + if(self->mIndices) 1.85 + free(self->mIndices); 1.86 + if(self->mNormals) 1.87 + free(self->mNormals); 1.88 + } 1.89 + 1.90 + // Clear externally assigned mesh arrays 1.91 + self->mVertices = (CTMfloat *) 0; 1.92 + self->mVertexCount = 0; 1.93 + self->mIndices = (CTMuint *) 0; 1.94 + self->mTriangleCount = 0; 1.95 + self->mNormals = (CTMfloat *) 0; 1.96 + 1.97 + // Free UV coordinate map list 1.98 + _ctmFreeMapList(self, self->mUVMaps); 1.99 + self->mUVMaps = (_CTMfloatmap *) 0; 1.100 + self->mUVMapCount = 0; 1.101 + 1.102 + // Free attribute map list 1.103 + _ctmFreeMapList(self, self->mAttribMaps); 1.104 + self->mAttribMaps = (_CTMfloatmap *) 0; 1.105 + self->mAttribMapCount = 0; 1.106 +} 1.107 + 1.108 +//----------------------------------------------------------------------------- 1.109 +// _ctmCheckMeshIntegrity() - Check if a mesh is valid (i.e. is non-empty, and 1.110 +// contains valid data). 1.111 +//----------------------------------------------------------------------------- 1.112 + 1.113 +static CTMint _ctmCheckMeshIntegrity(_CTMcontext * self) 1.114 +{ 1.115 + CTMuint i; 1.116 + _CTMfloatmap * map; 1.117 + 1.118 + // Check that we have all the mandatory data 1.119 + if(!self->mVertices || !self->mIndices || (self->mVertexCount < 1) || 1.120 + (self->mTriangleCount < 1)) 1.121 + { 1.122 + return CTM_FALSE; 1.123 + } 1.124 + 1.125 + // Check that all indices are within range 1.126 + for(i = 0; i < (self->mTriangleCount * 3); ++ i) 1.127 + { 1.128 + if(self->mIndices[i] >= self->mVertexCount) 1.129 + { 1.130 + return CTM_FALSE; 1.131 + } 1.132 + } 1.133 + 1.134 + // Check that all vertices are finite (non-NaN, non-inf) 1.135 + for(i = 0; i < self->mVertexCount * 3; ++ i) 1.136 + { 1.137 + if(!isfinite(self->mVertices[i])) 1.138 + { 1.139 + return CTM_FALSE; 1.140 + } 1.141 + } 1.142 + 1.143 + // Check that all normals are finite (non-NaN, non-inf) 1.144 + if(self->mNormals) 1.145 + { 1.146 + for(i = 0; i < self->mVertexCount * 3; ++ i) 1.147 + { 1.148 + if(!isfinite(self->mNormals[i])) 1.149 + { 1.150 + return CTM_FALSE; 1.151 + } 1.152 + } 1.153 + } 1.154 + 1.155 + // Check that all UV maps are finite (non-NaN, non-inf) 1.156 + map = self->mUVMaps; 1.157 + while(map) 1.158 + { 1.159 + for(i = 0; i < self->mVertexCount * 2; ++ i) 1.160 + { 1.161 + if(!isfinite(map->mValues[i])) 1.162 + { 1.163 + return CTM_FALSE; 1.164 + } 1.165 + } 1.166 + map = map->mNext; 1.167 + } 1.168 + 1.169 + // Check that all attribute maps are finite (non-NaN, non-inf) 1.170 + map = self->mAttribMaps; 1.171 + while(map) 1.172 + { 1.173 + for(i = 0; i < self->mVertexCount * 4; ++ i) 1.174 + { 1.175 + if(!isfinite(map->mValues[i])) 1.176 + { 1.177 + return CTM_FALSE; 1.178 + } 1.179 + } 1.180 + map = map->mNext; 1.181 + } 1.182 + 1.183 + return CTM_TRUE; 1.184 +} 1.185 + 1.186 +//----------------------------------------------------------------------------- 1.187 +// ctmNewContext() 1.188 +//----------------------------------------------------------------------------- 1.189 +CTMEXPORT CTMcontext CTMCALL ctmNewContext(CTMenum aMode) 1.190 +{ 1.191 + _CTMcontext * self; 1.192 + 1.193 + // Allocate memory for the new structure 1.194 + self = (_CTMcontext *) malloc(sizeof(_CTMcontext)); 1.195 + 1.196 + // Initialize structure (set null pointers and zero array lengths) 1.197 + memset(self, 0, sizeof(_CTMcontext)); 1.198 + self->mMode = aMode; 1.199 + self->mError = CTM_NONE; 1.200 + self->mMethod = CTM_METHOD_MG1; 1.201 + self->mCompressionLevel = 1; 1.202 + self->mVertexPrecision = 1.0f / 1024.0f; 1.203 + self->mNormalPrecision = 1.0f / 256.0f; 1.204 + 1.205 + return (CTMcontext) self; 1.206 +} 1.207 + 1.208 +//----------------------------------------------------------------------------- 1.209 +// ctmFreeContext() 1.210 +//----------------------------------------------------------------------------- 1.211 +CTMEXPORT void CTMCALL ctmFreeContext(CTMcontext aContext) 1.212 +{ 1.213 + _CTMcontext * self = (_CTMcontext *) aContext; 1.214 + if(!self) return; 1.215 + 1.216 + // Free all mesh resources 1.217 + _ctmClearMesh(self); 1.218 + 1.219 + // Free the file comment 1.220 + if(self->mFileComment) 1.221 + free(self->mFileComment); 1.222 + 1.223 + // Free the context 1.224 + free(self); 1.225 +} 1.226 + 1.227 +//----------------------------------------------------------------------------- 1.228 +// ctmGetError() 1.229 +//----------------------------------------------------------------------------- 1.230 +CTMEXPORT CTMenum CTMCALL ctmGetError(CTMcontext aContext) 1.231 +{ 1.232 + _CTMcontext * self = (_CTMcontext *) aContext; 1.233 + CTMenum err; 1.234 + 1.235 + if(!self) return CTM_INVALID_CONTEXT; 1.236 + 1.237 + // Get error code and reset error state 1.238 + err = self->mError; 1.239 + self->mError = CTM_NONE; 1.240 + return err; 1.241 +} 1.242 + 1.243 +//----------------------------------------------------------------------------- 1.244 +// ctmErrorString() 1.245 +//----------------------------------------------------------------------------- 1.246 +CTMEXPORT const char * CTMCALL ctmErrorString(CTMenum aError) 1.247 +{ 1.248 + switch(aError) 1.249 + { 1.250 + case CTM_INVALID_CONTEXT: 1.251 + return "CTM_INVALID_CONTEXT"; 1.252 + case CTM_INVALID_ARGUMENT: 1.253 + return "CTM_INVALID_ARGUMENT"; 1.254 + case CTM_INVALID_OPERATION: 1.255 + return "CTM_INVALID_OPERATION"; 1.256 + case CTM_INVALID_MESH: 1.257 + return "CTM_INVALID_MESH"; 1.258 + case CTM_OUT_OF_MEMORY: 1.259 + return "CTM_OUT_OF_MEMORY"; 1.260 + case CTM_FILE_ERROR: 1.261 + return "CTM_FILE_ERROR"; 1.262 + case CTM_BAD_FORMAT: 1.263 + return "CTM_BAD_FORMAT"; 1.264 + case CTM_LZMA_ERROR: 1.265 + return "CTM_LZMA_ERROR"; 1.266 + case CTM_INTERNAL_ERROR: 1.267 + return "CTM_INTERNAL_ERROR"; 1.268 + case CTM_UNSUPPORTED_FORMAT_VERSION: 1.269 + return "CTM_UNSUPPORTED_FORMAT_VERSION"; 1.270 + default: 1.271 + return "Unknown error code"; 1.272 + } 1.273 +} 1.274 + 1.275 +//----------------------------------------------------------------------------- 1.276 +// ctmGetInteger() 1.277 +//----------------------------------------------------------------------------- 1.278 +CTMEXPORT CTMuint CTMCALL ctmGetInteger(CTMcontext aContext, CTMenum aProperty) 1.279 +{ 1.280 + _CTMcontext * self = (_CTMcontext *) aContext; 1.281 + if(!self) return 0; 1.282 + 1.283 + switch(aProperty) 1.284 + { 1.285 + case CTM_VERTEX_COUNT: 1.286 + return self->mVertexCount; 1.287 + 1.288 + case CTM_TRIANGLE_COUNT: 1.289 + return self->mTriangleCount; 1.290 + 1.291 + case CTM_UV_MAP_COUNT: 1.292 + return self->mUVMapCount; 1.293 + 1.294 + case CTM_ATTRIB_MAP_COUNT: 1.295 + return self->mAttribMapCount; 1.296 + 1.297 + case CTM_HAS_NORMALS: 1.298 + return self->mNormals ? CTM_TRUE : CTM_FALSE; 1.299 + 1.300 + case CTM_COMPRESSION_METHOD: 1.301 + return (CTMuint) self->mMethod; 1.302 + 1.303 + default: 1.304 + self->mError = CTM_INVALID_ARGUMENT; 1.305 + } 1.306 + 1.307 + return 0; 1.308 +} 1.309 + 1.310 +//----------------------------------------------------------------------------- 1.311 +// ctmGetFloat() 1.312 +//----------------------------------------------------------------------------- 1.313 +CTMEXPORT CTMfloat CTMCALL ctmGetFloat(CTMcontext aContext, CTMenum aProperty) 1.314 +{ 1.315 + _CTMcontext * self = (_CTMcontext *) aContext; 1.316 + if(!self) return 0.0f; 1.317 + 1.318 + switch(aProperty) 1.319 + { 1.320 + case CTM_VERTEX_PRECISION: 1.321 + return self->mVertexPrecision; 1.322 + 1.323 + case CTM_NORMAL_PRECISION: 1.324 + return self->mNormalPrecision; 1.325 + 1.326 + default: 1.327 + self->mError = CTM_INVALID_ARGUMENT; 1.328 + } 1.329 + 1.330 + return 0.0f; 1.331 +} 1.332 + 1.333 +//----------------------------------------------------------------------------- 1.334 +// ctmGetIntegerArray() 1.335 +//----------------------------------------------------------------------------- 1.336 +CTMEXPORT const CTMuint * CTMCALL ctmGetIntegerArray(CTMcontext aContext, 1.337 + CTMenum aProperty) 1.338 +{ 1.339 + _CTMcontext * self = (_CTMcontext *) aContext; 1.340 + if(!self) return (CTMuint *) 0; 1.341 + 1.342 + switch(aProperty) 1.343 + { 1.344 + case CTM_INDICES: 1.345 + return self->mIndices; 1.346 + 1.347 + default: 1.348 + self->mError = CTM_INVALID_ARGUMENT; 1.349 + } 1.350 + 1.351 + return (CTMuint *) 0; 1.352 +} 1.353 + 1.354 +//----------------------------------------------------------------------------- 1.355 +// ctmGetFloatArray() 1.356 +//----------------------------------------------------------------------------- 1.357 +CTMEXPORT const CTMfloat * CTMCALL ctmGetFloatArray(CTMcontext aContext, 1.358 + CTMenum aProperty) 1.359 +{ 1.360 + _CTMcontext * self = (_CTMcontext *) aContext; 1.361 + _CTMfloatmap * map; 1.362 + CTMuint i; 1.363 + if(!self) return (CTMfloat *) 0; 1.364 + 1.365 + // Did the user request a UV map? 1.366 + if((aProperty >= CTM_UV_MAP_1) && 1.367 + ((CTMuint)(aProperty - CTM_UV_MAP_1) < self->mUVMapCount)) 1.368 + { 1.369 + map = self->mUVMaps; 1.370 + i = CTM_UV_MAP_1; 1.371 + while(map && (i != aProperty)) 1.372 + { 1.373 + map = map->mNext; 1.374 + ++ i; 1.375 + } 1.376 + if(!map) 1.377 + { 1.378 + self->mError = CTM_INTERNAL_ERROR; 1.379 + return (CTMfloat *) 0; 1.380 + } 1.381 + return map->mValues; 1.382 + } 1.383 + 1.384 + // Did the user request an attribute map? 1.385 + if((aProperty >= CTM_ATTRIB_MAP_1) && 1.386 + ((CTMuint)(aProperty - CTM_ATTRIB_MAP_1) < self->mAttribMapCount)) 1.387 + { 1.388 + map = self->mAttribMaps; 1.389 + i = CTM_ATTRIB_MAP_1; 1.390 + while(map && (i != aProperty)) 1.391 + { 1.392 + map = map->mNext; 1.393 + ++ i; 1.394 + } 1.395 + if(!map) 1.396 + { 1.397 + self->mError = CTM_INTERNAL_ERROR; 1.398 + return (CTMfloat *) 0; 1.399 + } 1.400 + return map->mValues; 1.401 + } 1.402 + 1.403 + switch(aProperty) 1.404 + { 1.405 + case CTM_VERTICES: 1.406 + return self->mVertices; 1.407 + 1.408 + case CTM_NORMALS: 1.409 + return self->mNormals; 1.410 + 1.411 + default: 1.412 + self->mError = CTM_INVALID_ARGUMENT; 1.413 + } 1.414 + 1.415 + return (CTMfloat *) 0; 1.416 +} 1.417 + 1.418 +//----------------------------------------------------------------------------- 1.419 +// ctmGetNamedUVMap() 1.420 +//----------------------------------------------------------------------------- 1.421 +CTMEXPORT CTMenum CTMCALL ctmGetNamedUVMap(CTMcontext aContext, 1.422 + const char * aName) 1.423 +{ 1.424 + _CTMcontext * self = (_CTMcontext *) aContext; 1.425 + _CTMfloatmap * map; 1.426 + CTMuint result; 1.427 + if(!self) return CTM_NONE; 1.428 + 1.429 + map = self->mUVMaps; 1.430 + result = CTM_UV_MAP_1; 1.431 + while(map && (strcmp(aName, map->mName) != 0)) 1.432 + { 1.433 + map = map->mNext; 1.434 + ++ result; 1.435 + } 1.436 + if(!map) 1.437 + { 1.438 + return CTM_NONE; 1.439 + } 1.440 + return result; 1.441 +} 1.442 + 1.443 +//----------------------------------------------------------------------------- 1.444 +// ctmGetUVMapString() 1.445 +//----------------------------------------------------------------------------- 1.446 +CTMEXPORT const char * CTMCALL ctmGetUVMapString(CTMcontext aContext, 1.447 + CTMenum aUVMap, CTMenum aProperty) 1.448 +{ 1.449 + _CTMcontext * self = (_CTMcontext *) aContext; 1.450 + _CTMfloatmap * map; 1.451 + CTMuint i; 1.452 + if(!self) return (const char *) 0; 1.453 + 1.454 + // Find the indicated map 1.455 + map = self->mUVMaps; 1.456 + i = CTM_UV_MAP_1; 1.457 + while(map && (i != aUVMap)) 1.458 + { 1.459 + ++ i; 1.460 + map = map->mNext; 1.461 + } 1.462 + if(!map) 1.463 + { 1.464 + self->mError = CTM_INVALID_ARGUMENT; 1.465 + return (const char *) 0; 1.466 + } 1.467 + 1.468 + // Get the requested string 1.469 + switch(aProperty) 1.470 + { 1.471 + case CTM_NAME: 1.472 + return (const char *) map->mName; 1.473 + 1.474 + case CTM_FILE_NAME: 1.475 + return (const char *) map->mFileName; 1.476 + 1.477 + default: 1.478 + self->mError = CTM_INVALID_ARGUMENT; 1.479 + } 1.480 + 1.481 + return (const char *) 0; 1.482 +} 1.483 + 1.484 +//----------------------------------------------------------------------------- 1.485 +// ctmGetUVMapFloat() 1.486 +//----------------------------------------------------------------------------- 1.487 +CTMEXPORT CTMfloat CTMCALL ctmGetUVMapFloat(CTMcontext aContext, 1.488 + CTMenum aUVMap, CTMenum aProperty) 1.489 +{ 1.490 + _CTMcontext * self = (_CTMcontext *) aContext; 1.491 + _CTMfloatmap * map; 1.492 + CTMuint i; 1.493 + if(!self) return 0.0f; 1.494 + 1.495 + // Find the indicated map 1.496 + map = self->mUVMaps; 1.497 + i = CTM_UV_MAP_1; 1.498 + while(map && (i != aUVMap)) 1.499 + { 1.500 + ++ i; 1.501 + map = map->mNext; 1.502 + } 1.503 + if(!map) 1.504 + { 1.505 + self->mError = CTM_INVALID_ARGUMENT; 1.506 + return 0.0f; 1.507 + } 1.508 + 1.509 + // Get the requested string 1.510 + switch(aProperty) 1.511 + { 1.512 + case CTM_PRECISION: 1.513 + return map->mPrecision; 1.514 + 1.515 + default: 1.516 + self->mError = CTM_INVALID_ARGUMENT; 1.517 + } 1.518 + 1.519 + return 0.0f; 1.520 +} 1.521 + 1.522 +//----------------------------------------------------------------------------- 1.523 +// ctmGetAttribMapString() 1.524 +//----------------------------------------------------------------------------- 1.525 +CTMEXPORT const char * CTMCALL ctmGetAttribMapString(CTMcontext aContext, 1.526 + CTMenum aAttribMap, CTMenum aProperty) 1.527 +{ 1.528 + _CTMcontext * self = (_CTMcontext *) aContext; 1.529 + _CTMfloatmap * map; 1.530 + CTMuint i; 1.531 + if(!self) return (const char *) 0; 1.532 + 1.533 + // Find the indicated map 1.534 + map = self->mAttribMaps; 1.535 + i = CTM_ATTRIB_MAP_1; 1.536 + while(map && (i != aAttribMap)) 1.537 + { 1.538 + ++ i; 1.539 + map = map->mNext; 1.540 + } 1.541 + if(!map) 1.542 + { 1.543 + self->mError = CTM_INVALID_ARGUMENT; 1.544 + return (const char *) 0; 1.545 + } 1.546 + 1.547 + // Get the requested string 1.548 + switch(aProperty) 1.549 + { 1.550 + case CTM_NAME: 1.551 + return (const char *) map->mName; 1.552 + 1.553 + default: 1.554 + self->mError = CTM_INVALID_ARGUMENT; 1.555 + } 1.556 + 1.557 + return (const char *) 0; 1.558 +} 1.559 + 1.560 +//----------------------------------------------------------------------------- 1.561 +// ctmGetAttribMapFloat() 1.562 +//----------------------------------------------------------------------------- 1.563 +CTMEXPORT CTMfloat CTMCALL ctmGetAttribMapFloat(CTMcontext aContext, 1.564 + CTMenum aAttribMap, CTMenum aProperty) 1.565 +{ 1.566 + _CTMcontext * self = (_CTMcontext *) aContext; 1.567 + _CTMfloatmap * map; 1.568 + CTMuint i; 1.569 + if(!self) return 0.0f; 1.570 + 1.571 + // Find the indicated map 1.572 + map = self->mAttribMaps; 1.573 + i = CTM_ATTRIB_MAP_1; 1.574 + while(map && (i != aAttribMap)) 1.575 + { 1.576 + ++ i; 1.577 + map = map->mNext; 1.578 + } 1.579 + if(!map) 1.580 + { 1.581 + self->mError = CTM_INVALID_ARGUMENT; 1.582 + return 0.0f; 1.583 + } 1.584 + 1.585 + // Get the requested string 1.586 + switch(aProperty) 1.587 + { 1.588 + case CTM_PRECISION: 1.589 + return map->mPrecision; 1.590 + 1.591 + default: 1.592 + self->mError = CTM_INVALID_ARGUMENT; 1.593 + } 1.594 + 1.595 + return 0.0f; 1.596 +} 1.597 + 1.598 +//----------------------------------------------------------------------------- 1.599 +// ctmGetNamedAttribMap() 1.600 +//----------------------------------------------------------------------------- 1.601 +CTMEXPORT CTMenum CTMCALL ctmGetNamedAttribMap(CTMcontext aContext, 1.602 + const char * aName) 1.603 +{ 1.604 + _CTMcontext * self = (_CTMcontext *) aContext; 1.605 + _CTMfloatmap * map; 1.606 + CTMuint result; 1.607 + if(!self) return CTM_NONE; 1.608 + 1.609 + map = self->mAttribMaps; 1.610 + result = CTM_ATTRIB_MAP_1; 1.611 + while(map && (strcmp(aName, map->mName) != 0)) 1.612 + { 1.613 + map = map->mNext; 1.614 + ++ result; 1.615 + } 1.616 + if(!map) 1.617 + { 1.618 + return CTM_NONE; 1.619 + } 1.620 + return result; 1.621 +} 1.622 + 1.623 +//----------------------------------------------------------------------------- 1.624 +// ctmGetString() 1.625 +//----------------------------------------------------------------------------- 1.626 +CTMEXPORT const char * CTMCALL ctmGetString(CTMcontext aContext, 1.627 + CTMenum aProperty) 1.628 +{ 1.629 + _CTMcontext * self = (_CTMcontext *) aContext; 1.630 + if(!self) return 0; 1.631 + 1.632 + switch(aProperty) 1.633 + { 1.634 + case CTM_FILE_COMMENT: 1.635 + return (const char *) self->mFileComment; 1.636 + 1.637 + default: 1.638 + self->mError = CTM_INVALID_ARGUMENT; 1.639 + } 1.640 + 1.641 + return (const char *) 0; 1.642 +} 1.643 + 1.644 +//----------------------------------------------------------------------------- 1.645 +// ctmCompressionMethod() 1.646 +//----------------------------------------------------------------------------- 1.647 +CTMEXPORT void CTMCALL ctmCompressionMethod(CTMcontext aContext, 1.648 + CTMenum aMethod) 1.649 +{ 1.650 + _CTMcontext * self = (_CTMcontext *) aContext; 1.651 + if(!self) return; 1.652 + 1.653 + // You are only allowed to change compression attributes in export mode 1.654 + if(self->mMode != CTM_EXPORT) 1.655 + { 1.656 + self->mError = CTM_INVALID_OPERATION; 1.657 + return; 1.658 + } 1.659 + 1.660 + // Check arguments 1.661 + if((aMethod != CTM_METHOD_RAW) && (aMethod != CTM_METHOD_MG1) && 1.662 + (aMethod != CTM_METHOD_MG2)) 1.663 + { 1.664 + self->mError = CTM_INVALID_ARGUMENT; 1.665 + return; 1.666 + } 1.667 + 1.668 + // Set method 1.669 + self->mMethod = aMethod; 1.670 +} 1.671 + 1.672 +//----------------------------------------------------------------------------- 1.673 +// ctmCompressionLevel() 1.674 +//----------------------------------------------------------------------------- 1.675 +CTMEXPORT void CTMCALL ctmCompressionLevel(CTMcontext aContext, 1.676 + CTMuint aLevel) 1.677 +{ 1.678 + _CTMcontext * self = (_CTMcontext *) aContext; 1.679 + if(!self) return; 1.680 + 1.681 + // You are only allowed to change compression attributes in export mode 1.682 + if(self->mMode != CTM_EXPORT) 1.683 + { 1.684 + self->mError = CTM_INVALID_OPERATION; 1.685 + return; 1.686 + } 1.687 + 1.688 + // Check arguments 1.689 + if(aLevel > 9) 1.690 + { 1.691 + self->mError = CTM_INVALID_ARGUMENT; 1.692 + return; 1.693 + } 1.694 + 1.695 + // Set the compression level 1.696 + self->mCompressionLevel = aLevel; 1.697 +} 1.698 + 1.699 +//----------------------------------------------------------------------------- 1.700 +// ctmVertexPrecision() 1.701 +//----------------------------------------------------------------------------- 1.702 +CTMEXPORT void CTMCALL ctmVertexPrecision(CTMcontext aContext, 1.703 + CTMfloat aPrecision) 1.704 +{ 1.705 + _CTMcontext * self = (_CTMcontext *) aContext; 1.706 + if(!self) return; 1.707 + 1.708 + // You are only allowed to change compression attributes in export mode 1.709 + if(self->mMode != CTM_EXPORT) 1.710 + { 1.711 + self->mError = CTM_INVALID_OPERATION; 1.712 + return; 1.713 + } 1.714 + 1.715 + // Check arguments 1.716 + if(aPrecision <= 0.0f) 1.717 + { 1.718 + self->mError = CTM_INVALID_ARGUMENT; 1.719 + return; 1.720 + } 1.721 + 1.722 + // Set precision 1.723 + self->mVertexPrecision = aPrecision; 1.724 +} 1.725 + 1.726 +//----------------------------------------------------------------------------- 1.727 +// ctmVertexPrecisionRel() 1.728 +//----------------------------------------------------------------------------- 1.729 +CTMEXPORT void CTMCALL ctmVertexPrecisionRel(CTMcontext aContext, 1.730 + CTMfloat aRelPrecision) 1.731 +{ 1.732 + _CTMcontext * self = (_CTMcontext *) aContext; 1.733 + CTMfloat avgEdgeLength, * p1, * p2; 1.734 + CTMuint edgeCount, i, j; 1.735 + if(!self) return; 1.736 + 1.737 + // You are only allowed to change compression attributes in export mode 1.738 + if(self->mMode != CTM_EXPORT) 1.739 + { 1.740 + self->mError = CTM_INVALID_OPERATION; 1.741 + return; 1.742 + } 1.743 + 1.744 + // Check arguments 1.745 + if(aRelPrecision <= 0.0f) 1.746 + { 1.747 + self->mError = CTM_INVALID_ARGUMENT; 1.748 + return; 1.749 + } 1.750 + 1.751 + // Calculate the average edge length (Note: we actually sum up all the half- 1.752 + // edges, so in a proper solid mesh all connected edges are counted twice) 1.753 + avgEdgeLength = 0.0f; 1.754 + edgeCount = 0; 1.755 + for(i = 0; i < self->mTriangleCount; ++ i) 1.756 + { 1.757 + p1 = &self->mVertices[self->mIndices[i * 3 + 2] * 3]; 1.758 + for(j = 0; j < 3; ++ j) 1.759 + { 1.760 + p2 = &self->mVertices[self->mIndices[i * 3 + j] * 3]; 1.761 + avgEdgeLength += sqrtf((p2[0] - p1[0]) * (p2[0] - p1[0]) + 1.762 + (p2[1] - p1[1]) * (p2[1] - p1[1]) + 1.763 + (p2[2] - p1[2]) * (p2[2] - p1[2])); 1.764 + p1 = p2; 1.765 + ++ edgeCount; 1.766 + } 1.767 + } 1.768 + if(edgeCount == 0) 1.769 + { 1.770 + self->mError = CTM_INVALID_MESH; 1.771 + return; 1.772 + } 1.773 + avgEdgeLength /= (CTMfloat) edgeCount; 1.774 + 1.775 + // Set precision 1.776 + self->mVertexPrecision = aRelPrecision * avgEdgeLength; 1.777 +} 1.778 + 1.779 +//----------------------------------------------------------------------------- 1.780 +// ctmNormalPrecision() 1.781 +//----------------------------------------------------------------------------- 1.782 +CTMEXPORT void CTMCALL ctmNormalPrecision(CTMcontext aContext, 1.783 + CTMfloat aPrecision) 1.784 +{ 1.785 + _CTMcontext * self = (_CTMcontext *) aContext; 1.786 + if(!self) return; 1.787 + 1.788 + // You are only allowed to change compression attributes in export mode 1.789 + if(self->mMode != CTM_EXPORT) 1.790 + { 1.791 + self->mError = CTM_INVALID_OPERATION; 1.792 + return; 1.793 + } 1.794 + 1.795 + // Check arguments 1.796 + if(aPrecision <= 0.0f) 1.797 + { 1.798 + self->mError = CTM_INVALID_ARGUMENT; 1.799 + return; 1.800 + } 1.801 + 1.802 + // Set precision 1.803 + self->mNormalPrecision = aPrecision; 1.804 +} 1.805 + 1.806 +//----------------------------------------------------------------------------- 1.807 +// ctmUVCoordPrecision() 1.808 +//----------------------------------------------------------------------------- 1.809 +CTMEXPORT void CTMCALL ctmUVCoordPrecision(CTMcontext aContext, 1.810 + CTMenum aUVMap, CTMfloat aPrecision) 1.811 +{ 1.812 + _CTMcontext * self = (_CTMcontext *) aContext; 1.813 + _CTMfloatmap * map; 1.814 + CTMuint i; 1.815 + if(!self) return; 1.816 + 1.817 + // You are only allowed to change compression attributes in export mode 1.818 + if(self->mMode != CTM_EXPORT) 1.819 + { 1.820 + self->mError = CTM_INVALID_OPERATION; 1.821 + return; 1.822 + } 1.823 + 1.824 + // Check arguments 1.825 + if(aPrecision <= 0.0f) 1.826 + { 1.827 + self->mError = CTM_INVALID_ARGUMENT; 1.828 + return; 1.829 + } 1.830 + 1.831 + // Find the indicated map 1.832 + map = self->mUVMaps; 1.833 + i = CTM_UV_MAP_1; 1.834 + while(map && (i != aUVMap)) 1.835 + { 1.836 + ++ i; 1.837 + map = map->mNext; 1.838 + } 1.839 + if(!map) 1.840 + { 1.841 + self->mError = CTM_INVALID_ARGUMENT; 1.842 + return; 1.843 + } 1.844 + 1.845 + // Update the precision 1.846 + map->mPrecision = aPrecision; 1.847 +} 1.848 + 1.849 +//----------------------------------------------------------------------------- 1.850 +// ctmAttribPrecision() 1.851 +//----------------------------------------------------------------------------- 1.852 +CTMEXPORT void CTMCALL ctmAttribPrecision(CTMcontext aContext, 1.853 + CTMenum aAttribMap, CTMfloat aPrecision) 1.854 +{ 1.855 + _CTMcontext * self = (_CTMcontext *) aContext; 1.856 + _CTMfloatmap * map; 1.857 + CTMuint i; 1.858 + if(!self) return; 1.859 + 1.860 + // You are only allowed to change compression attributes in export mode 1.861 + if(self->mMode != CTM_EXPORT) 1.862 + { 1.863 + self->mError = CTM_INVALID_OPERATION; 1.864 + return; 1.865 + } 1.866 + 1.867 + // Check arguments 1.868 + if(aPrecision <= 0.0f) 1.869 + { 1.870 + self->mError = CTM_INVALID_ARGUMENT; 1.871 + return; 1.872 + } 1.873 + 1.874 + // Find the indicated map 1.875 + map = self->mAttribMaps; 1.876 + i = CTM_ATTRIB_MAP_1; 1.877 + while(map && (i != aAttribMap)) 1.878 + { 1.879 + ++ i; 1.880 + map = map->mNext; 1.881 + } 1.882 + if(!map) 1.883 + { 1.884 + self->mError = CTM_INVALID_ARGUMENT; 1.885 + return; 1.886 + } 1.887 + 1.888 + // Update the precision 1.889 + map->mPrecision = aPrecision; 1.890 +} 1.891 + 1.892 +//----------------------------------------------------------------------------- 1.893 +// ctmFileComment() 1.894 +//----------------------------------------------------------------------------- 1.895 +CTMEXPORT void CTMCALL ctmFileComment(CTMcontext aContext, 1.896 + const char * aFileComment) 1.897 +{ 1.898 + _CTMcontext * self = (_CTMcontext *) aContext; 1.899 + int len; 1.900 + if(!self) return; 1.901 + 1.902 + // You are only allowed to change file attributes in export mode 1.903 + if(self->mMode != CTM_EXPORT) 1.904 + { 1.905 + self->mError = CTM_INVALID_OPERATION; 1.906 + return; 1.907 + } 1.908 + 1.909 + // Free the old comment string, if necessary 1.910 + if(self->mFileComment) 1.911 + { 1.912 + free(self->mFileComment); 1.913 + self->mFileComment = (char *) 0; 1.914 + } 1.915 + 1.916 + // Get length of string (if empty, do nothing) 1.917 + if(!aFileComment) 1.918 + return; 1.919 + len = strlen(aFileComment); 1.920 + if(!len) 1.921 + return; 1.922 + 1.923 + // Copy the string 1.924 + self->mFileComment = (char *) malloc(len + 1); 1.925 + if(!self->mFileComment) 1.926 + { 1.927 + self->mError = CTM_OUT_OF_MEMORY; 1.928 + return; 1.929 + } 1.930 + strcpy(self->mFileComment, aFileComment); 1.931 +} 1.932 + 1.933 +//----------------------------------------------------------------------------- 1.934 +// ctmDefineMesh() 1.935 +//----------------------------------------------------------------------------- 1.936 +CTMEXPORT void CTMCALL ctmDefineMesh(CTMcontext aContext, 1.937 + const CTMfloat * aVertices, CTMuint aVertexCount, const CTMuint * aIndices, 1.938 + CTMuint aTriangleCount, const CTMfloat * aNormals) 1.939 +{ 1.940 + _CTMcontext * self = (_CTMcontext *) aContext; 1.941 + if(!self) return; 1.942 + 1.943 + // You are only allowed to (re)define the mesh in export mode 1.944 + if(self->mMode != CTM_EXPORT) 1.945 + { 1.946 + self->mError = CTM_INVALID_OPERATION; 1.947 + return; 1.948 + } 1.949 + 1.950 + // Check arguments 1.951 + if(!aVertices || !aIndices || !aVertexCount || !aTriangleCount) 1.952 + { 1.953 + self->mError = CTM_INVALID_ARGUMENT; 1.954 + return; 1.955 + } 1.956 + 1.957 + // Clear the old mesh, if any 1.958 + _ctmClearMesh(self); 1.959 + 1.960 + // Set vertex array pointer 1.961 + self->mVertices = (CTMfloat *) aVertices; 1.962 + self->mVertexCount = aVertexCount; 1.963 + 1.964 + // Set index array pointer 1.965 + self->mIndices = (CTMuint *) aIndices; 1.966 + self->mTriangleCount = aTriangleCount; 1.967 + 1.968 + // Set normal array pointer 1.969 + self->mNormals = (CTMfloat *) aNormals; 1.970 +} 1.971 + 1.972 +//----------------------------------------------------------------------------- 1.973 +// _ctmAddFloatMap() 1.974 +//----------------------------------------------------------------------------- 1.975 +static _CTMfloatmap * _ctmAddFloatMap(_CTMcontext * self, 1.976 + const CTMfloat * aValues, const char * aName, const char * aFileName, 1.977 + _CTMfloatmap ** aList) 1.978 +{ 1.979 + _CTMfloatmap * map; 1.980 + CTMuint len; 1.981 + 1.982 + // Allocate memory for a new map list item and append it to the list 1.983 + if(!*aList) 1.984 + { 1.985 + *aList = (_CTMfloatmap *) malloc(sizeof(_CTMfloatmap)); 1.986 + map = *aList; 1.987 + } 1.988 + else 1.989 + { 1.990 + map = *aList; 1.991 + while(map->mNext) 1.992 + map = map->mNext; 1.993 + map->mNext = (_CTMfloatmap *) malloc(sizeof(_CTMfloatmap)); 1.994 + map = map->mNext; 1.995 + } 1.996 + if(!map) 1.997 + { 1.998 + self->mError = CTM_OUT_OF_MEMORY; 1.999 + return (_CTMfloatmap *) 0; 1.1000 + } 1.1001 + 1.1002 + // Init the map item 1.1003 + memset(map, 0, sizeof(_CTMfloatmap)); 1.1004 + map->mPrecision = 1.0f / 1024.0f; 1.1005 + map->mValues = (CTMfloat *) aValues; 1.1006 + 1.1007 + // Set name of the map 1.1008 + if(aName) 1.1009 + { 1.1010 + // Get length of string (if empty, do nothing) 1.1011 + len = strlen(aName); 1.1012 + if(len) 1.1013 + { 1.1014 + // Copy the string 1.1015 + map->mName = (char *) malloc(len + 1); 1.1016 + if(!map->mName) 1.1017 + { 1.1018 + self->mError = CTM_OUT_OF_MEMORY; 1.1019 + free(map); 1.1020 + return (_CTMfloatmap *) 0; 1.1021 + } 1.1022 + strcpy(map->mName, aName); 1.1023 + } 1.1024 + } 1.1025 + 1.1026 + // Set file name reference for the map 1.1027 + if(aFileName) 1.1028 + { 1.1029 + // Get length of string (if empty, do nothing) 1.1030 + len = strlen(aFileName); 1.1031 + if(len) 1.1032 + { 1.1033 + // Copy the string 1.1034 + map->mFileName = (char *) malloc(len + 1); 1.1035 + if(!map->mFileName) 1.1036 + { 1.1037 + self->mError = CTM_OUT_OF_MEMORY; 1.1038 + if(map->mName) 1.1039 + free(map->mName); 1.1040 + free(map); 1.1041 + return (_CTMfloatmap *) 0; 1.1042 + } 1.1043 + strcpy(map->mFileName, aFileName); 1.1044 + } 1.1045 + } 1.1046 + 1.1047 + return map; 1.1048 +} 1.1049 + 1.1050 +//----------------------------------------------------------------------------- 1.1051 +// ctmAddUVMap() 1.1052 +//----------------------------------------------------------------------------- 1.1053 +CTMEXPORT CTMenum CTMCALL ctmAddUVMap(CTMcontext aContext, 1.1054 + const CTMfloat * aUVCoords, const char * aName, const char * aFileName) 1.1055 +{ 1.1056 + _CTMcontext * self = (_CTMcontext *) aContext; 1.1057 + _CTMfloatmap * map; 1.1058 + if(!self) return CTM_NONE; 1.1059 + 1.1060 + // Add a new UV map to the UV map list 1.1061 + map = _ctmAddFloatMap(self, aUVCoords, aName, aFileName, &self->mUVMaps); 1.1062 + if(!map) 1.1063 + return CTM_NONE; 1.1064 + else 1.1065 + { 1.1066 + // The default UV coordinate precision is 2^-12 1.1067 + map->mPrecision = 1.0f / 4096.0f; 1.1068 + ++ self->mUVMapCount; 1.1069 + return CTM_UV_MAP_1 + self->mUVMapCount - 1; 1.1070 + } 1.1071 +} 1.1072 + 1.1073 +//----------------------------------------------------------------------------- 1.1074 +// ctmAddAttribMap() 1.1075 +//----------------------------------------------------------------------------- 1.1076 +CTMEXPORT CTMenum CTMCALL ctmAddAttribMap(CTMcontext aContext, 1.1077 + const CTMfloat * aAttribValues, const char * aName) 1.1078 +{ 1.1079 + _CTMcontext * self = (_CTMcontext *) aContext; 1.1080 + _CTMfloatmap * map; 1.1081 + if(!self) return CTM_NONE; 1.1082 + 1.1083 + // Add a new attribute map to the attribute map list 1.1084 + map = _ctmAddFloatMap(self, aAttribValues, aName, (const char *) 0, 1.1085 + &self->mAttribMaps); 1.1086 + if(!map) 1.1087 + return CTM_NONE; 1.1088 + else 1.1089 + { 1.1090 + // The default vertex attribute precision is 2^-8 1.1091 + map->mPrecision = 1.0f / 256.0f; 1.1092 + ++ self->mAttribMapCount; 1.1093 + return CTM_ATTRIB_MAP_1 + self->mAttribMapCount - 1; 1.1094 + } 1.1095 +} 1.1096 + 1.1097 +//----------------------------------------------------------------------------- 1.1098 +// _ctmDefaultRead() 1.1099 +//----------------------------------------------------------------------------- 1.1100 +static CTMuint CTMCALL _ctmDefaultRead(void * aBuf, CTMuint aCount, 1.1101 + void * aUserData) 1.1102 +{ 1.1103 + return (CTMuint) fread(aBuf, 1, (size_t) aCount, (FILE *) aUserData); 1.1104 +} 1.1105 + 1.1106 +//----------------------------------------------------------------------------- 1.1107 +// ctmLoad() 1.1108 +//----------------------------------------------------------------------------- 1.1109 +CTMEXPORT void CTMCALL ctmLoad(CTMcontext aContext, const char * aFileName) 1.1110 +{ 1.1111 + _CTMcontext * self = (_CTMcontext *) aContext; 1.1112 + FILE * f; 1.1113 + if(!self) return; 1.1114 + 1.1115 + // You are only allowed to load data in import mode 1.1116 + if(self->mMode != CTM_IMPORT) 1.1117 + { 1.1118 + self->mError = CTM_INVALID_OPERATION; 1.1119 + return; 1.1120 + } 1.1121 + 1.1122 + // Open file stream 1.1123 + f = fopen(aFileName, "rb"); 1.1124 + if(!f) 1.1125 + { 1.1126 + self->mError = CTM_FILE_ERROR; 1.1127 + return; 1.1128 + } 1.1129 + 1.1130 + // Load the file 1.1131 + ctmLoadCustom(self, _ctmDefaultRead, (void *) f); 1.1132 + 1.1133 + // Close file stream 1.1134 + fclose(f); 1.1135 +} 1.1136 + 1.1137 +//----------------------------------------------------------------------------- 1.1138 +// _ctmAllocateFloatMaps() 1.1139 +//----------------------------------------------------------------------------- 1.1140 +static CTMuint _ctmAllocateFloatMaps(_CTMcontext * self, 1.1141 + _CTMfloatmap ** aMapListPtr, CTMuint aCount, CTMuint aChannels) 1.1142 +{ 1.1143 + _CTMfloatmap ** mapListPtr; 1.1144 + CTMuint i, size; 1.1145 + 1.1146 + mapListPtr = aMapListPtr; 1.1147 + for(i = 0; i < aCount; ++ i) 1.1148 + { 1.1149 + // Allocate & clear memory for this map 1.1150 + *mapListPtr = (_CTMfloatmap *) malloc(sizeof(_CTMfloatmap)); 1.1151 + if(!*mapListPtr) 1.1152 + { 1.1153 + self->mError = CTM_OUT_OF_MEMORY; 1.1154 + return CTM_FALSE; 1.1155 + } 1.1156 + memset(*mapListPtr, 0, sizeof(_CTMfloatmap)); 1.1157 + 1.1158 + // Allocate & clear memory for the float array 1.1159 + size = aChannels * sizeof(CTMfloat) * self->mVertexCount; 1.1160 + (*mapListPtr)->mValues = (CTMfloat *) malloc(size); 1.1161 + if(!(*mapListPtr)->mValues) 1.1162 + { 1.1163 + self->mError = CTM_OUT_OF_MEMORY; 1.1164 + return CTM_FALSE; 1.1165 + } 1.1166 + memset((*mapListPtr)->mValues, 0, size); 1.1167 + 1.1168 + // Next map... 1.1169 + mapListPtr = &(*mapListPtr)->mNext; 1.1170 + } 1.1171 + 1.1172 + return CTM_TRUE; 1.1173 +} 1.1174 + 1.1175 +//----------------------------------------------------------------------------- 1.1176 +// ctmLoadCustom() 1.1177 +//----------------------------------------------------------------------------- 1.1178 +CTMEXPORT void CTMCALL ctmLoadCustom(CTMcontext aContext, CTMreadfn aReadFn, 1.1179 + void * aUserData) 1.1180 +{ 1.1181 + _CTMcontext * self = (_CTMcontext *) aContext; 1.1182 + CTMuint formatVersion, flags, method; 1.1183 + if(!self) return; 1.1184 + 1.1185 + // You are only allowed to load data in import mode 1.1186 + if(self->mMode != CTM_IMPORT) 1.1187 + { 1.1188 + self->mError = CTM_INVALID_OPERATION; 1.1189 + return; 1.1190 + } 1.1191 + 1.1192 + // Initialize stream 1.1193 + self->mReadFn = aReadFn; 1.1194 + self->mUserData = aUserData; 1.1195 + 1.1196 + // Clear any old mesh arrays 1.1197 + _ctmClearMesh(self); 1.1198 + 1.1199 + // Read header from stream 1.1200 + if(_ctmStreamReadUINT(self) != FOURCC("OCTM")) 1.1201 + { 1.1202 + self->mError = CTM_BAD_FORMAT; 1.1203 + return; 1.1204 + } 1.1205 + formatVersion = _ctmStreamReadUINT(self); 1.1206 + if(formatVersion != _CTM_FORMAT_VERSION) 1.1207 + { 1.1208 + self->mError = CTM_UNSUPPORTED_FORMAT_VERSION; 1.1209 + return; 1.1210 + } 1.1211 + method = _ctmStreamReadUINT(self); 1.1212 + if(method == FOURCC("RAW\0")) 1.1213 + self->mMethod = CTM_METHOD_RAW; 1.1214 + else if(method == FOURCC("MG1\0")) 1.1215 + self->mMethod = CTM_METHOD_MG1; 1.1216 + else if(method == FOURCC("MG2\0")) 1.1217 + self->mMethod = CTM_METHOD_MG2; 1.1218 + else 1.1219 + { 1.1220 + self->mError = CTM_BAD_FORMAT; 1.1221 + return; 1.1222 + } 1.1223 + self->mVertexCount = _ctmStreamReadUINT(self); 1.1224 + if(self->mVertexCount == 0) 1.1225 + { 1.1226 + self->mError = CTM_BAD_FORMAT; 1.1227 + return; 1.1228 + } 1.1229 + self->mTriangleCount = _ctmStreamReadUINT(self); 1.1230 + if(self->mTriangleCount == 0) 1.1231 + { 1.1232 + self->mError = CTM_BAD_FORMAT; 1.1233 + return; 1.1234 + } 1.1235 + self->mUVMapCount = _ctmStreamReadUINT(self); 1.1236 + self->mAttribMapCount = _ctmStreamReadUINT(self); 1.1237 + flags = _ctmStreamReadUINT(self); 1.1238 + _ctmStreamReadSTRING(self, &self->mFileComment); 1.1239 + 1.1240 + // Allocate memory for the mesh arrays 1.1241 + self->mVertices = (CTMfloat *) malloc(self->mVertexCount * sizeof(CTMfloat) * 3); 1.1242 + if(!self->mVertices) 1.1243 + { 1.1244 + self->mError = CTM_OUT_OF_MEMORY; 1.1245 + return; 1.1246 + } 1.1247 + self->mIndices = (CTMuint *) malloc(self->mTriangleCount * sizeof(CTMuint) * 3); 1.1248 + if(!self->mIndices) 1.1249 + { 1.1250 + _ctmClearMesh(self); 1.1251 + self->mError = CTM_OUT_OF_MEMORY; 1.1252 + return; 1.1253 + } 1.1254 + if(flags & _CTM_HAS_NORMALS_BIT) 1.1255 + { 1.1256 + self->mNormals = (CTMfloat *) malloc(self->mVertexCount * sizeof(CTMfloat) * 3); 1.1257 + if(!self->mNormals) 1.1258 + { 1.1259 + _ctmClearMesh(self); 1.1260 + self->mError = CTM_OUT_OF_MEMORY; 1.1261 + return; 1.1262 + } 1.1263 + } 1.1264 + 1.1265 + // Allocate memory for the UV and attribute maps (if any) 1.1266 + if(!_ctmAllocateFloatMaps(self, &self->mUVMaps, self->mUVMapCount, 2)) 1.1267 + { 1.1268 + _ctmClearMesh(self); 1.1269 + self->mError = CTM_OUT_OF_MEMORY; 1.1270 + return; 1.1271 + } 1.1272 + if(!_ctmAllocateFloatMaps(self, &self->mAttribMaps, self->mAttribMapCount, 4)) 1.1273 + { 1.1274 + _ctmClearMesh(self); 1.1275 + self->mError = CTM_OUT_OF_MEMORY; 1.1276 + return; 1.1277 + } 1.1278 + 1.1279 + // Uncompress from stream 1.1280 + switch(self->mMethod) 1.1281 + { 1.1282 + case CTM_METHOD_RAW: 1.1283 + _ctmUncompressMesh_RAW(self); 1.1284 + break; 1.1285 + 1.1286 + case CTM_METHOD_MG1: 1.1287 + _ctmUncompressMesh_MG1(self); 1.1288 + break; 1.1289 + 1.1290 + case CTM_METHOD_MG2: 1.1291 + _ctmUncompressMesh_MG2(self); 1.1292 + break; 1.1293 + 1.1294 + default: 1.1295 + self->mError = CTM_INTERNAL_ERROR; 1.1296 + } 1.1297 + 1.1298 + // Check mesh integrity 1.1299 + if(!_ctmCheckMeshIntegrity(self)) 1.1300 + { 1.1301 + self->mError = CTM_INVALID_MESH; 1.1302 + return; 1.1303 + } 1.1304 +} 1.1305 + 1.1306 +//----------------------------------------------------------------------------- 1.1307 +// _ctmDefaultWrite() 1.1308 +//----------------------------------------------------------------------------- 1.1309 +static CTMuint CTMCALL _ctmDefaultWrite(const void * aBuf, CTMuint aCount, 1.1310 + void * aUserData) 1.1311 +{ 1.1312 + return (CTMuint) fwrite(aBuf, 1, (size_t) aCount, (FILE *) aUserData); 1.1313 +} 1.1314 + 1.1315 +//----------------------------------------------------------------------------- 1.1316 +// ctmSave() 1.1317 +//----------------------------------------------------------------------------- 1.1318 +CTMEXPORT void CTMCALL ctmSave(CTMcontext aContext, const char * aFileName) 1.1319 +{ 1.1320 + _CTMcontext * self = (_CTMcontext *) aContext; 1.1321 + FILE * f; 1.1322 + if(!self) return; 1.1323 + 1.1324 + // You are only allowed to save data in export mode 1.1325 + if(self->mMode != CTM_EXPORT) 1.1326 + { 1.1327 + self->mError = CTM_INVALID_OPERATION; 1.1328 + return; 1.1329 + } 1.1330 + 1.1331 + // Open file stream 1.1332 + f = fopen(aFileName, "wb"); 1.1333 + if(!f) 1.1334 + { 1.1335 + self->mError = CTM_FILE_ERROR; 1.1336 + return; 1.1337 + } 1.1338 + 1.1339 + // Save the file 1.1340 + ctmSaveCustom(self, _ctmDefaultWrite, (void *) f); 1.1341 + 1.1342 + // Close file stream 1.1343 + fclose(f); 1.1344 +} 1.1345 + 1.1346 +//----------------------------------------------------------------------------- 1.1347 +// ctmSaveCustom() 1.1348 +//----------------------------------------------------------------------------- 1.1349 +void CTMCALL ctmSaveCustom(CTMcontext aContext, CTMwritefn aWriteFn, 1.1350 + void * aUserData) 1.1351 +{ 1.1352 + _CTMcontext * self = (_CTMcontext *) aContext; 1.1353 + CTMuint flags; 1.1354 + if(!self) return; 1.1355 + 1.1356 + // You are only allowed to save data in export mode 1.1357 + if(self->mMode != CTM_EXPORT) 1.1358 + { 1.1359 + self->mError = CTM_INVALID_OPERATION; 1.1360 + return; 1.1361 + } 1.1362 + 1.1363 + // Check mesh integrity 1.1364 + if(!_ctmCheckMeshIntegrity(self)) 1.1365 + { 1.1366 + self->mError = CTM_INVALID_MESH; 1.1367 + return; 1.1368 + } 1.1369 + 1.1370 + // Initialize stream 1.1371 + self->mWriteFn = aWriteFn; 1.1372 + self->mUserData = aUserData; 1.1373 + 1.1374 + // Determine flags 1.1375 + flags = 0; 1.1376 + if(self->mNormals) 1.1377 + flags |= _CTM_HAS_NORMALS_BIT; 1.1378 + 1.1379 + // Write header to stream 1.1380 + _ctmStreamWrite(self, (void *) "OCTM", 4); 1.1381 + _ctmStreamWriteUINT(self, _CTM_FORMAT_VERSION); 1.1382 + switch(self->mMethod) 1.1383 + { 1.1384 + case CTM_METHOD_RAW: 1.1385 + _ctmStreamWrite(self, (void *) "RAW\0", 4); 1.1386 + break; 1.1387 + 1.1388 + case CTM_METHOD_MG1: 1.1389 + _ctmStreamWrite(self, (void *) "MG1\0", 4); 1.1390 + break; 1.1391 + 1.1392 + case CTM_METHOD_MG2: 1.1393 + _ctmStreamWrite(self, (void *) "MG2\0", 4); 1.1394 + break; 1.1395 + 1.1396 + default: 1.1397 + self->mError = CTM_INTERNAL_ERROR; 1.1398 + return; 1.1399 + } 1.1400 + _ctmStreamWriteUINT(self, self->mVertexCount); 1.1401 + _ctmStreamWriteUINT(self, self->mTriangleCount); 1.1402 + _ctmStreamWriteUINT(self, self->mUVMapCount); 1.1403 + _ctmStreamWriteUINT(self, self->mAttribMapCount); 1.1404 + _ctmStreamWriteUINT(self, flags); 1.1405 + _ctmStreamWriteSTRING(self, self->mFileComment); 1.1406 + 1.1407 + // Compress to stream 1.1408 + switch(self->mMethod) 1.1409 + { 1.1410 + case CTM_METHOD_RAW: 1.1411 + _ctmCompressMesh_RAW(self); 1.1412 + break; 1.1413 + 1.1414 + case CTM_METHOD_MG1: 1.1415 + _ctmCompressMesh_MG1(self); 1.1416 + break; 1.1417 + 1.1418 + case CTM_METHOD_MG2: 1.1419 + _ctmCompressMesh_MG2(self); 1.1420 + break; 1.1421 + 1.1422 + default: 1.1423 + self->mError = CTM_INTERNAL_ERROR; 1.1424 + return; 1.1425 + } 1.1426 +}