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"
|
|
|
|
|
2025-06-22 10:18:46 +00:00
|
|
|
#include "scutcheon/osgScutcheon.h"
|
|
|
|
|
2025-06-19 23:57:30 +00:00
|
|
|
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;
|
2025-06-22 10:18:46 +00:00
|
|
|
if (textNode_.valid()) {
|
|
|
|
textNode_->setText(text_);
|
|
|
|
}
|
2025-06-19 23:57:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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;
|
2025-06-22 10:18:46 +00:00
|
|
|
if (billboard_.valid()) {
|
|
|
|
billboard_->setNodeMask(visible_ ? 0xffffffff : 0x0);
|
2025-06-19 23:57:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LabelComponent::CreateTextNode() {
|
2025-06-22 10:18:46 +00:00
|
|
|
if (mt_.valid()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// 使用布告板来显示文本,确保文本始终面向相机
|
|
|
|
if (!billboard_.valid()) {
|
|
|
|
billboard_ = new osg::Billboard();
|
|
|
|
billboard_->setMode(osg::Billboard::POINT_ROT_EYE);
|
|
|
|
|
2025-06-19 23:57:30 +00:00
|
|
|
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 10:18:46 +00:00
|
|
|
textNode_->setCharacterSizeMode(osgText::Text::SCREEN_COORDS);
|
|
|
|
textNode_->setText(text_);
|
|
|
|
textNode_->setPosition(osg::Vec3(0.0f, 0.0f, 0.0f)); // 文本相对于布告板的位置
|
2025-06-19 23:57:30 +00:00
|
|
|
|
2025-06-22 10:18:46 +00:00
|
|
|
// 直接将文本对象添加到布告板,并设置位置偏移
|
|
|
|
billboard_->addDrawable(textNode_.get(), osg::Vec3(0.0f, 0.0f, 5.0f));
|
2025-06-19 23:57:30 +00:00
|
|
|
|
2025-06-22 10:18:46 +00:00
|
|
|
// 设置渲染状态
|
|
|
|
osg::StateSet* stateSet = billboard_->getOrCreateStateSet();
|
2025-06-19 23:57:30 +00:00
|
|
|
stateSet->setMode(GL_BLEND, osg::StateAttribute::ON);
|
2025-06-22 10:18:46 +00:00
|
|
|
stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON);
|
2025-06-19 23:57:30 +00:00
|
|
|
stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
|
|
|
|
stateSet->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
|
|
|
|
|
2025-06-22 10:18:46 +00:00
|
|
|
osg::ref_ptr<osg::MatrixTransform> mt = new osg::MatrixTransform();
|
|
|
|
mt->addChild(billboard_);
|
2025-06-19 23:57:30 +00:00
|
|
|
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 10:18:46 +00:00
|
|
|
SPDLOG_INFO("LabelComponent: Updated billboard text '{}' with size {}", text_, fontSize_);
|
2025-06-19 23:57:30 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void LabelComponent::UpdateText(const QString& text) {
|
|
|
|
SetText(text.toLocal8Bit().data());
|
|
|
|
needUpdate_ = true;
|
|
|
|
}
|