SO3Engine
SO3Entity.cpp
Go to the documentation of this file.
1/*
2-----------------------------------------------------------------------------
3This source file is part of OpenSpace3D
4For the latest info, see http://www.openspace3d.com
5
6Copyright (c) 2012 I-maginer
7
8This program is free software; you can redistribute it and/or modify it under
9the terms of the GNU Lesser General Public License as published by the Free Software
10Foundation; either version 2 of the License, or (at your option) any later
11version.
12
13This program is distributed in the hope that it will be useful, but WITHOUT
14ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
15FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
16
17You should have received a copy of the GNU Lesser General Public License along with
18this program; if not, write to the Free Software Foundation, Inc., 59 Temple
19Place - Suite 330, Boston, MA 02111-1307, USA, or go to
20http://www.gnu.org/copyleft/lesser.txt
21
22-----------------------------------------------------------------------------
23*/
24
38#include "SO3Renderer/SO3Root.h"
40
41#include "OgreMeshLodGenerator.h"
42#include "OgrePixelCountLodStrategy.h"
43#include "OgreLodData.h"
44#include "OgreLodConfig.h"
45#include "OgreLodCollapser.h"
46
47 // Utils includes
49
50extern int OBJECT_LOADED_EVENT;
51
52namespace SO3
53{
54 SEntity::SEntity(SScene* parent, const std::string& groupName, const std::string& entityName, const std::string& meshName, bool loadInBackground) : SNode(parent, entityName, SNode::ENTITY_TYPE_ID)
55 {
56 entitySKL = 0;
57 mGroupName = groupName;
58 mReleaseResource = false;
59 mResourceName = meshName;
60 O3Entity = 0;
61 mLoading = loadInBackground;
62 mNumLodLevel = 0;
63
64 bool lastLogstate = SRoot::getSingletonPtr()->GetLogEnable();
66
67 //group name or not Ogre get the previous loaded ressource if exist !! the same in load
68 mMesh = Ogre::MeshManager::getSingleton().getByName(meshName, mGroupName);
69
70 if (!mMesh)
71 {
72 if (loadInBackground)
73 {
74 try
75 {
76 mMesh = Ogre::MeshManager::getSingletonPtr()->create(meshName, mGroupName);
77 }
78 catch (Ogre::Exception &e)
79 {
80 SRoot::getSingletonPtr()->SetLogEnable(lastLogstate);
81
82 // Catching .skeleton error. Forwarding other errors.
83 if (e.getFullDescription().find(".skeleton") == std::string::npos)
84 {
85 Ogre::LogManager::getSingletonPtr()->logMessage(e.getFullDescription(), Ogre::LML_CRITICAL, true);
86 throw e;
87 }
88 }
89 }
90 else
91 {
92 try
93 {
94 mMesh = Ogre::MeshManager::getSingletonPtr()->load(meshName, mGroupName);
95 }
96 catch (Ogre::Exception &e)
97 {
98 SRoot::getSingletonPtr()->SetLogEnable(lastLogstate);
99
100 // Catching .skeleton error. Forwarding other errors.
101 if (e.getFullDescription().find(".skeleton") == std::string::npos)
102 {
103 Ogre::LogManager::getSingletonPtr()->logMessage(e.getFullDescription(), Ogre::LML_CRITICAL, true);
104 throw e;
105 }
106 }
107 }
108
109 SRoot::getSingletonPtr()->SetLogEnable(lastLogstate);
110 }
111
112 if (mMesh->isLoaded() && !loadInBackground)
113 {
114 //we don't use stencil shadows anymore
115 mMesh->setAutoBuildEdgeLists(false);
116 if (mMesh->hasSkeleton())
117 {
118 if (!currentScene->O3SkeletonManager->getByName(mMesh->getSkeletonName(), mMesh->getGroup()))
119 mMesh->setSkeletonName("");
120 }
121
122 Ogre::PoseList plist = mMesh->getPoseList();
123
124 // Check if there's an animation per pose, and create it in the mesh if not exists. NB that those are created in the mesh BEFORE creating the entity!
125 if (plist.size() > 0)
126 {
127 for (unsigned int p = 0; p < plist.size(); p++)
128 {
129 Ogre::Pose* pose = plist[p];
130 std::string animationName = pose->getName();
131
132 // create the animation on the mesh if it doesn't already exist
133 Ogre::Animation* ogreAnimation = 0;
134 if (mMesh->hasAnimation(animationName) == false)
135 {
136 // Log a message for SO3Engine user.
137 Ogre::LogManager::getSingleton().logMessage("No animation was found for mesh pose \"" + animationName + "\", SO3Engine will generate automatically an animation for it, but it'll be cleaner to create this animation in your modeler!");
138
139 ogreAnimation = mMesh->createAnimation(animationName, 0);
140
141 // SO3PoseAnimation will be created later in the CommonConstructorsSequence...
142 // Store pose index as there's not simple way to retrieve this with ogre.
143 poseHandleList.insert(PoseHandleList::value_type(animationName, p));
144 }
145 else
146 {
147 ogreAnimation = mMesh->getAnimation(animationName);
148 }
149
150 Ogre::ushort targetSubMesh = pose->getTarget();
151 if (!ogreAnimation->hasVertexTrack(targetSubMesh))
152 {
153 Ogre::VertexAnimationTrack* vt = ogreAnimation->createVertexTrack(targetSubMesh, Ogre::VAT_POSE);
154 vt->createVertexPoseKeyFrame(0)->addPoseReference(p, 0.0f);
155 }
156 }
157 }
158
159 //initialize LOD
160 if (mMesh->getLodStrategy() != Ogre::ScreenRatioPixelCountLodStrategy::getSingletonPtr())
161 mMesh->setLodStrategy(Ogre::ScreenRatioPixelCountLodStrategy::getSingletonPtr());
162
163 O3Entity = currentScene->GetOgreScenePointer()->createEntity(GetName(), mResourceName, mGroupName);
164
165 CommonConstructorsSequence();
166 }
167 }
168
170 {
171 bool lastLogstate = SRoot::getSingletonPtr()->GetLogEnable();
172 if (mMesh->isLoading())
173 {
174 mMesh->addListener(this);
175 }
176 else if (!mMesh->isLoaded())
177 {
179 try
180 {
181 mMesh->addListener(this);
182 Ogre::ResourceBackgroundQueue::getSingleton().load(mMesh);
183 }
184 catch (Ogre::Exception &e)
185 {
186 SRoot::getSingletonPtr()->SetLogEnable(lastLogstate);
187
188 // Catching .skeleton error. Forwarding other errors.
189 if (e.getFullDescription().find(".skeleton") == std::string::npos)
190 {
191 Ogre::LogManager::getSingletonPtr()->logMessage(e.getFullDescription(), Ogre::LML_CRITICAL, true);
192 throw e;
193 }
194 }
195 SRoot::getSingletonPtr()->SetLogEnable(lastLogstate);
196 }
197
198 if (mMesh->isLoaded())
199 FinishAsync();
200 }
201
203 {
204 if (!mLoading)
205 return;
206
207 //we don't use stencil shadows anymore
208 mMesh->setAutoBuildEdgeLists(false);
209
210 if (mMesh->hasSkeleton())
211 {
212 if (!currentScene->O3SkeletonManager->getByName(mMesh->getSkeletonName(), mMesh->getGroup()))
213 mMesh->setSkeletonName("");
214 }
215
216 /*if(mMesh->isLodManual())
217 {
218 Ogre::MeshManager::getSingleton().unload(mMesh->getHandle());
219 OGRE_EXCEPT(Ogre::Exception::ERR_INTERNAL_ERROR, "Cannot load a mesh with manual LOD!", "SEntity::SEntity");
220 }*/
221
222 //remove skeleton path (will be added after)
223 //mMesh->setSkeletonName("");
224
225 // Check if there's an animation per pose, and create it in the mesh if not exists. NB that those are created in the mesh BEFORE creating the entity!
226 Ogre::PoseList poseList = mMesh->getPoseList();
227 if (poseList.size() > 0)
228 {
229 for (unsigned int p = 0; p < poseList.size(); p++)
230 {
231 Ogre::Pose* pose = poseList[p];
232 std::string animationName = pose->getName();
233
234 // create the animation on the mesh if it doesn't already exist
235 Ogre::Animation* ogreAnimation = 0;
236 if (mMesh->hasAnimation(animationName) == false)
237 {
238 // Log a message for SO3Engine user.
239 Ogre::LogManager::getSingleton().logMessage("No animation was found for mesh pose \"" + animationName + "\", SO3Engine will generate automatically an animation for it, but it'll be cleaner to create this animation in your modeler!");
240
241 ogreAnimation = mMesh->createAnimation(animationName, 0);
242
243 // SO3PoseAnimation will be created later in the CommonConstructorsSequence...
244 // Store pose index as there's not simple way to retrieve this with ogre.
245 poseHandleList.insert(PoseHandleList::value_type(animationName, p));
246 }
247 else
248 {
249 ogreAnimation = mMesh->getAnimation(animationName);
250 }
251
252 Ogre::ushort targetSubMesh = pose->getTarget();
253 if (!ogreAnimation->hasVertexTrack(targetSubMesh))
254 {
255 Ogre::VertexAnimationTrack* vt = ogreAnimation->createVertexTrack(targetSubMesh, Ogre::VAT_POSE);
256 vt->createVertexPoseKeyFrame(0)->addPoseReference(p, 0.0f);
257 }
258 }
259 }
260
261 O3Entity = currentScene->GetOgreScenePointer()->createEntity(GetName(), mResourceName, mGroupName);
262 CommonConstructorsSequence();
263
264 if (mNumLodLevel > 0)
265 GenerateLOD(mNumLodLevel);
266
267 mLoading = false;
268
269 OBJpostEvent(OBJECT_LOADED_EVENT, SCOL_PTR this, 0);
270 }
271
272 void SEntity::loadingComplete(Ogre::Resource* res)
273 {
274 FinishAsync();
275 }
276
277
278 SEntity::SEntity(SScene* parent, const std::string& entityName, const std::string& groupName, Ogre::MeshPtr meshPointer) : SNode(parent, entityName, SNode::ENTITY_TYPE_ID)
279 {
280 entitySKL = 0;
281 mGroupName = groupName;
282 mReleaseResource = false;
283 mResourceName = entityName;
284 mLoading = false;
285 mNumLodLevel = 0;
286
287 SRoot* tmpRoot = SRoot::getSingletonPtr();
288 assert(tmpRoot != 0);
289
290 bool lastLogstate = tmpRoot->GetLogEnable();
291 tmpRoot->SetLogEnable(false);
292
293 //group name or not Ogre get the previous loaded ressource if exist !! the same in load
294 mMesh = meshPointer;
295 if (!mMesh)
296 {
297 try
298 {
299 mMesh = meshPointer;
300 }
301 catch (Ogre::Exception &e)
302 {
303 tmpRoot->SetLogEnable(lastLogstate);
304
305 // Catching .skeleton error. Forwarding other errors.
306 if (e.getFullDescription().find(".skeleton") == std::string::npos)
307 {
308 Ogre::LogManager::getSingletonPtr()->logMessage(e.getFullDescription(), Ogre::LML_CRITICAL, true);
309 throw e;
310 }
311 }
312
313 tmpRoot->SetLogEnable(lastLogstate);
314
315 if (mMesh->hasSkeleton())
316 {
317 if (!currentScene->O3SkeletonManager->getByName(mMesh->getSkeletonName(), mMesh->getGroup()))
318 mMesh->setSkeletonName("");
319 }
320 }
321
322 //remove skeleton path (will be added after)
323 //mMesh->setSkeletonName("");
324
325 // Check if there's an animation per pose, and create it in the mesh if not exists. NB that those are created in the mesh BEFORE creating the entity!
326 Ogre::PoseList poseList = mMesh->getPoseList();
327 if (poseList.size() > 0)
328 {
329 for (unsigned int p = 0; p < poseList.size(); p++)
330 {
331 Ogre::Pose* pose = poseList[p];
332 std::string animationName = pose->getName();
333
334 // create the animation on the mesh if it doesn't already exist
335 Ogre::Animation* ogreAnimation = 0;
336 if (mMesh->hasAnimation(animationName) == false)
337 {
338 // Log a message for SO3Engine user.
339 Ogre::LogManager::getSingleton().logMessage("No animation was found for mesh pose \"" + animationName + "\", SO3Engine will generate automatically an animation for it, but it'll be cleaner to create this animation in your modeler!");
340
341 ogreAnimation = mMesh->createAnimation(animationName, 0);
342
343 // SO3PoseAnimation will be created later in the CommonConstructorsSequence...
344 // Store pose index as there's not simple way to retrieve this with ogre.
345 poseHandleList.insert(PoseHandleList::value_type(animationName, p));
346 }
347 else
348 {
349 ogreAnimation = mMesh->getAnimation(animationName);
350 }
351
352 Ogre::ushort targetSubMesh = pose->getTarget();
353 if (!ogreAnimation->hasVertexTrack(targetSubMesh))
354 {
355 Ogre::VertexAnimationTrack* vt = ogreAnimation->createVertexTrack(targetSubMesh, Ogre::VAT_POSE);
356 vt->createVertexPoseKeyFrame(0)->addPoseReference(p, 0.0f);
357 }
358 }
359 }
360
361 O3Entity = currentScene->GetOgreScenePointer()->createEntity(entityName, meshPointer);
362 CommonConstructorsSequence();
363 }
364
365 SEntity::SEntity(SScene* parent, const std::string& entityName, const EntityPrefabType& prefabType) : SNode(parent, entityName, SNode::ENTITY_TYPE_ID)
366 {
367 entitySKL = 0;
368 mGroupName = Ogre::RGN_DEFAULT;
369 mReleaseResource = false;
370 mResourceName = "";
371 mMesh.reset();
372 mLoading = false;
373 mNumLodLevel = 0;
374
375 switch (prefabType)
376 {
377 case SO3_PREFAB_PLANE:
378 O3Entity = currentScene->GetOgreScenePointer()->createEntity(entityName, Ogre::SceneManager::PT_PLANE);
379 break;
380 case SO3_PREFAB_CUBE:
381 O3Entity = currentScene->GetOgreScenePointer()->createEntity(entityName, Ogre::SceneManager::PT_CUBE);
382 break;
384 O3Entity = currentScene->GetOgreScenePointer()->createEntity(entityName, Ogre::SceneManager::PT_SPHERE);
385 break;
386 default:
387 OGRE_EXCEPT(Ogre::Exception::ERR_NOT_IMPLEMENTED, "Unknow prefab type!", "SEntity::SEntity");
388 }
389 CommonConstructorsSequence();
390 }
391
392 //Plane object
393 SEntity::SEntity(SScene* parent, const std::string& groupName, const std::string& entityName, const SPointFloat& sizev, const SPointInt& seg, const SPointFloat& uv) : SNode(parent, entityName, SNode::ENTITY_TYPE_ID)
394 {
395 entitySKL = 0;
396 mGroupName = groupName;
397 mReleaseResource = true;
398 mResourceName = groupName + entityName + ".PlaneRes";
399 mLoading = false;
400 mNumLodLevel = 0;
401
402 Ogre::Plane plane(Ogre::Vector3::UNIT_Y, 0);
403 mMesh = Ogre::MeshManager::getSingleton().createPlane(mResourceName, mGroupName, plane, sizev.x, sizev.y, seg.x, seg.y, true, 1, uv.x, uv.y, Ogre::Vector3::UNIT_Z);
404 O3Entity = currentScene->GetOgreScenePointer()->createEntity(entityName, mResourceName, groupName);
405 CommonConstructorsSequence();
406 }
407
408 //Sphere object
409 SEntity::SEntity(SScene* parent, const std::string& groupName, const std::string& entityName, const float& radius, const int& rings, const int& segments) : SNode(parent, entityName, SNode::ENTITY_TYPE_ID)
410 {
411 entitySKL = 0;
412 mGroupName = groupName;
413 mReleaseResource = true;
414 mResourceName = groupName + entityName + ".SphereRes";
415 mLoading = false;
416 mNumLodLevel = 0;
417
418 mMesh = SBaseMeshsTools::CreateSphere(mResourceName, radius, rings, segments, true, true, mGroupName);
419 O3Entity = currentScene->GetOgreScenePointer()->createEntity(entityName, mResourceName, groupName);
420 CommonConstructorsSequence();
421 }
422
423 //Cone object
424 SEntity::SEntity(SScene* parent, const std::string& groupName, const std::string& entityName, const float& radius, const float& height, const int& segments) : SNode(parent, entityName, SNode::ENTITY_TYPE_ID)
425 {
426 entitySKL = 0;
427 mGroupName = groupName;
428 mReleaseResource = true;
429 mResourceName = groupName + entityName + ".SphereRes";
430 mLoading = false;
431 mNumLodLevel = 0;
432
433 mMesh = SBaseMeshsTools::CreateCone(mResourceName, radius, height, segments, mGroupName);
434 O3Entity = currentScene->GetOgreScenePointer()->createEntity(entityName, mResourceName, groupName);
435 CommonConstructorsSequence();
436 }
437
438 //Octahedron object
439 SEntity::SEntity(SScene* parent, const std::string& groupName, const std::string& entityName, const float& base, const float& bottom, const float& dist) : SNode(parent, entityName, SNode::ENTITY_TYPE_ID)
440 {
441 entitySKL = 0;
442 mGroupName = groupName;
443 mReleaseResource = true;
444 mResourceName = groupName + entityName + ".SphereRes";
445 mLoading = false;
446 mNumLodLevel = 0;
447
448 mMesh = SBaseMeshsTools::CreateOctahedron(mResourceName, base, bottom, dist, mGroupName);
449 O3Entity = currentScene->GetOgreScenePointer()->createEntity(entityName, mResourceName, groupName);
450 CommonConstructorsSequence();
451 }
452
453 SEntity::SEntity() : SNode(0, "", SNode::ENTITY_TYPE_ID)
454 {
455 // Forbiden (private)
456 }
457
458 void SEntity::BuildMissingComponents()
459 {
460 //needed for D3D11
461 if (mMesh->getSubMesh(0) && mMesh->getSubMesh(0)->vertexData)
462 {
463 if (SRoot::getSingleton().GetRenderSystem() == SRoot::SO3_DIRECTX11_RENDERER)
464 {
465 for (unsigned int i = 0; i < mMesh->getNumSubMeshes(); i++)
466 {
467 Ogre::SubMesh* smesh = mMesh->getSubMesh(i);
468 Ogre::VertexData* vdata = smesh->vertexData;
469 if (vdata && !vdata->vertexDeclaration->findElementBySemantic(Ogre::VertexElementSemantic::VES_TEXTURE_COORDINATES))
470 {
471 unsigned short src = vdata->vertexDeclaration->getMaxSource();
472 Ogre::HardwareVertexBufferSharedPtr origBuffer = vdata->vertexBufferBinding->getBuffer(src);
473 unsigned int vcnt = origBuffer->getVertexSize();
474
475 src += 1;
476 Ogre::VertexElement::getTypeSize(Ogre::VET_FLOAT2);
477 vdata->vertexDeclaration->addElement(src, 0, Ogre::VET_FLOAT2, Ogre::VES_TEXTURE_COORDINATES);
478
479 auto tvbuf = mMesh->getHardwareBufferManager()->createVertexBuffer(vcnt + 2 * sizeof(float), vdata->vertexCount, origBuffer->getUsage(), origBuffer->hasShadowBuffer());
480
481 // Bind buffer
482 Ogre::VertexBufferBinding* vBind = vdata->vertexBufferBinding;
483 vBind->setBinding(src, tvbuf);
484
485 // Set up basic tex coordinates
486 Ogre::HardwareVertexBufferSharedPtr vbuf = vdata->vertexBufferBinding->getBuffer(src);
487 Ogre::HardwareBufferLockGuard vbufLock(vbuf, Ogre::HardwareBuffer::HBL_DISCARD);
488 float* pFloat = static_cast<float*>(vbufLock.pData);
489
490 if (smesh->operationType == Ogre::RenderOperation::OT_TRIANGLE_LIST)
491 {
492 for (unsigned int i = 0; i < (vcnt / 3); i++)
493 {
494 *pFloat++ = 0.0f;
495 *pFloat++ = 0.0f;
496 *pFloat++ = 0.0f;
497 *pFloat++ = 1.0f;
498 *pFloat++ = 1.0f;
499 *pFloat++ = 1.0f;
500 }
501 }
502 else
503 {
504 for (unsigned int i = 0; i < vcnt; i++)
505 {
506 *pFloat++ = 0.0f;
507 *pFloat++ = 0.0f;
508 }
509 }
510 }
511 }
512 }
513
514 const Ogre::VertexElement* hasTangent = mMesh->getSubMesh(0)->vertexData->vertexDeclaration->findElementBySemantic(Ogre::VertexElementSemantic::VES_TANGENT);
515 if (hasTangent)
516 return;
517
518 try
519 {
520 // build tangent vectors for our mesh
521 unsigned short src;
522 if (mMesh->suggestTangentVectorBuildParams(src))
523 {
524 mMesh->buildTangentVectors(src);
525 // this version cleans mirrored and rotated UVs but requires quality models
526 //mesh->buildTangentVectors(src, true, true);
527 }
528 }
529 catch (Ogre::Exception &e)
530 {
531 Ogre::LogManager::getSingletonPtr()->logMessage(e.getFullDescription(), Ogre::LML_CRITICAL, true);
532 }
533 }
534 }
535
536 void SEntity::CommonConstructorsSequence()
537 {
538 assert(O3Entity != 0);
540
541 //add missing UV
542 BuildMissingComponents();
543
544 //$BB removed, this break some mesh normals
545 /*
546 bool lastLogstate = SRoot::getSingletonPtr()->GetLogEnable();
547 SRoot::getSingletonPtr()->SetLogEnable(false);
548
549 try
550 {
551 // build tangent vectors for our mesh
552 unsigned short src, dest;
553 if (!mMesh->suggestTangentVectorBuildParams(Ogre::VES_TANGENT, src, dest))
554 {
555 mMesh->buildTangentVectors(Ogre::VES_TANGENT, src, dest);
556 // this version cleans mirrored and rotated UVs but requires quality models
557 //mesh->buildTangentVectors(VES_TANGENT, src, dest, true, true);
558 }
559 }
560 catch(Ogre::Exception &e)
561 {
562 tmpRoot->SetLogEnable(lastLogstate);
563
564 // Catching Exception::ERR_ITEM_NOT_FOUND. Forwarding other errors.
565 if(e.getNumber() != Ogre::Exception::ERR_ITEM_NOT_FOUND)
566 {
567 Ogre::LogManager::getSingletonPtr()->logMessage(e.getFullDescription(), Ogre::LML_CRITICAL, true);
568 throw e;
569 }
570 }
571
572 SRoot::getSingletonPtr()->SetLogEnable(lastLogstate);
573 */
574
575 // Build mesh edge list for stencil shadows. (take long)
576 /*if(!mMesh->isEdgeListBuilt())
577 {
578 mMesh->freeEdgeList();
579 mMesh->buildEdgeList();
580 }*/
581
582 O3SceneNode->attachObject(O3Entity);
583
584 //check if a parent is hidden
585 bool visible = GetVisible();
586 SNode* parent = GetParentSceneNode();
587 while (visible && parent != NULL)
588 {
589 visible = parent->GetVisible();
590 parent = parent->GetParentSceneNode();
591 }
592
593 if(!visible)
594 SetVisible(false, false);
595
596 // Create SO3VertexAnimation
597 if (O3Entity->hasVertexAnimation())
598 {
599 // Loading Animation
600 int numAnimations = mMesh->getNumAnimations();
601 for (int i = 0; i < numAnimations; i++)
602 {
603 Ogre::Animation* ogreAnimation = mMesh->getAnimation(i);
604
605 // Pose animation or standard vertex animation?
606 // NB that pose name is the same as animation name in case of a pose animation.
607 SAnim* animation = 0;
608 PoseHandleList::iterator iPoseAnim = poseHandleList.find(ogreAnimation->getName());
609 if (iPoseAnim != poseHandleList.end())
610 animation = new SPoseAnimation(GetParentScene(), ogreAnimation->getName(), this, animationCounter++, iPoseAnim->second);
611 else
612 animation = new SVertexAnimation(GetParentScene(), ogreAnimation->getName(), this, animationCounter++);
613
614 AddAnimation(animation);
615 }
616 }
617
618 // Bind this instance to every subentity of the entity (used in SEntitySelectorMaterialSwitcher).
619 int numSubEntities = O3Entity->getNumSubEntities();
620
621 for (int iSubEntities = 0; iSubEntities < numSubEntities; iSubEntities++)
622 {
623 Ogre::SubEntity* sEnt = O3Entity->getSubEntity(iSubEntities);
624 // If our ogre is anterior to v1.7
625#if OGRE_VERSION < ((1 << 16) | (7 << 8) | 0)
626 static_cast <Ogre::Renderable*> (sEnt)->setUserAny(Ogre::Any(this));
627#else
628 sEnt->getUserObjectBindings().setUserAny("SEntity", Ogre::Any(this));
629#endif
630 SMaterial* sMat = GetParentScene()->GetMaterial(mGroupName, sEnt->getMaterialName());
631 if (sMat == 0)
632 try
633 {
634 sMat = GetParentScene()->CreateMaterial(mGroupName, sEnt->getMaterialName());
635 sEnt->setMaterial(sMat->getOgreMaterialPointer());
636 }
637 catch (SException&)
638 {
639 MMechostr(MSKDEBUG, ">>>> Error on Material entity : %s\n", sEnt->getMaterialName().c_str());
640 }
641 }
642 }
643
645 {
646 // avoid a crash on scol close
648
649 if (mMesh)
650 mMesh->removeListener(this);
651
652 if (entitySKL)
653 {
655 //O3Entity->stopSharingSkeletonInstance();
656 entitySKL = 0;
657 }
658
659 if (O3Entity)
660 {
661 O3SceneNode->detachObject(O3Entity);
662 currentScene->GetOgreScenePointer()->destroyEntity(O3Entity);
663 }
664
665 //for unknown reason the use count = 4 just at load time
666 if (mMesh && ((mMesh.use_count() <= 4) || mReleaseResource))
667 {
668 if (mMesh->isLoaded())
669 mMesh->unload();
670
671 Ogre::MeshManager::getSingleton().remove(mMesh->getHandle());
672 mMesh.reset();
673 }
674
675 O3Entity = 0;
677 }
678
680 {
681 mReleaseResource = state;
682 }
683
685 {
686 return O3Entity;
687 }
688
690 {
691 return entitySKL;
692 }
693
695 {
696 return mGroupName;
697 }
698
699 void SEntity::SetCastShadows(const bool& castShadows)
700 {
701 if (O3Entity)
702 O3Entity->setCastShadows(castShadows);
703 }
704
706 {
707 if (O3Entity)
708 return O3Entity->getCastShadows();
709 else
710 return false;
711 }
712
713 void SEntity::SetRenderingDistance(const float& distance)
714 {
715 if (O3Entity)
716 O3Entity->setRenderingDistance(distance);
717 }
718
720 {
721 if (O3Entity)
722 return O3Entity->getRenderingDistance();
723 else
724 return 0.0f;
725 }
726
727 Ogre::Vector3 SEntity::GetBoundingBoxSize(const bool& childs)
728 {
729 if (childs)
730 return GetSonsBoundingBox();
731
732 Ogre::Vector3 scale = GetGlobalScale();
733
734 if (O3Entity)
735 return (O3Entity->getBoundingBox().getSize() * scale);
736 else
737 return Ogre::Vector3(1.0f, 1.0f, 1.0f) * scale;
738 }
739
740 Ogre::Vector3 SEntity::GetBoundingBoxCenter(const bool& childs)
741 {
742 Ogre::Vector3 scale = GetGlobalScale();
743 if (O3Entity)
744 return (O3Entity->getBoundingBox().getCenter() * scale);
745 else
746 return Ogre::Vector3(0.0f, 0.0f, 0.0f);
747 }
748
749 Ogre::Vector3 SEntity::GetWorldBoundingBoxSize(const bool& childs)
750 {
751 if (childs)
753
754 Ogre::Vector3 scale = GetGlobalScale();
755
756 if (O3Entity)
757 return O3Entity->getWorldBoundingBox(true).getSize();
758 else
759 return Ogre::Vector3(1.0f, 1.0f, 1.0f) * scale;
760 }
761
762 Ogre::Vector3 SEntity::GetWorldBoundingBoxCenter(const bool& childs)
763 {
764 if (O3Entity)
765 return O3Entity->getWorldBoundingBox(true).getCenter();
766 else
767 return Ogre::Vector3(0.0f, 0.0f, 0.0f);
768 }
769
771 {
772 unsigned int count = 0;
773 if (mMesh && mMesh->isLoaded())
774 {
775 for (unsigned short i = 0; i < mMesh->getNumSubMeshes(); ++i)
776 {
777 Ogre::SubMesh* submesh = mMesh->getSubMesh(i);
778 count += submesh->indexData->indexCount;
779 }
780 }
781
782 return count / 3;
783 }
784
786 {
787 unsigned int count = 0;
788 if (mMesh && mMesh->isLoaded())
789 {
790 for (unsigned short i = 0; i < mMesh->getNumSubMeshes(); ++i)
791 {
792 Ogre::SubMesh* submesh = mMesh->getSubMesh(i);
793 // We only need to add the shared vertices once
794 if (submesh->useSharedVertices)
795 {
796 count += mMesh->sharedVertexData->vertexCount;
797 break;
798 }
799 else
800 {
801 count += submesh->vertexData->vertexCount;
802 }
803 }
804 }
805
806 return count;
807 }
808
809 void SEntity::SetRenderQueue(const Ogre::RenderQueueGroupID& groupId)
810 {
811 if (O3Entity)
812 O3Entity->setRenderQueueGroup(groupId);
813 }
814
816 {
817 if (O3Entity)
818 return O3Entity->getNumSubEntities();
819 else
820 return 0;
821 }
822
823 void SEntity::SetVisibilityFlags(const Ogre::uint32& flags)
824 {
825 if (O3Entity)
826 O3Entity->setVisibilityFlags(flags);
827 }
828
830 {
831 if (O3Entity)
832 return O3Entity->getVisibilityFlags();
833 else
834 return 0xffffff;
835 }
836
837 void SEntity::SetVisibilityFlagIndexEnable(const Ogre::uint32& flagIndex, bool enable)
838 {
839 if (O3Entity)
840 {
841 assert((flagIndex > 0) && (flagIndex < 32));
842 Ogre::uint32 flag = 1 << flagIndex;
843 if (enable)
844 O3Entity->addVisibilityFlags(flag);
845 else
846 O3Entity->removeVisibilityFlags(flag);
847 }
848 }
849
850 bool SEntity::GetVisibilityFlagIndexEnable(const Ogre::uint32& flagIndex)
851 {
852 if (O3Entity)
853 {
854 assert((flagIndex > 0) && (flagIndex < 32));
855 // Declare a uint32 variable to be sure that the binary AND will be done on the same variable length as the var returned by getVisibilityFlags.
856 Ogre::uint32 flag = 1 << flagIndex;
857 if ((flag & O3Entity->getVisibilityFlags()) > 0)
858 return true;
859 else
860 return false;
861 }
862 else
863 return true;
864 }
865
867 {
868 entitySKL = newSkeleton;
869 }
870
871 void SEntity::GenerateLOD(int nbLevels)
872 {
873 mNumLodLevel = nbLevels;
874 if (O3Entity)
875 {
876 int curLevels = O3Entity->getMesh()->getNumLodLevels();
877 if ((curLevels == nbLevels) || (curLevels == 1 && nbLevels == 0))
878 return;
879
880 if ((nbLevels == 0) && (curLevels != nbLevels))
881 {
882 O3Entity->getMesh()->removeLodLevels();
883 return;
884 }
885
886 //reset LOD
887 O3Entity->getMesh()->removeLodLevels();
888 Ogre::LodConfig lodConfig;
889 lodConfig.levels.clear();
890 lodConfig.mesh = O3Entity->getMesh();
891 lodConfig.strategy = Ogre::ScreenRatioPixelCountLodStrategy::getSingletonPtr();
892 lodConfig.advanced.useCompression = true;
893 lodConfig.advanced.useVertexNormals = true;
894 lodConfig.advanced.useBackgroundQueue = mLoading;
895 //lodConfig.advanced.preventPunchingHoles = true;
896 //lodConfig.advanced.preventBreakingLines = true;
897
898 int nbl = nbLevels + 2;
899 Ogre::Real reduction = 0.7f / nbLevels;
900 for (int i = 2; i < nbl; i++)
901 {
902 Ogre::Real i4 = (Ogre::Real)(i * i * i * i);
903 lodConfig.createGeneratedLodLevel(2.0 / i4, reduction * i, Ogre::LodLevel::VRM_PROPORTIONAL);
904 }
905
906 Ogre::MeshLodGenerator::getSingleton().generateLodLevels(lodConfig);
907 }
908 }
909
910 //TODO apply subentities material
911 // need to reload animations / skeleton ?
913 {
914 if (O3Entity)
915 {
916 // Bind this instance to every subentity of the entity (used in SEntitySelectorMaterialSwitcher).
917 int numSubEntities = O3Entity->getNumSubEntities();
918
919 for (int iSubEntities = 0; iSubEntities < numSubEntities; iSubEntities++)
920 {
921 Ogre::SubEntity* sEnt = O3Entity->getSubEntity(iSubEntities);
922 // If our ogre is anterior to v1.7
923#if OGRE_VERSION < ((1 << 16) | (7 << 8) | 0)
924 static_cast <Ogre::Renderable*> (sEnt)->setUserAny(Ogre::Any(this));
925#else
926 sEnt->getUserObjectBindings().setUserAny("SEntity", Ogre::Any(this));
927#endif
928 SMaterial* sMat = GetParentScene()->GetMaterial(mGroupName, sEnt->getMaterialName());
929 if (sMat == 0)
930 try
931 {
932 sMat = GetParentScene()->CreateMaterial(mGroupName, sEnt->getMaterialName());
933 sEnt->setMaterial(sMat->getOgreMaterialPointer());
934 }
935 catch (SException&)
936 {
937 }
938 }
939 }
940 }
941
942 bool SEntity::SetMaterial(SMaterial* mat, int subindex)
943 {
944 if (!O3Entity)
945 return false;
946
947 try
948 {
949 if (subindex < 0)
950 {
951 O3Entity->setMaterialName(mat->GetName(), mat->GetGroupName());
952 }
953 else if (subindex < (int)O3Entity->getNumSubEntities())
954 {
955 O3Entity->getSubEntity(subindex)->setMaterialName(mat->GetName(), mat->GetGroupName());
956 }
957 else
958 return false;
959 }
960 catch (Ogre::Exception &)
961 {
962 //material not supported
963 return false;
964 }
965
966 return true;
967 }
968
969 void SEntity::SetMinPixelSize(const float &minsize)
970 {
971 if (!O3Entity)
972 return;
973
974 O3Entity->setRenderingMinPixelSize(minsize);
975 }
976
978 {
979 if (!O3Entity)
980 return 0.0f;
981
982 return O3Entity->getRenderingMinPixelSize();
983 }
984
985}
int OBJECT_LOADED_EVENT
Definition SO3SCOL.cpp:194
int OBJECT_LOADED_EVENT
Definition SO3SCOL.cpp:194
MMechostr(MSKDEBUG, " > Start loading Plugin SO3Engine dll\n")
static Ogre::MeshPtr CreateCone(const Ogre::String &strName, float radius, float height, int nVerticesInBase, Ogre::String groupName=Ogre::RGN_DEFAULT)
static Ogre::MeshPtr CreateSphere(const Ogre::String &strName, float radius, int nRings, int nSegments, bool bNormals, bool bTexCoords, Ogre::String groupName=Ogre::RGN_DEFAULT)
static Ogre::MeshPtr CreateOctahedron(const Ogre::String &strName, float baseLength, float bottomDistance, float upDistance, Ogre::String groupName=Ogre::RGN_DEFAULT)
std::string GetName() const
unsigned int GetVerticesCount()
SSkeleton * GetSkeleton()
Ogre::Entity * O3Entity
Definition SO3Entity.h:52
void _SetSkeleton(SSkeleton *newSkeleton)
unsigned int GetPolygonCount()
virtual void SetCastShadows(const bool &castShadows)
virtual void SetRenderingDistance(const float &distance)
bool SetMaterial(SMaterial *mat, int subindex)
void SetVisibilityFlags(const Ogre::uint32 &flags)
void GenerateLOD(int nbLevels)
@ SO3_PREFAB_SPHERE
Definition SO3Entity.h:49
std::string GetGroupName()
virtual Ogre::Vector3 GetWorldBoundingBoxCenter(const bool &childs=false)
void SetFreeResource(bool state)
void SetRenderQueue(const Ogre::RenderQueueGroupID &groupId)
virtual Ogre::Vector3 GetBoundingBoxCenter(const bool &childs=false)
void SetMinPixelSize(const float &minsize)
virtual Ogre::Vector3 GetBoundingBoxSize(const bool &childs=false)
virtual bool GetCastShadows()
SSkeleton * entitySKL
Definition SO3Entity.h:53
float GetMinPixelSize()
virtual Ogre::Vector3 GetWorldBoundingBoxSize(const bool &childs=false)
Ogre::uint32 GetVisibilityFlags()
Ogre::Entity * getOgreEntityPointer()
void LoadAsync()
void FinishAsync()
virtual float GetRenderingDistance()
void SetVisibilityFlagIndexEnable(const Ogre::uint32 &flagIndex, bool enable)
bool GetVisibilityFlagIndexEnable(const Ogre::uint32 &flagIndex)
virtual void loadingComplete(Ogre::Resource *res)
unsigned int GetNumSubEntities()
Base class for SO3 custom exception.
Ogre::MaterialPtr getOgreMaterialPointer()
std::string GetGroupName()
void AddAnimation(SAnim *existingAnimation)
Ogre::Vector3 GetSonsWorldBoundingBox()
SScene * currentScene
Definition SO3NodeScol.h:68
Ogre::SceneNode * O3SceneNode
Definition SO3NodeScol.h:69
bool GetVisible()
SScene * GetParentScene()
void DetachFromParent()
unsigned short animationCounter
Definition SO3NodeScol.h:72
virtual Ogre::Vector3 GetGlobalScale()
Ogre::MovableObject * ogreMovableObject
Definition SO3NodeScol.h:70
void SetVisible(const bool &visible, const bool &cascade=true)
SNode * GetParentSceneNode()
SNode(SScene *parent, const std::string &nodeName, const bool &isRootNode=false)
Ogre::Vector3 GetSonsBoundingBox()
NUMERIC_TYPE y
Definition SO3Point.h:40
NUMERIC_TYPE x
Definition SO3Point.h:39
void SetLogEnable(const bool &state)
Definition SO3Root.cpp:374
@ SO3_DIRECTX11_RENDERER
Definition SO3Root.h:79
bool GetLogEnable()
Definition SO3Root.cpp:379
static SRoot & getSingleton()
Definition SO3Root.cpp:116
static SRoot * getSingletonPtr()
Definition SO3Root.cpp:111
Ogre::SkeletonManager * O3SkeletonManager
Definition SO3Scene.h:130
SMaterial * GetMaterial(const std::string &groupName, const std::string &materialName, bool searchOtherGroups=true)
SMaterial * CreateMaterial(const std::string &groupname, const std::string &matname, const bool &loadedFromScript=false)
Ogre::SceneManager * GetOgreScenePointer()
Definition SO3Scene.cpp:449
void DeleteSkeleton(SSkeleton *existingSkeleton)
Definition SO3Scene.cpp:941
STBI_EXTERN unsigned long flags
Definition stb_image.h:1182