blob: 1aba4f158602c4877af122c1fad12d51d7feffd3 [file] [log] [blame]
Alex Sakhartchouk17bd28b2011-02-11 17:51:44 -08001/*
2* Copyright 2006 Sony Computer Entertainment Inc.
3*
4* Licensed under the MIT Open Source License, for details please see license.txt or the website
5* http://www.opensource.org/licenses/mit-license.php
6*
7*/
8
9#include "ColladaGeometry.h"
10#include <iostream>
11#include <sstream>
12
13ColladaGeometry::ColladaGeometry() :
14 mPositionFloats(NULL), mPositionOffset(-1),
15 mNormalFloats(NULL), mNormalOffset(-1),
16 mTangentFloats(NULL), mTangentOffset(-1),
17 mBinormalFloats(NULL), mBinormalOffset(-1),
18 mTexture1Floats(NULL), mTexture1Offset(-1),
19 mMultiIndexOffset(-1),
20 mPositionsStride(3), mNormalsStride(3),
21 mTextureCoordsStride(2), mTangentssStride(3), mBinormalsStride(3) {
22
23 mConvertedMesh.appendChannel("position", mPositionsStride);
24 mConvertedMesh.appendChannel("normal", mNormalsStride);
25 mConvertedMesh.appendChannel("texture0", mTextureCoordsStride);
26 mConvertedMesh.appendChannel("binormal", mBinormalsStride);
27 mConvertedMesh.appendChannel("tangent", mTangentssStride);
28
29 mPositions = &mConvertedMesh.mChannels[0].mData;
30 mNormals = &mConvertedMesh.mChannels[1].mData;
31 mTextureCoords = &mConvertedMesh.mChannels[2].mData;
32 mBinormals = &mConvertedMesh.mChannels[3].mData;
33 mTangents = &mConvertedMesh.mChannels[4].mData;
34}
35
36bool ColladaGeometry::init(domGeometryRef geometry) {
37
38 bool convertSuceeded = true;
39
40 const char* geoName = geometry->getName();
41 if (geoName == NULL) {
42 geoName = geometry->getId();
43 }
44 mConvertedMesh.mName = geoName;
45 mMesh = geometry->getMesh();
46
47 // Iterate over all the index groups and build up a simple resolved tri list and vertex array
48 const domTriangles_Array &allTriLists = mMesh->getTriangles_array();
49 int numTriLists = allTriLists.getCount();
50 mConvertedMesh.mTriangleLists.reserve(numTriLists);
51 mConvertedMesh.mTriangleListNames.reserve(numTriLists);
52 for (int i = 0; i < numTriLists; i ++) {
53 addTriangles(allTriLists[i]);
54 }
55
56 return convertSuceeded;
57}
58
59void ColladaGeometry::addTriangles(domTriangles * colladaTriangles) {
60
61 int numTriangles = colladaTriangles->getCount();
62 int triListIndex = mConvertedMesh.mTriangleLists.size();
63 mConvertedMesh.mTriangleLists.resize(triListIndex + 1);
64 std::string materialName = colladaTriangles->getMaterial();
65 if (materialName.size() == 0) {
66 char buffer[128];
67 sprintf(buffer, "index%d", triListIndex);
68 materialName = buffer;
69 }
70 mConvertedMesh.mTriangleListNames.push_back(materialName);
71
72 // It's a good idea to tell stl how much memory we intend to use
73 // to limit the number of reallocations
74 mPositions->reserve(numTriangles * 3);
75 mNormals->reserve(numTriangles * 3);
76 mTangents->reserve(numTriangles * 3);
77 mBinormals->reserve(numTriangles * 3);
78 mTextureCoords->reserve(numTriangles * 3);
79
80 // Stores the pointers to the image data and where in the tri list that data comes from
81 cacheOffsetsAndDataPointers(colladaTriangles);
82
83 // Collapse the multiindex that collada uses
84 const domListOfUInts &colladaIndexList = colladaTriangles->getP()->getValue();
85 std::vector<uint32_t> &a3dIndexList = mConvertedMesh.mTriangleLists[triListIndex];
86 a3dIndexList.resize(numTriangles * 3);
87 for (int i = 0; i < numTriangles * 3; i ++) {
88
89 a3dIndexList[i] = remapIndexAndStoreData(colladaIndexList, i);
90 }
91
92}
93
94void ColladaGeometry::cacheOffsetsAndDataPointers(domTriangles * colladaTriangles) {
95 // Define the names of known vertex channels
96 const char *positionSemantic = "POSITION";
97 const char *vertexSemantic = "VERTEX";
98 const char *normalSemantic = "NORMAL";
99 const char *tangentSemantic = "TANGENT";
100 const char *binormalSemantic = "BINORMAL";
101 const char *texture1Semantic = "TEXCOORD";
102
103 const domInputLocalOffset_Array &inputs = colladaTriangles->getInput_array();
104 mMultiIndexOffset = inputs.getCount();
105
106 // inputs with offsets
107 // There are two places collada can put links to our data
108 // 1 - in the VERTEX, which is its way of saying follow a link to the vertex structure
109 // then every geometry array you find there is the same size as the position array
110 // 2 - a direct link to the channel from the primitive list. This tells us that there are
111 // potentially more or less floats in those channels because there is some vertex re-use
112 // or divergence in that data channel. For example, highly segmented uv set would produce a
113 // larger array because for every physical vertex position thre might be 2 or more uv coords
114 for (uint32_t i = 0; i < inputs.getCount(); i ++) {
115
116 int currentOffset = inputs[i]->getOffset();
117 const char *currentSemantic = inputs[i]->getSemantic();
118
119 domSource * source = (domSource*) (domElement*) inputs[i]->getSource().getElement();
120 if (strcmp(vertexSemantic, currentSemantic) == 0) {
121 mPositionOffset = currentOffset;
122 }
123 else if (strcmp(normalSemantic, currentSemantic) == 0) {
124 mNormalOffset = currentOffset;
125 mNormalFloats = &source->getFloat_array()->getValue();
126 }
127 else if (strcmp(tangentSemantic, currentSemantic) == 0) {
128 mTangentOffset = currentOffset;
129 mTangentFloats = &source->getFloat_array()->getValue();
130 }
131 else if (strcmp(binormalSemantic, currentSemantic) == 0) {
132 mBinormalOffset = currentOffset;
133 mBinormalFloats = &source->getFloat_array()->getValue();
134 }
135 else if (strcmp(texture1Semantic, currentSemantic) == 0) {
136 mTexture1Offset = currentOffset;
137 mTexture1Floats = & source->getFloat_array()->getValue();
138 }
139 }
140
141 // There are multiple ways of getting to data, so follow them all
142 domVertices * vertices = mMesh->getVertices();
143 const domInputLocal_Array &verticesInputs = vertices->getInput_array();
144 for (uint32_t i = 0; i < verticesInputs.getCount(); i ++) {
145
146 const char *currentSemantic = verticesInputs[i]->getSemantic();
147
148 domSource * source = (domSource*) (domElement*) verticesInputs[i]->getSource().getElement();
149 if (strcmp(positionSemantic, currentSemantic) == 0) {
150 mPositionFloats = & source->getFloat_array()->getValue();
151 // TODO: Querry this from the accessor in the future because
152 // I supopose it's possible to have 4 floats if we hide something in w
153 int numberOfFloatsPerPoint = 3;
154 // We want to cllapse duplicate vertices, otherwise we could just unroll the tri list
155 mVertexRemap.resize(source->getFloat_array()->getCount()/numberOfFloatsPerPoint);
156 }
157 else if (strcmp(normalSemantic, currentSemantic) == 0) {
158 mNormalFloats = & source->getFloat_array()->getValue();
159 mNormalOffset = mPositionOffset;
160 }
161 else if (strcmp(tangentSemantic, currentSemantic) == 0) {
162 mTangentFloats = & source->getFloat_array()->getValue();
163 mTangentOffset = mPositionOffset;
164 }
165 else if (strcmp(binormalSemantic, currentSemantic) == 0) {
166 mBinormalFloats = & source->getFloat_array()->getValue();
167 mBinormalOffset = mPositionOffset;
168 }
169 else if (strcmp(texture1Semantic, currentSemantic) == 0) {
170 mTexture1Floats = & source->getFloat_array()->getValue();
171 mTexture1Offset = mPositionOffset;
172 }
173 }
174}
175
176int ColladaGeometry::remapIndexAndStoreData(const domListOfUInts &colladaIndexList, int indexToRemap) {
177
178 domUint positionIndex = colladaIndexList[indexToRemap*mMultiIndexOffset + mPositionOffset];
179
180 float posX = (*mPositionFloats)[positionIndex * mPositionsStride + 0];
181 float posY = (*mPositionFloats)[positionIndex * mPositionsStride + 1];
182 float posZ = (*mPositionFloats)[positionIndex * mPositionsStride + 2];
183
184 float normX = 0;
185 float normY = 0;
186 float normZ = 0;
187
188 if (mNormalOffset != -1) {
189 domUint normalIndex = colladaIndexList[indexToRemap*mMultiIndexOffset + mNormalOffset];
190 normX = (*mNormalFloats)[normalIndex * mNormalsStride + 0];
191 normY = (*mNormalFloats)[normalIndex * mNormalsStride + 1];
192 normZ = (*mNormalFloats)[normalIndex * mNormalsStride + 2];
193 }
194
195 float tanX = 0;
196 float tanY = 0;
197 float tanZ = 0;
198
199 if (mTangentOffset != -1) {
200 domUint tangentIndex = colladaIndexList[indexToRemap*mMultiIndexOffset + mTangentOffset];
201 tanX = (*mTangentFloats)[tangentIndex * mTangentssStride + 0];
202 tanY = (*mTangentFloats)[tangentIndex * mTangentssStride + 1];
203 tanZ = (*mTangentFloats)[tangentIndex * mTangentssStride + 2];
204 }
205
206 float binormX = 0;
207 float binormY = 0;
208 float binormZ = 0;
209
210 if (mBinormalOffset != -1) {
211 domUint binormalIndex = colladaIndexList[indexToRemap*mMultiIndexOffset + mNormalOffset];
212 binormX = (*mBinormalFloats)[binormalIndex * mBinormalsStride + 0];
213 binormY = (*mBinormalFloats)[binormalIndex * mBinormalsStride + 1];
214 binormZ = (*mBinormalFloats)[binormalIndex * mBinormalsStride + 2];
215 }
216
217 float texCoordX = 0;
218 float texCoordY = 0;
219
220 if (mTexture1Offset != -1) {
221 domUint texCoordIndex = colladaIndexList[indexToRemap*mMultiIndexOffset + mTexture1Offset];
222 texCoordX = (*mTexture1Floats)[texCoordIndex * mTextureCoordsStride + 0];
223 texCoordY = (*mTexture1Floats)[texCoordIndex * mTextureCoordsStride + 1];
224 }
225
226 std::vector<uint32_t> &ithRemapList = mVertexRemap[positionIndex];
227 // We may have some potential vertices we can reuse
228 // loop over all the potential candidates and see if any match our guy
229 for (uint32_t i = 0; i < ithRemapList.size(); i ++) {
230
231 int ithRemap = ithRemapList[i];
232 // compare existing vertex with the new one
233 if ((*mPositions)[ithRemap * mPositionsStride + 0] != posX ||
234 (*mPositions)[ithRemap * mPositionsStride + 1] != posY ||
235 (*mPositions)[ithRemap * mPositionsStride + 2] != posZ) {
236 continue;
237 }
238
239 // Now go over normals
240 if (mNormalOffset != -1) {
241 if ((*mNormals)[ithRemap * mNormalsStride + 0] != normX ||
242 (*mNormals)[ithRemap * mNormalsStride + 1] != normY ||
243 (*mNormals)[ithRemap * mNormalsStride + 2] != normZ) {
244 continue;
245 }
246 }
247
248 // Now go over tangents
249 if (mTangentOffset != -1) {
250 if ((*mTangents)[ithRemap * mTangentssStride + 0] != tanX ||
251 (*mTangents)[ithRemap * mTangentssStride + 1] != tanY ||
252 (*mTangents)[ithRemap * mTangentssStride + 2] != tanZ) {
253 continue;
254 }
255 }
256
257 // Now go over binormals
258 if (mBinormalOffset != -1) {
259 if ((*mBinormals)[ithRemap * mBinormalsStride + 0] != binormX ||
260 (*mBinormals)[ithRemap * mBinormalsStride + 1] != binormY ||
261 (*mBinormals)[ithRemap * mBinormalsStride + 2] != binormZ) {
262 continue;
263 }
264 }
265
266 // And texcoords
267 if (mTexture1Offset != -1) {
268 if ((*mTextureCoords)[ithRemap * mTextureCoordsStride + 0] != texCoordX ||
269 (*mTextureCoords)[ithRemap * mTextureCoordsStride + 1] != texCoordY) {
270 continue;
271 }
272 }
273
274 // If we got here the new vertex is identical to the one that we already stored
275 return ithRemap;
276 }
277
278 // We did not encounter this vertex yet, store it and return its index
279 mPositions->push_back(posX);
280 mPositions->push_back(posY);
281 mPositions->push_back(posZ);
282
283 if (mNormalOffset != -1) {
284 mNormals->push_back(normX);
285 mNormals->push_back(normY);
286 mNormals->push_back(normZ);
287 }
288
289 if (mTangentOffset != -1) {
290 mTangents->push_back(tanX);
291 mTangents->push_back(tanY);
292 mTangents->push_back(tanZ);
293 }
294
295 if (mBinormalOffset != -1) {
296 mBinormals->push_back(binormX);
297 mBinormals->push_back(binormY);
298 mBinormals->push_back(binormZ);
299 }
300
301 if (mTexture1Offset != -1) {
302 mTextureCoords->push_back(texCoordX);
303 mTextureCoords->push_back(texCoordY);
304 }
305
306 // We need to remember this mapping. Since we are storing floats, not vec3's, need to
307 // divide by position size to get the right index
308 int currentVertexIndex = (mPositions->size()/mPositionsStride) - 1;
309 ithRemapList.push_back(currentVertexIndex);
310
311 return currentVertexIndex;
312}
313
314
315
316
317
318
319