goat3d
view libs/openctm/compressMG1.c @ 88:7941e89798e5
selections
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 15 May 2014 06:52:01 +0300 |
parents | |
children |
line source
1 //-----------------------------------------------------------------------------
2 // Product: OpenCTM
3 // File: compressMG1.c
4 // Description: Implementation of the MG1 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
38 //-----------------------------------------------------------------------------
39 // _compareTriangle() - Comparator for the triangle sorting.
40 //-----------------------------------------------------------------------------
41 static int _compareTriangle(const void * elem1, const void * elem2)
42 {
43 CTMuint * tri1 = (CTMuint *) elem1;
44 CTMuint * tri2 = (CTMuint *) elem2;
45 if(tri1[0] != tri2[0])
46 return tri1[0] - tri2[0];
47 else
48 return tri1[1] - tri2[1];
49 }
51 //-----------------------------------------------------------------------------
52 // _ctmReArrangeTriangles() - Re-arrange all triangles for optimal
53 // compression.
54 //-----------------------------------------------------------------------------
55 static void _ctmReArrangeTriangles(_CTMcontext * self, CTMuint * aIndices)
56 {
57 CTMuint * tri, tmp, i;
59 // Step 1: Make sure that the first index of each triangle is the smallest
60 // one (rotate triangle nodes if necessary)
61 for(i = 0; i < self->mTriangleCount; ++ i)
62 {
63 tri = &aIndices[i * 3];
64 if((tri[1] < tri[0]) && (tri[1] < tri[2]))
65 {
66 tmp = tri[0];
67 tri[0] = tri[1];
68 tri[1] = tri[2];
69 tri[2] = tmp;
70 }
71 else if((tri[2] < tri[0]) && (tri[2] < tri[1]))
72 {
73 tmp = tri[0];
74 tri[0] = tri[2];
75 tri[2] = tri[1];
76 tri[1] = tmp;
77 }
78 }
80 // Step 2: Sort the triangles based on the first triangle index
81 qsort((void *) aIndices, self->mTriangleCount, sizeof(CTMuint) * 3, _compareTriangle);
82 }
84 //-----------------------------------------------------------------------------
85 // _ctmMakeIndexDeltas() - Calculate various forms of derivatives in order to
86 // reduce data entropy.
87 //-----------------------------------------------------------------------------
88 static void _ctmMakeIndexDeltas(_CTMcontext * self, CTMuint * aIndices)
89 {
90 CTMint i;
91 for(i = self->mTriangleCount - 1; i >= 0; -- i)
92 {
93 // Step 1: Calculate delta from second triangle index to the previous
94 // second triangle index, if the previous triangle shares the same first
95 // index, otherwise calculate the delta to the first triangle index
96 if((i >= 1) && (aIndices[i * 3] == aIndices[(i - 1) * 3]))
97 aIndices[i * 3 + 1] -= aIndices[(i - 1) * 3 + 1];
98 else
99 aIndices[i * 3 + 1] -= aIndices[i * 3];
101 // Step 2: Calculate delta from third triangle index to the first triangle
102 // index
103 aIndices[i * 3 + 2] -= aIndices[i * 3];
105 // Step 3: Calculate derivative of the first triangle index
106 if(i >= 1)
107 aIndices[i * 3] -= aIndices[(i - 1) * 3];
108 }
109 }
111 //-----------------------------------------------------------------------------
112 // _ctmRestoreIndices() - Restore original indices (inverse derivative
113 // operation).
114 //-----------------------------------------------------------------------------
115 static void _ctmRestoreIndices(_CTMcontext * self, CTMuint * aIndices)
116 {
117 CTMuint i;
119 for(i = 0; i < self->mTriangleCount; ++ i)
120 {
121 // Step 1: Reverse derivative of the first triangle index
122 if(i >= 1)
123 aIndices[i * 3] += aIndices[(i - 1) * 3];
125 // Step 2: Reverse delta from third triangle index to the first triangle
126 // index
127 aIndices[i * 3 + 2] += aIndices[i * 3];
129 // Step 3: Reverse delta from second triangle index to the previous
130 // second triangle index, if the previous triangle shares the same first
131 // index, otherwise reverse the delta to the first triangle index
132 if((i >= 1) && (aIndices[i * 3] == aIndices[(i - 1) * 3]))
133 aIndices[i * 3 + 1] += aIndices[(i - 1) * 3 + 1];
134 else
135 aIndices[i * 3 + 1] += aIndices[i * 3];
136 }
137 }
139 //-----------------------------------------------------------------------------
140 // _ctmCompressMesh_MG1() - Compress the mesh that is stored in the CTM
141 // context, and write it the the output stream in the CTM context.
142 //-----------------------------------------------------------------------------
143 int _ctmCompressMesh_MG1(_CTMcontext * self)
144 {
145 CTMuint * indices;
146 _CTMfloatmap * map;
147 CTMuint i;
149 #ifdef __DEBUG_
150 printf("COMPRESSION METHOD: MG1\n");
151 #endif
153 // Perpare (sort) indices
154 indices = (CTMuint *) malloc(sizeof(CTMuint) * self->mTriangleCount * 3);
155 if(!indices)
156 {
157 self->mError = CTM_OUT_OF_MEMORY;
158 return CTM_FALSE;
159 }
160 for(i = 0; i < self->mTriangleCount * 3; ++ i)
161 indices[i] = self->mIndices[i];
162 _ctmReArrangeTriangles(self, indices);
164 // Calculate index deltas (entropy-reduction)
165 _ctmMakeIndexDeltas(self, indices);
167 // Write triangle indices
168 #ifdef __DEBUG_
169 printf("Inidices: ");
170 #endif
171 _ctmStreamWrite(self, (void *) "INDX", 4);
172 if(!_ctmStreamWritePackedInts(self, (CTMint *) indices, self->mTriangleCount, 3, CTM_FALSE))
173 {
174 free((void *) indices);
175 return CTM_FALSE;
176 }
178 // Free temporary resources
179 free((void *) indices);
181 // Write vertices
182 #ifdef __DEBUG_
183 printf("Vertices: ");
184 #endif
185 _ctmStreamWrite(self, (void *) "VERT", 4);
186 if(!_ctmStreamWritePackedFloats(self, self->mVertices, self->mVertexCount * 3, 1))
187 {
188 free((void *) indices);
189 return CTM_FALSE;
190 }
192 // Write normals
193 if(self->mNormals)
194 {
195 #ifdef __DEBUG_
196 printf("Normals: ");
197 #endif
198 _ctmStreamWrite(self, (void *) "NORM", 4);
199 if(!_ctmStreamWritePackedFloats(self, self->mNormals, self->mVertexCount, 3))
200 return CTM_FALSE;
201 }
203 // Write UV maps
204 map = self->mUVMaps;
205 while(map)
206 {
207 #ifdef __DEBUG_
208 printf("UV coordinates (%s): ", map->mName ? map->mName : "no name");
209 #endif
210 _ctmStreamWrite(self, (void *) "TEXC", 4);
211 _ctmStreamWriteSTRING(self, map->mName);
212 _ctmStreamWriteSTRING(self, map->mFileName);
213 if(!_ctmStreamWritePackedFloats(self, map->mValues, self->mVertexCount, 2))
214 return CTM_FALSE;
215 map = map->mNext;
216 }
218 // Write attribute maps
219 map = self->mAttribMaps;
220 while(map)
221 {
222 #ifdef __DEBUG_
223 printf("Vertex attributes (%s): ", map->mName ? map->mName : "no name");
224 #endif
225 _ctmStreamWrite(self, (void *) "ATTR", 4);
226 _ctmStreamWriteSTRING(self, map->mName);
227 if(!_ctmStreamWritePackedFloats(self, map->mValues, self->mVertexCount, 4))
228 return CTM_FALSE;
229 map = map->mNext;
230 }
232 return CTM_TRUE;
233 }
235 //-----------------------------------------------------------------------------
236 // _ctmUncompressMesh_MG1() - Uncmpress the mesh from the input stream in the
237 // CTM context, and store the resulting mesh in the CTM context.
238 //-----------------------------------------------------------------------------
239 int _ctmUncompressMesh_MG1(_CTMcontext * self)
240 {
241 CTMuint * indices;
242 _CTMfloatmap * map;
243 CTMuint i;
245 // Allocate memory for the indices
246 indices = (CTMuint *) malloc(sizeof(CTMuint) * self->mTriangleCount * 3);
247 if(!indices)
248 {
249 self->mError = CTM_OUT_OF_MEMORY;
250 return CTM_FALSE;
251 }
253 // Read triangle indices
254 if(_ctmStreamReadUINT(self) != FOURCC("INDX"))
255 {
256 self->mError = CTM_BAD_FORMAT;
257 free(indices);
258 return CTM_FALSE;
259 }
260 if(!_ctmStreamReadPackedInts(self, (CTMint *) indices, self->mTriangleCount, 3, CTM_FALSE))
261 return CTM_FALSE;
263 // Restore indices
264 _ctmRestoreIndices(self, indices);
265 for(i = 0; i < self->mTriangleCount * 3; ++ i)
266 self->mIndices[i] = indices[i];
268 // Free temporary resources
269 free(indices);
271 // Read vertices
272 if(_ctmStreamReadUINT(self) != FOURCC("VERT"))
273 {
274 self->mError = CTM_BAD_FORMAT;
275 return CTM_FALSE;
276 }
277 if(!_ctmStreamReadPackedFloats(self, self->mVertices, self->mVertexCount * 3, 1))
278 return CTM_FALSE;
280 // Read normals
281 if(self->mNormals)
282 {
283 if(_ctmStreamReadUINT(self) != FOURCC("NORM"))
284 {
285 self->mError = CTM_BAD_FORMAT;
286 return CTM_FALSE;
287 }
288 if(!_ctmStreamReadPackedFloats(self, self->mNormals, self->mVertexCount, 3))
289 return CTM_FALSE;
290 }
292 // Read UV maps
293 map = self->mUVMaps;
294 while(map)
295 {
296 if(_ctmStreamReadUINT(self) != FOURCC("TEXC"))
297 {
298 self->mError = CTM_BAD_FORMAT;
299 return 0;
300 }
301 _ctmStreamReadSTRING(self, &map->mName);
302 _ctmStreamReadSTRING(self, &map->mFileName);
303 if(!_ctmStreamReadPackedFloats(self, map->mValues, self->mVertexCount, 2))
304 return CTM_FALSE;
305 map = map->mNext;
306 }
308 // Read vertex attribute maps
309 map = self->mAttribMaps;
310 while(map)
311 {
312 if(_ctmStreamReadUINT(self) != FOURCC("ATTR"))
313 {
314 self->mError = CTM_BAD_FORMAT;
315 return 0;
316 }
317 _ctmStreamReadSTRING(self, &map->mName);
318 if(!_ctmStreamReadPackedFloats(self, map->mValues, self->mVertexCount, 4))
319 return CTM_FALSE;
320 map = map->mNext;
321 }
323 return CTM_TRUE;
324 }