Working on messenger in portrait mode
This commit is contained in:
1 parent
0b4df8ab2d
commit
8c42179576
10 files changed
+498
-65
No files matched your search
+155
-25
@@ -7,6 +7,7 @@
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
|
||||
namespace ZL {
|
||||
|
||||
static int questStatusPriority(Quest::QuestStatus status) {
|
||||
@@ -149,9 +150,12 @@ namespace ZL {
|
||||
phoneChatListHintRoot = loadUiFromFile("resources/w/ui/screen_phone_chat_list_hint001.json", renderer, zipFile);
|
||||
verticalPhoneChatListRoot = loadUiFromFile("resources/w/ui/portrait_screen_phone_chat_list.json", renderer, zipFile);
|
||||
verticalPhoneChatListHintRoot = loadUiFromFile("resources/w/ui/portrait_screen_phone_chat_list_hint001.json", renderer, zipFile);
|
||||
phoneChat1Root = loadUiFromFile("resources/w/ui/screen_phone_chat1.json", renderer, zipFile);
|
||||
phoneChat2Root = loadUiFromFile("resources/w/ui/screen_phone_chat2.json", renderer, zipFile);
|
||||
phoneChat3Root = loadUiFromFile("resources/w/ui/screen_phone_chat3.json", renderer, zipFile);
|
||||
phoneChat1Root = loadUiFromFile("resources/w/ui/screen_phone_chat1.json", renderer, zipFile);
|
||||
phoneChat2Root = loadUiFromFile("resources/w/ui/screen_phone_chat2.json", renderer, zipFile);
|
||||
phoneChat3Root = loadUiFromFile("resources/w/ui/screen_phone_chat3.json", renderer, zipFile);
|
||||
verticalPhoneChat1Root = loadUiFromFile("resources/w/ui/portrait_screen_phone_chat1.json", renderer, zipFile);
|
||||
verticalPhoneChat2Root = loadUiFromFile("resources/w/ui/portrait_screen_phone_chat2.json", renderer, zipFile);
|
||||
verticalPhoneChat3Root = loadUiFromFile("resources/w/ui/portrait_screen_phone_chat3.json", renderer, zipFile);
|
||||
|
||||
modalMenuRoot = loadUiFromFile("resources/w/ui/screen_modal_menu.json", renderer, zipFile);
|
||||
newInventoryRoot = loadUiFromFile("resources/w/ui/screen_inventory.json", renderer, zipFile);
|
||||
@@ -657,15 +661,15 @@ namespace ZL {
|
||||
uiManager.setButtonCallback("phoneMain", [this](const std::string&) {});
|
||||
uiManager.setTextButtonCallback("chat1button", [this](const std::string&) {
|
||||
gameState_.chatUnread[0] = false;
|
||||
openPhoneChatFromList(0, phoneChat1Root);
|
||||
openPhoneChatFromList(0, isPortraitMode() ? verticalPhoneChat1Root : phoneChat1Root);
|
||||
});
|
||||
uiManager.setTextButtonCallback("chat2button", [this](const std::string&) {
|
||||
gameState_.chatUnread[1] = false;
|
||||
openPhoneChatFromList(1, phoneChat2Root);
|
||||
openPhoneChatFromList(1, isPortraitMode() ? verticalPhoneChat2Root : phoneChat2Root);
|
||||
});
|
||||
uiManager.setTextButtonCallback("chat3button", [this](const std::string&) {
|
||||
gameState_.chatUnread[2] = false;
|
||||
openPhoneChatFromList(2, phoneChat3Root);
|
||||
openPhoneChatFromList(2, isPortraitMode() ? verticalPhoneChat3Root : phoneChat3Root);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -784,7 +788,33 @@ namespace ZL {
|
||||
gameState_.tutorialPhoneChatScreenOpened = true;
|
||||
uiManager.pushMenuFromSavedRoot(chatRoot);
|
||||
|
||||
rebuildChatBubblesFromHistory(chatIndex);
|
||||
// Build a dedicated chatUiManager root sized to the FBO chat area
|
||||
{
|
||||
const bool portrait = isPortraitMode();
|
||||
const float fboW = portrait ? CHAT_FBO_WIDTH_P : CHAT_FBO_WIDTH_L;
|
||||
const float fboH = portrait ? (CHAT_FBO_OFFSET_UP_P + CHAT_FBO_OFFSET_DOWN_P)
|
||||
: (CHAT_FBO_OFFSET_UP_L + CHAT_FBO_OFFSET_DOWN_L);
|
||||
|
||||
auto fboRoot = std::make_shared<UiNode>();
|
||||
fboRoot->name = "chatFboRoot";
|
||||
fboRoot->width = fboW;
|
||||
fboRoot->height = fboH;
|
||||
fboRoot->screenRect = { 0.0f, 0.0f, fboW, fboH };
|
||||
|
||||
auto fboContainer = std::make_shared<UiNode>();
|
||||
fboContainer->name = "chatMessagesContainer";
|
||||
fboContainer->width = fboW;
|
||||
fboContainer->height = fboH;
|
||||
fboContainer->screenRect = { 0.0f, 0.0f, fboW, fboH };
|
||||
fboRoot->children.push_back(fboContainer);
|
||||
|
||||
chatUiManager.replaceRoot(fboRoot);
|
||||
chatFrameBuffer_ = std::make_unique<FrameBuffer>(
|
||||
static_cast<int>(fboW), static_cast<int>(fboH), false);
|
||||
chatFboQuadLastProjW_ = -1.0f;
|
||||
}
|
||||
|
||||
rebuildChatBubblesFromHistory(chatIndex, isPortraitMode());
|
||||
|
||||
uiManager.setButtonCallback("phoneExitButton", [this](const std::string&) {
|
||||
closePhoneScreenFromChat();
|
||||
@@ -808,6 +838,8 @@ namespace ZL {
|
||||
activeChatIndex_ = -1;
|
||||
currentPhoneSubScreen_ = PhoneSubScreen::ChatList;
|
||||
phoneChatVisibleBubbles_.clear();
|
||||
chatUiManager.replaceRoot(nullptr);
|
||||
chatFrameBuffer_.reset();
|
||||
uiManager.popMenu();
|
||||
uiManager.updateAllLayouts();
|
||||
if (gameState_.tutorialPhoneChatScreenOpened)
|
||||
@@ -832,6 +864,8 @@ namespace ZL {
|
||||
currentPhoneSubScreen_ = PhoneSubScreen::None;
|
||||
uiState_ = GameUiState::Gameplay;
|
||||
phoneChatVisibleBubbles_.clear();
|
||||
chatUiManager.replaceRoot(nullptr);
|
||||
chatFrameBuffer_.reset();
|
||||
const int depth = uiManager.menuStackSize();
|
||||
for (int i = 0; i < depth; ++i) uiManager.popMenu();
|
||||
uiManager.updateAllLayouts();
|
||||
@@ -1261,42 +1295,69 @@ namespace ZL {
|
||||
if (i > 0) totalHeight += CHAT_SPACING;
|
||||
}
|
||||
|
||||
const float available = CHAT_TOP_Y - CHAT_BOTTOM_Y;
|
||||
const float topY = (totalHeight <= available)
|
||||
? CHAT_TOP_Y
|
||||
: CHAT_BOTTOM_Y + totalHeight;
|
||||
const float fboH = CHAT_FBO_OFFSET_UP_L + CHAT_FBO_OFFSET_DOWN_L;
|
||||
const float topY = (totalHeight <= fboH) ? fboH : totalHeight;
|
||||
|
||||
float cursor = topY;
|
||||
for (auto& bubble : phoneChatVisibleBubbles_) {
|
||||
auto node = uiManager.findNode(bubble.nodeName);
|
||||
auto node = chatUiManager.findNode(bubble.nodeName);
|
||||
if (!node) continue;
|
||||
node->localY = cursor - bubble.height;
|
||||
cursor -= bubble.height + CHAT_SPACING;
|
||||
}
|
||||
uiManager.updateAllLayouts();
|
||||
chatUiManager.updateAllLayouts();
|
||||
}
|
||||
|
||||
void MenuManager::rebuildChatBubblesFromHistory(int chatIndex) {
|
||||
uiManager.clearChatBubbles("chatMessagesContainer");
|
||||
void MenuManager::recomputePhoneChatPositionsPortrait() {
|
||||
float totalHeight = 0.0f;
|
||||
for (size_t i = 0; i < phoneChatVisibleBubbles_.size(); ++i) {
|
||||
totalHeight += phoneChatVisibleBubbles_[i].height;
|
||||
if (i > 0) totalHeight += CHAT_SPACING;
|
||||
}
|
||||
|
||||
const float fboH = CHAT_FBO_OFFSET_UP_P + CHAT_FBO_OFFSET_DOWN_P;
|
||||
const float topY = (totalHeight <= fboH) ? fboH : totalHeight;
|
||||
|
||||
float cursor = topY;
|
||||
for (auto& bubble : phoneChatVisibleBubbles_) {
|
||||
auto node = chatUiManager.findNode(bubble.nodeName);
|
||||
if (!node) continue;
|
||||
node->localY = cursor - bubble.height;
|
||||
cursor -= bubble.height + CHAT_SPACING;
|
||||
}
|
||||
chatUiManager.updateAllLayouts();
|
||||
}
|
||||
|
||||
void MenuManager::rebuildChatBubblesFromHistory(int chatIndex, bool isPortrait) {
|
||||
chatUiManager.clearChatBubbles("chatMessagesContainer");
|
||||
phoneChatVisibleBubbles_.clear();
|
||||
|
||||
if (chatIndex < 0 || chatIndex > 2) return;
|
||||
for (const auto& msg : gameState_.chatHistory[chatIndex]) {
|
||||
const bool inc = msg.incoming;
|
||||
const std::string nodeName = uiManager.addChatBubble(
|
||||
const std::string nodeName = chatUiManager.addChatBubble(
|
||||
"chatMessagesContainer", msg.text, inc,
|
||||
inc ? texBubbleInCenter_ : texBubbleOutCenter_,
|
||||
inc ? texBubbleInLT_ : texBubbleOutLT_,
|
||||
inc ? texBubbleInLB_ : texBubbleOutLB_,
|
||||
inc ? texBubbleInRT_ : texBubbleOutRT_,
|
||||
inc ? texBubbleInRB_ : texBubbleOutRB_,
|
||||
renderer, "resources/fonts/DroidSans.ttf", 20, CONST_ZIP_FILE);
|
||||
renderer, "resources/fonts/DroidSans.ttf", isPortrait ? 32 : 20, isPortrait, CONST_ZIP_FILE);
|
||||
if (!nodeName.empty()) {
|
||||
auto n = uiManager.findNode(nodeName);
|
||||
auto n = chatUiManager.findNode(nodeName);
|
||||
phoneChatVisibleBubbles_.push_back({ nodeName, n ? n->height : 60.0f });
|
||||
}
|
||||
}
|
||||
recomputePhoneChatPositions();
|
||||
|
||||
if (isPortrait)
|
||||
{
|
||||
recomputePhoneChatPositionsPortrait();
|
||||
}
|
||||
else
|
||||
{
|
||||
recomputePhoneChatPositions();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void MenuManager::onChatBubbleReady(const std::string& text, bool incoming) {
|
||||
@@ -1310,25 +1371,34 @@ namespace ZL {
|
||||
|
||||
if (uiState_ != GameUiState::PhoneScreen) return;
|
||||
|
||||
const std::string nodeName = uiManager.addChatBubble(
|
||||
bool isPortrait = isPortraitMode();
|
||||
|
||||
const std::string nodeName = chatUiManager.addChatBubble(
|
||||
"chatMessagesContainer", text, incoming,
|
||||
incoming ? texBubbleInCenter_ : texBubbleOutCenter_,
|
||||
incoming ? texBubbleInLT_ : texBubbleOutLT_,
|
||||
incoming ? texBubbleInLB_ : texBubbleOutLB_,
|
||||
incoming ? texBubbleInRT_ : texBubbleOutRT_,
|
||||
incoming ? texBubbleInRB_ : texBubbleOutRB_,
|
||||
renderer, "resources/fonts/DroidSans.ttf", 20, CONST_ZIP_FILE);
|
||||
renderer, "resources/fonts/DroidSans.ttf", isPortrait ? 32 : 20, isPortrait, CONST_ZIP_FILE);
|
||||
|
||||
if (nodeName.empty()) return;
|
||||
|
||||
auto node = uiManager.findNode(nodeName);
|
||||
auto node = chatUiManager.findNode(nodeName);
|
||||
if (node) {
|
||||
node->scaleX = 0.0f;
|
||||
node->scaleY = 0.0f;
|
||||
phoneChatVisibleBubbles_.push_back({ nodeName, node->height });
|
||||
}
|
||||
recomputePhoneChatPositions();
|
||||
uiManager.startPopIn(nodeName, 300.0f);
|
||||
if (isPortrait)
|
||||
{
|
||||
recomputePhoneChatPositionsPortrait();
|
||||
}
|
||||
else
|
||||
{
|
||||
recomputePhoneChatPositions();
|
||||
}
|
||||
chatUiManager.startPopIn(nodeName, 300.0f);
|
||||
}
|
||||
|
||||
void MenuManager::setDarklandsMode(bool enabled)
|
||||
@@ -1537,6 +1607,57 @@ namespace ZL {
|
||||
|
||||
void MenuManager::update(float deltaMs) {
|
||||
updateToasts(deltaMs);
|
||||
chatUiManager.update(deltaMs);
|
||||
}
|
||||
|
||||
void MenuManager::drawChatFbo(Renderer& renderer) {
|
||||
if (!chatFrameBuffer_) return;
|
||||
|
||||
const bool portrait = isPortraitMode();
|
||||
const float fboW = portrait ? CHAT_FBO_WIDTH_P : CHAT_FBO_WIDTH_L;
|
||||
const float offsetUp = portrait ? CHAT_FBO_OFFSET_UP_P : CHAT_FBO_OFFSET_UP_L;
|
||||
const float offsetDown= portrait ? CHAT_FBO_OFFSET_DOWN_P : CHAT_FBO_OFFSET_DOWN_L;
|
||||
const float fboH = offsetUp + offsetDown;
|
||||
const float projW = Environment::projectionWidth;
|
||||
const float projH = Environment::projectionHeight;
|
||||
|
||||
// Pass 1: render chatUiManager into FBO
|
||||
chatFrameBuffer_->Bind();
|
||||
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
|
||||
glClear(GL_COLOR_BUFFER_BIT);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
chatUiManager.draw(renderer, fboW, fboH);
|
||||
chatFrameBuffer_->Unbind();
|
||||
|
||||
// Pass 2: blit FBO texture onto screen, centered with up/down offsets from screen center
|
||||
if (chatFboQuadLastProjW_ != projW || chatFboQuadLastPortrait_ != portrait ||
|
||||
chatFboQuadLastProjH_ != projH) {
|
||||
const float x0 = (projW - fboW) * 0.5f;
|
||||
const float y0 = projH * 0.5f - offsetDown;
|
||||
const float x1 = x0 + fboW;
|
||||
const float y1 = y0 + fboH;
|
||||
VertexDataStruct vd;
|
||||
vd.PositionData = { {x0,y0,0},{x0,y1,0},{x1,y1,0},
|
||||
{x0,y0,0},{x1,y1,0},{x1,y0,0} };
|
||||
vd.TexCoordData = { {0,0},{0,1},{1,1},
|
||||
{0,0},{1,1},{1,0} };
|
||||
chatFboQuad_.AssignFrom(vd);
|
||||
chatFboQuadLastProjW_ = projW;
|
||||
chatFboQuadLastProjH_ = projH;
|
||||
chatFboQuadLastPortrait_ = portrait;
|
||||
}
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
renderer.PushProjectionMatrix(projW, projH, -1, 1);
|
||||
renderer.PushMatrix();
|
||||
renderer.LoadIdentity();
|
||||
renderer.RenderUniform1f("uAlpha", 1.0f);
|
||||
glBindTexture(GL_TEXTURE_2D, chatFrameBuffer_->getTextureID());
|
||||
renderer.DrawVertexRenderStruct(chatFboQuad_);
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
}
|
||||
|
||||
void MenuManager::saveSettings() {
|
||||
@@ -1609,10 +1730,19 @@ namespace ZL {
|
||||
currentPhoneSubScreen_ = PhoneSubScreen::MapUni;
|
||||
break;
|
||||
case PhoneSubScreen::ChatList:
|
||||
case PhoneSubScreen::Chat:
|
||||
openPhoneScreen();
|
||||
openPhoneMessenger();
|
||||
break;
|
||||
case PhoneSubScreen::Chat: {
|
||||
openPhoneScreen();
|
||||
openPhoneMessenger();
|
||||
std::shared_ptr<UiNode> chatRoot;
|
||||
if (savedChatIndex == 0) chatRoot = isPortraitMode() ? verticalPhoneChat1Root : phoneChat1Root;
|
||||
else if (savedChatIndex == 1) chatRoot = isPortraitMode() ? verticalPhoneChat2Root : phoneChat2Root;
|
||||
else if (savedChatIndex == 2) chatRoot = isPortraitMode() ? verticalPhoneChat3Root : phoneChat3Root;
|
||||
if (chatRoot) openPhoneChatFromList(savedChatIndex, chatRoot);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
openPhoneScreen();
|
||||
break;
|
||||
|
||||
Reference in new issue
Block a user