SO3Engine
ALNode.cpp
Go to the documentation of this file.
6
7namespace SO3
8{
9 ALNode::ALNode(aiNode* asNode, SNode* pNode, ALScene* alscene, std::vector<aiCamera*> camerasNames, std::vector<aiLight*> lightsNames)
10 {
11 mCameras = camerasNames;
12 mLights = lightsNames;
13 mScene = alscene;
14 mOrigin = asNode;
15 mParent = pNode;
16
17 // building NodeAnim vector.
18 aiAnimation** anims = alscene->getAiScene()->mAnimations;
19 for(unsigned int n=0; n<alscene->getAiScene()->mNumAnimations; ++n)
20 {
21 //nodes animation
22 for(unsigned int i=0; i<anims[n]->mNumChannels; ++i)
23 {
24 if(anims[n]->mChannels[i]->mNodeName == mOrigin->mName)
25 {
26 ALConverterNodeAnim nodeAnim(mScene, anims[n], anims[n]->mChannels[i], mOrigin, anims[n]->mTicksPerSecond);
27 mNodeAnim.push_back(nodeAnim);
28 }
29 }
30 }
31 }
32
33 ALNode::ALNode(aiNode* asNode, SNode* pNode, ALScene* alscene, std::vector<aiCamera*> camerasNames, std::vector<aiLight*> lightsNames, tinyxml2::XMLElement* xmlParent)
34 {
35 mScene = alscene;
36 mCameras = camerasNames;
37 mLights = lightsNames;
38
39 mOrigin = asNode;
40 mParent = pNode;
41 mParentNodeXml = xmlParent;
42
43 // building NodeAnim vector.
44 aiAnimation** anims = alscene->getAiScene()->mAnimations;
45 for(unsigned int n=0; n<alscene->getAiScene()->mNumAnimations; ++n)
46 {
47 for(unsigned int i=0; i<anims[n]->mNumChannels; ++i)
48 {
49 if(anims[n]->mChannels[i]->mNodeName == mOrigin->mName)
50 {
51 ALConverterNodeAnim nodeAnim(mScene, anims[n], anims[n]->mChannels[i], mOrigin, anims[n]->mTicksPerSecond);
52 mNodeAnim.push_back(nodeAnim);
53 }
54 }
55 }
56 }
57
59 {
60 mNodeAnim.clear();
61 mCameras.clear();
62 mLights.clear();
63 }
64
65 float ALNode::processRange(aiLight* light)
66 {
67 if ((ConversionTools::fequal(light->mAttenuationLinear, 0.0f)) && (ConversionTools::fequal(light->mAttenuationQuadratic, 0.0f)))
68 return 100.0f;
69
70 if (ConversionTools::fequal(light->mAttenuationConstant, 0.0f))
71 light->mAttenuationConstant = 1.0f;
72
73 if (ConversionTools::fequal(light->mAttenuationQuadratic, 0.0f))
74 light->mAttenuationQuadratic = 0.000001f;
75
76 float range = (sqrt(4 * light->mAttenuationConstant * light->mAttenuationQuadratic + light->mAttenuationLinear + 4 * light->mAttenuationQuadratic) - light->mAttenuationLinear) / (2 * light->mAttenuationQuadratic);
77
78 aiVector3D scale;
79 aiVector3D pos;
80 aiQuaternion quat;
81 mScene->getFullTransform(mOrigin).Decompose(scale, quat, pos);
82 float coef = (scale.x + scale.y + scale.z) / 3.0f;
83 return range * coef;
84 }
85
86 tinyxml2::XMLElement* ALNode::convert(boost::filesystem::path expPath)
87 {
88 if (!isSceneDependent(mOrigin))
89 return 0;
90
91 // Before converting the asimmp node in a scol one, we need to clean the name.
92 // It's very important since a lot of 3d application allow a lot of things
93 // ( like space, redundant name, non-ASCII char, ... ) in ressources and nodes name,
94 // which is nice from a user stand point but generate a lot of troubles for the programmer
95 // ( especially when dealing with Ogre and his way of handling things by name ).
96 // So we clean all those nasty things before hand.
97 std::string basename((mOrigin->mName).C_Str());
98
99 if (basename.find(mScene->getRessourcePath()) != std::string::npos)
100 basename = boost::filesystem::path(basename).stem().generic_string();
101
102 //For complex ifc node names we remove the hash
103 if (basename.find("Ifc") != std::string::npos)
104 basename = basename.substr(0, basename.length() - 22);
105
106 if (basename == "")
107 basename = ALStringCleaner::cleanString(mScene->getSceneName());
108 else
109 basename = ALStringCleaner::cleanString(basename);
110
111 tinyxml2::XMLDocument* dotScene = mParentNodeXml->GetDocument();
112 tinyxml2::XMLElement* xmlNode = dotScene->NewElement("node");
113 xmlNode->SetAttribute("name", basename.c_str());
114 xmlNode->SetAttribute("id", ALStringCleaner::curentUID().c_str());
115 xmlNode->SetAttribute("isTarget", "false");
116
117 // Node animations :
118 for(unsigned int n=0; n<mNodeAnim.size(); ++n)
119 {
120 if(mNodeAnim[n].isAffected(mOrigin->mName))
121 mNodeAnim[n].convert(xmlNode, (n == 0) ? true : false);
122 }
123
124 Ogre::Vector3 direction(Ogre::Vector3::UNIT_Z);
125 if(isMesh(mOrigin))
126 {
127 convertMesh(expPath, xmlNode);
128 }
129 else if(isLight(mOrigin))
130 {
131 aiLight* cLight=0;
132 for(unsigned int n=0; n<mLights.size(); ++n)
133 {
134 if(mOrigin->mName == mLights[n]->mName)
135 {
136 cLight = mLights[n];
137 break;
138 }
139 }
140
141 if(cLight==0)
142 throw "No light associated to this node.";
143
144 tinyxml2::XMLElement* xmlight = dotScene->NewElement("light");
145 direction = Ogre::Vector3(cLight->mDirection.x, cLight->mDirection.y, cLight->mDirection.z);
146 xmlight->SetAttribute("name", basename.c_str());
147 xmlight->SetAttribute("id", ALStringCleaner::curentUID().c_str());
148 if(cLight->mType == aiLightSource_POINT)
149 xmlight->SetAttribute("type", "point");
150 else if(cLight->mType == aiLightSource_SPOT)
151 xmlight->SetAttribute("type", "spot");
152 else
153 xmlight->SetAttribute("type", "directional");
154
155 xmlight->SetAttribute("castShadows", (cLight->mType == aiLightSource_DIRECTIONAL) ? true : false);
156
157 tinyxml2::XMLElement* diffuse = dotScene->NewElement("colourDiffuse");
158 diffuse->SetAttribute("r", cLight->mColorDiffuse.r);
159 diffuse->SetAttribute("g", cLight->mColorDiffuse.g);
160 diffuse->SetAttribute("b", cLight->mColorDiffuse.b);
161 xmlight->InsertEndChild(diffuse);
162
163 tinyxml2::XMLElement* specular = dotScene->NewElement("colourSpecular");
164 specular->SetAttribute("r", cLight->mColorSpecular.r);
165 specular->SetAttribute("g", cLight->mColorSpecular.g);
166 specular->SetAttribute("b", cLight->mColorSpecular.b);
167 xmlight->InsertEndChild(specular);
168
169 tinyxml2::XMLElement* atten = dotScene->NewElement("lightAttenuation");
170 atten->SetAttribute("range", ConversionTools::formatFloatToString(processRange(cLight)).c_str());
171 atten->SetAttribute("constant", ConversionTools::formatFloatToString(cLight->mAttenuationConstant).c_str());
172 atten->SetAttribute("linear", ConversionTools::formatFloatToString(cLight->mAttenuationLinear).c_str());
173 atten->SetAttribute("quadratic", ConversionTools::formatFloatToString(cLight->mAttenuationQuadratic).c_str());
174 xmlight->InsertEndChild(atten);
175
176 if(cLight->mType == aiLightSource_SPOT)
177 {
178 tinyxml2::XMLElement* lrange = dotScene->NewElement("lightRange");
179 lrange->SetAttribute("inner", ConversionTools::formatFloatToString(cLight->mAngleInnerCone).c_str());
180 lrange->SetAttribute("outer", ConversionTools::formatFloatToString(cLight->mAngleOuterCone).c_str());
181 //lrange->SetAttribute("falloff", cLight->);
182 xmlight->InsertEndChild(lrange);
183 }
184
185 xmlNode->InsertEndChild(xmlight);
186 }
187 else if(isCamera(mOrigin))
188 {
189 aiCamera* cCamera=0;
190 for(unsigned int n=0; n<mCameras.size(); ++n)
191 {
192 if(mOrigin->mName == mCameras[n]->mName)
193 {
194 cCamera = mCameras[n];
195 break;
196 }
197 }
198
199 tinyxml2::XMLElement* xmlcam = dotScene->NewElement("camera");
200
201 float fovY = cCamera->mHorizontalFOV * cCamera->mAspect;
202 Ogre::Radian gfovY(fovY);
203
204 if (fovY < 0.1f)
205 gfovY = Ogre::Radian(3.14f / 4.0f);
206
207 xmlcam->SetAttribute("name", basename.c_str());
208 xmlcam->SetAttribute("id", ALStringCleaner::curentUID().c_str());
209 xmlcam->SetAttribute("fov", ConversionTools::formatFloatToString(gfovY.valueRadians()).c_str());
210
211 tinyxml2::XMLElement* clipping = dotScene->NewElement("clipping");
212 clipping->SetAttribute("near", ConversionTools::formatFloatToString(cCamera->mClipPlaneNear).c_str());
213 clipping->SetAttribute("far", ConversionTools::formatFloatToString(cCamera->mClipPlaneFar).c_str());
214 xmlcam->InsertEndChild(clipping);
215
216 xmlNode->InsertEndChild(xmlcam);
217 }
218
219 // Set up the transformation
220 aiMatrix4x4 transformation = mOrigin->mTransformation;
221 aiVector3D scale;
222 aiVector3D pos;
223 aiQuaternion rotation;
224 transformation.Decompose(scale, rotation, pos);
225
226 tinyxml2::XMLElement* xmlposition = dotScene->NewElement("position");
227 xmlposition->SetAttribute("x", ConversionTools::formatFloatToString(pos.x).c_str());
228 xmlposition->SetAttribute("y", ConversionTools::formatFloatToString(pos.y).c_str());
229 xmlposition->SetAttribute("z", ConversionTools::formatFloatToString(pos.z).c_str());
230 xmlNode->InsertFirstChild(xmlposition);
231
232 Ogre::Quaternion oRot(rotation.w, rotation.x, rotation.y, rotation.z);
233 if (!mParent && mScene->GetSceneLoader()->getFlags() & so3Converter_RotateX)
234 oRot = oRot * Ogre::Quaternion(sqrt(0.5f), -sqrt(0.5f), 0.0f, 0.0f);
235
236 if(isLight(mOrigin) || isCamera(mOrigin))
237 {
238 Ogre::Vector3 xaxis = Ogre::Vector3::UNIT_X * direction.x;
239 Ogre::Vector3 yaxis = Ogre::Vector3::UNIT_Y * direction.y;
240 Ogre::Vector3 zaxis = Ogre::Vector3::UNIT_Z * direction.z;
241 Ogre::Quaternion dirRotation(xaxis, yaxis, zaxis);
242
243 oRot = oRot * dirRotation;
244 }
245
246 tinyxml2::XMLElement* xmlrotation = dotScene->NewElement("rotation");
247 xmlrotation->SetAttribute("qx", ConversionTools::formatFloatToString(oRot.x).c_str());
248 xmlrotation->SetAttribute("qy", ConversionTools::formatFloatToString(oRot.y).c_str());
249 xmlrotation->SetAttribute("qz", ConversionTools::formatFloatToString(oRot.z).c_str());
250 xmlrotation->SetAttribute("qw", ConversionTools::formatFloatToString(oRot.w).c_str());
251 xmlNode->InsertFirstChild(xmlrotation);
252
253 tinyxml2::XMLElement* xmlscale = dotScene->NewElement("scale");
254 xmlscale->SetAttribute("x", ConversionTools::formatFloatToString(scale.x).c_str());
255 xmlscale->SetAttribute("y", ConversionTools::formatFloatToString(scale.y).c_str());
256 xmlscale->SetAttribute("z", ConversionTools::formatFloatToString(scale.z).c_str());
257 xmlNode->InsertFirstChild(xmlscale);
258
259
260 mParentNodeXml->InsertEndChild(xmlNode);
261
262 return xmlNode;
263 }
264
266 {
267 // Before converting the asimmp node in a scol one, we need to clean the name.
268 // It's very important since a lot of 3d application allow a lot of things
269 // ( like space, redundant name, non-ASCII char, ... ) in ressources and nodes name,
270 // which is nice from a user stand point but generate a lot of troubles for the programmer
271 // ( especially when dealing with Ogre and his way of handling things by name ).
272 // So we clean all those nasty things before hand.
273 std::string basename((mOrigin->mName).C_Str());
274
275 //For complex ifc node names we remove the hash
276 if (basename.find("Ifc") != std::string::npos)
277 basename = basename.substr(0, basename.length() - 22);
278
279 basename = ALStringCleaner::cleanString(basename);
280
281 // Now we create the SNode.
282 // Note that the constructor we use should create a unique name by suffixing the basename
283 // with the position of the node in the list.
284 SNode* gudNode = 0;
285 Ogre::Vector3 direction;
286
287 try
288 {
289 if(isMesh(mOrigin))
290 {
291 SEntity* entity = loadMesh();
292 gudNode = static_cast<SNode*>(entity);
293 }
294 else if(isLight(mOrigin))
295 {
296 SLight* nlight = makeLight(mOrigin, direction);
297 gudNode = static_cast<SNode*>(nlight);
298 }
299 else if (!isBone(mOrigin))
300 {
301 gudNode = mScene->getSScene()->CreateNodeWithUniqueName(basename);
302 }
303
304 if (gudNode)
305 {
306 gudNode->AttachToParent(mParent);
307
308 // Now we need to add the position of the Node.
309 aiMatrix4x4 transformation = mOrigin->mTransformation;
310 aiVector3D scale;
311 aiVector3D pos;
312 aiQuaternion rotation;
313
314 transformation.Decompose(scale, rotation, pos);
315 Ogre::Vector3 oScale(scale.x, scale.y, scale.z);
316 Ogre::Vector3 oPos(pos.x, pos.y, pos.z);
317
318 Ogre::Quaternion oRot(rotation.w, rotation.x, rotation.y, rotation.z);
319 if (!mParent && mScene->GetSceneLoader()->getFlags() & so3Converter_RotateX)
320 oRot = oRot * Ogre::Quaternion(sqrt(0.5f), -sqrt(0.5f), 0.0f, 0.0f);
321
322 gudNode->SetPosition(oPos);
323 gudNode->SetScale(oScale);
324 gudNode->SetOrientation(oRot);
325
326 // Node animations :
327 for(unsigned int n=0; n<mNodeAnim.size(); ++n)
328 {
329 if(mNodeAnim[n].isAffected(mOrigin->mName))
330 mNodeAnim[n].load(gudNode);
331 }
332 }
333 }
334 catch(Ogre::Exception&)
335 {
336 //error on creation
337 }
338
339 return gudNode;
340 }
341
342 void ALNode::convertMesh(boost::filesystem::path expPath, tinyxml2::XMLElement* nParent)
343 {
344 ALMesh meshConverter(mOrigin, mScene);
345 meshConverter.convert(expPath, nParent);
346 }
347
348 SEntity* ALNode::loadMesh()
349 {
350 ALMesh meshConverter(mOrigin, mScene);
351 SEntity* convertedMesh = meshConverter.load();
352
353 return convertedMesh;
354 }
355
356 bool ALNode::isMesh(aiNode* node)
357 {
358 return (node->mNumMeshes > 0) ? true : false;
359 }
360
361 bool ALNode::isCamera(aiNode* node)
362 {
363 for(unsigned int n=0; n<mCameras.size(); ++n)
364 {
365 if(node->mName == mCameras[n]->mName)
366 return true;
367 }
368
369 return false;
370 }
371
372 bool ALNode::isLight(aiNode* node)
373 {
374 for(unsigned int n=0; n<mLights.size(); ++n)
375 {
376 if(node->mName == mLights[n]->mName)
377 return true;
378 }
379
380 return false;
381 }
382
383 bool ALNode::isBone(aiNode* node)
384 {
385 return mScene->isBone(node);
386 }
387
388 bool ALNode::isSceneDependent(aiNode* node)
389 {
390 return mScene->isSceneDependent(node);
391 }
392
393 SCamera* ALNode::makeCamera(aiNode* node)
394 {
395 aiCamera* cCamera=0;
396 for(unsigned int n=0; n<mCameras.size(); ++n)
397 {
398 if(node->mName == mCameras[n]->mName)
399 {
400 cCamera = mCameras[n];
401 break;
402 }
403 }
404
405 float fovY = cCamera->mHorizontalFOV * cCamera->mAspect;
406 Ogre::Radian gfovY(fovY);
407
408 if (fovY < 0.1f)
409 gfovY = Ogre::Radian(3.14f / 4.0f);
410
411 SCamera* scolCam = mScene->getSScene()->CreateCamera(ALStringCleaner::cleanString(cCamera->mName.C_Str()));
412 scolCam->SetAutoAspectRatio(true);
413 scolCam->SetFarClipDistance(cCamera->mClipPlaneFar);
414 scolCam->SetNearClipDistance(cCamera->mClipPlaneNear);
415 scolCam->SetFOVy(gfovY.valueRadians());
416 scolCam->LookAt(Ogre::Vector3(cCamera->mLookAt.x, cCamera->mLookAt.y, cCamera->mLookAt.z), SNode::SO3_WORLD_TS);
417
418 return scolCam;
419 }
420
421 SLight* ALNode::makeLight(aiNode* node, Ogre::Vector3& direction)
422 {
423 aiLight* cLight=0;
424 for(unsigned int n=0; n<mLights.size(); ++n)
425 {
426 if(node->mName == mLights[n]->mName)
427 {
428 cLight = mLights[n];
429 break;
430 }
431 }
432
433 if(cLight==0)
434 throw "No light associated to this node.";
435
436 SLight* scolLight = mScene->getSScene()->CreateLight(ALStringCleaner::cleanString(cLight->mName.C_Str()));
437 //scolLight->SetAttenuation(solveLightRange(light[n]), light[n]->mAttenuationConstant, light[n]->mAttenuationLinear, light[n]->mAttenuationQuadratic);
438
439 scolLight->SetAttenuation(processRange(cLight));
440 scolLight->SetDiffuseColour(Ogre::ColourValue(cLight->mColorDiffuse.r, cLight->mColorDiffuse.g, cLight->mColorDiffuse.b, 1.f));
441 scolLight->SetSpecularColour(Ogre::ColourValue(cLight->mColorSpecular.r, cLight->mColorSpecular.g, cLight->mColorSpecular.b, 1.f));
442
443 scolLight->SetDirection(Ogre::Vector3(cLight->mDirection.x, cLight->mDirection.y, cLight->mDirection.z));
444
445 if(cLight->mType == aiLightSource_SPOT)
446 scolLight->SetType(SLight::SO3_SPOT_LIGHT);
447 else if(cLight->mType == aiLightSource_POINT)
448 scolLight->SetType(SLight::SO3_POINT_LIGHT);
449 else if(cLight->mType == aiLightSource_AREA)
450 scolLight->SetType(SLight::SO3_RECT_LIGHT);
451 else
452 scolLight->SetType(SLight::SO3_DIRECTIONAL_LIGHT);
453
454 scolLight->SetSourceSize(cLight->mSize.x, cLight->mSize.y);
455 scolLight->SetSpotlightInnerAngle(cLight->mAngleInnerCone);
456 scolLight->SetSpotlightOuterAngle(cLight->mAngleOuterCone);
457
458 return scolLight;
459 }
460}
static std::string curentUID()
return the current UID WITHOUT incrementing the UID.
static std::string cleanString(std::string str, bool toLower=true, bool clASCII=true, bool clSpaces=true, bool bUID=true)
Clean a string.
bool isMesh(aiNode *node)
Check if a node is a mesh.
Definition ALNode.cpp:356
SNode * load()
Definition ALNode.cpp:265
ALNode(aiNode *asNode, SNode *pNode, ALScene *alscene, std::vector< aiCamera * > camerasNames, std::vector< aiLight * > lightsNames)
Definition ALNode.cpp:9
bool isSceneDependent(aiNode *node)
Definition ALNode.cpp:388
bool isCamera(aiNode *node)
Check if a node is a camera.
Definition ALNode.cpp:361
bool isBone(aiNode *node)
Check if a node is a bone.
Definition ALNode.cpp:383
bool isLight(aiNode *node)
Check if a node is a light.
Definition ALNode.cpp:372
tinyxml2::XMLElement * convert(boost::filesystem::path expPath)
Definition ALNode.cpp:86
aiMatrix4x4 getFullTransform(aiNode *toThis)
Definition ALScene.cpp:60
SScene * getSScene()
Definition ALScene.cpp:487
ALSceneLoader * GetSceneLoader()
Definition ALScene.h:98
bool isSceneDependent(aiNode *node)
Definition ALScene.cpp:545
const aiScene * getAiScene()
Definition ALScene.cpp:492
std::string getSceneName()
Definition ALScene.cpp:507
bool isBone(aiNode *node)
Check if a node is a bone.
Definition ALScene.cpp:517
std::string getRessourcePath()
Definition ALScene.cpp:502
unsigned int getFlags()
static std::string formatFloatToString(double val)
static bool fequal(float a, float b)
void SetAutoAspectRatio(bool state)
Definition SO3Camera.cpp:89
void SetAttenuation(const float &range, const float &constant, const float &linear, const float &quadratic)
Definition SO3Light.cpp:172
@ SO3_RECT_LIGHT
Definition SO3Light.h:51
@ SO3_SPOT_LIGHT
Definition SO3Light.h:50
@ SO3_POINT_LIGHT
Definition SO3Light.h:48
@ SO3_DIRECTIONAL_LIGHT
Definition SO3Light.h:49
virtual void SetScale(const Ogre::Vector3 &scale)
virtual void SetOrientation(const Ogre::Quaternion &quat)
virtual void SetPosition(const Ogre::Vector3 &pos)
void AttachToParent(SNode *newParentNode)
SNode * CreateNodeWithUniqueName(const std::string &basename)
Definition SO3Scene.cpp:611
SLight * CreateLight(const std::string &newLightName)
Definition SO3Scene.cpp:980
SCamera * CreateCamera(const std::string &newCameraName)
Definition SO3Scene.cpp:653
XMLElement * NewElement(const char *name)
void SetAttribute(const char *name, const char *value)
Sets the named attribute to value.
Definition tinyxml2.h:1303
const XMLDocument * GetDocument() const
Get the XMLDocument that owns this XMLNode.
Definition tinyxml2.h:592
XMLNode * InsertFirstChild(XMLNode *addThis)
XMLNode * InsertEndChild(XMLNode *addThis)