Working on portrait mode
This commit is contained in:
1 parent
b8d79c7b7b
commit
6b39cfca3b
5 files changed
+162
-27
No files matched your search
@@ -56,6 +56,13 @@ void DialogueOverlay::draw(Renderer& renderer, const PresentationModel& model) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (Environment::projectionWidth < Environment::projectionHeight)
|
||||
drawPortrait(renderer, model);
|
||||
else
|
||||
drawLandscape(renderer, model);
|
||||
}
|
||||
|
||||
void DialogueOverlay::drawLandscape(Renderer& renderer, const PresentationModel& model) {
|
||||
const float W = Environment::projectionWidth;
|
||||
|
||||
const float nameX = 312 + 8;
|
||||
@@ -64,7 +71,7 @@ void DialogueOverlay::draw(Renderer& renderer, const PresentationModel& model) {
|
||||
const float bodyY = 232 - 78.0f;
|
||||
|
||||
const float bodyMaxWidthPx = 1280.0 - nameX - 48.f - 60.f;
|
||||
|
||||
|
||||
|
||||
float centeredShiftX = ((W - nameX - 48.f - 60.f) - bodyMaxWidthPx)*0.5;
|
||||
|
||||
@@ -147,16 +154,13 @@ void DialogueOverlay::draw(Renderer& renderer, const PresentationModel& model) {
|
||||
const std::string wrappedBody = wrapTextToWidth(model.visibleText, *bodyRenderer, bodyMaxWidthPx, 1.0f);
|
||||
bodyRenderer->drawText(wrappedBody, bodyX + centeredShiftX, bodyY, 1.0f, false, { 1.0f, 1.0f, 1.0f, 1.0f });
|
||||
|
||||
|
||||
|
||||
if (model.mode == PresentationMode::Choice) {
|
||||
const float choiceStartY = 270.f-35;
|
||||
const float choiceHeight = 121.f*0.9;
|
||||
const float choiceSpacing = -30.f;
|
||||
const float choiceWidth = 913.f * 0.9;
|
||||
|
||||
//UiRect textboxRect{ 30.f, -48.f, 1222.f, 340.0f };
|
||||
|
||||
|
||||
if (choiceQuads.size() < model.choices.size()) {
|
||||
choiceQuads.resize(model.choices.size());
|
||||
}
|
||||
@@ -204,6 +208,141 @@ void DialogueOverlay::draw(Renderer& renderer, const PresentationModel& model) {
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
void DialogueOverlay::drawPortrait(Renderer& renderer, const PresentationModel& model) {
|
||||
const float W = Environment::projectionWidth;
|
||||
const float H = Environment::projectionHeight;
|
||||
|
||||
// Panel: DialogChoice001.png scaled to full screen width, aspect ratio preserved.
|
||||
const float texAspect = static_cast<float>(textboxChoiceTexture->getWidth())
|
||||
/ static_cast<float>(textboxChoiceTexture->getHeight());
|
||||
const float panelW = W;
|
||||
const float panelH = panelW / texAspect;
|
||||
const float clipAtBottom = 18.f;
|
||||
const float panelTopY = panelH - clipAtBottom;
|
||||
|
||||
// Character portrait sits above the panel, shifted right and slightly overlapping.
|
||||
const float portraitSize = 200.f;
|
||||
const float portraitX = 56.f;
|
||||
const float portraitY = panelTopY + 6.f - 40.f;
|
||||
|
||||
// Text sits inside the panel near the top.
|
||||
const float leftPad = 60.f;
|
||||
const float rightPad = 60.f;
|
||||
const float textMaxWidth = W - leftPad - rightPad;
|
||||
const float nameY = panelTopY - 32.f - 50.f;
|
||||
const float bodyY = nameY - 38.f;
|
||||
|
||||
// --- Rebuild quads only when geometry changes ---
|
||||
{
|
||||
UiRect panelRect{ 0.f, -clipAtBottom, panelW, panelH };
|
||||
if (!portraitPanelQuad.initialized
|
||||
|| portraitPanelQuad.rect.x != panelRect.x || portraitPanelQuad.rect.y != panelRect.y
|
||||
|| portraitPanelQuad.rect.w != panelRect.w || portraitPanelQuad.rect.h != panelRect.h) {
|
||||
portraitPanelQuad.rebuild(panelRect);
|
||||
}
|
||||
}
|
||||
{
|
||||
UiRect portraitRect{ portraitX, portraitY, portraitSize, portraitSize };
|
||||
if (!portraitAbovePortraitQuad.initialized
|
||||
|| portraitAbovePortraitQuad.rect.x != portraitRect.x || portraitAbovePortraitQuad.rect.y != portraitRect.y
|
||||
|| portraitAbovePortraitQuad.rect.w != portraitRect.w || portraitAbovePortraitQuad.rect.h != portraitRect.h) {
|
||||
portraitAbovePortraitQuad.rebuild(portraitRect);
|
||||
}
|
||||
}
|
||||
|
||||
// --- Draw panel and portrait image ---
|
||||
glEnable(GL_BLEND);
|
||||
renderer.shaderManager.PushShader(defaultShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.PushProjectionMatrix(0.f, W, 0.f, H, -10.f, 10.f);
|
||||
renderer.PushMatrix();
|
||||
renderer.LoadIdentity();
|
||||
renderer.RenderUniform1f("uAlpha", 1.0f);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, textboxChoiceTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(portraitPanelQuad.mesh);
|
||||
|
||||
auto portrait = loadTextureCached(model.portraitPath);
|
||||
if (portrait) {
|
||||
glBindTexture(GL_TEXTURE_2D, portrait->getTexID());
|
||||
renderer.DrawVertexRenderStruct(portraitAbovePortraitQuad.mesh);
|
||||
}
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.shaderManager.PopShader();
|
||||
|
||||
// --- Name and body text ---
|
||||
lastChoiceRects.clear();
|
||||
|
||||
if (!model.speaker.empty()) {
|
||||
nameRenderer->drawText(model.speaker, leftPad, nameY, 1.0f, false, { 1.0f, 0.88f, 0.45f, 1.0f });
|
||||
}
|
||||
|
||||
const std::string wrappedBody = wrapTextToWidth(model.visibleText, *bodyRenderer, textMaxWidth, 1.0f);
|
||||
bodyRenderer->drawText(wrappedBody, leftPad, bodyY, 1.0f, false, { 1.0f, 1.0f, 1.0f, 1.0f });
|
||||
|
||||
// Hit rect for tap-to-advance.
|
||||
lastDialogueAdvanceRect = { 0.f, 0.f, W, panelTopY };
|
||||
|
||||
// --- Choice mode: stack choices inside the panel ---
|
||||
if (model.mode == PresentationMode::Choice) {
|
||||
const float choiceTexAspect = static_cast<float>(choiceMainTexture->getWidth())
|
||||
/ static_cast<float>(choiceMainTexture->getHeight());
|
||||
const float choiceW = W - leftPad - rightPad;
|
||||
const float choiceH = choiceW / choiceTexAspect;
|
||||
const float choiceSpacing = 8.f;
|
||||
|
||||
const float totalChoicesH = (choiceH + choiceSpacing) * static_cast<float>(model.choices.size()) - choiceSpacing;
|
||||
const float choiceStartY = panelTopY - 34.f - totalChoicesH; // below name row
|
||||
|
||||
if (choiceQuads.size() < model.choices.size()) {
|
||||
choiceQuads.resize(model.choices.size());
|
||||
}
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
renderer.shaderManager.PushShader(defaultShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.PushProjectionMatrix(0.f, W, 0.f, H, -10.f, 10.f);
|
||||
renderer.PushMatrix();
|
||||
renderer.LoadIdentity();
|
||||
|
||||
for (size_t i = 0; i < model.choices.size(); ++i) {
|
||||
const float cy = choiceStartY + (choiceH + choiceSpacing) * static_cast<float>(model.choices.size() - 1 - i);
|
||||
UiRect rect{ leftPad, cy, choiceW, choiceH };
|
||||
lastChoiceRects.push_back(rect);
|
||||
choiceQuads[i].rebuild(rect);
|
||||
|
||||
const bool isHighlighted = static_cast<int>(i) == hoveredChoiceIndex || static_cast<int>(i) == model.selectedChoice;
|
||||
std::shared_ptr<Texture> choiceTexture =
|
||||
(model.choices[i].kind == ChoiceKind::Optional) ? choiceOptionalTexture : choiceMainTexture;
|
||||
if (isHighlighted) choiceTexture = choiceSelectedTexture;
|
||||
glBindTexture(GL_TEXTURE_2D, choiceTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(choiceQuads[i].mesh);
|
||||
}
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.shaderManager.PopShader();
|
||||
|
||||
for (size_t i = 0; i < model.choices.size(); ++i) {
|
||||
const UiRect& rect = lastChoiceRects[i];
|
||||
const bool isHighlighted = static_cast<int>(i) == hoveredChoiceIndex || static_cast<int>(i) == model.selectedChoice;
|
||||
const std::array<float, 4> color = (model.choices[i].kind == ChoiceKind::Optional)
|
||||
? std::array<float, 4>{0.82f, 0.82f, 0.82f, 1.0f}
|
||||
: std::array<float, 4>{ 1.0f, 0.93f, 0.65f, 1.0f };
|
||||
|
||||
const std::string wrappedChoice = wrapTextToWidth(model.choices[i].text, *choiceRenderer, rect.w - 20.0f, 1.0f);
|
||||
choiceRenderer->drawText(
|
||||
wrappedChoice, rect.x + 20.f, rect.y + choiceH * 0.35f, 1.5f, false,
|
||||
isHighlighted ? std::array<float, 4>{1.0f, 1.0f, 1.0f, 1.0f} : color
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
}
|
||||
|
||||
void DialogueOverlay::handlePointerDown(float x, float y, const PresentationModel& model) {
|
||||
if (model.mode == PresentationMode::Choice) {
|
||||
handlePointerMoved(x, y, model);
|
||||
@@ -241,8 +380,8 @@ bool DialogueOverlay::handlePointerReleased(float x, float y, const Presentation
|
||||
}
|
||||
|
||||
if (model.mode == PresentationMode::Dialogue) {
|
||||
outAdvanceDialogue = rectContains(lastDialogueAdvanceRect, x, y);
|
||||
return outAdvanceDialogue;
|
||||
outAdvanceDialogue = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
|
||||
@@ -47,11 +47,18 @@ private:
|
||||
UiQuad textboxChoiceQuad;
|
||||
mutable std::vector<UiQuad> choiceQuads;
|
||||
|
||||
// Portrait-mode quads (rebuilt when geometry changes)
|
||||
UiQuad portraitPanelQuad;
|
||||
UiQuad portraitAbovePortraitQuad;
|
||||
|
||||
std::shared_ptr<Texture> loadTextureCached(const std::string& path);
|
||||
|
||||
static std::string wrapTextToWidth(const std::string& input, const TextRenderer& textRenderer,
|
||||
float maxWidthPx, float scale);
|
||||
static bool rectContains(const UiRect& rect, float x, float y);
|
||||
|
||||
void drawLandscape(Renderer& renderer, const PresentationModel& model);
|
||||
void drawPortrait(Renderer& renderer, const PresentationModel& model);
|
||||
};
|
||||
|
||||
} // namespace ZL::Dialogue
|
||||
Reference in new issue
Block a user