Merge branch 'main' into linux

This commit is contained in:
Vladislav Khorev committed 2026-03-09 10:52:04 +00:00
commit e5d7885a12
48 files changed
+1085 -871

No files matched your search

+2
View File
@@ -73,6 +73,8 @@ set(SOURCES
../src/MenuManager.cpp ../src/MenuManager.cpp
../src/Space.h ../src/Space.h
../src/Space.cpp ../src/Space.cpp
../src/GameConstants.h
../src/GameConstants.cpp
) )
add_executable(space-game001 ${SOURCES}) add_executable(space-game001 ${SOURCES})
+2
View File
@@ -67,6 +67,8 @@ add_executable(space-game001
../src/MenuManager.cpp ../src/MenuManager.cpp
../src/Space.h ../src/Space.h
../src/Space.cpp ../src/Space.cpp
../src/GameConstants.h
../src/GameConstants.cpp
) )
# Установка проекта по умолчанию для Visual Studio # Установка проекта по умолчанию для Visual Studio
Binary file not shown.
Binary file not shown.
+22
View File
@@ -0,0 +1,22 @@
{
"root": {
"type": "FrameLayout",
"x": 0,
"y": 0,
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "StaticImage",
"name": "connecting",
"x" : 0,
"y" : 0,
"width": 488,
"height": 154,
"horizontal_gravity": "center",
"vertical_gravity": "center",
"texture": "resources/connecting.png"
}
]
}
}
+52
View File
@@ -0,0 +1,52 @@
{
"root": {
"type": "FrameLayout",
"x": 0,
"y": 0,
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "StaticImage",
"name": "connectionFailed",
"x" : 0,
"y" : 0,
"width": 488,
"height": 308,
"horizontal_gravity": "center",
"vertical_gravity": "center",
"texture": "resources/connection_failed.png"
},
{
"type": "Button",
"name": "connectionFailedReconnectButton",
"width": 382,
"height": 56,
"x" : 0,
"y" : -20,
"horizontal_gravity": "center",
"vertical_gravity": "center",
"textures": {
"normal": "resources/game_over/Filledbuttons.png",
"hover": "resources/game_over/Variant5.png",
"pressed": "resources/game_over/Variant6.png"
}
},
{
"type": "Button",
"name": "connectionFailedGoBack",
"width": 382,
"height": 56,
"x" : 0,
"y" : -86,
"horizontal_gravity": "center",
"vertical_gravity": "center",
"textures": {
"normal": "resources/game_over/Secondarybutton.png",
"hover": "resources/game_over/Secondarybutton.png",
"pressed": "resources/game_over/Secondarybutton.png"
}
}
]
}
}
+52
View File
@@ -0,0 +1,52 @@
{
"root": {
"type": "FrameLayout",
"x": 0,
"y": 0,
"width": "match_parent",
"height": "match_parent",
"children": [
{
"type": "StaticImage",
"name": "connectionLost",
"x" : 0,
"y" : 0,
"width": 488,
"height": 308,
"horizontal_gravity": "center",
"vertical_gravity": "center",
"texture": "resources/connection_lost.png"
},
{
"type": "Button",
"name": "reconnectButton",
"width": 382,
"height": 56,
"x" : 0,
"y" : -20,
"horizontal_gravity": "center",
"vertical_gravity": "center",
"textures": {
"normal": "resources/game_over/Filledbuttons.png",
"hover": "resources/game_over/Variant5.png",
"pressed": "resources/game_over/Variant6.png"
}
},
{
"type": "Button",
"name": "exitServerButton",
"width": 382,
"height": 56,
"x" : 0,
"y" : -86,
"horizontal_gravity": "center",
"vertical_gravity": "center",
"textures": {
"normal": "resources/game_over/Secondarybutton.png",
"hover": "resources/game_over/Secondarybutton.png",
"pressed": "resources/game_over/Secondarybutton.png"
}
}
]
}
}
+1 -1
View File
@@ -5,7 +5,7 @@
"texture": "resources/spark_white.png", "texture": "resources/spark_white.png",
"speedRange": [10.0, 30.0], "speedRange": [10.0, 30.0],
"zSpeedRange": [-1.0, 1.0], "zSpeedRange": [-1.0, 1.0],
"scaleRange": [0.5, 1.0], "scaleRange": [5.0, 10.0],
"lifeTimeRange": [200.0, 800.0], "lifeTimeRange": [200.0, 800.0],
"emissionRate": 50.0, "emissionRate": 50.0,
"maxParticles": 5, "maxParticles": 5,
+9 -25
View File
@@ -11,37 +11,25 @@
"height": "match_parent", "height": "match_parent",
"children": [ "children": [
{ {
"type": "Button", "type": "StaticImage",
"name": "titleBtn", "name": "titleBtn",
"width": 254, "width": 434,
"height": 35, "height": 35,
"textures": { "texture": "resources/main_menu/title.png"
"normal": "resources/main_menu/title.png",
"hover": "resources/main_menu/title.png",
"pressed": "resources/main_menu/title.png"
}
}, },
{ {
"type": "Button", "type": "StaticImage",
"name": "underlineBtn", "name": "underlineBtn",
"width": 168, "width": 168,
"height": 44, "height": 44,
"textures": { "texture": "resources/main_menu/line.png"
"normal": "resources/main_menu/line.png",
"hover": "resources/main_menu/line.png",
"pressed": "resources/main_menu/line.png"
}
}, },
{ {
"type": "Button", "type": "StaticImage",
"name": "subtitleBtn", "name": "subtitleBtn",
"width": 144, "width": 144,
"height": 11, "height": 11,
"textures": { "texture": "resources/main_menu/subtitle.png"
"normal": "resources/main_menu/subtitle.png",
"hover": "resources/main_menu/subtitle.png",
"pressed": "resources/main_menu/subtitle.png"
}
}, },
{ {
"type": "Button", "type": "Button",
@@ -66,15 +54,11 @@
} }
}, },
{ {
"type": "Button", "type": "StaticImage",
"name": "versionLabel", "name": "versionLabel",
"width": 81, "width": 81,
"height": 9, "height": 9,
"textures": { "texture": "resources/main_menu/version.png"
"normal": "resources/main_menu/version.png",
"hover": "resources/main_menu/version.png",
"pressed": "resources/main_menu/version.png"
}
} }
] ]
} }
@@ -10,6 +10,13 @@
"width": "match_parent", "width": "match_parent",
"height": "match_parent", "height": "match_parent",
"children": [ "children": [
{
"type": "StaticImage",
"name": "titleBtn",
"width": 266,
"height": 66,
"texture": "resources/select_your_ship.png"
},
{ {
"type": "LinearLayout", "type": "LinearLayout",
"orientation": "horizontal", "orientation": "horizontal",
+3 -9
View File
@@ -1,20 +1,14 @@
{ {
"emissionRate": 10.0, "emissionRate": 1.2,
"maxParticles": 200, "maxParticles": 400,
"particleSize": 0.3, "particleSize": 0.3,
"biasX": 0.3, "biasX": 0.3,
"emissionPoints": [ "emissionPoints": [
{
"position": [-1.0, 1.4, -3.5]
},
{
"position": [1.0, 1.4, -3.5]
}
], ],
"speedRange": [0.5, 2.0], "speedRange": [0.5, 2.0],
"zSpeedRange": [1.0, 3.0], "zSpeedRange": [1.0, 3.0],
"scaleRange": [0.8, 1.2], "scaleRange": [0.8, 1.2],
"lifeTimeRange": [600.0, 1400.0], "lifeTimeRange": [300.0, 500.0],
"texture": "resources/spark.png", "texture": "resources/spark.png",
"shaderProgramName": "spark" "shaderProgramName": "spark"
} }
+2 -2
View File
@@ -1,6 +1,6 @@
{ {
"emissionRate": 10.0, "emissionRate": 1.2,
"maxParticles": 200, "maxParticles": 400,
"particleSize": 0.3, "particleSize": 0.3,
"biasX": 0.3, "biasX": 0.3,
"emissionPoints": [ "emissionPoints": [
+6 -4
View File
@@ -31,7 +31,7 @@
"vertical_gravity": "bottom", "vertical_gravity": "bottom",
"textures": { "textures": {
"normal": "resources/fire.png", "normal": "resources/fire.png",
"hover": "resources/fire2.png", "hover": "resources/fire.png",
"pressed": "resources/fire2.png", "pressed": "resources/fire2.png",
"disabled": "resources/fire_disabled.png" "disabled": "resources/fire_disabled.png"
} }
@@ -47,7 +47,7 @@
"vertical_gravity": "bottom", "vertical_gravity": "bottom",
"textures": { "textures": {
"normal": "resources/fire.png", "normal": "resources/fire.png",
"hover": "resources/fire2.png", "hover": "resources/fire.png",
"pressed": "resources/fire2.png", "pressed": "resources/fire2.png",
"disabled": "resources/fire_disabled.png" "disabled": "resources/fire_disabled.png"
} }
@@ -65,7 +65,8 @@
"textures": { "textures": {
"normal": "resources/button_minus.png", "normal": "resources/button_minus.png",
"hover": "resources/button_minus_pressed.png", "hover": "resources/button_minus_pressed.png",
"pressed": "resources/button_minus_pressed.png" "pressed": "resources/button_minus_pressed.png",
"disabled" : "resources/button_minus_disabled.png"
} }
}, },
{ {
@@ -81,7 +82,8 @@
"textures": { "textures": {
"normal": "resources/button_plus.png", "normal": "resources/button_plus.png",
"hover": "resources/button_plus_pressed.png", "hover": "resources/button_plus_pressed.png",
"pressed": "resources/button_plus_pressed.png" "pressed": "resources/button_plus_pressed.png",
"disabled" : "resources/button_plus_disabled.png"
} }
} }
] ]
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
View File
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+2 -2
View File
@@ -13,8 +13,8 @@ namespace ZL {
int Environment::windowHeaderHeight = 0; int Environment::windowHeaderHeight = 0;
int Environment::width = 0; int Environment::width = CONST_DEFAULT_WIDTH;
int Environment::height = 0; int Environment::height = CONST_DEFAULT_HEIGHT;
float Environment::zoom = DEFAULT_ZOOM; float Environment::zoom = DEFAULT_ZOOM;
+2
View File
@@ -14,6 +14,8 @@ namespace ZL {
class Environment { class Environment {
public: public:
static constexpr int CONST_DEFAULT_WIDTH = 1280;
static constexpr int CONST_DEFAULT_HEIGHT = 720;
static int windowHeaderHeight; static int windowHeaderHeight;
static int width; static int width;
static int height; static int height;
+105 -92
View File
@@ -30,7 +30,7 @@
#include "network/LocalClient.h" #include "network/LocalClient.h"
#include "network/ClientState.h" #include "network/ClientState.h"
#include "GameConstants.h"
namespace ZL namespace ZL
{ {
@@ -41,6 +41,10 @@ namespace ZL
const char* CONST_ZIP_FILE = ""; const char* CONST_ZIP_FILE = "";
#endif #endif
float x = 0;
float y = 0;
float z = 0;
#ifdef EMSCRIPTEN #ifdef EMSCRIPTEN
Game* Game::s_instance = nullptr; Game* Game::s_instance = nullptr;
@@ -86,6 +90,8 @@ namespace ZL
//glContext = SDL_GL_CreateContext(ZL::Environment::window); //glContext = SDL_GL_CreateContext(ZL::Environment::window);
//glContext = in_glContext; //glContext = in_glContext;
Environment::width = Environment::CONST_DEFAULT_WIDTH;
Environment::height = Environment::CONST_DEFAULT_HEIGHT;
Environment::computeProjectionDimensions(); Environment::computeProjectionDimensions();
ZL::BindOpenGlFunctions(); ZL::BindOpenGlFunctions();
@@ -104,7 +110,20 @@ namespace ZL
loadingTexture = std::make_unique<Texture>(CreateTextureDataFromPng("resources/loading.png", CONST_ZIP_FILE)); loadingTexture = std::make_unique<Texture>(CreateTextureDataFromPng("resources/loading.png", CONST_ZIP_FILE));
#endif #endif
loadingMesh.data = CreateRect2D({ 0.5f, 0.5f }, { 0.5f, 0.5f }, 3); float minDimension;
float width = Environment::projectionWidth;
float height = Environment::projectionHeight;
if (width >= height)
{
minDimension = height;
}
else
{
minDimension = width;
}
loadingMesh.data = CreateRect2D({ 0.0f, 0.0f }, { minDimension*0.5f, minDimension*0.5f }, 3);
loadingMesh.RefreshVBO(); loadingMesh.RefreshVBO();
#ifdef EMSCRIPTEN #ifdef EMSCRIPTEN
@@ -146,11 +165,17 @@ namespace ZL
menuManager.setupMenu(); menuManager.setupMenu();
menuManager.onMainMenuEntered = [this]() {
if (networkClient) {
networkClient->Disconnect();
networkClient.reset();
}
};
menuManager.onSingleplayerPressed = [this](const std::string& nickname, int shipType) { menuManager.onSingleplayerPressed = [this](const std::string& nickname, int shipType) {
Environment::shipState.nickname = nickname; Environment::shipState.nickname = nickname;
Environment::shipState.shipType = shipType; Environment::shipState.shipType = shipType;
if (Environment::shipState.shipType == 1) if (Environment::shipState.shipType == 1)
{ {
menuManager.uiManager.findButton("shootButton")->state = ButtonState::Disabled; menuManager.uiManager.findButton("shootButton")->state = ButtonState::Disabled;
@@ -170,15 +195,14 @@ namespace ZL
networkClient = std::unique_ptr<INetworkClient>(localClient); networkClient = std::unique_ptr<INetworkClient>(localClient);
networkClient->Connect("", 0); networkClient->Connect("", 0);
space.resetPlayerState();
lastTickCount = 0; lastTickCount = 0;
spaceGameStarted = 1;
}; };
menuManager.onMultiplayerPressed = [this](const std::string& nickname, int shipType) { menuManager.onMultiplayerPressed = [this](const std::string& nickname, int shipType) {
Environment::shipState.nickname = nickname; Environment::shipState.nickname = nickname;
Environment::shipState.shipType = shipType; Environment::shipState.shipType = shipType;
#ifdef EMSCRIPTEN #ifdef EMSCRIPTEN
networkClient = std::make_unique<WebSocketClientEmscripten>(); networkClient = std::make_unique<WebSocketClientEmscripten>();
networkClient->Connect("localhost", 8081); networkClient->Connect("localhost", 8081);
@@ -195,12 +219,12 @@ namespace ZL
space.boxCoordsArr.clear(); space.boxCoordsArr.clear();
space.boxRenderArr.clear(); space.boxRenderArr.clear();
//space.boxLabels.clear();
space.boxAlive.clear(); space.boxAlive.clear();
space.serverBoxesApplied = false; space.serverBoxesApplied = false;
space.resetPlayerState();
connectingStartTicks = SDL_GetTicks();
lastTickCount = 0; lastTickCount = 0;
spaceGameStarted = 1;
}; };
@@ -212,21 +236,10 @@ namespace ZL
void Game::drawUI() void Game::drawUI()
{ {
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
glClear(GL_DEPTH_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT);
renderer.shaderManager.PushShader(defaultShaderName); renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0); renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
glEnable(GL_BLEND); glEnable(GL_BLEND);
menuManager.uiManager.draw(renderer); menuManager.uiManager.draw(renderer);
glDisable(GL_BLEND); glDisable(GL_BLEND);
@@ -242,17 +255,14 @@ namespace ZL
} }
void Game::drawScene() { void Game::drawScene() {
//For low quality:
glViewport(0, 0, Environment::width, Environment::height); glViewport(0, 0, Environment::width, Environment::height);
//For high quality:
//glViewport(0, 0, Environment::projectionWidth, Environment::projectionHeight);
if (!loadingCompleted) { if (!loadingCompleted) {
drawLoading(); drawLoading();
} }
else else
{ {
if (spaceGameStarted) { if (menuManager.shouldRenderSpace()) {
space.drawScene(); space.drawScene();
} }
else else
@@ -266,24 +276,17 @@ namespace ZL
void Game::drawLoading() void Game::drawLoading()
{ {
static const std::string defaultShaderName = "default";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
glClear(GL_DEPTH_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT);
renderer.shaderManager.PushShader(defaultShaderName); renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0); renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
//float width = Environment::projectionWidth; float width = Environment::projectionWidth;
//float height = Environment::projectionHeight; float height = Environment::projectionHeight;
renderer.PushProjectionMatrix( renderer.PushProjectionMatrix(
0, 1, -width * 0.5f, width*0.5f,
0, 1, -height * 0.5f, height * 0.5f,
-10, 10); -10, 10);
renderer.PushMatrix(); renderer.PushMatrix();
@@ -294,9 +297,6 @@ namespace ZL
renderer.PopMatrix(); renderer.PopMatrix();
renderer.PopProjectionMatrix(); renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
CheckGlError(); CheckGlError();
} }
@@ -336,7 +336,7 @@ namespace ZL
//throw std::runtime_error("Synchronization is lost"); //throw std::runtime_error("Synchronization is lost");
} }
if (spaceGameStarted) { if (menuManager.shouldRenderSpace()) {
space.processTickCount(newTickCount, delta); space.processTickCount(newTickCount, delta);
} }
menuManager.uiManager.update(static_cast<float>(delta)); menuManager.uiManager.update(static_cast<float>(delta));
@@ -348,11 +348,13 @@ namespace ZL
//SDL_GL_MakeCurrent(ZL::Environment::window, glContext); //SDL_GL_MakeCurrent(ZL::Environment::window, glContext);
ZL::CheckGlError(); ZL::CheckGlError();
glClearColor(0.0f, 0.0f, 1.0f, 1.0f); glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//processTickCount();
drawScene(); drawScene();
processTickCount(); processTickCount();
//std::this_thread::sleep_for(std::chrono::milliseconds(50));
SDL_GL_SwapWindow(ZL::Environment::window); SDL_GL_SwapWindow(ZL::Environment::window);
} }
@@ -386,51 +388,55 @@ namespace ZL
if (event.type == SDL_FINGERDOWN) { if (event.type == SDL_FINGERDOWN) {
int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth); int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth);
int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight); int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight);
handleDown(mx, my); handleDown(static_cast<int64_t>(event.tfinger.fingerId), mx, my);
} }
else if (event.type == SDL_FINGERUP) { else if (event.type == SDL_FINGERUP) {
int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth); int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth);
int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight); int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight);
handleUp(mx, my); handleUp(static_cast<int64_t>(event.tfinger.fingerId), mx, my);
} }
else if (event.type == SDL_FINGERMOTION) { else if (event.type == SDL_FINGERMOTION) {
int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth); int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth);
int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight); int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight);
handleMotion(mx, my); handleMotion(static_cast<int64_t>(event.tfinger.fingerId), mx, my);
} }
#else #else
// Emscripten on mobile browser: handle real touch events with per-finger IDs.
// SDL_HINT_TOUCH_MOUSE_EVENTS="0" is set in main.cpp so these don't
// also fire SDL_MOUSEBUTTONDOWN, preventing double-processing.
#ifdef EMSCRIPTEN
if (event.type == SDL_FINGERDOWN) {
int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth);
int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight);
handleDown(static_cast<int64_t>(event.tfinger.fingerId), mx, my);
}
else if (event.type == SDL_FINGERUP) {
int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth);
int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight);
handleUp(static_cast<int64_t>(event.tfinger.fingerId), mx, my);
}
else if (event.type == SDL_FINGERMOTION) {
int mx = static_cast<int>(event.tfinger.x * Environment::projectionWidth);
int my = static_cast<int>(event.tfinger.y * Environment::projectionHeight);
handleMotion(static_cast<int64_t>(event.tfinger.fingerId), mx, my);
}
#endif
if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) { if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP) {
// Преобразуем экранные пиксели в проекционные единицы // Преобразуем экранные пиксели в проекционные единицы
int mx = static_cast<int>((float)event.button.x / Environment::width * Environment::projectionWidth); int mx = static_cast<int>((float)event.button.x / Environment::width * Environment::projectionWidth);
int my = static_cast<int>((float)event.button.y / Environment::height * Environment::projectionHeight); int my = static_cast<int>((float)event.button.y / Environment::height * Environment::projectionHeight);
if (event.type == SDL_MOUSEBUTTONDOWN) handleDown(mx, my); if (event.type == SDL_MOUSEBUTTONDOWN) handleDown(ZL::UiManager::MOUSE_FINGER_ID, mx, my);
else handleUp(mx, my); else handleUp(ZL::UiManager::MOUSE_FINGER_ID, mx, my);
//std::cout << "Mouse button " << (event.type == SDL_MOUSEBUTTONDOWN ? "down" : "up") << ": x=" << mx << " y=" << my << std::endl;
} }
else if (event.type == SDL_MOUSEMOTION) { else if (event.type == SDL_MOUSEMOTION) {
int mx = static_cast<int>((float)event.motion.x / Environment::width * Environment::projectionWidth); int mx = static_cast<int>((float)event.motion.x / Environment::width * Environment::projectionWidth);
int my = static_cast<int>((float)event.motion.y / Environment::height * Environment::projectionHeight); int my = static_cast<int>((float)event.motion.y / Environment::height * Environment::projectionHeight);
handleMotion(mx, my); handleMotion(ZL::UiManager::MOUSE_FINGER_ID, mx, my);
} }
/*if (event.type == SDL_MOUSEBUTTONDOWN) {
int mx = event.button.x;
int my = event.button.y;
handleDown(mx, my);
}
if (event.type == SDL_MOUSEBUTTONUP) {
int mx = event.button.x;
int my = event.button.y;
handleUp(mx, my);
}
if (event.type == SDL_MOUSEMOTION) {
int mx = event.motion.x;
int my = event.motion.y;
handleMotion(mx, my);
}*/
if (event.type == SDL_MOUSEWHEEL) { if (event.type == SDL_MOUSEWHEEL) {
static const float zoomstep = 2.0f; static const float zoomstep = 2.0f;
if (event.wheel.y > 0) { if (event.wheel.y > 0) {
@@ -459,8 +465,8 @@ namespace ZL
} }
if (event.type == SDL_KEYUP) { if (event.type == SDL_KEYUP) {
if (event.key.keysym.sym == SDLK_a) { if (event.key.keysym.sym == SDLK_r) {
//Environment::shipState.position = { 9466.15820, 1046.00159, 18531.2090 }; std::cout << "Camera position: x=" << x << " y=" << y << " z=" << z << std::endl;
} }
} }
#endif #endif
@@ -475,6 +481,22 @@ namespace ZL
} }
//#endif //#endif
networkClient->Poll(); networkClient->Poll();
if (menuManager.getState() == GameState::Connecting) {
if (networkClient->IsConnected()) {
menuManager.notifyConnected();
// Enable/disable shoot buttons based on ship type
if (Environment::shipState.shipType == 1) {
if (auto b = menuManager.uiManager.findButton("shootButton")) b->state = ButtonState::Disabled;
if (auto b = menuManager.uiManager.findButton("shootButton2")) b->state = ButtonState::Disabled;
} else {
if (auto b = menuManager.uiManager.findButton("shootButton")) b->state = ButtonState::Normal;
if (auto b = menuManager.uiManager.findButton("shootButton2")) b->state = ButtonState::Normal;
}
} else if (SDL_GetTicks() - connectingStartTicks > CONNECTING_TIMEOUT_MS) {
menuManager.notifyConnectionFailed();
}
}
#ifdef NETWORK #ifdef NETWORK
auto* wsBase = dynamic_cast<ZL::WebSocketClientBase*>(networkClient.get()); auto* wsBase = dynamic_cast<ZL::WebSocketClientBase*>(networkClient.get());
if (wsBase) { if (wsBase) {
@@ -503,67 +525,58 @@ namespace ZL
} }
mainThreadHandler.processMainThreadTasks(); mainThreadHandler.processMainThreadTasks();
if (spaceGameStarted) { if (menuManager.shouldRenderSpace()) {
space.update(); space.update();
} }
} }
void Game::handleDown(int mx, int my) void Game::handleDown(int64_t fingerId, int mx, int my)
{ {
int uiX = mx; int uiX = mx;
int uiY = Environment::projectionHeight - my; int uiY = Environment::projectionHeight - my;
menuManager.uiManager.onMouseDown(uiX, uiY); menuManager.uiManager.onTouchDown(fingerId, uiX, uiY);
bool uiHandled = false; if (!menuManager.uiManager.isUiInteractionForFinger(fingerId)) {
if (menuManager.shouldRenderSpace()) {
for (const auto& button : menuManager.uiManager.findButton("") ? std::vector<std::shared_ptr<UiButton>>{} : std::vector<std::shared_ptr<UiButton>>{}) {
(void)button;
}
auto pressedSlider = [&]() -> std::shared_ptr<UiSlider> {
for (const auto& slider : menuManager.uiManager.findSlider("") ? std::vector<std::shared_ptr<UiSlider>>{} : std::vector<std::shared_ptr<UiSlider>>{}) {
(void)slider;
}
return nullptr;
}();
if (!menuManager.uiManager.isUiInteraction()) {
if (spaceGameStarted) {
space.handleDown(mx, my); space.handleDown(mx, my);
} }
} }
} }
void Game::handleUp(int mx, int my) void Game::handleUp(int64_t fingerId, int mx, int my)
{ {
int uiX = mx; int uiX = mx;
int uiY = Environment::projectionHeight - my; int uiY = Environment::projectionHeight - my;
menuManager.uiManager.onMouseUp(uiX, uiY); // Check BEFORE onTouchUp erases the finger from the map.
// If this finger started on a UI element, don't notify space —
// otherwise space would think the ship-control finger was released.
bool wasUiInteraction = menuManager.uiManager.isUiInteractionForFinger(fingerId);
menuManager.uiManager.onTouchUp(fingerId, uiX, uiY);
if (!menuManager.uiManager.isUiInteraction()) { if (!wasUiInteraction) {
if (spaceGameStarted) { if (menuManager.shouldRenderSpace()) {
space.handleUp(mx, my); space.handleUp(mx, my);
} }
} }
} }
void Game::handleMotion(int mx, int my) void Game::handleMotion(int64_t fingerId, int mx, int my)
{ {
int uiX = mx; int uiX = mx;
int uiY = Environment::projectionHeight - my; int uiY = Environment::projectionHeight - my;
menuManager.uiManager.onMouseMove(uiX, uiY); // Check before onTouchMove so the "started on UI" state is preserved
// regardless of what onTouchMove does internally.
bool wasUiInteraction = menuManager.uiManager.isUiInteractionForFinger(fingerId);
menuManager.uiManager.onTouchMove(fingerId, uiX, uiY);
if (!menuManager.uiManager.isUiInteraction()) { if (!wasUiInteraction) {
if (spaceGameStarted) { if (menuManager.shouldRenderSpace()) {
space.handleMotion(mx, my); space.handleMotion(mx, my);
} }
} }
} }
+6 -5
View File
@@ -13,6 +13,7 @@
#include <vector> #include <vector>
#include <string> #include <string>
#include <memory> #include <memory>
#include <cstdint>
#include <render/TextRenderer.h> #include <render/TextRenderer.h>
#include "MenuManager.h" #include "MenuManager.h"
#include "Space.h" #include "Space.h"
@@ -50,9 +51,9 @@ namespace ZL {
void drawUI(); void drawUI();
void drawUnderMainMenu(); void drawUnderMainMenu();
void drawLoading(); void drawLoading();
void handleDown(int mx, int my); void handleDown(int64_t fingerId, int mx, int my);
void handleUp(int mx, int my); void handleUp(int64_t fingerId, int mx, int my);
void handleMotion(int mx, int my); void handleMotion(int64_t fingerId, int mx, int my);
#ifdef EMSCRIPTEN #ifdef EMSCRIPTEN
static Game* s_instance; static Game* s_instance;
@@ -65,14 +66,14 @@ namespace ZL {
int64_t newTickCount; int64_t newTickCount;
int64_t lastTickCount; int64_t lastTickCount;
uint32_t connectingStartTicks = 0;
static constexpr uint32_t CONNECTING_TIMEOUT_MS = 10000;
static const size_t CONST_TIMER_INTERVAL = 10; static const size_t CONST_TIMER_INTERVAL = 10;
static const size_t CONST_MAX_TIME_INTERVAL = 1000; static const size_t CONST_MAX_TIME_INTERVAL = 1000;
MenuManager menuManager; MenuManager menuManager;
Space space; Space space;
int spaceGameStarted = 0;
}; };
+9
View File
@@ -0,0 +1,9 @@
#include "GameConstants.h"
namespace ZL
{
const std::string defaultShaderName = "default";
const std::string envShaderName = "env";
const std::string textureUniformName = "Texture";
}
+11
View File
@@ -0,0 +1,11 @@
#pragma once
#include "render/Renderer.h"
namespace ZL
{
extern const std::string defaultShaderName;
extern const std::string envShaderName;
extern const std::string textureUniformName;
}
+205 -253
View File
@@ -1,5 +1,5 @@
#include "MenuManager.h" #include "MenuManager.h"
#include <iostream>
namespace ZL { namespace ZL {
@@ -10,294 +10,246 @@ namespace ZL {
void MenuManager::setupMenu() void MenuManager::setupMenu()
{ {
mainMenuRoot = loadUiFromFile("resources/config/main_menu.json", renderer, CONST_ZIP_FILE);
shipSelectionRoot = loadUiFromFile("resources/config/ship_selection_menu.json", renderer, CONST_ZIP_FILE);
connectingRoot = loadUiFromFile("resources/config/connecting.json", renderer, CONST_ZIP_FILE);
connectionFailedRoot= loadUiFromFile("resources/config/connection_failed.json", renderer, CONST_ZIP_FILE);
gameplayRoot = loadUiFromFile("resources/config/ui.json", renderer, CONST_ZIP_FILE);
gameOverRoot = loadUiFromFile("resources/config/game_over.json", renderer, CONST_ZIP_FILE);
connectionLostRoot = loadUiFromFile("resources/config/connection_lost.json", renderer, CONST_ZIP_FILE);
uiManager.loadFromFile("resources/config/main_menu.json", renderer, CONST_ZIP_FILE); enterMainMenu();
}
uiSavedRoot = loadUiFromFile("resources/config/ui.json", renderer, CONST_ZIP_FILE); bool MenuManager::shouldRenderSpace() const
{
return state == GameState::Gameplay
|| state == GameState::GameOver
|| state == GameState::ConnectionLost;
}
settingsSavedRoot = loadUiFromFile("resources/config/settings.json", renderer, CONST_ZIP_FILE); // ── State: MainMenu ──────────────────────────────────────────────────────
multiplayerSavedRoot = loadUiFromFile("resources/config/multiplayer_menu.json", renderer, CONST_ZIP_FILE); void MenuManager::enterMainMenu()
{
state = GameState::MainMenu;
uiManager.replaceRoot(mainMenuRoot);
gameOverSavedRoot = loadUiFromFile("resources/config/game_over.json", renderer, CONST_ZIP_FILE); if (onMainMenuEntered) onMainMenuEntered();
uiManager.setButtonCallback("singleButton", [this](const std::string&) {
enterShipSelectionSingle();
});
uiManager.setButtonCallback("multiplayerButton", [this](const std::string&) {
enterShipSelectionMulti();
});
}
// ── State: ShipSelectionSingle ───────────────────────────────────────────
void MenuManager::enterShipSelectionSingle()
{
state = GameState::ShipSelectionSingle;
uiManager.replaceRoot(shipSelectionRoot);
uiManager.setButtonCallback("spaceshipButton", [this](const std::string&) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
enterGameplay();
if (onSingleplayerPressed) onSingleplayerPressed(nick, 0);
});
uiManager.setButtonCallback("cargoshipButton", [this](const std::string&) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
enterGameplay();
if (onSingleplayerPressed) onSingleplayerPressed(nick, 1);
});
uiManager.setButtonCallback("backButton", [this](const std::string&) {
enterMainMenu();
});
}
// ── State: ShipSelectionMulti ─────────────────────────────────────────────
void MenuManager::enterShipSelectionMulti()
{
state = GameState::ShipSelectionMulti;
uiManager.replaceRoot(shipSelectionRoot);
uiManager.setButtonCallback("spaceshipButton", [this](const std::string&) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
pendingMultiNick = nick;
pendingMultiShipType = 0;
enterConnecting();
if (onMultiplayerPressed) onMultiplayerPressed(nick, 0);
});
uiManager.setButtonCallback("cargoshipButton", [this](const std::string&) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
pendingMultiNick = nick;
pendingMultiShipType = 1;
enterConnecting();
if (onMultiplayerPressed) onMultiplayerPressed(nick, 1);
});
uiManager.setButtonCallback("backButton", [this](const std::string&) {
enterMainMenu();
});
}
// ── State: Connecting ────────────────────────────────────────────────────
void MenuManager::enterConnecting()
{
state = GameState::Connecting;
uiManager.replaceRoot(connectingRoot);
// No interactive elements — just a static "Connecting..." image
}
// ── State: ConnectionFailed ───────────────────────────────────────────────
void MenuManager::enterConnectionFailed()
{
state = GameState::ConnectionFailed;
uiManager.replaceRoot(connectionFailedRoot);
uiManager.setButtonCallback("connectionFailedReconnectButton", [this](const std::string&) {
enterConnecting();
if (onMultiplayerPressed) onMultiplayerPressed(pendingMultiNick, pendingMultiShipType);
});
uiManager.setButtonCallback("connectionFailedGoBack", [this](const std::string&) {
enterMainMenu();
});
}
// ── State: Gameplay ──────────────────────────────────────────────────────
void MenuManager::enterGameplay()
{
state = GameState::Gameplay;
uiManager.replaceRoot(gameplayRoot);
uiManager.findButton("minusButton")->state = ButtonState::Disabled;
auto shipSelectionRoot = loadUiFromFile("resources/config/ship_selection_menu.json", renderer, CONST_ZIP_FILE);
std::function<void()> loadGameplayUI;
loadGameplayUI = [this]() {
uiManager.replaceRoot(uiSavedRoot);
auto velocityTv = uiManager.findTextView("velocityText"); auto velocityTv = uiManager.findTextView("velocityText");
if (velocityTv) { if (velocityTv) {
velocityTv->rect.x = 10.0f; velocityTv->rect.x = 10.0f;
velocityTv->rect.y = static_cast<float>(Environment::height) - velocityTv->rect.h - 10.0f; velocityTv->rect.y = static_cast<float>(Environment::height) - velocityTv->rect.h - 10.0f;
} }
else {
std::cerr << "Failed to find velocityText in UI" << std::endl;
}
uiManager.startAnimationOnNode("backgroundNode", "bgScroll"); //uiManager.startAnimationOnNode("backgroundNode", "bgScroll");
static bool isExitButtonAnimating = false;
uiManager.setAnimationCallback("settingsButton", "buttonsExit", [this]() {
std::cerr << "Settings button animation finished -> ??????? ? ?????????" << std::endl;
if (uiManager.pushMenuFromSavedRoot(settingsSavedRoot)) {
uiManager.setButtonCallback("Opt1", [this](const std::string& n) {
std::cerr << "Opt1 pressed: " << n << std::endl;
});
uiManager.setButtonCallback("Opt2", [this](const std::string& n) {
std::cerr << "Opt2 pressed: " << n << std::endl;
});
uiManager.setButtonCallback("backButton", [this](const std::string& n) {
uiManager.stopAllAnimations();
uiManager.popMenu();
});
}
else {
std::cerr << "Failed to open settings menu after animations" << std::endl;
}
});
uiManager.setAnimationCallback("exitButton", "bgScroll", [this]() { uiManager.setButtonPressCallback("shootButton", [this](const std::string&) {
std::cerr << "Exit button bgScroll animation finished" << std::endl; if (onFirePressed) onFirePressed();
g_exitBgAnimating = false;
}); });
uiManager.setButtonPressCallback("shootButton2", [this](const std::string&) {
uiManager.setButtonCallback("playButton", [this](const std::string& name) { if (onFirePressed) onFirePressed();
std::cerr << "Play button pressed: " << name << std::endl;
}); });
uiManager.setButtonPressCallback("plusButton", [this](const std::string&) {
uiManager.setButtonCallback("settingsButton", [this](const std::string& name) {
std::cerr << "Settings button pressed: " << name << std::endl;
uiManager.startAnimationOnNode("playButton", "buttonsExit");
uiManager.startAnimationOnNode("settingsButton", "buttonsExit");
uiManager.startAnimationOnNode("exitButton", "buttonsExit");
});
uiManager.setButtonCallback("exitButton", [this](const std::string& name) {
std::cerr << "Exit button pressed: " << name << std::endl;
if (!g_exitBgAnimating) {
std::cerr << "start repeat anim bgScroll on exitButton" << std::endl;
g_exitBgAnimating = true;
uiManager.startAnimationOnNode("exitButton", "bgScroll");
}
else {
std::cerr << "stop repeat anim bgScroll on exitButton" << std::endl;
g_exitBgAnimating = false;
uiManager.stopAnimationOnNode("exitButton", "bgScroll");
auto exitButton = uiManager.findButton("exitButton");
if (exitButton) {
exitButton->animOffsetX = 0.0f;
exitButton->animOffsetY = 0.0f;
exitButton->animScaleX = 1.0f;
exitButton->animScaleY = 1.0f;
exitButton->buildMesh();
}
}
});
uiManager.setButtonCallback("shootButton", [this](const std::string& name) {
onFirePressed();
});
uiManager.setButtonCallback("shootButton2", [this](const std::string& name) {
onFirePressed();
});
uiManager.setButtonCallback("plusButton", [this](const std::string& name) {
int newVel = Environment::shipState.selectedVelocity + 1; int newVel = Environment::shipState.selectedVelocity + 1;
if (newVel > 4) if (newVel > 4) newVel = 4;
uiManager.findButton("minusButton")->state = ButtonState::Normal;
if (newVel == 4)
{ {
newVel = 4; uiManager.findButton("plusButton")->state = ButtonState::Disabled;
} }
onVelocityChanged(newVel); else
{
uiManager.findButton("plusButton")->state = ButtonState::Normal;
}
if (onVelocityChanged) onVelocityChanged(newVel);
}); });
uiManager.setButtonCallback("minusButton", [this](const std::string& name) { uiManager.setButtonPressCallback("minusButton", [this](const std::string&) {
int newVel = Environment::shipState.selectedVelocity - 1; int newVel = Environment::shipState.selectedVelocity - 1;
if (newVel < 0) if (newVel < 0) newVel = 0;
uiManager.findButton("plusButton")->state = ButtonState::Normal;
if (newVel == 0)
{ {
newVel = 0; uiManager.findButton("minusButton")->state = ButtonState::Disabled;
} }
onVelocityChanged(newVel); else
{
uiManager.findButton("minusButton")->state = ButtonState::Normal;
}
if (onVelocityChanged) onVelocityChanged(newVel);
}); });
uiManager.setSliderCallback("velocitySlider", [this](const std::string& name, float value) { uiManager.setSliderCallback("velocitySlider", [this](const std::string&, float value) {
int newVel = static_cast<int>(roundf(value * 10));
int newVel = roundf(value * 10); if (newVel > 2) newVel = 2;
if (newVel > 2)
{
newVel = 2;
}
if (newVel != Environment::shipState.selectedVelocity) { if (newVel != Environment::shipState.selectedVelocity) {
onVelocityChanged(newVel); if (onVelocityChanged) onVelocityChanged(newVel);
} }
}); });
};
uiManager.setButtonCallback("singleButton", [this, shipSelectionRoot, loadGameplayUI](const std::string& name) {
std::cerr << "Single button pressed: " << name << " -> open ship selection UI\n";
if (!shipSelectionRoot) {
std::cerr << "Failed to load ship selection UI\n";
return;
}
if (uiManager.pushMenuFromSavedRoot(shipSelectionRoot)) {
uiManager.setButtonCallback("spaceshipButton", [this, loadGameplayUI](const std::string& btnName) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
int shipType = 0;
uiManager.popMenu();
loadGameplayUI();
if (onSingleplayerPressed) onSingleplayerPressed(nick, shipType);
});
uiManager.setButtonCallback("cargoshipButton", [this, loadGameplayUI](const std::string& btnName) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
int shipType = 1;
uiManager.popMenu();
loadGameplayUI();
if (onSingleplayerPressed) onSingleplayerPressed(nick, shipType);
});
uiManager.setButtonCallback("backButton", [this](const std::string& btnName) {
uiManager.popMenu();
});
}
else {
std::cerr << "Failed to push ship selection menu\n";
}
});
uiManager.setButtonCallback("multiplayerButton", [this, shipSelectionRoot, loadGameplayUI](const std::string& name) {
std::cerr << "Multiplayer button pressed: " << name << " -> open ship selection UI\n";
if (!shipSelectionRoot) {
std::cerr << "Failed to load ship selection UI\n";
return;
}
if (uiManager.pushMenuFromSavedRoot(shipSelectionRoot)) {
uiManager.setButtonCallback("spaceshipButton", [this, loadGameplayUI](const std::string& btnName) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
int shipType = 0;
uiManager.popMenu();
loadGameplayUI();
if (onMultiplayerPressed) onMultiplayerPressed(nick, shipType);
});
uiManager.setButtonCallback("cargoshipButton", [this, loadGameplayUI](const std::string& btnName) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
int shipType = 1;
uiManager.popMenu();
loadGameplayUI();
if (onMultiplayerPressed) onMultiplayerPressed(nick, shipType);
});
uiManager.setButtonCallback("backButton", [this](const std::string& btnName) {
uiManager.popMenu();
});
}
else {
std::cerr << "Failed to push ship selection menu\n";
}
});
/*uiManager.setButtonCallback("multiplayerButton2", [this, shipSelectionRoot, loadGameplayUI](const std::string& name) {
std::cerr << "Multiplayer button pressed → opening multiplayer menu\n";
uiManager.startAnimationOnNode("playButton", "buttonsExit");
uiManager.startAnimationOnNode("settingsButton", "buttonsExit");
uiManager.startAnimationOnNode("multiplayerButton", "buttonsExit");
uiManager.startAnimationOnNode("exitButton", "buttonsExit");
if (uiManager.pushMenuFromSavedRoot(multiplayerSavedRoot)) {
uiManager.setButtonCallback("connectButton", [this](const std::string& buttonName) {
std::string serverAddress = uiManager.getTextFieldValue("serverInputField");
if (serverAddress.empty()) {
uiManager.setText("statusText", "Please enter server address");
return;
} }
uiManager.setText("statusText", "Connecting to " + serverAddress + "..."); // ── State: GameOver ──────────────────────────────────────────────────────
std::cerr << "Connecting to server: " << serverAddress << std::endl;
void MenuManager::enterGameOver(int score)
{
state = GameState::GameOver;
uiManager.replaceRoot(gameOverRoot);
uiManager.setText("scoreText", "Score: " + std::to_string(score));
uiManager.setButtonCallback("restartButton", [this](const std::string&) {
if (onRestartPressed) onRestartPressed();
enterGameplay();
}); });
uiManager.setButtonCallback("gameOverExitButton", [this](const std::string&) {
uiManager.setButtonCallback("backButton", [this](const std::string& buttonName) { enterMainMenu();
uiManager.popMenu();
});
uiManager.setTextFieldCallback("serverInputField",
[this](const std::string& fieldName, const std::string& newText) {
std::cout << "Server input field changed to: " << newText << std::endl;
});
std::cerr << "Multiplayer menu loaded successfully\n";
}
else {
std::cerr << "Failed to load multiplayer menu\n";
}
std::cerr << "Single button pressed: " << name << " -> open ship selection UI\n";
if (!shipSelectionRoot) {
std::cerr << "Failed to load ship selection UI\n";
return;
}
if (uiManager.pushMenuFromSavedRoot(shipSelectionRoot)) {
uiManager.setButtonCallback("spaceshipButton", [this, loadGameplayUI](const std::string& btnName) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
int shipType = 0;
uiManager.popMenu();
loadGameplayUI();
if (onSingleplayerPressed) onSingleplayerPressed(nick, shipType);
});
uiManager.setButtonCallback("cargoshipButton", [this, loadGameplayUI](const std::string& btnName) {
std::string nick = uiManager.getTextFieldValue("nicknameInput");
if (nick.empty()) nick = "Player";
int shipType = 1;
uiManager.popMenu();
loadGameplayUI();
if (onSingleplayerPressed) onSingleplayerPressed(nick, shipType);
});
uiManager.setButtonCallback("backButton", [this](const std::string& btnName) {
uiManager.popMenu();
}); });
} }
else {
std::cerr << "Failed to push ship selection menu\n"; // ── State: ConnectionLost ─────────────────────────────────────────────────
}
void MenuManager::enterConnectionLost()
{
state = GameState::ConnectionLost;
uiManager.replaceRoot(connectionLostRoot);
uiManager.setButtonCallback("reconnectButton", [this](const std::string&) {
// TODO: reconnect logic
}); });
uiManager.setButtonCallback("exitButton", [](const std::string& name) { uiManager.setButtonCallback("exitServerButton", [this](const std::string&) {
std::cerr << "Exit from main menu pressed: " << name << " -> exiting\n"; enterMainMenu();
Environment::exitGameLoop = true; });
});*/ }
// ── Public event API ──────────────────────────────────────────────────────
void MenuManager::notifyConnected()
{
if (state == GameState::Connecting) {
enterGameplay();
}
}
void MenuManager::notifyConnectionFailed()
{
if (state == GameState::Connecting) {
enterConnectionFailed();
}
} }
void MenuManager::showGameOver(int score) void MenuManager::showGameOver(int score)
{ {
if (!uiGameOverShown) { if (state == GameState::Gameplay) {
if (uiManager.pushMenuFromSavedRoot(gameOverSavedRoot)) { enterGameOver(score);
uiManager.setText("scoreText", std::string("Score: ") + std::to_string(score)); }
}
uiManager.setButtonCallback("restartButton", [this](const std::string& name) { void MenuManager::showConnectionLost()
uiManager.setText("scoreText", ""); {
uiGameOverShown = false; if (state == GameState::Gameplay) {
uiManager.popMenu(); enterConnectionLost();
if (onRestartPressed) onRestartPressed(); }
}); }
uiManager.setButtonCallback("gameOverExitButton", [this](const std::string& name) { } // namespace ZL
Environment::exitGameLoop = true;
});
uiGameOverShown = true;
}
else {
std::cerr << "Failed to load game_over.json\n";
}
}
}
}
+50 -16
View File
@@ -1,4 +1,4 @@
#pragma once #pragma once
#include "render/Renderer.h" #include "render/Renderer.h"
#include "Environment.h" #include "Environment.h"
#include "render/TextureManager.h" #include "render/TextureManager.h"
@@ -7,37 +7,71 @@
namespace ZL { namespace ZL {
extern const char* CONST_ZIP_FILE; extern const char* CONST_ZIP_FILE;
//extern bool g_exitBgAnimating;
class MenuManager enum class GameState {
{ MainMenu,
ShipSelectionSingle,
ShipSelectionMulti,
Connecting,
ConnectionFailed,
Gameplay,
GameOver,
ConnectionLost
};
class MenuManager {
protected: protected:
Renderer& renderer; Renderer& renderer;
std::shared_ptr<UiNode> uiSavedRoot;
std::shared_ptr<UiNode> gameOverSavedRoot; // Pre-loaded UI roots (loaded once in setupMenu)
std::shared_ptr<UiNode> settingsSavedRoot; std::shared_ptr<UiNode> mainMenuRoot;
std::shared_ptr<UiNode> multiplayerSavedRoot; std::shared_ptr<UiNode> shipSelectionRoot;
std::shared_ptr<UiNode> connectingRoot;
std::shared_ptr<UiNode> connectionFailedRoot;
std::shared_ptr<UiNode> gameplayRoot;
std::shared_ptr<UiNode> gameOverRoot;
std::shared_ptr<UiNode> connectionLostRoot;
// Stored for multiplayer retry
std::string pendingMultiNick;
int pendingMultiShipType = 0;
GameState state = GameState::MainMenu;
// State transition methods
void enterMainMenu();
void enterShipSelectionSingle();
void enterShipSelectionMulti();
void enterConnecting();
void enterConnectionFailed();
void enterGameplay();
void enterGameOver(int score);
void enterConnectionLost();
public: public:
bool uiGameOverShown = false;
bool g_exitBgAnimating = false;
UiManager uiManager; UiManager uiManager;
MenuManager(Renderer& iRenderer); MenuManager(Renderer& iRenderer);
void setupMenu(); void setupMenu();
//void showGameOver(); // Returns true for states where Space should render and run (Gameplay, GameOver, ConnectionLost)
void showGameOver(int score); bool shouldRenderSpace() const;
GameState getState() const { return state; }
// Called by game events
void showGameOver(int score);
void showConnectionLost();
void notifyConnected();
void notifyConnectionFailed();
// Callbacks set by Game/Space
std::function<void()> onMainMenuEntered;
std::function<void()> onRestartPressed; std::function<void()> onRestartPressed;
std::function<void(float)> onVelocityChanged; std::function<void(float)> onVelocityChanged;
std::function<void()> onFirePressed; std::function<void()> onFirePressed;
std::function<void(const std::string&, int)> onSingleplayerPressed; std::function<void(const std::string&, int)> onSingleplayerPressed;
std::function<void(const std::string&, int)> onMultiplayerPressed; std::function<void(const std::string&, int)> onMultiplayerPressed;
};
}; };
} // namespace ZL
+129 -140
View File
@@ -25,12 +25,16 @@
#include "network/LocalClient.h" #include "network/LocalClient.h"
#endif #endif
#include "GameConstants.h"
namespace ZL namespace ZL
{ {
extern const char* CONST_ZIP_FILE; extern const char* CONST_ZIP_FILE;
extern float x; extern float x;
extern float y;
extern float z;
Eigen::Quaternionf generateRandomQuaternion(std::mt19937& gen) Eigen::Quaternionf generateRandomQuaternion(std::mt19937& gen)
{ {
@@ -252,20 +256,32 @@ namespace ZL
Space::~Space() { Space::~Space() {
} }
void Space::setup() { void Space::resetPlayerState()
{
shipAlive = true;
menuManager.onRestartPressed = [this]() { gameOver = false;
this->shipAlive = true; showExplosion = false;
this->gameOver = false; explosionEmitter.setEmissionPoints(std::vector<Vector3f>());
this->showExplosion = false;
this->explosionEmitter.setEmissionPoints(std::vector<Vector3f>());
Environment::shipState.position = Vector3f{ 0, 0, 45000.f }; Environment::shipState.position = Vector3f{ 0, 0, 45000.f };
Environment::shipState.velocity = 0.0f; Environment::shipState.velocity = 0.0f;
Environment::shipState.selectedVelocity = 0;
Environment::shipState.rotation = Eigen::Matrix3f::Identity(); Environment::shipState.rotation = Eigen::Matrix3f::Identity();
Environment::inverseShipMatrix = Eigen::Matrix3f::Identity(); Environment::inverseShipMatrix = Eigen::Matrix3f::Identity();
Environment::zoom = DEFAULT_ZOOM; Environment::zoom = DEFAULT_ZOOM;
Environment::tapDownHold = false; Environment::tapDownHold = false;
playerScore = 0;
if (menuManager.uiManager.findButton("minusButton"))
{
menuManager.uiManager.findButton("minusButton")->state = ButtonState::Disabled;
}
}
void Space::setup() {
menuManager.onRestartPressed = [this]() {
resetPlayerState();
if (networkClient) { if (networkClient) {
try { try {
@@ -276,7 +292,6 @@ namespace ZL
std::cerr << "Client: Failed to send RESPAWN\n"; std::cerr << "Client: Failed to send RESPAWN\n";
} }
} }
this->playerScore = 0;
std::cerr << "Game restarted\n"; std::cerr << "Game restarted\n";
}; };
@@ -304,6 +319,9 @@ namespace ZL
bool cfgLoaded = sparkEmitter.loadFromJsonFile("resources/config/spark_config.json", renderer, CONST_ZIP_FILE); bool cfgLoaded = sparkEmitter.loadFromJsonFile("resources/config/spark_config.json", renderer, CONST_ZIP_FILE);
bool cfgLoaded2 = sparkEmitterCargo.loadFromJsonFile("resources/config/spark_config_cargo.json", renderer, CONST_ZIP_FILE); bool cfgLoaded2 = sparkEmitterCargo.loadFromJsonFile("resources/config/spark_config_cargo.json", renderer, CONST_ZIP_FILE);
sparkEmitter.setIsActive(false);
sparkEmitterCargo.setIsActive(false);
bool projCfgLoaded = projectileEmitter.loadFromJsonFile("resources/config/spark_projectile_config.json", renderer, CONST_ZIP_FILE); bool projCfgLoaded = projectileEmitter.loadFromJsonFile("resources/config/spark_projectile_config.json", renderer, CONST_ZIP_FILE);
bool explosionCfgLoaded = explosionEmitter.loadFromJsonFile("resources/config/explosion_config.json", renderer, CONST_ZIP_FILE); bool explosionCfgLoaded = explosionEmitter.loadFromJsonFile("resources/config/explosion_config.json", renderer, CONST_ZIP_FILE);
explosionEmitter.setEmissionPoints(std::vector<Vector3f>()); explosionEmitter.setEmissionPoints(std::vector<Vector3f>());
@@ -413,17 +431,13 @@ namespace ZL
void Space::drawCubemap(float skyPercent) void Space::drawCubemap(float skyPercent)
{ {
static const std::string defaultShaderName = "default"; static const std::string envSkyShaderName = "env_sky";
static const std::string envShaderName = "env_sky";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
static const std::string skyPercentUniformName = "skyPercent"; static const std::string skyPercentUniformName = "skyPercent";
renderer.shaderManager.PushShader(envShaderName); renderer.shaderManager.PushShader(envSkyShaderName);
renderer.RenderUniform1i(textureUniformName, 0); renderer.RenderUniform1i(textureUniformName, 0);
renderer.RenderUniform1f(skyPercentUniformName, skyPercent); renderer.RenderUniform1f(skyPercentUniformName, skyPercent);
renderer.EnableVertexAttribArray(vPositionName);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height), static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR); Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
@@ -471,24 +485,14 @@ namespace ZL
renderer.PopMatrix(); renderer.PopMatrix();
renderer.PopProjectionMatrix(); renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
CheckGlError(); CheckGlError();
} }
void Space::drawShip() void Space::drawShip()
{ {
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(defaultShaderName); renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0); renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height), static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
@@ -509,15 +513,17 @@ namespace ZL
glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID()); glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID());
renderer.DrawVertexRenderStruct(spaceship); renderer.DrawVertexRenderStruct(spaceship);
} }
drawShipSparkEmitters();
} }
renderer.PopMatrix(); renderer.PopMatrix();
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
renderer.shaderManager.PushShader("default"); renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0); renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE); glBlendFunc(GL_SRC_ALPHA, GL_ONE);
renderer.PushMatrix(); renderer.PushMatrix();
@@ -527,62 +533,29 @@ namespace ZL
renderer.TranslateMatrix(-Environment::shipState.position); renderer.TranslateMatrix(-Environment::shipState.position);
for (const auto& p : projectiles) { for (const auto& p : projectiles) {
if (p && p->isActive()) { if (p && p->isActive()) {
//p->draw(renderer);
p->projectileEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height); p->projectileEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
} }
} }
renderer.PopMatrix(); renderer.PopMatrix();
glDisable(GL_BLEND); glDisable(GL_BLEND);
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
//projectileEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
if (shipAlive) {
renderer.PushMatrix();
renderer.TranslateMatrix({ 0, 0, 16 });
renderer.TranslateMatrix({ 0, -6.f, 0 });
if (Environment::shipState.shipType == 1) {
sparkEmitterCargo.draw(renderer, Environment::zoom, Environment::width, Environment::height, false);
}
else {
sparkEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height, false);
}
renderer.PopMatrix();
}
if (showExplosion) { if (showExplosion) {
explosionEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height, false); explosionEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height, false);
} }
//glBindTexture(GL_TEXTURE_2D, basePlatformTexture->getTexID());
//renderer.DrawVertexRenderStruct(basePlatform);
glDisable(GL_BLEND); glDisable(GL_BLEND);
renderer.PopMatrix(); renderer.PopMatrix();
renderer.PopProjectionMatrix(); renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
CheckGlError(); CheckGlError();
} }
void Space::drawBoxes() void Space::drawBoxes()
{ {
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(defaultShaderName); renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0); renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height), static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR); Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
@@ -601,31 +574,23 @@ namespace ZL
renderer.RotateMatrix(boxCoordsArr[i].m); renderer.RotateMatrix(boxCoordsArr[i].m);
glBindTexture(GL_TEXTURE_2D, boxTexture->getTexID()); glBindTexture(GL_TEXTURE_2D, boxTexture->getTexID());
//glBindTexture(GL_TEXTURE_2D, rockTexture->getTexID());
renderer.DrawVertexRenderStruct(boxRenderArr[i]); renderer.DrawVertexRenderStruct(boxRenderArr[i]);
renderer.PopMatrix(); renderer.PopMatrix();
} }
renderer.PopProjectionMatrix(); renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
CheckGlError(); CheckGlError();
} }
void Space::drawScene() { void Space::drawScene() {
static const std::string defaultShaderName = "default";
static const std::string envShaderName = "env";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
glClearColor(0.0f, 1.0f, 0.0f, 1.0f); glClearColor(0.0f, 1.0f, 0.0f, 1.0f);
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
glViewport(0, 0, Environment::width, Environment::height); glViewport(0, 0, Environment::width, Environment::height);
prepareSparkEmittersForDraw();
CheckGlError(); CheckGlError();
float skyPercent = 0.0; float skyPercent = 0.0;
@@ -663,17 +628,9 @@ namespace ZL
} }
void Space::drawRemoteShips() { void Space::drawRemoteShips() {
static const std::string defaultShaderName = "default";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(defaultShaderName); renderer.shaderManager.PushShader(defaultShaderName);
renderer.RenderUniform1i(textureUniformName, 0); renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
static_cast<float>(Environment::width) / static_cast<float>(Environment::height), static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR); Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
@@ -714,7 +671,6 @@ namespace ZL
renderer.LoadIdentity(); renderer.LoadIdentity();
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
//renderer.TranslateMatrix({ 0, -6.f, 0 }); //Ship camera offset
renderer.RotateMatrix(Environment::inverseShipMatrix); renderer.RotateMatrix(Environment::inverseShipMatrix);
renderer.TranslateMatrix(-Environment::shipState.position); renderer.TranslateMatrix(-Environment::shipState.position);
@@ -736,8 +692,6 @@ namespace ZL
} }
renderer.PopProjectionMatrix(); renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
CheckGlError(); CheckGlError();
@@ -991,17 +945,11 @@ namespace ZL
renderer.PushMatrix(); renderer.PushMatrix();
renderer.LoadIdentity(); renderer.LoadIdentity();
renderer.EnableVertexAttribArray("vPosition");
renderer.EnableVertexAttribArray("vColor");
Eigen::Vector4f uColor(crosshairCfg.color.x(), crosshairCfg.color.y(), crosshairCfg.color.z(), crosshairCfg.alpha); Eigen::Vector4f uColor(crosshairCfg.color.x(), crosshairCfg.color.y(), crosshairCfg.color.z(), crosshairCfg.alpha);
renderer.RenderUniform4fv("uColor", uColor.data()); renderer.RenderUniform4fv("uColor", uColor.data());
renderer.DrawVertexRenderStruct(crosshairMesh); renderer.DrawVertexRenderStruct(crosshairMesh);
renderer.DisableVertexAttribArray("vPosition");
renderer.DisableVertexAttribArray("vColor");
renderer.PopMatrix(); renderer.PopMatrix();
renderer.PopProjectionMatrix(); renderer.PopProjectionMatrix();
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
@@ -1330,7 +1278,6 @@ namespace ZL
renderer.PushMatrix(); renderer.PushMatrix();
renderer.LoadIdentity(); renderer.LoadIdentity();
renderer.EnableVertexAttribArray("vPosition");
renderer.RenderUniform4fv("uColor", enemyColor.data()); renderer.RenderUniform4fv("uColor", enemyColor.data());
// рамки // рамки
@@ -1353,7 +1300,6 @@ namespace ZL
drawLeadRing2D(lx, ly); drawLeadRing2D(lx, ly);
} }
renderer.DisableVertexAttribArray("vPosition");
renderer.PopMatrix(); renderer.PopMatrix();
renderer.PopProjectionMatrix(); renderer.PopProjectionMatrix();
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
@@ -1439,7 +1385,6 @@ namespace ZL
renderer.PushMatrix(); renderer.PushMatrix();
renderer.LoadIdentity(); renderer.LoadIdentity();
renderer.EnableVertexAttribArray("vPosition");
renderer.RenderUniform4fv("uColor", enemyColor.data()); renderer.RenderUniform4fv("uColor", enemyColor.data());
// стрелка // стрелка
@@ -1457,7 +1402,6 @@ namespace ZL
drawLeadRing2D(lx, ly); drawLeadRing2D(lx, ly);
} }
renderer.DisableVertexAttribArray("vPosition");
renderer.PopMatrix(); renderer.PopMatrix();
renderer.PopProjectionMatrix(); renderer.PopProjectionMatrix();
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
@@ -1476,23 +1420,93 @@ namespace ZL
targetWasVisible = false; targetWasVisible = false;
} }
void Space::updateSparkEmitters(float deltaMs)
{
// Local ship
SparkEmitter* sparkEmitterPtr;
if (Environment::shipState.shipType == 1) {
sparkEmitterPtr = &sparkEmitterCargo;
static std::vector<Vector3f> emissionPoints = { Vector3f(0, 0, 0), Vector3f(0, 0, 0) };
emissionPoints[0] = Environment::shipState.position + Environment::shipState.rotation * Vector3f{ 0.0, 2.8, -6.5 + 16.0 };
emissionPoints[1] = Environment::shipState.position + Environment::shipState.rotation * Vector3f{ 0.0, 1.5, -6.5 + 16.0 };
sparkEmitterPtr->setEmissionPoints(emissionPoints);
}
else {
sparkEmitterPtr = &sparkEmitter;
static std::vector<Vector3f> emissionPoints = { Vector3f(0, 0, 0), Vector3f(0, 0, 0) };
emissionPoints[0] = Environment::shipState.position + Environment::shipState.rotation * Vector3f{ -0.9, 1.4 - 1.0, -8.5 + 16.0 };
emissionPoints[1] = Environment::shipState.position + Environment::shipState.rotation * Vector3f{ 0.9, 1.4 - 1.0, -8.5 + 16.0 };
sparkEmitterPtr->setEmissionPoints(emissionPoints);
}
sparkEmitterPtr->setIsActive(Environment::shipState.velocity > 0.1f);
sparkEmitterPtr->update(deltaMs);
// Remote ships
for (auto const& [id, playerState] : remotePlayerStates) {
if (deadRemotePlayers.count(id)) continue;
if (!remoteShipSparkEmitters.count(id)) {
remoteShipSparkEmitters.emplace(id, playerState.shipType == 1 ? sparkEmitterCargo : sparkEmitter);
}
auto& remEmitter = remoteShipSparkEmitters.at(id);
std::vector<Vector3f> remEmitPts(2);
if (playerState.shipType == 1) {
remEmitPts[0] = playerState.position + playerState.rotation * Vector3f{ 0.0f, -0.4f+2.8f, 8.4f };
remEmitPts[1] = playerState.position + playerState.rotation * Vector3f{ 0.0f, -0.4f+1.5f, 8.4f };
} else {
remEmitPts[0] = playerState.position + playerState.rotation * Vector3f{ -0.9f, -0.2,5.6 };
remEmitPts[1] = playerState.position + playerState.rotation * Vector3f{ 0.9f,-0.2,5.6 };
}
remEmitter.setEmissionPoints(remEmitPts);
remEmitter.setIsActive(playerState.velocity > 0.1f);
remEmitter.update(deltaMs);
}
}
void Space::prepareSparkEmittersForDraw()
{
sparkEmitter.prepareForDraw(true);
sparkEmitterCargo.prepareForDraw(true);
for (auto& [id, emitter] : remoteShipSparkEmitters) {
if (!deadRemotePlayers.count(id)) emitter.prepareForDraw(true);
}
explosionEmitter.prepareForDraw(false);
for (const auto& p : projectiles) {
if (p && p->isActive()) {
p->projectileEmitter.prepareForDraw(true);
}
}
}
void Space::drawShipSparkEmitters()
{
renderer.PushMatrix();
renderer.RotateMatrix(Environment::inverseShipMatrix);
renderer.TranslateMatrix(-Environment::shipState.position);
if (Environment::shipState.shipType == 1) {
sparkEmitterCargo.draw(renderer, Environment::zoom, Environment::width, Environment::height);
} else {
sparkEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
}
for (auto& [id, emitter] : remoteShipSparkEmitters) {
if (!deadRemotePlayers.count(id)) {
renderer.PushMatrix();
renderer.LoadIdentity();
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
renderer.RotateMatrix(Environment::inverseShipMatrix);
renderer.TranslateMatrix(-Environment::shipState.position);
emitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
renderer.PopMatrix();
}
}
renderer.PopMatrix();
}
void Space::processTickCount(int64_t newTickCount, int64_t delta) { void Space::processTickCount(int64_t newTickCount, int64_t delta) {
auto now_ms = newTickCount; auto now_ms = newTickCount;
SparkEmitter* sparkEmitterPtr;
if (Environment::shipState.shipType == 1) {
sparkEmitterPtr = &sparkEmitterCargo;
}
else
{
sparkEmitterPtr = &sparkEmitter;
}
sparkEmitterPtr->update(static_cast<float>(delta));
planetObject.update(static_cast<float>(delta));
if (firePressed) if (firePressed)
{ {
firePressed = false; firePressed = false;
@@ -1580,7 +1594,7 @@ namespace ZL
std::string msg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent(); std::string msg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent();
networkClient->Send(msg); networkClient->Send(msg);
std::cout << "Sending: " << msg << std::endl; //std::cout << "Sending: " << msg << std::endl;
} }
long long leftoverDelta = delta; long long leftoverDelta = delta;
@@ -1624,6 +1638,8 @@ namespace ZL
remotePlayerStates[id] = playerState; remotePlayerStates[id] = playerState;
} }
updateSparkEmitters(static_cast<float>(delta));
for (auto& p : projectiles) { for (auto& p : projectiles) {
if (p && p->isActive()) { if (p && p->isActive()) {
p->update(static_cast<float>(delta), renderer); p->update(static_cast<float>(delta), renderer);
@@ -1634,42 +1650,11 @@ namespace ZL
for (const auto& p : projectiles) { for (const auto& p : projectiles) {
if (p && p->isActive()) { if (p && p->isActive()) {
Vector3f worldPos = p->getPosition(); Vector3f worldPos = p->getPosition();
//Vector3f rel = worldPos - Environment::shipState.position; p->projectileEmitter.resetEmissionPoints({ worldPos });
//Vector3f camPos = Environment::inverseShipMatrix * rel;
p->projectileEmitter.setEmissionPoints({ worldPos });
p->projectileEmitter.emit();
p->projectileEmitter.update(static_cast<float>(delta)); p->projectileEmitter.update(static_cast<float>(delta));
} }
} }
/*
if (!projCameraPoints.empty()) {
projectileEmitter.setEmissionPoints(projCameraPoints);
projectileEmitter.emit();
}
else {
projectileEmitter.setEmissionPoints(std::vector<Vector3f>());
}*/
if (Environment::shipState.velocity > 0.1f) {
sparkEmitterPtr->setIsActive(true);
std::vector<Vector3f> shipCameraPoints;
for (const auto& lp : shipLocalEmissionPoints) {
Vector3f adjusted = lp + Vector3f{ 0.0f, -Environment::zoom * 0.03f, 0.0f };
shipCameraPoints.push_back(adjusted);
}
if (!shipCameraPoints.empty()) {
sparkEmitterPtr->setEmissionPoints(shipCameraPoints);
}
}
else
{
sparkEmitterPtr->setIsActive(false);
}
sparkEmitterPtr->update(static_cast<float>(delta));
//projectileEmitter.update(static_cast<float>(delta));
explosionEmitter.update(static_cast<float>(delta)); explosionEmitter.update(static_cast<float>(delta));
if (showExplosion) { if (showExplosion) {
@@ -1690,6 +1675,7 @@ namespace ZL
shipAlive = false; shipAlive = false;
gameOver = true; gameOver = true;
Environment::shipState.selectedVelocity = 0;
Environment::shipState.velocity = 0.0f; Environment::shipState.velocity = 0.0f;
showExplosion = true; showExplosion = true;
@@ -1780,6 +1766,8 @@ namespace ZL
} }
} }
planetObject.update(static_cast<float>(delta));
// update velocity text // update velocity text
if (shipAlive && !gameOver) { if (shipAlive && !gameOver) {
@@ -1831,7 +1819,7 @@ namespace ZL
gameOver = true; gameOver = true;
Environment::shipState.velocity = 0.0f; Environment::shipState.velocity = 0.0f;
std::cout << "Client: Lost connection to server\n"; std::cout << "Client: Lost connection to server\n";
menuManager.showGameOver(this->playerScore); menuManager.showConnectionLost();
} }
auto pending = networkClient->getPendingProjectiles(); auto pending = networkClient->getPendingProjectiles();
@@ -1927,6 +1915,7 @@ namespace ZL
for (int pid : disconnects) { for (int pid : disconnects) {
remotePlayerStates.erase(pid); remotePlayerStates.erase(pid);
deadRemotePlayers.erase(pid); deadRemotePlayers.erase(pid);
remoteShipSparkEmitters.erase(pid);
if (trackedTargetId == pid) { if (trackedTargetId == pid) {
trackedTargetId = -1; trackedTargetId = -1;
targetAcquireAnim = 0.f; targetAcquireAnim = 0.f;
+7 -1
View File
@@ -66,6 +66,7 @@ namespace ZL {
std::unique_ptr<TextRenderer> textRenderer; std::unique_ptr<TextRenderer> textRenderer;
std::unordered_map<int, ClientState> remotePlayerStates; std::unordered_map<int, ClientState> remotePlayerStates;
std::unordered_map<int, SparkEmitter> remoteShipSparkEmitters;
float newShipVelocity = 0; float newShipVelocity = 0;
@@ -98,7 +99,7 @@ namespace ZL {
float projectileCooldownMs = 500.0f; float projectileCooldownMs = 500.0f;
int64_t lastProjectileFireTime = 0; int64_t lastProjectileFireTime = 0;
int maxProjectiles = 500; int maxProjectiles = 500;
std::vector<Vector3f> shipLocalEmissionPoints; //std::vector<Vector3f> shipLocalEmissionPoints;
bool shipAlive = true; bool shipAlive = true;
@@ -141,8 +142,13 @@ namespace ZL {
void drawTargetHud(); // рисует рамку или стрелку void drawTargetHud(); // рисует рамку или стрелку
int pickTargetId() const; // ???????? ???? (????: ????????? ????? ????????? ?????) int pickTargetId() const; // ???????? ???? (????: ????????? ????? ????????? ?????)
void resetPlayerState();
void clearTextRendererCache(); void clearTextRendererCache();
void updateSparkEmitters(float deltaMs);
void prepareSparkEmittersForDraw();
void drawShipSparkEmitters();
// Crosshair HUD // Crosshair HUD
struct CrosshairConfig { struct CrosshairConfig {
bool enabled = true; bool enabled = true;
+76 -58
View File
@@ -8,6 +8,7 @@
#include "Environment.h" #include "Environment.h"
#include <stdexcept> #include <stdexcept>
#include "utils/Utils.h" #include "utils/Utils.h"
#include "GameConstants.h"
namespace ZL { namespace ZL {
@@ -29,8 +30,8 @@ namespace ZL {
: particles(copyFrom.particles), emissionPoints(copyFrom.emissionPoints), : particles(copyFrom.particles), emissionPoints(copyFrom.emissionPoints),
lastEmissionTime(copyFrom.lastEmissionTime), emissionRate(copyFrom.emissionRate), lastEmissionTime(copyFrom.lastEmissionTime), emissionRate(copyFrom.emissionRate),
isActive(copyFrom.isActive), drawPositions(copyFrom.drawPositions), isActive(copyFrom.isActive), drawPositions(copyFrom.drawPositions),
drawTexCoords(copyFrom.drawTexCoords), drawDataDirty(copyFrom.drawDataDirty), drawTexCoords(copyFrom.drawTexCoords), drawDataDirty(true),
sparkQuad(copyFrom.sparkQuad), texture(copyFrom.texture), texture(copyFrom.texture),
maxParticles(copyFrom.maxParticles), particleSize(copyFrom.particleSize), maxParticles(copyFrom.maxParticles), particleSize(copyFrom.particleSize),
biasX(copyFrom.biasX), speedRange(copyFrom.speedRange), biasX(copyFrom.biasX), speedRange(copyFrom.speedRange),
zSpeedRange(copyFrom.zSpeedRange), zSpeedRange(copyFrom.zSpeedRange),
@@ -39,6 +40,8 @@ namespace ZL {
shaderProgramName(copyFrom.shaderProgramName), shaderProgramName(copyFrom.shaderProgramName),
configured(copyFrom.configured), useWorldSpace(copyFrom.useWorldSpace) configured(copyFrom.configured), useWorldSpace(copyFrom.useWorldSpace)
{ {
// Each copy gets its own GPU buffers; only copy CPU-side data
sparkQuad.data = copyFrom.sparkQuad.data;
} }
@@ -167,6 +170,18 @@ namespace ZL {
drawDataDirty = false; drawDataDirty = false;
} }
void SparkEmitter::prepareForDraw(bool withRotation) {
if (!configured) return;
prepareDrawData(withRotation);
if (!drawPositions.empty()) {
sparkQuad.data.PositionData = drawPositions;
sparkQuad.data.TexCoordData = drawTexCoords;
sparkQuad.RefreshVBO();
}
}
void SparkEmitter::draw(Renderer& renderer, float zoom, int screenWidth, int screenHeight) void SparkEmitter::draw(Renderer& renderer, float zoom, int screenWidth, int screenHeight)
{ {
draw(renderer, zoom, screenWidth, screenHeight, true); draw(renderer, zoom, screenWidth, screenHeight, true);
@@ -185,46 +200,24 @@ namespace ZL {
throw std::runtime_error("Failed to load spark emitter config file 2!"); throw std::runtime_error("Failed to load spark emitter config file 2!");
} }
prepareDrawData(withRotation);
if (drawPositions.empty()) { if (drawPositions.empty()) {
return; return;
} }
sparkQuad.data.PositionData = drawPositions;
sparkQuad.data.TexCoordData = drawTexCoords;
sparkQuad.RefreshVBO();
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(shaderProgramName); renderer.shaderManager.PushShader(shaderProgramName);
renderer.RenderUniform1i(textureUniformName, 0); renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName); renderer.SetMatrix();
renderer.EnableVertexAttribArray(vTexCoordName);
//float aspectRatio = static_cast<float>(screenWidth) / static_cast<float>(screenHeight);
//renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, aspectRatio, Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
glBindTexture(GL_TEXTURE_2D, texture->getTexID()); glBindTexture(GL_TEXTURE_2D, texture->getTexID());
glEnable(GL_BLEND); glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE); glBlendFunc(GL_SRC_ALPHA, GL_ONE);
renderer.PushMatrix(); //renderer.PushMatrix();
//renderer.LoadIdentity();
//renderer.TranslateMatrix({ 0, 0, -1.0f * zoom });
renderer.DrawVertexRenderStruct(sparkQuad); renderer.DrawVertexRenderStruct(sparkQuad);
//renderer.PopMatrix();
renderer.PopMatrix();
//renderer.PopProjectionMatrix();
glDisable(GL_BLEND); glDisable(GL_BLEND);
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
} }
@@ -237,9 +230,19 @@ namespace ZL {
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>( auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
currentTime - lastEmissionTime).count(); currentTime - lastEmissionTime).count();
if (isActive && elapsed >= emissionRate) { if (isActive && elapsed >= static_cast<long long>(emissionRate)) {
emit(); int emitCount = static_cast<int>(elapsed / emissionRate);
lastEmissionTime = currentTime; float elapsedF = static_cast<float>(elapsed);
for (int e = 0; e < emitCount; ++e) {
// e=0 — самая старая эмиссия, e=emitCount-1 — самая свежая
float ageMs = static_cast<float>(emitCount - 1 - e) * emissionRate;
// lerpT=0 → текущая позиция (новейшая), lerpT=1 → предыдущая (самая старая)
float lerpT = (elapsedF > 0.0f) ? min(ageMs / elapsedF, 1.0f) : 0.0f;
emit(ageMs, lerpT);
}
lastEmissionTime += std::chrono::milliseconds(
static_cast<long long>(emitCount * emissionRate));
drawDataDirty = true; drawDataDirty = true;
} }
@@ -278,7 +281,7 @@ namespace ZL {
} }
} }
void SparkEmitter::emit() { void SparkEmitter::emit(float ageMs, float lerpT) {
if (!configured) { if (!configured) {
throw std::runtime_error("Failed to load spark emitter config file 4!"); throw std::runtime_error("Failed to load spark emitter config file 4!");
} }
@@ -286,7 +289,30 @@ namespace ZL {
if (emissionPoints.empty()) return; if (emissionPoints.empty()) return;
bool emitted = false; bool emitted = false;
for (int i = 0; i < emissionPoints.size(); ++i) { auto applyAge = [](SparkParticle& particle, float age) {
if (age <= 0.0f) return;
particle.position(0) += particle.velocity(0) * age / 1000.0f;
particle.position(1) += particle.velocity(1) * age / 1000.0f;
particle.position(2) += particle.velocity(2) * age / 1000.0f;
particle.lifeTime = age;
if (particle.lifeTime >= particle.maxLifeTime) {
particle.active = false;
} else {
float lifeRatio = particle.lifeTime / particle.maxLifeTime;
particle.scale = 1.0f - lifeRatio * 0.8f;
}
};
// Вычисляем стартовую позицию с интерполяцией между prev и current
// lerpT=0 → текущая позиция (новейшая эмиссия), lerpT=1 → предыдущая (самая старая)
bool canInterp = (prevEmissionPoints.size() == emissionPoints.size());
for (int i = 0; i < (int)emissionPoints.size(); ++i) {
Vector3f birthPos = emissionPoints[i];
if (canInterp && lerpT > 0.0f) {
birthPos = emissionPoints[i] * (1.0f - lerpT) + prevEmissionPoints[i] * lerpT;
}
bool particleFound = false; bool particleFound = false;
for (auto& particle : particles) { for (auto& particle : particles) {
@@ -294,8 +320,9 @@ namespace ZL {
initParticle(particle, i); initParticle(particle, i);
particle.active = true; particle.active = true;
particle.lifeTime = 0; particle.lifeTime = 0;
particle.position = emissionPoints[i]; particle.position = birthPos;
particle.emitterIndex = i; particle.emitterIndex = i;
applyAge(particle, ageMs);
particleFound = true; particleFound = true;
emitted = true; emitted = true;
break; break;
@@ -304,11 +331,11 @@ namespace ZL {
if (!particleFound && !particles.empty()) { if (!particleFound && !particles.empty()) {
size_t oldestIndex = 0; size_t oldestIndex = 0;
float maxLifeTime = 0; float maxLifeRatio = 0;
for (size_t j = 0; j < particles.size(); ++j) { for (size_t j = 0; j < particles.size(); ++j) {
if (particles[j].lifeTime > maxLifeTime) { if (particles[j].lifeTime > maxLifeRatio) {
maxLifeTime = particles[j].lifeTime; maxLifeRatio = particles[j].lifeTime;
oldestIndex = j; oldestIndex = j;
} }
} }
@@ -316,8 +343,9 @@ namespace ZL {
initParticle(particles[oldestIndex], i); initParticle(particles[oldestIndex], i);
particles[oldestIndex].active = true; particles[oldestIndex].active = true;
particles[oldestIndex].lifeTime = 0; particles[oldestIndex].lifeTime = 0;
particles[oldestIndex].position = emissionPoints[i]; particles[oldestIndex].position = birthPos;
particles[oldestIndex].emitterIndex = i; particles[oldestIndex].emitterIndex = i;
applyAge(particles[oldestIndex], ageMs);
emitted = true; emitted = true;
} }
} }
@@ -328,6 +356,14 @@ namespace ZL {
} }
void SparkEmitter::setEmissionPoints(const std::vector<Vector3f>& positions) { void SparkEmitter::setEmissionPoints(const std::vector<Vector3f>& positions) {
prevEmissionPoints = emissionPoints;
emissionPoints = positions;
drawDataDirty = true;
}
void SparkEmitter::resetEmissionPoints(const std::vector<Vector3f>& positions)
{
prevEmissionPoints.clear();
emissionPoints = positions; emissionPoints = positions;
drawDataDirty = true; drawDataDirty = true;
} }
@@ -495,8 +531,9 @@ namespace ZL {
std::cout << "Total emission points: " << emissionPoints.size() << std::endl; std::cout << "Total emission points: " << emissionPoints.size() << std::endl;
} }
else { else {
std::cerr << "Emission points parsed but empty" << std::endl; setEmissionPoints({});
throw std::runtime_error("Failed to load spark emitter config file 10!"); std::cout << "Emission points parsed but empty" << std::endl;
//throw std::runtime_error("Failed to load spark emitter config file 10!");
} }
} }
else { else {
@@ -583,25 +620,6 @@ namespace ZL {
throw std::runtime_error("Failed to load spark emitter config file 18!"); throw std::runtime_error("Failed to load spark emitter config file 18!");
} }
std::cout << "Working with shaders 2" << std::endl;
/*
if (j.contains("vertexShader") && j.contains("fragmentShader")
&& j["vertexShader"].is_string() && j["fragmentShader"].is_string()) {
std::string v = j["vertexShader"].get<std::string>();
std::string f = j["fragmentShader"].get<std::string>();
std::cout << "Loading shaders - vertex: " << v << ", fragment: " << f << std::endl;
try {
renderer.shaderManager.AddShaderFromFiles(shaderProgramName, v, f, zipFile.c_str());
std::cout << "Shaders loaded successfully" << std::endl;
}
catch (const std::exception& e) {
std::cerr << "Shader load error: " << e.what() << std::endl;
throw std::runtime_error("Failed to load spark emitter config file 19!");
}
}*/
drawDataDirty = true; drawDataDirty = true;
configured = true; configured = true;
std::cout << "SparkEmitter configuration loaded successfully!" << std::endl; std::cout << "SparkEmitter configuration loaded successfully!" << std::endl;
+6 -1
View File
@@ -26,6 +26,7 @@ namespace ZL {
private: private:
std::vector<SparkParticle> particles; std::vector<SparkParticle> particles;
std::vector<Vector3f> emissionPoints; std::vector<Vector3f> emissionPoints;
std::vector<Vector3f> prevEmissionPoints;
std::chrono::steady_clock::time_point lastEmissionTime; std::chrono::steady_clock::time_point lastEmissionTime;
float emissionRate; float emissionRate;
bool isActive; bool isActive;
@@ -62,6 +63,7 @@ namespace ZL {
float rate = 100.0f); float rate = 100.0f);
void setEmissionPoints(const std::vector<Vector3f>& positions); void setEmissionPoints(const std::vector<Vector3f>& positions);
void resetEmissionPoints(const std::vector<Vector3f>& positions);
void setTexture(std::shared_ptr<Texture> tex); void setTexture(std::shared_ptr<Texture> tex);
void setEmissionRate(float rate) { emissionRate = rate; } void setEmissionRate(float rate) { emissionRate = rate; }
void setShaderProgramName(const std::string& name) { shaderProgramName = name; } void setShaderProgramName(const std::string& name) { shaderProgramName = name; }
@@ -73,7 +75,10 @@ namespace ZL {
bool loadFromJsonFile(const std::string& path, Renderer& renderer, const std::string& zipFile = ""); bool loadFromJsonFile(const std::string& path, Renderer& renderer, const std::string& zipFile = "");
void update(float deltaTimeMs); void update(float deltaTimeMs);
void emit(); void emit(float ageMs = 0.0f, float lerpT = 0.0f);
// Вызывать ДО draw() в начале кадра: готовит данные и загружает в VBO.
void prepareForDraw(bool withRotation = true);
void draw(Renderer& renderer, float zoom, int screenWidth, int screenHeight); void draw(Renderer& renderer, float zoom, int screenWidth, int screenHeight);
void draw(Renderer& renderer, float zoom, int screenWidth, int screenHeight, bool withRotation); void draw(Renderer& renderer, float zoom, int screenWidth, int screenHeight, bool withRotation);
+135 -38
View File
@@ -4,6 +4,7 @@
#include <fstream> #include <fstream>
#include <iostream> #include <iostream>
#include <algorithm> #include <algorithm>
#include "GameConstants.h"
namespace ZL { namespace ZL {
@@ -61,23 +62,13 @@ namespace ZL {
} }
if (!(*tex)) return; if (!(*tex)) return;
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.PushMatrix(); renderer.PushMatrix();
renderer.TranslateMatrix({ animOffsetX, animOffsetY, 0.0f }); renderer.TranslateMatrix({ animOffsetX, animOffsetY, 0.0f });
renderer.ScaleMatrix({ animScaleX, animScaleY, 1.0f }); renderer.ScaleMatrix({ animScaleX, animScaleY, 1.0f });
renderer.RenderUniform1i(textureUniformName, 0); renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
glBindTexture(GL_TEXTURE_2D, (*tex)->getTexID()); glBindTexture(GL_TEXTURE_2D, (*tex)->getTexID());
renderer.DrawVertexRenderStruct(mesh); renderer.DrawVertexRenderStruct(mesh);
renderer.DisableVertexAttribArray(vPositionName);
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.PopMatrix(); renderer.PopMatrix();
} }
@@ -148,14 +139,7 @@ namespace ZL {
} }
void UiSlider::draw(Renderer& renderer) const { void UiSlider::draw(Renderer& renderer) const {
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.RenderUniform1i(textureUniformName, 0); renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
if (texTrack) { if (texTrack) {
glBindTexture(GL_TEXTURE_2D, texTrack->getTexID()); glBindTexture(GL_TEXTURE_2D, texTrack->getTexID());
renderer.DrawVertexRenderStruct(trackMesh); renderer.DrawVertexRenderStruct(trackMesh);
@@ -164,9 +148,44 @@ namespace ZL {
glBindTexture(GL_TEXTURE_2D, texKnob->getTexID()); glBindTexture(GL_TEXTURE_2D, texKnob->getTexID());
renderer.DrawVertexRenderStruct(knobMesh); renderer.DrawVertexRenderStruct(knobMesh);
} }
}
renderer.DisableVertexAttribArray(vPositionName); void UiStaticImage::buildMesh() {
renderer.DisableVertexAttribArray(vTexCoordName); mesh.data.PositionData.clear();
mesh.data.TexCoordData.clear();
float x0 = rect.x;
float y0 = rect.y;
float x1 = rect.x + rect.w;
float y1 = rect.y + rect.h;
mesh.data.PositionData.push_back({ x0, y0, 0 });
mesh.data.TexCoordData.push_back({ 0, 0 });
mesh.data.PositionData.push_back({ x0, y1, 0 });
mesh.data.TexCoordData.push_back({ 0, 1 });
mesh.data.PositionData.push_back({ x1, y1, 0 });
mesh.data.TexCoordData.push_back({ 1, 1 });
mesh.data.PositionData.push_back({ x0, y0, 0 });
mesh.data.TexCoordData.push_back({ 0, 0 });
mesh.data.PositionData.push_back({ x1, y1, 0 });
mesh.data.TexCoordData.push_back({ 1, 1 });
mesh.data.PositionData.push_back({ x1, y0, 0 });
mesh.data.TexCoordData.push_back({ 1, 0 });
mesh.RefreshVBO();
}
void UiStaticImage::draw(Renderer& renderer) const {
if (!texture) return;
renderer.RenderUniform1i(textureUniformName, 0);
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
renderer.DrawVertexRenderStruct(mesh);
} }
void UiTextField::draw(Renderer& renderer) const { void UiTextField::draw(Renderer& renderer) const {
@@ -249,6 +268,7 @@ namespace ZL {
if (j.contains("horizontal_gravity")) { if (j.contains("horizontal_gravity")) {
std::string hg = j["horizontal_gravity"].get<std::string>(); std::string hg = j["horizontal_gravity"].get<std::string>();
if (hg == "right") node->layoutSettings.hGravity = HorizontalGravity::Right; if (hg == "right") node->layoutSettings.hGravity = HorizontalGravity::Right;
else if (hg == "center") node->layoutSettings.hGravity = HorizontalGravity::Center;
else node->layoutSettings.hGravity = HorizontalGravity::Left; else node->layoutSettings.hGravity = HorizontalGravity::Left;
} }
@@ -256,6 +276,7 @@ namespace ZL {
if (j.contains("vertical_gravity")) { if (j.contains("vertical_gravity")) {
std::string vg = j["vertical_gravity"].get<std::string>(); std::string vg = j["vertical_gravity"].get<std::string>();
if (vg == "bottom") node->layoutSettings.vGravity = VerticalGravity::Bottom; if (vg == "bottom") node->layoutSettings.vGravity = VerticalGravity::Bottom;
else if (vg == "center") node->layoutSettings.vGravity = VerticalGravity::Center;
else node->layoutSettings.vGravity = VerticalGravity::Top; else node->layoutSettings.vGravity = VerticalGravity::Top;
} }
@@ -403,6 +424,32 @@ namespace ZL {
} }
} }
if (typeStr == "StaticImage") {
auto img = std::make_shared<UiStaticImage>();
img->name = node->name;
img->rect = initialRect;
std::string texPath;
if (j.contains("texture") && j["texture"].is_string()) {
texPath = j["texture"].get<std::string>();
}
else if (j.contains("textures") && j["textures"].is_object() && j["textures"].contains("normal")) {
texPath = j["textures"]["normal"].get<std::string>();
}
if (!texPath.empty()) {
try {
auto data = CreateTextureDataFromPng(texPath.c_str(), zipFile.c_str());
img->texture = std::make_shared<Texture>(data);
}
catch (const std::exception& e) {
std::cerr << "UiManager: failed load texture for StaticImage '" << img->name << "' : " << e.what() << std::endl;
}
}
node->staticImage = img;
}
if (typeStr == "TextView") { if (typeStr == "TextView") {
auto tv = std::make_shared<UiTextView>(); auto tv = std::make_shared<UiTextView>();
@@ -492,6 +539,7 @@ namespace ZL {
sliders.clear(); sliders.clear();
textViews.clear(); textViews.clear();
textFields.clear(); textFields.clear();
staticImages.clear();
collectButtonsAndSliders(root); collectButtonsAndSliders(root);
nodeActiveAnims.clear(); nodeActiveAnims.clear();
@@ -503,6 +551,9 @@ namespace ZL {
s->buildTrackMesh(); s->buildTrackMesh();
s->buildKnobMesh(); s->buildKnobMesh();
} }
for (auto& img : staticImages) {
img->buildMesh();
}
} }
void UiManager::loadFromFile(const std::string& path, Renderer& renderer, const std::string& zipFile) { void UiManager::loadFromFile(const std::string& path, Renderer& renderer, const std::string& zipFile) {
@@ -618,9 +669,15 @@ namespace ZL {
if (child->layoutSettings.hGravity == HorizontalGravity::Right) { if (child->layoutSettings.hGravity == HorizontalGravity::Right) {
fLX = currentW - childW - child->localX; fLX = currentW - childW - child->localX;
} }
else if (child->layoutSettings.hGravity == HorizontalGravity::Center) {
fLX = (currentW - childW) / 2.0f + child->localX;
}
if (child->layoutSettings.vGravity == VerticalGravity::Top) { if (child->layoutSettings.vGravity == VerticalGravity::Top) {
fLY = currentH - childH - child->localY; fLY = currentH - childH - child->localY;
} }
else if (child->layoutSettings.vGravity == VerticalGravity::Center) {
fLY = (currentH - childH) / 2.0f + child->localY;
}
// Передаем рассчитанные fLX, fLY в рекурсию // Передаем рассчитанные fLX, fLY в рекурсию
layoutNode(child, node->screenRect.x, node->screenRect.y, currentW, currentH, fLX, fLY); layoutNode(child, node->screenRect.x, node->screenRect.y, currentW, currentH, fLX, fLY);
@@ -661,6 +718,12 @@ namespace ZL {
node->textField->rect = node->screenRect; node->textField->rect = node->screenRect;
// Аналогично для курсора и фонового меша // Аналогично для курсора и фонового меша
} }
// 5. Обновляем статическое изображение
if (node->staticImage) {
node->staticImage->rect = node->screenRect;
node->staticImage->buildMesh();
}
} }
void UiManager::updateAllLayouts() { void UiManager::updateAllLayouts() {
@@ -690,6 +753,9 @@ namespace ZL {
if (node->textField) { if (node->textField) {
textFields.push_back(node->textField); textFields.push_back(node->textField);
} }
if (node->staticImage) {
staticImages.push_back(node->staticImage);
}
for (auto& c : node->children) collectButtonsAndSliders(c); for (auto& c : node->children) collectButtonsAndSliders(c);
} }
@@ -703,6 +769,16 @@ namespace ZL {
return true; return true;
} }
bool UiManager::setButtonPressCallback(const std::string& name, std::function<void(const std::string&)> cb) {
auto b = findButton(name);
if (!b) {
std::cerr << "UiManager: setButtonPressCallback failed, button not found: " << name << std::endl;
return false;
}
b->onPress = std::move(cb);
return true;
}
bool UiManager::addSlider(const std::string& name, const UiRect& rect, Renderer& renderer, const std::string& zipFile, bool UiManager::addSlider(const std::string& name, const UiRect& rect, Renderer& renderer, const std::string& zipFile,
const std::string& trackPath, const std::string& knobPath, float initialValue, bool vertical) { const std::string& trackPath, const std::string& knobPath, float initialValue, bool vertical) {
@@ -788,8 +864,9 @@ namespace ZL {
prev.buttons = buttons; prev.buttons = buttons;
prev.sliders = sliders; prev.sliders = sliders;
prev.textFields = textFields; prev.textFields = textFields;
prev.pressedButton = pressedButton; prev.staticImages = staticImages;
prev.pressedSlider = pressedSlider; prev.pressedButtons = pressedButtons;
prev.pressedSliders = pressedSliders;
prev.focusedTextField = focusedTextField; prev.focusedTextField = focusedTextField;
prev.path = ""; prev.path = "";
@@ -838,8 +915,9 @@ namespace ZL {
buttons = s.buttons; buttons = s.buttons;
sliders = s.sliders; sliders = s.sliders;
textFields = s.textFields; textFields = s.textFields;
pressedButton = s.pressedButton; staticImages = s.staticImages;
pressedSlider = s.pressedSlider; pressedButtons = s.pressedButtons;
pressedSliders = s.pressedSliders;
focusedTextField = s.focusedTextField; focusedTextField = s.focusedTextField;
animCallbacks = s.animCallbacks; animCallbacks = s.animCallbacks;
@@ -872,6 +950,9 @@ namespace ZL {
renderer.PushMatrix(); renderer.PushMatrix();
renderer.LoadIdentity(); renderer.LoadIdentity();
for (const auto& img : staticImages) {
img->draw(renderer);
}
for (const auto& b : buttons) { for (const auto& b : buttons) {
b->draw(renderer); b->draw(renderer);
} }
@@ -1051,7 +1132,9 @@ namespace ZL {
} }
} }
void UiManager::onMouseMove(int x, int y) { void UiManager::onTouchMove(int64_t fingerId, int x, int y) {
// Hover state updates only make sense for mouse (single pointer)
if (fingerId == MOUSE_FINGER_ID) {
for (auto& b : buttons) { for (auto& b : buttons) {
if (b->state != ButtonState::Disabled) if (b->state != ButtonState::Disabled)
{ {
@@ -1063,9 +1146,11 @@ namespace ZL {
} }
} }
} }
}
if (pressedSlider) { auto it = pressedSliders.find(fingerId);
auto s = pressedSlider; if (it != pressedSliders.end()) {
auto s = it->second;
float t; float t;
if (s->vertical) { if (s->vertical) {
t = (y - s->rect.y) / s->rect.h; t = (y - s->rect.y) / s->rect.h;
@@ -1082,20 +1167,22 @@ namespace ZL {
} }
void UiManager::onMouseDown(int x, int y) { void UiManager::onTouchDown(int64_t fingerId, int x, int y) {
for (auto& b : buttons) { for (auto& b : buttons) {
if (b->state != ButtonState::Disabled) if (b->state != ButtonState::Disabled)
{ {
if (b->rect.containsConsideringBorder((float)x, (float)y, b->border)) { if (b->rect.containsConsideringBorder((float)x, (float)y, b->border)) {
b->state = ButtonState::Pressed; b->state = ButtonState::Pressed;
pressedButton = b; pressedButtons[fingerId] = b;
if (b->onPress) b->onPress(b->name);
break; // a single finger can only press one button
} }
} }
} }
for (auto& s : sliders) { for (auto& s : sliders) {
if (s->rect.contains((float)x, (float)y)) { if (s->rect.contains((float)x, (float)y)) {
pressedSlider = s; pressedSliders[fingerId] = s;
float t; float t;
if (s->vertical) { if (s->vertical) {
t = (y - s->rect.y) / s->rect.h; t = (y - s->rect.y) / s->rect.h;
@@ -1123,29 +1210,32 @@ namespace ZL {
} }
} }
void UiManager::onMouseUp(int x, int y) { void UiManager::onTouchUp(int64_t fingerId, int x, int y) {
std::vector<std::shared_ptr<UiButton>> clicked; std::vector<std::shared_ptr<UiButton>> clicked;
for (auto& b : buttons) { auto btnIt = pressedButtons.find(fingerId);
if (!b) continue; if (btnIt != pressedButtons.end()) {
auto b = btnIt->second;
if (b) {
bool contains = b->rect.contains((float)x, (float)y); bool contains = b->rect.contains((float)x, (float)y);
if (b->state == ButtonState::Pressed) { if (b->state == ButtonState::Pressed) {
if (contains && pressedButton == b) { if (contains) {
clicked.push_back(b); clicked.push_back(b);
} }
b->state = contains ? ButtonState::Hover : ButtonState::Normal; // On mouse: leave Hover if still over button. On touch: always Normal.
b->state = (contains && fingerId == MOUSE_FINGER_ID) ? ButtonState::Hover : ButtonState::Normal;
} }
} }
pressedButtons.erase(btnIt);
}
pressedSliders.erase(fingerId);
for (auto& b : clicked) { for (auto& b : clicked) {
if (b->onClick) { if (b->onClick) {
b->onClick(b->name); b->onClick(b->name);
} }
} }
pressedButton.reset();
if (pressedSlider) pressedSlider.reset();
} }
void UiManager::onKeyPress(unsigned char key) { void UiManager::onKeyPress(unsigned char key) {
@@ -1261,6 +1351,13 @@ namespace ZL {
return true; return true;
} }
std::shared_ptr<UiStaticImage> UiManager::findStaticImage(const std::string& name) {
for (auto& img : staticImages) {
if (img->name == name) return img;
}
return nullptr;
}
std::shared_ptr<UiTextView> UiManager::findTextView(const std::string& name) { std::shared_ptr<UiTextView> UiManager::findTextView(const std::string& name) {
for (auto& tv : textViews) { for (auto& tv : textViews) {
if (tv->name == name) return tv; if (tv->name == name) return tv;
+46 -8
View File
@@ -10,6 +10,7 @@
#include <memory> #include <memory>
#include <functional> #include <functional>
#include <map> #include <map>
#include <cstdint>
namespace ZL { namespace ZL {
@@ -60,11 +61,13 @@ namespace ZL {
enum class HorizontalGravity { enum class HorizontalGravity {
Left, Left,
Center,
Right Right
}; };
enum class VerticalGravity { enum class VerticalGravity {
Bottom, // Обычно в OpenGL Y растет вверх, так что низ - это 0 Bottom, // Обычно в OpenGL Y растет вверх, так что низ - это 0
Center,
Top Top
}; };
@@ -91,6 +94,7 @@ namespace ZL {
VertexRenderStruct mesh; VertexRenderStruct mesh;
std::function<void(const std::string&)> onClick; std::function<void(const std::string&)> onClick;
std::function<void(const std::string&)> onPress; // fires on touch/mouse down
// animation runtime // animation runtime
float animOffsetX = 0.0f; float animOffsetX = 0.0f;
@@ -159,6 +163,17 @@ namespace ZL {
void draw(Renderer& renderer) const; void draw(Renderer& renderer) const;
}; };
struct UiStaticImage {
std::string name;
UiRect rect;
std::shared_ptr<Texture> texture;
VertexRenderStruct mesh;
void buildMesh();
void draw(Renderer& renderer) const;
};
struct UiNode { struct UiNode {
std::string name; std::string name;
LayoutType layoutType = LayoutType::Frame; LayoutType layoutType = LayoutType::Frame;
@@ -185,6 +200,7 @@ namespace ZL {
std::shared_ptr<UiSlider> slider; std::shared_ptr<UiSlider> slider;
std::shared_ptr<UiTextView> textView; std::shared_ptr<UiTextView> textView;
std::shared_ptr<UiTextField> textField; std::shared_ptr<UiTextField> textField;
std::shared_ptr<UiStaticImage> staticImage;
// Анимации // Анимации
struct AnimStep { struct AnimStep {
@@ -210,19 +226,35 @@ namespace ZL {
public: public:
UiManager() = default; UiManager() = default;
// Sentinel finger ID used for mouse events on desktop/web
static constexpr int64_t MOUSE_FINGER_ID = -1LL;
void replaceRoot(std::shared_ptr<UiNode> newRoot); void replaceRoot(std::shared_ptr<UiNode> newRoot);
void loadFromFile(const std::string& path, Renderer& renderer, const std::string& zipFile = ""); void loadFromFile(const std::string& path, Renderer& renderer, const std::string& zipFile = "");
void draw(Renderer& renderer); void draw(Renderer& renderer);
void onMouseMove(int x, int y); // Multi-touch methods (used directly for touch events with per-finger IDs)
void onMouseDown(int x, int y); void onTouchDown(int64_t fingerId, int x, int y);
void onMouseUp(int x, int y); void onTouchUp(int64_t fingerId, int x, int y);
void onTouchMove(int64_t fingerId, int x, int y);
// Mouse convenience wrappers (delegate to touch with MOUSE_FINGER_ID)
void onMouseMove(int x, int y) { onTouchMove(MOUSE_FINGER_ID, x, y); }
void onMouseDown(int x, int y) { onTouchDown(MOUSE_FINGER_ID, x, y); }
void onMouseUp(int x, int y) { onTouchUp(MOUSE_FINGER_ID, x, y); }
void onKeyPress(unsigned char key); void onKeyPress(unsigned char key);
void onKeyBackspace(); void onKeyBackspace();
// Returns true if any finger is currently interacting with UI
bool isUiInteraction() const { bool isUiInteraction() const {
return pressedButton != nullptr || pressedSlider != nullptr || focusedTextField != nullptr; return !pressedButtons.empty() || !pressedSliders.empty() || focusedTextField != nullptr;
}
// Returns true if this specific finger is currently interacting with UI
bool isUiInteractionForFinger(int64_t fingerId) const {
return pressedButtons.count(fingerId) > 0 || pressedSliders.count(fingerId) > 0 || focusedTextField != nullptr;
} }
void stopAllAnimations() { void stopAllAnimations() {
@@ -241,6 +273,7 @@ namespace ZL {
std::shared_ptr<UiButton> findButton(const std::string& name); std::shared_ptr<UiButton> findButton(const std::string& name);
bool setButtonCallback(const std::string& name, std::function<void(const std::string&)> cb); bool setButtonCallback(const std::string& name, std::function<void(const std::string&)> cb);
bool setButtonPressCallback(const std::string& name, std::function<void(const std::string&)> cb);
bool addSlider(const std::string& name, const UiRect& rect, Renderer& renderer, const std::string& zipFile, bool addSlider(const std::string& name, const UiRect& rect, Renderer& renderer, const std::string& zipFile,
const std::string& trackPath, const std::string& knobPath, float initialValue = 0.0f, bool vertical = true); const std::string& trackPath, const std::string& knobPath, float initialValue = 0.0f, bool vertical = true);
@@ -256,6 +289,8 @@ namespace ZL {
bool setTextFieldCallback(const std::string& name, std::function<void(const std::string&, const std::string&)> cb); bool setTextFieldCallback(const std::string& name, std::function<void(const std::string&, const std::string&)> cb);
std::string getTextFieldValue(const std::string& name); std::string getTextFieldValue(const std::string& name);
std::shared_ptr<UiStaticImage> findStaticImage(const std::string& name);
bool pushMenuFromFile(const std::string& path, Renderer& renderer, const std::string& zipFile = ""); bool pushMenuFromFile(const std::string& path, Renderer& renderer, const std::string& zipFile = "");
bool pushMenuFromSavedRoot(std::shared_ptr<UiNode> newRoot); bool pushMenuFromSavedRoot(std::shared_ptr<UiNode> newRoot);
bool popMenu(); bool popMenu();
@@ -301,12 +336,14 @@ namespace ZL {
std::vector<std::shared_ptr<UiSlider>> sliders; std::vector<std::shared_ptr<UiSlider>> sliders;
std::vector<std::shared_ptr<UiTextView>> textViews; std::vector<std::shared_ptr<UiTextView>> textViews;
std::vector<std::shared_ptr<UiTextField>> textFields; std::vector<std::shared_ptr<UiTextField>> textFields;
std::vector<std::shared_ptr<UiStaticImage>> staticImages;
std::map<std::shared_ptr<UiNode>, std::vector<ActiveAnim>> nodeActiveAnims; std::map<std::shared_ptr<UiNode>, std::vector<ActiveAnim>> nodeActiveAnims;
std::map<std::pair<std::string, std::string>, std::function<void()>> animCallbacks; // key: (nodeName, animName) std::map<std::pair<std::string, std::string>, std::function<void()>> animCallbacks; // key: (nodeName, animName)
std::shared_ptr<UiButton> pressedButton; // Per-finger tracking for multi-touch support
std::shared_ptr<UiSlider> pressedSlider; std::map<int64_t, std::shared_ptr<UiButton>> pressedButtons;
std::map<int64_t, std::shared_ptr<UiSlider>> pressedSliders;
std::shared_ptr<UiTextField> focusedTextField; std::shared_ptr<UiTextField> focusedTextField;
struct MenuState { struct MenuState {
@@ -314,8 +351,9 @@ namespace ZL {
std::vector<std::shared_ptr<UiButton>> buttons; std::vector<std::shared_ptr<UiButton>> buttons;
std::vector<std::shared_ptr<UiSlider>> sliders; std::vector<std::shared_ptr<UiSlider>> sliders;
std::vector<std::shared_ptr<UiTextField>> textFields; std::vector<std::shared_ptr<UiTextField>> textFields;
std::shared_ptr<UiButton> pressedButton; std::vector<std::shared_ptr<UiStaticImage>> staticImages;
std::shared_ptr<UiSlider> pressedSlider; std::map<int64_t, std::shared_ptr<UiButton>> pressedButtons;
std::map<int64_t, std::shared_ptr<UiSlider>> pressedSliders;
std::shared_ptr<UiTextField> focusedTextField; std::shared_ptr<UiTextField> focusedTextField;
std::string path; std::string path;
std::map<std::pair<std::string, std::string>, std::function<void()>> animCallbacks; std::map<std::pair<std::string, std::string>, std::function<void()>> animCallbacks;
+4 -68
View File
@@ -68,10 +68,6 @@ static void applyResize(int logicalW, int logicalH) {
SDL_SetWindowSize(ZL::Environment::window, physicalW, physicalH); SDL_SetWindowSize(ZL::Environment::window, physicalW, physicalH);
} }
// Обновляем ваши внутренние переменные окружения
ZL::Environment::width = physicalW;
ZL::Environment::height = physicalH;
// Пушим событие, чтобы движок пересчитал матрицы проекции // Пушим событие, чтобы движок пересчитал матрицы проекции
SDL_Event e = {}; SDL_Event e = {};
e.type = SDL_WINDOWEVENT; e.type = SDL_WINDOWEVENT;
@@ -131,7 +127,11 @@ int main(int argc, char* argv[]) {
// канваса и отправит SDL_WINDOWEVENT_RESIZED для настройки проекции. // канваса и отправит SDL_WINDOWEVENT_RESIZED для настройки проекции.
applyResize(canvasW, canvasH); applyResize(canvasW, canvasH);
// Prevent mouse clicks from generating fake SDL_FINGERDOWN events (desktop browser)
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0"); SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
// Prevent touch events from generating fake SDL_MOUSEBUTTONDOWN events (mobile browser),
// since we now handle SDL_FINGERDOWN directly for multi-touch support.
SDL_SetHint(SDL_HINT_TOUCH_MOUSE_EVENTS, "0");
emscripten_set_main_loop(MainLoop, 0, 1); emscripten_set_main_loop(MainLoop, 0, 1);
@@ -240,68 +240,6 @@ int main(int argc, char *argv[]) {
ZL::Environment::width = CONST_WIDTH; ZL::Environment::width = CONST_WIDTH;
ZL::Environment::height = CONST_HEIGHT; ZL::Environment::height = CONST_HEIGHT;
/*#ifdef EMSCRIPTEN
if (SDL_Init(SDL_INIT_VIDEO) != 0) {
std::cerr << "SDL_Init failed: " << SDL_GetError() << std::endl;
return 1;
}
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 2);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 0);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_ES);
SDL_Window* win = SDL_CreateWindow("Space Ship Game",
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
CONST_WIDTH, CONST_HEIGHT,
SDL_WINDOW_OPENGL);
if (!win) {
std::cerr << "SDL_CreateWindow failed: " << SDL_GetError() << std::endl;
return 1;
}
SDL_GLContext glContext = SDL_GL_CreateContext(win);
if (!glContext) {
std::cerr << "SDL_GL_CreateContext failed: " << SDL_GetError() << std::endl;
return 1;
}
// Привязка контекста к окну — важно!
SDL_GL_MakeCurrent(win, glContext);
ZL::Environment::window = win;
g_game = new ZL::Game();
g_game->setup();
// Re-create the game object when the WebGL context is lost and restored
// (this happens e.g. when the user toggles fullscreen in the browser).
emscripten_set_webglcontextlost_callback("#canvas", nullptr, EM_TRUE, onWebGLContextLost);
emscripten_set_webglcontextrestored_callback("#canvas", nullptr, EM_TRUE, onWebGLContextRestored);
// Keep Environment::width/height in sync when the canvas is resized.
emscripten_set_resize_callback(EMSCRIPTEN_EVENT_TARGET_WINDOW, nullptr, EM_FALSE, onWindowResized);
emscripten_set_fullscreenchange_callback(EMSCRIPTEN_EVENT_TARGET_DOCUMENT, nullptr, EM_FALSE, onFullscreenChanged);
// 2. ИНИЦИАЛИЗАЦИЯ РАЗМЕРОВ:
// Получаем реальные размеры окна браузера на момент запуска
int canvasW = EM_ASM_INT({ return window.innerWidth; });
int canvasH = EM_ASM_INT({ return window.innerHeight; });
// Вызываем вашу функцию — она сама применит DPR, выставит физический размер
// канваса и отправит SDL_WINDOWEVENT_RESIZED для настройки проекции.
applyResize(canvasW, canvasH);
// 3. Создаем игру и вызываем setup (теперь проекция уже будет знать верный size)
g_game = new ZL::Game();
g_game->setup();
SDL_SetHint(SDL_HINT_MOUSE_TOUCH_EVENTS, "0");
emscripten_set_main_loop(MainLoop, 0, 1);
#else*/
if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) { if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) {
SDL_Log("SDL init failed: %s", SDL_GetError()); SDL_Log("SDL init failed: %s", SDL_GetError());
return 1; return 1;
@@ -327,8 +265,6 @@ int main(int argc, char *argv[]) {
game.update(); game.update();
SDL_Delay(2); SDL_Delay(2);
} }
//#endif
} }
catch (const std::exception& e) catch (const std::exception& e)
{ {
+1
View File
@@ -34,6 +34,7 @@ namespace ZL {
public: public:
virtual ~INetworkClient() = default; virtual ~INetworkClient() = default;
virtual void Connect(const std::string& host, uint16_t port) = 0; virtual void Connect(const std::string& host, uint16_t port) = 0;
virtual void Disconnect() {}
virtual void Send(const std::string& message) = 0; virtual void Send(const std::string& message) = 0;
virtual bool IsConnected() const = 0; virtual bool IsConnected() const = 0;
virtual void Poll() = 0; // ƒл¤ обработки вход¤щих пакетов virtual void Poll() = 0; // ƒл¤ обработки вход¤щих пакетов
+9
View File
@@ -28,6 +28,15 @@ namespace ZL {
} }
} }
void WebSocketClient::Disconnect() {
if (!ws_ || !connected) return;
connected = false;
try {
boost::beast::get_lowest_layer(*ws_).cancel();
}
catch (...) {}
}
void WebSocketClient::startAsyncRead() { void WebSocketClient::startAsyncRead() {
ws_->async_read(buffer_, [this](boost::beast::error_code ec, std::size_t bytes) { ws_->async_read(buffer_, [this](boost::beast::error_code ec, std::size_t bytes) {
if (!ec) { if (!ec) {
+1
View File
@@ -54,6 +54,7 @@ namespace ZL {
{} {}
void Connect(const std::string& host, uint16_t port) override; void Connect(const std::string& host, uint16_t port) override;
void Disconnect() override;
void Poll() override; void Poll() override;
@@ -26,6 +26,15 @@ namespace ZL {
connected = false; connected = false;
} }
void WebSocketClientEmscripten::Disconnect() {
if (socket_ > 0) {
emscripten_websocket_close(socket_, 1000, "User disconnected");
emscripten_websocket_delete(socket_);
socket_ = 0;
}
connected = false;
}
void WebSocketClientEmscripten::flushOutgoingQueue() { void WebSocketClientEmscripten::flushOutgoingQueue() {
std::lock_guard<std::mutex> lock(outgoingMutex); std::lock_guard<std::mutex> lock(outgoingMutex);
if (!socket_) return; if (!socket_) return;
+1
View File
@@ -28,6 +28,7 @@ namespace ZL {
virtual ~WebSocketClientEmscripten() = default; virtual ~WebSocketClientEmscripten() = default;
void Connect(const std::string& host, uint16_t port) override; void Connect(const std::string& host, uint16_t port) override;
void Disconnect() override;
void Send(const std::string& message) override; void Send(const std::string& message) override;
void Poll() override; void Poll() override;
+9 -73
View File
@@ -6,6 +6,7 @@
#include "StoneObject.h" #include "StoneObject.h"
#include "utils/TaskManager.h" #include "utils/TaskManager.h"
#include "TextModel.h" #include "TextModel.h"
#include "GameConstants.h"
namespace ZL { namespace ZL {
@@ -185,16 +186,10 @@ namespace ZL {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
static const std::string defaultShaderName2 = "planetBake"; static const std::string planetBakeShaderName = "planetBake";
static const std::string vPositionName = "vPosition";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(planetBakeShaderName);
renderer.shaderManager.PushShader(defaultShaderName2);
renderer.RenderUniform1i(textureUniformName, 0); renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vTexCoordName);
Triangle tr = planetData.getLodLevel().triangles[0]; Triangle tr = planetData.getLodLevel().triangles[0];
@@ -260,8 +255,6 @@ namespace ZL {
glDisable(GL_CULL_FACE); // Не забываем выключить, чтобы не сломать остальной рендер glDisable(GL_CULL_FACE); // Не забываем выключить, чтобы не сломать остальной рендер
renderer.PopMatrix(); renderer.PopMatrix();
renderer.PopProjectionMatrix(); renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.DisableVertexAttribArray(vPositionName);
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
CheckGlError(); CheckGlError();
} }
@@ -298,22 +291,11 @@ namespace ZL {
void PlanetObject::drawPlanet(Renderer& renderer) void PlanetObject::drawPlanet(Renderer& renderer)
{ {
static const std::string defaultShaderName = "planetLand"; static const std::string planetLandShaderName = "planetLand";
static const std::string vPositionName = "vPosition";
static const std::string vColorName = "vColor";
static const std::string vNormalName = "vNormal";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture"; static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(defaultShaderName); renderer.shaderManager.PushShader(planetLandShaderName);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vColorName);
renderer.EnableVertexAttribArray(vNormalName);
renderer.EnableVertexAttribArray("vTangent");
renderer.EnableVertexAttribArray("vBinormal");
renderer.EnableVertexAttribArray(vTexCoordName);
float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipState.position); float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipState.position);
@@ -335,10 +317,9 @@ namespace ZL {
const Matrix4f viewMatrix = renderer.GetCurrentModelViewMatrix(); const Matrix4f viewMatrix = renderer.GetCurrentModelViewMatrix();
renderer.RenderUniform1i("Texture", 0); renderer.RenderUniform1i(textureUniformName, 0);
renderer.RenderUniform1i("BakedTexture", 1); renderer.RenderUniform1i("BakedTexture", 1);
Triangle tr = planetData.getLodLevel().triangles[0]; // Берем базовый треугольник Triangle tr = planetData.getLodLevel().triangles[0]; // Берем базовый треугольник
Matrix3f mr = GetRotationForTriangle(tr); // Та же матрица, что и при запекании Matrix3f mr = GetRotationForTriangle(tr); // Та же матрица, что и при запекании
@@ -376,12 +357,6 @@ namespace ZL {
renderer.PopMatrix(); renderer.PopMatrix();
renderer.PopProjectionMatrix(); renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.DisableVertexAttribArray(vNormalName);
renderer.DisableVertexAttribArray("vTangent");
renderer.DisableVertexAttribArray("vBinormal");
renderer.DisableVertexAttribArray(vColorName);
renderer.DisableVertexAttribArray(vPositionName);
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
CheckGlError(); CheckGlError();
@@ -390,20 +365,10 @@ namespace ZL {
void PlanetObject::drawStones(Renderer& renderer) void PlanetObject::drawStones(Renderer& renderer)
{ {
static const std::string defaultShaderName2 = "planetStone"; static const std::string planetStoneShaderName = "planetStone";
static const std::string vPositionName = "vPosition";
static const std::string vColorName = "vColor";
static const std::string vNormalName = "vNormal";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(defaultShaderName2); renderer.shaderManager.PushShader(planetStoneShaderName);
renderer.RenderUniform1i(textureUniformName, 0); renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vColorName);
renderer.EnableVertexAttribArray(vNormalName);
renderer.EnableVertexAttribArray(vTexCoordName);
float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipState.position); float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipState.position);
auto zRange = planetData.calculateZRange(dist); auto zRange = planetData.calculateZRange(dist);
@@ -468,10 +433,6 @@ namespace ZL {
renderer.PopMatrix(); renderer.PopMatrix();
renderer.PopProjectionMatrix(); renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.DisableVertexAttribArray(vNormalName);
renderer.DisableVertexAttribArray(vColorName);
renderer.DisableVertexAttribArray(vPositionName);
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
CheckGlError(); CheckGlError();
@@ -480,16 +441,10 @@ namespace ZL {
void PlanetObject::drawAtmosphere(Renderer& renderer) { void PlanetObject::drawAtmosphere(Renderer& renderer) {
static const std::string defaultShaderName = "defaultAtmosphere"; static const std::string defaultShaderName = "defaultAtmosphere";
//static const std::string defaultShaderName = "defaultColor";
static const std::string vPositionName = "vPosition";
static const std::string vNormalName = "vNormal";
//glClear(GL_DEPTH_BUFFER_BIT); //glClear(GL_DEPTH_BUFFER_BIT);
glDepthMask(GL_FALSE); glDepthMask(GL_FALSE);
renderer.shaderManager.PushShader(defaultShaderName); renderer.shaderManager.PushShader(defaultShaderName);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vNormalName);
float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipState.position); float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipState.position);
auto zRange = planetData.calculateZRange(dist); auto zRange = planetData.calculateZRange(dist);
float currentZNear = zRange.first; float currentZNear = zRange.first;
@@ -571,9 +526,6 @@ namespace ZL {
glDepthMask(GL_TRUE); glDepthMask(GL_TRUE);
renderer.PopMatrix(); renderer.PopMatrix();
renderer.PopProjectionMatrix(); renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vNormalName);
renderer.DisableVertexAttribArray(vPositionName);
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
CheckGlError(); CheckGlError();
@@ -581,20 +533,8 @@ namespace ZL {
void PlanetObject::drawCamp(Renderer& renderer) void PlanetObject::drawCamp(Renderer& renderer)
{ {
static const std::string defaultShaderName2 = "default"; renderer.shaderManager.PushShader(defaultShaderName);
static const std::string vPositionName = "vPosition";
static const std::string vColorName = "vColor";
static const std::string vNormalName = "vNormal";
static const std::string vTexCoordName = "vTexCoord";
static const std::string textureUniformName = "Texture";
renderer.shaderManager.PushShader(defaultShaderName2);
renderer.RenderUniform1i(textureUniformName, 0); renderer.RenderUniform1i(textureUniformName, 0);
renderer.EnableVertexAttribArray(vPositionName);
renderer.EnableVertexAttribArray(vColorName);
renderer.EnableVertexAttribArray(vNormalName);
renderer.EnableVertexAttribArray(vTexCoordName);
float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipState.position); float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipState.position);
auto zRange = planetData.calculateZRange(dist); auto zRange = planetData.calculateZRange(dist);
@@ -655,10 +595,6 @@ namespace ZL {
renderer.PopMatrix(); renderer.PopMatrix();
renderer.PopProjectionMatrix(); renderer.PopProjectionMatrix();
renderer.DisableVertexAttribArray(vTexCoordName);
renderer.DisableVertexAttribArray(vNormalName);
renderer.DisableVertexAttribArray(vColorName);
renderer.DisableVertexAttribArray(vPositionName);
renderer.shaderManager.PopShader(); renderer.shaderManager.PopShader();
CheckGlError(); CheckGlError();
+24 -54
View File
@@ -50,17 +50,14 @@ namespace ZL {
Matrix4f r; Matrix4f r;
// ���������������
r.data()[0] = 2.f / width; r.data()[0] = 2.f / width;
r.data()[5] = 2.f / height; r.data()[5] = 2.f / height;
r.data()[10] = -1.f / depthRange; r.data()[10] = -1.f / depthRange;
// ��������� �������������� �����������
r.data()[1] = r.data()[2] = r.data()[3] = 0; r.data()[1] = r.data()[2] = r.data()[3] = 0;
r.data()[4] = r.data()[6] = r.data()[7] = 0; r.data()[4] = r.data()[6] = r.data()[7] = 0;
r.data()[8] = r.data()[9] = r.data()[11] = 0; r.data()[8] = r.data()[9] = r.data()[11] = 0;
// ���������� (��������)
r.data()[12] = -(xmax + xmin) / width; r.data()[12] = -(xmax + xmin) / width;
r.data()[13] = -(ymax + ymin) / height; r.data()[13] = -(ymax + ymin) / height;
r.data()[14] = zNear / depthRange; r.data()[14] = zNear / depthRange;
@@ -384,7 +381,7 @@ namespace ZL {
glBindBuffer(GL_ARRAY_BUFFER, positionVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, positionVBO->getBuffer());
glBufferData(GL_ARRAY_BUFFER, data.PositionData.size() * 12, &data.PositionData[0], GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, data.PositionData.size() * 12, &data.PositionData[0], GL_DYNAMIC_DRAW);
if (data.TexCoordData.size() > 0) if (data.TexCoordData.size() > 0)
{ {
@@ -395,7 +392,7 @@ namespace ZL {
glBindBuffer(GL_ARRAY_BUFFER, texCoordVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, texCoordVBO->getBuffer());
glBufferData(GL_ARRAY_BUFFER, data.TexCoordData.size() * 8, &data.TexCoordData[0], GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, data.TexCoordData.size() * 8, &data.TexCoordData[0], GL_DYNAMIC_DRAW);
} }
if (data.NormalData.size() > 0) if (data.NormalData.size() > 0)
@@ -407,7 +404,7 @@ namespace ZL {
glBindBuffer(GL_ARRAY_BUFFER, normalVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, normalVBO->getBuffer());
glBufferData(GL_ARRAY_BUFFER, data.NormalData.size() * 12, &data.NormalData[0], GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, data.NormalData.size() * 12, &data.NormalData[0], GL_DYNAMIC_DRAW);
} }
if (data.TangentData.size() > 0) if (data.TangentData.size() > 0)
@@ -419,7 +416,7 @@ namespace ZL {
glBindBuffer(GL_ARRAY_BUFFER, tangentVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, tangentVBO->getBuffer());
glBufferData(GL_ARRAY_BUFFER, data.TangentData.size() * 12, &data.TangentData[0], GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, data.TangentData.size() * 12, &data.TangentData[0], GL_DYNAMIC_DRAW);
} }
if (data.BinormalData.size() > 0) if (data.BinormalData.size() > 0)
@@ -431,7 +428,7 @@ namespace ZL {
glBindBuffer(GL_ARRAY_BUFFER, binormalVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, binormalVBO->getBuffer());
glBufferData(GL_ARRAY_BUFFER, data.BinormalData.size() * 12, &data.BinormalData[0], GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, data.BinormalData.size() * 12, &data.BinormalData[0], GL_DYNAMIC_DRAW);
} }
if (data.ColorData.size() > 0) if (data.ColorData.size() > 0)
@@ -443,7 +440,7 @@ namespace ZL {
glBindBuffer(GL_ARRAY_BUFFER, colorVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, colorVBO->getBuffer());
glBufferData(GL_ARRAY_BUFFER, data.ColorData.size() * 12, &data.ColorData[0], GL_STATIC_DRAW); glBufferData(GL_ARRAY_BUFFER, data.ColorData.size() * 12, &data.ColorData[0], GL_DYNAMIC_DRAW);
} }
} }
@@ -620,6 +617,7 @@ namespace ZL {
{ {
throw std::runtime_error("Modelview matrix stack overflow!!!!"); throw std::runtime_error("Modelview matrix stack overflow!!!!");
} }
SetMatrix();
} }
void Renderer::LoadIdentity() void Renderer::LoadIdentity()
@@ -703,19 +701,7 @@ namespace ZL {
Matrix4f m = Matrix4f::Identity(); Matrix4f m = Matrix4f::Identity();
m.block<3, 3>(0, 0) = m3; m.block<3, 3>(0, 0) = m3;
/*
m.m[0] = m3.data()[0];
m.m[1] = m3.data()[1];
m.m[2] = m3.data()[2];
m.m[4] = m3.data()[3];
m.m[5] = m3.data()[4];
m.m[6] = m3.data()[5];
m.m[8] = m3.data()[6];
m.m[9] = m3.data()[7];
m.m[10] = m3.data()[8];
*/
m = ModelviewMatrixStack.top() * m; m = ModelviewMatrixStack.top() * m;
if (ModelviewMatrixStack.size() == 0) if (ModelviewMatrixStack.size() == 0)
@@ -733,17 +719,7 @@ namespace ZL {
void Renderer::RotateMatrix(const Matrix3f& m3) void Renderer::RotateMatrix(const Matrix3f& m3)
{ {
Matrix4f m = Matrix4f::Identity(); Matrix4f m = Matrix4f::Identity();
/*m.m[0] = m3.data()[0];
m.m[1] = m3.data()[1];
m.m[2] = m3.data()[2];
m.m[4] = m3.data()[3];
m.m[5] = m3.data()[4];
m.m[6] = m3.data()[5];
m.m[8] = m3.data()[6];
m.m[9] = m3.data()[7];
m.m[10] = m3.data()[8];*/
m.block<3, 3>(0, 0) = m3; m.block<3, 3>(0, 0) = m3;
m = ModelviewMatrixStack.top() * m; m = ModelviewMatrixStack.top() * m;
@@ -782,22 +758,6 @@ namespace ZL {
SetMatrix(); SetMatrix();
} }
void Renderer::EnableVertexAttribArray(const std::string& attribName)
{
auto shader = shaderManager.GetCurrentShader();
if (shader->attribList.find(attribName) != shader->attribList.end())
glEnableVertexAttribArray(shader->attribList[attribName]);
}
void Renderer::DisableVertexAttribArray(const std::string& attribName)
{
auto shader = shaderManager.GetCurrentShader();
if (shader->attribList.find(attribName) != shader->attribList.end())
glDisableVertexAttribArray(shader->attribList[attribName]);
}
void Renderer::RenderUniformMatrix3fv(const std::string& uniformName, bool transpose, const float* value) void Renderer::RenderUniformMatrix3fv(const std::string& uniformName, bool transpose, const float* value)
{ {
auto shader = shaderManager.GetCurrentShader(); auto shader = shaderManager.GetCurrentShader();
@@ -887,8 +847,25 @@ namespace ZL {
glVertexAttribPointer(shader->attribList[attribName], 3, GL_FLOAT, GL_FALSE, stride, pointer); glVertexAttribPointer(shader->attribList[attribName], 3, GL_FLOAT, GL_FALSE, stride, pointer);
} }
void Renderer::DisableVertexAttribArray(const std::string& attribName)
{
auto shader = shaderManager.GetCurrentShader();
auto it = shader->attribList.find(attribName);
if (it != shader->attribList.end())
glDisableVertexAttribArray(it->second);
}
void Renderer::DrawVertexRenderStruct(const VertexRenderStruct& VertexRenderStruct) void Renderer::DrawVertexRenderStruct(const VertexRenderStruct& VertexRenderStruct)
{ {
#ifndef EMSCRIPTEN
#ifndef __ANDROID__
if (VertexRenderStruct.vao) {
glBindVertexArray(VertexRenderStruct.vao->getBuffer());
shaderManager.EnableVertexAttribArrays();
}
#endif
#endif
static const std::string vNormal("vNormal"); static const std::string vNormal("vNormal");
static const std::string vTangent("vTangent"); static const std::string vTangent("vTangent");
static const std::string vBinormal("vBinormal"); static const std::string vBinormal("vBinormal");
@@ -902,7 +879,6 @@ namespace ZL {
{ {
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.normalVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.normalVBO->getBuffer());
VertexAttribPointer3fv(vNormal, 0, NULL); VertexAttribPointer3fv(vNormal, 0, NULL);
EnableVertexAttribArray(vNormal);
} }
else else
{ {
@@ -912,7 +888,6 @@ namespace ZL {
{ {
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.tangentVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.tangentVBO->getBuffer());
VertexAttribPointer3fv(vTangent, 0, NULL); VertexAttribPointer3fv(vTangent, 0, NULL);
EnableVertexAttribArray(vTangent);
} }
else else
{ {
@@ -922,7 +897,6 @@ namespace ZL {
{ {
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.binormalVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.binormalVBO->getBuffer());
VertexAttribPointer3fv(vBinormal, 0, NULL); VertexAttribPointer3fv(vBinormal, 0, NULL);
EnableVertexAttribArray(vBinormal);
} }
else else
{ {
@@ -932,7 +906,6 @@ namespace ZL {
{ {
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.colorVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.colorVBO->getBuffer());
VertexAttribPointer3fv(vColor, 0, NULL); VertexAttribPointer3fv(vColor, 0, NULL);
EnableVertexAttribArray(vColor);
} }
else else
{ {
@@ -942,7 +915,6 @@ namespace ZL {
{ {
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.texCoordVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.texCoordVBO->getBuffer());
VertexAttribPointer2fv(vTexCoord, 0, NULL); VertexAttribPointer2fv(vTexCoord, 0, NULL);
EnableVertexAttribArray(vTexCoord);
} }
else else
{ {
@@ -951,8 +923,6 @@ namespace ZL {
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.positionVBO->getBuffer()); glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.positionVBO->getBuffer());
VertexAttribPointer3fv(vPosition, 0, NULL); VertexAttribPointer3fv(vPosition, 0, NULL);
EnableVertexAttribArray(vPosition);
glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(VertexRenderStruct.data.PositionData.size())); glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(VertexRenderStruct.data.PositionData.size()));
} }
+2 -7
View File
@@ -127,13 +127,6 @@ namespace ZL {
void SetMatrix(); void SetMatrix();
void EnableVertexAttribArray(const std::string& attribName);
void DisableVertexAttribArray(const std::string& attribName);
void RenderUniformMatrix3fv(const std::string& uniformName, bool transpose, const float* value); void RenderUniformMatrix3fv(const std::string& uniformName, bool transpose, const float* value);
void RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value); void RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* value);
void RenderUniform1i(const std::string& uniformName, const int value); void RenderUniform1i(const std::string& uniformName, const int value);
@@ -145,6 +138,8 @@ namespace ZL {
void VertexAttribPointer3fv(const std::string& attribName, int stride, const char* pointer); void VertexAttribPointer3fv(const std::string& attribName, int stride, const char* pointer);
void DisableVertexAttribArray(const std::string& attribName);
void DrawVertexRenderStruct(const VertexRenderStruct& VertexRenderStruct); void DrawVertexRenderStruct(const VertexRenderStruct& VertexRenderStruct);
}; };
+46 -3
View File
@@ -167,7 +167,6 @@ namespace ZL {
fragmentShader = readTextFile(fragmentShaderFileName); fragmentShader = readTextFile(fragmentShaderFileName);
} }
///std::cout << "Shader: "<< vertexShader << std::endl;
shaderResourceMap[shaderName] = std::make_shared<ShaderResource>(vertexShader, shaderResourceMap[shaderName] = std::make_shared<ShaderResource>(vertexShader,
fragmentShader); fragmentShader);
} }
@@ -181,9 +180,26 @@ namespace ZL {
throw std::runtime_error("Shader does not exist!"); throw std::runtime_error("Shader does not exist!");
} }
if (shaderStack.size() > 0)
{
auto& prevShaderAttribList = shaderResourceMap[shaderStack.top()]->attribList;
for (auto& attrib : prevShaderAttribList)
{
glDisableVertexAttribArray(attrib.second);
}
}
shaderStack.push(shaderName); shaderStack.push(shaderName);
glUseProgram(shaderResourceMap[shaderName]->getShaderProgram()); auto& shaderResource = shaderResourceMap[shaderName];
glUseProgram(shaderResource->getShaderProgram());
auto& shaderAttribList = shaderResource->attribList;
for (auto& attrib : shaderAttribList)
{
glEnableVertexAttribArray(attrib.second);
}
} }
@@ -192,12 +208,39 @@ namespace ZL {
throw std::runtime_error("Shader stack underflow!"); throw std::runtime_error("Shader stack underflow!");
} }
auto& prevShaderAttribList = shaderResourceMap[shaderStack.top()]->attribList;
for (auto& attrib : prevShaderAttribList)
{
glDisableVertexAttribArray(attrib.second);
}
shaderStack.pop(); shaderStack.pop();
if (shaderStack.size() == 0) { if (shaderStack.size() == 0) {
glUseProgram(0); glUseProgram(0);
} else { } else {
glUseProgram(shaderResourceMap[shaderStack.top()]->getShaderProgram()); auto& shaderResource = shaderResourceMap[shaderStack.top()];
glUseProgram(shaderResource->getShaderProgram());
auto& shaderAttribList = shaderResource->attribList;
for (auto& attrib : shaderAttribList)
{
glEnableVertexAttribArray(attrib.second);
}
}
}
void ShaderManager::EnableVertexAttribArrays()
{
if (shaderStack.size() != 0) {
auto& shaderResource = shaderResourceMap[shaderStack.top()];
auto& shaderAttribList = shaderResource->attribList;
for (auto& attrib : shaderAttribList)
{
glEnableVertexAttribArray(attrib.second);
}
} }
} }
+1
View File
@@ -42,6 +42,7 @@ namespace ZL {
void PushShader(const std::string& shaderName); void PushShader(const std::string& shaderName);
void PopShader(); void PopShader();
void EnableVertexAttribArrays();
std::shared_ptr<ShaderResource> GetCurrentShader(); std::shared_ptr<ShaderResource> GetCurrentShader();
}; };
-7
View File
@@ -380,10 +380,6 @@ void TextRenderer::drawText(const std::string& text, float x, float y, float sca
glActiveTexture(GL_TEXTURE0); glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, atlasTexture->getTexID()); glBindTexture(GL_TEXTURE_2D, atlasTexture->getTexID());
r->EnableVertexAttribArray("vPosition");
r->EnableVertexAttribArray("vTexCoord");
//for (size_t i = 0; i < text.length(); ++i) { //for (size_t i = 0; i < text.length(); ++i) {
// auto it = glyphs.find(text[i]); // auto it = glyphs.find(text[i]);
// if (it == glyphs.end()) continue; // if (it == glyphs.end()) continue;
@@ -401,9 +397,6 @@ void TextRenderer::drawText(const std::string& text, float x, float y, float sca
// glDrawArrays(GL_TRIANGLES, 0, 6); // glDrawArrays(GL_TRIANGLES, 0, 6);
//} //}
r->DrawVertexRenderStruct(cached.mesh); r->DrawVertexRenderStruct(cached.mesh);
r->DisableVertexAttribArray("vPosition");
r->DisableVertexAttribArray("vTexCoord");
r->shaderManager.PopShader(); r->shaderManager.PopShader();
// Сброс бинда текстуры не обязателен, но можно для чистоты // Сброс бинда текстуры не обязателен, но можно для чистоты