• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
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 
ColladaGeometry()13 ColladaGeometry::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 
init(domGeometryRef geometry)36 bool 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 
addTriangles(domTriangles * colladaTriangles)59 void 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 
cacheOffsetsAndDataPointers(domTriangles * colladaTriangles)94 void 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 
remapIndexAndStoreData(const domListOfUInts & colladaIndexList,int indexToRemap)176 int 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 
320