2023-06-20 04:33:09 +00:00
|
|
|
#include "StarNameplatePainter.hpp"
|
|
|
|
#include "StarJsonExtra.hpp"
|
|
|
|
#include "StarAssets.hpp"
|
|
|
|
#include "StarNametagEntity.hpp"
|
|
|
|
#include "StarPlayer.hpp"
|
|
|
|
#include "StarGuiContext.hpp"
|
|
|
|
|
|
|
|
namespace Star {
|
|
|
|
|
|
|
|
NameplatePainter::NameplatePainter() {
|
|
|
|
auto assets = Root::singleton().assets();
|
|
|
|
|
|
|
|
Json nametagConfig = assets->json("/interface.config:nametag");
|
2023-06-23 10:24:40 +00:00
|
|
|
m_showMasterNames = nametagConfig.getBool("showMasterNames");
|
2023-06-20 04:33:09 +00:00
|
|
|
m_opacityRate = nametagConfig.getFloat("opacityRate");
|
2023-06-23 10:24:40 +00:00
|
|
|
m_inspectOpacityRate = nametagConfig.queryFloat("inspectOpacityRate", m_opacityRate);
|
2023-06-20 04:33:09 +00:00
|
|
|
m_offset = jsonToVec2F(nametagConfig.get("offset"));
|
2024-04-21 20:07:59 +00:00
|
|
|
Json textStyle = nametagConfig.get("textStyle");
|
|
|
|
m_textStyle = textStyle;
|
|
|
|
m_statusTextStyle = nametagConfig.get("statusTextStyle", textStyle);
|
2023-06-20 04:33:09 +00:00
|
|
|
m_statusOffset = jsonToVec2F(nametagConfig.get("statusOffset"));
|
2024-04-21 20:07:59 +00:00
|
|
|
m_statusTextStyle.color = jsonToColor(nametagConfig.get("statusColor")).toRgba();
|
2023-06-20 04:33:09 +00:00
|
|
|
m_opacityBoost = nametagConfig.getFloat("opacityBoost");
|
|
|
|
m_nametags.setTweenFactor(nametagConfig.getFloat("tweenFactor"));
|
|
|
|
m_nametags.setMovementThreshold(nametagConfig.getFloat("movementThreshold"));
|
|
|
|
}
|
|
|
|
|
2023-07-20 14:58:49 +00:00
|
|
|
void NameplatePainter::update(float dt, WorldClientPtr const& world, WorldCamera const& camera, bool inspectionMode) {
|
2023-06-20 04:33:09 +00:00
|
|
|
m_camera = camera;
|
|
|
|
|
|
|
|
Set<EntityId> foundEntities;
|
|
|
|
for (auto const& entity : world->query<NametagEntity>(camera.worldScreenRect())) {
|
2023-06-23 10:24:40 +00:00
|
|
|
if ((entity->isMaster() && !m_showMasterNames) || !entity->displayNametag())
|
2023-06-20 04:33:09 +00:00
|
|
|
continue;
|
|
|
|
if (auto player = as<Player>(entity)) {
|
|
|
|
if (player->isTeleporting())
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
foundEntities.insert(entity->entityId());
|
|
|
|
|
|
|
|
if (!m_entitiesWithNametags.contains(entity->entityId())) {
|
|
|
|
Nametag nametag = {entity->name(), entity->statusText(), entity->nametagColor(), 1.0f, entity->entityId()};
|
|
|
|
RectF boundBox = determineBoundBox(Vec2F(), nametag);
|
2024-02-19 15:55:19 +00:00
|
|
|
m_nametags.addBubble(Vec2F(), boundBox, std::move(nametag));
|
2023-06-20 04:33:09 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
m_nametags.filter([&foundEntities](
|
|
|
|
BubbleState<Nametag> const&, Nametag const& nametag) { return foundEntities.contains(nametag.entityId); });
|
|
|
|
|
|
|
|
m_nametags.forEach([&world, &camera, this, inspectionMode](BubbleState<Nametag>& bubbleState, Nametag& nametag) {
|
|
|
|
if (auto entity = as<NametagEntity>(world->entity(nametag.entityId))) {
|
2023-06-26 14:42:07 +00:00
|
|
|
bubbleState.idealDestination = camera.worldToScreen(entity->nametagOrigin()) + m_offset * camera.pixelRatio();
|
2023-06-20 04:33:09 +00:00
|
|
|
bubbleState.boundBox = determineBoundBox(bubbleState.idealDestination, nametag);
|
|
|
|
|
|
|
|
nametag.statusText = entity->statusText();
|
|
|
|
nametag.name = entity->name();
|
|
|
|
nametag.color = entity->nametagColor();
|
|
|
|
bool fullyOnScreen = world->geometry().rectContains(camera.worldScreenRect(), entity->position());
|
|
|
|
if (inspectionMode)
|
2023-06-23 10:24:40 +00:00
|
|
|
nametag.opacity = approach(1.0f, nametag.opacity, m_inspectOpacityRate);
|
2023-06-20 04:33:09 +00:00
|
|
|
else if (fullyOnScreen)
|
|
|
|
nametag.opacity = approach(0.0f, nametag.opacity, m_opacityRate);
|
|
|
|
else
|
|
|
|
nametag.opacity = approach(m_opacityBoost, nametag.opacity, m_opacityRate);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-02-19 15:55:19 +00:00
|
|
|
m_entitiesWithNametags = std::move(foundEntities);
|
2023-07-20 14:58:49 +00:00
|
|
|
m_nametags.update(dt);
|
2023-06-20 04:33:09 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void NameplatePainter::render() {
|
|
|
|
auto& context = GuiContext::singleton();
|
|
|
|
|
|
|
|
m_nametags.forEach([&context, this](BubbleState<Nametag> const& bubble, Nametag const& nametag) {
|
|
|
|
if (nametag.opacity == 0.0f)
|
|
|
|
return;
|
|
|
|
|
2024-04-21 20:07:59 +00:00
|
|
|
auto& setStyle = context.setTextStyle(m_textStyle);
|
2023-06-20 04:33:09 +00:00
|
|
|
auto color = Color::rgb(nametag.color);
|
|
|
|
color.setAlphaF(nametag.opacity);
|
2024-04-21 20:07:59 +00:00
|
|
|
setStyle.color = color.toRgba();
|
2023-06-20 04:33:09 +00:00
|
|
|
|
|
|
|
context.renderText(nametag.name, namePosition(bubble.currentPosition));
|
|
|
|
|
|
|
|
if (nametag.statusText) {
|
2024-04-21 20:07:59 +00:00
|
|
|
context.setTextStyle(m_statusTextStyle).color[3] *= nametag.opacity;
|
2023-06-20 04:33:09 +00:00
|
|
|
context.renderText(*nametag.statusText, statusPosition(bubble.currentPosition));
|
|
|
|
}
|
2024-04-21 20:07:59 +00:00
|
|
|
context.clearTextStyle();
|
2023-06-20 04:33:09 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
TextPositioning NameplatePainter::namePosition(Vec2F bubblePosition) const {
|
|
|
|
return TextPositioning(bubblePosition, HorizontalAnchor::HMidAnchor, VerticalAnchor::BottomAnchor);
|
|
|
|
}
|
|
|
|
|
|
|
|
TextPositioning NameplatePainter::statusPosition(Vec2F bubblePosition) const {
|
|
|
|
auto& context = GuiContext::singleton();
|
|
|
|
return TextPositioning(
|
|
|
|
bubblePosition + m_statusOffset * context.interfaceScale(),
|
|
|
|
HorizontalAnchor::HMidAnchor, VerticalAnchor::BottomAnchor);
|
|
|
|
}
|
|
|
|
|
|
|
|
RectF NameplatePainter::determineBoundBox(Vec2F bubblePosition, Nametag const& nametag) const {
|
|
|
|
auto& context = GuiContext::singleton();
|
2024-04-21 20:07:59 +00:00
|
|
|
context.setTextStyle(m_textStyle);
|
2023-06-20 04:33:09 +00:00
|
|
|
RectF nametagBox = context.determineTextSize(nametag.name, namePosition(bubblePosition));
|
|
|
|
if (nametag.statusText) {
|
2024-04-21 20:07:59 +00:00
|
|
|
context.setTextStyle(m_statusTextStyle);
|
2023-06-20 04:33:09 +00:00
|
|
|
nametagBox.combine(context.determineTextSize(*nametag.statusText, statusPosition(bubblePosition)));
|
|
|
|
}
|
2024-04-21 20:07:59 +00:00
|
|
|
context.clearTextStyle();
|
2023-06-20 04:33:09 +00:00
|
|
|
return nametagBox;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|