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@94
|
916 len = (int)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@94
|
1008 len = (CTMuint)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@94
|
1027 len = (CTMuint)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 }
|