Working on UI part

This commit is contained in:
Vladislav Khorev 2026-05-26 22:21:05 +03:00
parent 6c8fcf17b6
commit 0da1ae124c
17 changed files with 221 additions and 42 deletions

View File

@ -8,16 +8,8 @@
"id": "line_1",
"type": "Line",
"speaker": "Бекзат",
"portrait": "resources/w/gg/gg2_s_podsvetkoy5.png",
"text": "Новый день! Я проснулся, позавтракал и готов поехать в универ!",
"next": "line_2"
},
{
"id": "line_2",
"type": "Line",
"speaker": "Бекзат",
"portrait": "resources/w/gg/gg2_s_podsvetkoy5.png",
"text": "Надо проверить телефон, и не забыть взять свою записную книжку.",
"portrait": "resources/dialogue/portrait_hero_neutral.png",
"text": "Новый день! Я проснулся, позавтракал и готов поехать в универ! Надо проверить телефон, и не забыть взять свою записную книжку.",
"next": "end_1"
},
{

BIN
resources/dialogue/portrait_hero_neutral.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/dialogue/textbox_bg.png (Stored with Git LFS)

Binary file not shown.

BIN
resources/dialogue/textbox_bg_old.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -0,0 +1,36 @@
{
"root": {
"type": "FrameLayout",
"name": "hud_root",
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "LinearLayout",
"orientation": "vertical",
"vertical_align": "center",
"horizontal_align": "center",
"spacing": 0,
"width": "match_parent",
"height": 600,
"children": [
{
"type": "StaticImage",
"name": "hint1",
"width": 440,
"height": 134,
"horizontal_gravity": "center",
"texture": "resources/w/ui/img/Hint2.png"
},
{
"type": "StaticImage",
"name": "hint2",
"width": 24,
"height": 118,
"horizontal_gravity": "center",
"texture": "resources/w/ui/img/hint_arrow_down.png"
}
]
}]
}
}

View File

@ -0,0 +1,46 @@
{
"root": {
"type": "FrameLayout",
"name": "hud_root",
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "TextButton",
"name": "inventory_button",
"x": 50.0,
"y": 50.0,
"width": 150.0,
"height": 60.0,
"text": "Inventory",
"fontSize": 24,
"fontPath": "resources/fonts/DroidSans.ttf",
"textCentered": true,
"color": [1.0, 1.0, 1.0, 1.0],
"textures": {
"normal": "resources/w/red.png",
"hover": "resources/w/red.png",
"pressed": "resources/w/red.png"
}
},
{
"type": "TextButton",
"name": "quest_journal_button",
"x": 220.0,
"y": 50.0,
"width": 170.0,
"height": 60.0,
"text": "Quests",
"fontSize": 24,
"fontPath": "resources/fonts/DroidSans.ttf",
"textCentered": true,
"color": [1.0, 1.0, 1.0, 1.0],
"textures": {
"normal": "resources/w/red.png",
"hover": "resources/w/red.png",
"pressed": "resources/w/red.png"
}
}
]
}
}

BIN
resources/w/ui/img/Hint1.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/ui/img/Hint2.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
resources/w/ui/img/hint_arrow_down.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -286,7 +286,6 @@ namespace ZL
if (locations["uni_exterior"]->player)
locations["uni_exterior"]->player->onDeathAnimComplete = [this]() { startDarklandsTransition(); };
LocationSetup params_dorm;
//params_dorm.gameObjectsJsonPath = "resources/config2/gameobjects_dorm.json";
//params_dorm.gameObjectsJsonPath = "resources/config2/gameobjects_dorm_trees001.json";
@ -436,6 +435,7 @@ namespace ZL
glDisable(GL_DEPTH_TEST);
glDepthMask(GL_FALSE);
renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0);
glEnable(GL_BLEND);
@ -697,6 +697,8 @@ namespace ZL
break;
case SDLK_o:
x = x + 1;
std::cout << "current x: " << x << std::endl;
//y = y + 0.002;
//currentLocation->player->hp = 200;
//currentLocation->npcs[0]->walkSpeed += 0.01f;
@ -704,8 +706,10 @@ namespace ZL
break;
case SDLK_k:
y = y + 1;
std::cout << "current y: " << y << std::endl;
//y = y - 0.002;
std::cout << "Player pos: " << currentLocation->player->position.transpose() << std::endl;
//std::cout << "Player pos: " << currentLocation->player->position.transpose() << std::endl;
//currentLocation->npcs[0]->walkSpeed -= 0.01f;
//std::cout << "Walk speed: " << currentLocation->npcs[0]->walkSpeed << std::endl;
break;
@ -718,7 +722,8 @@ namespace ZL
break;
case SDLK_l:
x = x - 0.002;
x = x - 1;
std::cout << "current x: " << x << std::endl;
break;
case SDLK_c:
@ -726,6 +731,11 @@ namespace ZL
activateSlowMoEffect();
break;
case SDLK_i:
y = y - 1;
std::cout << "current y: " << y << std::endl;
break;
case SDLK_b:
if (navigationEditorMode && currentLocation) {
currentLocation->navigationEditorSave();

View File

@ -33,7 +33,8 @@ namespace ZL {
void MenuManager::setup(Inventory& inv, const std::string& zipFile) {
inventory = &inv;
hudRoot = loadUiFromFile("resources/config2/hud.json", renderer, zipFile);
//hudRoot = loadUiFromFile("resources/config2/hud.json", renderer, zipFile);
hudRoot = loadUiFromFile("resources/w/ui/hud_step0.json", renderer, zipFile);
inventoryRoot = loadUiFromFile("resources/config2/ui_inventory.json", renderer, zipFile);
questJournalRoot = loadUiFromFile("resources/config2/ui_quest_journal.json", renderer, zipFile);

View File

@ -231,6 +231,7 @@ namespace ZL {
renderer.DrawVertexRenderStruct(sparkQuad);
//renderer.PopMatrix();
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glDisable(GL_BLEND);
renderer.shaderManager.PopShader();
}

View File

@ -490,7 +490,7 @@ namespace ZL {
std::string path = t[key].get<std::string>();
try {
std::cout << "UiManager: loading texture for button '" << btn->name << "' : " << path << " Zip file: " << zipFile << std::endl;
return renderer.textureManager.LoadFromPng(path, zipFile);
return renderer.textureManager.LoadFromPng(path, zipFile, true);
}
catch (const std::exception& e) {
std::cerr << "UiManager: failed load texture " << path << " : " << e.what() << std::endl;
@ -522,7 +522,7 @@ namespace ZL {
std::string path = t[key].get<std::string>();
try {
std::cout << "UiManager: --loading texture for slider '" << s->name << "' : " << path << " Zip file: " << zipFile << std::endl;
return renderer.textureManager.LoadFromPng(path, zipFile);
return renderer.textureManager.LoadFromPng(path, zipFile, true);
}
catch (const std::exception& e) {
std::cerr << "UiManager: failed load texture " << path << " : " << e.what() << std::endl;
@ -594,8 +594,7 @@ namespace ZL {
if (!t.contains(key) || !t[key].is_string()) return nullptr;
std::string path = t[key].get<std::string>();
try {
auto data = CreateTextureDataFromPng(path.c_str(), zipFile.c_str());
return std::make_shared<Texture>(data);
return renderer.textureManager.LoadFromPng(path, zipFile, true);
}
catch (const std::exception& e) {
std::cerr << "UiManager: TextButton '" << tb->name << "' failed to load texture " << path << ": " << e.what() << std::endl;
@ -672,7 +671,7 @@ namespace ZL {
if (!texPath.empty()) {
try {
img->texture = renderer.textureManager.LoadFromPng(texPath, zipFile);
img->texture = renderer.textureManager.LoadFromPng(texPath, zipFile, true);
}
catch (const std::exception& e) {
std::cerr << "UiManager: failed load texture for StaticImage '" << img->name << "' : " << e.what() << std::endl;
@ -1056,9 +1055,9 @@ namespace ZL {
try {
if (!trackPath.empty())
s->texTrack = renderer.textureManager.LoadFromPng(trackPath, zipFile);
s->texTrack = renderer.textureManager.LoadFromPng(trackPath, zipFile, true);
if (!knobPath.empty())
s->texKnob = renderer.textureManager.LoadFromPng(knobPath, zipFile);
s->texKnob = renderer.textureManager.LoadFromPng(knobPath, zipFile, true);
}
catch (const std::exception& e) {
std::cerr << "UiManager: addSlider failed to load textures: " << e.what() << std::endl;

View File

@ -7,6 +7,12 @@
#include <array>
#include <cmath>
namespace ZL
{
extern float x;
extern float y;
}
namespace ZL::Dialogue {
void DialogueOverlay::TexturedQuad::rebuild(const UiRect& newRect) {
@ -161,8 +167,10 @@ void DialogueOverlay::drawDialogue(Renderer& renderer, const PresentationModel&
const float W = Environment::projectionWidth;
// const float H = Environment::projectionHeight;
const UiRect portraitRect{ 24.0f, 24.0f, 182.0f, 182.0f };
const UiRect textboxRect{ 220.0f, 24.0f, max(200.0f, W - 244.0f), 182.0f };
UiRect portraitRect{ 24.0f+90, 24.0f+16, 176.0f, 176.0f };
//const UiRect textboxRect{ 220.0f, 24.0f, max(200.0f, W - 244.0f), 182.0f };
UiRect textboxRect{ 30.f, -48.f, 1222.f, 340.0f };
lastDialogueAdvanceRect = { portraitRect.x, portraitRect.y, textboxRect.x + textboxRect.w - portraitRect.x, textboxRect.h };
lastCutsceneAdvanceRect = {};
@ -187,27 +195,27 @@ void DialogueOverlay::drawDialogue(Renderer& renderer, const PresentationModel&
renderer.PushProjectionMatrix(0.0f, W, 0.0f, Environment::projectionHeight, -10.0f, 10.0f);
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.RenderUniform1f("uAlpha", 1.0f);
drawQuad(renderer, textboxQuad, textboxTexture);
drawQuad(renderer, portraitQuad, model.portraitPath.empty() ? portraitFrameTexture : loadTextureCached(model.portraitPath));
drawQuad(renderer, portraitQuad, portraitFrameTexture);
//drawQuad(renderer, portraitQuad, model.portraitPath.empty() ? portraitFrameTexture : loadTextureCached(model.portraitPath));
drawQuad(renderer, portraitQuad, loadTextureCached(model.portraitPath));
renderer.PopMatrix();
renderer.PopProjectionMatrix();
renderer.shaderManager.PopShader();
const float nameX = textboxRect.x + 24.0f;
const float nameY = textboxRect.y + textboxRect.h - 38.0f;
const float bodyX = textboxRect.x + 24.0f;
const float bodyY = textboxRect.y + textboxRect.h - 78.0f;
const float nameX = 312;
const float nameY = 232 - 38.0f;
const float bodyX = 312;
const float bodyY = 232 - 78.0f;
if (!model.speaker.empty()) {
nameRenderer->drawText(model.speaker, nameX, nameY, 1.0f, false, { 1.0f, 0.88f, 0.45f, 1.0f });
}
const float bodyTextScale = 1.0f;
const float bodyMaxWidthPx = textboxRect.w - 48.0f;
const float bodyMaxWidthPx = W - nameX - 48.f-x;
const std::string wrappedBody = wrapTextToWidth(model.visibleText, *bodyRenderer, bodyMaxWidthPx, bodyTextScale);
bodyRenderer->drawText(wrappedBody, bodyX, bodyY, bodyTextScale, false, { 1.0f, 1.0f, 1.0f, 1.0f });

View File

@ -459,6 +459,8 @@ void TextRenderer::drawText(const std::string& text, float x, float y, float sca
r->RenderUniform1i("uText", 0);
r->RenderUniform4fv("uColor", color.data());
r->RenderUniform1f("uAlpha", 1.0f);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, atlasTexture->getTexID());

View File

@ -8,9 +8,68 @@
namespace ZL
{
bool IsPowerOf2(size_t n) {
return n > 0 && (n & (n - 1)) == 0;
}
size_t NextPowerOf2(size_t n) {
if (n == 0) return 1;
--n;
n |= n >> 1; n |= n >> 2; n |= n >> 4; n |= n >> 8; n |= n >> 16;
#if SIZE_MAX > 0xFFFFFFFF
n |= n >> 32;
#endif
return n + 1;
}
TextureDataStruct ResizeTextureDataToPOT(const TextureDataStruct& src) {
size_t newW = IsPowerOf2(src.width) ? src.width : NextPowerOf2(src.width);
size_t newH = IsPowerOf2(src.height) ? src.height : NextPowerOf2(src.height);
if (newW == src.width && newH == src.height) return src;
int channels = (src.format == TextureDataStruct::R8) ? 1
: (src.format == TextureDataStruct::RGB) ? 3 : 4;
TextureDataStruct dst = src;
dst.width = newW;
dst.height = newH;
dst.data.resize(newW * newH * channels);
for (size_t y = 0; y < newH; ++y) {
for (size_t x = 0; x < newW; ++x) {
float fx = (newW > 1) ? (float)x * (float)(src.width - 1) / (float)(newW - 1) : 0.f;
float fy = (newH > 1) ? (float)y * (float)(src.height - 1) / (float)(newH - 1) : 0.f;
size_t x0 = (size_t)fx, y0 = (size_t)fy;
size_t x1 = min(x0 + 1, src.width - 1);
size_t y1 = min(y0 + 1, src.height - 1);
float tx = fx - (float)x0, ty = fy - (float)y0;
for (int c = 0; c < channels; ++c) {
float v00 = (float)(unsigned char)src.data[(y0 * src.width + x0) * channels + c];
float v10 = (float)(unsigned char)src.data[(y0 * src.width + x1) * channels + c];
float v01 = (float)(unsigned char)src.data[(y1 * src.width + x0) * channels + c];
float v11 = (float)(unsigned char)src.data[(y1 * src.width + x1) * channels + c];
float val = v00 * (1.f - tx) * (1.f - ty) + v10 * tx * (1.f - ty)
+ v01 * (1.f - tx) * ty + v11 * tx * ty;
dst.data[(y * newW + x) * channels + c] = (char)(unsigned char)(val + 0.5f);
}
}
}
std::cout << "TextureManager: resized texture from "
<< src.width << "x" << src.height
<< " to " << newW << "x" << newH << " (POT)" << std::endl;
return dst;
}
Texture::Texture(const TextureDataStruct& texData) {
width = texData.width;
height = texData.height;
if (!IsPowerOf2(width) || !IsPowerOf2(height)) {
std::cerr << "TextureManager WARNING: non-POT texture "
<< width << "x" << height
<< " — upload may fail on some platforms." << std::endl;
}
glGenTextures(1, &texID);
glBindTexture(GL_TEXTURE_2D, texID);
@ -422,36 +481,42 @@ namespace ZL
return zipFile.empty() ? fileName : fileName + "|" + zipFile;
}
std::shared_ptr<Texture> TextureManager::LoadFromBmp24(const std::string& fileName, const std::string& zipFile)
std::shared_ptr<Texture> TextureManager::LoadFromBmp24(const std::string& fileName, const std::string& zipFile, bool resizeToPOT)
{
std::string key = MakeKey(fileName, zipFile);
auto it = textureMap.find(key);
if (it != textureMap.end())
return it->second;
auto tex = std::make_shared<Texture>(CreateTextureDataFromBmp24(fileName, zipFile));
auto data = CreateTextureDataFromBmp24(fileName, zipFile);
if (resizeToPOT) data = ResizeTextureDataToPOT(data);
auto tex = std::make_shared<Texture>(data);
textureMap[key] = tex;
return tex;
}
std::shared_ptr<Texture> TextureManager::LoadFromBmp32(const std::string& fileName, const std::string& zipFile)
std::shared_ptr<Texture> TextureManager::LoadFromBmp32(const std::string& fileName, const std::string& zipFile, bool resizeToPOT)
{
std::string key = MakeKey(fileName, zipFile);
auto it = textureMap.find(key);
if (it != textureMap.end())
return it->second;
auto tex = std::make_shared<Texture>(CreateTextureDataFromBmp32(fileName, zipFile));
auto data = CreateTextureDataFromBmp32(fileName, zipFile);
if (resizeToPOT) data = ResizeTextureDataToPOT(data);
auto tex = std::make_shared<Texture>(data);
textureMap[key] = tex;
return tex;
}
#ifdef PNG_ENABLED
std::shared_ptr<Texture> TextureManager::LoadFromPng(const std::string& fileName, const std::string& zipFile)
std::shared_ptr<Texture> TextureManager::LoadFromPng(const std::string& fileName, const std::string& zipFile, bool resizeToPOT)
{
std::string key = MakeKey(fileName, zipFile);
auto it = textureMap.find(key);
if (it != textureMap.end())
return it->second;
auto tex = std::make_shared<Texture>(CreateTextureDataFromPng(fileName, zipFile));
auto data = CreateTextureDataFromPng(fileName, zipFile);
if (resizeToPOT) data = ResizeTextureDataToPOT(data);
auto tex = std::make_shared<Texture>(data);
textureMap[key] = tex;
return tex;
}

View File

@ -62,13 +62,17 @@ namespace ZL
TextureDataStruct CreateTextureDataFromPng(const std::string& fullFileName, const std::string& ZIPFileName = "");
#endif
bool IsPowerOf2(size_t n);
size_t NextPowerOf2(size_t n);
TextureDataStruct ResizeTextureDataToPOT(const TextureDataStruct& texData);
class TextureManager
{
public:
std::shared_ptr<Texture> LoadFromBmp24(const std::string& fileName, const std::string& zipFile = "");
std::shared_ptr<Texture> LoadFromBmp32(const std::string& fileName, const std::string& zipFile = "");
std::shared_ptr<Texture> LoadFromBmp24(const std::string& fileName, const std::string& zipFile = "", bool resizeToPOT = false);
std::shared_ptr<Texture> LoadFromBmp32(const std::string& fileName, const std::string& zipFile = "", bool resizeToPOT = false);
#ifdef PNG_ENABLED
std::shared_ptr<Texture> LoadFromPng(const std::string& fileName, const std::string& zipFile = "");
std::shared_ptr<Texture> LoadFromPng(const std::string& fileName, const std::string& zipFile = "", bool resizeToPOT = false);
#endif
void Unload(const std::string& fileName, const std::string& zipFile = "");