DYTSrouce/src/entities/LabelComponent.cpp

199 lines
5.5 KiB
C++

#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"
#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<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() 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<osg::MatrixTransform> 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;
}