Working on portrait mode
This commit is contained in:
parent
b8d79c7b7b
commit
6b39cfca3b
10
src/Game.cpp
10
src/Game.cpp
@ -694,9 +694,9 @@ namespace ZL
|
||||
if (!loadingCompleted) {
|
||||
drawLoading();
|
||||
}
|
||||
else if (Environment::width < Environment::height) {
|
||||
/*else if (Environment::width < Environment::height) {
|
||||
drawMobilePortraitOverlay();
|
||||
}
|
||||
}*/
|
||||
else
|
||||
{
|
||||
Location* loc = currentLocation();
|
||||
@ -733,7 +733,7 @@ namespace ZL
|
||||
CheckGlError(__FILE__, __LINE__);
|
||||
}
|
||||
|
||||
void Game::drawMobilePortraitOverlay()
|
||||
/*void Game::drawMobilePortraitOverlay()
|
||||
{
|
||||
if (!mobileRotateTexture) return;
|
||||
|
||||
@ -762,7 +762,7 @@ namespace ZL
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError(__FILE__, __LINE__);
|
||||
}
|
||||
}*/
|
||||
|
||||
void Game::drawLoading()
|
||||
{
|
||||
@ -944,7 +944,7 @@ namespace ZL
|
||||
}
|
||||
|
||||
// Suppress all input while portrait overlay is shown
|
||||
if (mobileIsPortrait) continue;
|
||||
//if (mobileIsPortrait) continue;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
if (event.type == SDL_KEYDOWN && event.key.keysym.sym == SDLK_AC_BACK) {
|
||||
|
||||
@ -153,7 +153,7 @@ namespace ZL {
|
||||
float mobileRotateMeshLastW = -1.0f;
|
||||
float mobileRotateMeshLastH = -1.0f;
|
||||
|
||||
void drawMobilePortraitOverlay();
|
||||
//void drawMobilePortraitOverlay();
|
||||
|
||||
int64_t newTickCount;
|
||||
int64_t lastTickCount;
|
||||
|
||||
@ -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
|
||||
|
||||
17
src/main.cpp
17
src/main.cpp
@ -38,14 +38,10 @@ void MainLoop() {
|
||||
#ifdef EMSCRIPTEN
|
||||
|
||||
EM_BOOL onWebGLContextLost(int /*eventType*/, const void* /*reserved*/, void* /*userData*/) {
|
||||
//delete g_game;
|
||||
//g_game = nullptr;
|
||||
return EM_TRUE;
|
||||
}
|
||||
|
||||
EM_BOOL onWebGLContextRestored(int /*eventType*/, const void* /*reserved*/, void* /*userData*/) {
|
||||
//g_game = new ZL::Game();
|
||||
//g_game->setup();
|
||||
return EM_TRUE;
|
||||
}
|
||||
|
||||
@ -235,8 +231,8 @@ int main(int argc, char *argv[]) {
|
||||
{
|
||||
|
||||
|
||||
constexpr int CONST_WIDTH = 1280;
|
||||
constexpr int CONST_HEIGHT = 720;
|
||||
constexpr int CONST_WIDTH = ZL::Environment::CONST_DEFAULT_WIDTH;
|
||||
constexpr int CONST_HEIGHT = ZL::Environment::CONST_DEFAULT_HEIGHT;
|
||||
|
||||
ZL::Environment::width = CONST_WIDTH;
|
||||
ZL::Environment::height = CONST_HEIGHT;
|
||||
@ -250,16 +246,9 @@ int main(int argc, char *argv[]) {
|
||||
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE);
|
||||
|
||||
#ifdef FULLSCREEN
|
||||
// Match the desktop's current resolution so the framebuffer matches
|
||||
// the screen and we don't force a video mode change.
|
||||
/*SDL_DisplayMode dm;
|
||||
if (SDL_GetCurrentDisplayMode(0, &dm) == 0) {
|
||||
ZL::Environment::width = dm.w;
|
||||
ZL::Environment::height = dm.h;
|
||||
}*/
|
||||
const Uint32 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_FULLSCREEN_DESKTOP;
|
||||
#else
|
||||
const Uint32 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI;
|
||||
const Uint32 windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_RESIZABLE;
|
||||
#endif
|
||||
|
||||
ZL::Environment::window = SDL_CreateWindow(
|
||||
|
||||
Loading…
Reference in New Issue
Block a user