goat3d

annotate 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
rev   line source
nuclear@14 1 //-----------------------------------------------------------------------------
nuclear@14 2 // Product: OpenCTM
nuclear@14 3 // File: openctm.c
nuclear@14 4 // Description: API functions.
nuclear@14 5 //-----------------------------------------------------------------------------
nuclear@14 6 // Copyright (c) 2009-2010 Marcus Geelnard
nuclear@14 7 //
nuclear@14 8 // This software is provided 'as-is', without any express or implied
nuclear@14 9 // warranty. In no event will the authors be held liable for any damages
nuclear@14 10 // arising from the use of this software.
nuclear@14 11 //
nuclear@14 12 // Permission is granted to anyone to use this software for any purpose,
nuclear@14 13 // including commercial applications, and to alter it and redistribute it
nuclear@14 14 // freely, subject to the following restrictions:
nuclear@14 15 //
nuclear@14 16 // 1. The origin of this software must not be misrepresented; you must not
nuclear@14 17 // claim that you wrote the original software. If you use this software
nuclear@14 18 // in a product, an acknowledgment in the product documentation would be
nuclear@14 19 // appreciated but is not required.
nuclear@14 20 //
nuclear@14 21 // 2. Altered source versions must be plainly marked as such, and must not
nuclear@14 22 // be misrepresented as being the original software.
nuclear@14 23 //
nuclear@14 24 // 3. This notice may not be removed or altered from any source
nuclear@14 25 // distribution.
nuclear@14 26 //-----------------------------------------------------------------------------
nuclear@14 27
nuclear@14 28 #include <stdlib.h>
nuclear@14 29 #include <string.h>
nuclear@14 30 #include <stdio.h>
nuclear@14 31 #include <math.h>
nuclear@14 32 #include "openctm.h"
nuclear@14 33 #include "internal.h"
nuclear@14 34
nuclear@14 35
nuclear@14 36 // The C99 macro isfinite() is not supported on all platforms (specifically,
nuclear@14 37 // MS Visual Studio does not support C99)
nuclear@14 38 #if !defined(isfinite) && defined(_MSC_VER)
nuclear@14 39 #include <float.h>
nuclear@14 40 #define isfinite(x) _finite(x)
nuclear@14 41 #endif
nuclear@14 42
nuclear@14 43
nuclear@14 44 //-----------------------------------------------------------------------------
nuclear@14 45 // _ctmFreeMapList() - Free a float map list.
nuclear@14 46 //-----------------------------------------------------------------------------
nuclear@14 47 static void _ctmFreeMapList(_CTMcontext * self, _CTMfloatmap * aMapList)
nuclear@14 48 {
nuclear@14 49 _CTMfloatmap * map, * nextMap;
nuclear@14 50 map = aMapList;
nuclear@14 51 while(map)
nuclear@14 52 {
nuclear@14 53 // Free internally allocated array (if we are in import mode)
nuclear@14 54 if((self->mMode == CTM_IMPORT) && map->mValues)
nuclear@14 55 free(map->mValues);
nuclear@14 56
nuclear@14 57 // Free map name
nuclear@14 58 if(map->mName)
nuclear@14 59 free(map->mName);
nuclear@14 60
nuclear@14 61 // Free file name
nuclear@14 62 if(map->mFileName)
nuclear@14 63 free(map->mFileName);
nuclear@14 64
nuclear@14 65 nextMap = map->mNext;
nuclear@14 66 free(map);
nuclear@14 67 map = nextMap;
nuclear@14 68 }
nuclear@14 69 }
nuclear@14 70
nuclear@14 71 //-----------------------------------------------------------------------------
nuclear@14 72 // _ctmClearMesh() - Clear the mesh in a CTM context.
nuclear@14 73 //-----------------------------------------------------------------------------
nuclear@14 74 static void _ctmClearMesh(_CTMcontext * self)
nuclear@14 75 {
nuclear@14 76 // Free internally allocated mesh arrays
nuclear@14 77 if(self->mMode == CTM_IMPORT)
nuclear@14 78 {
nuclear@14 79 if(self->mVertices)
nuclear@14 80 free(self->mVertices);
nuclear@14 81 if(self->mIndices)
nuclear@14 82 free(self->mIndices);
nuclear@14 83 if(self->mNormals)
nuclear@14 84 free(self->mNormals);
nuclear@14 85 }
nuclear@14 86
nuclear@14 87 // Clear externally assigned mesh arrays
nuclear@14 88 self->mVertices = (CTMfloat *) 0;
nuclear@14 89 self->mVertexCount = 0;
nuclear@14 90 self->mIndices = (CTMuint *) 0;
nuclear@14 91 self->mTriangleCount = 0;
nuclear@14 92 self->mNormals = (CTMfloat *) 0;
nuclear@14 93
nuclear@14 94 // Free UV coordinate map list
nuclear@14 95 _ctmFreeMapList(self, self->mUVMaps);
nuclear@14 96 self->mUVMaps = (_CTMfloatmap *) 0;
nuclear@14 97 self->mUVMapCount = 0;
nuclear@14 98
nuclear@14 99 // Free attribute map list
nuclear@14 100 _ctmFreeMapList(self, self->mAttribMaps);
nuclear@14 101 self->mAttribMaps = (_CTMfloatmap *) 0;
nuclear@14 102 self->mAttribMapCount = 0;
nuclear@14 103 }
nuclear@14 104
nuclear@14 105 //-----------------------------------------------------------------------------
nuclear@14 106 // _ctmCheckMeshIntegrity() - Check if a mesh is valid (i.e. is non-empty, and
nuclear@14 107 // contains valid data).
nuclear@14 108 //-----------------------------------------------------------------------------
nuclear@14 109
nuclear@14 110 static CTMint _ctmCheckMeshIntegrity(_CTMcontext * self)
nuclear@14 111 {
nuclear@14 112 CTMuint i;
nuclear@14 113 _CTMfloatmap * map;
nuclear@14 114
nuclear@14 115 // Check that we have all the mandatory data
nuclear@14 116 if(!self->mVertices || !self->mIndices || (self->mVertexCount < 1) ||
nuclear@14 117 (self->mTriangleCount < 1))
nuclear@14 118 {
nuclear@14 119 return CTM_FALSE;
nuclear@14 120 }
nuclear@14 121
nuclear@14 122 // Check that all indices are within range
nuclear@14 123 for(i = 0; i < (self->mTriangleCount * 3); ++ i)
nuclear@14 124 {
nuclear@14 125 if(self->mIndices[i] >= self->mVertexCount)
nuclear@14 126 {
nuclear@14 127 return CTM_FALSE;
nuclear@14 128 }
nuclear@14 129 }
nuclear@14 130
nuclear@14 131 // Check that all vertices are finite (non-NaN, non-inf)
nuclear@14 132 for(i = 0; i < self->mVertexCount * 3; ++ i)
nuclear@14 133 {
nuclear@14 134 if(!isfinite(self->mVertices[i]))
nuclear@14 135 {
nuclear@14 136 return CTM_FALSE;
nuclear@14 137 }
nuclear@14 138 }
nuclear@14 139
nuclear@14 140 // Check that all normals are finite (non-NaN, non-inf)
nuclear@14 141 if(self->mNormals)
nuclear@14 142 {
nuclear@14 143 for(i = 0; i < self->mVertexCount * 3; ++ i)
nuclear@14 144 {
nuclear@14 145 if(!isfinite(self->mNormals[i]))
nuclear@14 146 {
nuclear@14 147 return CTM_FALSE;
nuclear@14 148 }
nuclear@14 149 }
nuclear@14 150 }
nuclear@14 151
nuclear@14 152 // Check that all UV maps are finite (non-NaN, non-inf)
nuclear@14 153 map = self->mUVMaps;
nuclear@14 154 while(map)
nuclear@14 155 {
nuclear@14 156 for(i = 0; i < self->mVertexCount * 2; ++ i)
nuclear@14 157 {
nuclear@14 158 if(!isfinite(map->mValues[i]))
nuclear@14 159 {
nuclear@14 160 return CTM_FALSE;
nuclear@14 161 }
nuclear@14 162 }
nuclear@14 163 map = map->mNext;
nuclear@14 164 }
nuclear@14 165
nuclear@14 166 // Check that all attribute maps are finite (non-NaN, non-inf)
nuclear@14 167 map = self->mAttribMaps;
nuclear@14 168 while(map)
nuclear@14 169 {
nuclear@14 170 for(i = 0; i < self->mVertexCount * 4; ++ i)
nuclear@14 171 {
nuclear@14 172 if(!isfinite(map->mValues[i]))
nuclear@14 173 {
nuclear@14 174 return CTM_FALSE;
nuclear@14 175 }
nuclear@14 176 }
nuclear@14 177 map = map->mNext;
nuclear@14 178 }
nuclear@14 179
nuclear@14 180 return CTM_TRUE;
nuclear@14 181 }
nuclear@14 182
nuclear@14 183 //-----------------------------------------------------------------------------
nuclear@14 184 // ctmNewContext()
nuclear@14 185 //-----------------------------------------------------------------------------
nuclear@14 186 CTMEXPORT CTMcontext CTMCALL ctmNewContext(CTMenum aMode)
nuclear@14 187 {
nuclear@14 188 _CTMcontext * self;
nuclear@14 189
nuclear@14 190 // Allocate memory for the new structure
nuclear@14 191 self = (_CTMcontext *) malloc(sizeof(_CTMcontext));
nuclear@14 192
nuclear@14 193 // Initialize structure (set null pointers and zero array lengths)
nuclear@14 194 memset(self, 0, sizeof(_CTMcontext));
nuclear@14 195 self->mMode = aMode;
nuclear@14 196 self->mError = CTM_NONE;
nuclear@14 197 self->mMethod = CTM_METHOD_MG1;
nuclear@14 198 self->mCompressionLevel = 1;
nuclear@14 199 self->mVertexPrecision = 1.0f / 1024.0f;
nuclear@14 200 self->mNormalPrecision = 1.0f / 256.0f;
nuclear@14 201
nuclear@14 202 return (CTMcontext) self;
nuclear@14 203 }
nuclear@14 204
nuclear@14 205 //-----------------------------------------------------------------------------
nuclear@14 206 // ctmFreeContext()
nuclear@14 207 //-----------------------------------------------------------------------------
nuclear@14 208 CTMEXPORT void CTMCALL ctmFreeContext(CTMcontext aContext)
nuclear@14 209 {
nuclear@14 210 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 211 if(!self) return;
nuclear@14 212
nuclear@14 213 // Free all mesh resources
nuclear@14 214 _ctmClearMesh(self);
nuclear@14 215
nuclear@14 216 // Free the file comment
nuclear@14 217 if(self->mFileComment)
nuclear@14 218 free(self->mFileComment);
nuclear@14 219
nuclear@14 220 // Free the context
nuclear@14 221 free(self);
nuclear@14 222 }
nuclear@14 223
nuclear@14 224 //-----------------------------------------------------------------------------
nuclear@14 225 // ctmGetError()
nuclear@14 226 //-----------------------------------------------------------------------------
nuclear@14 227 CTMEXPORT CTMenum CTMCALL ctmGetError(CTMcontext aContext)
nuclear@14 228 {
nuclear@14 229 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 230 CTMenum err;
nuclear@14 231
nuclear@14 232 if(!self) return CTM_INVALID_CONTEXT;
nuclear@14 233
nuclear@14 234 // Get error code and reset error state
nuclear@14 235 err = self->mError;
nuclear@14 236 self->mError = CTM_NONE;
nuclear@14 237 return err;
nuclear@14 238 }
nuclear@14 239
nuclear@14 240 //-----------------------------------------------------------------------------
nuclear@14 241 // ctmErrorString()
nuclear@14 242 //-----------------------------------------------------------------------------
nuclear@14 243 CTMEXPORT const char * CTMCALL ctmErrorString(CTMenum aError)
nuclear@14 244 {
nuclear@14 245 switch(aError)
nuclear@14 246 {
nuclear@14 247 case CTM_INVALID_CONTEXT:
nuclear@14 248 return "CTM_INVALID_CONTEXT";
nuclear@14 249 case CTM_INVALID_ARGUMENT:
nuclear@14 250 return "CTM_INVALID_ARGUMENT";
nuclear@14 251 case CTM_INVALID_OPERATION:
nuclear@14 252 return "CTM_INVALID_OPERATION";
nuclear@14 253 case CTM_INVALID_MESH:
nuclear@14 254 return "CTM_INVALID_MESH";
nuclear@14 255 case CTM_OUT_OF_MEMORY:
nuclear@14 256 return "CTM_OUT_OF_MEMORY";
nuclear@14 257 case CTM_FILE_ERROR:
nuclear@14 258 return "CTM_FILE_ERROR";
nuclear@14 259 case CTM_BAD_FORMAT:
nuclear@14 260 return "CTM_BAD_FORMAT";
nuclear@14 261 case CTM_LZMA_ERROR:
nuclear@14 262 return "CTM_LZMA_ERROR";
nuclear@14 263 case CTM_INTERNAL_ERROR:
nuclear@14 264 return "CTM_INTERNAL_ERROR";
nuclear@14 265 case CTM_UNSUPPORTED_FORMAT_VERSION:
nuclear@14 266 return "CTM_UNSUPPORTED_FORMAT_VERSION";
nuclear@14 267 default:
nuclear@14 268 return "Unknown error code";
nuclear@14 269 }
nuclear@14 270 }
nuclear@14 271
nuclear@14 272 //-----------------------------------------------------------------------------
nuclear@14 273 // ctmGetInteger()
nuclear@14 274 //-----------------------------------------------------------------------------
nuclear@14 275 CTMEXPORT CTMuint CTMCALL ctmGetInteger(CTMcontext aContext, CTMenum aProperty)
nuclear@14 276 {
nuclear@14 277 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 278 if(!self) return 0;
nuclear@14 279
nuclear@14 280 switch(aProperty)
nuclear@14 281 {
nuclear@14 282 case CTM_VERTEX_COUNT:
nuclear@14 283 return self->mVertexCount;
nuclear@14 284
nuclear@14 285 case CTM_TRIANGLE_COUNT:
nuclear@14 286 return self->mTriangleCount;
nuclear@14 287
nuclear@14 288 case CTM_UV_MAP_COUNT:
nuclear@14 289 return self->mUVMapCount;
nuclear@14 290
nuclear@14 291 case CTM_ATTRIB_MAP_COUNT:
nuclear@14 292 return self->mAttribMapCount;
nuclear@14 293
nuclear@14 294 case CTM_HAS_NORMALS:
nuclear@14 295 return self->mNormals ? CTM_TRUE : CTM_FALSE;
nuclear@14 296
nuclear@14 297 case CTM_COMPRESSION_METHOD:
nuclear@14 298 return (CTMuint) self->mMethod;
nuclear@14 299
nuclear@14 300 default:
nuclear@14 301 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 302 }
nuclear@14 303
nuclear@14 304 return 0;
nuclear@14 305 }
nuclear@14 306
nuclear@14 307 //-----------------------------------------------------------------------------
nuclear@14 308 // ctmGetFloat()
nuclear@14 309 //-----------------------------------------------------------------------------
nuclear@14 310 CTMEXPORT CTMfloat CTMCALL ctmGetFloat(CTMcontext aContext, CTMenum aProperty)
nuclear@14 311 {
nuclear@14 312 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 313 if(!self) return 0.0f;
nuclear@14 314
nuclear@14 315 switch(aProperty)
nuclear@14 316 {
nuclear@14 317 case CTM_VERTEX_PRECISION:
nuclear@14 318 return self->mVertexPrecision;
nuclear@14 319
nuclear@14 320 case CTM_NORMAL_PRECISION:
nuclear@14 321 return self->mNormalPrecision;
nuclear@14 322
nuclear@14 323 default:
nuclear@14 324 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 325 }
nuclear@14 326
nuclear@14 327 return 0.0f;
nuclear@14 328 }
nuclear@14 329
nuclear@14 330 //-----------------------------------------------------------------------------
nuclear@14 331 // ctmGetIntegerArray()
nuclear@14 332 //-----------------------------------------------------------------------------
nuclear@14 333 CTMEXPORT const CTMuint * CTMCALL ctmGetIntegerArray(CTMcontext aContext,
nuclear@14 334 CTMenum aProperty)
nuclear@14 335 {
nuclear@14 336 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 337 if(!self) return (CTMuint *) 0;
nuclear@14 338
nuclear@14 339 switch(aProperty)
nuclear@14 340 {
nuclear@14 341 case CTM_INDICES:
nuclear@14 342 return self->mIndices;
nuclear@14 343
nuclear@14 344 default:
nuclear@14 345 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 346 }
nuclear@14 347
nuclear@14 348 return (CTMuint *) 0;
nuclear@14 349 }
nuclear@14 350
nuclear@14 351 //-----------------------------------------------------------------------------
nuclear@14 352 // ctmGetFloatArray()
nuclear@14 353 //-----------------------------------------------------------------------------
nuclear@14 354 CTMEXPORT const CTMfloat * CTMCALL ctmGetFloatArray(CTMcontext aContext,
nuclear@14 355 CTMenum aProperty)
nuclear@14 356 {
nuclear@14 357 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 358 _CTMfloatmap * map;
nuclear@14 359 CTMuint i;
nuclear@14 360 if(!self) return (CTMfloat *) 0;
nuclear@14 361
nuclear@14 362 // Did the user request a UV map?
nuclear@14 363 if((aProperty >= CTM_UV_MAP_1) &&
nuclear@14 364 ((CTMuint)(aProperty - CTM_UV_MAP_1) < self->mUVMapCount))
nuclear@14 365 {
nuclear@14 366 map = self->mUVMaps;
nuclear@14 367 i = CTM_UV_MAP_1;
nuclear@14 368 while(map && (i != aProperty))
nuclear@14 369 {
nuclear@14 370 map = map->mNext;
nuclear@14 371 ++ i;
nuclear@14 372 }
nuclear@14 373 if(!map)
nuclear@14 374 {
nuclear@14 375 self->mError = CTM_INTERNAL_ERROR;
nuclear@14 376 return (CTMfloat *) 0;
nuclear@14 377 }
nuclear@14 378 return map->mValues;
nuclear@14 379 }
nuclear@14 380
nuclear@14 381 // Did the user request an attribute map?
nuclear@14 382 if((aProperty >= CTM_ATTRIB_MAP_1) &&
nuclear@14 383 ((CTMuint)(aProperty - CTM_ATTRIB_MAP_1) < self->mAttribMapCount))
nuclear@14 384 {
nuclear@14 385 map = self->mAttribMaps;
nuclear@14 386 i = CTM_ATTRIB_MAP_1;
nuclear@14 387 while(map && (i != aProperty))
nuclear@14 388 {
nuclear@14 389 map = map->mNext;
nuclear@14 390 ++ i;
nuclear@14 391 }
nuclear@14 392 if(!map)
nuclear@14 393 {
nuclear@14 394 self->mError = CTM_INTERNAL_ERROR;
nuclear@14 395 return (CTMfloat *) 0;
nuclear@14 396 }
nuclear@14 397 return map->mValues;
nuclear@14 398 }
nuclear@14 399
nuclear@14 400 switch(aProperty)
nuclear@14 401 {
nuclear@14 402 case CTM_VERTICES:
nuclear@14 403 return self->mVertices;
nuclear@14 404
nuclear@14 405 case CTM_NORMALS:
nuclear@14 406 return self->mNormals;
nuclear@14 407
nuclear@14 408 default:
nuclear@14 409 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 410 }
nuclear@14 411
nuclear@14 412 return (CTMfloat *) 0;
nuclear@14 413 }
nuclear@14 414
nuclear@14 415 //-----------------------------------------------------------------------------
nuclear@14 416 // ctmGetNamedUVMap()
nuclear@14 417 //-----------------------------------------------------------------------------
nuclear@14 418 CTMEXPORT CTMenum CTMCALL ctmGetNamedUVMap(CTMcontext aContext,
nuclear@14 419 const char * aName)
nuclear@14 420 {
nuclear@14 421 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 422 _CTMfloatmap * map;
nuclear@14 423 CTMuint result;
nuclear@14 424 if(!self) return CTM_NONE;
nuclear@14 425
nuclear@14 426 map = self->mUVMaps;
nuclear@14 427 result = CTM_UV_MAP_1;
nuclear@14 428 while(map && (strcmp(aName, map->mName) != 0))
nuclear@14 429 {
nuclear@14 430 map = map->mNext;
nuclear@14 431 ++ result;
nuclear@14 432 }
nuclear@14 433 if(!map)
nuclear@14 434 {
nuclear@14 435 return CTM_NONE;
nuclear@14 436 }
nuclear@14 437 return result;
nuclear@14 438 }
nuclear@14 439
nuclear@14 440 //-----------------------------------------------------------------------------
nuclear@14 441 // ctmGetUVMapString()
nuclear@14 442 //-----------------------------------------------------------------------------
nuclear@14 443 CTMEXPORT const char * CTMCALL ctmGetUVMapString(CTMcontext aContext,
nuclear@14 444 CTMenum aUVMap, CTMenum aProperty)
nuclear@14 445 {
nuclear@14 446 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 447 _CTMfloatmap * map;
nuclear@14 448 CTMuint i;
nuclear@14 449 if(!self) return (const char *) 0;
nuclear@14 450
nuclear@14 451 // Find the indicated map
nuclear@14 452 map = self->mUVMaps;
nuclear@14 453 i = CTM_UV_MAP_1;
nuclear@14 454 while(map && (i != aUVMap))
nuclear@14 455 {
nuclear@14 456 ++ i;
nuclear@14 457 map = map->mNext;
nuclear@14 458 }
nuclear@14 459 if(!map)
nuclear@14 460 {
nuclear@14 461 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 462 return (const char *) 0;
nuclear@14 463 }
nuclear@14 464
nuclear@14 465 // Get the requested string
nuclear@14 466 switch(aProperty)
nuclear@14 467 {
nuclear@14 468 case CTM_NAME:
nuclear@14 469 return (const char *) map->mName;
nuclear@14 470
nuclear@14 471 case CTM_FILE_NAME:
nuclear@14 472 return (const char *) map->mFileName;
nuclear@14 473
nuclear@14 474 default:
nuclear@14 475 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 476 }
nuclear@14 477
nuclear@14 478 return (const char *) 0;
nuclear@14 479 }
nuclear@14 480
nuclear@14 481 //-----------------------------------------------------------------------------
nuclear@14 482 // ctmGetUVMapFloat()
nuclear@14 483 //-----------------------------------------------------------------------------
nuclear@14 484 CTMEXPORT CTMfloat CTMCALL ctmGetUVMapFloat(CTMcontext aContext,
nuclear@14 485 CTMenum aUVMap, CTMenum aProperty)
nuclear@14 486 {
nuclear@14 487 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 488 _CTMfloatmap * map;
nuclear@14 489 CTMuint i;
nuclear@14 490 if(!self) return 0.0f;
nuclear@14 491
nuclear@14 492 // Find the indicated map
nuclear@14 493 map = self->mUVMaps;
nuclear@14 494 i = CTM_UV_MAP_1;
nuclear@14 495 while(map && (i != aUVMap))
nuclear@14 496 {
nuclear@14 497 ++ i;
nuclear@14 498 map = map->mNext;
nuclear@14 499 }
nuclear@14 500 if(!map)
nuclear@14 501 {
nuclear@14 502 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 503 return 0.0f;
nuclear@14 504 }
nuclear@14 505
nuclear@14 506 // Get the requested string
nuclear@14 507 switch(aProperty)
nuclear@14 508 {
nuclear@14 509 case CTM_PRECISION:
nuclear@14 510 return map->mPrecision;
nuclear@14 511
nuclear@14 512 default:
nuclear@14 513 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 514 }
nuclear@14 515
nuclear@14 516 return 0.0f;
nuclear@14 517 }
nuclear@14 518
nuclear@14 519 //-----------------------------------------------------------------------------
nuclear@14 520 // ctmGetAttribMapString()
nuclear@14 521 //-----------------------------------------------------------------------------
nuclear@14 522 CTMEXPORT const char * CTMCALL ctmGetAttribMapString(CTMcontext aContext,
nuclear@14 523 CTMenum aAttribMap, CTMenum aProperty)
nuclear@14 524 {
nuclear@14 525 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 526 _CTMfloatmap * map;
nuclear@14 527 CTMuint i;
nuclear@14 528 if(!self) return (const char *) 0;
nuclear@14 529
nuclear@14 530 // Find the indicated map
nuclear@14 531 map = self->mAttribMaps;
nuclear@14 532 i = CTM_ATTRIB_MAP_1;
nuclear@14 533 while(map && (i != aAttribMap))
nuclear@14 534 {
nuclear@14 535 ++ i;
nuclear@14 536 map = map->mNext;
nuclear@14 537 }
nuclear@14 538 if(!map)
nuclear@14 539 {
nuclear@14 540 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 541 return (const char *) 0;
nuclear@14 542 }
nuclear@14 543
nuclear@14 544 // Get the requested string
nuclear@14 545 switch(aProperty)
nuclear@14 546 {
nuclear@14 547 case CTM_NAME:
nuclear@14 548 return (const char *) map->mName;
nuclear@14 549
nuclear@14 550 default:
nuclear@14 551 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 552 }
nuclear@14 553
nuclear@14 554 return (const char *) 0;
nuclear@14 555 }
nuclear@14 556
nuclear@14 557 //-----------------------------------------------------------------------------
nuclear@14 558 // ctmGetAttribMapFloat()
nuclear@14 559 //-----------------------------------------------------------------------------
nuclear@14 560 CTMEXPORT CTMfloat CTMCALL ctmGetAttribMapFloat(CTMcontext aContext,
nuclear@14 561 CTMenum aAttribMap, CTMenum aProperty)
nuclear@14 562 {
nuclear@14 563 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 564 _CTMfloatmap * map;
nuclear@14 565 CTMuint i;
nuclear@14 566 if(!self) return 0.0f;
nuclear@14 567
nuclear@14 568 // Find the indicated map
nuclear@14 569 map = self->mAttribMaps;
nuclear@14 570 i = CTM_ATTRIB_MAP_1;
nuclear@14 571 while(map && (i != aAttribMap))
nuclear@14 572 {
nuclear@14 573 ++ i;
nuclear@14 574 map = map->mNext;
nuclear@14 575 }
nuclear@14 576 if(!map)
nuclear@14 577 {
nuclear@14 578 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 579 return 0.0f;
nuclear@14 580 }
nuclear@14 581
nuclear@14 582 // Get the requested string
nuclear@14 583 switch(aProperty)
nuclear@14 584 {
nuclear@14 585 case CTM_PRECISION:
nuclear@14 586 return map->mPrecision;
nuclear@14 587
nuclear@14 588 default:
nuclear@14 589 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 590 }
nuclear@14 591
nuclear@14 592 return 0.0f;
nuclear@14 593 }
nuclear@14 594
nuclear@14 595 //-----------------------------------------------------------------------------
nuclear@14 596 // ctmGetNamedAttribMap()
nuclear@14 597 //-----------------------------------------------------------------------------
nuclear@14 598 CTMEXPORT CTMenum CTMCALL ctmGetNamedAttribMap(CTMcontext aContext,
nuclear@14 599 const char * aName)
nuclear@14 600 {
nuclear@14 601 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 602 _CTMfloatmap * map;
nuclear@14 603 CTMuint result;
nuclear@14 604 if(!self) return CTM_NONE;
nuclear@14 605
nuclear@14 606 map = self->mAttribMaps;
nuclear@14 607 result = CTM_ATTRIB_MAP_1;
nuclear@14 608 while(map && (strcmp(aName, map->mName) != 0))
nuclear@14 609 {
nuclear@14 610 map = map->mNext;
nuclear@14 611 ++ result;
nuclear@14 612 }
nuclear@14 613 if(!map)
nuclear@14 614 {
nuclear@14 615 return CTM_NONE;
nuclear@14 616 }
nuclear@14 617 return result;
nuclear@14 618 }
nuclear@14 619
nuclear@14 620 //-----------------------------------------------------------------------------
nuclear@14 621 // ctmGetString()
nuclear@14 622 //-----------------------------------------------------------------------------
nuclear@14 623 CTMEXPORT const char * CTMCALL ctmGetString(CTMcontext aContext,
nuclear@14 624 CTMenum aProperty)
nuclear@14 625 {
nuclear@14 626 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 627 if(!self) return 0;
nuclear@14 628
nuclear@14 629 switch(aProperty)
nuclear@14 630 {
nuclear@14 631 case CTM_FILE_COMMENT:
nuclear@14 632 return (const char *) self->mFileComment;
nuclear@14 633
nuclear@14 634 default:
nuclear@14 635 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 636 }
nuclear@14 637
nuclear@14 638 return (const char *) 0;
nuclear@14 639 }
nuclear@14 640
nuclear@14 641 //-----------------------------------------------------------------------------
nuclear@14 642 // ctmCompressionMethod()
nuclear@14 643 //-----------------------------------------------------------------------------
nuclear@14 644 CTMEXPORT void CTMCALL ctmCompressionMethod(CTMcontext aContext,
nuclear@14 645 CTMenum aMethod)
nuclear@14 646 {
nuclear@14 647 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 648 if(!self) return;
nuclear@14 649
nuclear@14 650 // You are only allowed to change compression attributes in export mode
nuclear@14 651 if(self->mMode != CTM_EXPORT)
nuclear@14 652 {
nuclear@14 653 self->mError = CTM_INVALID_OPERATION;
nuclear@14 654 return;
nuclear@14 655 }
nuclear@14 656
nuclear@14 657 // Check arguments
nuclear@14 658 if((aMethod != CTM_METHOD_RAW) && (aMethod != CTM_METHOD_MG1) &&
nuclear@14 659 (aMethod != CTM_METHOD_MG2))
nuclear@14 660 {
nuclear@14 661 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 662 return;
nuclear@14 663 }
nuclear@14 664
nuclear@14 665 // Set method
nuclear@14 666 self->mMethod = aMethod;
nuclear@14 667 }
nuclear@14 668
nuclear@14 669 //-----------------------------------------------------------------------------
nuclear@14 670 // ctmCompressionLevel()
nuclear@14 671 //-----------------------------------------------------------------------------
nuclear@14 672 CTMEXPORT void CTMCALL ctmCompressionLevel(CTMcontext aContext,
nuclear@14 673 CTMuint aLevel)
nuclear@14 674 {
nuclear@14 675 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 676 if(!self) return;
nuclear@14 677
nuclear@14 678 // You are only allowed to change compression attributes in export mode
nuclear@14 679 if(self->mMode != CTM_EXPORT)
nuclear@14 680 {
nuclear@14 681 self->mError = CTM_INVALID_OPERATION;
nuclear@14 682 return;
nuclear@14 683 }
nuclear@14 684
nuclear@14 685 // Check arguments
nuclear@14 686 if(aLevel > 9)
nuclear@14 687 {
nuclear@14 688 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 689 return;
nuclear@14 690 }
nuclear@14 691
nuclear@14 692 // Set the compression level
nuclear@14 693 self->mCompressionLevel = aLevel;
nuclear@14 694 }
nuclear@14 695
nuclear@14 696 //-----------------------------------------------------------------------------
nuclear@14 697 // ctmVertexPrecision()
nuclear@14 698 //-----------------------------------------------------------------------------
nuclear@14 699 CTMEXPORT void CTMCALL ctmVertexPrecision(CTMcontext aContext,
nuclear@14 700 CTMfloat aPrecision)
nuclear@14 701 {
nuclear@14 702 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 703 if(!self) return;
nuclear@14 704
nuclear@14 705 // You are only allowed to change compression attributes in export mode
nuclear@14 706 if(self->mMode != CTM_EXPORT)
nuclear@14 707 {
nuclear@14 708 self->mError = CTM_INVALID_OPERATION;
nuclear@14 709 return;
nuclear@14 710 }
nuclear@14 711
nuclear@14 712 // Check arguments
nuclear@14 713 if(aPrecision <= 0.0f)
nuclear@14 714 {
nuclear@14 715 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 716 return;
nuclear@14 717 }
nuclear@14 718
nuclear@14 719 // Set precision
nuclear@14 720 self->mVertexPrecision = aPrecision;
nuclear@14 721 }
nuclear@14 722
nuclear@14 723 //-----------------------------------------------------------------------------
nuclear@14 724 // ctmVertexPrecisionRel()
nuclear@14 725 //-----------------------------------------------------------------------------
nuclear@14 726 CTMEXPORT void CTMCALL ctmVertexPrecisionRel(CTMcontext aContext,
nuclear@14 727 CTMfloat aRelPrecision)
nuclear@14 728 {
nuclear@14 729 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 730 CTMfloat avgEdgeLength, * p1, * p2;
nuclear@14 731 CTMuint edgeCount, i, j;
nuclear@14 732 if(!self) return;
nuclear@14 733
nuclear@14 734 // You are only allowed to change compression attributes in export mode
nuclear@14 735 if(self->mMode != CTM_EXPORT)
nuclear@14 736 {
nuclear@14 737 self->mError = CTM_INVALID_OPERATION;
nuclear@14 738 return;
nuclear@14 739 }
nuclear@14 740
nuclear@14 741 // Check arguments
nuclear@14 742 if(aRelPrecision <= 0.0f)
nuclear@14 743 {
nuclear@14 744 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 745 return;
nuclear@14 746 }
nuclear@14 747
nuclear@14 748 // Calculate the average edge length (Note: we actually sum up all the half-
nuclear@14 749 // edges, so in a proper solid mesh all connected edges are counted twice)
nuclear@14 750 avgEdgeLength = 0.0f;
nuclear@14 751 edgeCount = 0;
nuclear@14 752 for(i = 0; i < self->mTriangleCount; ++ i)
nuclear@14 753 {
nuclear@14 754 p1 = &self->mVertices[self->mIndices[i * 3 + 2] * 3];
nuclear@14 755 for(j = 0; j < 3; ++ j)
nuclear@14 756 {
nuclear@14 757 p2 = &self->mVertices[self->mIndices[i * 3 + j] * 3];
nuclear@14 758 avgEdgeLength += sqrtf((p2[0] - p1[0]) * (p2[0] - p1[0]) +
nuclear@14 759 (p2[1] - p1[1]) * (p2[1] - p1[1]) +
nuclear@14 760 (p2[2] - p1[2]) * (p2[2] - p1[2]));
nuclear@14 761 p1 = p2;
nuclear@14 762 ++ edgeCount;
nuclear@14 763 }
nuclear@14 764 }
nuclear@14 765 if(edgeCount == 0)
nuclear@14 766 {
nuclear@14 767 self->mError = CTM_INVALID_MESH;
nuclear@14 768 return;
nuclear@14 769 }
nuclear@14 770 avgEdgeLength /= (CTMfloat) edgeCount;
nuclear@14 771
nuclear@14 772 // Set precision
nuclear@14 773 self->mVertexPrecision = aRelPrecision * avgEdgeLength;
nuclear@14 774 }
nuclear@14 775
nuclear@14 776 //-----------------------------------------------------------------------------
nuclear@14 777 // ctmNormalPrecision()
nuclear@14 778 //-----------------------------------------------------------------------------
nuclear@14 779 CTMEXPORT void CTMCALL ctmNormalPrecision(CTMcontext aContext,
nuclear@14 780 CTMfloat aPrecision)
nuclear@14 781 {
nuclear@14 782 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 783 if(!self) return;
nuclear@14 784
nuclear@14 785 // You are only allowed to change compression attributes in export mode
nuclear@14 786 if(self->mMode != CTM_EXPORT)
nuclear@14 787 {
nuclear@14 788 self->mError = CTM_INVALID_OPERATION;
nuclear@14 789 return;
nuclear@14 790 }
nuclear@14 791
nuclear@14 792 // Check arguments
nuclear@14 793 if(aPrecision <= 0.0f)
nuclear@14 794 {
nuclear@14 795 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 796 return;
nuclear@14 797 }
nuclear@14 798
nuclear@14 799 // Set precision
nuclear@14 800 self->mNormalPrecision = aPrecision;
nuclear@14 801 }
nuclear@14 802
nuclear@14 803 //-----------------------------------------------------------------------------
nuclear@14 804 // ctmUVCoordPrecision()
nuclear@14 805 //-----------------------------------------------------------------------------
nuclear@14 806 CTMEXPORT void CTMCALL ctmUVCoordPrecision(CTMcontext aContext,
nuclear@14 807 CTMenum aUVMap, CTMfloat aPrecision)
nuclear@14 808 {
nuclear@14 809 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 810 _CTMfloatmap * map;
nuclear@14 811 CTMuint i;
nuclear@14 812 if(!self) return;
nuclear@14 813
nuclear@14 814 // You are only allowed to change compression attributes in export mode
nuclear@14 815 if(self->mMode != CTM_EXPORT)
nuclear@14 816 {
nuclear@14 817 self->mError = CTM_INVALID_OPERATION;
nuclear@14 818 return;
nuclear@14 819 }
nuclear@14 820
nuclear@14 821 // Check arguments
nuclear@14 822 if(aPrecision <= 0.0f)
nuclear@14 823 {
nuclear@14 824 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 825 return;
nuclear@14 826 }
nuclear@14 827
nuclear@14 828 // Find the indicated map
nuclear@14 829 map = self->mUVMaps;
nuclear@14 830 i = CTM_UV_MAP_1;
nuclear@14 831 while(map && (i != aUVMap))
nuclear@14 832 {
nuclear@14 833 ++ i;
nuclear@14 834 map = map->mNext;
nuclear@14 835 }
nuclear@14 836 if(!map)
nuclear@14 837 {
nuclear@14 838 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 839 return;
nuclear@14 840 }
nuclear@14 841
nuclear@14 842 // Update the precision
nuclear@14 843 map->mPrecision = aPrecision;
nuclear@14 844 }
nuclear@14 845
nuclear@14 846 //-----------------------------------------------------------------------------
nuclear@14 847 // ctmAttribPrecision()
nuclear@14 848 //-----------------------------------------------------------------------------
nuclear@14 849 CTMEXPORT void CTMCALL ctmAttribPrecision(CTMcontext aContext,
nuclear@14 850 CTMenum aAttribMap, CTMfloat aPrecision)
nuclear@14 851 {
nuclear@14 852 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 853 _CTMfloatmap * map;
nuclear@14 854 CTMuint i;
nuclear@14 855 if(!self) return;
nuclear@14 856
nuclear@14 857 // You are only allowed to change compression attributes in export mode
nuclear@14 858 if(self->mMode != CTM_EXPORT)
nuclear@14 859 {
nuclear@14 860 self->mError = CTM_INVALID_OPERATION;
nuclear@14 861 return;
nuclear@14 862 }
nuclear@14 863
nuclear@14 864 // Check arguments
nuclear@14 865 if(aPrecision <= 0.0f)
nuclear@14 866 {
nuclear@14 867 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 868 return;
nuclear@14 869 }
nuclear@14 870
nuclear@14 871 // Find the indicated map
nuclear@14 872 map = self->mAttribMaps;
nuclear@14 873 i = CTM_ATTRIB_MAP_1;
nuclear@14 874 while(map && (i != aAttribMap))
nuclear@14 875 {
nuclear@14 876 ++ i;
nuclear@14 877 map = map->mNext;
nuclear@14 878 }
nuclear@14 879 if(!map)
nuclear@14 880 {
nuclear@14 881 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 882 return;
nuclear@14 883 }
nuclear@14 884
nuclear@14 885 // Update the precision
nuclear@14 886 map->mPrecision = aPrecision;
nuclear@14 887 }
nuclear@14 888
nuclear@14 889 //-----------------------------------------------------------------------------
nuclear@14 890 // ctmFileComment()
nuclear@14 891 //-----------------------------------------------------------------------------
nuclear@14 892 CTMEXPORT void CTMCALL ctmFileComment(CTMcontext aContext,
nuclear@14 893 const char * aFileComment)
nuclear@14 894 {
nuclear@14 895 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 896 int len;
nuclear@14 897 if(!self) return;
nuclear@14 898
nuclear@14 899 // You are only allowed to change file attributes in export mode
nuclear@14 900 if(self->mMode != CTM_EXPORT)
nuclear@14 901 {
nuclear@14 902 self->mError = CTM_INVALID_OPERATION;
nuclear@14 903 return;
nuclear@14 904 }
nuclear@14 905
nuclear@14 906 // Free the old comment string, if necessary
nuclear@14 907 if(self->mFileComment)
nuclear@14 908 {
nuclear@14 909 free(self->mFileComment);
nuclear@14 910 self->mFileComment = (char *) 0;
nuclear@14 911 }
nuclear@14 912
nuclear@14 913 // Get length of string (if empty, do nothing)
nuclear@14 914 if(!aFileComment)
nuclear@14 915 return;
nuclear@14 916 len = strlen(aFileComment);
nuclear@14 917 if(!len)
nuclear@14 918 return;
nuclear@14 919
nuclear@14 920 // Copy the string
nuclear@14 921 self->mFileComment = (char *) malloc(len + 1);
nuclear@14 922 if(!self->mFileComment)
nuclear@14 923 {
nuclear@14 924 self->mError = CTM_OUT_OF_MEMORY;
nuclear@14 925 return;
nuclear@14 926 }
nuclear@14 927 strcpy(self->mFileComment, aFileComment);
nuclear@14 928 }
nuclear@14 929
nuclear@14 930 //-----------------------------------------------------------------------------
nuclear@14 931 // ctmDefineMesh()
nuclear@14 932 //-----------------------------------------------------------------------------
nuclear@14 933 CTMEXPORT void CTMCALL ctmDefineMesh(CTMcontext aContext,
nuclear@14 934 const CTMfloat * aVertices, CTMuint aVertexCount, const CTMuint * aIndices,
nuclear@14 935 CTMuint aTriangleCount, const CTMfloat * aNormals)
nuclear@14 936 {
nuclear@14 937 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 938 if(!self) return;
nuclear@14 939
nuclear@14 940 // You are only allowed to (re)define the mesh in export mode
nuclear@14 941 if(self->mMode != CTM_EXPORT)
nuclear@14 942 {
nuclear@14 943 self->mError = CTM_INVALID_OPERATION;
nuclear@14 944 return;
nuclear@14 945 }
nuclear@14 946
nuclear@14 947 // Check arguments
nuclear@14 948 if(!aVertices || !aIndices || !aVertexCount || !aTriangleCount)
nuclear@14 949 {
nuclear@14 950 self->mError = CTM_INVALID_ARGUMENT;
nuclear@14 951 return;
nuclear@14 952 }
nuclear@14 953
nuclear@14 954 // Clear the old mesh, if any
nuclear@14 955 _ctmClearMesh(self);
nuclear@14 956
nuclear@14 957 // Set vertex array pointer
nuclear@14 958 self->mVertices = (CTMfloat *) aVertices;
nuclear@14 959 self->mVertexCount = aVertexCount;
nuclear@14 960
nuclear@14 961 // Set index array pointer
nuclear@14 962 self->mIndices = (CTMuint *) aIndices;
nuclear@14 963 self->mTriangleCount = aTriangleCount;
nuclear@14 964
nuclear@14 965 // Set normal array pointer
nuclear@14 966 self->mNormals = (CTMfloat *) aNormals;
nuclear@14 967 }
nuclear@14 968
nuclear@14 969 //-----------------------------------------------------------------------------
nuclear@14 970 // _ctmAddFloatMap()
nuclear@14 971 //-----------------------------------------------------------------------------
nuclear@14 972 static _CTMfloatmap * _ctmAddFloatMap(_CTMcontext * self,
nuclear@14 973 const CTMfloat * aValues, const char * aName, const char * aFileName,
nuclear@14 974 _CTMfloatmap ** aList)
nuclear@14 975 {
nuclear@14 976 _CTMfloatmap * map;
nuclear@14 977 CTMuint len;
nuclear@14 978
nuclear@14 979 // Allocate memory for a new map list item and append it to the list
nuclear@14 980 if(!*aList)
nuclear@14 981 {
nuclear@14 982 *aList = (_CTMfloatmap *) malloc(sizeof(_CTMfloatmap));
nuclear@14 983 map = *aList;
nuclear@14 984 }
nuclear@14 985 else
nuclear@14 986 {
nuclear@14 987 map = *aList;
nuclear@14 988 while(map->mNext)
nuclear@14 989 map = map->mNext;
nuclear@14 990 map->mNext = (_CTMfloatmap *) malloc(sizeof(_CTMfloatmap));
nuclear@14 991 map = map->mNext;
nuclear@14 992 }
nuclear@14 993 if(!map)
nuclear@14 994 {
nuclear@14 995 self->mError = CTM_OUT_OF_MEMORY;
nuclear@14 996 return (_CTMfloatmap *) 0;
nuclear@14 997 }
nuclear@14 998
nuclear@14 999 // Init the map item
nuclear@14 1000 memset(map, 0, sizeof(_CTMfloatmap));
nuclear@14 1001 map->mPrecision = 1.0f / 1024.0f;
nuclear@14 1002 map->mValues = (CTMfloat *) aValues;
nuclear@14 1003
nuclear@14 1004 // Set name of the map
nuclear@14 1005 if(aName)
nuclear@14 1006 {
nuclear@14 1007 // Get length of string (if empty, do nothing)
nuclear@14 1008 len = strlen(aName);
nuclear@14 1009 if(len)
nuclear@14 1010 {
nuclear@14 1011 // Copy the string
nuclear@14 1012 map->mName = (char *) malloc(len + 1);
nuclear@14 1013 if(!map->mName)
nuclear@14 1014 {
nuclear@14 1015 self->mError = CTM_OUT_OF_MEMORY;
nuclear@14 1016 free(map);
nuclear@14 1017 return (_CTMfloatmap *) 0;
nuclear@14 1018 }
nuclear@14 1019 strcpy(map->mName, aName);
nuclear@14 1020 }
nuclear@14 1021 }
nuclear@14 1022
nuclear@14 1023 // Set file name reference for the map
nuclear@14 1024 if(aFileName)
nuclear@14 1025 {
nuclear@14 1026 // Get length of string (if empty, do nothing)
nuclear@14 1027 len = strlen(aFileName);
nuclear@14 1028 if(len)
nuclear@14 1029 {
nuclear@14 1030 // Copy the string
nuclear@14 1031 map->mFileName = (char *) malloc(len + 1);
nuclear@14 1032 if(!map->mFileName)
nuclear@14 1033 {
nuclear@14 1034 self->mError = CTM_OUT_OF_MEMORY;
nuclear@14 1035 if(map->mName)
nuclear@14 1036 free(map->mName);
nuclear@14 1037 free(map);
nuclear@14 1038 return (_CTMfloatmap *) 0;
nuclear@14 1039 }
nuclear@14 1040 strcpy(map->mFileName, aFileName);
nuclear@14 1041 }
nuclear@14 1042 }
nuclear@14 1043
nuclear@14 1044 return map;
nuclear@14 1045 }
nuclear@14 1046
nuclear@14 1047 //-----------------------------------------------------------------------------
nuclear@14 1048 // ctmAddUVMap()
nuclear@14 1049 //-----------------------------------------------------------------------------
nuclear@14 1050 CTMEXPORT CTMenum CTMCALL ctmAddUVMap(CTMcontext aContext,
nuclear@14 1051 const CTMfloat * aUVCoords, const char * aName, const char * aFileName)
nuclear@14 1052 {
nuclear@14 1053 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 1054 _CTMfloatmap * map;
nuclear@14 1055 if(!self) return CTM_NONE;
nuclear@14 1056
nuclear@14 1057 // Add a new UV map to the UV map list
nuclear@14 1058 map = _ctmAddFloatMap(self, aUVCoords, aName, aFileName, &self->mUVMaps);
nuclear@14 1059 if(!map)
nuclear@14 1060 return CTM_NONE;
nuclear@14 1061 else
nuclear@14 1062 {
nuclear@14 1063 // The default UV coordinate precision is 2^-12
nuclear@14 1064 map->mPrecision = 1.0f / 4096.0f;
nuclear@14 1065 ++ self->mUVMapCount;
nuclear@14 1066 return CTM_UV_MAP_1 + self->mUVMapCount - 1;
nuclear@14 1067 }
nuclear@14 1068 }
nuclear@14 1069
nuclear@14 1070 //-----------------------------------------------------------------------------
nuclear@14 1071 // ctmAddAttribMap()
nuclear@14 1072 //-----------------------------------------------------------------------------
nuclear@14 1073 CTMEXPORT CTMenum CTMCALL ctmAddAttribMap(CTMcontext aContext,
nuclear@14 1074 const CTMfloat * aAttribValues, const char * aName)
nuclear@14 1075 {
nuclear@14 1076 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 1077 _CTMfloatmap * map;
nuclear@14 1078 if(!self) return CTM_NONE;
nuclear@14 1079
nuclear@14 1080 // Add a new attribute map to the attribute map list
nuclear@14 1081 map = _ctmAddFloatMap(self, aAttribValues, aName, (const char *) 0,
nuclear@14 1082 &self->mAttribMaps);
nuclear@14 1083 if(!map)
nuclear@14 1084 return CTM_NONE;
nuclear@14 1085 else
nuclear@14 1086 {
nuclear@14 1087 // The default vertex attribute precision is 2^-8
nuclear@14 1088 map->mPrecision = 1.0f / 256.0f;
nuclear@14 1089 ++ self->mAttribMapCount;
nuclear@14 1090 return CTM_ATTRIB_MAP_1 + self->mAttribMapCount - 1;
nuclear@14 1091 }
nuclear@14 1092 }
nuclear@14 1093
nuclear@14 1094 //-----------------------------------------------------------------------------
nuclear@14 1095 // _ctmDefaultRead()
nuclear@14 1096 //-----------------------------------------------------------------------------
nuclear@14 1097 static CTMuint CTMCALL _ctmDefaultRead(void * aBuf, CTMuint aCount,
nuclear@14 1098 void * aUserData)
nuclear@14 1099 {
nuclear@14 1100 return (CTMuint) fread(aBuf, 1, (size_t) aCount, (FILE *) aUserData);
nuclear@14 1101 }
nuclear@14 1102
nuclear@14 1103 //-----------------------------------------------------------------------------
nuclear@14 1104 // ctmLoad()
nuclear@14 1105 //-----------------------------------------------------------------------------
nuclear@14 1106 CTMEXPORT void CTMCALL ctmLoad(CTMcontext aContext, const char * aFileName)
nuclear@14 1107 {
nuclear@14 1108 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 1109 FILE * f;
nuclear@14 1110 if(!self) return;
nuclear@14 1111
nuclear@14 1112 // You are only allowed to load data in import mode
nuclear@14 1113 if(self->mMode != CTM_IMPORT)
nuclear@14 1114 {
nuclear@14 1115 self->mError = CTM_INVALID_OPERATION;
nuclear@14 1116 return;
nuclear@14 1117 }
nuclear@14 1118
nuclear@14 1119 // Open file stream
nuclear@14 1120 f = fopen(aFileName, "rb");
nuclear@14 1121 if(!f)
nuclear@14 1122 {
nuclear@14 1123 self->mError = CTM_FILE_ERROR;
nuclear@14 1124 return;
nuclear@14 1125 }
nuclear@14 1126
nuclear@14 1127 // Load the file
nuclear@14 1128 ctmLoadCustom(self, _ctmDefaultRead, (void *) f);
nuclear@14 1129
nuclear@14 1130 // Close file stream
nuclear@14 1131 fclose(f);
nuclear@14 1132 }
nuclear@14 1133
nuclear@14 1134 //-----------------------------------------------------------------------------
nuclear@14 1135 // _ctmAllocateFloatMaps()
nuclear@14 1136 //-----------------------------------------------------------------------------
nuclear@14 1137 static CTMuint _ctmAllocateFloatMaps(_CTMcontext * self,
nuclear@14 1138 _CTMfloatmap ** aMapListPtr, CTMuint aCount, CTMuint aChannels)
nuclear@14 1139 {
nuclear@14 1140 _CTMfloatmap ** mapListPtr;
nuclear@14 1141 CTMuint i, size;
nuclear@14 1142
nuclear@14 1143 mapListPtr = aMapListPtr;
nuclear@14 1144 for(i = 0; i < aCount; ++ i)
nuclear@14 1145 {
nuclear@14 1146 // Allocate & clear memory for this map
nuclear@14 1147 *mapListPtr = (_CTMfloatmap *) malloc(sizeof(_CTMfloatmap));
nuclear@14 1148 if(!*mapListPtr)
nuclear@14 1149 {
nuclear@14 1150 self->mError = CTM_OUT_OF_MEMORY;
nuclear@14 1151 return CTM_FALSE;
nuclear@14 1152 }
nuclear@14 1153 memset(*mapListPtr, 0, sizeof(_CTMfloatmap));
nuclear@14 1154
nuclear@14 1155 // Allocate & clear memory for the float array
nuclear@14 1156 size = aChannels * sizeof(CTMfloat) * self->mVertexCount;
nuclear@14 1157 (*mapListPtr)->mValues = (CTMfloat *) malloc(size);
nuclear@14 1158 if(!(*mapListPtr)->mValues)
nuclear@14 1159 {
nuclear@14 1160 self->mError = CTM_OUT_OF_MEMORY;
nuclear@14 1161 return CTM_FALSE;
nuclear@14 1162 }
nuclear@14 1163 memset((*mapListPtr)->mValues, 0, size);
nuclear@14 1164
nuclear@14 1165 // Next map...
nuclear@14 1166 mapListPtr = &(*mapListPtr)->mNext;
nuclear@14 1167 }
nuclear@14 1168
nuclear@14 1169 return CTM_TRUE;
nuclear@14 1170 }
nuclear@14 1171
nuclear@14 1172 //-----------------------------------------------------------------------------
nuclear@14 1173 // ctmLoadCustom()
nuclear@14 1174 //-----------------------------------------------------------------------------
nuclear@14 1175 CTMEXPORT void CTMCALL ctmLoadCustom(CTMcontext aContext, CTMreadfn aReadFn,
nuclear@14 1176 void * aUserData)
nuclear@14 1177 {
nuclear@14 1178 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 1179 CTMuint formatVersion, flags, method;
nuclear@14 1180 if(!self) return;
nuclear@14 1181
nuclear@14 1182 // You are only allowed to load data in import mode
nuclear@14 1183 if(self->mMode != CTM_IMPORT)
nuclear@14 1184 {
nuclear@14 1185 self->mError = CTM_INVALID_OPERATION;
nuclear@14 1186 return;
nuclear@14 1187 }
nuclear@14 1188
nuclear@14 1189 // Initialize stream
nuclear@14 1190 self->mReadFn = aReadFn;
nuclear@14 1191 self->mUserData = aUserData;
nuclear@14 1192
nuclear@14 1193 // Clear any old mesh arrays
nuclear@14 1194 _ctmClearMesh(self);
nuclear@14 1195
nuclear@14 1196 // Read header from stream
nuclear@14 1197 if(_ctmStreamReadUINT(self) != FOURCC("OCTM"))
nuclear@14 1198 {
nuclear@14 1199 self->mError = CTM_BAD_FORMAT;
nuclear@14 1200 return;
nuclear@14 1201 }
nuclear@14 1202 formatVersion = _ctmStreamReadUINT(self);
nuclear@14 1203 if(formatVersion != _CTM_FORMAT_VERSION)
nuclear@14 1204 {
nuclear@14 1205 self->mError = CTM_UNSUPPORTED_FORMAT_VERSION;
nuclear@14 1206 return;
nuclear@14 1207 }
nuclear@14 1208 method = _ctmStreamReadUINT(self);
nuclear@14 1209 if(method == FOURCC("RAW\0"))
nuclear@14 1210 self->mMethod = CTM_METHOD_RAW;
nuclear@14 1211 else if(method == FOURCC("MG1\0"))
nuclear@14 1212 self->mMethod = CTM_METHOD_MG1;
nuclear@14 1213 else if(method == FOURCC("MG2\0"))
nuclear@14 1214 self->mMethod = CTM_METHOD_MG2;
nuclear@14 1215 else
nuclear@14 1216 {
nuclear@14 1217 self->mError = CTM_BAD_FORMAT;
nuclear@14 1218 return;
nuclear@14 1219 }
nuclear@14 1220 self->mVertexCount = _ctmStreamReadUINT(self);
nuclear@14 1221 if(self->mVertexCount == 0)
nuclear@14 1222 {
nuclear@14 1223 self->mError = CTM_BAD_FORMAT;
nuclear@14 1224 return;
nuclear@14 1225 }
nuclear@14 1226 self->mTriangleCount = _ctmStreamReadUINT(self);
nuclear@14 1227 if(self->mTriangleCount == 0)
nuclear@14 1228 {
nuclear@14 1229 self->mError = CTM_BAD_FORMAT;
nuclear@14 1230 return;
nuclear@14 1231 }
nuclear@14 1232 self->mUVMapCount = _ctmStreamReadUINT(self);
nuclear@14 1233 self->mAttribMapCount = _ctmStreamReadUINT(self);
nuclear@14 1234 flags = _ctmStreamReadUINT(self);
nuclear@14 1235 _ctmStreamReadSTRING(self, &self->mFileComment);
nuclear@14 1236
nuclear@14 1237 // Allocate memory for the mesh arrays
nuclear@14 1238 self->mVertices = (CTMfloat *) malloc(self->mVertexCount * sizeof(CTMfloat) * 3);
nuclear@14 1239 if(!self->mVertices)
nuclear@14 1240 {
nuclear@14 1241 self->mError = CTM_OUT_OF_MEMORY;
nuclear@14 1242 return;
nuclear@14 1243 }
nuclear@14 1244 self->mIndices = (CTMuint *) malloc(self->mTriangleCount * sizeof(CTMuint) * 3);
nuclear@14 1245 if(!self->mIndices)
nuclear@14 1246 {
nuclear@14 1247 _ctmClearMesh(self);
nuclear@14 1248 self->mError = CTM_OUT_OF_MEMORY;
nuclear@14 1249 return;
nuclear@14 1250 }
nuclear@14 1251 if(flags & _CTM_HAS_NORMALS_BIT)
nuclear@14 1252 {
nuclear@14 1253 self->mNormals = (CTMfloat *) malloc(self->mVertexCount * sizeof(CTMfloat) * 3);
nuclear@14 1254 if(!self->mNormals)
nuclear@14 1255 {
nuclear@14 1256 _ctmClearMesh(self);
nuclear@14 1257 self->mError = CTM_OUT_OF_MEMORY;
nuclear@14 1258 return;
nuclear@14 1259 }
nuclear@14 1260 }
nuclear@14 1261
nuclear@14 1262 // Allocate memory for the UV and attribute maps (if any)
nuclear@14 1263 if(!_ctmAllocateFloatMaps(self, &self->mUVMaps, self->mUVMapCount, 2))
nuclear@14 1264 {
nuclear@14 1265 _ctmClearMesh(self);
nuclear@14 1266 self->mError = CTM_OUT_OF_MEMORY;
nuclear@14 1267 return;
nuclear@14 1268 }
nuclear@14 1269 if(!_ctmAllocateFloatMaps(self, &self->mAttribMaps, self->mAttribMapCount, 4))
nuclear@14 1270 {
nuclear@14 1271 _ctmClearMesh(self);
nuclear@14 1272 self->mError = CTM_OUT_OF_MEMORY;
nuclear@14 1273 return;
nuclear@14 1274 }
nuclear@14 1275
nuclear@14 1276 // Uncompress from stream
nuclear@14 1277 switch(self->mMethod)
nuclear@14 1278 {
nuclear@14 1279 case CTM_METHOD_RAW:
nuclear@14 1280 _ctmUncompressMesh_RAW(self);
nuclear@14 1281 break;
nuclear@14 1282
nuclear@14 1283 case CTM_METHOD_MG1:
nuclear@14 1284 _ctmUncompressMesh_MG1(self);
nuclear@14 1285 break;
nuclear@14 1286
nuclear@14 1287 case CTM_METHOD_MG2:
nuclear@14 1288 _ctmUncompressMesh_MG2(self);
nuclear@14 1289 break;
nuclear@14 1290
nuclear@14 1291 default:
nuclear@14 1292 self->mError = CTM_INTERNAL_ERROR;
nuclear@14 1293 }
nuclear@14 1294
nuclear@14 1295 // Check mesh integrity
nuclear@14 1296 if(!_ctmCheckMeshIntegrity(self))
nuclear@14 1297 {
nuclear@14 1298 self->mError = CTM_INVALID_MESH;
nuclear@14 1299 return;
nuclear@14 1300 }
nuclear@14 1301 }
nuclear@14 1302
nuclear@14 1303 //-----------------------------------------------------------------------------
nuclear@14 1304 // _ctmDefaultWrite()
nuclear@14 1305 //-----------------------------------------------------------------------------
nuclear@14 1306 static CTMuint CTMCALL _ctmDefaultWrite(const void * aBuf, CTMuint aCount,
nuclear@14 1307 void * aUserData)
nuclear@14 1308 {
nuclear@14 1309 return (CTMuint) fwrite(aBuf, 1, (size_t) aCount, (FILE *) aUserData);
nuclear@14 1310 }
nuclear@14 1311
nuclear@14 1312 //-----------------------------------------------------------------------------
nuclear@14 1313 // ctmSave()
nuclear@14 1314 //-----------------------------------------------------------------------------
nuclear@14 1315 CTMEXPORT void CTMCALL ctmSave(CTMcontext aContext, const char * aFileName)
nuclear@14 1316 {
nuclear@14 1317 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 1318 FILE * f;
nuclear@14 1319 if(!self) return;
nuclear@14 1320
nuclear@14 1321 // You are only allowed to save data in export mode
nuclear@14 1322 if(self->mMode != CTM_EXPORT)
nuclear@14 1323 {
nuclear@14 1324 self->mError = CTM_INVALID_OPERATION;
nuclear@14 1325 return;
nuclear@14 1326 }
nuclear@14 1327
nuclear@14 1328 // Open file stream
nuclear@14 1329 f = fopen(aFileName, "wb");
nuclear@14 1330 if(!f)
nuclear@14 1331 {
nuclear@14 1332 self->mError = CTM_FILE_ERROR;
nuclear@14 1333 return;
nuclear@14 1334 }
nuclear@14 1335
nuclear@14 1336 // Save the file
nuclear@14 1337 ctmSaveCustom(self, _ctmDefaultWrite, (void *) f);
nuclear@14 1338
nuclear@14 1339 // Close file stream
nuclear@14 1340 fclose(f);
nuclear@14 1341 }
nuclear@14 1342
nuclear@14 1343 //-----------------------------------------------------------------------------
nuclear@14 1344 // ctmSaveCustom()
nuclear@14 1345 //-----------------------------------------------------------------------------
nuclear@14 1346 void CTMCALL ctmSaveCustom(CTMcontext aContext, CTMwritefn aWriteFn,
nuclear@14 1347 void * aUserData)
nuclear@14 1348 {
nuclear@14 1349 _CTMcontext * self = (_CTMcontext *) aContext;
nuclear@14 1350 CTMuint flags;
nuclear@14 1351 if(!self) return;
nuclear@14 1352
nuclear@14 1353 // You are only allowed to save data in export mode
nuclear@14 1354 if(self->mMode != CTM_EXPORT)
nuclear@14 1355 {
nuclear@14 1356 self->mError = CTM_INVALID_OPERATION;
nuclear@14 1357 return;
nuclear@14 1358 }
nuclear@14 1359
nuclear@14 1360 // Check mesh integrity
nuclear@14 1361 if(!_ctmCheckMeshIntegrity(self))
nuclear@14 1362 {
nuclear@14 1363 self->mError = CTM_INVALID_MESH;
nuclear@14 1364 return;
nuclear@14 1365 }
nuclear@14 1366
nuclear@14 1367 // Initialize stream
nuclear@14 1368 self->mWriteFn = aWriteFn;
nuclear@14 1369 self->mUserData = aUserData;
nuclear@14 1370
nuclear@14 1371 // Determine flags
nuclear@14 1372 flags = 0;
nuclear@14 1373 if(self->mNormals)
nuclear@14 1374 flags |= _CTM_HAS_NORMALS_BIT;
nuclear@14 1375
nuclear@14 1376 // Write header to stream
nuclear@14 1377 _ctmStreamWrite(self, (void *) "OCTM", 4);
nuclear@14 1378 _ctmStreamWriteUINT(self, _CTM_FORMAT_VERSION);
nuclear@14 1379 switch(self->mMethod)
nuclear@14 1380 {
nuclear@14 1381 case CTM_METHOD_RAW:
nuclear@14 1382 _ctmStreamWrite(self, (void *) "RAW\0", 4);
nuclear@14 1383 break;
nuclear@14 1384
nuclear@14 1385 case CTM_METHOD_MG1:
nuclear@14 1386 _ctmStreamWrite(self, (void *) "MG1\0", 4);
nuclear@14 1387 break;
nuclear@14 1388
nuclear@14 1389 case CTM_METHOD_MG2:
nuclear@14 1390 _ctmStreamWrite(self, (void *) "MG2\0", 4);
nuclear@14 1391 break;
nuclear@14 1392
nuclear@14 1393 default:
nuclear@14 1394 self->mError = CTM_INTERNAL_ERROR;
nuclear@14 1395 return;
nuclear@14 1396 }
nuclear@14 1397 _ctmStreamWriteUINT(self, self->mVertexCount);
nuclear@14 1398 _ctmStreamWriteUINT(self, self->mTriangleCount);
nuclear@14 1399 _ctmStreamWriteUINT(self, self->mUVMapCount);
nuclear@14 1400 _ctmStreamWriteUINT(self, self->mAttribMapCount);
nuclear@14 1401 _ctmStreamWriteUINT(self, flags);
nuclear@14 1402 _ctmStreamWriteSTRING(self, self->mFileComment);
nuclear@14 1403
nuclear@14 1404 // Compress to stream
nuclear@14 1405 switch(self->mMethod)
nuclear@14 1406 {
nuclear@14 1407 case CTM_METHOD_RAW:
nuclear@14 1408 _ctmCompressMesh_RAW(self);
nuclear@14 1409 break;
nuclear@14 1410
nuclear@14 1411 case CTM_METHOD_MG1:
nuclear@14 1412 _ctmCompressMesh_MG1(self);
nuclear@14 1413 break;
nuclear@14 1414
nuclear@14 1415 case CTM_METHOD_MG2:
nuclear@14 1416 _ctmCompressMesh_MG2(self);
nuclear@14 1417 break;
nuclear@14 1418
nuclear@14 1419 default:
nuclear@14 1420 self->mError = CTM_INTERNAL_ERROR;
nuclear@14 1421 return;
nuclear@14 1422 }
nuclear@14 1423 }