2025-06-19 23:57:30 +00:00
|
|
|
#include "entities/LabelComponent.h"
|
|
|
|
|
|
|
|
#include <osg/Billboard>
|
|
|
|
#include <osg/StateSet>
|
|
|
|
#include <osg/BlendFunc>
|
|
|
|
#include <osg/Depth>
|
|
|
|
#include <osgText/Font>
|
|
|
|
|
|
|
|
#include "entities/Entity.h"
|
|
|
|
#include "common/SpdLogger.h"
|
|
|
|
|
|
|
|
LabelComponent::LabelComponent(SceneComponent* parent)
|
|
|
|
: SceneComponent(parent)
|
|
|
|
, text_("Label")
|
2025-06-22 08:27:44 +00:00
|
|
|
, fontSize_(26.0f)
|
|
|
|
, color_(1.0f, 0.0f, 0.0f, 1.0f)
|
2025-06-19 23:57:30 +00:00
|
|
|
, visible_(true)
|
|
|
|
, needUpdate_(true) {
|
|
|
|
}
|
|
|
|
|
|
|
|
LabelComponent::~LabelComponent() {
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string LabelComponent::GetTypeName() {
|
|
|
|
return "LabelComponent";
|
|
|
|
}
|
|
|
|
|
|
|
|
void LabelComponent::AttachEntity(Entity* entity) {
|
|
|
|
SceneComponent::AttachEntity(entity);
|
|
|
|
|
|
|
|
if (entity && !entity->GetName().isEmpty()) {
|
|
|
|
LOG_INFO("LabelComponent: Attaching to entity '{}'", entity->GetName().toUtf8().data());
|
|
|
|
SetText(entity->GetName().toLocal8Bit().data());
|
|
|
|
|
|
|
|
Entity* entity = GetEntity();
|
|
|
|
if (nullptr != entity) {
|
|
|
|
connect(entity, &Entity::NameChanged, this, &LabelComponent::UpdateText);
|
|
|
|
}
|
|
|
|
|
|
|
|
CreateTextNode();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool LabelComponent::SetAttribute(const char* name, const char* value) {
|
|
|
|
if (0 == strcmp(name, "text")) {
|
|
|
|
SetText(value);
|
|
|
|
return true;
|
|
|
|
} else if (0 == strcmp(name, "fontSize")) {
|
|
|
|
SetFontSize(static_cast<float>(atof(value)));
|
|
|
|
return true;
|
|
|
|
} else if (0 == strcmp(name, "visible")) {
|
|
|
|
SetVisible(0 == strcmp(value, "true"));
|
|
|
|
return true;
|
|
|
|
} else if (0 == strcmp(name, "color")) {
|
|
|
|
float r, g, b, a = 1.0f;
|
|
|
|
int parsed = sscanf(value, "%f,%f,%f,%f", &r, &g, &b, &a);
|
|
|
|
if (parsed >= 3) {
|
|
|
|
SetColor(osg::Vec4(r, g, b, a));
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return SceneComponent::SetAttribute(name, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool LabelComponent::SaveAttribute(tinyxml2::XMLElement* element) {
|
|
|
|
element->SetAttribute("text", text_.c_str());
|
|
|
|
element->SetAttribute("fontSize", fontSize_);
|
|
|
|
element->SetAttribute("visible", visible_ ? "true" : "false");
|
|
|
|
|
|
|
|
// 保存颜色
|
|
|
|
char colorStr[64];
|
|
|
|
sprintf(colorStr, "%.2f,%.2f,%.2f,%.2f", color_.r(), color_.g(), color_.b(), color_.a());
|
|
|
|
element->SetAttribute("color", colorStr);
|
|
|
|
|
|
|
|
return SceneComponent::SaveAttribute(element);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string LabelComponent::GetSelfTypeName() {
|
|
|
|
return LabelComponent::GetTypeName();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LabelComponent::Begin() {
|
|
|
|
SceneComponent::Begin();
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
void LabelComponent::Update(double dt) {
|
|
|
|
SceneComponent::Update(dt);
|
|
|
|
|
|
|
|
if (needUpdate_) {
|
|
|
|
UpdateTextNode();
|
|
|
|
needUpdate_ = false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LabelComponent::End() {
|
|
|
|
SceneComponent::End();
|
|
|
|
|
|
|
|
Entity* entity = GetEntity();
|
|
|
|
if (nullptr != entity) {
|
|
|
|
disconnect(entity, &Entity::NameChanged, this, &LabelComponent::UpdateText);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LabelComponent::AddToRender() {
|
|
|
|
SceneComponent::AddToRender();
|
|
|
|
}
|
|
|
|
|
|
|
|
void LabelComponent::SetText(const std::string& text) {
|
|
|
|
if (text_ != text) {
|
|
|
|
text_ = text;
|
|
|
|
needUpdate_ = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LabelComponent::SetFontSize(float size) {
|
|
|
|
if (fontSize_ != size) {
|
|
|
|
fontSize_ = size;
|
|
|
|
needUpdate_ = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LabelComponent::SetColor(const osg::Vec4& color) {
|
|
|
|
if (color_ != color) {
|
|
|
|
color_ = color;
|
|
|
|
needUpdate_ = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LabelComponent::SetVisible(bool visible) {
|
|
|
|
if (visible_ != visible) {
|
|
|
|
visible_ = visible;
|
|
|
|
if (textGeode_.valid()) {
|
|
|
|
textGeode_->setNodeMask(visible_ ? 0xffffffff : 0x0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LabelComponent::CreateTextNode() {
|
|
|
|
if (!textGeode_.valid()) {
|
|
|
|
textGeode_ = new osg::Geode();
|
|
|
|
textNode_ = new osgText::Text();
|
|
|
|
|
2025-06-22 08:27:44 +00:00
|
|
|
// 设置文本对齐方式为底部居中,这样文本会显示在指定位置的上方
|
|
|
|
textNode_->setAlignment(osgText::Text::CENTER_BOTTOM);
|
2025-06-19 23:57:30 +00:00
|
|
|
textNode_->setAxisAlignment(osgText::Text::SCREEN);
|
2025-06-22 08:27:44 +00:00
|
|
|
textNode_->setCharacterSizeMode(osgText::Text::OBJECT_COORDS);
|
2025-06-19 23:57:30 +00:00
|
|
|
textNode_->setText(text_);
|
2025-06-22 08:27:44 +00:00
|
|
|
textNode_->setPosition(osg::Vec3(0.0f, 0.0f, 500.0f)); // 设置初始位置在模型上方
|
2025-06-19 23:57:30 +00:00
|
|
|
|
|
|
|
textGeode_->addDrawable(textNode_.get());
|
|
|
|
|
|
|
|
osg::StateSet* stateSet = textGeode_->getOrCreateStateSet();
|
|
|
|
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
|
|
|
|
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::OFF);
|
|
|
|
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
|
|
|
stateSet->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
|
|
|
|
|
|
|
osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform();
|
|
|
|
mt->addChild(textGeode_);
|
|
|
|
if (!mt_.valid()) {
|
|
|
|
mt_ = mt;
|
|
|
|
}
|
|
|
|
|
|
|
|
needUpdate_ = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LabelComponent::UpdateTextNode() {
|
|
|
|
if (textNode_.valid()) {
|
|
|
|
textNode_->setText(text_);
|
|
|
|
textNode_->setCharacterSize(fontSize_);
|
|
|
|
textNode_->setColor(color_);
|
|
|
|
|
2025-06-22 08:27:44 +00:00
|
|
|
// 设置标签位置在模型上方,增加偏移量使其更明显
|
|
|
|
textNode_->setPosition(osg::Vec3(0.0f, 0.0f, 500.0f));
|
2025-06-19 23:57:30 +00:00
|
|
|
|
|
|
|
SPDLOG_INFO("LabelComponent: Updated text '{}' with size {}", text_, fontSize_);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LabelComponent::UpdateText(const QString& text) {
|
|
|
|
SetText(text.toLocal8Bit().data());
|
|
|
|
needUpdate_ = true;
|
|
|
|
}
|