space-game001/src/dialogue/DialogueOverlay.h

120 lines
3.9 KiB
C++

#pragma once
#include "dialogue/DialogueRuntime.h"
#include "render/Renderer.h"
#include "render/TextRenderer.h"
#include "render/TextureManager.h"
#include "UiManager.h"
#include <memory>
#include <string>
#include <unordered_map>
#include <vector>
namespace ZL::Dialogue {
class DialogueOverlay {
public:
bool init(Renderer& renderer, const std::string& zipFile = "");
void update(const PresentationModel& model, int deltaMs);
void draw(Renderer& renderer, const PresentationModel& model);
void handlePointerDown(float x, float y, const PresentationModel& model);
void handlePointerMoved(float x, float y, const PresentationModel& model);
bool handlePointerReleased(float x, float y, const PresentationModel& model, int& outChoiceIndex, bool& outAdvanceDialogue);
bool consumeSkipRequested();
private:
struct TexturedQuad {
UiRect rect;
VertexRenderStruct mesh;
bool initialized = false;
void rebuild(const UiRect& newRect);
void rebuildWithUV(
const UiRect& newRect,
const Eigen::Vector2f& uvBottomLeft,
const Eigen::Vector2f& uvTopLeft,
const Eigen::Vector2f& uvTopRight,
const Eigen::Vector2f& uvBottomRight
);
};
struct ResolvedViewport {
float centerXPx = 0.0f;
float centerYPx = 0.0f;
float widthPx = 1.0f;
float heightPx = 1.0f;
float rotationDeg = 0.0f;
};
Renderer* rendererRef = nullptr;
std::string zipFilename;
std::shared_ptr<Texture> textboxTexture;
std::shared_ptr<Texture> portraitFrameTexture;
std::shared_ptr<Texture> choiceMainTexture;
std::shared_ptr<Texture> choiceOptionalTexture;
std::shared_ptr<Texture> choiceSelectedTexture;
std::shared_ptr<Texture> cutsceneSubtitleTexture;
mutable std::vector<UiRect> lastChoiceRects;
mutable UiRect lastDialogueAdvanceRect{};
mutable UiRect lastCutsceneAdvanceRect{};
mutable UiRect lastCutsceneSkipRect{};
int hoveredChoiceIndex = -1;
// Cutscene skip UX:
// First LMB/tap anywhere arms skip and shows a hint for 5 seconds.
// While armed, holding LMB/touch anywhere for 3.5 seconds requests skip.
bool cutsceneSkipHintVisible = false;
bool cutsceneSkipArmed = false;
bool cutsceneSkipHolding = false;
bool cutsceneSkipTriggered = false;
int cutsceneSkipHintRemainingMs = 0;
int cutsceneSkipHoldElapsedMs = 0;
static constexpr int CutsceneSkipHintDurationMs = 5000;
static constexpr int CutsceneSkipHoldDurationMs = 3500;
std::unique_ptr<TextRenderer> nameRenderer;
std::unique_ptr<TextRenderer> bodyRenderer;
std::unique_ptr<TextRenderer> choiceRenderer;
std::unique_ptr<TextRenderer> cutsceneRenderer;
TexturedQuad portraitQuad;
TexturedQuad textboxQuad;
TexturedQuad subtitleQuad;
TexturedQuad backgroundQuad;
TexturedQuad skipHintBgQuad;
TexturedQuad skipProgressBgQuad;
TexturedQuad skipProgressFillQuad;
mutable std::vector<TexturedQuad> choiceQuads;
std::unordered_map<std::string, std::shared_ptr<Texture>> textureCache;
void drawDialogue(Renderer& renderer, const PresentationModel& model);
void drawCutscene(Renderer& renderer, const PresentationModel& model);
std::shared_ptr<Texture> loadTextureCached(const std::string& path);
void drawQuad(Renderer& renderer, const TexturedQuad& quad, const std::shared_ptr<Texture>& texture) const;
static std::string wrapText(const std::string& input, size_t maxLineLength);
static bool rectContains(const UiRect& rect, float x, float y);
static float lerpFloat(float a, float b, float t);
static ResolvedViewport resolveViewportPose(
const CutsceneCameraPose& pose,
float texW,
float texH,
float screenW,
float screenH
);
static ResolvedViewport blendViewport(
const ResolvedViewport& from,
const ResolvedViewport& to,
float t
);
};
} // namespace ZL::Dialogue