317 lines
7.3 KiB
C++
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_;
|
|
}
|