#include "entities/LabelComponent.h" #include #include #include #include #include #include "entities/Entity.h" #include "common/SpdLogger.h" #include "scutcheon/osgScutcheon.h" LabelComponent::LabelComponent(SceneComponent* parent) : SceneComponent(parent) , text_("Label") , fontSize_(26.0f) , color_(1.0f, 0.0f, 0.0f, 1.0f) , 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(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() const { 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; if (textNode_.valid()) { textNode_->setText(text_); } } } 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 (billboard_.valid()) { billboard_->setNodeMask(visible_ ? 0xffffffff : 0x0); } } } void LabelComponent::CreateTextNode() { if (mt_.valid()) { return; } // 使用布告板来显示文本,确保文本始终面向相机 if (!billboard_.valid()) { billboard_ = new osg::Billboard(); billboard_->setMode(osg::Billboard::POINT_ROT_EYE); textNode_ = new osgText::Text(); // 设置文本对齐方式为底部居中,这样文本会显示在指定位置的上方 textNode_->setAlignment(osgText::Text::CENTER_BOTTOM); textNode_->setAxisAlignment(osgText::Text::SCREEN); textNode_->setCharacterSizeMode(osgText::Text::SCREEN_COORDS); textNode_->setText(text_); textNode_->setPosition(osg::Vec3(0.0f, 0.0f, 0.0f)); // 文本相对于布告板的位置 // 直接将文本对象添加到布告板,并设置位置偏移 billboard_->addDrawable(textNode_.get(), osg::Vec3(0.0f, 0.0f, 5.0f)); // 设置渲染状态 osg::StateSet* stateSet = billboard_->getOrCreateStateSet(); stateSet->setMode(GL_BLEND, osg::StateAttribute::ON); stateSet->setMode(GL_DEPTH_TEST, osg::StateAttribute::ON); stateSet->setRenderingHint(osg::StateSet::TRANSPARENT_BIN); stateSet->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA)); osg::ref_ptr mt = new osg::MatrixTransform(); mt->addChild(billboard_); if (!mt_.valid()) { mt_ = mt; } needUpdate_ = true; } } void LabelComponent::UpdateTextNode() { if (textNode_.valid()) { textNode_->setText(text_); textNode_->setCharacterSize(fontSize_); textNode_->setColor(color_); SPDLOG_INFO("LabelComponent: Updated billboard text '{}' with size {}", text_, fontSize_); } } void LabelComponent::UpdateText(const QString& text) { SetText(text.toLocal8Bit().data()); needUpdate_ = true; }