rev |
line source |
nuclear@0
|
1 /*
|
nuclear@0
|
2 ---------------------------------------------------------------------------
|
nuclear@0
|
3 Open Asset Import Library (assimp)
|
nuclear@0
|
4 ---------------------------------------------------------------------------
|
nuclear@0
|
5
|
nuclear@0
|
6 Copyright (c) 2006-2012, assimp team
|
nuclear@0
|
7
|
nuclear@0
|
8 All rights reserved.
|
nuclear@0
|
9
|
nuclear@0
|
10 Redistribution and use of this software in source and binary forms,
|
nuclear@0
|
11 with or without modification, are permitted provided that the following
|
nuclear@0
|
12 conditions are met:
|
nuclear@0
|
13
|
nuclear@0
|
14 * Redistributions of source code must retain the above
|
nuclear@0
|
15 copyright notice, this list of conditions and the
|
nuclear@0
|
16 following disclaimer.
|
nuclear@0
|
17
|
nuclear@0
|
18 * Redistributions in binary form must reproduce the above
|
nuclear@0
|
19 copyright notice, this list of conditions and the
|
nuclear@0
|
20 following disclaimer in the documentation and/or other
|
nuclear@0
|
21 materials provided with the distribution.
|
nuclear@0
|
22
|
nuclear@0
|
23 * Neither the name of the assimp team, nor the names of its
|
nuclear@0
|
24 contributors may be used to endorse or promote products
|
nuclear@0
|
25 derived from this software without specific prior
|
nuclear@0
|
26 written permission of the assimp team.
|
nuclear@0
|
27
|
nuclear@0
|
28 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
nuclear@0
|
29 "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
nuclear@0
|
30 LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
|
nuclear@0
|
31 A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
|
nuclear@0
|
32 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
nuclear@0
|
33 SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
nuclear@0
|
34 LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
nuclear@0
|
35 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
nuclear@0
|
36 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
nuclear@0
|
37 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
|
nuclear@0
|
38 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
nuclear@0
|
39 ---------------------------------------------------------------------------
|
nuclear@0
|
40 */
|
nuclear@0
|
41
|
nuclear@0
|
42 /** @file LWOLoader.cpp
|
nuclear@0
|
43 * @brief Implementation of the LWO importer class
|
nuclear@0
|
44 */
|
nuclear@0
|
45
|
nuclear@0
|
46 #include "AssimpPCH.h"
|
nuclear@0
|
47 #ifndef ASSIMP_BUILD_NO_LWO_IMPORTER
|
nuclear@0
|
48
|
nuclear@0
|
49 // internal headers
|
nuclear@0
|
50 #include "LWOLoader.h"
|
nuclear@0
|
51 #include "StringComparison.h"
|
nuclear@0
|
52 #include "SGSpatialSort.h"
|
nuclear@0
|
53 #include "ByteSwap.h"
|
nuclear@0
|
54 #include "ProcessHelper.h"
|
nuclear@0
|
55 #include "ConvertToLHProcess.h"
|
nuclear@0
|
56
|
nuclear@0
|
57 using namespace Assimp;
|
nuclear@0
|
58
|
nuclear@0
|
59 static const aiImporterDesc desc = {
|
nuclear@0
|
60 "LightWave/Modo Object Importer",
|
nuclear@0
|
61 "",
|
nuclear@0
|
62 "",
|
nuclear@0
|
63 "http://www.newtek.com/lightwave.html\nhttp://www.luxology.com/modo/",
|
nuclear@0
|
64 aiImporterFlags_SupportTextFlavour,
|
nuclear@0
|
65 0,
|
nuclear@0
|
66 0,
|
nuclear@0
|
67 0,
|
nuclear@0
|
68 0,
|
nuclear@0
|
69 "lwo lxo"
|
nuclear@0
|
70 };
|
nuclear@0
|
71
|
nuclear@0
|
72 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
73 // Constructor to be privately used by Importer
|
nuclear@0
|
74 LWOImporter::LWOImporter()
|
nuclear@0
|
75 {}
|
nuclear@0
|
76
|
nuclear@0
|
77 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
78 // Destructor, private as well
|
nuclear@0
|
79 LWOImporter::~LWOImporter()
|
nuclear@0
|
80 {}
|
nuclear@0
|
81
|
nuclear@0
|
82 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
83 // Returns whether the class can handle the format of the given file.
|
nuclear@0
|
84 bool LWOImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler, bool checkSig) const
|
nuclear@0
|
85 {
|
nuclear@0
|
86 const std::string extension = GetExtension(pFile);
|
nuclear@0
|
87 if (extension == "lwo" || extension == "lxo") {
|
nuclear@0
|
88 return true;
|
nuclear@0
|
89 }
|
nuclear@0
|
90
|
nuclear@0
|
91 // if check for extension is not enough, check for the magic tokens
|
nuclear@0
|
92 if (!extension.length() || checkSig) {
|
nuclear@0
|
93 uint32_t tokens[3];
|
nuclear@0
|
94 tokens[0] = AI_LWO_FOURCC_LWOB;
|
nuclear@0
|
95 tokens[1] = AI_LWO_FOURCC_LWO2;
|
nuclear@0
|
96 tokens[2] = AI_LWO_FOURCC_LXOB;
|
nuclear@0
|
97 return CheckMagicToken(pIOHandler,pFile,tokens,3,8);
|
nuclear@0
|
98 }
|
nuclear@0
|
99 return false;
|
nuclear@0
|
100 }
|
nuclear@0
|
101
|
nuclear@0
|
102 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
103 // Setup configuration properties
|
nuclear@0
|
104 void LWOImporter::SetupProperties(const Importer* pImp)
|
nuclear@0
|
105 {
|
nuclear@0
|
106 configSpeedFlag = ( 0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED,0) ? true : false);
|
nuclear@0
|
107 configLayerIndex = pImp->GetPropertyInteger (AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY,UINT_MAX);
|
nuclear@0
|
108 configLayerName = pImp->GetPropertyString (AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY,"");
|
nuclear@0
|
109 }
|
nuclear@0
|
110
|
nuclear@0
|
111 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
112 // Get list of file extensions
|
nuclear@0
|
113 const aiImporterDesc* LWOImporter::GetInfo () const
|
nuclear@0
|
114 {
|
nuclear@0
|
115 return &desc;
|
nuclear@0
|
116 }
|
nuclear@0
|
117
|
nuclear@0
|
118 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
119 // Imports the given file into the given scene structure.
|
nuclear@0
|
120 void LWOImporter::InternReadFile( const std::string& pFile,
|
nuclear@0
|
121 aiScene* pScene,
|
nuclear@0
|
122 IOSystem* pIOHandler)
|
nuclear@0
|
123 {
|
nuclear@0
|
124 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
|
nuclear@0
|
125
|
nuclear@0
|
126 // Check whether we can read from the file
|
nuclear@0
|
127 if( file.get() == NULL)
|
nuclear@0
|
128 throw DeadlyImportError( "Failed to open LWO file " + pFile + ".");
|
nuclear@0
|
129
|
nuclear@0
|
130 if((this->fileSize = (unsigned int)file->FileSize()) < 12)
|
nuclear@0
|
131 throw DeadlyImportError("LWO: The file is too small to contain the IFF header");
|
nuclear@0
|
132
|
nuclear@0
|
133 // Allocate storage and copy the contents of the file to a memory buffer
|
nuclear@0
|
134 std::vector< uint8_t > mBuffer(fileSize);
|
nuclear@0
|
135 file->Read( &mBuffer[0], 1, fileSize);
|
nuclear@0
|
136 this->pScene = pScene;
|
nuclear@0
|
137
|
nuclear@0
|
138 // Determine the type of the file
|
nuclear@0
|
139 uint32_t fileType;
|
nuclear@0
|
140 const char* sz = IFF::ReadHeader(&mBuffer[0],fileType);
|
nuclear@0
|
141 if (sz)throw DeadlyImportError(sz);
|
nuclear@0
|
142
|
nuclear@0
|
143 mFileBuffer = &mBuffer[0] + 12;
|
nuclear@0
|
144 fileSize -= 12;
|
nuclear@0
|
145
|
nuclear@0
|
146 // Initialize some members with their default values
|
nuclear@0
|
147 hasNamedLayer = false;
|
nuclear@0
|
148
|
nuclear@0
|
149 // Create temporary storage on the stack but store pointers to it in the class
|
nuclear@0
|
150 // instance. Therefore everything will be destructed properly if an exception
|
nuclear@0
|
151 // is thrown and we needn't take care of that.
|
nuclear@0
|
152 LayerList _mLayers;
|
nuclear@0
|
153 SurfaceList _mSurfaces;
|
nuclear@0
|
154 TagList _mTags;
|
nuclear@0
|
155 TagMappingTable _mMapping;
|
nuclear@0
|
156
|
nuclear@0
|
157 mLayers = &_mLayers;
|
nuclear@0
|
158 mTags = &_mTags;
|
nuclear@0
|
159 mMapping = &_mMapping;
|
nuclear@0
|
160 mSurfaces = &_mSurfaces;
|
nuclear@0
|
161
|
nuclear@0
|
162 // Allocate a default layer (layer indices are 1-based from now)
|
nuclear@0
|
163 mLayers->push_back(Layer());
|
nuclear@0
|
164 mCurLayer = &mLayers->back();
|
nuclear@0
|
165 mCurLayer->mName = "<LWODefault>";
|
nuclear@0
|
166 mCurLayer->mIndex = -1;
|
nuclear@0
|
167
|
nuclear@0
|
168 // old lightwave file format (prior to v6)
|
nuclear@0
|
169 if (AI_LWO_FOURCC_LWOB == fileType) {
|
nuclear@0
|
170 DefaultLogger::get()->info("LWO file format: LWOB (<= LightWave 5.5)");
|
nuclear@0
|
171
|
nuclear@0
|
172 mIsLWO2 = false;
|
nuclear@0
|
173 mIsLXOB = false;
|
nuclear@0
|
174 LoadLWOBFile();
|
nuclear@0
|
175 }
|
nuclear@0
|
176 // New lightwave format
|
nuclear@0
|
177 else if (AI_LWO_FOURCC_LWO2 == fileType) {
|
nuclear@0
|
178 mIsLXOB = false;
|
nuclear@0
|
179 DefaultLogger::get()->info("LWO file format: LWO2 (>= LightWave 6)");
|
nuclear@0
|
180 }
|
nuclear@0
|
181 // MODO file format
|
nuclear@0
|
182 else if (AI_LWO_FOURCC_LXOB == fileType) {
|
nuclear@0
|
183 mIsLXOB = true;
|
nuclear@0
|
184 DefaultLogger::get()->info("LWO file format: LXOB (Modo)");
|
nuclear@0
|
185 }
|
nuclear@0
|
186 // we don't know this format
|
nuclear@0
|
187 else
|
nuclear@0
|
188 {
|
nuclear@0
|
189 char szBuff[5];
|
nuclear@0
|
190 szBuff[0] = (char)(fileType >> 24u);
|
nuclear@0
|
191 szBuff[1] = (char)(fileType >> 16u);
|
nuclear@0
|
192 szBuff[2] = (char)(fileType >> 8u);
|
nuclear@0
|
193 szBuff[3] = (char)(fileType);
|
nuclear@0
|
194 szBuff[4] = '\0';
|
nuclear@0
|
195 throw DeadlyImportError(std::string("Unknown LWO sub format: ") + szBuff);
|
nuclear@0
|
196 }
|
nuclear@0
|
197
|
nuclear@0
|
198 if (AI_LWO_FOURCC_LWOB != fileType) {
|
nuclear@0
|
199 mIsLWO2 = true;
|
nuclear@0
|
200 LoadLWO2File();
|
nuclear@0
|
201
|
nuclear@0
|
202 // The newer lightwave format allows the user to configure the
|
nuclear@0
|
203 // loader that just one layer is used. If this is the case
|
nuclear@0
|
204 // we need to check now whether the requested layer has been found.
|
nuclear@0
|
205 if (UINT_MAX != configLayerIndex) {
|
nuclear@0
|
206 unsigned int layerCount = 0;
|
nuclear@0
|
207 for(std::list<LWO::Layer>::iterator itLayers=mLayers->begin(); itLayers!=mLayers->end(); itLayers++)
|
nuclear@0
|
208 if (!itLayers->skip)
|
nuclear@0
|
209 layerCount++;
|
nuclear@0
|
210 if (layerCount!=2)
|
nuclear@0
|
211 throw DeadlyImportError("LWO2: The requested layer was not found");
|
nuclear@0
|
212 }
|
nuclear@0
|
213
|
nuclear@0
|
214 if (configLayerName.length() && !hasNamedLayer) {
|
nuclear@0
|
215 throw DeadlyImportError("LWO2: Unable to find the requested layer: "
|
nuclear@0
|
216 + configLayerName);
|
nuclear@0
|
217 }
|
nuclear@0
|
218 }
|
nuclear@0
|
219
|
nuclear@0
|
220 // now, as we have loaded all data, we can resolve cross-referenced tags and clips
|
nuclear@0
|
221 ResolveTags();
|
nuclear@0
|
222 ResolveClips();
|
nuclear@0
|
223
|
nuclear@0
|
224 // now process all layers and build meshes and nodes
|
nuclear@0
|
225 std::vector<aiMesh*> apcMeshes;
|
nuclear@0
|
226 std::map<uint16_t, aiNode*> apcNodes;
|
nuclear@0
|
227
|
nuclear@0
|
228 apcMeshes.reserve(mLayers->size()*std::min(((unsigned int)mSurfaces->size()/2u), 1u));
|
nuclear@0
|
229
|
nuclear@0
|
230 unsigned int iDefaultSurface = UINT_MAX; // index of the default surface
|
nuclear@0
|
231 for (LayerList::iterator lit = mLayers->begin(), lend = mLayers->end();lit != lend;++lit) {
|
nuclear@0
|
232 LWO::Layer& layer = *lit;
|
nuclear@0
|
233 if (layer.skip)
|
nuclear@0
|
234 continue;
|
nuclear@0
|
235
|
nuclear@0
|
236 // I don't know whether there could be dummy layers, but it would be possible
|
nuclear@0
|
237 const unsigned int meshStart = (unsigned int)apcMeshes.size();
|
nuclear@0
|
238 if (!layer.mFaces.empty() && !layer.mTempPoints.empty()) {
|
nuclear@0
|
239
|
nuclear@0
|
240 // now sort all faces by the surfaces assigned to them
|
nuclear@0
|
241 std::vector<SortedRep> pSorted(mSurfaces->size()+1);
|
nuclear@0
|
242
|
nuclear@0
|
243 unsigned int i = 0;
|
nuclear@0
|
244 for (FaceList::iterator it = layer.mFaces.begin(), end = layer.mFaces.end();it != end;++it,++i) {
|
nuclear@0
|
245 // Check whether we support this face's type
|
nuclear@0
|
246 if ((*it).type != AI_LWO_FACE && (*it).type != AI_LWO_PTCH &&
|
nuclear@0
|
247 (*it).type != AI_LWO_BONE && (*it).type != AI_LWO_SUBD) {
|
nuclear@0
|
248 continue;
|
nuclear@0
|
249 }
|
nuclear@0
|
250
|
nuclear@0
|
251 unsigned int idx = (*it).surfaceIndex;
|
nuclear@0
|
252 if (idx >= mTags->size())
|
nuclear@0
|
253 {
|
nuclear@0
|
254 DefaultLogger::get()->warn("LWO: Invalid face surface index");
|
nuclear@0
|
255 idx = UINT_MAX;
|
nuclear@0
|
256 }
|
nuclear@0
|
257 if(UINT_MAX == idx || UINT_MAX == (idx = _mMapping[idx])) {
|
nuclear@0
|
258 if (UINT_MAX == iDefaultSurface) {
|
nuclear@0
|
259 iDefaultSurface = (unsigned int)mSurfaces->size();
|
nuclear@0
|
260 mSurfaces->push_back(LWO::Surface());
|
nuclear@0
|
261 LWO::Surface& surf = mSurfaces->back();
|
nuclear@0
|
262 surf.mColor.r = surf.mColor.g = surf.mColor.b = 0.6f;
|
nuclear@0
|
263 surf.mName = "LWODefaultSurface";
|
nuclear@0
|
264 }
|
nuclear@0
|
265 idx = iDefaultSurface;
|
nuclear@0
|
266 }
|
nuclear@0
|
267 pSorted[idx].push_back(i);
|
nuclear@0
|
268 }
|
nuclear@0
|
269 if (UINT_MAX == iDefaultSurface) {
|
nuclear@0
|
270 pSorted.erase(pSorted.end()-1);
|
nuclear@0
|
271 }
|
nuclear@0
|
272 for (unsigned int p = 0,i = 0;i < mSurfaces->size();++i) {
|
nuclear@0
|
273 SortedRep& sorted = pSorted[i];
|
nuclear@0
|
274 if (sorted.empty())
|
nuclear@0
|
275 continue;
|
nuclear@0
|
276
|
nuclear@0
|
277 // generate the mesh
|
nuclear@0
|
278 aiMesh* mesh = new aiMesh();
|
nuclear@0
|
279 apcMeshes.push_back(mesh);
|
nuclear@0
|
280 mesh->mNumFaces = (unsigned int)sorted.size();
|
nuclear@0
|
281
|
nuclear@0
|
282 // count the number of vertices
|
nuclear@0
|
283 SortedRep::const_iterator it = sorted.begin(), end = sorted.end();
|
nuclear@0
|
284 for (;it != end;++it) {
|
nuclear@0
|
285 mesh->mNumVertices += layer.mFaces[*it].mNumIndices;
|
nuclear@0
|
286 }
|
nuclear@0
|
287
|
nuclear@0
|
288 aiVector3D *nrm = NULL, * pv = mesh->mVertices = new aiVector3D[mesh->mNumVertices];
|
nuclear@0
|
289 aiFace* pf = mesh->mFaces = new aiFace[mesh->mNumFaces];
|
nuclear@0
|
290 mesh->mMaterialIndex = i;
|
nuclear@0
|
291
|
nuclear@0
|
292 // find out which vertex color channels and which texture coordinate
|
nuclear@0
|
293 // channels are really required by the material attached to this mesh
|
nuclear@0
|
294 unsigned int vUVChannelIndices[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
nuclear@0
|
295 unsigned int vVColorIndices[AI_MAX_NUMBER_OF_COLOR_SETS];
|
nuclear@0
|
296
|
nuclear@0
|
297 #if _DEBUG
|
nuclear@0
|
298 for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_TEXTURECOORDS;++mui ) {
|
nuclear@0
|
299 vUVChannelIndices[mui] = UINT_MAX;
|
nuclear@0
|
300 }
|
nuclear@0
|
301 for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_COLOR_SETS;++mui ) {
|
nuclear@0
|
302 vVColorIndices[mui] = UINT_MAX;
|
nuclear@0
|
303 }
|
nuclear@0
|
304 #endif
|
nuclear@0
|
305
|
nuclear@0
|
306 FindUVChannels(_mSurfaces[i],sorted,layer,vUVChannelIndices);
|
nuclear@0
|
307 FindVCChannels(_mSurfaces[i],sorted,layer,vVColorIndices);
|
nuclear@0
|
308
|
nuclear@0
|
309 // allocate storage for UV and CV channels
|
nuclear@0
|
310 aiVector3D* pvUV[AI_MAX_NUMBER_OF_TEXTURECOORDS];
|
nuclear@0
|
311 for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_TEXTURECOORDS;++mui ) {
|
nuclear@0
|
312 if (UINT_MAX == vUVChannelIndices[mui]) {
|
nuclear@0
|
313 break;
|
nuclear@0
|
314 }
|
nuclear@0
|
315
|
nuclear@0
|
316 pvUV[mui] = mesh->mTextureCoords[mui] = new aiVector3D[mesh->mNumVertices];
|
nuclear@0
|
317
|
nuclear@0
|
318 // LightWave doesn't support more than 2 UV components (?)
|
nuclear@0
|
319 mesh->mNumUVComponents[0] = 2;
|
nuclear@0
|
320 }
|
nuclear@0
|
321
|
nuclear@0
|
322 if (layer.mNormals.name.length())
|
nuclear@0
|
323 nrm = mesh->mNormals = new aiVector3D[mesh->mNumVertices];
|
nuclear@0
|
324
|
nuclear@0
|
325 aiColor4D* pvVC[AI_MAX_NUMBER_OF_COLOR_SETS];
|
nuclear@0
|
326 for (unsigned int mui = 0; mui < AI_MAX_NUMBER_OF_COLOR_SETS;++mui) {
|
nuclear@0
|
327 if (UINT_MAX == vVColorIndices[mui]) {
|
nuclear@0
|
328 break;
|
nuclear@0
|
329 }
|
nuclear@0
|
330 pvVC[mui] = mesh->mColors[mui] = new aiColor4D[mesh->mNumVertices];
|
nuclear@0
|
331 }
|
nuclear@0
|
332
|
nuclear@0
|
333 // we would not need this extra array, but the code is much cleaner if we use it
|
nuclear@0
|
334 std::vector<unsigned int>& smoothingGroups = layer.mPointReferrers;
|
nuclear@0
|
335 smoothingGroups.erase (smoothingGroups.begin(),smoothingGroups.end());
|
nuclear@0
|
336 smoothingGroups.resize(mesh->mNumFaces,0);
|
nuclear@0
|
337
|
nuclear@0
|
338 // now convert all faces
|
nuclear@0
|
339 unsigned int vert = 0;
|
nuclear@0
|
340 std::vector<unsigned int>::iterator outIt = smoothingGroups.begin();
|
nuclear@0
|
341 for (it = sorted.begin(); it != end;++it,++outIt) {
|
nuclear@0
|
342 const LWO::Face& face = layer.mFaces[*it];
|
nuclear@0
|
343 *outIt = face.smoothGroup;
|
nuclear@0
|
344
|
nuclear@0
|
345 // copy all vertices
|
nuclear@0
|
346 for (unsigned int q = 0; q < face.mNumIndices;++q,++vert) {
|
nuclear@0
|
347 register unsigned int idx = face.mIndices[q];
|
nuclear@0
|
348 *pv++ = layer.mTempPoints[idx] /*- layer.mPivot*/;
|
nuclear@0
|
349
|
nuclear@0
|
350 // process UV coordinates
|
nuclear@0
|
351 for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_TEXTURECOORDS;++w) {
|
nuclear@0
|
352 if (UINT_MAX == vUVChannelIndices[w]) {
|
nuclear@0
|
353 break;
|
nuclear@0
|
354 }
|
nuclear@0
|
355 aiVector3D*& pp = pvUV[w];
|
nuclear@0
|
356 const aiVector2D& src = ((aiVector2D*)&layer.mUVChannels[vUVChannelIndices[w]].rawData[0])[idx];
|
nuclear@0
|
357 pp->x = src.x;
|
nuclear@0
|
358 pp->y = src.y;
|
nuclear@0
|
359 pp++;
|
nuclear@0
|
360 }
|
nuclear@0
|
361
|
nuclear@0
|
362 // process normals (MODO extension)
|
nuclear@0
|
363 if (nrm) {
|
nuclear@0
|
364 *nrm = ((aiVector3D*)&layer.mNormals.rawData[0])[idx];
|
nuclear@0
|
365 nrm->z *= -1.f;
|
nuclear@0
|
366 ++nrm;
|
nuclear@0
|
367 }
|
nuclear@0
|
368
|
nuclear@0
|
369 // process vertex colors
|
nuclear@0
|
370 for (unsigned int w = 0; w < AI_MAX_NUMBER_OF_COLOR_SETS;++w) {
|
nuclear@0
|
371 if (UINT_MAX == vVColorIndices[w]) {
|
nuclear@0
|
372 break;
|
nuclear@0
|
373 }
|
nuclear@0
|
374 *pvVC[w] = ((aiColor4D*)&layer.mVColorChannels[vVColorIndices[w]].rawData[0])[idx];
|
nuclear@0
|
375
|
nuclear@0
|
376 // If a RGB color map is explicitly requested delete the
|
nuclear@0
|
377 // alpha channel - it could theoretically be != 1.
|
nuclear@0
|
378 if(_mSurfaces[i].mVCMapType == AI_LWO_RGB)
|
nuclear@0
|
379 pvVC[w]->a = 1.f;
|
nuclear@0
|
380
|
nuclear@0
|
381 pvVC[w]++;
|
nuclear@0
|
382 }
|
nuclear@0
|
383
|
nuclear@0
|
384 #if 0
|
nuclear@0
|
385 // process vertex weights. We can't properly reconstruct the whole skeleton for now,
|
nuclear@0
|
386 // but we can create dummy bones for all weight channels which we have.
|
nuclear@0
|
387 for (unsigned int w = 0; w < layer.mWeightChannels.size();++w)
|
nuclear@0
|
388 {
|
nuclear@0
|
389 }
|
nuclear@0
|
390 #endif
|
nuclear@0
|
391
|
nuclear@0
|
392 face.mIndices[q] = vert;
|
nuclear@0
|
393 }
|
nuclear@0
|
394 pf->mIndices = face.mIndices;
|
nuclear@0
|
395 pf->mNumIndices = face.mNumIndices;
|
nuclear@0
|
396 unsigned int** p = (unsigned int**)&face.mIndices;*p = NULL; // HACK: make sure it won't be deleted
|
nuclear@0
|
397 pf++;
|
nuclear@0
|
398 }
|
nuclear@0
|
399
|
nuclear@0
|
400 if (!mesh->mNormals) {
|
nuclear@0
|
401 // Compute normal vectors for the mesh - we can't use our GenSmoothNormal-
|
nuclear@0
|
402 // Step here since it wouldn't handle smoothing groups correctly for LWO.
|
nuclear@0
|
403 // So we use a separate implementation.
|
nuclear@0
|
404 ComputeNormals(mesh,smoothingGroups,_mSurfaces[i]);
|
nuclear@0
|
405 }
|
nuclear@0
|
406 else DefaultLogger::get()->debug("LWO2: No need to compute normals, they're already there");
|
nuclear@0
|
407 ++p;
|
nuclear@0
|
408 }
|
nuclear@0
|
409 }
|
nuclear@0
|
410
|
nuclear@0
|
411 // Generate nodes to render the mesh. Store the source layer in the mParent member of the nodes
|
nuclear@0
|
412 unsigned int num = apcMeshes.size() - meshStart;
|
nuclear@0
|
413 if (layer.mName != "<LWODefault>" || num > 0) {
|
nuclear@0
|
414 aiNode* pcNode = new aiNode();
|
nuclear@0
|
415 apcNodes[layer.mIndex] = pcNode;
|
nuclear@0
|
416 pcNode->mName.Set(layer.mName);
|
nuclear@0
|
417 pcNode->mParent = (aiNode*)&layer;
|
nuclear@0
|
418 pcNode->mNumMeshes = num;
|
nuclear@0
|
419
|
nuclear@0
|
420 if (pcNode->mNumMeshes) {
|
nuclear@0
|
421 pcNode->mMeshes = new unsigned int[pcNode->mNumMeshes];
|
nuclear@0
|
422 for (unsigned int p = 0; p < pcNode->mNumMeshes;++p)
|
nuclear@0
|
423 pcNode->mMeshes[p] = p + meshStart;
|
nuclear@0
|
424 }
|
nuclear@0
|
425 }
|
nuclear@0
|
426 }
|
nuclear@0
|
427
|
nuclear@0
|
428 if (apcNodes.empty() || apcMeshes.empty())
|
nuclear@0
|
429 throw DeadlyImportError("LWO: No meshes loaded");
|
nuclear@0
|
430
|
nuclear@0
|
431 // The RemoveRedundantMaterials step will clean this up later
|
nuclear@0
|
432 pScene->mMaterials = new aiMaterial*[pScene->mNumMaterials = (unsigned int)mSurfaces->size()];
|
nuclear@0
|
433 for (unsigned int mat = 0; mat < pScene->mNumMaterials;++mat) {
|
nuclear@0
|
434 aiMaterial* pcMat = new aiMaterial();
|
nuclear@0
|
435 pScene->mMaterials[mat] = pcMat;
|
nuclear@0
|
436 ConvertMaterial((*mSurfaces)[mat],pcMat);
|
nuclear@0
|
437 }
|
nuclear@0
|
438
|
nuclear@0
|
439 // copy the meshes to the output structure
|
nuclear@0
|
440 pScene->mMeshes = new aiMesh*[ pScene->mNumMeshes = (unsigned int)apcMeshes.size() ];
|
nuclear@0
|
441 ::memcpy(pScene->mMeshes,&apcMeshes[0],pScene->mNumMeshes*sizeof(void*));
|
nuclear@0
|
442
|
nuclear@0
|
443 // generate the final node graph
|
nuclear@0
|
444 GenerateNodeGraph(apcNodes);
|
nuclear@0
|
445 }
|
nuclear@0
|
446
|
nuclear@0
|
447 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
448 void LWOImporter::ComputeNormals(aiMesh* mesh, const std::vector<unsigned int>& smoothingGroups,
|
nuclear@0
|
449 const LWO::Surface& surface)
|
nuclear@0
|
450 {
|
nuclear@0
|
451 // Allocate output storage
|
nuclear@0
|
452 mesh->mNormals = new aiVector3D[mesh->mNumVertices];
|
nuclear@0
|
453
|
nuclear@0
|
454 // First generate per-face normals
|
nuclear@0
|
455 aiVector3D* out;
|
nuclear@0
|
456 std::vector<aiVector3D> faceNormals;
|
nuclear@0
|
457
|
nuclear@0
|
458 // ... in some cases that's already enough
|
nuclear@0
|
459 if (!surface.mMaximumSmoothAngle)
|
nuclear@0
|
460 out = mesh->mNormals;
|
nuclear@0
|
461 else {
|
nuclear@0
|
462 faceNormals.resize(mesh->mNumVertices);
|
nuclear@0
|
463 out = &faceNormals[0];
|
nuclear@0
|
464 }
|
nuclear@0
|
465
|
nuclear@0
|
466 aiFace* begin = mesh->mFaces, *const end = mesh->mFaces+mesh->mNumFaces;
|
nuclear@0
|
467 for (; begin != end; ++begin) {
|
nuclear@0
|
468 aiFace& face = *begin;
|
nuclear@0
|
469
|
nuclear@0
|
470 if(face.mNumIndices < 3) {
|
nuclear@0
|
471 continue;
|
nuclear@0
|
472 }
|
nuclear@0
|
473
|
nuclear@0
|
474 // LWO doc: "the normal is defined as the cross product of the first and last edges"
|
nuclear@0
|
475 aiVector3D* pV1 = mesh->mVertices + face.mIndices[0];
|
nuclear@0
|
476 aiVector3D* pV2 = mesh->mVertices + face.mIndices[1];
|
nuclear@0
|
477 aiVector3D* pV3 = mesh->mVertices + face.mIndices[face.mNumIndices-1];
|
nuclear@0
|
478
|
nuclear@0
|
479 aiVector3D vNor = ((*pV2 - *pV1) ^(*pV3 - *pV1)).Normalize();
|
nuclear@0
|
480 for (unsigned int i = 0; i < face.mNumIndices;++i)
|
nuclear@0
|
481 out[face.mIndices[i]] = vNor;
|
nuclear@0
|
482 }
|
nuclear@0
|
483 if (!surface.mMaximumSmoothAngle)return;
|
nuclear@0
|
484 const float posEpsilon = ComputePositionEpsilon(mesh);
|
nuclear@0
|
485
|
nuclear@0
|
486 // Now generate the spatial sort tree
|
nuclear@0
|
487 SGSpatialSort sSort;
|
nuclear@0
|
488 std::vector<unsigned int>::const_iterator it = smoothingGroups.begin();
|
nuclear@0
|
489 for( begin = mesh->mFaces; begin != end; ++begin, ++it)
|
nuclear@0
|
490 {
|
nuclear@0
|
491 aiFace& face = *begin;
|
nuclear@0
|
492 for (unsigned int i = 0; i < face.mNumIndices;++i)
|
nuclear@0
|
493 {
|
nuclear@0
|
494 register unsigned int tt = face.mIndices[i];
|
nuclear@0
|
495 sSort.Add(mesh->mVertices[tt],tt,*it);
|
nuclear@0
|
496 }
|
nuclear@0
|
497 }
|
nuclear@0
|
498 // Sort everything - this takes O(nlogn) time
|
nuclear@0
|
499 sSort.Prepare();
|
nuclear@0
|
500 std::vector<unsigned int> poResult;
|
nuclear@0
|
501 poResult.reserve(20);
|
nuclear@0
|
502
|
nuclear@0
|
503 // Generate vertex normals. We have O(logn) for the binary lookup, which we need
|
nuclear@0
|
504 // for n elements, thus the EXPECTED complexity is O(nlogn)
|
nuclear@0
|
505 if (surface.mMaximumSmoothAngle < 3.f && !configSpeedFlag) {
|
nuclear@0
|
506 const float fLimit = cos(surface.mMaximumSmoothAngle);
|
nuclear@0
|
507
|
nuclear@0
|
508 for( begin = mesh->mFaces, it = smoothingGroups.begin(); begin != end; ++begin, ++it) {
|
nuclear@0
|
509 const aiFace& face = *begin;
|
nuclear@0
|
510 unsigned int* beginIdx = face.mIndices, *const endIdx = face.mIndices+face.mNumIndices;
|
nuclear@0
|
511 for (; beginIdx != endIdx; ++beginIdx)
|
nuclear@0
|
512 {
|
nuclear@0
|
513 register unsigned int idx = *beginIdx;
|
nuclear@0
|
514 sSort.FindPositions(mesh->mVertices[idx],*it,posEpsilon,poResult,true);
|
nuclear@0
|
515 std::vector<unsigned int>::const_iterator a, end = poResult.end();
|
nuclear@0
|
516
|
nuclear@0
|
517 aiVector3D vNormals;
|
nuclear@0
|
518 for (a = poResult.begin();a != end;++a) {
|
nuclear@0
|
519 const aiVector3D& v = faceNormals[*a];
|
nuclear@0
|
520 if (v * faceNormals[idx] < fLimit)
|
nuclear@0
|
521 continue;
|
nuclear@0
|
522 vNormals += v;
|
nuclear@0
|
523 }
|
nuclear@0
|
524 mesh->mNormals[idx] = vNormals.Normalize();
|
nuclear@0
|
525 }
|
nuclear@0
|
526 }
|
nuclear@0
|
527 }
|
nuclear@0
|
528 // faster code path in case there is no smooth angle
|
nuclear@0
|
529 else {
|
nuclear@0
|
530 std::vector<bool> vertexDone(mesh->mNumVertices,false);
|
nuclear@0
|
531 for( begin = mesh->mFaces, it = smoothingGroups.begin(); begin != end; ++begin, ++it) {
|
nuclear@0
|
532 const aiFace& face = *begin;
|
nuclear@0
|
533 unsigned int* beginIdx = face.mIndices, *const endIdx = face.mIndices+face.mNumIndices;
|
nuclear@0
|
534 for (; beginIdx != endIdx; ++beginIdx)
|
nuclear@0
|
535 {
|
nuclear@0
|
536 register unsigned int idx = *beginIdx;
|
nuclear@0
|
537 if (vertexDone[idx])
|
nuclear@0
|
538 continue;
|
nuclear@0
|
539 sSort.FindPositions(mesh->mVertices[idx],*it,posEpsilon,poResult,true);
|
nuclear@0
|
540 std::vector<unsigned int>::const_iterator a, end = poResult.end();
|
nuclear@0
|
541
|
nuclear@0
|
542 aiVector3D vNormals;
|
nuclear@0
|
543 for (a = poResult.begin();a != end;++a) {
|
nuclear@0
|
544 const aiVector3D& v = faceNormals[*a];
|
nuclear@0
|
545 vNormals += v;
|
nuclear@0
|
546 }
|
nuclear@0
|
547 vNormals.Normalize();
|
nuclear@0
|
548 for (a = poResult.begin();a != end;++a) {
|
nuclear@0
|
549 mesh->mNormals[*a] = vNormals;
|
nuclear@0
|
550 vertexDone[*a] = true;
|
nuclear@0
|
551 }
|
nuclear@0
|
552 }
|
nuclear@0
|
553 }
|
nuclear@0
|
554 }
|
nuclear@0
|
555 }
|
nuclear@0
|
556
|
nuclear@0
|
557 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
558 void LWOImporter::GenerateNodeGraph(std::map<uint16_t,aiNode*>& apcNodes)
|
nuclear@0
|
559 {
|
nuclear@0
|
560 // now generate the final nodegraph - generate a root node and attach children
|
nuclear@0
|
561 aiNode* root = pScene->mRootNode = new aiNode();
|
nuclear@0
|
562 root->mName.Set("<LWORoot>");
|
nuclear@0
|
563
|
nuclear@0
|
564 //Set parent of all children, inserting pivots
|
nuclear@0
|
565 //std::cout << "Set parent of all children" << std::endl;
|
nuclear@0
|
566 std::map<uint16_t, aiNode*> mapPivot;
|
nuclear@0
|
567 for (std::map<uint16_t,aiNode*>::iterator itapcNodes = apcNodes.begin(); itapcNodes != apcNodes.end(); ++itapcNodes) {
|
nuclear@0
|
568
|
nuclear@0
|
569 //Get the parent index
|
nuclear@0
|
570 LWO::Layer* nodeLayer = (LWO::Layer*)(itapcNodes->second->mParent);
|
nuclear@0
|
571 uint16_t parentIndex = nodeLayer->mParent;
|
nuclear@0
|
572
|
nuclear@0
|
573 //Create pivot node, store it into the pivot map, and set the parent as the pivot
|
nuclear@0
|
574 aiNode* pivotNode = new aiNode();
|
nuclear@0
|
575 pivotNode->mName.Set("Pivot-"+std::string(itapcNodes->second->mName.data));
|
nuclear@0
|
576 mapPivot[-(itapcNodes->first+2)] = pivotNode;
|
nuclear@0
|
577 itapcNodes->second->mParent = pivotNode;
|
nuclear@0
|
578
|
nuclear@0
|
579 //Look for the parent node to attach the pivot to
|
nuclear@0
|
580 if (apcNodes.find(parentIndex) != apcNodes.end()) {
|
nuclear@0
|
581 pivotNode->mParent = apcNodes[parentIndex];
|
nuclear@0
|
582 } else {
|
nuclear@0
|
583 //If not, attach to the root node
|
nuclear@0
|
584 pivotNode->mParent = root;
|
nuclear@0
|
585 }
|
nuclear@0
|
586
|
nuclear@0
|
587 //Set the node and the pivot node transformation
|
nuclear@0
|
588 itapcNodes->second->mTransformation.a4 = -nodeLayer->mPivot.x;
|
nuclear@0
|
589 itapcNodes->second->mTransformation.b4 = -nodeLayer->mPivot.y;
|
nuclear@0
|
590 itapcNodes->second->mTransformation.c4 = -nodeLayer->mPivot.z;
|
nuclear@0
|
591 pivotNode->mTransformation.a4 = nodeLayer->mPivot.x;
|
nuclear@0
|
592 pivotNode->mTransformation.b4 = nodeLayer->mPivot.y;
|
nuclear@0
|
593 pivotNode->mTransformation.c4 = nodeLayer->mPivot.z;
|
nuclear@0
|
594 }
|
nuclear@0
|
595
|
nuclear@0
|
596 //Merge pivot map into node map
|
nuclear@0
|
597 //std::cout << "Merge pivot map into node map" << std::endl;
|
nuclear@0
|
598 for (std::map<uint16_t, aiNode*>::iterator itMapPivot = mapPivot.begin(); itMapPivot != mapPivot.end(); ++itMapPivot) {
|
nuclear@0
|
599 apcNodes[itMapPivot->first] = itMapPivot->second;
|
nuclear@0
|
600 }
|
nuclear@0
|
601
|
nuclear@0
|
602 //Set children of all parents
|
nuclear@0
|
603 apcNodes[-1] = root;
|
nuclear@0
|
604 for (std::map<uint16_t,aiNode*>::iterator itMapParentNodes = apcNodes.begin(); itMapParentNodes != apcNodes.end(); ++itMapParentNodes) {
|
nuclear@0
|
605 for (std::map<uint16_t,aiNode*>::iterator itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
|
nuclear@0
|
606 if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
|
nuclear@0
|
607 ++(itMapParentNodes->second->mNumChildren);
|
nuclear@0
|
608 }
|
nuclear@0
|
609 }
|
nuclear@0
|
610 if (itMapParentNodes->second->mNumChildren) {
|
nuclear@0
|
611 itMapParentNodes->second->mChildren = new aiNode* [ itMapParentNodes->second->mNumChildren ];
|
nuclear@0
|
612 uint16_t p = 0;
|
nuclear@0
|
613 for (std::map<uint16_t,aiNode*>::iterator itMapChildNodes = apcNodes.begin(); itMapChildNodes != apcNodes.end(); ++itMapChildNodes) {
|
nuclear@0
|
614 if ((itMapParentNodes->first != itMapChildNodes->first) && (itMapParentNodes->second == itMapChildNodes->second->mParent)) {
|
nuclear@0
|
615 itMapParentNodes->second->mChildren[p++] = itMapChildNodes->second;
|
nuclear@0
|
616 }
|
nuclear@0
|
617 }
|
nuclear@0
|
618 }
|
nuclear@0
|
619 }
|
nuclear@0
|
620
|
nuclear@0
|
621 if (!pScene->mRootNode->mNumChildren)
|
nuclear@0
|
622 throw DeadlyImportError("LWO: Unable to build a valid node graph");
|
nuclear@0
|
623
|
nuclear@0
|
624 // Remove a single root node with no meshes assigned to it ...
|
nuclear@0
|
625 if (1 == pScene->mRootNode->mNumChildren) {
|
nuclear@0
|
626 aiNode* pc = pScene->mRootNode->mChildren[0];
|
nuclear@0
|
627 pc->mParent = pScene->mRootNode->mChildren[0] = NULL;
|
nuclear@0
|
628 delete pScene->mRootNode;
|
nuclear@0
|
629 pScene->mRootNode = pc;
|
nuclear@0
|
630 }
|
nuclear@0
|
631
|
nuclear@0
|
632 // convert the whole stuff to RH with CCW winding
|
nuclear@0
|
633 MakeLeftHandedProcess maker;
|
nuclear@0
|
634 maker.Execute(pScene);
|
nuclear@0
|
635
|
nuclear@0
|
636 FlipWindingOrderProcess flipper;
|
nuclear@0
|
637 flipper.Execute(pScene);
|
nuclear@0
|
638 }
|
nuclear@0
|
639
|
nuclear@0
|
640 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
641 void LWOImporter::ResolveTags()
|
nuclear@0
|
642 {
|
nuclear@0
|
643 // --- this function is used for both LWO2 and LWOB
|
nuclear@0
|
644 mMapping->resize(mTags->size(), UINT_MAX);
|
nuclear@0
|
645 for (unsigned int a = 0; a < mTags->size();++a) {
|
nuclear@0
|
646
|
nuclear@0
|
647 const std::string& c = (*mTags)[a];
|
nuclear@0
|
648 for (unsigned int i = 0; i < mSurfaces->size();++i) {
|
nuclear@0
|
649
|
nuclear@0
|
650 const std::string& d = (*mSurfaces)[i].mName;
|
nuclear@0
|
651 if (!ASSIMP_stricmp(c,d)) {
|
nuclear@0
|
652
|
nuclear@0
|
653 (*mMapping)[a] = i;
|
nuclear@0
|
654 break;
|
nuclear@0
|
655 }
|
nuclear@0
|
656 }
|
nuclear@0
|
657 }
|
nuclear@0
|
658 }
|
nuclear@0
|
659
|
nuclear@0
|
660 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
661 void LWOImporter::ResolveClips()
|
nuclear@0
|
662 {
|
nuclear@0
|
663 for( unsigned int i = 0; i < mClips.size();++i) {
|
nuclear@0
|
664
|
nuclear@0
|
665 Clip& clip = mClips[i];
|
nuclear@0
|
666 if (Clip::REF == clip.type) {
|
nuclear@0
|
667
|
nuclear@0
|
668 if (clip.clipRef >= mClips.size()) {
|
nuclear@0
|
669 DefaultLogger::get()->error("LWO2: Clip referrer index is out of range");
|
nuclear@0
|
670 clip.clipRef = 0;
|
nuclear@0
|
671 }
|
nuclear@0
|
672
|
nuclear@0
|
673 Clip& dest = mClips[clip.clipRef];
|
nuclear@0
|
674 if (Clip::REF == dest.type) {
|
nuclear@0
|
675 DefaultLogger::get()->error("LWO2: Clip references another clip reference");
|
nuclear@0
|
676 clip.type = Clip::UNSUPPORTED;
|
nuclear@0
|
677 }
|
nuclear@0
|
678
|
nuclear@0
|
679 else {
|
nuclear@0
|
680 clip.path = dest.path;
|
nuclear@0
|
681 clip.type = dest.type;
|
nuclear@0
|
682 }
|
nuclear@0
|
683 }
|
nuclear@0
|
684 }
|
nuclear@0
|
685 }
|
nuclear@0
|
686
|
nuclear@0
|
687 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
688 void LWOImporter::AdjustTexturePath(std::string& out)
|
nuclear@0
|
689 {
|
nuclear@0
|
690 // --- this function is used for both LWO2 and LWOB
|
nuclear@0
|
691 if (!mIsLWO2 && ::strstr(out.c_str(), "(sequence)")) {
|
nuclear@0
|
692
|
nuclear@0
|
693 // remove the (sequence) and append 000
|
nuclear@0
|
694 DefaultLogger::get()->info("LWOB: Sequence of animated texture found. It will be ignored");
|
nuclear@0
|
695 out = out.substr(0,out.length()-10) + "000";
|
nuclear@0
|
696 }
|
nuclear@0
|
697
|
nuclear@0
|
698 // format: drive:path/file - we just need to insert a slash after the drive
|
nuclear@0
|
699 std::string::size_type n = out.find_first_of(':');
|
nuclear@0
|
700 if (std::string::npos != n) {
|
nuclear@0
|
701 out.insert(n+1,"/");
|
nuclear@0
|
702 }
|
nuclear@0
|
703 }
|
nuclear@0
|
704
|
nuclear@0
|
705 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
706 void LWOImporter::LoadLWOTags(unsigned int size)
|
nuclear@0
|
707 {
|
nuclear@0
|
708 // --- this function is used for both LWO2 and LWOB
|
nuclear@0
|
709
|
nuclear@0
|
710 const char* szCur = (const char*)mFileBuffer, *szLast = szCur;
|
nuclear@0
|
711 const char* const szEnd = szLast+size;
|
nuclear@0
|
712 while (szCur < szEnd)
|
nuclear@0
|
713 {
|
nuclear@0
|
714 if (!(*szCur))
|
nuclear@0
|
715 {
|
nuclear@0
|
716 const size_t len = (size_t)(szCur-szLast);
|
nuclear@0
|
717 // FIX: skip empty-sized tags
|
nuclear@0
|
718 if (len)
|
nuclear@0
|
719 mTags->push_back(std::string(szLast,len));
|
nuclear@0
|
720 szCur += (len&0x1 ? 1 : 2);
|
nuclear@0
|
721 szLast = szCur;
|
nuclear@0
|
722 }
|
nuclear@0
|
723 szCur++;
|
nuclear@0
|
724 }
|
nuclear@0
|
725 }
|
nuclear@0
|
726
|
nuclear@0
|
727 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
728 void LWOImporter::LoadLWOPoints(unsigned int length)
|
nuclear@0
|
729 {
|
nuclear@0
|
730 // --- this function is used for both LWO2 and LWOB but for
|
nuclear@0
|
731 // LWO2 we need to allocate 25% more storage - it could be we'll
|
nuclear@0
|
732 // need to duplicate some points later.
|
nuclear@0
|
733 register unsigned int regularSize = (unsigned int)mCurLayer->mTempPoints.size() + length / 12;
|
nuclear@0
|
734 if (mIsLWO2)
|
nuclear@0
|
735 {
|
nuclear@0
|
736 mCurLayer->mTempPoints.reserve ( regularSize + (regularSize>>2u) );
|
nuclear@0
|
737 mCurLayer->mTempPoints.resize ( regularSize );
|
nuclear@0
|
738
|
nuclear@0
|
739 // initialize all point referrers with the default values
|
nuclear@0
|
740 mCurLayer->mPointReferrers.reserve ( regularSize + (regularSize>>2u) );
|
nuclear@0
|
741 mCurLayer->mPointReferrers.resize ( regularSize, UINT_MAX );
|
nuclear@0
|
742 }
|
nuclear@0
|
743 else mCurLayer->mTempPoints.resize( regularSize );
|
nuclear@0
|
744
|
nuclear@0
|
745 // perform endianess conversions
|
nuclear@0
|
746 #ifndef AI_BUILD_BIG_ENDIAN
|
nuclear@0
|
747 for (unsigned int i = 0; i < length>>2;++i)
|
nuclear@0
|
748 ByteSwap::Swap4( mFileBuffer + (i << 2));
|
nuclear@0
|
749 #endif
|
nuclear@0
|
750 ::memcpy(&mCurLayer->mTempPoints[0],mFileBuffer,length);
|
nuclear@0
|
751 }
|
nuclear@0
|
752
|
nuclear@0
|
753 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
754 void LWOImporter::LoadLWO2Polygons(unsigned int length)
|
nuclear@0
|
755 {
|
nuclear@0
|
756 LE_NCONST uint16_t* const end = (LE_NCONST uint16_t*)(mFileBuffer+length);
|
nuclear@0
|
757 const uint32_t type = GetU4();
|
nuclear@0
|
758
|
nuclear@0
|
759 // Determine the type of the polygons
|
nuclear@0
|
760 switch (type)
|
nuclear@0
|
761 {
|
nuclear@0
|
762 // read unsupported stuff too (although we wont process it)
|
nuclear@0
|
763 case AI_LWO_MBAL:
|
nuclear@0
|
764 DefaultLogger::get()->warn("LWO2: Encountered unsupported primitive chunk (METABALL)");
|
nuclear@0
|
765 break;
|
nuclear@0
|
766 case AI_LWO_CURV:
|
nuclear@0
|
767 DefaultLogger::get()->warn("LWO2: Encountered unsupported primitive chunk (SPLINE)");;
|
nuclear@0
|
768 break;
|
nuclear@0
|
769
|
nuclear@0
|
770 // These are ok with no restrictions
|
nuclear@0
|
771 case AI_LWO_PTCH:
|
nuclear@0
|
772 case AI_LWO_FACE:
|
nuclear@0
|
773 case AI_LWO_BONE:
|
nuclear@0
|
774 case AI_LWO_SUBD:
|
nuclear@0
|
775 break;
|
nuclear@0
|
776 default:
|
nuclear@0
|
777
|
nuclear@0
|
778 // hm!? wtf is this? ok ...
|
nuclear@0
|
779 DefaultLogger::get()->error("LWO2: Ignoring unknown polygon type.");
|
nuclear@0
|
780 break;
|
nuclear@0
|
781 }
|
nuclear@0
|
782
|
nuclear@0
|
783 // first find out how many faces and vertices we'll finally need
|
nuclear@0
|
784 uint16_t* cursor= (uint16_t*)mFileBuffer;
|
nuclear@0
|
785
|
nuclear@0
|
786 unsigned int iNumFaces = 0,iNumVertices = 0;
|
nuclear@0
|
787 CountVertsAndFacesLWO2(iNumVertices,iNumFaces,cursor,end);
|
nuclear@0
|
788
|
nuclear@0
|
789 // allocate the output array and copy face indices
|
nuclear@0
|
790 if (iNumFaces) {
|
nuclear@0
|
791 cursor = (uint16_t*)mFileBuffer;
|
nuclear@0
|
792
|
nuclear@0
|
793 mCurLayer->mFaces.resize(iNumFaces,LWO::Face(type));
|
nuclear@0
|
794 FaceList::iterator it = mCurLayer->mFaces.begin();
|
nuclear@0
|
795 CopyFaceIndicesLWO2(it,cursor,end);
|
nuclear@0
|
796 }
|
nuclear@0
|
797 }
|
nuclear@0
|
798
|
nuclear@0
|
799 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
800 void LWOImporter::CountVertsAndFacesLWO2(unsigned int& verts, unsigned int& faces,
|
nuclear@0
|
801 uint16_t*& cursor, const uint16_t* const end, unsigned int max)
|
nuclear@0
|
802 {
|
nuclear@0
|
803 while (cursor < end && max--)
|
nuclear@0
|
804 {
|
nuclear@0
|
805 AI_LSWAP2P(cursor);
|
nuclear@0
|
806 uint16_t numIndices = *cursor++;
|
nuclear@0
|
807 numIndices &= 0x03FF;
|
nuclear@0
|
808 verts += numIndices;++faces;
|
nuclear@0
|
809
|
nuclear@0
|
810 for(uint16_t i = 0; i < numIndices; i++)
|
nuclear@0
|
811 ReadVSizedIntLWO2((uint8_t*&)cursor);
|
nuclear@0
|
812 }
|
nuclear@0
|
813 }
|
nuclear@0
|
814
|
nuclear@0
|
815 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
816 void LWOImporter::CopyFaceIndicesLWO2(FaceList::iterator& it,
|
nuclear@0
|
817 uint16_t*& cursor,
|
nuclear@0
|
818 const uint16_t* const end)
|
nuclear@0
|
819 {
|
nuclear@0
|
820 while (cursor < end) {
|
nuclear@0
|
821
|
nuclear@0
|
822 LWO::Face& face = *it++;;
|
nuclear@0
|
823 if((face.mNumIndices = (*cursor++) & 0x03FF)) /* byte swapping has already been done */ {
|
nuclear@0
|
824 face.mIndices = new unsigned int[face.mNumIndices];
|
nuclear@0
|
825 for(unsigned int i = 0; i < face.mNumIndices; i++)
|
nuclear@0
|
826 {
|
nuclear@0
|
827 face.mIndices[i] = ReadVSizedIntLWO2((uint8_t*&)cursor) + mCurLayer->mPointIDXOfs;
|
nuclear@0
|
828 if(face.mIndices[i] > mCurLayer->mTempPoints.size())
|
nuclear@0
|
829 {
|
nuclear@0
|
830 DefaultLogger::get()->warn("LWO2: Failure evaluating face record, index is out of range");
|
nuclear@0
|
831 face.mIndices[i] = (unsigned int)mCurLayer->mTempPoints.size()-1;
|
nuclear@0
|
832 }
|
nuclear@0
|
833 }
|
nuclear@0
|
834 }
|
nuclear@0
|
835 else throw DeadlyImportError("LWO2: Encountered invalid face record with zero indices");
|
nuclear@0
|
836 }
|
nuclear@0
|
837 }
|
nuclear@0
|
838
|
nuclear@0
|
839
|
nuclear@0
|
840 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
841 void LWOImporter::LoadLWO2PolygonTags(unsigned int length)
|
nuclear@0
|
842 {
|
nuclear@0
|
843 LE_NCONST uint8_t* const end = mFileBuffer+length;
|
nuclear@0
|
844
|
nuclear@0
|
845 AI_LWO_VALIDATE_CHUNK_LENGTH(length,PTAG,4);
|
nuclear@0
|
846 uint32_t type = GetU4();
|
nuclear@0
|
847
|
nuclear@0
|
848 if (type != AI_LWO_SURF && type != AI_LWO_SMGP)
|
nuclear@0
|
849 return;
|
nuclear@0
|
850
|
nuclear@0
|
851 while (mFileBuffer < end) {
|
nuclear@0
|
852
|
nuclear@0
|
853 unsigned int i = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
|
nuclear@0
|
854 unsigned int j = GetU2();
|
nuclear@0
|
855
|
nuclear@0
|
856 if (i >= mCurLayer->mFaces.size()) {
|
nuclear@0
|
857 DefaultLogger::get()->warn("LWO2: face index in PTAG is out of range");
|
nuclear@0
|
858 continue;
|
nuclear@0
|
859 }
|
nuclear@0
|
860
|
nuclear@0
|
861 switch (type) {
|
nuclear@0
|
862
|
nuclear@0
|
863 case AI_LWO_SURF:
|
nuclear@0
|
864 mCurLayer->mFaces[i].surfaceIndex = j;
|
nuclear@0
|
865 break;
|
nuclear@0
|
866 case AI_LWO_SMGP: /* is that really used? */
|
nuclear@0
|
867 mCurLayer->mFaces[i].smoothGroup = j;
|
nuclear@0
|
868 break;
|
nuclear@0
|
869 };
|
nuclear@0
|
870 }
|
nuclear@0
|
871 }
|
nuclear@0
|
872
|
nuclear@0
|
873 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
874 template <class T>
|
nuclear@0
|
875 VMapEntry* FindEntry(std::vector< T >& list,const std::string& name, bool perPoly)
|
nuclear@0
|
876 {
|
nuclear@0
|
877 for (typename std::vector< T >::iterator it = list.begin(), end = list.end();it != end; ++it) {
|
nuclear@0
|
878 if ((*it).name == name) {
|
nuclear@0
|
879 if (!perPoly) {
|
nuclear@0
|
880 DefaultLogger::get()->warn("LWO2: Found two VMAP sections with equal names");
|
nuclear@0
|
881 }
|
nuclear@0
|
882 return &(*it);
|
nuclear@0
|
883 }
|
nuclear@0
|
884 }
|
nuclear@0
|
885 list.push_back( T() );
|
nuclear@0
|
886 VMapEntry* p = &list.back();
|
nuclear@0
|
887 p->name = name;
|
nuclear@0
|
888 return p;
|
nuclear@0
|
889 }
|
nuclear@0
|
890
|
nuclear@0
|
891 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
892 template <class T>
|
nuclear@0
|
893 inline void CreateNewEntry(T& chan, unsigned int srcIdx)
|
nuclear@0
|
894 {
|
nuclear@0
|
895 if (!chan.name.length())
|
nuclear@0
|
896 return;
|
nuclear@0
|
897
|
nuclear@0
|
898 chan.abAssigned[srcIdx] = true;
|
nuclear@0
|
899 chan.abAssigned.resize(chan.abAssigned.size()+1,false);
|
nuclear@0
|
900
|
nuclear@0
|
901 for (unsigned int a = 0; a < chan.dims;++a)
|
nuclear@0
|
902 chan.rawData.push_back(chan.rawData[srcIdx*chan.dims+a]);
|
nuclear@0
|
903 }
|
nuclear@0
|
904
|
nuclear@0
|
905 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
906 template <class T>
|
nuclear@0
|
907 inline void CreateNewEntry(std::vector< T >& list, unsigned int srcIdx)
|
nuclear@0
|
908 {
|
nuclear@0
|
909 for (typename std::vector< T >::iterator it = list.begin(), end = list.end();it != end;++it) {
|
nuclear@0
|
910 CreateNewEntry( *it, srcIdx );
|
nuclear@0
|
911 }
|
nuclear@0
|
912 }
|
nuclear@0
|
913
|
nuclear@0
|
914 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
915 inline void LWOImporter::DoRecursiveVMAPAssignment(VMapEntry* base, unsigned int numRead,
|
nuclear@0
|
916 unsigned int idx, float* data)
|
nuclear@0
|
917 {
|
nuclear@0
|
918 ai_assert(NULL != data);
|
nuclear@0
|
919 LWO::ReferrerList& refList = mCurLayer->mPointReferrers;
|
nuclear@0
|
920 unsigned int i;
|
nuclear@0
|
921
|
nuclear@0
|
922 base->abAssigned[idx] = true;
|
nuclear@0
|
923 for (i = 0; i < numRead;++i) {
|
nuclear@0
|
924 base->rawData[idx*base->dims+i]= data[i];
|
nuclear@0
|
925 }
|
nuclear@0
|
926
|
nuclear@0
|
927 if (UINT_MAX != (i = refList[idx])) {
|
nuclear@0
|
928 DoRecursiveVMAPAssignment(base,numRead,i,data);
|
nuclear@0
|
929 }
|
nuclear@0
|
930 }
|
nuclear@0
|
931
|
nuclear@0
|
932 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
933 inline void AddToSingleLinkedList(ReferrerList& refList, unsigned int srcIdx, unsigned int destIdx)
|
nuclear@0
|
934 {
|
nuclear@0
|
935 if(UINT_MAX == refList[srcIdx]) {
|
nuclear@0
|
936 refList[srcIdx] = destIdx;
|
nuclear@0
|
937 return;
|
nuclear@0
|
938 }
|
nuclear@0
|
939 AddToSingleLinkedList(refList,refList[srcIdx],destIdx);
|
nuclear@0
|
940 }
|
nuclear@0
|
941
|
nuclear@0
|
942 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
943 // Load LWO2 vertex map
|
nuclear@0
|
944 void LWOImporter::LoadLWO2VertexMap(unsigned int length, bool perPoly)
|
nuclear@0
|
945 {
|
nuclear@0
|
946 LE_NCONST uint8_t* const end = mFileBuffer+length;
|
nuclear@0
|
947
|
nuclear@0
|
948 AI_LWO_VALIDATE_CHUNK_LENGTH(length,VMAP,6);
|
nuclear@0
|
949 unsigned int type = GetU4();
|
nuclear@0
|
950 unsigned int dims = GetU2();
|
nuclear@0
|
951
|
nuclear@0
|
952 VMapEntry* base;
|
nuclear@0
|
953
|
nuclear@0
|
954 // read the name of the vertex map
|
nuclear@0
|
955 std::string name;
|
nuclear@0
|
956 GetS0(name,length);
|
nuclear@0
|
957
|
nuclear@0
|
958 switch (type)
|
nuclear@0
|
959 {
|
nuclear@0
|
960 case AI_LWO_TXUV:
|
nuclear@0
|
961 if (dims != 2) {
|
nuclear@0
|
962 DefaultLogger::get()->warn("LWO2: Skipping UV channel \'"
|
nuclear@0
|
963 + name + "\' with !2 components");
|
nuclear@0
|
964 return;
|
nuclear@0
|
965 }
|
nuclear@0
|
966 base = FindEntry(mCurLayer->mUVChannels,name,perPoly);
|
nuclear@0
|
967 break;
|
nuclear@0
|
968 case AI_LWO_WGHT:
|
nuclear@0
|
969 case AI_LWO_MNVW:
|
nuclear@0
|
970 if (dims != 1) {
|
nuclear@0
|
971 DefaultLogger::get()->warn("LWO2: Skipping Weight Channel \'"
|
nuclear@0
|
972 + name + "\' with !1 components");
|
nuclear@0
|
973 return;
|
nuclear@0
|
974 }
|
nuclear@0
|
975 base = FindEntry((type == AI_LWO_WGHT ? mCurLayer->mWeightChannels
|
nuclear@0
|
976 : mCurLayer->mSWeightChannels),name,perPoly);
|
nuclear@0
|
977 break;
|
nuclear@0
|
978 case AI_LWO_RGB:
|
nuclear@0
|
979 case AI_LWO_RGBA:
|
nuclear@0
|
980 if (dims != 3 && dims != 4) {
|
nuclear@0
|
981 DefaultLogger::get()->warn("LWO2: Skipping Color Map \'"
|
nuclear@0
|
982 + name + "\' with a dimension > 4 or < 3");
|
nuclear@0
|
983 return;
|
nuclear@0
|
984 }
|
nuclear@0
|
985 base = FindEntry(mCurLayer->mVColorChannels,name,perPoly);
|
nuclear@0
|
986 break;
|
nuclear@0
|
987
|
nuclear@0
|
988 case AI_LWO_MODO_NORM:
|
nuclear@0
|
989 /* This is a non-standard extension chunk used by Luxology's MODO.
|
nuclear@0
|
990 * It stores per-vertex normals. This VMAP exists just once, has
|
nuclear@0
|
991 * 3 dimensions and is btw extremely beautiful.
|
nuclear@0
|
992 */
|
nuclear@0
|
993 if (name != "vert_normals" || dims != 3 || mCurLayer->mNormals.name.length())
|
nuclear@0
|
994 return;
|
nuclear@0
|
995
|
nuclear@0
|
996 DefaultLogger::get()->info("Processing non-standard extension: MODO VMAP.NORM.vert_normals");
|
nuclear@0
|
997
|
nuclear@0
|
998 mCurLayer->mNormals.name = name;
|
nuclear@0
|
999 base = & mCurLayer->mNormals;
|
nuclear@0
|
1000 break;
|
nuclear@0
|
1001
|
nuclear@0
|
1002 case AI_LWO_PICK: /* these VMAPs are just silently dropped */
|
nuclear@0
|
1003 case AI_LWO_MORF:
|
nuclear@0
|
1004 case AI_LWO_SPOT:
|
nuclear@0
|
1005 return;
|
nuclear@0
|
1006
|
nuclear@0
|
1007 default:
|
nuclear@0
|
1008 if (name == "APS.Level") {
|
nuclear@0
|
1009 // XXX handle this (seems to be subdivision-related).
|
nuclear@0
|
1010 }
|
nuclear@0
|
1011 DefaultLogger::get()->warn("LWO2: Skipping unknown VMAP/VMAD channel \'" + name + "\'");
|
nuclear@0
|
1012 return;
|
nuclear@0
|
1013 };
|
nuclear@0
|
1014 base->Allocate((unsigned int)mCurLayer->mTempPoints.size());
|
nuclear@0
|
1015
|
nuclear@0
|
1016 // now read all entries in the map
|
nuclear@0
|
1017 type = std::min(dims,base->dims);
|
nuclear@0
|
1018 const unsigned int diff = (dims - type)<<2u;
|
nuclear@0
|
1019
|
nuclear@0
|
1020 LWO::FaceList& list = mCurLayer->mFaces;
|
nuclear@0
|
1021 LWO::PointList& pointList = mCurLayer->mTempPoints;
|
nuclear@0
|
1022 LWO::ReferrerList& refList = mCurLayer->mPointReferrers;
|
nuclear@0
|
1023
|
nuclear@0
|
1024 float temp[4];
|
nuclear@0
|
1025
|
nuclear@0
|
1026 const unsigned int numPoints = (unsigned int)pointList.size();
|
nuclear@0
|
1027 const unsigned int numFaces = (unsigned int)list.size();
|
nuclear@0
|
1028
|
nuclear@0
|
1029 while (mFileBuffer < end) {
|
nuclear@0
|
1030
|
nuclear@0
|
1031 unsigned int idx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mPointIDXOfs;
|
nuclear@0
|
1032 if (idx >= numPoints) {
|
nuclear@0
|
1033 DefaultLogger::get()->warn("LWO2: Failure evaluating VMAP/VMAD entry \'" + name + "\', vertex index is out of range");
|
nuclear@0
|
1034 mFileBuffer += base->dims<<2u;
|
nuclear@0
|
1035 continue;
|
nuclear@0
|
1036 }
|
nuclear@0
|
1037 if (perPoly) {
|
nuclear@0
|
1038 unsigned int polyIdx = ReadVSizedIntLWO2(mFileBuffer) + mCurLayer->mFaceIDXOfs;
|
nuclear@0
|
1039 if (base->abAssigned[idx]) {
|
nuclear@0
|
1040 // we have already a VMAP entry for this vertex - thus
|
nuclear@0
|
1041 // we need to duplicate the corresponding polygon.
|
nuclear@0
|
1042 if (polyIdx >= numFaces) {
|
nuclear@0
|
1043 DefaultLogger::get()->warn("LWO2: Failure evaluating VMAD entry \'" + name + "\', polygon index is out of range");
|
nuclear@0
|
1044 mFileBuffer += base->dims<<2u;
|
nuclear@0
|
1045 continue;
|
nuclear@0
|
1046 }
|
nuclear@0
|
1047
|
nuclear@0
|
1048 LWO::Face& src = list[polyIdx];
|
nuclear@0
|
1049
|
nuclear@0
|
1050 // generate a new unique vertex for the corresponding index - but only
|
nuclear@0
|
1051 // if we can find the index in the face
|
nuclear@0
|
1052 bool had = false;
|
nuclear@0
|
1053 for (unsigned int i = 0; i < src.mNumIndices;++i) {
|
nuclear@0
|
1054
|
nuclear@0
|
1055 unsigned int srcIdx = src.mIndices[i], tmp = idx;
|
nuclear@0
|
1056 do {
|
nuclear@0
|
1057 if (tmp == srcIdx)
|
nuclear@0
|
1058 break;
|
nuclear@0
|
1059 }
|
nuclear@0
|
1060 while ((tmp = refList[tmp]) != UINT_MAX);
|
nuclear@0
|
1061 if (tmp == UINT_MAX) {
|
nuclear@0
|
1062 continue;
|
nuclear@0
|
1063 }
|
nuclear@0
|
1064
|
nuclear@0
|
1065 had = true;
|
nuclear@0
|
1066 refList.resize(refList.size()+1, UINT_MAX);
|
nuclear@0
|
1067
|
nuclear@0
|
1068 idx = (unsigned int)pointList.size();
|
nuclear@0
|
1069 src.mIndices[i] = (unsigned int)pointList.size();
|
nuclear@0
|
1070
|
nuclear@0
|
1071 // store the index of the new vertex in the old vertex
|
nuclear@0
|
1072 // so we get a single linked list we can traverse in
|
nuclear@0
|
1073 // only one direction
|
nuclear@0
|
1074 AddToSingleLinkedList(refList,srcIdx,src.mIndices[i]);
|
nuclear@0
|
1075 pointList.push_back(pointList[srcIdx]);
|
nuclear@0
|
1076
|
nuclear@0
|
1077 CreateNewEntry(mCurLayer->mVColorChannels, srcIdx );
|
nuclear@0
|
1078 CreateNewEntry(mCurLayer->mUVChannels, srcIdx );
|
nuclear@0
|
1079 CreateNewEntry(mCurLayer->mWeightChannels, srcIdx );
|
nuclear@0
|
1080 CreateNewEntry(mCurLayer->mSWeightChannels, srcIdx );
|
nuclear@0
|
1081 CreateNewEntry(mCurLayer->mNormals, srcIdx );
|
nuclear@0
|
1082 }
|
nuclear@0
|
1083 if (!had) {
|
nuclear@0
|
1084 DefaultLogger::get()->warn("LWO2: Failure evaluating VMAD entry \'" + name + "\', vertex index wasn't found in that polygon");
|
nuclear@0
|
1085 ai_assert(had);
|
nuclear@0
|
1086 }
|
nuclear@0
|
1087 }
|
nuclear@0
|
1088 }
|
nuclear@0
|
1089 for (unsigned int l = 0; l < type;++l)
|
nuclear@0
|
1090 temp[l] = GetF4();
|
nuclear@0
|
1091
|
nuclear@0
|
1092 DoRecursiveVMAPAssignment(base,type,idx, temp);
|
nuclear@0
|
1093 mFileBuffer += diff;
|
nuclear@0
|
1094 }
|
nuclear@0
|
1095 }
|
nuclear@0
|
1096
|
nuclear@0
|
1097 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1098 // Load LWO2 clip
|
nuclear@0
|
1099 void LWOImporter::LoadLWO2Clip(unsigned int length)
|
nuclear@0
|
1100 {
|
nuclear@0
|
1101 AI_LWO_VALIDATE_CHUNK_LENGTH(length,CLIP,10);
|
nuclear@0
|
1102
|
nuclear@0
|
1103 mClips.push_back(LWO::Clip());
|
nuclear@0
|
1104 LWO::Clip& clip = mClips.back();
|
nuclear@0
|
1105
|
nuclear@0
|
1106 // first - get the index of the clip
|
nuclear@0
|
1107 clip.idx = GetU4();
|
nuclear@0
|
1108
|
nuclear@0
|
1109 IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
|
nuclear@0
|
1110 switch (head->type)
|
nuclear@0
|
1111 {
|
nuclear@0
|
1112 case AI_LWO_STIL:
|
nuclear@0
|
1113 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,STIL,1);
|
nuclear@0
|
1114
|
nuclear@0
|
1115 // "Normal" texture
|
nuclear@0
|
1116 GetS0(clip.path,head->length);
|
nuclear@0
|
1117 clip.type = Clip::STILL;
|
nuclear@0
|
1118 break;
|
nuclear@0
|
1119
|
nuclear@0
|
1120 case AI_LWO_ISEQ:
|
nuclear@0
|
1121 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,ISEQ,16);
|
nuclear@0
|
1122 // Image sequence. We'll later take the first.
|
nuclear@0
|
1123 {
|
nuclear@0
|
1124 uint8_t digits = GetU1(); mFileBuffer++;
|
nuclear@0
|
1125 int16_t offset = GetU2(); mFileBuffer+=4;
|
nuclear@0
|
1126 int16_t start = GetU2(); mFileBuffer+=4;
|
nuclear@0
|
1127
|
nuclear@0
|
1128 std::string s;
|
nuclear@0
|
1129 std::ostringstream ss;
|
nuclear@0
|
1130 GetS0(s,head->length);
|
nuclear@0
|
1131
|
nuclear@0
|
1132 head->length -= (unsigned int)s.length()+1;
|
nuclear@0
|
1133 ss << s;
|
nuclear@0
|
1134 ss << std::setw(digits) << offset + start;
|
nuclear@0
|
1135 GetS0(s,head->length);
|
nuclear@0
|
1136 ss << s;
|
nuclear@0
|
1137 clip.path = ss.str();
|
nuclear@0
|
1138 clip.type = Clip::SEQ;
|
nuclear@0
|
1139 }
|
nuclear@0
|
1140 break;
|
nuclear@0
|
1141
|
nuclear@0
|
1142 case AI_LWO_STCC:
|
nuclear@0
|
1143 DefaultLogger::get()->warn("LWO2: Color shifted images are not supported");
|
nuclear@0
|
1144 break;
|
nuclear@0
|
1145
|
nuclear@0
|
1146 case AI_LWO_ANIM:
|
nuclear@0
|
1147 DefaultLogger::get()->warn("LWO2: Animated textures are not supported");
|
nuclear@0
|
1148 break;
|
nuclear@0
|
1149
|
nuclear@0
|
1150 case AI_LWO_XREF:
|
nuclear@0
|
1151 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,XREF,4);
|
nuclear@0
|
1152
|
nuclear@0
|
1153 // Just a cross-reference to another CLIp
|
nuclear@0
|
1154 clip.type = Clip::REF;
|
nuclear@0
|
1155 clip.clipRef = GetU4();
|
nuclear@0
|
1156 break;
|
nuclear@0
|
1157
|
nuclear@0
|
1158 case AI_LWO_NEGA:
|
nuclear@0
|
1159 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,NEGA,2);
|
nuclear@0
|
1160 clip.negate = (0 != GetU2());
|
nuclear@0
|
1161 break;
|
nuclear@0
|
1162
|
nuclear@0
|
1163 default:
|
nuclear@0
|
1164 DefaultLogger::get()->warn("LWO2: Encountered unknown CLIP subchunk");
|
nuclear@0
|
1165 }
|
nuclear@0
|
1166 }
|
nuclear@0
|
1167
|
nuclear@0
|
1168 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1169 // Load envelope description
|
nuclear@0
|
1170 void LWOImporter::LoadLWO2Envelope(unsigned int length)
|
nuclear@0
|
1171 {
|
nuclear@0
|
1172 LE_NCONST uint8_t* const end = mFileBuffer + length;
|
nuclear@0
|
1173 AI_LWO_VALIDATE_CHUNK_LENGTH(length,ENVL,4);
|
nuclear@0
|
1174
|
nuclear@0
|
1175 mEnvelopes.push_back(LWO::Envelope());
|
nuclear@0
|
1176 LWO::Envelope& envelope = mEnvelopes.back();
|
nuclear@0
|
1177
|
nuclear@0
|
1178 // Get the index of the envelope
|
nuclear@0
|
1179 envelope.index = ReadVSizedIntLWO2(mFileBuffer);
|
nuclear@0
|
1180
|
nuclear@0
|
1181 // It looks like there might be an extra U4 right after the index,
|
nuclear@0
|
1182 // at least in modo (LXOB) files: we'll ignore it if it's zero,
|
nuclear@0
|
1183 // otherwise it represents the start of a subchunk, so we backtrack.
|
nuclear@0
|
1184 if (mIsLXOB)
|
nuclear@0
|
1185 {
|
nuclear@0
|
1186 uint32_t extra = GetU4();
|
nuclear@0
|
1187 if (extra)
|
nuclear@0
|
1188 {
|
nuclear@0
|
1189 mFileBuffer -= 4;
|
nuclear@0
|
1190 }
|
nuclear@0
|
1191 }
|
nuclear@0
|
1192
|
nuclear@0
|
1193 // ... and read all subchunks
|
nuclear@0
|
1194 while (true)
|
nuclear@0
|
1195 {
|
nuclear@0
|
1196 if (mFileBuffer + 6 >= end)break;
|
nuclear@0
|
1197 LE_NCONST IFF::SubChunkHeader* const head = IFF::LoadSubChunk(mFileBuffer);
|
nuclear@0
|
1198
|
nuclear@0
|
1199 if (mFileBuffer + head->length > end)
|
nuclear@0
|
1200 throw DeadlyImportError("LWO2: Invalid envelope chunk length");
|
nuclear@0
|
1201
|
nuclear@0
|
1202 uint8_t* const next = mFileBuffer+head->length;
|
nuclear@0
|
1203 switch (head->type)
|
nuclear@0
|
1204 {
|
nuclear@0
|
1205 // Type & representation of the envelope
|
nuclear@0
|
1206 case AI_LWO_TYPE:
|
nuclear@0
|
1207 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,TYPE,2);
|
nuclear@0
|
1208 mFileBuffer++; // skip user format
|
nuclear@0
|
1209
|
nuclear@0
|
1210 // Determine type of envelope
|
nuclear@0
|
1211 envelope.type = (LWO::EnvelopeType)*mFileBuffer;
|
nuclear@0
|
1212 ++mFileBuffer;
|
nuclear@0
|
1213 break;
|
nuclear@0
|
1214
|
nuclear@0
|
1215 // precondition
|
nuclear@0
|
1216 case AI_LWO_PRE:
|
nuclear@0
|
1217 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,PRE,2);
|
nuclear@0
|
1218 envelope.pre = (LWO::PrePostBehaviour)GetU2();
|
nuclear@0
|
1219 break;
|
nuclear@0
|
1220
|
nuclear@0
|
1221 // postcondition
|
nuclear@0
|
1222 case AI_LWO_POST:
|
nuclear@0
|
1223 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,POST,2);
|
nuclear@0
|
1224 envelope.post = (LWO::PrePostBehaviour)GetU2();
|
nuclear@0
|
1225 break;
|
nuclear@0
|
1226
|
nuclear@0
|
1227 // keyframe
|
nuclear@0
|
1228 case AI_LWO_KEY:
|
nuclear@0
|
1229 {
|
nuclear@0
|
1230 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,KEY,8);
|
nuclear@0
|
1231
|
nuclear@0
|
1232 envelope.keys.push_back(LWO::Key());
|
nuclear@0
|
1233 LWO::Key& key = envelope.keys.back();
|
nuclear@0
|
1234
|
nuclear@0
|
1235 key.time = GetF4();
|
nuclear@0
|
1236 key.value = GetF4();
|
nuclear@0
|
1237 break;
|
nuclear@0
|
1238 }
|
nuclear@0
|
1239
|
nuclear@0
|
1240 // interval interpolation
|
nuclear@0
|
1241 case AI_LWO_SPAN:
|
nuclear@0
|
1242 {
|
nuclear@0
|
1243 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,SPAN,4);
|
nuclear@0
|
1244 if (envelope.keys.size()<2)
|
nuclear@0
|
1245 DefaultLogger::get()->warn("LWO2: Unexpected SPAN chunk");
|
nuclear@0
|
1246 else {
|
nuclear@0
|
1247 LWO::Key& key = envelope.keys.back();
|
nuclear@0
|
1248 switch (GetU4())
|
nuclear@0
|
1249 {
|
nuclear@0
|
1250 case AI_LWO_STEP:
|
nuclear@0
|
1251 key.inter = LWO::IT_STEP;break;
|
nuclear@0
|
1252 case AI_LWO_LINE:
|
nuclear@0
|
1253 key.inter = LWO::IT_LINE;break;
|
nuclear@0
|
1254 case AI_LWO_TCB:
|
nuclear@0
|
1255 key.inter = LWO::IT_TCB;break;
|
nuclear@0
|
1256 case AI_LWO_HERM:
|
nuclear@0
|
1257 key.inter = LWO::IT_HERM;break;
|
nuclear@0
|
1258 case AI_LWO_BEZI:
|
nuclear@0
|
1259 key.inter = LWO::IT_BEZI;break;
|
nuclear@0
|
1260 case AI_LWO_BEZ2:
|
nuclear@0
|
1261 key.inter = LWO::IT_BEZ2;break;
|
nuclear@0
|
1262 default:
|
nuclear@0
|
1263 DefaultLogger::get()->warn("LWO2: Unknown interval interpolation mode");
|
nuclear@0
|
1264 };
|
nuclear@0
|
1265
|
nuclear@0
|
1266 // todo ... read params
|
nuclear@0
|
1267 }
|
nuclear@0
|
1268 break;
|
nuclear@0
|
1269 }
|
nuclear@0
|
1270
|
nuclear@0
|
1271 default:
|
nuclear@0
|
1272 DefaultLogger::get()->warn("LWO2: Encountered unknown ENVL subchunk");
|
nuclear@0
|
1273 }
|
nuclear@0
|
1274 // regardless how much we did actually read, go to the next chunk
|
nuclear@0
|
1275 mFileBuffer = next;
|
nuclear@0
|
1276 }
|
nuclear@0
|
1277 }
|
nuclear@0
|
1278
|
nuclear@0
|
1279 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
1280 // Load file - master function
|
nuclear@0
|
1281 void LWOImporter::LoadLWO2File()
|
nuclear@0
|
1282 {
|
nuclear@0
|
1283 bool skip = false;
|
nuclear@0
|
1284
|
nuclear@0
|
1285 LE_NCONST uint8_t* const end = mFileBuffer + fileSize;
|
nuclear@0
|
1286 while (true)
|
nuclear@0
|
1287 {
|
nuclear@0
|
1288 if (mFileBuffer + sizeof(IFF::ChunkHeader) > end)break;
|
nuclear@0
|
1289 IFF::ChunkHeader* const head = IFF::LoadChunk(mFileBuffer);
|
nuclear@0
|
1290
|
nuclear@0
|
1291 if (mFileBuffer + head->length > end)
|
nuclear@0
|
1292 {
|
nuclear@0
|
1293 throw DeadlyImportError("LWO2: Chunk length points behind the file");
|
nuclear@0
|
1294 break;
|
nuclear@0
|
1295 }
|
nuclear@0
|
1296 uint8_t* const next = mFileBuffer+head->length;
|
nuclear@0
|
1297 unsigned int iUnnamed = 0;
|
nuclear@0
|
1298
|
nuclear@0
|
1299 switch (head->type)
|
nuclear@0
|
1300 {
|
nuclear@0
|
1301 // new layer
|
nuclear@0
|
1302 case AI_LWO_LAYR:
|
nuclear@0
|
1303 {
|
nuclear@0
|
1304 // add a new layer to the list ....
|
nuclear@0
|
1305 mLayers->push_back ( LWO::Layer() );
|
nuclear@0
|
1306 LWO::Layer& layer = mLayers->back();
|
nuclear@0
|
1307 mCurLayer = &layer;
|
nuclear@0
|
1308
|
nuclear@0
|
1309 AI_LWO_VALIDATE_CHUNK_LENGTH(head->length,LAYR,16);
|
nuclear@0
|
1310
|
nuclear@0
|
1311 // layer index.
|
nuclear@0
|
1312 layer.mIndex = GetU2();
|
nuclear@0
|
1313
|
nuclear@0
|
1314 // Continue loading this layer or ignore it? Check the layer index property
|
nuclear@0
|
1315 if (UINT_MAX != configLayerIndex && (configLayerIndex-1) != layer.mIndex) {
|
nuclear@0
|
1316 skip = true;
|
nuclear@0
|
1317 }
|
nuclear@0
|
1318 else skip = false;
|
nuclear@0
|
1319
|
nuclear@0
|
1320 // pivot point
|
nuclear@0
|
1321 mFileBuffer += 2; /* unknown */
|
nuclear@0
|
1322 mCurLayer->mPivot.x = GetF4();
|
nuclear@0
|
1323 mCurLayer->mPivot.y = GetF4();
|
nuclear@0
|
1324 mCurLayer->mPivot.z = GetF4();
|
nuclear@0
|
1325 GetS0(layer.mName,head->length-16);
|
nuclear@0
|
1326
|
nuclear@0
|
1327 // if the name is empty, generate a default name
|
nuclear@0
|
1328 if (layer.mName.empty()) {
|
nuclear@0
|
1329 char buffer[128]; // should be sufficiently large
|
nuclear@0
|
1330 ::sprintf(buffer,"Layer_%i", iUnnamed++);
|
nuclear@0
|
1331 layer.mName = buffer;
|
nuclear@0
|
1332 }
|
nuclear@0
|
1333
|
nuclear@0
|
1334 // load this layer or ignore it? Check the layer name property
|
nuclear@0
|
1335 if (configLayerName.length() && configLayerName != layer.mName) {
|
nuclear@0
|
1336 skip = true;
|
nuclear@0
|
1337 }
|
nuclear@0
|
1338 else hasNamedLayer = true;
|
nuclear@0
|
1339
|
nuclear@0
|
1340 // optional: parent of this layer
|
nuclear@0
|
1341 if (mFileBuffer + 2 <= next)
|
nuclear@0
|
1342 layer.mParent = GetU2();
|
nuclear@0
|
1343 else layer.mParent = -1;
|
nuclear@0
|
1344
|
nuclear@0
|
1345 // Set layer skip parameter
|
nuclear@0
|
1346 layer.skip = skip;
|
nuclear@0
|
1347
|
nuclear@0
|
1348 break;
|
nuclear@0
|
1349 }
|
nuclear@0
|
1350
|
nuclear@0
|
1351 // vertex list
|
nuclear@0
|
1352 case AI_LWO_PNTS:
|
nuclear@0
|
1353 {
|
nuclear@0
|
1354 if (skip)
|
nuclear@0
|
1355 break;
|
nuclear@0
|
1356
|
nuclear@0
|
1357 unsigned int old = (unsigned int)mCurLayer->mTempPoints.size();
|
nuclear@0
|
1358 LoadLWOPoints(head->length);
|
nuclear@0
|
1359 mCurLayer->mPointIDXOfs = old;
|
nuclear@0
|
1360 break;
|
nuclear@0
|
1361 }
|
nuclear@0
|
1362 // vertex tags
|
nuclear@0
|
1363 case AI_LWO_VMAD:
|
nuclear@0
|
1364 if (mCurLayer->mFaces.empty())
|
nuclear@0
|
1365 {
|
nuclear@0
|
1366 DefaultLogger::get()->warn("LWO2: Unexpected VMAD chunk");
|
nuclear@0
|
1367 break;
|
nuclear@0
|
1368 }
|
nuclear@0
|
1369 // --- intentionally no break here
|
nuclear@0
|
1370 case AI_LWO_VMAP:
|
nuclear@0
|
1371 {
|
nuclear@0
|
1372 if (skip)
|
nuclear@0
|
1373 break;
|
nuclear@0
|
1374
|
nuclear@0
|
1375 if (mCurLayer->mTempPoints.empty())
|
nuclear@0
|
1376 DefaultLogger::get()->warn("LWO2: Unexpected VMAP chunk");
|
nuclear@0
|
1377 else LoadLWO2VertexMap(head->length,head->type == AI_LWO_VMAD);
|
nuclear@0
|
1378 break;
|
nuclear@0
|
1379 }
|
nuclear@0
|
1380 // face list
|
nuclear@0
|
1381 case AI_LWO_POLS:
|
nuclear@0
|
1382 {
|
nuclear@0
|
1383 if (skip)
|
nuclear@0
|
1384 break;
|
nuclear@0
|
1385
|
nuclear@0
|
1386 unsigned int old = (unsigned int)mCurLayer->mFaces.size();
|
nuclear@0
|
1387 LoadLWO2Polygons(head->length);
|
nuclear@0
|
1388 mCurLayer->mFaceIDXOfs = old;
|
nuclear@0
|
1389 break;
|
nuclear@0
|
1390 }
|
nuclear@0
|
1391 // polygon tags
|
nuclear@0
|
1392 case AI_LWO_PTAG:
|
nuclear@0
|
1393 {
|
nuclear@0
|
1394 if (skip)
|
nuclear@0
|
1395 break;
|
nuclear@0
|
1396
|
nuclear@0
|
1397 if (mCurLayer->mFaces.empty())
|
nuclear@0
|
1398 DefaultLogger::get()->warn("LWO2: Unexpected PTAG");
|
nuclear@0
|
1399 else LoadLWO2PolygonTags(head->length);
|
nuclear@0
|
1400 break;
|
nuclear@0
|
1401 }
|
nuclear@0
|
1402 // list of tags
|
nuclear@0
|
1403 case AI_LWO_TAGS:
|
nuclear@0
|
1404 {
|
nuclear@0
|
1405 if (!mTags->empty())
|
nuclear@0
|
1406 DefaultLogger::get()->warn("LWO2: SRFS chunk encountered twice");
|
nuclear@0
|
1407 else LoadLWOTags(head->length);
|
nuclear@0
|
1408 break;
|
nuclear@0
|
1409 }
|
nuclear@0
|
1410
|
nuclear@0
|
1411 // surface chunk
|
nuclear@0
|
1412 case AI_LWO_SURF:
|
nuclear@0
|
1413 {
|
nuclear@0
|
1414 LoadLWO2Surface(head->length);
|
nuclear@0
|
1415 break;
|
nuclear@0
|
1416 }
|
nuclear@0
|
1417
|
nuclear@0
|
1418 // clip chunk
|
nuclear@0
|
1419 case AI_LWO_CLIP:
|
nuclear@0
|
1420 {
|
nuclear@0
|
1421 LoadLWO2Clip(head->length);
|
nuclear@0
|
1422 break;
|
nuclear@0
|
1423 }
|
nuclear@0
|
1424
|
nuclear@0
|
1425 // envelope chunk
|
nuclear@0
|
1426 case AI_LWO_ENVL:
|
nuclear@0
|
1427 {
|
nuclear@0
|
1428 LoadLWO2Envelope(head->length);
|
nuclear@0
|
1429 break;
|
nuclear@0
|
1430 }
|
nuclear@0
|
1431 }
|
nuclear@0
|
1432 mFileBuffer = next;
|
nuclear@0
|
1433 }
|
nuclear@0
|
1434 }
|
nuclear@0
|
1435
|
nuclear@0
|
1436 #endif // !! ASSIMP_BUILD_NO_LWO_IMPORTER
|