/src/ogre/PlugIns/DotScene/src/DotSceneLoader.cpp
Line | Count | Source |
1 | | #include <Ogre.h> |
2 | | #include <OgreDotSceneLoader.h> |
3 | | #include <OgreComponents.h> |
4 | | |
5 | | #ifdef OGRE_BUILD_COMPONENT_TERRAIN |
6 | | #include <OgreTerrain.h> |
7 | | #include <OgreTerrainGroup.h> |
8 | | #endif |
9 | | |
10 | | #include <pugixml.hpp> |
11 | | |
12 | | using namespace Ogre; |
13 | | |
14 | | #ifndef OGRE_BUILD_COMPONENT_TERRAIN |
15 | | namespace Ogre { |
16 | | class TerrainGroup {}; // appease unique_ptr destructor |
17 | | } |
18 | | #endif |
19 | | |
20 | | namespace |
21 | | { |
22 | | String getAttrib(const pugi::xml_node& XMLNode, const String& attrib, const String& defaultValue = "") |
23 | 0 | { |
24 | 0 | if (auto anode = XMLNode.attribute(attrib.c_str())) |
25 | 0 | return anode.value(); |
26 | 0 | else |
27 | 0 | return defaultValue; |
28 | 0 | } |
29 | | |
30 | | Real getAttribReal(const pugi::xml_node& XMLNode, const String& attrib, Real defaultValue = 0) |
31 | 0 | { |
32 | 0 | if (auto anode = XMLNode.attribute(attrib.c_str())) |
33 | 0 | return StringConverter::parseReal(anode.value()); |
34 | 0 | else |
35 | 0 | return defaultValue; |
36 | 0 | } |
37 | | |
38 | | bool getAttribBool(const pugi::xml_node& XMLNode, const String& attrib, bool defaultValue = false) |
39 | 0 | { |
40 | 0 | if (auto anode = XMLNode.attribute(attrib.c_str())) |
41 | 0 | return anode.as_bool(); |
42 | 0 | else |
43 | 0 | return defaultValue; |
44 | | |
45 | 0 | return false; |
46 | 0 | } |
47 | | |
48 | | Vector3 parseVector3(const pugi::xml_node& XMLNode) |
49 | 0 | { |
50 | 0 | return Vector3(StringConverter::parseReal(XMLNode.attribute("x").value()), |
51 | 0 | StringConverter::parseReal(XMLNode.attribute("y").value()), |
52 | 0 | StringConverter::parseReal(XMLNode.attribute("z").value())); |
53 | 0 | } |
54 | | |
55 | | Quaternion parseQuaternion(const pugi::xml_node& XMLNode) |
56 | 0 | { |
57 | | //! @todo Fix this crap! |
58 | |
|
59 | 0 | Quaternion orientation; |
60 | |
|
61 | 0 | if (XMLNode.attribute("qw")) |
62 | 0 | { |
63 | 0 | orientation.w = StringConverter::parseReal(XMLNode.attribute("qw").value()); |
64 | 0 | orientation.x = StringConverter::parseReal(XMLNode.attribute("qx").value()); |
65 | 0 | orientation.y = StringConverter::parseReal(XMLNode.attribute("qy").value()); |
66 | 0 | orientation.z = StringConverter::parseReal(XMLNode.attribute("qz").value()); |
67 | 0 | } |
68 | 0 | else if (XMLNode.attribute("axisX")) |
69 | 0 | { |
70 | 0 | Vector3 axis; |
71 | 0 | axis.x = StringConverter::parseReal(XMLNode.attribute("axisX").value()); |
72 | 0 | axis.y = StringConverter::parseReal(XMLNode.attribute("axisY").value()); |
73 | 0 | axis.z = StringConverter::parseReal(XMLNode.attribute("axisZ").value()); |
74 | 0 | Real angle = StringConverter::parseReal(XMLNode.attribute("angle").value()); |
75 | |
|
76 | 0 | orientation.FromAngleAxis(Radian(angle), axis); |
77 | 0 | } |
78 | 0 | else if (XMLNode.attribute("angleX")) |
79 | 0 | { |
80 | 0 | Matrix3 rot; |
81 | 0 | rot.FromEulerAnglesXYZ(StringConverter::parseAngle(XMLNode.attribute("angleX").value()), |
82 | 0 | StringConverter::parseAngle(XMLNode.attribute("angleY").value()), |
83 | 0 | StringConverter::parseAngle(XMLNode.attribute("angleZ").value())); |
84 | 0 | orientation.FromRotationMatrix(rot); |
85 | 0 | } |
86 | 0 | else if (XMLNode.attribute("x")) |
87 | 0 | { |
88 | 0 | orientation.x = StringConverter::parseReal(XMLNode.attribute("x").value()); |
89 | 0 | orientation.y = StringConverter::parseReal(XMLNode.attribute("y").value()); |
90 | 0 | orientation.z = StringConverter::parseReal(XMLNode.attribute("z").value()); |
91 | 0 | orientation.w = StringConverter::parseReal(XMLNode.attribute("w").value()); |
92 | 0 | } |
93 | 0 | else if (XMLNode.attribute("w")) |
94 | 0 | { |
95 | 0 | orientation.w = StringConverter::parseReal(XMLNode.attribute("w").value()); |
96 | 0 | orientation.x = StringConverter::parseReal(XMLNode.attribute("x").value()); |
97 | 0 | orientation.y = StringConverter::parseReal(XMLNode.attribute("y").value()); |
98 | 0 | orientation.z = StringConverter::parseReal(XMLNode.attribute("z").value()); |
99 | 0 | } |
100 | |
|
101 | 0 | return orientation; |
102 | 0 | } |
103 | | |
104 | | ColourValue parseColour(pugi::xml_node& XMLNode) |
105 | 0 | { |
106 | 0 | return ColourValue(StringConverter::parseReal(XMLNode.attribute("r").value()), |
107 | 0 | StringConverter::parseReal(XMLNode.attribute("g").value()), |
108 | 0 | StringConverter::parseReal(XMLNode.attribute("b").value()), |
109 | 0 | XMLNode.attribute("a") != NULL ? StringConverter::parseReal(XMLNode.attribute("a").value()) : 1); |
110 | 0 | } |
111 | | |
112 | | struct DotSceneCodec : public Codec |
113 | | { |
114 | 0 | String magicNumberToFileExt(const char* magicNumberPtr, size_t maxbytes) const override { return ""; } |
115 | 1 | String getType() const override { return "scene"; } |
116 | | void decode(const DataStreamPtr& stream, const Any& output) const override |
117 | 0 | { |
118 | 0 | DataStreamPtr _stream(stream); |
119 | 0 | DotSceneLoader loader; |
120 | 0 | loader.load(_stream, ResourceGroupManager::getSingleton().getWorldResourceGroupName(), |
121 | 0 | any_cast<SceneNode*>(output)); |
122 | 0 | } |
123 | | |
124 | | void encodeToFile(const Any& input, const String& outFileName) const override |
125 | 0 | { |
126 | 0 | DotSceneLoader loader; |
127 | 0 | loader.exportScene(any_cast<SceneNode*>(input), outFileName); |
128 | 0 | } |
129 | | }; |
130 | | |
131 | | } // namespace |
132 | | |
133 | 0 | DotSceneLoader::DotSceneLoader() : mSceneMgr(0), mBackgroundColour(ColourValue::Black), mItemPrefix("") {} |
134 | | |
135 | 0 | DotSceneLoader::~DotSceneLoader() {} |
136 | | |
137 | | void DotSceneLoader::load(DataStreamPtr& stream, const String& groupName, SceneNode* rootNode) |
138 | 0 | { |
139 | 0 | m_sGroupName = groupName; |
140 | 0 | mSceneMgr = rootNode->getCreator(); |
141 | |
|
142 | 0 | pugi::xml_document XMLDoc; // character type defaults to char |
143 | |
|
144 | 0 | auto optsAny = rootNode->getUserObjectBindings().getUserAny("_DotSceneLoaderOptions"); |
145 | 0 | if (optsAny.has_value()) |
146 | 0 | { |
147 | 0 | std::map<Ogre::String, Ogre::Any> options = any_cast<std::map<Ogre::String, Ogre::Any>>(optsAny); |
148 | 0 | if (options.find("namePrefix") != options.end()) |
149 | 0 | { |
150 | 0 | Ogre::Any optionValue = options["namePrefix"]; |
151 | 0 | if (optionValue.has_value()) |
152 | 0 | mItemPrefix = Ogre::any_cast<Ogre::String>(optionValue); |
153 | 0 | } |
154 | 0 | } |
155 | |
|
156 | 0 | auto result = XMLDoc.load_buffer(stream->getAsString().c_str(), stream->size()); |
157 | 0 | if (!result) |
158 | 0 | { |
159 | 0 | LogManager::getSingleton().logError("DotSceneLoader - " + String(result.description())); |
160 | 0 | return; |
161 | 0 | } |
162 | | |
163 | | // Grab the scene node |
164 | 0 | auto XMLRoot = XMLDoc.child("scene"); |
165 | | |
166 | | // Validate the File |
167 | 0 | if (!XMLRoot.attribute("formatVersion")) |
168 | 0 | { |
169 | 0 | LogManager::getSingleton().logError("DotSceneLoader - Invalid .scene File. Missing <scene formatVersion='x.y' >"); |
170 | 0 | return; |
171 | 0 | } |
172 | | |
173 | | // figure out where to attach any nodes we create |
174 | 0 | mAttachNode = rootNode; |
175 | | |
176 | | // Process the scene |
177 | 0 | processScene(XMLRoot); |
178 | 0 | } |
179 | | |
180 | | void DotSceneLoader::processScene(pugi::xml_node& XMLRoot) |
181 | 0 | { |
182 | | // Process the scene parameters |
183 | 0 | String version = getAttrib(XMLRoot, "formatVersion", "unknown"); |
184 | |
|
185 | 0 | String message = "[DotSceneLoader] Parsing dotScene file with version " + version; |
186 | 0 | if (XMLRoot.attribute("sceneManager")) |
187 | 0 | message += ", scene manager " + String(XMLRoot.attribute("sceneManager").value()); |
188 | 0 | if (XMLRoot.attribute("minOgreVersion")) |
189 | 0 | message += ", min. Ogre version " + String(XMLRoot.attribute("minOgreVersion").value()); |
190 | 0 | if (XMLRoot.attribute("author")) |
191 | 0 | message += ", author " + String(XMLRoot.attribute("author").value()); |
192 | |
|
193 | 0 | LogManager::getSingleton().logMessage(message); |
194 | | |
195 | | // Process environment (?) |
196 | 0 | if (auto pElement = XMLRoot.child("environment")) |
197 | 0 | processEnvironment(pElement); |
198 | | |
199 | | // Process nodes (?) |
200 | 0 | if (auto pElement = XMLRoot.child("nodes")) |
201 | 0 | processNodes(pElement); |
202 | | |
203 | | // Process externals (?) |
204 | 0 | if (auto pElement = XMLRoot.child("externals")) |
205 | 0 | processExternals(pElement); |
206 | | |
207 | | // Process userDataReference (?) |
208 | 0 | if (auto pElement = XMLRoot.child("userData")) |
209 | 0 | processUserData(pElement, mAttachNode->getUserObjectBindings()); |
210 | | |
211 | | // Process light (?) |
212 | 0 | if (auto pElement = XMLRoot.child("light")) |
213 | 0 | processLight(pElement); |
214 | | |
215 | | // Process camera (?) |
216 | 0 | if (auto pElement = XMLRoot.child("camera")) |
217 | 0 | processCamera(pElement); |
218 | | |
219 | | // Process terrain (?) |
220 | 0 | if (auto pElement = XMLRoot.child("terrainGroup")) |
221 | 0 | processTerrainGroup(pElement); |
222 | 0 | } |
223 | | |
224 | | void DotSceneLoader::processNodes(pugi::xml_node& XMLNode) |
225 | 0 | { |
226 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing Nodes...", LML_TRIVIAL); |
227 | | |
228 | | // Process node (*) |
229 | 0 | for (auto pElement : XMLNode.children("node")) |
230 | 0 | { |
231 | 0 | processNode(pElement); |
232 | 0 | } |
233 | | |
234 | | // Process position (?) |
235 | 0 | if (auto pElement = XMLNode.child("position")) |
236 | 0 | { |
237 | 0 | mAttachNode->setPosition(parseVector3(pElement)); |
238 | 0 | } |
239 | | |
240 | | // Process rotation (?) |
241 | 0 | if (auto pElement = XMLNode.child("rotation")) |
242 | 0 | { |
243 | 0 | mAttachNode->setOrientation(parseQuaternion(pElement)); |
244 | 0 | } |
245 | | |
246 | | // Process scale (?) |
247 | 0 | if (auto pElement = XMLNode.child("scale")) |
248 | 0 | { |
249 | 0 | mAttachNode->setScale(parseVector3(pElement)); |
250 | 0 | } |
251 | 0 | } |
252 | | |
253 | | void DotSceneLoader::processExternals(pugi::xml_node& XMLNode) |
254 | 0 | { |
255 | | //! @todo Implement this |
256 | 0 | } |
257 | | |
258 | | void DotSceneLoader::processEnvironment(pugi::xml_node& XMLNode) |
259 | 0 | { |
260 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing Environment...", LML_TRIVIAL); |
261 | | |
262 | | // Process camera (?) |
263 | 0 | if (auto pElement = XMLNode.child("camera")) |
264 | 0 | processCamera(pElement); |
265 | | |
266 | | // Process fog (?) |
267 | 0 | if (auto pElement = XMLNode.child("fog")) |
268 | 0 | processFog(pElement); |
269 | | |
270 | | // Process skyBox (?) |
271 | 0 | if (auto pElement = XMLNode.child("skyBox")) |
272 | 0 | processSkyBox(pElement); |
273 | | |
274 | | // Process skyDome (?) |
275 | 0 | if (auto pElement = XMLNode.child("skyDome")) |
276 | 0 | processSkyDome(pElement); |
277 | | |
278 | | // Process skyPlane (?) |
279 | 0 | if (auto pElement = XMLNode.child("skyPlane")) |
280 | 0 | processSkyPlane(pElement); |
281 | | |
282 | | // Process colourAmbient (?) |
283 | 0 | if (auto pElement = XMLNode.child("colourAmbient")) |
284 | 0 | mSceneMgr->setAmbientLight(parseColour(pElement)); |
285 | | |
286 | | // Process colourBackground (?) |
287 | 0 | if (auto pElement = XMLNode.child("colourBackground")) |
288 | 0 | mBackgroundColour = parseColour(pElement); |
289 | 0 | } |
290 | | |
291 | | void DotSceneLoader::processTerrainGroup(pugi::xml_node& XMLNode) |
292 | 0 | { |
293 | 0 | #ifdef OGRE_BUILD_COMPONENT_TERRAIN |
294 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing Terrain Group...", LML_TRIVIAL); |
295 | |
|
296 | 0 | Real worldSize = getAttribReal(XMLNode, "worldSize"); |
297 | 0 | int mapSize = StringConverter::parseInt(XMLNode.attribute("size").value()); |
298 | 0 | int compositeMapDistance = StringConverter::parseInt(XMLNode.attribute("tuningCompositeMapDistance").value()); |
299 | 0 | int maxPixelError = StringConverter::parseInt(XMLNode.attribute("tuningMaxPixelError").value()); |
300 | |
|
301 | 0 | auto terrainGlobalOptions = TerrainGlobalOptions::getSingletonPtr(); |
302 | 0 | OgreAssert(terrainGlobalOptions, "TerrainGlobalOptions not available"); |
303 | | |
304 | 0 | terrainGlobalOptions->setMaxPixelError((Real)maxPixelError); |
305 | 0 | terrainGlobalOptions->setCompositeMapDistance((Real)compositeMapDistance); |
306 | |
|
307 | 0 | auto terrainGroup = std::make_shared<TerrainGroup>(mSceneMgr, Terrain::ALIGN_X_Z, mapSize, worldSize); |
308 | 0 | terrainGroup->setOrigin(Vector3::ZERO); |
309 | 0 | terrainGroup->setResourceGroup(m_sGroupName); |
310 | | |
311 | | // Process terrain pages (*) |
312 | 0 | for (auto pPageElement : XMLNode.children("terrain")) |
313 | 0 | { |
314 | 0 | int pageX = StringConverter::parseInt(pPageElement.attribute("x").value()); |
315 | 0 | int pageY = StringConverter::parseInt(pPageElement.attribute("y").value()); |
316 | |
|
317 | 0 | terrainGroup->defineTerrain(pageX, pageY, pPageElement.attribute("dataFile").value()); |
318 | 0 | } |
319 | 0 | terrainGroup->loadAllTerrains(true); |
320 | |
|
321 | 0 | terrainGroup->freeTemporaryResources(); |
322 | |
|
323 | 0 | mAttachNode->getUserObjectBindings().setUserAny("TerrainGroup", terrainGroup); |
324 | | #else |
325 | | OGRE_EXCEPT(Exception::ERR_INVALID_CALL, "recompile with Terrain component"); |
326 | | #endif |
327 | 0 | } |
328 | | |
329 | | void DotSceneLoader::processLight(pugi::xml_node& XMLNode, SceneNode* pParent) |
330 | 0 | { |
331 | | // Process attributes |
332 | 0 | String name = getAttrib(XMLNode, "name"); |
333 | |
|
334 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing Light: " + name, LML_TRIVIAL); |
335 | | |
336 | | // Create the light |
337 | 0 | Light* pLight = mSceneMgr->createLight(name); |
338 | 0 | if (pParent) |
339 | 0 | pParent->attachObject(pLight); |
340 | |
|
341 | 0 | String sValue = getAttrib(XMLNode, "type"); |
342 | 0 | if (sValue == "point") |
343 | 0 | pLight->setType(Light::LT_POINT); |
344 | 0 | else if (sValue == "directional") |
345 | 0 | pLight->setType(Light::LT_DIRECTIONAL); |
346 | 0 | else if (sValue == "spot") |
347 | 0 | pLight->setType(Light::LT_SPOTLIGHT); |
348 | 0 | else if (sValue == "radPoint") |
349 | 0 | pLight->setType(Light::LT_POINT); |
350 | 0 | else if (sValue == "rect") |
351 | 0 | pLight->setType(Light::LT_RECTLIGHT); |
352 | |
|
353 | 0 | pLight->setVisible(getAttribBool(XMLNode, "visible", true)); |
354 | 0 | pLight->setCastShadows(getAttribBool(XMLNode, "castShadows", true)); |
355 | 0 | pLight->setPowerScale(getAttribReal(XMLNode, "powerScale", 1.0)); |
356 | | |
357 | | // Process colourDiffuse (?) |
358 | 0 | if (auto pElement = XMLNode.child("colourDiffuse")) |
359 | 0 | pLight->setDiffuseColour(parseColour(pElement)); |
360 | | |
361 | | // Process colourSpecular (?) |
362 | 0 | if (auto pElement = XMLNode.child("colourSpecular")) |
363 | 0 | pLight->setSpecularColour(parseColour(pElement)); |
364 | |
|
365 | 0 | if (sValue != "directional") |
366 | 0 | { |
367 | | // Process lightRange (?) |
368 | 0 | if (auto pElement = XMLNode.child("lightRange")) |
369 | 0 | processLightRange(pElement, pLight); |
370 | | |
371 | | // Process lightAttenuation (?) |
372 | 0 | if (auto pElement = XMLNode.child("lightAttenuation")) |
373 | 0 | processLightAttenuation(pElement, pLight); |
374 | 0 | } |
375 | |
|
376 | 0 | if (sValue == "rect") |
377 | 0 | { |
378 | | // Process lightSourceSize (?) |
379 | 0 | if (auto pElement = XMLNode.child("lightSourceSize")) |
380 | 0 | processLightSourceSize(pElement, pLight); |
381 | 0 | } |
382 | | |
383 | | // Process userDataReference (?) |
384 | 0 | if (auto pElement = XMLNode.child("userData")) |
385 | 0 | processUserData(pElement, pLight->getUserObjectBindings()); |
386 | 0 | } |
387 | | |
388 | | void DotSceneLoader::processCamera(pugi::xml_node& XMLNode, SceneNode* pParent) |
389 | 0 | { |
390 | | // Process attributes |
391 | 0 | String name = getAttrib(XMLNode, "name"); |
392 | |
|
393 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing Camera: " + name, LML_TRIVIAL); |
394 | | |
395 | | // Real fov = getAttribReal(XMLNode, "fov", 45); |
396 | 0 | Real aspectRatio = getAttribReal(XMLNode, "aspectRatio", 1.3333); |
397 | 0 | String projectionType = getAttrib(XMLNode, "projectionType", "perspective"); |
398 | | |
399 | | // Create the camera |
400 | 0 | Camera* pCamera = mSceneMgr->createCamera(name); |
401 | | |
402 | | // construct a scenenode is no parent |
403 | 0 | if (!pParent) |
404 | 0 | pParent = mAttachNode->createChildSceneNode(name); |
405 | |
|
406 | 0 | pParent->attachObject(pCamera); |
407 | | |
408 | | // Set the field-of-view |
409 | | //! @todo Is this always in degrees? |
410 | | // pCamera->setFOVy(Degree(fov)); |
411 | | |
412 | | // Set the aspect ratio |
413 | 0 | pCamera->setAspectRatio(aspectRatio); |
414 | | |
415 | | // Set the projection type |
416 | 0 | if (projectionType == "perspective") |
417 | 0 | pCamera->setProjectionType(PT_PERSPECTIVE); |
418 | 0 | else if (projectionType == "orthographic") |
419 | 0 | pCamera->setProjectionType(PT_ORTHOGRAPHIC); |
420 | | |
421 | | // Process clipping (?) |
422 | 0 | if (auto pElement = XMLNode.child("clipping")) |
423 | 0 | { |
424 | 0 | Real nearDist = getAttribReal(pElement, "near"); |
425 | 0 | pCamera->setNearClipDistance(nearDist); |
426 | |
|
427 | 0 | Real farDist = getAttribReal(pElement, "far"); |
428 | 0 | pCamera->setFarClipDistance(farDist); |
429 | 0 | } |
430 | | |
431 | | // Process userDataReference (?) |
432 | 0 | if (auto pElement = XMLNode.child("userData")) |
433 | 0 | processUserData(pElement, static_cast<MovableObject*>(pCamera)->getUserObjectBindings()); |
434 | 0 | } |
435 | | |
436 | | void DotSceneLoader::processNode(pugi::xml_node& XMLNode, SceneNode* pParent) |
437 | 0 | { |
438 | | // Construct the node's name |
439 | 0 | String name = getAttrib(XMLNode, "name"); |
440 | |
|
441 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing Node: " + name, LML_TRIVIAL); |
442 | | |
443 | | // Create the scene node |
444 | 0 | SceneNode* pNode; |
445 | 0 | if (name.empty()) |
446 | 0 | { |
447 | | // Let Ogre choose the name |
448 | 0 | if (pParent) |
449 | 0 | pNode = pParent->createChildSceneNode(); |
450 | 0 | else |
451 | 0 | pNode = mAttachNode->createChildSceneNode(); |
452 | 0 | } |
453 | 0 | else |
454 | 0 | { |
455 | | // Provide the name |
456 | 0 | if (pParent) |
457 | 0 | pNode = pParent->createChildSceneNode(mItemPrefix + name); |
458 | 0 | else |
459 | 0 | pNode = mAttachNode->createChildSceneNode(mItemPrefix + name); |
460 | 0 | } |
461 | | |
462 | | // Process other attributes |
463 | | |
464 | | // Process position (?) |
465 | 0 | if (auto pElement = XMLNode.child("position")) |
466 | 0 | { |
467 | 0 | pNode->setPosition(parseVector3(pElement)); |
468 | 0 | } |
469 | | |
470 | | // Process rotation (?) |
471 | 0 | if (auto pElement = XMLNode.child("rotation")) |
472 | 0 | { |
473 | 0 | pNode->setOrientation(parseQuaternion(pElement)); |
474 | 0 | } |
475 | | |
476 | | // Process scale (?) |
477 | 0 | if (auto pElement = XMLNode.child("scale")) |
478 | 0 | { |
479 | 0 | pNode->setScale(parseVector3(pElement)); |
480 | 0 | } |
481 | | |
482 | | // Process lookTarget (?) |
483 | 0 | if (auto pElement = XMLNode.child("lookTarget")) |
484 | 0 | processLookTarget(pElement, pNode); |
485 | | |
486 | | // Process trackTarget (?) |
487 | 0 | if (auto pElement = XMLNode.child("trackTarget")) |
488 | 0 | processTrackTarget(pElement, pNode); |
489 | | |
490 | | // Process node (*) |
491 | 0 | for (auto pElement : XMLNode.children("node")) |
492 | 0 | { |
493 | 0 | processNode(pElement, pNode); |
494 | 0 | } |
495 | | |
496 | | // Process entity (*) |
497 | 0 | for (auto pElement : XMLNode.children("entity")) |
498 | 0 | { |
499 | 0 | processEntity(pElement, pNode); |
500 | 0 | } |
501 | | |
502 | | // Process light (*) |
503 | 0 | for (auto pElement : XMLNode.children("light")) |
504 | 0 | { |
505 | 0 | processLight(pElement, pNode); |
506 | 0 | } |
507 | | |
508 | | // Process camera (*) |
509 | 0 | for (auto pElement : XMLNode.children("camera")) |
510 | 0 | { |
511 | 0 | processCamera(pElement, pNode); |
512 | 0 | } |
513 | | |
514 | | // Process particleSystem (*) |
515 | 0 | for (auto pElement : XMLNode.children("particleSystem")) |
516 | 0 | { |
517 | 0 | processParticleSystem(pElement, pNode); |
518 | 0 | } |
519 | | |
520 | | // Process billboardSet (*) |
521 | 0 | for (auto pElement : XMLNode.children("billboardSet")) |
522 | 0 | { |
523 | 0 | processBillboardSet(pElement, pNode); |
524 | 0 | } |
525 | | |
526 | | // Process plane (*) |
527 | 0 | for (auto pElement : XMLNode.children("plane")) |
528 | 0 | { |
529 | 0 | processPlane(pElement, pNode); |
530 | 0 | } |
531 | | |
532 | | // Process userDataReference (?) |
533 | 0 | if (auto pElement = XMLNode.child("userData")) |
534 | 0 | processUserData(pElement, pNode->getUserObjectBindings()); |
535 | | |
536 | | // Process node animations (?) |
537 | 0 | if (auto pElement = XMLNode.child("animations")) |
538 | 0 | processNodeAnimations(pElement, pNode); |
539 | 0 | } |
540 | | |
541 | | void DotSceneLoader::processLookTarget(pugi::xml_node& XMLNode, SceneNode* pParent) |
542 | 0 | { |
543 | | //! @todo Is this correct? Cause I don't have a clue actually |
544 | | |
545 | | // Process attributes |
546 | 0 | String nodeName = getAttrib(XMLNode, "nodeName"); |
547 | |
|
548 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing Look Target, nodeName: " + nodeName, LML_TRIVIAL); |
549 | |
|
550 | 0 | Node::TransformSpace relativeTo = Node::TS_PARENT; |
551 | 0 | String sValue = getAttrib(XMLNode, "relativeTo"); |
552 | 0 | if (sValue == "local") |
553 | 0 | relativeTo = Node::TS_LOCAL; |
554 | 0 | else if (sValue == "parent") |
555 | 0 | relativeTo = Node::TS_PARENT; |
556 | 0 | else if (sValue == "world") |
557 | 0 | relativeTo = Node::TS_WORLD; |
558 | | |
559 | | // Process position (?) |
560 | 0 | Vector3 position; |
561 | 0 | if (auto pElement = XMLNode.child("position")) |
562 | 0 | position = parseVector3(pElement); |
563 | | |
564 | | // Process localDirection (?) |
565 | 0 | Vector3 localDirection = Vector3::NEGATIVE_UNIT_Z; |
566 | 0 | if (auto pElement = XMLNode.child("localDirection")) |
567 | 0 | localDirection = parseVector3(pElement); |
568 | | |
569 | | // Setup the look target |
570 | 0 | try |
571 | 0 | { |
572 | 0 | if (!nodeName.empty()) |
573 | 0 | { |
574 | 0 | SceneNode* pLookNode = mSceneMgr->getSceneNode(nodeName); |
575 | 0 | position = pLookNode->_getDerivedPosition(); |
576 | 0 | } |
577 | |
|
578 | 0 | pParent->lookAt(position, relativeTo, localDirection); |
579 | 0 | } |
580 | 0 | catch (const Exception& e) |
581 | 0 | { |
582 | 0 | LogManager::getSingleton().logError("DotSceneLoader - " + e.getDescription()); |
583 | 0 | } |
584 | 0 | } |
585 | | |
586 | | void DotSceneLoader::processTrackTarget(pugi::xml_node& XMLNode, SceneNode* pParent) |
587 | 0 | { |
588 | | // Process attributes |
589 | 0 | String nodeName = getAttrib(XMLNode, "nodeName"); |
590 | |
|
591 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing Track Target, nodeName: " + nodeName, LML_TRIVIAL); |
592 | | |
593 | | // Process localDirection (?) |
594 | 0 | Vector3 localDirection = Vector3::NEGATIVE_UNIT_Z; |
595 | 0 | if (auto pElement = XMLNode.child("localDirection")) |
596 | 0 | localDirection = parseVector3(pElement); |
597 | | |
598 | | // Process offset (?) |
599 | 0 | Vector3 offset = Vector3::ZERO; |
600 | 0 | if (auto pElement = XMLNode.child("offset")) |
601 | 0 | offset = parseVector3(pElement); |
602 | | |
603 | | // Setup the track target |
604 | 0 | try |
605 | 0 | { |
606 | 0 | SceneNode* pTrackNode = mSceneMgr->getSceneNode(nodeName); |
607 | 0 | pParent->setAutoTracking(true, pTrackNode, localDirection, offset); |
608 | 0 | } |
609 | 0 | catch (const Exception& e) |
610 | 0 | { |
611 | 0 | LogManager::getSingleton().logError("DotSceneLoader - " + e.getDescription()); |
612 | 0 | } |
613 | 0 | } |
614 | | |
615 | | void DotSceneLoader::processEntity(pugi::xml_node& XMLNode, SceneNode* pParent) |
616 | 0 | { |
617 | | // Process attributes |
618 | 0 | String name = getAttrib(XMLNode, "name"); |
619 | |
|
620 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing Entity: " + mItemPrefix + name, LML_TRIVIAL); |
621 | |
|
622 | 0 | String meshFile = getAttrib(XMLNode, "meshFile"); |
623 | 0 | String staticGeometry = getAttrib(XMLNode, "static"); |
624 | 0 | String instancedManager = getAttrib(XMLNode, "instanced"); |
625 | 0 | String material = getAttrib(XMLNode, "material"); |
626 | 0 | bool castShadows = getAttribBool(XMLNode, "castShadows", true); |
627 | 0 | bool visible = getAttribBool(XMLNode, "visible", true); |
628 | | |
629 | | // Create the entity |
630 | 0 | MovableObject* pEntity = 0; |
631 | |
|
632 | 0 | try |
633 | 0 | { |
634 | | // If the Entity is instanced then the creation path is different |
635 | 0 | if (!instancedManager.empty()) |
636 | 0 | { |
637 | 0 | LogManager::getSingleton().logMessage( |
638 | 0 | "[DotSceneLoader] Adding entity: " + name + " to Instance Manager: " + instancedManager, LML_TRIVIAL); |
639 | | |
640 | | // Load the Mesh to get the material name of the first submesh |
641 | 0 | Ogre::MeshPtr mesh = MeshManager::getSingletonPtr()->load(meshFile, m_sGroupName); |
642 | | |
643 | | // Get the material name of the entity |
644 | 0 | if (!material.empty()) |
645 | 0 | pEntity = mSceneMgr->createInstancedEntity(material, instancedManager); |
646 | 0 | else |
647 | 0 | pEntity = mSceneMgr->createInstancedEntity(mesh->getSubMesh(0)->getMaterialName(), instancedManager); |
648 | |
|
649 | 0 | pParent->attachObject(static_cast<InstancedEntity*>(pEntity)); |
650 | 0 | } |
651 | 0 | else |
652 | 0 | { |
653 | 0 | pEntity = mSceneMgr->createEntity(mItemPrefix + name, meshFile, m_sGroupName); |
654 | |
|
655 | 0 | static_cast<Entity*>(pEntity)->setCastShadows(castShadows); |
656 | 0 | static_cast<Entity*>(pEntity)->setVisible(visible); |
657 | |
|
658 | 0 | if (!material.empty()) |
659 | 0 | static_cast<Entity*>(pEntity)->setMaterialName(material); |
660 | | |
661 | | // If the Entity belongs to a Static Geometry group then it doesn't get attached to a node |
662 | | // * TODO * : Clean up nodes without attached entities or children nodes? (should be done afterwards |
663 | | // if the hierarchy is being processed) |
664 | 0 | if (!staticGeometry.empty()) |
665 | 0 | { |
666 | 0 | LogManager::getSingleton().logMessage( |
667 | 0 | "[DotSceneLoader] Adding entity: " + name + " to Static Group: " + staticGeometry, LML_TRIVIAL); |
668 | 0 | mSceneMgr->getStaticGeometry(staticGeometry) |
669 | 0 | ->addEntity(static_cast<Entity*>(pEntity), pParent->_getDerivedPosition(), |
670 | 0 | pParent->_getDerivedOrientation(), pParent->_getDerivedScale()); |
671 | 0 | } |
672 | 0 | else |
673 | 0 | { |
674 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] pParent->attachObject(): " + name, LML_TRIVIAL); |
675 | 0 | pParent->attachObject(static_cast<Entity*>(pEntity)); |
676 | 0 | } |
677 | 0 | } |
678 | 0 | } |
679 | 0 | catch (const Exception& e) |
680 | 0 | { |
681 | 0 | LogManager::getSingleton().logError("DotSceneLoader - " + e.getDescription()); |
682 | 0 | return; |
683 | 0 | } |
684 | | |
685 | | // Process userDataReference (?) |
686 | 0 | if (auto pElement = XMLNode.child("userData")) |
687 | 0 | processUserData(pElement, pEntity->getUserObjectBindings()); |
688 | 0 | } |
689 | | |
690 | | void DotSceneLoader::processParticleSystem(pugi::xml_node& XMLNode, SceneNode* pParent) |
691 | 0 | { |
692 | | // Process attributes |
693 | 0 | String name = getAttrib(XMLNode, "name"); |
694 | |
|
695 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing Particle System: " + name, LML_TRIVIAL); |
696 | |
|
697 | 0 | String templateName = getAttrib(XMLNode, "template"); |
698 | |
|
699 | 0 | if (templateName.empty()) |
700 | 0 | templateName = getAttrib(XMLNode, "file"); // compatibility with old scenes |
701 | | |
702 | | // Create the particle system |
703 | 0 | try |
704 | 0 | { |
705 | 0 | ParticleSystem* pParticles = mSceneMgr->createParticleSystem(name, templateName); |
706 | 0 | pParent->attachObject(pParticles); |
707 | 0 | } |
708 | 0 | catch (const Exception& e) |
709 | 0 | { |
710 | 0 | LogManager::getSingleton().logError("DotSceneLoader - " + e.getDescription()); |
711 | 0 | } |
712 | 0 | } |
713 | | |
714 | | void DotSceneLoader::processBillboardSet(pugi::xml_node& XMLNode, SceneNode* pParent) |
715 | 0 | { |
716 | | //! @todo Implement this |
717 | 0 | } |
718 | | |
719 | | void DotSceneLoader::processPlane(pugi::xml_node& XMLNode, SceneNode* pParent) |
720 | 0 | { |
721 | 0 | String name = getAttrib(XMLNode, "name"); |
722 | |
|
723 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing Plane: " + name, LML_TRIVIAL); |
724 | |
|
725 | 0 | Real distance = getAttribReal(XMLNode, "distance"); |
726 | 0 | Real width = getAttribReal(XMLNode, "width"); |
727 | 0 | Real height = getAttribReal(XMLNode, "height"); |
728 | 0 | int xSegments = StringConverter::parseInt(getAttrib(XMLNode, "xSegments")); |
729 | 0 | int ySegments = StringConverter::parseInt(getAttrib(XMLNode, "ySegments")); |
730 | 0 | int numTexCoordSets = StringConverter::parseInt(getAttrib(XMLNode, "numTexCoordSets")); |
731 | 0 | Real uTile = getAttribReal(XMLNode, "uTile"); |
732 | 0 | Real vTile = getAttribReal(XMLNode, "vTile"); |
733 | 0 | String material = getAttrib(XMLNode, "material"); |
734 | 0 | bool hasNormals = getAttribBool(XMLNode, "hasNormals"); |
735 | 0 | Vector3 normal = parseVector3(XMLNode.child("normal")); |
736 | 0 | Vector3 up = parseVector3(XMLNode.child("upVector")); |
737 | |
|
738 | 0 | Plane plane(normal, distance); |
739 | 0 | MeshPtr res = |
740 | 0 | MeshManager::getSingletonPtr()->createPlane(name + "mesh", m_sGroupName, plane, width, height, xSegments, |
741 | 0 | ySegments, hasNormals, numTexCoordSets, uTile, vTile, up); |
742 | 0 | Entity* ent = mSceneMgr->createEntity(name, name + "mesh"); |
743 | |
|
744 | 0 | ent->setMaterialName(material); |
745 | |
|
746 | 0 | pParent->attachObject(ent); |
747 | 0 | } |
748 | | |
749 | | void DotSceneLoader::processFog(pugi::xml_node& XMLNode) |
750 | 0 | { |
751 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing Fog...", LML_TRIVIAL); |
752 | | |
753 | | // Process attributes |
754 | 0 | Real expDensity = getAttribReal(XMLNode, "density", 0.001); |
755 | 0 | Real linearStart = getAttribReal(XMLNode, "start", 0.0); |
756 | 0 | Real linearEnd = getAttribReal(XMLNode, "end", 1.0); |
757 | |
|
758 | 0 | FogMode mode = FOG_NONE; |
759 | 0 | String sMode = getAttrib(XMLNode, "mode"); |
760 | 0 | if (sMode == "none") |
761 | 0 | mode = FOG_NONE; |
762 | 0 | else if (sMode == "exp") |
763 | 0 | mode = FOG_EXP; |
764 | 0 | else if (sMode == "exp2") |
765 | 0 | mode = FOG_EXP2; |
766 | 0 | else if (sMode == "linear") |
767 | 0 | mode = FOG_LINEAR; |
768 | 0 | else |
769 | 0 | mode = (FogMode)StringConverter::parseInt(sMode); |
770 | | |
771 | | // Process colourDiffuse (?) |
772 | 0 | ColourValue colourDiffuse = ColourValue::White; |
773 | |
|
774 | 0 | if (auto pElement = XMLNode.child("colour")) |
775 | 0 | colourDiffuse = parseColour(pElement); |
776 | | |
777 | | // Setup the fog |
778 | 0 | mSceneMgr->setFog(mode, colourDiffuse, expDensity, linearStart, linearEnd); |
779 | 0 | } |
780 | | |
781 | | void DotSceneLoader::processSkyBox(pugi::xml_node& XMLNode) |
782 | 0 | { |
783 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing SkyBox...", LML_TRIVIAL); |
784 | | |
785 | | // Process attributes |
786 | 0 | String material = getAttrib(XMLNode, "material", "BaseWhite"); |
787 | 0 | Real distance = getAttribReal(XMLNode, "distance", 5000); |
788 | 0 | bool drawFirst = getAttribBool(XMLNode, "drawFirst", true); |
789 | | |
790 | | // Process rotation (?) |
791 | 0 | Quaternion rotation = Quaternion::IDENTITY; |
792 | |
|
793 | 0 | if (auto pElement = XMLNode.child("rotation")) |
794 | 0 | rotation = parseQuaternion(pElement); |
795 | | |
796 | | // Setup the sky box |
797 | 0 | mSceneMgr->setSkyBox(true, material, distance, drawFirst, rotation, m_sGroupName); |
798 | 0 | } |
799 | | |
800 | | void DotSceneLoader::processSkyDome(pugi::xml_node& XMLNode) |
801 | 0 | { |
802 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing SkyDome...", LML_TRIVIAL); |
803 | | |
804 | | // Process attributes |
805 | 0 | String material = XMLNode.attribute("material").value(); |
806 | 0 | Real curvature = getAttribReal(XMLNode, "curvature", 10); |
807 | 0 | Real tiling = getAttribReal(XMLNode, "tiling", 8); |
808 | 0 | Real distance = getAttribReal(XMLNode, "distance", 4000); |
809 | 0 | bool drawFirst = getAttribBool(XMLNode, "drawFirst", true); |
810 | 0 | bool active = getAttribBool(XMLNode, "active", false); |
811 | 0 | if (!active) |
812 | 0 | return; |
813 | | |
814 | | // Process rotation (?) |
815 | 0 | Quaternion rotation = Quaternion::IDENTITY; |
816 | 0 | if (auto pElement = XMLNode.child("rotation")) |
817 | 0 | rotation = parseQuaternion(pElement); |
818 | | |
819 | | // Setup the sky dome |
820 | 0 | mSceneMgr->setSkyDome(true, material, curvature, tiling, distance, drawFirst, rotation, 16, 16, -1, m_sGroupName); |
821 | 0 | } |
822 | | |
823 | | void DotSceneLoader::processSkyPlane(pugi::xml_node& XMLNode) |
824 | 0 | { |
825 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing SkyPlane...", LML_TRIVIAL); |
826 | | |
827 | | // Process attributes |
828 | 0 | String material = getAttrib(XMLNode, "material"); |
829 | 0 | Real planeX = getAttribReal(XMLNode, "planeX", 0); |
830 | 0 | Real planeY = getAttribReal(XMLNode, "planeY", -1); |
831 | 0 | Real planeZ = getAttribReal(XMLNode, "planeZ", 0); |
832 | 0 | Real planeD = getAttribReal(XMLNode, "planeD", 5000); |
833 | 0 | Real scale = getAttribReal(XMLNode, "scale", 1000); |
834 | 0 | Real bow = getAttribReal(XMLNode, "bow", 0); |
835 | 0 | Real tiling = getAttribReal(XMLNode, "tiling", 10); |
836 | 0 | bool drawFirst = getAttribBool(XMLNode, "drawFirst", true); |
837 | | |
838 | | // Setup the sky plane |
839 | 0 | Plane plane; |
840 | 0 | plane.normal = Vector3(planeX, planeY, planeZ); |
841 | 0 | plane.d = planeD; |
842 | 0 | mSceneMgr->setSkyPlane(true, plane, material, scale, tiling, drawFirst, bow, 1, 1, m_sGroupName); |
843 | 0 | } |
844 | | |
845 | | void DotSceneLoader::processLightRange(pugi::xml_node& XMLNode, Light* pLight) |
846 | 0 | { |
847 | | // Process attributes |
848 | 0 | Real inner = getAttribReal(XMLNode, "inner"); |
849 | 0 | Real outer = getAttribReal(XMLNode, "outer"); |
850 | 0 | Real falloff = getAttribReal(XMLNode, "falloff", 1.0); |
851 | | |
852 | | // Setup the light range |
853 | 0 | pLight->setSpotlightRange(Radian(inner), Radian(outer), falloff); |
854 | 0 | } |
855 | | |
856 | | void DotSceneLoader::processLightAttenuation(pugi::xml_node& XMLNode, Light* pLight) |
857 | 0 | { |
858 | | // Process attributes |
859 | 0 | Real range = getAttribReal(XMLNode, "range"); |
860 | 0 | Real constant = getAttribReal(XMLNode, "constant"); |
861 | 0 | Real linear = getAttribReal(XMLNode, "linear"); |
862 | 0 | Real quadratic = getAttribReal(XMLNode, "quadratic"); |
863 | | |
864 | | // Setup the light attenuation |
865 | 0 | pLight->setAttenuation(range, constant, linear, quadratic); |
866 | 0 | } |
867 | | |
868 | | void DotSceneLoader::processLightSourceSize(pugi::xml_node& XMLNode, Light* pLight) |
869 | 0 | { |
870 | | // Process attributes |
871 | 0 | Real width = getAttribReal(XMLNode, "width"); |
872 | 0 | Real height = getAttribReal(XMLNode, "height"); |
873 | | |
874 | | // Setup the light range |
875 | 0 | pLight->setSourceSize(width, height); |
876 | 0 | } |
877 | | |
878 | | void DotSceneLoader::processUserData(pugi::xml_node& XMLNode, UserObjectBindings& userData) |
879 | 0 | { |
880 | | // Process node (*) |
881 | 0 | for (auto pElement : XMLNode.children("property")) |
882 | 0 | { |
883 | 0 | String name = getAttrib(pElement, "name"); |
884 | 0 | String type = getAttrib(pElement, "type"); |
885 | 0 | String data = getAttrib(pElement, "data"); |
886 | |
|
887 | 0 | Any value; |
888 | 0 | if (type == "bool") |
889 | 0 | value = StringConverter::parseBool(data); |
890 | 0 | else if (type == "float") |
891 | 0 | value = StringConverter::parseReal(data); |
892 | 0 | else if (type == "int") |
893 | 0 | value = StringConverter::parseInt(data); |
894 | 0 | else |
895 | 0 | value = data; |
896 | |
|
897 | 0 | userData.setUserAny(name, value); |
898 | 0 | } |
899 | 0 | } |
900 | | |
901 | | void DotSceneLoader::processNodeAnimations(pugi::xml_node& XMLNode, SceneNode* pParent) |
902 | 0 | { |
903 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing Node Animations for SceneNode: " + pParent->getName(), LML_TRIVIAL); |
904 | | |
905 | | // Process node animations (*) |
906 | 0 | for (auto pElement : XMLNode.children("animation")) |
907 | 0 | { |
908 | 0 | processNodeAnimation(pElement, pParent); |
909 | 0 | } |
910 | 0 | } |
911 | | |
912 | | void DotSceneLoader::processNodeAnimation(pugi::xml_node& XMLNode, SceneNode* pParent) |
913 | 0 | { |
914 | | // Process node animation (*) |
915 | | |
916 | | // Construct the animation name |
917 | 0 | String name = getAttrib(XMLNode, "name"); |
918 | |
|
919 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing Node Animation: " + name, LML_TRIVIAL); |
920 | |
|
921 | 0 | Real length = getAttribReal(XMLNode, "length"); |
922 | |
|
923 | 0 | Animation* anim = mSceneMgr->createAnimation(name, length); |
924 | |
|
925 | 0 | bool enable = getAttribBool(XMLNode, "enable", false); |
926 | 0 | bool loop = getAttribBool(XMLNode, "loop", false); |
927 | |
|
928 | 0 | String interpolationMode = getAttrib(XMLNode, "interpolationMode"); |
929 | |
|
930 | 0 | if (interpolationMode == "linear") |
931 | 0 | anim->setInterpolationMode(Animation::IM_LINEAR); |
932 | 0 | else if (interpolationMode == "spline") |
933 | 0 | anim->setInterpolationMode(Animation::IM_SPLINE); |
934 | 0 | else |
935 | 0 | LogManager::getSingleton().logError("DotSceneLoader - Invalid interpolationMode: " + interpolationMode); |
936 | |
|
937 | 0 | String rotationInterpolationMode = getAttrib(XMLNode, "rotationInterpolationMode"); |
938 | |
|
939 | 0 | if (rotationInterpolationMode == "linear") |
940 | 0 | anim->setRotationInterpolationMode(Animation::RIM_LINEAR); |
941 | 0 | else if (rotationInterpolationMode == "spherical") |
942 | 0 | anim->setRotationInterpolationMode(Animation::RIM_SPHERICAL); |
943 | 0 | else |
944 | 0 | LogManager::getSingleton().logError("DotSceneLoader - Invalid rotationInterpolationMode: " + rotationInterpolationMode); |
945 | | |
946 | | // create a track to animate the camera's node |
947 | 0 | NodeAnimationTrack* track = anim->createNodeTrack(0, pParent); |
948 | 0 | pParent->setInitialState(); |
949 | | |
950 | | // Process keyframes (*) |
951 | 0 | for (auto pElement : XMLNode.children("keyframe")) |
952 | 0 | { |
953 | 0 | processKeyframe(pElement, track); |
954 | 0 | } |
955 | | |
956 | | // create a new animation state to track this |
957 | 0 | auto animState = mSceneMgr->createAnimationState(name); |
958 | 0 | animState->setEnabled(enable); |
959 | 0 | animState->setLoop(loop); |
960 | 0 | } |
961 | | |
962 | | void DotSceneLoader::processKeyframe(pugi::xml_node& XMLNode, NodeAnimationTrack* pTrack) |
963 | 0 | { |
964 | | // Process node animation keyframe (*) |
965 | 0 | Real time = getAttribReal(XMLNode, "time"); |
966 | |
|
967 | 0 | LogManager::getSingleton().logMessage("[DotSceneLoader] Processing Keyframe: " + StringConverter::toString(time), LML_TRIVIAL); |
968 | |
|
969 | 0 | auto keyframe = pTrack->createNodeKeyFrame(time); |
970 | | |
971 | | // Process translation (?) |
972 | 0 | if (auto pElement = XMLNode.child("position")) { |
973 | 0 | Vector3 translation = parseVector3(pElement); |
974 | 0 | keyframe->setTranslate(translation); |
975 | 0 | } |
976 | | |
977 | | // Process rotation (?) |
978 | | //Quaternion rotation = Quaternion::IDENTITY; |
979 | 0 | if (auto pElement = XMLNode.child("rotation")) { |
980 | 0 | Quaternion rotation = parseQuaternion(pElement); |
981 | 0 | keyframe->setRotation(rotation); |
982 | 0 | } |
983 | | |
984 | | // Process scale (?) |
985 | | //Vector3 scale = parseVector3(XMLNode.child("scale")); |
986 | 0 | if (auto pElement = XMLNode.child("scale")) { |
987 | 0 | Vector3 scale = parseVector3(pElement); |
988 | 0 | keyframe->setScale(scale); |
989 | 0 | } |
990 | 0 | } |
991 | | |
992 | | void DotSceneLoader::exportScene(SceneNode* rootNode, const String& outFileName) |
993 | 0 | { |
994 | 0 | pugi::xml_document XMLDoc; // character type defaults to char |
995 | 0 | auto comment = XMLDoc.append_child(pugi::node_comment); |
996 | 0 | comment.set_value(StringUtil::format(" exporter: Plugin_DotScene %d.%d.%d ", OGRE_VERSION_MAJOR, |
997 | 0 | OGRE_VERSION_MINOR, OGRE_VERSION_PATCH) |
998 | 0 | .c_str()); |
999 | 0 | auto scene = XMLDoc.append_child("scene"); |
1000 | 0 | scene.append_attribute("formatVersion") = "1.1"; |
1001 | 0 | scene.append_attribute("sceneManager") = rootNode->getCreator()->getTypeName().c_str(); |
1002 | |
|
1003 | 0 | auto nodes = scene.append_child("nodes"); |
1004 | |
|
1005 | 0 | for(auto c : rootNode->getChildren()) |
1006 | 0 | writeNode(nodes, static_cast<SceneNode*>(c)); |
1007 | | |
1008 | | //writeNode(nodes, rootNode); |
1009 | |
|
1010 | 0 | XMLDoc.save_file(outFileName.c_str()); |
1011 | 0 | } |
1012 | | |
1013 | | static void write(pugi::xml_node& node, const Vector3& v) |
1014 | 0 | { |
1015 | 0 | node.append_attribute("x") = StringConverter::toString(v.x).c_str(); |
1016 | 0 | node.append_attribute("y") = StringConverter::toString(v.y).c_str(); |
1017 | 0 | node.append_attribute("z") = StringConverter::toString(v.z).c_str(); |
1018 | 0 | } |
1019 | | |
1020 | | static void write(pugi::xml_node& node, const ColourValue& c) |
1021 | 0 | { |
1022 | 0 | node.append_attribute("r") = StringConverter::toString(c.r).c_str(); |
1023 | 0 | node.append_attribute("g") = StringConverter::toString(c.g).c_str(); |
1024 | 0 | node.append_attribute("b") = StringConverter::toString(c.b).c_str(); |
1025 | 0 | node.append_attribute("a") = StringConverter::toString(c.a).c_str(); |
1026 | 0 | } |
1027 | | |
1028 | | void DotSceneLoader::writeNode(pugi::xml_node& parentXML, const SceneNode* n) |
1029 | 0 | { |
1030 | 0 | auto nodeXML = parentXML.append_child("node"); |
1031 | 0 | if(!n->getName().empty()) |
1032 | 0 | nodeXML.append_attribute("name") = n->getName().c_str(); |
1033 | |
|
1034 | 0 | auto pos = nodeXML.append_child("position"); |
1035 | 0 | write(pos, n->getPosition()); |
1036 | |
|
1037 | 0 | auto scale = nodeXML.append_child("scale"); |
1038 | 0 | write(scale, n->getScale()); |
1039 | |
|
1040 | 0 | auto rot = nodeXML.append_child("rotation"); |
1041 | 0 | rot.append_attribute("qw") = StringConverter::toString(n->getOrientation().w).c_str(); |
1042 | 0 | rot.append_attribute("qx") = StringConverter::toString(n->getOrientation().x).c_str(); |
1043 | 0 | rot.append_attribute("qy") = StringConverter::toString(n->getOrientation().y).c_str(); |
1044 | 0 | rot.append_attribute("qz") = StringConverter::toString(n->getOrientation().z).c_str(); |
1045 | |
|
1046 | 0 | for(auto mo : n->getAttachedObjects()) |
1047 | 0 | { |
1048 | 0 | if(auto c = dynamic_cast<Camera*>(mo)) |
1049 | 0 | { |
1050 | 0 | auto camera = nodeXML.append_child("camera"); |
1051 | 0 | camera.append_attribute("name") = c->getName().c_str(); |
1052 | 0 | auto clipping = camera.append_child("clipping"); |
1053 | 0 | clipping.append_attribute("near") = StringConverter::toString(c->getNearClipDistance()).c_str(); |
1054 | 0 | clipping.append_attribute("far") = StringConverter::toString(c->getFarClipDistance()).c_str(); |
1055 | 0 | continue; |
1056 | 0 | } |
1057 | | |
1058 | 0 | if (auto l = dynamic_cast<Light*>(mo)) |
1059 | 0 | { |
1060 | 0 | auto light = nodeXML.append_child("light"); |
1061 | 0 | light.append_attribute("name") = l->getName().c_str(); |
1062 | 0 | light.append_attribute("castShadows") = StringConverter::toString(l->getCastShadows()).c_str(); |
1063 | |
|
1064 | 0 | if(!l->isVisible()) |
1065 | 0 | light.append_attribute("visible") = "false"; |
1066 | |
|
1067 | 0 | auto diffuse = light.append_child("colourDiffuse"); |
1068 | 0 | write(diffuse, l->getDiffuseColour()); |
1069 | 0 | auto specular = light.append_child("colourSpecular"); |
1070 | 0 | write(specular, l->getSpecularColour()); |
1071 | 0 | switch (l->getType()) |
1072 | 0 | { |
1073 | 0 | case Light::LT_POINT: |
1074 | 0 | light.append_attribute("type") = "point"; |
1075 | 0 | break; |
1076 | 0 | case Light::LT_DIRECTIONAL: |
1077 | 0 | light.append_attribute("type") = "directional"; |
1078 | 0 | break; |
1079 | 0 | case Light::LT_SPOTLIGHT: |
1080 | 0 | light.append_attribute("type") = "spot"; |
1081 | 0 | break; |
1082 | 0 | case Light::LT_RECTLIGHT: |
1083 | 0 | light.append_attribute("type") = "rect"; |
1084 | 0 | break; |
1085 | 0 | } |
1086 | | |
1087 | 0 | if(l->getType() != Light::LT_DIRECTIONAL) |
1088 | 0 | { |
1089 | 0 | auto range = light.append_child("lightRange"); |
1090 | 0 | range.append_attribute("inner") = |
1091 | 0 | StringConverter::toString(l->getSpotlightInnerAngle()).c_str(); |
1092 | 0 | range.append_attribute("outer") = |
1093 | 0 | StringConverter::toString(l->getSpotlightOuterAngle()).c_str(); |
1094 | 0 | range.append_attribute("falloff") = |
1095 | 0 | StringConverter::toString(l->getSpotlightFalloff()).c_str(); |
1096 | 0 | auto atten = light.append_child("lightAttenuation"); |
1097 | 0 | atten.append_attribute("range") = |
1098 | 0 | StringConverter::toString(l->getAttenuationRange()).c_str(); |
1099 | 0 | atten.append_attribute("constant") = |
1100 | 0 | StringConverter::toString(l->getAttenuationConstant()).c_str(); |
1101 | 0 | atten.append_attribute("linear") = |
1102 | 0 | StringConverter::toString(l->getAttenuationLinear()).c_str(); |
1103 | 0 | atten.append_attribute("quadratic") = |
1104 | 0 | StringConverter::toString(l->getAttenuationQuadric()).c_str(); |
1105 | 0 | } |
1106 | |
|
1107 | 0 | continue; |
1108 | 0 | } |
1109 | | |
1110 | 0 | if(auto e = dynamic_cast<Entity*>(mo)) |
1111 | 0 | { |
1112 | 0 | auto entity = nodeXML.append_child("entity"); |
1113 | 0 | entity.append_attribute("name") = e->getName().c_str(); |
1114 | 0 | entity.append_attribute("meshFile") = e->getMesh()->getName().c_str(); |
1115 | |
|
1116 | 0 | if(!e->isVisible()) |
1117 | 0 | entity.append_attribute("visible") = "false"; |
1118 | | |
1119 | | // Heuristic: assume first submesh is representative |
1120 | 0 | auto sub0mat = e->getSubEntity(0)->getMaterial(); |
1121 | 0 | if(sub0mat != e->getMesh()->getSubMesh(0)->getMaterial()) |
1122 | 0 | entity.append_attribute("material") = sub0mat->getName().c_str(); |
1123 | 0 | continue; |
1124 | 0 | } |
1125 | | |
1126 | 0 | LogManager::getSingleton().logWarning("DotSceneLoader - unsupported MovableType " + |
1127 | 0 | mo->getMovableType()); |
1128 | 0 | } |
1129 | | |
1130 | | // recurse |
1131 | 0 | for(auto c : n->getChildren()) |
1132 | 0 | writeNode(nodeXML, static_cast<SceneNode*>(c)); |
1133 | 0 | } |
1134 | | |
1135 | 1 | const Ogre::String& DotScenePlugin::getName() const { |
1136 | 1 | static Ogre::String name = "DotScene Loader"; |
1137 | 1 | return name; |
1138 | 1 | } |
1139 | | |
1140 | | void DotScenePlugin::install() |
1141 | 1 | { |
1142 | 1 | mCodec = new DotSceneCodec(); |
1143 | 1 | Codec::registerCodec(mCodec); |
1144 | 1 | } |
1145 | | |
1146 | 0 | void DotScenePlugin::shutdown() { |
1147 | 0 | Codec::unregisterCodec(mCodec); |
1148 | 0 | delete mCodec; |
1149 | 0 | } |
1150 | | |
1151 | | #ifndef OGRE_STATIC_LIB |
1152 | | extern "C" _OgreDotScenePluginExport void dllStartPlugin(); |
1153 | | extern "C" _OgreDotScenePluginExport void dllStopPlugin(); |
1154 | | |
1155 | | static DotScenePlugin plugin; |
1156 | | |
1157 | | extern "C" _OgreDotScenePluginExport void dllStartPlugin() |
1158 | | { |
1159 | | Ogre::Root::getSingleton().installPlugin(&plugin); |
1160 | | } |
1161 | | extern "C" _OgreDotScenePluginExport void dllStopPlugin() |
1162 | | { |
1163 | | Ogre::Root::getSingleton().uninstallPlugin(&plugin); |
1164 | | } |
1165 | | #endif |