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 LWSLoader.cpp
|
nuclear@0
|
43 * @brief Implementation of the LWS importer class
|
nuclear@0
|
44 */
|
nuclear@0
|
45
|
nuclear@0
|
46 #include "AssimpPCH.h"
|
nuclear@0
|
47 #ifndef ASSIMP_BUILD_NO_LWS_IMPORTER
|
nuclear@0
|
48
|
nuclear@0
|
49 #include "LWSLoader.h"
|
nuclear@0
|
50 #include "ParsingUtils.h"
|
nuclear@0
|
51 #include "fast_atof.h"
|
nuclear@0
|
52
|
nuclear@0
|
53 #include "SceneCombiner.h"
|
nuclear@0
|
54 #include "GenericProperty.h"
|
nuclear@0
|
55 #include "SkeletonMeshBuilder.h"
|
nuclear@0
|
56 #include "ConvertToLHProcess.h"
|
nuclear@0
|
57 #include "Importer.h"
|
nuclear@0
|
58
|
nuclear@0
|
59 using namespace Assimp;
|
nuclear@0
|
60
|
nuclear@0
|
61 static const aiImporterDesc desc = {
|
nuclear@0
|
62 "LightWave Scene Importer",
|
nuclear@0
|
63 "",
|
nuclear@0
|
64 "",
|
nuclear@0
|
65 "http://www.newtek.com/lightwave.html=",
|
nuclear@0
|
66 aiImporterFlags_SupportTextFlavour,
|
nuclear@0
|
67 0,
|
nuclear@0
|
68 0,
|
nuclear@0
|
69 0,
|
nuclear@0
|
70 0,
|
nuclear@0
|
71 "lws mot"
|
nuclear@0
|
72 };
|
nuclear@0
|
73
|
nuclear@0
|
74 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
75 // Recursive parsing of LWS files
|
nuclear@0
|
76 void LWS::Element::Parse (const char*& buffer)
|
nuclear@0
|
77 {
|
nuclear@0
|
78 for (;SkipSpacesAndLineEnd(&buffer);SkipLine(&buffer)) {
|
nuclear@0
|
79
|
nuclear@0
|
80 // begin of a new element with children
|
nuclear@0
|
81 bool sub = false;
|
nuclear@0
|
82 if (*buffer == '{') {
|
nuclear@0
|
83 ++buffer;
|
nuclear@0
|
84 SkipSpaces(&buffer);
|
nuclear@0
|
85 sub = true;
|
nuclear@0
|
86 }
|
nuclear@0
|
87 else if (*buffer == '}')
|
nuclear@0
|
88 return;
|
nuclear@0
|
89
|
nuclear@0
|
90 children.push_back(Element());
|
nuclear@0
|
91
|
nuclear@0
|
92 // copy data line - read token per token
|
nuclear@0
|
93
|
nuclear@0
|
94 const char* cur = buffer;
|
nuclear@0
|
95 while (!IsSpaceOrNewLine(*buffer)) ++buffer;
|
nuclear@0
|
96 children.back().tokens[0] = std::string(cur,(size_t) (buffer-cur));
|
nuclear@0
|
97 SkipSpaces(&buffer);
|
nuclear@0
|
98
|
nuclear@0
|
99 if (children.back().tokens[0] == "Plugin")
|
nuclear@0
|
100 {
|
nuclear@0
|
101 DefaultLogger::get()->debug("LWS: Skipping over plugin-specific data");
|
nuclear@0
|
102
|
nuclear@0
|
103 // strange stuff inside Plugin/Endplugin blocks. Needn't
|
nuclear@0
|
104 // follow LWS syntax, so we skip over it
|
nuclear@0
|
105 for (;SkipSpacesAndLineEnd(&buffer);SkipLine(&buffer)) {
|
nuclear@0
|
106 if (!::strncmp(buffer,"EndPlugin",9)) {
|
nuclear@0
|
107 //SkipLine(&buffer);
|
nuclear@0
|
108 break;
|
nuclear@0
|
109 }
|
nuclear@0
|
110 }
|
nuclear@0
|
111 continue;
|
nuclear@0
|
112 }
|
nuclear@0
|
113
|
nuclear@0
|
114 cur = buffer;
|
nuclear@0
|
115 while (!IsLineEnd(*buffer)) ++buffer;
|
nuclear@0
|
116 children.back().tokens[1] = std::string(cur,(size_t) (buffer-cur));
|
nuclear@0
|
117
|
nuclear@0
|
118 // parse more elements recursively
|
nuclear@0
|
119 if (sub)
|
nuclear@0
|
120 children.back().Parse(buffer);
|
nuclear@0
|
121 }
|
nuclear@0
|
122 }
|
nuclear@0
|
123
|
nuclear@0
|
124 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
125 // Constructor to be privately used by Importer
|
nuclear@0
|
126 LWSImporter::LWSImporter()
|
nuclear@0
|
127 : noSkeletonMesh()
|
nuclear@0
|
128 {
|
nuclear@0
|
129 // nothing to do here
|
nuclear@0
|
130 }
|
nuclear@0
|
131
|
nuclear@0
|
132 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
133 // Destructor, private as well
|
nuclear@0
|
134 LWSImporter::~LWSImporter()
|
nuclear@0
|
135 {
|
nuclear@0
|
136 // nothing to do here
|
nuclear@0
|
137 }
|
nuclear@0
|
138
|
nuclear@0
|
139 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
140 // Returns whether the class can handle the format of the given file.
|
nuclear@0
|
141 bool LWSImporter::CanRead( const std::string& pFile, IOSystem* pIOHandler,bool checkSig) const
|
nuclear@0
|
142 {
|
nuclear@0
|
143 const std::string extension = GetExtension(pFile);
|
nuclear@0
|
144 if (extension == "lws" || extension == "mot")
|
nuclear@0
|
145 return true;
|
nuclear@0
|
146
|
nuclear@0
|
147 // if check for extension is not enough, check for the magic tokens LWSC and LWMO
|
nuclear@0
|
148 if (!extension.length() || checkSig) {
|
nuclear@0
|
149 uint32_t tokens[2];
|
nuclear@0
|
150 tokens[0] = AI_MAKE_MAGIC("LWSC");
|
nuclear@0
|
151 tokens[1] = AI_MAKE_MAGIC("LWMO");
|
nuclear@0
|
152 return CheckMagicToken(pIOHandler,pFile,tokens,2);
|
nuclear@0
|
153 }
|
nuclear@0
|
154 return false;
|
nuclear@0
|
155 }
|
nuclear@0
|
156
|
nuclear@0
|
157 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
158 // Get list of file extensions
|
nuclear@0
|
159 const aiImporterDesc* LWSImporter::GetInfo () const
|
nuclear@0
|
160 {
|
nuclear@0
|
161 return &desc;
|
nuclear@0
|
162 }
|
nuclear@0
|
163
|
nuclear@0
|
164 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
165 // Setup configuration properties
|
nuclear@0
|
166 void LWSImporter::SetupProperties(const Importer* pImp)
|
nuclear@0
|
167 {
|
nuclear@0
|
168 // AI_CONFIG_FAVOUR_SPEED
|
nuclear@0
|
169 configSpeedFlag = (0 != pImp->GetPropertyInteger(AI_CONFIG_FAVOUR_SPEED,0));
|
nuclear@0
|
170
|
nuclear@0
|
171 // AI_CONFIG_IMPORT_LWS_ANIM_START
|
nuclear@0
|
172 first = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_START,
|
nuclear@0
|
173 150392 /* magic hack */);
|
nuclear@0
|
174
|
nuclear@0
|
175 // AI_CONFIG_IMPORT_LWS_ANIM_END
|
nuclear@0
|
176 last = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_LWS_ANIM_END,
|
nuclear@0
|
177 150392 /* magic hack */);
|
nuclear@0
|
178
|
nuclear@0
|
179 if (last < first) {
|
nuclear@0
|
180 std::swap(last,first);
|
nuclear@0
|
181 }
|
nuclear@0
|
182
|
nuclear@0
|
183 noSkeletonMesh = pImp->GetPropertyInteger(AI_CONFIG_IMPORT_NO_SKELETON_MESHES,0) != 0;
|
nuclear@0
|
184 }
|
nuclear@0
|
185
|
nuclear@0
|
186 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
187 // Read an envelope description
|
nuclear@0
|
188 void LWSImporter::ReadEnvelope(const LWS::Element& dad, LWO::Envelope& fill )
|
nuclear@0
|
189 {
|
nuclear@0
|
190 if (dad.children.empty()) {
|
nuclear@0
|
191 DefaultLogger::get()->error("LWS: Envelope descriptions must not be empty");
|
nuclear@0
|
192 return;
|
nuclear@0
|
193 }
|
nuclear@0
|
194
|
nuclear@0
|
195 // reserve enough storage
|
nuclear@0
|
196 std::list< LWS::Element >::const_iterator it = dad.children.begin();;
|
nuclear@0
|
197 fill.keys.reserve(strtoul10(it->tokens[1].c_str()));
|
nuclear@0
|
198
|
nuclear@0
|
199 for (++it; it != dad.children.end(); ++it) {
|
nuclear@0
|
200 const char* c = (*it).tokens[1].c_str();
|
nuclear@0
|
201
|
nuclear@0
|
202 if ((*it).tokens[0] == "Key") {
|
nuclear@0
|
203 fill.keys.push_back(LWO::Key());
|
nuclear@0
|
204 LWO::Key& key = fill.keys.back();
|
nuclear@0
|
205
|
nuclear@0
|
206 float f;
|
nuclear@0
|
207 SkipSpaces(&c);
|
nuclear@0
|
208 c = fast_atoreal_move<float>(c,key.value);
|
nuclear@0
|
209 SkipSpaces(&c);
|
nuclear@0
|
210 c = fast_atoreal_move<float>(c,f);
|
nuclear@0
|
211
|
nuclear@0
|
212 key.time = f;
|
nuclear@0
|
213
|
nuclear@0
|
214 unsigned int span = strtoul10(c,&c), num = 0;
|
nuclear@0
|
215 switch (span) {
|
nuclear@0
|
216
|
nuclear@0
|
217 case 0:
|
nuclear@0
|
218 key.inter = LWO::IT_TCB;
|
nuclear@0
|
219 num = 5;
|
nuclear@0
|
220 break;
|
nuclear@0
|
221 case 1:
|
nuclear@0
|
222 case 2:
|
nuclear@0
|
223 key.inter = LWO::IT_HERM;
|
nuclear@0
|
224 num = 5;
|
nuclear@0
|
225 break;
|
nuclear@0
|
226 case 3:
|
nuclear@0
|
227 key.inter = LWO::IT_LINE;
|
nuclear@0
|
228 num = 0;
|
nuclear@0
|
229 break;
|
nuclear@0
|
230 case 4:
|
nuclear@0
|
231 key.inter = LWO::IT_STEP;
|
nuclear@0
|
232 num = 0;
|
nuclear@0
|
233 break;
|
nuclear@0
|
234 case 5:
|
nuclear@0
|
235 key.inter = LWO::IT_BEZ2;
|
nuclear@0
|
236 num = 4;
|
nuclear@0
|
237 break;
|
nuclear@0
|
238 default:
|
nuclear@0
|
239 DefaultLogger::get()->error("LWS: Unknown span type");
|
nuclear@0
|
240 }
|
nuclear@0
|
241 for (unsigned int i = 0; i < num;++i) {
|
nuclear@0
|
242 SkipSpaces(&c);
|
nuclear@0
|
243 c = fast_atoreal_move<float>(c,key.params[i]);
|
nuclear@0
|
244 }
|
nuclear@0
|
245 }
|
nuclear@0
|
246 else if ((*it).tokens[0] == "Behaviors") {
|
nuclear@0
|
247 SkipSpaces(&c);
|
nuclear@0
|
248 fill.pre = (LWO::PrePostBehaviour) strtoul10(c,&c);
|
nuclear@0
|
249 SkipSpaces(&c);
|
nuclear@0
|
250 fill.post = (LWO::PrePostBehaviour) strtoul10(c,&c);
|
nuclear@0
|
251 }
|
nuclear@0
|
252 }
|
nuclear@0
|
253 }
|
nuclear@0
|
254
|
nuclear@0
|
255 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
256 // Read animation channels in the old LightWave animation format
|
nuclear@0
|
257 void LWSImporter::ReadEnvelope_Old(
|
nuclear@0
|
258 std::list< LWS::Element >::const_iterator& it,
|
nuclear@0
|
259 const std::list< LWS::Element >::const_iterator& end,
|
nuclear@0
|
260 LWS::NodeDesc& nodes,
|
nuclear@0
|
261 unsigned int /*version*/)
|
nuclear@0
|
262 {
|
nuclear@0
|
263 unsigned int num,sub_num;
|
nuclear@0
|
264 if (++it == end)goto unexpected_end;
|
nuclear@0
|
265
|
nuclear@0
|
266 num = strtoul10((*it).tokens[0].c_str());
|
nuclear@0
|
267 for (unsigned int i = 0; i < num; ++i) {
|
nuclear@0
|
268
|
nuclear@0
|
269 nodes.channels.push_back(LWO::Envelope());
|
nuclear@0
|
270 LWO::Envelope& envl = nodes.channels.back();
|
nuclear@0
|
271
|
nuclear@0
|
272 envl.index = i;
|
nuclear@0
|
273 envl.type = (LWO::EnvelopeType)(i+1);
|
nuclear@0
|
274
|
nuclear@0
|
275 if (++it == end)goto unexpected_end;
|
nuclear@0
|
276 sub_num = strtoul10((*it).tokens[0].c_str());
|
nuclear@0
|
277
|
nuclear@0
|
278 for (unsigned int n = 0; n < sub_num;++n) {
|
nuclear@0
|
279
|
nuclear@0
|
280 if (++it == end)goto unexpected_end;
|
nuclear@0
|
281
|
nuclear@0
|
282 // parse value and time, skip the rest for the moment.
|
nuclear@0
|
283 LWO::Key key;
|
nuclear@0
|
284 const char* c = fast_atoreal_move<float>((*it).tokens[0].c_str(),key.value);
|
nuclear@0
|
285 SkipSpaces(&c);
|
nuclear@0
|
286 float f;
|
nuclear@0
|
287 fast_atoreal_move<float>((*it).tokens[0].c_str(),f);
|
nuclear@0
|
288 key.time = f;
|
nuclear@0
|
289
|
nuclear@0
|
290 envl.keys.push_back(key);
|
nuclear@0
|
291 }
|
nuclear@0
|
292 }
|
nuclear@0
|
293 return;
|
nuclear@0
|
294
|
nuclear@0
|
295 unexpected_end:
|
nuclear@0
|
296 DefaultLogger::get()->error("LWS: Encountered unexpected end of file while parsing object motion");
|
nuclear@0
|
297 }
|
nuclear@0
|
298
|
nuclear@0
|
299 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
300 // Setup a nice name for a node
|
nuclear@0
|
301 void LWSImporter::SetupNodeName(aiNode* nd, LWS::NodeDesc& src)
|
nuclear@0
|
302 {
|
nuclear@0
|
303 const unsigned int combined = src.number | ((unsigned int)src.type) << 28u;
|
nuclear@0
|
304
|
nuclear@0
|
305 // the name depends on the type. We break LWS's strange naming convention
|
nuclear@0
|
306 // and return human-readable, but still machine-parsable and unique, strings.
|
nuclear@0
|
307 if (src.type == LWS::NodeDesc::OBJECT) {
|
nuclear@0
|
308
|
nuclear@0
|
309 if (src.path.length()) {
|
nuclear@0
|
310 std::string::size_type s = src.path.find_last_of("\\/");
|
nuclear@0
|
311 if (s == std::string::npos)
|
nuclear@0
|
312 s = 0;
|
nuclear@0
|
313 else ++s;
|
nuclear@0
|
314 std::string::size_type t = src.path.substr(s).find_last_of(".");
|
nuclear@0
|
315
|
nuclear@0
|
316 nd->mName.length = ::sprintf(nd->mName.data,"%s_(%08X)",src.path.substr(s).substr(0,t).c_str(),combined);
|
nuclear@0
|
317 return;
|
nuclear@0
|
318 }
|
nuclear@0
|
319 }
|
nuclear@0
|
320 nd->mName.length = ::sprintf(nd->mName.data,"%s_(%08X)",src.name,combined);
|
nuclear@0
|
321 }
|
nuclear@0
|
322
|
nuclear@0
|
323 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
324 // Recursively build the scenegraph
|
nuclear@0
|
325 void LWSImporter::BuildGraph(aiNode* nd, LWS::NodeDesc& src, std::vector<AttachmentInfo>& attach,
|
nuclear@0
|
326 BatchLoader& batch,
|
nuclear@0
|
327 aiCamera**& camOut,
|
nuclear@0
|
328 aiLight**& lightOut,
|
nuclear@0
|
329 std::vector<aiNodeAnim*>& animOut)
|
nuclear@0
|
330 {
|
nuclear@0
|
331 // Setup a very cryptic name for the node, we want the user to be happy
|
nuclear@0
|
332 SetupNodeName(nd,src);
|
nuclear@0
|
333 aiNode* ndAnim = nd;
|
nuclear@0
|
334
|
nuclear@0
|
335 // If the node is an object
|
nuclear@0
|
336 if (src.type == LWS::NodeDesc::OBJECT) {
|
nuclear@0
|
337
|
nuclear@0
|
338 // If the object is from an external file, get it
|
nuclear@0
|
339 aiScene* obj = NULL;
|
nuclear@0
|
340 if (src.path.length() ) {
|
nuclear@0
|
341 obj = batch.GetImport(src.id);
|
nuclear@0
|
342 if (!obj) {
|
nuclear@0
|
343 DefaultLogger::get()->error("LWS: Failed to read external file " + src.path);
|
nuclear@0
|
344 }
|
nuclear@0
|
345 else {
|
nuclear@0
|
346 if (obj->mRootNode->mNumChildren == 1) {
|
nuclear@0
|
347
|
nuclear@0
|
348 //If the pivot is not set for this layer, get it from the external object
|
nuclear@0
|
349 if (!src.isPivotSet) {
|
nuclear@0
|
350 src.pivotPos.x = +obj->mRootNode->mTransformation.a4;
|
nuclear@0
|
351 src.pivotPos.y = +obj->mRootNode->mTransformation.b4;
|
nuclear@0
|
352 src.pivotPos.z = -obj->mRootNode->mTransformation.c4; //The sign is the RH to LH back conversion
|
nuclear@0
|
353 }
|
nuclear@0
|
354
|
nuclear@0
|
355 //Remove first node from obj (the old pivot), reset transform of second node (the mesh node)
|
nuclear@0
|
356 aiNode* newRootNode = obj->mRootNode->mChildren[0];
|
nuclear@0
|
357 obj->mRootNode->mChildren[0] = NULL;
|
nuclear@0
|
358 delete obj->mRootNode;
|
nuclear@0
|
359
|
nuclear@0
|
360 obj->mRootNode = newRootNode;
|
nuclear@0
|
361 obj->mRootNode->mTransformation.a4 = 0.0;
|
nuclear@0
|
362 obj->mRootNode->mTransformation.b4 = 0.0;
|
nuclear@0
|
363 obj->mRootNode->mTransformation.c4 = 0.0;
|
nuclear@0
|
364 }
|
nuclear@0
|
365 }
|
nuclear@0
|
366 }
|
nuclear@0
|
367
|
nuclear@0
|
368 //Setup the pivot node (also the animation node), the one we received
|
nuclear@0
|
369 nd->mName = std::string("Pivot:") + nd->mName.data;
|
nuclear@0
|
370 ndAnim = nd;
|
nuclear@0
|
371
|
nuclear@0
|
372 //Add the attachment node to it
|
nuclear@0
|
373 nd->mNumChildren = 1;
|
nuclear@0
|
374 nd->mChildren = new aiNode*[1];
|
nuclear@0
|
375 nd->mChildren[0] = new aiNode();
|
nuclear@0
|
376 nd->mChildren[0]->mParent = nd;
|
nuclear@0
|
377 nd->mChildren[0]->mTransformation.a4 = -src.pivotPos.x;
|
nuclear@0
|
378 nd->mChildren[0]->mTransformation.b4 = -src.pivotPos.y;
|
nuclear@0
|
379 nd->mChildren[0]->mTransformation.c4 = -src.pivotPos.z;
|
nuclear@0
|
380 SetupNodeName(nd->mChildren[0], src);
|
nuclear@0
|
381
|
nuclear@0
|
382 //Update the attachment node
|
nuclear@0
|
383 nd = nd->mChildren[0];
|
nuclear@0
|
384
|
nuclear@0
|
385 //Push attachment, if the object came from an external file
|
nuclear@0
|
386 if (obj) {
|
nuclear@0
|
387 attach.push_back(AttachmentInfo(obj,nd));
|
nuclear@0
|
388 }
|
nuclear@0
|
389 }
|
nuclear@0
|
390
|
nuclear@0
|
391 // If object is a light source - setup a corresponding ai structure
|
nuclear@0
|
392 else if (src.type == LWS::NodeDesc::LIGHT) {
|
nuclear@0
|
393 aiLight* lit = *lightOut++ = new aiLight();
|
nuclear@0
|
394
|
nuclear@0
|
395 // compute final light color
|
nuclear@0
|
396 lit->mColorDiffuse = lit->mColorSpecular = src.lightColor*src.lightIntensity;
|
nuclear@0
|
397
|
nuclear@0
|
398 // name to attach light to node -> unique due to LWs indexing system
|
nuclear@0
|
399 lit->mName = nd->mName;
|
nuclear@0
|
400
|
nuclear@0
|
401 // detemine light type and setup additional members
|
nuclear@0
|
402 if (src.lightType == 2) { /* spot light */
|
nuclear@0
|
403
|
nuclear@0
|
404 lit->mType = aiLightSource_SPOT;
|
nuclear@0
|
405 lit->mAngleInnerCone = (float)AI_DEG_TO_RAD( src.lightConeAngle );
|
nuclear@0
|
406 lit->mAngleOuterCone = lit->mAngleInnerCone+(float)AI_DEG_TO_RAD( src.lightEdgeAngle );
|
nuclear@0
|
407
|
nuclear@0
|
408 }
|
nuclear@0
|
409 else if (src.lightType == 1) { /* directional light source */
|
nuclear@0
|
410 lit->mType = aiLightSource_DIRECTIONAL;
|
nuclear@0
|
411 }
|
nuclear@0
|
412 else lit->mType = aiLightSource_POINT;
|
nuclear@0
|
413
|
nuclear@0
|
414 // fixme: no proper handling of light falloffs yet
|
nuclear@0
|
415 if (src.lightFalloffType == 1)
|
nuclear@0
|
416 lit->mAttenuationConstant = 1.f;
|
nuclear@0
|
417 else if (src.lightFalloffType == 1)
|
nuclear@0
|
418 lit->mAttenuationLinear = 1.f;
|
nuclear@0
|
419 else
|
nuclear@0
|
420 lit->mAttenuationQuadratic = 1.f;
|
nuclear@0
|
421 }
|
nuclear@0
|
422
|
nuclear@0
|
423 // If object is a camera - setup a corresponding ai structure
|
nuclear@0
|
424 else if (src.type == LWS::NodeDesc::CAMERA) {
|
nuclear@0
|
425 aiCamera* cam = *camOut++ = new aiCamera();
|
nuclear@0
|
426
|
nuclear@0
|
427 // name to attach cam to node -> unique due to LWs indexing system
|
nuclear@0
|
428 cam->mName = nd->mName;
|
nuclear@0
|
429 }
|
nuclear@0
|
430
|
nuclear@0
|
431 // Get the node transformation from the LWO key
|
nuclear@0
|
432 LWO::AnimResolver resolver(src.channels,fps);
|
nuclear@0
|
433 resolver.ExtractBindPose(ndAnim->mTransformation);
|
nuclear@0
|
434
|
nuclear@0
|
435 // .. and construct animation channels
|
nuclear@0
|
436 aiNodeAnim* anim = NULL;
|
nuclear@0
|
437
|
nuclear@0
|
438 if (first != last) {
|
nuclear@0
|
439 resolver.SetAnimationRange(first,last);
|
nuclear@0
|
440 resolver.ExtractAnimChannel(&anim,AI_LWO_ANIM_FLAG_SAMPLE_ANIMS|AI_LWO_ANIM_FLAG_START_AT_ZERO);
|
nuclear@0
|
441 if (anim) {
|
nuclear@0
|
442 anim->mNodeName = ndAnim->mName;
|
nuclear@0
|
443 animOut.push_back(anim);
|
nuclear@0
|
444 }
|
nuclear@0
|
445 }
|
nuclear@0
|
446
|
nuclear@0
|
447 // Add children
|
nuclear@0
|
448 if (src.children.size()) {
|
nuclear@0
|
449 nd->mChildren = new aiNode*[src.children.size()];
|
nuclear@0
|
450 for (std::list<LWS::NodeDesc*>::iterator it = src.children.begin(); it != src.children.end(); ++it) {
|
nuclear@0
|
451 aiNode* ndd = nd->mChildren[nd->mNumChildren++] = new aiNode();
|
nuclear@0
|
452 ndd->mParent = nd;
|
nuclear@0
|
453
|
nuclear@0
|
454 BuildGraph(ndd,**it,attach,batch,camOut,lightOut,animOut);
|
nuclear@0
|
455 }
|
nuclear@0
|
456 }
|
nuclear@0
|
457 }
|
nuclear@0
|
458
|
nuclear@0
|
459 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
460 // Determine the exact location of a LWO file
|
nuclear@0
|
461 std::string LWSImporter::FindLWOFile(const std::string& in)
|
nuclear@0
|
462 {
|
nuclear@0
|
463 // insert missing directory seperator if necessary
|
nuclear@0
|
464 std::string tmp;
|
nuclear@0
|
465 if (in.length() > 3 && in[1] == ':'&& in[2] != '\\' && in[2] != '/')
|
nuclear@0
|
466 {
|
nuclear@0
|
467 tmp = in[0] + (":\\" + in.substr(2));
|
nuclear@0
|
468 }
|
nuclear@0
|
469 else tmp = in;
|
nuclear@0
|
470
|
nuclear@0
|
471 if (io->Exists(tmp)) {
|
nuclear@0
|
472 return in;
|
nuclear@0
|
473 }
|
nuclear@0
|
474
|
nuclear@0
|
475 // file is not accessible for us ... maybe it's packed by
|
nuclear@0
|
476 // LightWave's 'Package Scene' command?
|
nuclear@0
|
477
|
nuclear@0
|
478 // Relevant for us are the following two directories:
|
nuclear@0
|
479 // <folder>\Objects\<hh>\<*>.lwo
|
nuclear@0
|
480 // <folder>\Scenes\<hh>\<*>.lws
|
nuclear@0
|
481 // where <hh> is optional.
|
nuclear@0
|
482
|
nuclear@0
|
483 std::string test = ".." + (io->getOsSeparator() + tmp);
|
nuclear@0
|
484 if (io->Exists(test)) {
|
nuclear@0
|
485 return test;
|
nuclear@0
|
486 }
|
nuclear@0
|
487
|
nuclear@0
|
488 test = ".." + (io->getOsSeparator() + test);
|
nuclear@0
|
489 if (io->Exists(test)) {
|
nuclear@0
|
490 return test;
|
nuclear@0
|
491 }
|
nuclear@0
|
492
|
nuclear@0
|
493
|
nuclear@0
|
494 // return original path, maybe the IOsystem knows better
|
nuclear@0
|
495 return tmp;
|
nuclear@0
|
496 }
|
nuclear@0
|
497
|
nuclear@0
|
498 // ------------------------------------------------------------------------------------------------
|
nuclear@0
|
499 // Read file into given scene data structure
|
nuclear@0
|
500 void LWSImporter::InternReadFile( const std::string& pFile, aiScene* pScene,
|
nuclear@0
|
501 IOSystem* pIOHandler)
|
nuclear@0
|
502 {
|
nuclear@0
|
503 io = pIOHandler;
|
nuclear@0
|
504 boost::scoped_ptr<IOStream> file( pIOHandler->Open( pFile, "rb"));
|
nuclear@0
|
505
|
nuclear@0
|
506 // Check whether we can read from the file
|
nuclear@0
|
507 if( file.get() == NULL) {
|
nuclear@0
|
508 throw DeadlyImportError( "Failed to open LWS file " + pFile + ".");
|
nuclear@0
|
509 }
|
nuclear@0
|
510
|
nuclear@0
|
511 // Allocate storage and copy the contents of the file to a memory buffer
|
nuclear@0
|
512 std::vector< char > mBuffer;
|
nuclear@0
|
513 TextFileToBuffer(file.get(),mBuffer);
|
nuclear@0
|
514
|
nuclear@0
|
515 // Parse the file structure
|
nuclear@0
|
516 LWS::Element root; const char* dummy = &mBuffer[0];
|
nuclear@0
|
517 root.Parse(dummy);
|
nuclear@0
|
518
|
nuclear@0
|
519 // Construct a Batchimporter to read more files recursively
|
nuclear@0
|
520 BatchLoader batch(pIOHandler);
|
nuclear@0
|
521 // batch.SetBasePath(pFile);
|
nuclear@0
|
522
|
nuclear@0
|
523 // Construct an array to receive the flat output graph
|
nuclear@0
|
524 std::list<LWS::NodeDesc> nodes;
|
nuclear@0
|
525
|
nuclear@0
|
526 unsigned int cur_light = 0, cur_camera = 0, cur_object = 0;
|
nuclear@0
|
527 unsigned int num_light = 0, num_camera = 0, num_object = 0;
|
nuclear@0
|
528
|
nuclear@0
|
529 // check magic identifier, 'LWSC'
|
nuclear@0
|
530 bool motion_file = false;
|
nuclear@0
|
531 std::list< LWS::Element >::const_iterator it = root.children.begin();
|
nuclear@0
|
532
|
nuclear@0
|
533 if ((*it).tokens[0] == "LWMO")
|
nuclear@0
|
534 motion_file = true;
|
nuclear@0
|
535
|
nuclear@0
|
536 if ((*it).tokens[0] != "LWSC" && !motion_file)
|
nuclear@0
|
537 throw DeadlyImportError("LWS: Not a LightWave scene, magic tag LWSC not found");
|
nuclear@0
|
538
|
nuclear@0
|
539 // get file format version and print to log
|
nuclear@0
|
540 ++it;
|
nuclear@0
|
541 unsigned int version = strtoul10((*it).tokens[0].c_str());
|
nuclear@0
|
542 DefaultLogger::get()->info("LWS file format version is " + (*it).tokens[0]);
|
nuclear@0
|
543 first = 0.;
|
nuclear@0
|
544 last = 60.;
|
nuclear@0
|
545 fps = 25.; /* seems to be a good default frame rate */
|
nuclear@0
|
546
|
nuclear@0
|
547 // Now read all elements in a very straghtforward manner
|
nuclear@0
|
548 for (; it != root.children.end(); ++it) {
|
nuclear@0
|
549 const char* c = (*it).tokens[1].c_str();
|
nuclear@0
|
550
|
nuclear@0
|
551 // 'FirstFrame': begin of animation slice
|
nuclear@0
|
552 if ((*it).tokens[0] == "FirstFrame") {
|
nuclear@0
|
553 if (150392. != first /* see SetupProperties() */)
|
nuclear@0
|
554 first = strtoul10(c,&c)-1.; /* we're zero-based */
|
nuclear@0
|
555 }
|
nuclear@0
|
556
|
nuclear@0
|
557 // 'LastFrame': end of animation slice
|
nuclear@0
|
558 else if ((*it).tokens[0] == "LastFrame") {
|
nuclear@0
|
559 if (150392. != last /* see SetupProperties() */)
|
nuclear@0
|
560 last = strtoul10(c,&c)-1.; /* we're zero-based */
|
nuclear@0
|
561 }
|
nuclear@0
|
562
|
nuclear@0
|
563 // 'FramesPerSecond': frames per second
|
nuclear@0
|
564 else if ((*it).tokens[0] == "FramesPerSecond") {
|
nuclear@0
|
565 fps = strtoul10(c,&c);
|
nuclear@0
|
566 }
|
nuclear@0
|
567
|
nuclear@0
|
568 // 'LoadObjectLayer': load a layer of a specific LWO file
|
nuclear@0
|
569 else if ((*it).tokens[0] == "LoadObjectLayer") {
|
nuclear@0
|
570
|
nuclear@0
|
571 // get layer index
|
nuclear@0
|
572 const int layer = strtoul10(c,&c);
|
nuclear@0
|
573
|
nuclear@0
|
574 // setup the layer to be loaded
|
nuclear@0
|
575 BatchLoader::PropertyMap props;
|
nuclear@0
|
576 SetGenericProperty(props.ints,AI_CONFIG_IMPORT_LWO_ONE_LAYER_ONLY,layer);
|
nuclear@0
|
577
|
nuclear@0
|
578 // add node to list
|
nuclear@0
|
579 LWS::NodeDesc d;
|
nuclear@0
|
580 d.type = LWS::NodeDesc::OBJECT;
|
nuclear@0
|
581 if (version >= 4) { // handle LWSC 4 explicit ID
|
nuclear@0
|
582 SkipSpaces(&c);
|
nuclear@0
|
583 d.number = strtoul16(c,&c) & AI_LWS_MASK;
|
nuclear@0
|
584 }
|
nuclear@0
|
585 else d.number = cur_object++;
|
nuclear@0
|
586
|
nuclear@0
|
587 // and add the file to the import list
|
nuclear@0
|
588 SkipSpaces(&c);
|
nuclear@0
|
589 std::string path = FindLWOFile( c );
|
nuclear@0
|
590 d.path = path;
|
nuclear@0
|
591 d.id = batch.AddLoadRequest(path,0,&props);
|
nuclear@0
|
592
|
nuclear@0
|
593 nodes.push_back(d);
|
nuclear@0
|
594 num_object++;
|
nuclear@0
|
595 }
|
nuclear@0
|
596 // 'LoadObject': load a LWO file into the scenegraph
|
nuclear@0
|
597 else if ((*it).tokens[0] == "LoadObject") {
|
nuclear@0
|
598
|
nuclear@0
|
599 // add node to list
|
nuclear@0
|
600 LWS::NodeDesc d;
|
nuclear@0
|
601 d.type = LWS::NodeDesc::OBJECT;
|
nuclear@0
|
602
|
nuclear@0
|
603 if (version >= 4) { // handle LWSC 4 explicit ID
|
nuclear@0
|
604 d.number = strtoul16(c,&c) & AI_LWS_MASK;
|
nuclear@0
|
605 SkipSpaces(&c);
|
nuclear@0
|
606 }
|
nuclear@0
|
607 else d.number = cur_object++;
|
nuclear@0
|
608 std::string path = FindLWOFile( c );
|
nuclear@0
|
609 d.id = batch.AddLoadRequest(path,0,NULL);
|
nuclear@0
|
610
|
nuclear@0
|
611 d.path = path;
|
nuclear@0
|
612 nodes.push_back(d);
|
nuclear@0
|
613 num_object++;
|
nuclear@0
|
614 }
|
nuclear@0
|
615 // 'AddNullObject': add a dummy node to the hierarchy
|
nuclear@0
|
616 else if ((*it).tokens[0] == "AddNullObject") {
|
nuclear@0
|
617
|
nuclear@0
|
618 // add node to list
|
nuclear@0
|
619 LWS::NodeDesc d;
|
nuclear@0
|
620 d.type = LWS::NodeDesc::OBJECT;
|
nuclear@0
|
621 if (version >= 4) { // handle LWSC 4 explicit ID
|
nuclear@0
|
622 d.number = strtoul16(c,&c) & AI_LWS_MASK;
|
nuclear@0
|
623 SkipSpaces(&c);
|
nuclear@0
|
624 }
|
nuclear@0
|
625 else d.number = cur_object++;
|
nuclear@0
|
626 d.name = c;
|
nuclear@0
|
627 nodes.push_back(d);
|
nuclear@0
|
628
|
nuclear@0
|
629 num_object++;
|
nuclear@0
|
630 }
|
nuclear@0
|
631 // 'NumChannels': Number of envelope channels assigned to last layer
|
nuclear@0
|
632 else if ((*it).tokens[0] == "NumChannels") {
|
nuclear@0
|
633 // ignore for now
|
nuclear@0
|
634 }
|
nuclear@0
|
635 // 'Channel': preceedes any envelope description
|
nuclear@0
|
636 else if ((*it).tokens[0] == "Channel") {
|
nuclear@0
|
637 if (nodes.empty()) {
|
nuclear@0
|
638 if (motion_file) {
|
nuclear@0
|
639
|
nuclear@0
|
640 // LightWave motion file. Add dummy node
|
nuclear@0
|
641 LWS::NodeDesc d;
|
nuclear@0
|
642 d.type = LWS::NodeDesc::OBJECT;
|
nuclear@0
|
643 d.name = c;
|
nuclear@0
|
644 d.number = cur_object++;
|
nuclear@0
|
645 nodes.push_back(d);
|
nuclear@0
|
646 }
|
nuclear@0
|
647 else DefaultLogger::get()->error("LWS: Unexpected keyword: \'Channel\'");
|
nuclear@0
|
648 }
|
nuclear@0
|
649
|
nuclear@0
|
650 // important: index of channel
|
nuclear@0
|
651 nodes.back().channels.push_back(LWO::Envelope());
|
nuclear@0
|
652 LWO::Envelope& env = nodes.back().channels.back();
|
nuclear@0
|
653
|
nuclear@0
|
654 env.index = strtoul10(c);
|
nuclear@0
|
655
|
nuclear@0
|
656 // currently we can just interpret the standard channels 0...9
|
nuclear@0
|
657 // (hack) assume that index-i yields the binary channel type from LWO
|
nuclear@0
|
658 env.type = (LWO::EnvelopeType)(env.index+1);
|
nuclear@0
|
659
|
nuclear@0
|
660 }
|
nuclear@0
|
661 // 'Envelope': a single animation channel
|
nuclear@0
|
662 else if ((*it).tokens[0] == "Envelope") {
|
nuclear@0
|
663 if (nodes.empty() || nodes.back().channels.empty())
|
nuclear@0
|
664 DefaultLogger::get()->error("LWS: Unexpected keyword: \'Envelope\'");
|
nuclear@0
|
665 else {
|
nuclear@0
|
666 ReadEnvelope((*it),nodes.back().channels.back());
|
nuclear@0
|
667 }
|
nuclear@0
|
668 }
|
nuclear@0
|
669 // 'ObjectMotion': animation information for older lightwave formats
|
nuclear@0
|
670 else if (version < 3 && ((*it).tokens[0] == "ObjectMotion" ||
|
nuclear@0
|
671 (*it).tokens[0] == "CameraMotion" ||
|
nuclear@0
|
672 (*it).tokens[0] == "LightMotion")) {
|
nuclear@0
|
673
|
nuclear@0
|
674 if (nodes.empty())
|
nuclear@0
|
675 DefaultLogger::get()->error("LWS: Unexpected keyword: \'<Light|Object|Camera>Motion\'");
|
nuclear@0
|
676 else {
|
nuclear@0
|
677 ReadEnvelope_Old(it,root.children.end(),nodes.back(),version);
|
nuclear@0
|
678 }
|
nuclear@0
|
679 }
|
nuclear@0
|
680 // 'Pre/PostBehavior': pre/post animation behaviour for LWSC 2
|
nuclear@0
|
681 else if (version == 2 && (*it).tokens[0] == "Pre/PostBehavior") {
|
nuclear@0
|
682 if (nodes.empty())
|
nuclear@0
|
683 DefaultLogger::get()->error("LWS: Unexpected keyword: \'Pre/PostBehavior'");
|
nuclear@0
|
684 else {
|
nuclear@0
|
685 for (std::list<LWO::Envelope>::iterator it = nodes.back().channels.begin(); it != nodes.back().channels.end(); ++it) {
|
nuclear@0
|
686 // two ints per envelope
|
nuclear@0
|
687 LWO::Envelope& env = *it;
|
nuclear@0
|
688 env.pre = (LWO::PrePostBehaviour) strtoul10(c,&c); SkipSpaces(&c);
|
nuclear@0
|
689 env.post = (LWO::PrePostBehaviour) strtoul10(c,&c); SkipSpaces(&c);
|
nuclear@0
|
690 }
|
nuclear@0
|
691 }
|
nuclear@0
|
692 }
|
nuclear@0
|
693 // 'ParentItem': specifies the parent of the current element
|
nuclear@0
|
694 else if ((*it).tokens[0] == "ParentItem") {
|
nuclear@0
|
695 if (nodes.empty())
|
nuclear@0
|
696 DefaultLogger::get()->error("LWS: Unexpected keyword: \'ParentItem\'");
|
nuclear@0
|
697
|
nuclear@0
|
698 else nodes.back().parent = strtoul16(c,&c);
|
nuclear@0
|
699 }
|
nuclear@0
|
700 // 'ParentObject': deprecated one for older formats
|
nuclear@0
|
701 else if (version < 3 && (*it).tokens[0] == "ParentObject") {
|
nuclear@0
|
702 if (nodes.empty())
|
nuclear@0
|
703 DefaultLogger::get()->error("LWS: Unexpected keyword: \'ParentObject\'");
|
nuclear@0
|
704
|
nuclear@0
|
705 else {
|
nuclear@0
|
706 nodes.back().parent = strtoul10(c,&c) | (1u << 28u);
|
nuclear@0
|
707 }
|
nuclear@0
|
708 }
|
nuclear@0
|
709 // 'AddCamera': add a camera to the scenegraph
|
nuclear@0
|
710 else if ((*it).tokens[0] == "AddCamera") {
|
nuclear@0
|
711
|
nuclear@0
|
712 // add node to list
|
nuclear@0
|
713 LWS::NodeDesc d;
|
nuclear@0
|
714 d.type = LWS::NodeDesc::CAMERA;
|
nuclear@0
|
715
|
nuclear@0
|
716 if (version >= 4) { // handle LWSC 4 explicit ID
|
nuclear@0
|
717 d.number = strtoul16(c,&c) & AI_LWS_MASK;
|
nuclear@0
|
718 }
|
nuclear@0
|
719 else d.number = cur_camera++;
|
nuclear@0
|
720 nodes.push_back(d);
|
nuclear@0
|
721
|
nuclear@0
|
722 num_camera++;
|
nuclear@0
|
723 }
|
nuclear@0
|
724 // 'CameraName': set name of currently active camera
|
nuclear@0
|
725 else if ((*it).tokens[0] == "CameraName") {
|
nuclear@0
|
726 if (nodes.empty() || nodes.back().type != LWS::NodeDesc::CAMERA)
|
nuclear@0
|
727 DefaultLogger::get()->error("LWS: Unexpected keyword: \'CameraName\'");
|
nuclear@0
|
728
|
nuclear@0
|
729 else nodes.back().name = c;
|
nuclear@0
|
730 }
|
nuclear@0
|
731 // 'AddLight': add a light to the scenegraph
|
nuclear@0
|
732 else if ((*it).tokens[0] == "AddLight") {
|
nuclear@0
|
733
|
nuclear@0
|
734 // add node to list
|
nuclear@0
|
735 LWS::NodeDesc d;
|
nuclear@0
|
736 d.type = LWS::NodeDesc::LIGHT;
|
nuclear@0
|
737
|
nuclear@0
|
738 if (version >= 4) { // handle LWSC 4 explicit ID
|
nuclear@0
|
739 d.number = strtoul16(c,&c) & AI_LWS_MASK;
|
nuclear@0
|
740 }
|
nuclear@0
|
741 else d.number = cur_light++;
|
nuclear@0
|
742 nodes.push_back(d);
|
nuclear@0
|
743
|
nuclear@0
|
744 num_light++;
|
nuclear@0
|
745 }
|
nuclear@0
|
746 // 'LightName': set name of currently active light
|
nuclear@0
|
747 else if ((*it).tokens[0] == "LightName") {
|
nuclear@0
|
748 if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
|
nuclear@0
|
749 DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightName\'");
|
nuclear@0
|
750
|
nuclear@0
|
751 else nodes.back().name = c;
|
nuclear@0
|
752 }
|
nuclear@0
|
753 // 'LightIntensity': set intensity of currently active light
|
nuclear@0
|
754 else if ((*it).tokens[0] == "LightIntensity" || (*it).tokens[0] == "LgtIntensity" ) {
|
nuclear@0
|
755 if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
|
nuclear@0
|
756 DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightIntensity\'");
|
nuclear@0
|
757
|
nuclear@0
|
758 else fast_atoreal_move<float>(c, nodes.back().lightIntensity );
|
nuclear@0
|
759
|
nuclear@0
|
760 }
|
nuclear@0
|
761 // 'LightType': set type of currently active light
|
nuclear@0
|
762 else if ((*it).tokens[0] == "LightType") {
|
nuclear@0
|
763 if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
|
nuclear@0
|
764 DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightType\'");
|
nuclear@0
|
765
|
nuclear@0
|
766 else nodes.back().lightType = strtoul10(c);
|
nuclear@0
|
767
|
nuclear@0
|
768 }
|
nuclear@0
|
769 // 'LightFalloffType': set falloff type of currently active light
|
nuclear@0
|
770 else if ((*it).tokens[0] == "LightFalloffType") {
|
nuclear@0
|
771 if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
|
nuclear@0
|
772 DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightFalloffType\'");
|
nuclear@0
|
773
|
nuclear@0
|
774 else nodes.back().lightFalloffType = strtoul10(c);
|
nuclear@0
|
775
|
nuclear@0
|
776 }
|
nuclear@0
|
777 // 'LightConeAngle': set cone angle of currently active light
|
nuclear@0
|
778 else if ((*it).tokens[0] == "LightConeAngle") {
|
nuclear@0
|
779 if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
|
nuclear@0
|
780 DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightConeAngle\'");
|
nuclear@0
|
781
|
nuclear@0
|
782 else nodes.back().lightConeAngle = fast_atof(c);
|
nuclear@0
|
783
|
nuclear@0
|
784 }
|
nuclear@0
|
785 // 'LightEdgeAngle': set area where we're smoothing from min to max intensity
|
nuclear@0
|
786 else if ((*it).tokens[0] == "LightEdgeAngle") {
|
nuclear@0
|
787 if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
|
nuclear@0
|
788 DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightEdgeAngle\'");
|
nuclear@0
|
789
|
nuclear@0
|
790 else nodes.back().lightEdgeAngle = fast_atof(c);
|
nuclear@0
|
791
|
nuclear@0
|
792 }
|
nuclear@0
|
793 // 'LightColor': set color of currently active light
|
nuclear@0
|
794 else if ((*it).tokens[0] == "LightColor") {
|
nuclear@0
|
795 if (nodes.empty() || nodes.back().type != LWS::NodeDesc::LIGHT)
|
nuclear@0
|
796 DefaultLogger::get()->error("LWS: Unexpected keyword: \'LightColor\'");
|
nuclear@0
|
797
|
nuclear@0
|
798 else {
|
nuclear@0
|
799 c = fast_atoreal_move<float>(c, (float&) nodes.back().lightColor.r );
|
nuclear@0
|
800 SkipSpaces(&c);
|
nuclear@0
|
801 c = fast_atoreal_move<float>(c, (float&) nodes.back().lightColor.g );
|
nuclear@0
|
802 SkipSpaces(&c);
|
nuclear@0
|
803 c = fast_atoreal_move<float>(c, (float&) nodes.back().lightColor.b );
|
nuclear@0
|
804 }
|
nuclear@0
|
805 }
|
nuclear@0
|
806
|
nuclear@0
|
807 // 'PivotPosition': position of local transformation origin
|
nuclear@0
|
808 else if ((*it).tokens[0] == "PivotPosition" || (*it).tokens[0] == "PivotPoint") {
|
nuclear@0
|
809 if (nodes.empty())
|
nuclear@0
|
810 DefaultLogger::get()->error("LWS: Unexpected keyword: \'PivotPosition\'");
|
nuclear@0
|
811 else {
|
nuclear@0
|
812 c = fast_atoreal_move<float>(c, (float&) nodes.back().pivotPos.x );
|
nuclear@0
|
813 SkipSpaces(&c);
|
nuclear@0
|
814 c = fast_atoreal_move<float>(c, (float&) nodes.back().pivotPos.y );
|
nuclear@0
|
815 SkipSpaces(&c);
|
nuclear@0
|
816 c = fast_atoreal_move<float>(c, (float&) nodes.back().pivotPos.z );
|
nuclear@0
|
817 // Mark pivotPos as set
|
nuclear@0
|
818 nodes.back().isPivotSet = true;
|
nuclear@0
|
819 }
|
nuclear@0
|
820 }
|
nuclear@0
|
821 }
|
nuclear@0
|
822
|
nuclear@0
|
823 // resolve parenting
|
nuclear@0
|
824 for (std::list<LWS::NodeDesc>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
|
nuclear@0
|
825
|
nuclear@0
|
826 // check whether there is another node which calls us a parent
|
nuclear@0
|
827 for (std::list<LWS::NodeDesc>::iterator dit = nodes.begin(); dit != nodes.end(); ++dit) {
|
nuclear@0
|
828 if (dit != it && *it == (*dit).parent) {
|
nuclear@0
|
829 if ((*dit).parent_resolved) {
|
nuclear@0
|
830 // fixme: it's still possible to produce an overflow due to cross references ..
|
nuclear@0
|
831 DefaultLogger::get()->error("LWS: Found cross reference in scenegraph");
|
nuclear@0
|
832 continue;
|
nuclear@0
|
833 }
|
nuclear@0
|
834
|
nuclear@0
|
835 (*it).children.push_back(&*dit);
|
nuclear@0
|
836 (*dit).parent_resolved = &*it;
|
nuclear@0
|
837 }
|
nuclear@0
|
838 }
|
nuclear@0
|
839 }
|
nuclear@0
|
840
|
nuclear@0
|
841 // find out how many nodes have no parent yet
|
nuclear@0
|
842 unsigned int no_parent = 0;
|
nuclear@0
|
843 for (std::list<LWS::NodeDesc>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
|
nuclear@0
|
844 if (!(*it).parent_resolved)
|
nuclear@0
|
845 ++ no_parent;
|
nuclear@0
|
846 }
|
nuclear@0
|
847 if (!no_parent)
|
nuclear@0
|
848 throw DeadlyImportError("LWS: Unable to find scene root node");
|
nuclear@0
|
849
|
nuclear@0
|
850
|
nuclear@0
|
851 // Load all subsequent files
|
nuclear@0
|
852 batch.LoadAll();
|
nuclear@0
|
853
|
nuclear@0
|
854 // and build the final output graph by attaching the loaded external
|
nuclear@0
|
855 // files to ourselves. first build a master graph
|
nuclear@0
|
856 aiScene* master = new aiScene();
|
nuclear@0
|
857 aiNode* nd = master->mRootNode = new aiNode();
|
nuclear@0
|
858
|
nuclear@0
|
859 // allocate storage for cameras&lights
|
nuclear@0
|
860 if (num_camera) {
|
nuclear@0
|
861 master->mCameras = new aiCamera*[master->mNumCameras = num_camera];
|
nuclear@0
|
862 }
|
nuclear@0
|
863 aiCamera** cams = master->mCameras;
|
nuclear@0
|
864 if (num_light) {
|
nuclear@0
|
865 master->mLights = new aiLight*[master->mNumLights = num_light];
|
nuclear@0
|
866 }
|
nuclear@0
|
867 aiLight** lights = master->mLights;
|
nuclear@0
|
868
|
nuclear@0
|
869 std::vector<AttachmentInfo> attach;
|
nuclear@0
|
870 std::vector<aiNodeAnim*> anims;
|
nuclear@0
|
871
|
nuclear@0
|
872 nd->mName.Set("<LWSRoot>");
|
nuclear@0
|
873 nd->mChildren = new aiNode*[no_parent];
|
nuclear@0
|
874 for (std::list<LWS::NodeDesc>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
|
nuclear@0
|
875 if (!(*it).parent_resolved) {
|
nuclear@0
|
876 aiNode* ro = nd->mChildren[ nd->mNumChildren++ ] = new aiNode();
|
nuclear@0
|
877 ro->mParent = nd;
|
nuclear@0
|
878
|
nuclear@0
|
879 // ... and build the scene graph. If we encounter object nodes,
|
nuclear@0
|
880 // add then to our attachment table.
|
nuclear@0
|
881 BuildGraph(ro,*it, attach, batch, cams, lights, anims);
|
nuclear@0
|
882 }
|
nuclear@0
|
883 }
|
nuclear@0
|
884
|
nuclear@0
|
885 // create a master animation channel for us
|
nuclear@0
|
886 if (anims.size()) {
|
nuclear@0
|
887 master->mAnimations = new aiAnimation*[master->mNumAnimations = 1];
|
nuclear@0
|
888 aiAnimation* anim = master->mAnimations[0] = new aiAnimation();
|
nuclear@0
|
889 anim->mName.Set("LWSMasterAnim");
|
nuclear@0
|
890
|
nuclear@0
|
891 // LWS uses seconds as time units, but we convert to frames
|
nuclear@0
|
892 anim->mTicksPerSecond = fps;
|
nuclear@0
|
893 anim->mDuration = last-(first-1); /* fixme ... zero or one-based?*/
|
nuclear@0
|
894
|
nuclear@0
|
895 anim->mChannels = new aiNodeAnim*[anim->mNumChannels = anims.size()];
|
nuclear@0
|
896 std::copy(anims.begin(),anims.end(),anim->mChannels);
|
nuclear@0
|
897 }
|
nuclear@0
|
898
|
nuclear@0
|
899 // convert the master scene to RH
|
nuclear@0
|
900 MakeLeftHandedProcess monster_cheat;
|
nuclear@0
|
901 monster_cheat.Execute(master);
|
nuclear@0
|
902
|
nuclear@0
|
903 // .. ccw
|
nuclear@0
|
904 FlipWindingOrderProcess flipper;
|
nuclear@0
|
905 flipper.Execute(master);
|
nuclear@0
|
906
|
nuclear@0
|
907 // OK ... finally build the output graph
|
nuclear@0
|
908 SceneCombiner::MergeScenes(&pScene,master,attach,
|
nuclear@0
|
909 AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES | (!configSpeedFlag ? (
|
nuclear@0
|
910 AI_INT_MERGE_SCENE_GEN_UNIQUE_NAMES_IF_NECESSARY | AI_INT_MERGE_SCENE_GEN_UNIQUE_MATNAMES) : 0));
|
nuclear@0
|
911
|
nuclear@0
|
912 // Check flags
|
nuclear@0
|
913 if (!pScene->mNumMeshes || !pScene->mNumMaterials) {
|
nuclear@0
|
914 pScene->mFlags |= AI_SCENE_FLAGS_INCOMPLETE;
|
nuclear@0
|
915
|
nuclear@0
|
916 if (pScene->mNumAnimations && !noSkeletonMesh) {
|
nuclear@0
|
917 // construct skeleton mesh
|
nuclear@0
|
918 SkeletonMeshBuilder builder(pScene);
|
nuclear@0
|
919 }
|
nuclear@0
|
920 }
|
nuclear@0
|
921
|
nuclear@0
|
922 }
|
nuclear@0
|
923
|
nuclear@0
|
924 #endif // !! ASSIMP_BUILD_NO_LWS_IMPORTER
|