#include "StatBar.h" #include #include #include "Gui.h" static constexpr float BAR_BORDER = 3.0f; static constexpr float LABEL_HEIGHT = 26.0f; static constexpr float LABEL_GAP = 2.0f; static constexpr float TRAIL_DELAY = 0.45f; // seconds the lost amount lingers before draining static constexpr float TRAIL_DRAIN_SPEED = 0.6f; // of the whole bar a second static constexpr float FLASH_TIME = 0.35f; static const glm::vec3 BACKGROUND_COLOR(0.03f, 0.04f, 0.06f); static const glm::vec3 HURT_BACKGROUND_COLOR(0.45f, 0.06f, 0.05f); static const glm::vec3 TRAIL_COLOR(0.98f, 0.92f, 0.80f); static const glm::vec3 DIMMED_COLOR(0.38f, 0.40f, 0.44f); static const glm::vec3 TEXT_COLOR(0.95f, 0.97f, 1.0f); // Drawn from images: the empty part is the fill image darkened, the lost part the fill image brightened static const glm::vec3 IMAGE_EMPTY_TINT(0.16f, 0.13f, 0.13f); static const glm::vec3 IMAGE_HURT_TINT(0.55f, 0.18f, 0.16f); static const glm::vec3 IMAGE_TRAIL_TINT(2.2f, 1.9f, 1.7f); static ImageBox* MakeImage(Texture* texture) { ImageBox* image = new ImageBox(); image->surface = SurfaceTexture::Stretched(texture); image->Opacity = 0.0f; image->BindToRenderSystem(); return image; } static Box* MakeBox(const glm::vec3& color) { Box* box = new Box(); box->Color = color; box->Opacity = 0.0f; box->BindToRenderSystem(); return box; } StatBar::StatBar(Font* font, const Style& newStyle) : style(newStyle) { if (Images()) { background = MakeImage(style.fillImage); trail = MakeImage(style.fillImage); fill = MakeImage(style.fillImage); if (style.frameImage) frame = MakeImage(style.frameImage); } else { background = MakeBox(BACKGROUND_COLOR); background->rounding = 0.5f; trail = MakeBox(TRAIL_COLOR); fill = MakeBox(style.fillColor); } label = new TextBox(); label->font = font; label->fontsize = style.labelSize; label->Color = TEXT_COLOR; label->Opacity = 0.0f; label->textCenter = { 0.0f, 1.0f }; label->BindToRenderSystem(); } float StatBar::GetHeight() const { return LABEL_HEIGHT + LABEL_GAP + style.height; } void StatBar::Update(float dt, float opacity, float target, const std::string& text, const glm::vec2& position, bool reset, bool dimmed) { target = glm::clamp(target, 0.0f, 1.0f); if (reset) { fraction = trailFraction = target; flash = 0.0f; trailWait = 0.0f; } if (style.showLoss && target < fraction - 0.0001f) { flash = 1.0f; trailWait = TRAIL_DELAY; } fraction = target; if (style.showLoss) { trailWait -= dt; if (trailWait <= 0.0f) trailFraction = std::max(trailFraction - TRAIL_DRAIN_SPEED * dt, fraction); trailFraction = std::max(trailFraction, fraction); // filling back up doesn't leave a trail } else { trailFraction = fraction; } flash = std::max(flash - dt / FLASH_TIME, 0.0f); dim += ((dimmed ? 1.0f : 0.0f) - dim) * (1.0f - std::exp(-10.0f * dt)); const glm::vec2 barTopLeft = glm::round(position + glm::vec2(0.0f, LABEL_HEIGHT + LABEL_GAP)); label->text = text; label->t2d.position = { 0.0f, 0.0f, std::round(position.x + 2.0f), std::round(position.y) }; label->t2d.size = { 0.0f, 0.0f, style.width, LABEL_HEIGHT }; label->Opacity = text.empty() ? 0.0f : opacity; // The fill color all the way down to lowFraction, then turning to lowColor const float low = 1.0f - glm::clamp(fraction / std::max(style.lowFraction, 0.0001f), 0.0f, 1.0f); glm::vec3 color = glm::mix(style.fillColor, style.lowColor, low); color = glm::mix(color, DIMMED_COLOR, dim); color = glm::mix(color, glm::vec3(1.0f), flash * 0.5f); if (Images()) { // Every layer covers the whole bar, the trail and fill cropped from the left to how much they show auto Place = [&](Box* box, float shown) { box->t2d.position = { 0.0f, 0.0f, barTopLeft.x, barTopLeft.y }; box->t2d.size = { 0.0f, 0.0f, std::round(style.width * shown), style.height }; static_cast(box)->crop = glm::vec2(shown, 1.0f); }; Place(background, 1.0f); background->Color = glm::mix(IMAGE_EMPTY_TINT, IMAGE_HURT_TINT, flash); background->Opacity = opacity * 0.9f; Place(trail, trailFraction); trail->Color = IMAGE_TRAIL_TINT; trail->Opacity = trailFraction > fraction ? opacity : 0.0f; Place(fill, fraction); fill->Color = color; fill->Opacity = fraction > 0.0f ? opacity : 0.0f; if (frame) { Place(frame, 1.0f); frame->Opacity = opacity; } return; } const float inner = style.width - BAR_BORDER * 2.0f; const float innerHeight = style.height - BAR_BORDER * 2.0f; background->t2d.position = { 0.0f, 0.0f, barTopLeft.x, barTopLeft.y }; background->t2d.size = { 0.0f, 0.0f, style.width, style.height }; background->Color = glm::mix(BACKGROUND_COLOR, HURT_BACKGROUND_COLOR, flash); background->Opacity = opacity * 0.8f; trail->t2d.position = { 0.0f, 0.0f, barTopLeft.x + BAR_BORDER, barTopLeft.y + BAR_BORDER }; trail->t2d.size = { 0.0f, 0.0f, std::round(inner * trailFraction), innerHeight }; trail->Opacity = opacity * 0.85f; fill->t2d.position = { 0.0f, 0.0f, barTopLeft.x + BAR_BORDER, barTopLeft.y + BAR_BORDER }; fill->t2d.size = { 0.0f, 0.0f, std::round(inner * fraction), innerHeight }; fill->Color = color; fill->Opacity = opacity; }