DYTSrouce/src/entities/SceneComponent.cpp
2025-11-13 22:13:40 +08:00

317 lines
7.3 KiB
C++

#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<class SceneComponent*> 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<SceneComponent*>(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<SceneComponent*>& 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_;
}