#include "entities/SceneComponent.h" #include "common/SpdLogger.h" #include "utils/StringUtils.h" #include "workspace/WorkSpace.h" #include "entities/Entity.h" #include "utils/OsgUtils.h" #include "scene/SceneContent.h" SceneComponent::SceneComponent(SceneComponent* parent) : Component(parent) { //AttachTo(parent); transform_.SetChangeCallback([this](Transform* transform) { UpdateLocationAndRotation(); } ); } SceneComponent::~SceneComponent() { } std::vector SceneComponent::GetChildren() const { return children_; } void SceneComponent::AttachEntity(Entity* owner) { if (nullptr == owner && owner_ != owner) { return; } Component::AttachEntity(owner); SceneComponent* root = owner_->GetRootComponent(); if (nullptr == root) { owner_->SetRootComponent(this); } } bool SceneComponent::SetAttribute(const char* name, const char* value) { if (0 == strcmp(name, "location")) { transform_.SetLocation(StringUtils::StringToVec3(value)); return true; } else if (0 == strcmp(name, "rotation")) { transform_.SetRotation(StringUtils::StringToVec3(value)); return true; } else if (0 == strcmp(name, "scale")) { transform_.SetScale(StringUtils::StringToVec3(value)); return true; } return Component::SetAttribute(name, value); } bool SceneComponent::SaveAttribute(tinyxml2::XMLElement* element) { element->SetAttribute("location", StringUtils::Vec3ToString(transform_.GetLocation()).c_str()); element->SetAttribute("rotation", StringUtils::Vec3ToString(transform_.GetRotation()).c_str()); element->SetAttribute("scale", StringUtils::Vec3ToString(transform_.GetScale()).c_str()); return Component::SaveAttribute(element); } void SceneComponent::Begin() { for (auto& item : children_) { item->Begin(); } } void SceneComponent::Update(double dt) { for (auto& item : children_) { item->Update(dt); } } void SceneComponent::End() { for (auto& item : children_) { item->End(); } } bool SceneComponent::OnDestroy() { RemoveRender(); for (auto& item : children_) { item->OnDestroy(); } RemoveParent(); return Component::OnDestroy(); } SceneComponent* SceneComponent::GetRootComponent() const { if (nullptr != parent_) { return parent_->GetRootComponent(); } if (nullptr != GetEntity()) { return const_cast(this); } return nullptr; } bool SceneComponent::AttachTo(SceneComponent* parent) { if (nullptr == parent) { return false; } parent_ = parent; parent->children_.push_back(this); AttachEntity(parent->GetEntity()); AddToRender(); return true; } void SceneComponent::SetLocation(const osg::Vec3& location) { transform_.SetLocation(location); } const osg::Vec3& SceneComponent::GetLocation() const { return transform_.GetLocation(); } void SceneComponent::AttachScene(Entity* entity) { WorkSpace* workspace = entity->GetWorkspace(); if (nullptr == workspace) { LOG_WARN("workspace is nullptr"); return; } #if USE_OCEAN OsgScene* scene = workspace->GetActiveScene(); #else OEScene* scene = workspace->GetActiveScene(); #endif if (nullptr == scene) { LOG_WARN("scene is nullptr"); return; } #if USE_OCEAN scene->AddToScene(mt_); #else if (!geo_) { geo_ = new osgEarth::GeoTransform; geo_->addChild(mt_); } scene->AddToScene(geo_); #endif UpdateLocationAndRotation(); } void SceneComponent::AttachParent(Entity* entity) { SceneComponent* rootCompont = entity->GetRootComponent(); if (nullptr == rootCompont) { LOG_INFO("rootCompont is nullptr"); return; } UpdateLocationAndRotation(); rootCompont->mt_->addChild(mt_); } void SceneComponent::AttachParent(SceneComponent* parent) { if (nullptr == parent) { LOG_INFO("parent is nullptr"); return; } if (parent_ != parent) { parent_ = parent; parent->children_.push_back(this); } AttachEntity(parent->GetEntity()); if (nullptr != mt_ && nullptr != parent->mt_) { parent->mt_->addChild(mt_); } } void SceneComponent::UpdateLocationAndRotation() { if (nullptr == mt_) { return; } const osg::Vec3& r = transform_.GetRotation(); const osg::Vec3& s = transform_.GetScale(); const osg::Vec3& t = transform_.GetLocation(); osg::Quat quat = OsgUtils::HPRToQuat(r); osg::Matrix matrix = osg::Matrix::scale(s) * osg::Matrix::rotate(quat); if (!geo_.valid()) { matrix *= osg::Matrix::translate(t); mt_->setMatrix(matrix); } else { mt_->setMatrix(matrix); osgEarth::GeoPoint pos(g_srs_, t); geo_->setPosition(pos); } } void SceneComponent::RemoveRender() { if (nullptr == mt_) { return; } for (auto child : children_) { child->RemoveRender(); } // If attached via GeoTransform (osgEarth), remove the GeoTransform from the scene #ifndef USE_OCEAN if (geo_.valid()) { for (int i = geo_->getNumParents() - 1; i >= 0; --i) { osg::Group* parent = geo_->getParent(i)->asGroup(); if (nullptr != parent) { parent->removeChild(geo_.get()); } } // Break the child link to mt_ to avoid lingering references geo_->removeChild(mt_.get()); } #endif for (int i = mt_->getNumParents() - 1; i >= 0; --i) { osg::Group* parent = mt_->getParent(i)->asGroup(); if (nullptr != parent) { parent->removeChild(mt_); } } // Release local references proactively #ifndef USE_OCEAN geo_ = nullptr; #endif mt_ = nullptr; } void SceneComponent::RemoveParent() { if (nullptr == parent_) { return; } SceneComponent* self = this; std::vector& children = children_; auto itor = std::find_if(children.begin(), children.end(), [self](auto* item) { return item == self; } ); if (children.end() != itor) { children.erase(itor); } } void SceneComponent::AddToRender() { if (nullptr == mt_) { LOG_WARN("mt is nullptr"); return; } for (auto child : children_) { child->AddToRender(); } if (nullptr != parent_) { AttachParent(parent_); return; } Entity* entity = GetEntity(); if (nullptr == entity) { LOG_WARN("entity is nullptr"); return; } Entity* parent = entity->GetParent(); if (nullptr == parent) { LOG_INFO("parent is nullptr"); AttachScene(entity); return; } else { AttachParent(parent); } } bool SceneComponent::HasComponent(const std::string& name) const { if (GetSelfTypeName() == name) { return true; } for (auto& componet : children_) { if (componet->GetSelfTypeName() == name) { return true; } } return false; } void SceneComponent::SetVisible(bool v) { visible_ = v; if (nullptr == mt_) { return; } mt_->setNodeMask(v ? ~0 : 0); // for (auto child : children_) { // child->SetVisible(v); // } } bool SceneComponent::IsVisible() const { return visible_; }