goat3d

view libs/openctm/compressMG2.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
line source
1 //-----------------------------------------------------------------------------
2 // Product: OpenCTM
3 // File: compressMG2.c
4 // Description: Implementation of the MG2 compression method.
5 //-----------------------------------------------------------------------------
6 // Copyright (c) 2009-2010 Marcus Geelnard
7 //
8 // This software is provided 'as-is', without any express or implied
9 // warranty. In no event will the authors be held liable for any damages
10 // arising from the use of this software.
11 //
12 // Permission is granted to anyone to use this software for any purpose,
13 // including commercial applications, and to alter it and redistribute it
14 // freely, subject to the following restrictions:
15 //
16 // 1. The origin of this software must not be misrepresented; you must not
17 // claim that you wrote the original software. If you use this software
18 // in a product, an acknowledgment in the product documentation would be
19 // appreciated but is not required.
20 //
21 // 2. Altered source versions must be plainly marked as such, and must not
22 // be misrepresented as being the original software.
23 //
24 // 3. This notice may not be removed or altered from any source
25 // distribution.
26 //-----------------------------------------------------------------------------
28 #include <stdlib.h>
29 #include <math.h>
30 #include "openctm.h"
31 #include "internal.h"
33 #ifdef __DEBUG_
34 #include <stdio.h>
35 #endif
37 // We need PI
38 #ifndef PI
39 #define PI 3.141592653589793238462643f
40 #endif
43 //-----------------------------------------------------------------------------
44 // _CTMgrid - 3D space subdivision grid.
45 //-----------------------------------------------------------------------------
46 typedef struct {
47 // Axis-aligned boudning box for the grid.
48 CTMfloat mMin[3];
49 CTMfloat mMax[3];
51 // How many divisions per axis (minimum 1).
52 CTMuint mDivision[3];
54 // Size of each grid box.
55 CTMfloat mSize[3];
56 } _CTMgrid;
58 //-----------------------------------------------------------------------------
59 // _CTMsortvertex - Vertex information.
60 //-----------------------------------------------------------------------------
61 typedef struct {
62 // Vertex X coordinate (used for sorting).
63 CTMfloat x;
65 // Grid index. This is the index into the 3D space subdivision grid.
66 CTMuint mGridIndex;
68 // Original index (before sorting).
69 CTMuint mOriginalIndex;
70 } _CTMsortvertex;
72 //-----------------------------------------------------------------------------
73 // _ctmSetupGrid() - Setup the 3D space subdivision grid.
74 //-----------------------------------------------------------------------------
75 static void _ctmSetupGrid(_CTMcontext * self, _CTMgrid * aGrid)
76 {
77 CTMuint i;
78 CTMfloat factor[3], sum, wantedGrids;
80 // Calculate the mesh bounding box
81 aGrid->mMin[0] = aGrid->mMax[0] = self->mVertices[0];
82 aGrid->mMin[1] = aGrid->mMax[1] = self->mVertices[1];
83 aGrid->mMin[2] = aGrid->mMax[2] = self->mVertices[2];
84 for(i = 1; i < self->mVertexCount; ++ i)
85 {
86 if(self->mVertices[i * 3] < aGrid->mMin[0])
87 aGrid->mMin[0] = self->mVertices[i * 3];
88 else if(self->mVertices[i * 3] > aGrid->mMax[0])
89 aGrid->mMax[0] = self->mVertices[i * 3];
90 if(self->mVertices[i * 3 + 1] < aGrid->mMin[1])
91 aGrid->mMin[1] = self->mVertices[i * 3 + 1];
92 else if(self->mVertices[i * 3 + 1] > aGrid->mMax[1])
93 aGrid->mMax[1] = self->mVertices[i * 3 + 1];
94 if(self->mVertices[i * 3 + 2] < aGrid->mMin[2])
95 aGrid->mMin[2] = self->mVertices[i * 3 + 2];
96 else if(self->mVertices[i * 3 + 2] > aGrid->mMax[2])
97 aGrid->mMax[2] = self->mVertices[i * 3 + 2];
98 }
100 // Determine optimal grid resolution, based on the number of vertices and
101 // the bounding box.
102 // NOTE: This algorithm is quite crude, and could very well be optimized for
103 // better compression levels in the future without affecting the file format
104 // or backward compatibility at all.
105 for(i = 0; i < 3; ++ i)
106 factor[i] = aGrid->mMax[i] - aGrid->mMin[i];
107 sum = factor[0] + factor[1] + factor[2];
108 if(sum > 1e-30f)
109 {
110 sum = 1.0f / sum;
111 for(i = 0; i < 3; ++ i)
112 factor[i] *= sum;
113 wantedGrids = powf(100.0f * self->mVertexCount, 1.0f / 3.0f);
114 for(i = 0; i < 3; ++ i)
115 {
116 aGrid->mDivision[i] = (CTMuint) ceilf(wantedGrids * factor[i]);
117 if(aGrid->mDivision[i] < 1)
118 aGrid->mDivision[i] = 1;
119 }
120 }
121 else
122 {
123 aGrid->mDivision[0] = 4;
124 aGrid->mDivision[1] = 4;
125 aGrid->mDivision[2] = 4;
126 }
127 #ifdef __DEBUG_
128 printf("Division: (%d %d %d)\n", aGrid->mDivision[0], aGrid->mDivision[1], aGrid->mDivision[2]);
129 #endif
131 // Calculate grid sizes
132 for(i = 0; i < 3; ++ i)
133 aGrid->mSize[i] = (aGrid->mMax[i] - aGrid->mMin[i]) / aGrid->mDivision[i];
134 }
136 //-----------------------------------------------------------------------------
137 // _ctmPointToGridIdx() - Convert a point to a grid index.
138 //-----------------------------------------------------------------------------
139 static CTMuint _ctmPointToGridIdx(_CTMgrid * aGrid, CTMfloat * aPoint)
140 {
141 CTMuint i, idx[3];
143 for(i = 0; i < 3; ++ i)
144 {
145 idx[i] = (CTMuint) floorf((aPoint[i] - aGrid->mMin[i]) / aGrid->mSize[i]);
146 if(idx[i] >= aGrid->mDivision[i])
147 idx[i] = aGrid->mDivision[i] - 1;
148 }
150 return idx[0] + aGrid->mDivision[0] * (idx[1] + aGrid->mDivision[1] * idx[2]);
151 }
153 //-----------------------------------------------------------------------------
154 // _ctmGridIdxToPoint() - Convert a grid index to a point (the min x/y/z for
155 // the given grid box).
156 //-----------------------------------------------------------------------------
157 static void _ctmGridIdxToPoint(_CTMgrid * aGrid, CTMuint aIdx, CTMfloat * aPoint)
158 {
159 CTMuint gridIdx[3], zdiv, ydiv, i;
161 zdiv = aGrid->mDivision[0] * aGrid->mDivision[1];
162 ydiv = aGrid->mDivision[0];
164 gridIdx[2] = aIdx / zdiv;
165 aIdx -= gridIdx[2] * zdiv;
166 gridIdx[1] = aIdx / ydiv;
167 aIdx -= gridIdx[1] * ydiv;
168 gridIdx[0] = aIdx;
170 for(i = 0; i < 3; ++ i)
171 aPoint[i] = gridIdx[i] * aGrid->mSize[i] + aGrid->mMin[i];
172 }
174 //-----------------------------------------------------------------------------
175 // _compareVertex() - Comparator for the vertex sorting.
176 //-----------------------------------------------------------------------------
177 static int _compareVertex(const void * elem1, const void * elem2)
178 {
179 _CTMsortvertex * v1 = (_CTMsortvertex *) elem1;
180 _CTMsortvertex * v2 = (_CTMsortvertex *) elem2;
181 if(v1->mGridIndex != v2->mGridIndex)
182 return v1->mGridIndex - v2->mGridIndex;
183 else if(v1->x < v2->x)
184 return -1;
185 else if(v1->x > v2->x)
186 return 1;
187 else
188 return 0;
189 }
191 //-----------------------------------------------------------------------------
192 // _ctmSortVertices() - Setup the vertex array. Assign each vertex to a grid
193 // box, and sort all vertices.
194 //-----------------------------------------------------------------------------
195 static void _ctmSortVertices(_CTMcontext * self, _CTMsortvertex * aSortVertices,
196 _CTMgrid * aGrid)
197 {
198 CTMuint i;
200 // Prepare sort vertex array
201 for(i = 0; i < self->mVertexCount; ++ i)
202 {
203 // Store vertex properties in the sort vertex array
204 aSortVertices[i].x = self->mVertices[i * 3];
205 aSortVertices[i].mGridIndex = _ctmPointToGridIdx(aGrid, &self->mVertices[i * 3]);
206 aSortVertices[i].mOriginalIndex = i;
207 }
209 // Sort vertices. The elements are first sorted by their grid indices, and
210 // scondly by their x coordinates.
211 qsort((void *) aSortVertices, self->mVertexCount, sizeof(_CTMsortvertex), _compareVertex);
212 }
214 //-----------------------------------------------------------------------------
215 // _ctmReIndexIndices() - Re-index all indices, based on the sorted vertices.
216 //-----------------------------------------------------------------------------
217 static int _ctmReIndexIndices(_CTMcontext * self, _CTMsortvertex * aSortVertices,
218 CTMuint * aIndices)
219 {
220 CTMuint i, * indexLUT;
222 // Create temporary lookup-array, O(n)
223 indexLUT = (CTMuint *) malloc(sizeof(CTMuint) * self->mVertexCount);
224 if(!indexLUT)
225 {
226 self->mError = CTM_OUT_OF_MEMORY;
227 return CTM_FALSE;
228 }
229 for(i = 0; i < self->mVertexCount; ++ i)
230 indexLUT[aSortVertices[i].mOriginalIndex] = i;
232 // Convert old indices to new indices, O(n)
233 for(i = 0; i < self->mTriangleCount * 3; ++ i)
234 aIndices[i] = indexLUT[self->mIndices[i]];
236 // Free temporary lookup-array
237 free((void *) indexLUT);
239 return CTM_TRUE;
240 }
242 //-----------------------------------------------------------------------------
243 // _compareTriangle() - Comparator for the triangle sorting.
244 //-----------------------------------------------------------------------------
245 static int _compareTriangle(const void * elem1, const void * elem2)
246 {
247 CTMuint * tri1 = (CTMuint *) elem1;
248 CTMuint * tri2 = (CTMuint *) elem2;
249 if(tri1[0] != tri2[0])
250 return tri1[0] - tri2[0];
251 else
252 return tri1[1] - tri2[1];
253 }
255 //-----------------------------------------------------------------------------
256 // _ctmReArrangeTriangles() - Re-arrange all triangles for optimal
257 // compression.
258 //-----------------------------------------------------------------------------
259 static void _ctmReArrangeTriangles(_CTMcontext * self, CTMuint * aIndices)
260 {
261 CTMuint * tri, tmp, i;
263 // Step 1: Make sure that the first index of each triangle is the smallest
264 // one (rotate triangle nodes if necessary)
265 for(i = 0; i < self->mTriangleCount; ++ i)
266 {
267 tri = &aIndices[i * 3];
268 if((tri[1] < tri[0]) && (tri[1] < tri[2]))
269 {
270 tmp = tri[0];
271 tri[0] = tri[1];
272 tri[1] = tri[2];
273 tri[2] = tmp;
274 }
275 else if((tri[2] < tri[0]) && (tri[2] < tri[1]))
276 {
277 tmp = tri[0];
278 tri[0] = tri[2];
279 tri[2] = tri[1];
280 tri[1] = tmp;
281 }
282 }
284 // Step 2: Sort the triangles based on the first triangle index
285 qsort((void *) aIndices, self->mTriangleCount, sizeof(CTMuint) * 3, _compareTriangle);
286 }
288 //-----------------------------------------------------------------------------
289 // _ctmMakeIndexDeltas() - Calculate various forms of derivatives in order to
290 // reduce data entropy.
291 //-----------------------------------------------------------------------------
292 static void _ctmMakeIndexDeltas(_CTMcontext * self, CTMuint * aIndices)
293 {
294 CTMint i;
295 for(i = self->mTriangleCount - 1; i >= 0; -- i)
296 {
297 // Step 1: Calculate delta from second triangle index to the previous
298 // second triangle index, if the previous triangle shares the same first
299 // index, otherwise calculate the delta to the first triangle index
300 if((i >= 1) && (aIndices[i * 3] == aIndices[(i - 1) * 3]))
301 aIndices[i * 3 + 1] -= aIndices[(i - 1) * 3 + 1];
302 else
303 aIndices[i * 3 + 1] -= aIndices[i * 3];
305 // Step 2: Calculate delta from third triangle index to the first triangle
306 // index
307 aIndices[i * 3 + 2] -= aIndices[i * 3];
309 // Step 3: Calculate derivative of the first triangle index
310 if(i >= 1)
311 aIndices[i * 3] -= aIndices[(i - 1) * 3];
312 }
313 }
315 //-----------------------------------------------------------------------------
316 // _ctmRestoreIndices() - Restore original indices (inverse derivative
317 // operation).
318 //-----------------------------------------------------------------------------
319 static void _ctmRestoreIndices(_CTMcontext * self, CTMuint * aIndices)
320 {
321 CTMuint i;
323 for(i = 0; i < self->mTriangleCount; ++ i)
324 {
325 // Step 1: Reverse derivative of the first triangle index
326 if(i >= 1)
327 aIndices[i * 3] += aIndices[(i - 1) * 3];
329 // Step 2: Reverse delta from third triangle index to the first triangle
330 // index
331 aIndices[i * 3 + 2] += aIndices[i * 3];
333 // Step 3: Reverse delta from second triangle index to the previous
334 // second triangle index, if the previous triangle shares the same first
335 // index, otherwise reverse the delta to the first triangle index
336 if((i >= 1) && (aIndices[i * 3] == aIndices[(i - 1) * 3]))
337 aIndices[i * 3 + 1] += aIndices[(i - 1) * 3 + 1];
338 else
339 aIndices[i * 3 + 1] += aIndices[i * 3];
340 }
341 }
343 //-----------------------------------------------------------------------------
344 // _ctmMakeVertexDeltas() - Calculate various forms of derivatives in order to
345 // reduce data entropy.
346 //-----------------------------------------------------------------------------
347 static void _ctmMakeVertexDeltas(_CTMcontext * self, CTMint * aIntVertices,
348 _CTMsortvertex * aSortVertices, _CTMgrid * aGrid)
349 {
350 CTMuint i, gridIdx, prevGridIndex, oldIdx;
351 CTMfloat gridOrigin[3], scale;
352 CTMint deltaX, prevDeltaX;
354 // Vertex scaling factor
355 scale = 1.0f / self->mVertexPrecision;
357 prevGridIndex = 0x7fffffff;
358 prevDeltaX = 0;
359 for(i = 0; i < self->mVertexCount; ++ i)
360 {
361 // Get grid box origin
362 gridIdx = aSortVertices[i].mGridIndex;
363 _ctmGridIdxToPoint(aGrid, gridIdx, gridOrigin);
365 // Get old vertex coordinate index (before vertex sorting)
366 oldIdx = aSortVertices[i].mOriginalIndex;
368 // Store delta to the grid box origin in the integer vertex array. For the
369 // X axis (which is sorted) we also do the delta to the previous coordinate
370 // in the box.
371 deltaX = (CTMint) floorf(scale * (self->mVertices[oldIdx * 3] - gridOrigin[0]) + 0.5f);
372 if(gridIdx == prevGridIndex)
373 aIntVertices[i * 3] = deltaX - prevDeltaX;
374 else
375 aIntVertices[i * 3] = deltaX;
376 aIntVertices[i * 3 + 1] = (CTMint) floorf(scale * (self->mVertices[oldIdx * 3 + 1] - gridOrigin[1]) + 0.5f);
377 aIntVertices[i * 3 + 2] = (CTMint) floorf(scale * (self->mVertices[oldIdx * 3 + 2] - gridOrigin[2]) + 0.5f);
379 prevGridIndex = gridIdx;
380 prevDeltaX = deltaX;
381 }
382 }
384 //-----------------------------------------------------------------------------
385 // _ctmRestoreVertices() - Calculate inverse derivatives of the vertices.
386 //-----------------------------------------------------------------------------
387 static void _ctmRestoreVertices(_CTMcontext * self, CTMint * aIntVertices,
388 CTMuint * aGridIndices, _CTMgrid * aGrid, CTMfloat * aVertices)
389 {
390 CTMuint i, gridIdx, prevGridIndex;
391 CTMfloat gridOrigin[3], scale;
392 CTMint deltaX, prevDeltaX;
394 scale = self->mVertexPrecision;
396 prevGridIndex = 0x7fffffff;
397 prevDeltaX = 0;
398 for(i = 0; i < self->mVertexCount; ++ i)
399 {
400 // Get grid box origin
401 gridIdx = aGridIndices[i];
402 _ctmGridIdxToPoint(aGrid, gridIdx, gridOrigin);
404 // Restore original point
405 deltaX = aIntVertices[i * 3];
406 if(gridIdx == prevGridIndex)
407 deltaX += prevDeltaX;
408 aVertices[i * 3] = scale * deltaX + gridOrigin[0];
409 aVertices[i * 3 + 1] = scale * aIntVertices[i * 3 + 1] + gridOrigin[1];
410 aVertices[i * 3 + 2] = scale * aIntVertices[i * 3 + 2] + gridOrigin[2];
412 prevGridIndex = gridIdx;
413 prevDeltaX = deltaX;
414 }
415 }
417 //-----------------------------------------------------------------------------
418 // _ctmCalcSmoothNormals() - Calculate the smooth normals for a given mesh.
419 // These are used as the nominal normals for normal deltas & reconstruction.
420 //-----------------------------------------------------------------------------
421 static void _ctmCalcSmoothNormals(_CTMcontext * self, CTMfloat * aVertices,
422 CTMuint * aIndices, CTMfloat * aSmoothNormals)
423 {
424 CTMuint i, j, k, tri[3];
425 CTMfloat len;
426 CTMfloat v1[3], v2[3], n[3];
428 // Clear smooth normals array
429 for(i = 0; i < 3 * self->mVertexCount; ++ i)
430 aSmoothNormals[i] = 0.0f;
432 // Calculate sums of all neigbouring triangle normals for each vertex
433 for(i = 0; i < self->mTriangleCount; ++ i)
434 {
435 // Get triangle corner indices
436 for(j = 0; j < 3; ++ j)
437 tri[j] = aIndices[i * 3 + j];
439 // Calculate the normalized cross product of two triangle edges (i.e. the
440 // flat triangle normal)
441 for(j = 0; j < 3; ++ j)
442 {
443 v1[j] = aVertices[tri[1] * 3 + j] - aVertices[tri[0] * 3 + j];
444 v2[j] = aVertices[tri[2] * 3 + j] - aVertices[tri[0] * 3 + j];
445 }
446 n[0] = v1[1] * v2[2] - v1[2] * v2[1];
447 n[1] = v1[2] * v2[0] - v1[0] * v2[2];
448 n[2] = v1[0] * v2[1] - v1[1] * v2[0];
449 len = sqrtf(n[0] * n[0] + n[1] * n[1] + n[2] * n[2]);
450 if(len > 1e-10f)
451 len = 1.0f / len;
452 else
453 len = 1.0f;
454 for(j = 0; j < 3; ++ j)
455 n[j] *= len;
457 // Add the flat normal to all three triangle vertices
458 for(k = 0; k < 3; ++ k)
459 for(j = 0; j < 3; ++ j)
460 aSmoothNormals[tri[k] * 3 + j] += n[j];
461 }
463 // Normalize the normal sums, which gives the unit length smooth normals
464 for(i = 0; i < self->mVertexCount; ++ i)
465 {
466 len = sqrtf(aSmoothNormals[i * 3] * aSmoothNormals[i * 3] +
467 aSmoothNormals[i * 3 + 1] * aSmoothNormals[i * 3 + 1] +
468 aSmoothNormals[i * 3 + 2] * aSmoothNormals[i * 3 + 2]);
469 if(len > 1e-10f)
470 len = 1.0f / len;
471 else
472 len = 1.0f;
473 for(j = 0; j < 3; ++ j)
474 aSmoothNormals[i * 3 + j] *= len;
475 }
476 }
478 //-----------------------------------------------------------------------------
479 // _ctmMakeNormalCoordSys() - Create an ortho-normalized coordinate system
480 // where the Z-axis is aligned with the given normal.
481 // Note 1: This function is central to how the compressed normal data is
482 // interpreted, and it can not be changed (mathematically) without making the
483 // coder/decoder incompatible with other versions of the library!
484 // Note 2: Since we do this for every single normal, this routine needs to be
485 // fast. The current implementation uses: 12 MUL, 1 DIV, 1 SQRT, ~6 ADD.
486 //-----------------------------------------------------------------------------
487 static void _ctmMakeNormalCoordSys(CTMfloat * aNormal, CTMfloat * aBasisAxes)
488 {
489 CTMfloat len, * x, * y, * z;
490 CTMuint i;
492 // Pointers to the basis axes (aBasisAxes is a 3x3 matrix)
493 x = aBasisAxes;
494 y = &aBasisAxes[3];
495 z = &aBasisAxes[6];
497 // Z = normal (must be unit length!)
498 for(i = 0; i < 3; ++ i)
499 z[i] = aNormal[i];
501 // Calculate a vector that is guaranteed to be orthogonal to the normal, non-
502 // zero, and a continuous function of the normal (no discrete jumps):
503 // X = (0,0,1) x normal + (1,0,0) x normal
504 x[0] = -aNormal[1];
505 x[1] = aNormal[0] - aNormal[2];
506 x[2] = aNormal[1];
508 // Normalize the new X axis (note: |x[2]| = |x[0]|)
509 len = sqrtf(2.0 * x[0] * x[0] + x[1] * x[1]);
510 if(len > 1.0e-20f)
511 {
512 len = 1.0f / len;
513 x[0] *= len;
514 x[1] *= len;
515 x[2] *= len;
516 }
518 // Let Y = Z x X (no normalization needed, since |Z| = |X| = 1)
519 y[0] = z[1] * x[2] - z[2] * x[1];
520 y[1] = z[2] * x[0] - z[0] * x[2];
521 y[2] = z[0] * x[1] - z[1] * x[0];
522 }
524 //-----------------------------------------------------------------------------
525 // _ctmMakeNormalDeltas() - Convert the normals to a new coordinate system:
526 // magnitude, phi, theta (relative to predicted smooth normals).
527 //-----------------------------------------------------------------------------
528 static CTMint _ctmMakeNormalDeltas(_CTMcontext * self, CTMint * aIntNormals,
529 CTMfloat * aVertices, CTMuint * aIndices, _CTMsortvertex * aSortVertices)
530 {
531 CTMuint i, j, oldIdx, intPhi;
532 CTMfloat magn, phi, theta, scale, thetaScale;
533 CTMfloat * smoothNormals, n[3], n2[3], basisAxes[9];
535 // Allocate temporary memory for the nominal vertex normals
536 smoothNormals = (CTMfloat *) malloc(3 * sizeof(CTMfloat) * self->mVertexCount);
537 if(!smoothNormals)
538 {
539 self->mError = CTM_OUT_OF_MEMORY;
540 return CTM_FALSE;
541 }
543 // Calculate smooth normals (Note: aVertices and aIndices use the sorted
544 // index space, so smoothNormals will too)
545 _ctmCalcSmoothNormals(self, aVertices, aIndices, smoothNormals);
547 // Normal scaling factor
548 scale = 1.0f / self->mNormalPrecision;
550 for(i = 0; i < self->mVertexCount; ++ i)
551 {
552 // Get old normal index (before vertex sorting)
553 oldIdx = aSortVertices[i].mOriginalIndex;
555 // Calculate normal magnitude (should always be 1.0 for unit length normals)
556 magn = sqrtf(self->mNormals[oldIdx * 3] * self->mNormals[oldIdx * 3] +
557 self->mNormals[oldIdx * 3 + 1] * self->mNormals[oldIdx * 3 + 1] +
558 self->mNormals[oldIdx * 3 + 2] * self->mNormals[oldIdx * 3 + 2]);
559 if(magn < 1e-10f)
560 magn = 1.0f;
562 // Invert magnitude if the normal is negative compared to the predicted
563 // smooth normal
564 if((smoothNormals[i * 3] * self->mNormals[oldIdx * 3] +
565 smoothNormals[i * 3 + 1] * self->mNormals[oldIdx * 3 + 1] +
566 smoothNormals[i * 3 + 2] * self->mNormals[oldIdx * 3 + 2]) < 0.0f)
567 magn = -magn;
569 // Store the magnitude in the first element of the three normal elements
570 aIntNormals[i * 3] = (CTMint) floorf(scale * magn + 0.5f);
572 // Normalize the normal (1 / magn) - and flip it if magn < 0
573 magn = 1.0f / magn;
574 for(j = 0; j < 3; ++ j)
575 n[j] = self->mNormals[oldIdx * 3 + j] * magn;
577 // Convert the normal to angular representation (phi, theta) in a coordinate
578 // system where the nominal (smooth) normal is the Z-axis
579 _ctmMakeNormalCoordSys(&smoothNormals[i * 3], basisAxes);
580 for(j = 0; j < 3; ++ j)
581 n2[j] = basisAxes[j * 3] * n[0] +
582 basisAxes[j * 3 + 1] * n[1] +
583 basisAxes[j * 3 + 2] * n[2];
584 if(n2[2] >= 1.0f)
585 phi = 0.0f;
586 else
587 phi = acosf(n2[2]);
588 theta = atan2f(n2[1], n2[0]);
590 // Round phi and theta (spherical coordinates) to integers. Note: We let the
591 // theta resolution vary with the x/y circumference (roughly phi).
592 intPhi = (CTMint) floorf(phi * (scale / (0.5f * PI)) + 0.5f);
593 if(intPhi == 0)
594 thetaScale = 0.0f;
595 else if(intPhi <= 4)
596 thetaScale = 2.0f / PI;
597 else
598 thetaScale = ((CTMfloat) intPhi) / (2.0f * PI);
599 aIntNormals[i * 3 + 1] = intPhi;
600 aIntNormals[i * 3 + 2] = (CTMint) floorf((theta + PI) * thetaScale + 0.5f);
601 }
603 // Free temporary resources
604 free(smoothNormals);
606 return CTM_TRUE;
607 }
609 //-----------------------------------------------------------------------------
610 // _ctmRestoreNormals() - Convert the normals back to cartesian coordinates.
611 //-----------------------------------------------------------------------------
612 static CTMint _ctmRestoreNormals(_CTMcontext * self, CTMint * aIntNormals)
613 {
614 CTMuint i, j, intPhi;
615 CTMfloat magn, phi, theta, scale, thetaScale;
616 CTMfloat * smoothNormals, n[3], n2[3], basisAxes[9];
618 // Allocate temporary memory for the nominal vertex normals
619 smoothNormals = (CTMfloat *) malloc(3 * sizeof(CTMfloat) * self->mVertexCount);
620 if(!smoothNormals)
621 {
622 self->mError = CTM_OUT_OF_MEMORY;
623 return CTM_FALSE;
624 }
626 // Calculate smooth normals (nominal normals)
627 _ctmCalcSmoothNormals(self, self->mVertices, self->mIndices, smoothNormals);
629 // Normal scaling factor
630 scale = self->mNormalPrecision;
632 for(i = 0; i < self->mVertexCount; ++ i)
633 {
634 // Get the normal magnitude from the first of the three normal elements
635 magn = aIntNormals[i * 3] * scale;
637 // Get phi and theta (spherical coordinates, relative to the smooth normal).
638 intPhi = aIntNormals[i * 3 + 1];
639 phi = intPhi * (0.5f * PI) * scale;
640 if(intPhi == 0)
641 thetaScale = 0.0f;
642 else if(intPhi <= 4)
643 thetaScale = PI / 2.0f;
644 else
645 thetaScale = (2.0f * PI) / ((CTMfloat) intPhi);
646 theta = aIntNormals[i * 3 + 2] * thetaScale - PI;
648 // Convert the normal from the angular representation (phi, theta) back to
649 // cartesian coordinates
650 n2[0] = sinf(phi) * cosf(theta);
651 n2[1] = sinf(phi) * sinf(theta);
652 n2[2] = cosf(phi);
653 _ctmMakeNormalCoordSys(&smoothNormals[i * 3], basisAxes);
654 for(j = 0; j < 3; ++ j)
655 n[j] = basisAxes[j] * n2[0] +
656 basisAxes[3 + j] * n2[1] +
657 basisAxes[6 + j] * n2[2];
659 // Apply normal magnitude, and output to the normals array
660 for(j = 0; j < 3; ++ j)
661 self->mNormals[i * 3 + j] = n[j] * magn;
662 }
664 // Free temporary resources
665 free(smoothNormals);
667 return CTM_TRUE;
668 }
670 //-----------------------------------------------------------------------------
671 // _ctmMakeUVCoordDeltas() - Calculate various forms of derivatives in order
672 // to reduce data entropy.
673 //-----------------------------------------------------------------------------
674 static void _ctmMakeUVCoordDeltas(_CTMcontext * self, _CTMfloatmap * aMap,
675 CTMint * aIntUVCoords, _CTMsortvertex * aSortVertices)
676 {
677 CTMuint i, oldIdx;
678 CTMint u, v, prevU, prevV;
679 CTMfloat scale;
681 // UV coordinate scaling factor
682 scale = 1.0f / aMap->mPrecision;
684 prevU = prevV = 0;
685 for(i = 0; i < self->mVertexCount; ++ i)
686 {
687 // Get old UV coordinate index (before vertex sorting)
688 oldIdx = aSortVertices[i].mOriginalIndex;
690 // Convert to fixed point
691 u = (CTMint) floorf(scale * aMap->mValues[oldIdx * 2] + 0.5f);
692 v = (CTMint) floorf(scale * aMap->mValues[oldIdx * 2 + 1] + 0.5f);
694 // Calculate delta and store it in the converted array. NOTE: Here we rely
695 // on the fact that vertices are sorted, and usually close to each other,
696 // which means that UV coordinates should also be close to each other...
697 aIntUVCoords[i * 2] = u - prevU;
698 aIntUVCoords[i * 2 + 1] = v - prevV;
700 prevU = u;
701 prevV = v;
702 }
703 }
705 //-----------------------------------------------------------------------------
706 // _ctmRestoreUVCoords() - Calculate inverse derivatives of the UV
707 // coordinates.
708 //-----------------------------------------------------------------------------
709 static void _ctmRestoreUVCoords(_CTMcontext * self, _CTMfloatmap * aMap,
710 CTMint * aIntUVCoords)
711 {
712 CTMuint i;
713 CTMint u, v, prevU, prevV;
714 CTMfloat scale;
716 // UV coordinate scaling factor
717 scale = aMap->mPrecision;
719 prevU = prevV = 0;
720 for(i = 0; i < self->mVertexCount; ++ i)
721 {
722 // Calculate inverse delta
723 u = aIntUVCoords[i * 2] + prevU;
724 v = aIntUVCoords[i * 2 + 1] + prevV;
726 // Convert to floating point
727 aMap->mValues[i * 2] = (CTMfloat) u * scale;
728 aMap->mValues[i * 2 + 1] = (CTMfloat) v * scale;
730 prevU = u;
731 prevV = v;
732 }
733 }
735 //-----------------------------------------------------------------------------
736 // _ctmMakeAttribDeltas() - Calculate various forms of derivatives in order
737 // to reduce data entropy.
738 //-----------------------------------------------------------------------------
739 static void _ctmMakeAttribDeltas(_CTMcontext * self, _CTMfloatmap * aMap,
740 CTMint * aIntAttribs, _CTMsortvertex * aSortVertices)
741 {
742 CTMuint i, j, oldIdx;
743 CTMint value[4], prev[4];
744 CTMfloat scale;
746 // Attribute scaling factor
747 scale = 1.0f / aMap->mPrecision;
749 for(j = 0; j < 4; ++ j)
750 prev[j] = 0;
752 for(i = 0; i < self->mVertexCount; ++ i)
753 {
754 // Get old attribute index (before vertex sorting)
755 oldIdx = aSortVertices[i].mOriginalIndex;
757 // Convert to fixed point, and calculate delta and store it in the converted
758 // array. NOTE: Here we rely on the fact that vertices are sorted, and
759 // usually close to each other, which means that attributes should also
760 // be close to each other (and we assume that they somehow vary slowly with
761 // the geometry)...
762 for(j = 0; j < 4; ++ j)
763 {
764 value[j] = (CTMint) floorf(scale * aMap->mValues[oldIdx * 4 + j] + 0.5f);
765 aIntAttribs[i * 4 + j] = value[j] - prev[j];
766 prev[j] = value[j];
767 }
768 }
769 }
771 //-----------------------------------------------------------------------------
772 // _ctmRestoreAttribs() - Calculate inverse derivatives of the vertex
773 // attributes.
774 //-----------------------------------------------------------------------------
775 static void _ctmRestoreAttribs(_CTMcontext * self, _CTMfloatmap * aMap,
776 CTMint * aIntAttribs)
777 {
778 CTMuint i, j;
779 CTMint value[4], prev[4];
780 CTMfloat scale;
782 // Attribute scaling factor
783 scale = aMap->mPrecision;
785 for(j = 0; j < 4; ++ j)
786 prev[j] = 0;
788 for(i = 0; i < self->mVertexCount; ++ i)
789 {
790 // Calculate inverse delta, and convert to floating point
791 for(j = 0; j < 4; ++ j)
792 {
793 value[j] = aIntAttribs[i * 4 + j] + prev[j];
794 aMap->mValues[i * 4 + j] = (CTMfloat) value[j] * scale;
795 prev[j] = value[j];
796 }
797 }
798 }
800 //-----------------------------------------------------------------------------
801 // _ctmCompressMesh_MG2() - Compress the mesh that is stored in the CTM
802 // context, and write it the the output stream in the CTM context.
803 //-----------------------------------------------------------------------------
804 int _ctmCompressMesh_MG2(_CTMcontext * self)
805 {
806 _CTMgrid grid;
807 _CTMsortvertex * sortVertices;
808 _CTMfloatmap * map;
809 CTMuint * indices, * deltaIndices, * gridIndices;
810 CTMint * intVertices, * intNormals, * intUVCoords, * intAttribs;
811 CTMfloat * restoredVertices;
812 CTMuint i;
814 #ifdef __DEBUG_
815 printf("COMPRESSION METHOD: MG2\n");
816 #endif
818 // Setup 3D space subdivision grid
819 _ctmSetupGrid(self, &grid);
821 // Write MG2-specific header information to the stream
822 _ctmStreamWrite(self, (void *) "MG2H", 4);
823 _ctmStreamWriteFLOAT(self, self->mVertexPrecision);
824 _ctmStreamWriteFLOAT(self, self->mNormalPrecision);
825 _ctmStreamWriteFLOAT(self, grid.mMin[0]);
826 _ctmStreamWriteFLOAT(self, grid.mMin[1]);
827 _ctmStreamWriteFLOAT(self, grid.mMin[2]);
828 _ctmStreamWriteFLOAT(self, grid.mMax[0]);
829 _ctmStreamWriteFLOAT(self, grid.mMax[1]);
830 _ctmStreamWriteFLOAT(self, grid.mMax[2]);
831 _ctmStreamWriteUINT(self, grid.mDivision[0]);
832 _ctmStreamWriteUINT(self, grid.mDivision[1]);
833 _ctmStreamWriteUINT(self, grid.mDivision[2]);
835 // Prepare (sort) vertices
836 sortVertices = (_CTMsortvertex *) malloc(sizeof(_CTMsortvertex) * self->mVertexCount);
837 if(!sortVertices)
838 {
839 self->mError = CTM_OUT_OF_MEMORY;
840 return CTM_FALSE;
841 }
842 _ctmSortVertices(self, sortVertices, &grid);
844 // Convert vertices to integers and calculate vertex deltas (entropy-reduction)
845 intVertices = (CTMint *) malloc(sizeof(CTMint) * 3 * self->mVertexCount);
846 if(!intVertices)
847 {
848 self->mError = CTM_OUT_OF_MEMORY;
849 free((void *) sortVertices);
850 return CTM_FALSE;
851 }
852 _ctmMakeVertexDeltas(self, intVertices, sortVertices, &grid);
854 // Write vertices
855 #ifdef __DEBUG_
856 printf("Vertices: ");
857 #endif
858 _ctmStreamWrite(self, (void *) "VERT", 4);
859 if(!_ctmStreamWritePackedInts(self, intVertices, self->mVertexCount, 3, CTM_FALSE))
860 {
861 free((void *) intVertices);
862 free((void *) sortVertices);
863 return CTM_FALSE;
864 }
866 // Prepare grid indices (deltas)
867 gridIndices = (CTMuint *) malloc(sizeof(CTMuint) * self->mVertexCount);
868 if(!gridIndices)
869 {
870 self->mError = CTM_OUT_OF_MEMORY;
871 free((void *) intVertices);
872 free((void *) sortVertices);
873 return CTM_FALSE;
874 }
875 gridIndices[0] = sortVertices[0].mGridIndex;
876 for(i = 1; i < self->mVertexCount; ++ i)
877 gridIndices[i] = sortVertices[i].mGridIndex - sortVertices[i - 1].mGridIndex;
879 // Write grid indices
880 #ifdef __DEBUG_
881 printf("Grid indices: ");
882 #endif
883 _ctmStreamWrite(self, (void *) "GIDX", 4);
884 if(!_ctmStreamWritePackedInts(self, (CTMint *) gridIndices, self->mVertexCount, 1, CTM_FALSE))
885 {
886 free((void *) gridIndices);
887 free((void *) intVertices);
888 free((void *) sortVertices);
889 return CTM_FALSE;
890 }
892 // Calculate the result of the compressed -> decompressed vertices, in order
893 // to use the same vertex data for calculating nominal normals as the
894 // decompression routine (i.e. compensate for the vertex error when
895 // calculating the normals)
896 restoredVertices = (CTMfloat *) malloc(sizeof(CTMfloat) * 3 * self->mVertexCount);
897 if(!restoredVertices)
898 {
899 self->mError = CTM_OUT_OF_MEMORY;
900 free((void *) gridIndices);
901 free((void *) intVertices);
902 free((void *) sortVertices);
903 return CTM_FALSE;
904 }
905 for(i = 1; i < self->mVertexCount; ++ i)
906 gridIndices[i] += gridIndices[i - 1];
907 _ctmRestoreVertices(self, intVertices, gridIndices, &grid, restoredVertices);
909 // Free temporary resources
910 free((void *) gridIndices);
911 free((void *) intVertices);
913 // Perpare (sort) indices
914 indices = (CTMuint *) malloc(sizeof(CTMuint) * self->mTriangleCount * 3);
915 if(!indices)
916 {
917 self->mError = CTM_OUT_OF_MEMORY;
918 free((void *) restoredVertices);
919 free((void *) sortVertices);
920 return CTM_FALSE;
921 }
922 if(!_ctmReIndexIndices(self, sortVertices, indices))
923 {
924 free((void *) indices);
925 free((void *) restoredVertices);
926 free((void *) sortVertices);
927 return CTM_FALSE;
928 }
929 _ctmReArrangeTriangles(self, indices);
931 // Calculate index deltas (entropy-reduction)
932 deltaIndices = (CTMuint *) malloc(sizeof(CTMuint) * self->mTriangleCount * 3);
933 if(!indices)
934 {
935 self->mError = CTM_OUT_OF_MEMORY;
936 free((void *) indices);
937 free((void *) restoredVertices);
938 free((void *) sortVertices);
939 return CTM_FALSE;
940 }
941 for(i = 0; i < self->mTriangleCount * 3; ++ i)
942 deltaIndices[i] = indices[i];
943 _ctmMakeIndexDeltas(self, deltaIndices);
945 // Write triangle indices
946 #ifdef __DEBUG_
947 printf("Indices: ");
948 #endif
949 _ctmStreamWrite(self, (void *) "INDX", 4);
950 if(!_ctmStreamWritePackedInts(self, (CTMint *) deltaIndices, self->mTriangleCount, 3, CTM_FALSE))
951 {
952 free((void *) deltaIndices);
953 free((void *) indices);
954 free((void *) restoredVertices);
955 free((void *) sortVertices);
956 return CTM_FALSE;
957 }
959 // Free temporary data for the indices
960 free((void *) deltaIndices);
962 if(self->mNormals)
963 {
964 // Convert normals to integers and calculate deltas (entropy-reduction)
965 intNormals = (CTMint *) malloc(sizeof(CTMint) * 3 * self->mVertexCount);
966 if(!intNormals)
967 {
968 self->mError = CTM_OUT_OF_MEMORY;
969 free((void *) indices);
970 free((void *) restoredVertices);
971 free((void *) sortVertices);
972 return CTM_FALSE;
973 }
974 if(!_ctmMakeNormalDeltas(self, intNormals, restoredVertices, indices, sortVertices))
975 {
976 free((void *) indices);
977 free((void *) intNormals);
978 free((void *) restoredVertices);
979 free((void *) sortVertices);
980 return CTM_FALSE;
981 }
983 // Write normals
984 #ifdef __DEBUG_
985 printf("Normals: ");
986 #endif
987 _ctmStreamWrite(self, (void *) "NORM", 4);
988 if(!_ctmStreamWritePackedInts(self, intNormals, self->mVertexCount, 3, CTM_FALSE))
989 {
990 free((void *) indices);
991 free((void *) intNormals);
992 free((void *) restoredVertices);
993 free((void *) sortVertices);
994 return CTM_FALSE;
995 }
997 // Free temporary normal data
998 free((void *) intNormals);
999 }
1001 // Free restored indices and vertices
1002 free((void *) indices);
1003 free((void *) restoredVertices);
1005 // Write UV maps
1006 map = self->mUVMaps;
1007 while(map)
1009 // Convert UV coordinates to integers and calculate deltas (entropy-reduction)
1010 intUVCoords = (CTMint *) malloc(sizeof(CTMint) * 2 * self->mVertexCount);
1011 if(!intUVCoords)
1013 self->mError = CTM_OUT_OF_MEMORY;
1014 free((void *) sortVertices);
1015 return CTM_FALSE;
1017 _ctmMakeUVCoordDeltas(self, map, intUVCoords, sortVertices);
1019 // Write UV coordinates
1020 #ifdef __DEBUG_
1021 printf("Texture coordinates (%s): ", map->mName ? map->mName : "no name");
1022 #endif
1023 _ctmStreamWrite(self, (void *) "TEXC", 4);
1024 _ctmStreamWriteSTRING(self, map->mName);
1025 _ctmStreamWriteSTRING(self, map->mFileName);
1026 _ctmStreamWriteFLOAT(self, map->mPrecision);
1027 if(!_ctmStreamWritePackedInts(self, intUVCoords, self->mVertexCount, 2, CTM_TRUE))
1029 free((void *) intUVCoords);
1030 free((void *) sortVertices);
1031 return CTM_FALSE;
1034 // Free temporary UV coordinate data
1035 free((void *) intUVCoords);
1037 map = map->mNext;
1040 // Write vertex attribute maps
1041 map = self->mAttribMaps;
1042 while(map)
1044 // Convert vertex attributes to integers and calculate deltas (entropy-reduction)
1045 intAttribs = (CTMint *) malloc(sizeof(CTMint) * 4 * self->mVertexCount);
1046 if(!intAttribs)
1048 self->mError = CTM_OUT_OF_MEMORY;
1049 free((void *) sortVertices);
1050 return CTM_FALSE;
1052 _ctmMakeAttribDeltas(self, map, intAttribs, sortVertices);
1054 // Write vertex attributes
1055 #ifdef __DEBUG_
1056 printf("Vertex attributes (%s): ", map->mName ? map->mName : "no name");
1057 #endif
1058 _ctmStreamWrite(self, (void *) "ATTR", 4);
1059 _ctmStreamWriteSTRING(self, map->mName);
1060 _ctmStreamWriteFLOAT(self, map->mPrecision);
1061 if(!_ctmStreamWritePackedInts(self, intAttribs, self->mVertexCount, 4, CTM_TRUE))
1063 free((void *) intAttribs);
1064 free((void *) sortVertices);
1065 return CTM_FALSE;
1068 // Free temporary vertex attribute data
1069 free((void *) intAttribs);
1071 map = map->mNext;
1074 // Free temporary data
1075 free((void *) sortVertices);
1077 return CTM_TRUE;
1080 //-----------------------------------------------------------------------------
1081 // _ctmUncompressMesh_MG2() - Uncmpress the mesh from the input stream in the
1082 // CTM context, and store the resulting mesh in the CTM context.
1083 //-----------------------------------------------------------------------------
1084 int _ctmUncompressMesh_MG2(_CTMcontext * self)
1086 CTMuint * gridIndices, i;
1087 CTMint * intVertices, * intNormals, * intUVCoords, * intAttribs;
1088 _CTMfloatmap * map;
1089 _CTMgrid grid;
1091 // Read MG2-specific header information from the stream
1092 if(_ctmStreamReadUINT(self) != FOURCC("MG2H"))
1094 self->mError = CTM_BAD_FORMAT;
1095 return CTM_FALSE;
1097 self->mVertexPrecision = _ctmStreamReadFLOAT(self);
1098 if(self->mVertexPrecision <= 0.0f)
1100 self->mError = CTM_BAD_FORMAT;
1101 return CTM_FALSE;
1103 self->mNormalPrecision = _ctmStreamReadFLOAT(self);
1104 if(self->mNormalPrecision <= 0.0f)
1106 self->mError = CTM_BAD_FORMAT;
1107 return CTM_FALSE;
1109 grid.mMin[0] = _ctmStreamReadFLOAT(self);
1110 grid.mMin[1] = _ctmStreamReadFLOAT(self);
1111 grid.mMin[2] = _ctmStreamReadFLOAT(self);
1112 grid.mMax[0] = _ctmStreamReadFLOAT(self);
1113 grid.mMax[1] = _ctmStreamReadFLOAT(self);
1114 grid.mMax[2] = _ctmStreamReadFLOAT(self);
1115 if((grid.mMax[0] < grid.mMin[0]) ||
1116 (grid.mMax[1] < grid.mMin[1]) ||
1117 (grid.mMax[2] < grid.mMin[2]))
1119 self->mError = CTM_BAD_FORMAT;
1120 return CTM_FALSE;
1122 grid.mDivision[0] = _ctmStreamReadUINT(self);
1123 grid.mDivision[1] = _ctmStreamReadUINT(self);
1124 grid.mDivision[2] = _ctmStreamReadUINT(self);
1125 if((grid.mDivision[0] < 1) || (grid.mDivision[1] < 1) || (grid.mDivision[2] < 1))
1127 self->mError = CTM_BAD_FORMAT;
1128 return CTM_FALSE;
1131 // Initialize 3D space subdivision grid
1132 for(i = 0; i < 3; ++ i)
1133 grid.mSize[i] = (grid.mMax[i] - grid.mMin[i]) / grid.mDivision[i];
1135 // Read vertices
1136 if(_ctmStreamReadUINT(self) != FOURCC("VERT"))
1138 self->mError = CTM_BAD_FORMAT;
1139 return CTM_FALSE;
1141 intVertices = (CTMint *) malloc(sizeof(CTMint) * self->mVertexCount * 3);
1142 if(!intVertices)
1144 self->mError = CTM_OUT_OF_MEMORY;
1145 return CTM_FALSE;
1147 if(!_ctmStreamReadPackedInts(self, intVertices, self->mVertexCount, 3, CTM_FALSE))
1149 free((void *) intVertices);
1150 return CTM_FALSE;
1153 // Read grid indices
1154 if(_ctmStreamReadUINT(self) != FOURCC("GIDX"))
1156 free((void *) intVertices);
1157 self->mError = CTM_BAD_FORMAT;
1158 return CTM_FALSE;
1160 gridIndices = (CTMuint *) malloc(sizeof(CTMuint) * self->mVertexCount);
1161 if(!gridIndices)
1163 self->mError = CTM_OUT_OF_MEMORY;
1164 free((void *) intVertices);
1165 return CTM_FALSE;
1167 if(!_ctmStreamReadPackedInts(self, (CTMint *) gridIndices, self->mVertexCount, 1, CTM_FALSE))
1169 free((void *) gridIndices);
1170 free((void *) intVertices);
1171 return CTM_FALSE;
1174 // Restore grid indices (deltas)
1175 for(i = 1; i < self->mVertexCount; ++ i)
1176 gridIndices[i] += gridIndices[i - 1];
1178 // Restore vertices
1179 _ctmRestoreVertices(self, intVertices, gridIndices, &grid, self->mVertices);
1181 // Free temporary resources
1182 free((void *) gridIndices);
1183 free((void *) intVertices);
1185 // Read triangle indices
1186 if(_ctmStreamReadUINT(self) != FOURCC("INDX"))
1188 self->mError = CTM_BAD_FORMAT;
1189 return CTM_FALSE;
1191 if(!_ctmStreamReadPackedInts(self, (CTMint *) self->mIndices, self->mTriangleCount, 3, CTM_FALSE))
1192 return CTM_FALSE;
1194 // Restore indices
1195 _ctmRestoreIndices(self, self->mIndices);
1197 // Check that all indices are within range
1198 for(i = 0; i < (self->mTriangleCount * 3); ++ i)
1200 if(self->mIndices[i] >= self->mVertexCount)
1202 self->mError = CTM_INVALID_MESH;
1203 return CTM_FALSE;
1207 // Read normals
1208 if(self->mNormals)
1210 intNormals = (CTMint *) malloc(sizeof(CTMint) * self->mVertexCount * 3);
1211 if(!intNormals)
1213 self->mError = CTM_OUT_OF_MEMORY;
1214 return CTM_FALSE;
1216 if(_ctmStreamReadUINT(self) != FOURCC("NORM"))
1218 self->mError = CTM_BAD_FORMAT;
1219 free((void *) intNormals);
1220 return CTM_FALSE;
1222 if(!_ctmStreamReadPackedInts(self, intNormals, self->mVertexCount, 3, CTM_FALSE))
1224 free((void *) intNormals);
1225 return CTM_FALSE;
1228 // Restore normals
1229 if(!_ctmRestoreNormals(self, intNormals))
1231 free((void *) intNormals);
1232 return CTM_FALSE;
1235 // Free temporary normals data
1236 free((void *) intNormals);
1239 // Read UV maps
1240 map = self->mUVMaps;
1241 while(map)
1243 intUVCoords = (CTMint *) malloc(sizeof(CTMint) * self->mVertexCount * 2);
1244 if(!intUVCoords)
1246 self->mError = CTM_OUT_OF_MEMORY;
1247 return CTM_FALSE;
1249 if(_ctmStreamReadUINT(self) != FOURCC("TEXC"))
1251 self->mError = CTM_BAD_FORMAT;
1252 free((void *) intUVCoords);
1253 return CTM_FALSE;
1255 _ctmStreamReadSTRING(self, &map->mName);
1256 _ctmStreamReadSTRING(self, &map->mFileName);
1257 map->mPrecision = _ctmStreamReadFLOAT(self);
1258 if(map->mPrecision <= 0.0f)
1260 self->mError = CTM_BAD_FORMAT;
1261 free((void *) intUVCoords);
1262 return CTM_FALSE;
1264 if(!_ctmStreamReadPackedInts(self, intUVCoords, self->mVertexCount, 2, CTM_TRUE))
1266 free((void *) intUVCoords);
1267 return CTM_FALSE;
1270 // Restore UV coordinates
1271 _ctmRestoreUVCoords(self, map, intUVCoords);
1273 // Free temporary UV coordinate data
1274 free((void *) intUVCoords);
1276 map = map->mNext;
1279 // Read vertex attribute maps
1280 map = self->mAttribMaps;
1281 while(map)
1283 intAttribs = (CTMint *) malloc(sizeof(CTMint) * self->mVertexCount * 4);
1284 if(!intAttribs)
1286 self->mError = CTM_OUT_OF_MEMORY;
1287 return CTM_FALSE;
1289 if(_ctmStreamReadUINT(self) != FOURCC("ATTR"))
1291 self->mError = CTM_BAD_FORMAT;
1292 free((void *) intAttribs);
1293 return CTM_FALSE;
1295 _ctmStreamReadSTRING(self, &map->mName);
1296 map->mPrecision = _ctmStreamReadFLOAT(self);
1297 if(map->mPrecision <= 0.0f)
1299 self->mError = CTM_BAD_FORMAT;
1300 free((void *) intAttribs);
1301 return CTM_FALSE;
1303 if(!_ctmStreamReadPackedInts(self, intAttribs, self->mVertexCount, 4, CTM_TRUE))
1305 free((void *) intAttribs);
1306 return CTM_FALSE;
1309 // Restore vertex attributes
1310 _ctmRestoreAttribs(self, map, intAttribs);
1312 // Free temporary vertex attribute data
1313 free((void *) intAttribs);
1315 map = map->mNext;
1318 return CTM_TRUE;