Merge branch 'main' into linux
This commit is contained in:
commit
e5d7885a12
48 files changed
+1109
-895
No files matched your search
@@ -73,6 +73,8 @@ set(SOURCES
|
||||
../src/MenuManager.cpp
|
||||
../src/Space.h
|
||||
../src/Space.cpp
|
||||
../src/GameConstants.h
|
||||
../src/GameConstants.cpp
|
||||
)
|
||||
|
||||
add_executable(space-game001 ${SOURCES})
|
||||
|
||||
@@ -67,6 +67,8 @@ add_executable(space-game001
|
||||
../src/MenuManager.cpp
|
||||
../src/Space.h
|
||||
../src/Space.cpp
|
||||
../src/GameConstants.h
|
||||
../src/GameConstants.cpp
|
||||
)
|
||||
|
||||
# Установка проекта по умолчанию для Visual Studio
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
"texture": "resources/spark_white.png",
|
||||
"speedRange": [10.0, 30.0],
|
||||
"zSpeedRange": [-1.0, 1.0],
|
||||
"scaleRange": [0.5, 1.0],
|
||||
"scaleRange": [5.0, 10.0],
|
||||
"lifeTimeRange": [200.0, 800.0],
|
||||
"emissionRate": 50.0,
|
||||
"maxParticles": 5,
|
||||
|
||||
@@ -11,37 +11,25 @@
|
||||
"height": "match_parent",
|
||||
"children": [
|
||||
{
|
||||
"type": "Button",
|
||||
"type": "StaticImage",
|
||||
"name": "titleBtn",
|
||||
"width": 254,
|
||||
"width": 434,
|
||||
"height": 35,
|
||||
"textures": {
|
||||
"normal": "resources/main_menu/title.png",
|
||||
"hover": "resources/main_menu/title.png",
|
||||
"pressed": "resources/main_menu/title.png"
|
||||
}
|
||||
"texture": "resources/main_menu/title.png"
|
||||
},
|
||||
{
|
||||
"type": "Button",
|
||||
"type": "StaticImage",
|
||||
"name": "underlineBtn",
|
||||
"width": 168,
|
||||
"height": 44,
|
||||
"textures": {
|
||||
"normal": "resources/main_menu/line.png",
|
||||
"hover": "resources/main_menu/line.png",
|
||||
"pressed": "resources/main_menu/line.png"
|
||||
}
|
||||
"texture": "resources/main_menu/line.png"
|
||||
},
|
||||
{
|
||||
"type": "Button",
|
||||
"type": "StaticImage",
|
||||
"name": "subtitleBtn",
|
||||
"width": 144,
|
||||
"height": 11,
|
||||
"textures": {
|
||||
"normal": "resources/main_menu/subtitle.png",
|
||||
"hover": "resources/main_menu/subtitle.png",
|
||||
"pressed": "resources/main_menu/subtitle.png"
|
||||
}
|
||||
"texture": "resources/main_menu/subtitle.png"
|
||||
},
|
||||
{
|
||||
"type": "Button",
|
||||
@@ -66,15 +54,11 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"type": "Button",
|
||||
"type": "StaticImage",
|
||||
"name": "versionLabel",
|
||||
"width": 81,
|
||||
"height": 9,
|
||||
"textures": {
|
||||
"normal": "resources/main_menu/version.png",
|
||||
"hover": "resources/main_menu/version.png",
|
||||
"pressed": "resources/main_menu/version.png"
|
||||
}
|
||||
"texture": "resources/main_menu/version.png"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -10,6 +10,13 @@
|
||||
"width": "match_parent",
|
||||
"height": "match_parent",
|
||||
"children": [
|
||||
{
|
||||
"type": "StaticImage",
|
||||
"name": "titleBtn",
|
||||
"width": 266,
|
||||
"height": 66,
|
||||
"texture": "resources/select_your_ship.png"
|
||||
},
|
||||
{
|
||||
"type": "LinearLayout",
|
||||
"orientation": "horizontal",
|
||||
|
||||
@@ -1,20 +1,14 @@
|
||||
{
|
||||
"emissionRate": 10.0,
|
||||
"maxParticles": 200,
|
||||
"emissionRate": 1.2,
|
||||
"maxParticles": 400,
|
||||
"particleSize": 0.3,
|
||||
"biasX": 0.3,
|
||||
"emissionPoints": [
|
||||
{
|
||||
"position": [-1.0, 1.4, -3.5]
|
||||
},
|
||||
{
|
||||
"position": [1.0, 1.4, -3.5]
|
||||
}
|
||||
],
|
||||
"speedRange": [0.5, 2.0],
|
||||
"zSpeedRange": [1.0, 3.0],
|
||||
"scaleRange": [0.8, 1.2],
|
||||
"lifeTimeRange": [600.0, 1400.0],
|
||||
"lifeTimeRange": [300.0, 500.0],
|
||||
"texture": "resources/spark.png",
|
||||
"shaderProgramName": "spark"
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"emissionRate": 10.0,
|
||||
"maxParticles": 200,
|
||||
"emissionRate": 1.2,
|
||||
"maxParticles": 400,
|
||||
"particleSize": 0.3,
|
||||
"biasX": 0.3,
|
||||
"emissionPoints": [
|
||||
|
||||
@@ -31,7 +31,7 @@
|
||||
"vertical_gravity": "bottom",
|
||||
"textures": {
|
||||
"normal": "resources/fire.png",
|
||||
"hover": "resources/fire2.png",
|
||||
"hover": "resources/fire.png",
|
||||
"pressed": "resources/fire2.png",
|
||||
"disabled": "resources/fire_disabled.png"
|
||||
}
|
||||
@@ -47,7 +47,7 @@
|
||||
"vertical_gravity": "bottom",
|
||||
"textures": {
|
||||
"normal": "resources/fire.png",
|
||||
"hover": "resources/fire2.png",
|
||||
"hover": "resources/fire.png",
|
||||
"pressed": "resources/fire2.png",
|
||||
"disabled": "resources/fire_disabled.png"
|
||||
}
|
||||
@@ -65,7 +65,8 @@
|
||||
"textures": {
|
||||
"normal": "resources/button_minus.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": {
|
||||
"normal": "resources/button_plus.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"
|
||||
}
|
||||
}
|
||||
]
|
||||
|
||||
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
BIN
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
+4
-4
@@ -13,8 +13,8 @@ namespace ZL {
|
||||
|
||||
|
||||
int Environment::windowHeaderHeight = 0;
|
||||
int Environment::width = 0;
|
||||
int Environment::height = 0;
|
||||
int Environment::width = CONST_DEFAULT_WIDTH;
|
||||
int Environment::height = CONST_DEFAULT_HEIGHT;
|
||||
float Environment::zoom = DEFAULT_ZOOM;
|
||||
|
||||
|
||||
@@ -49,10 +49,10 @@ void Environment::computeProjectionDimensions()
|
||||
if (width >= height) {
|
||||
// Landscape: fix height to 720, scale width to preserve aspect
|
||||
projectionHeight = refShortSide;
|
||||
projectionWidth = refShortSide * aspect;
|
||||
projectionWidth = refShortSide * aspect;
|
||||
} else {
|
||||
// Portrait: fix width to 720, scale height to preserve aspect
|
||||
projectionWidth = refShortSide;
|
||||
projectionWidth = refShortSide;
|
||||
projectionHeight = refShortSide / aspect;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,6 +14,8 @@ namespace ZL {
|
||||
|
||||
class Environment {
|
||||
public:
|
||||
static constexpr int CONST_DEFAULT_WIDTH = 1280;
|
||||
static constexpr int CONST_DEFAULT_HEIGHT = 720;
|
||||
static int windowHeaderHeight;
|
||||
static int width;
|
||||
static int height;
|
||||
|
||||
+106
-93
@@ -30,7 +30,7 @@
|
||||
|
||||
#include "network/LocalClient.h"
|
||||
#include "network/ClientState.h"
|
||||
|
||||
#include "GameConstants.h"
|
||||
|
||||
namespace ZL
|
||||
{
|
||||
@@ -41,6 +41,10 @@ namespace ZL
|
||||
const char* CONST_ZIP_FILE = "";
|
||||
#endif
|
||||
|
||||
float x = 0;
|
||||
float y = 0;
|
||||
float z = 0;
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
Game* Game::s_instance = nullptr;
|
||||
|
||||
@@ -86,6 +90,8 @@ namespace ZL
|
||||
//glContext = SDL_GL_CreateContext(ZL::Environment::window);
|
||||
//glContext = in_glContext;
|
||||
|
||||
Environment::width = Environment::CONST_DEFAULT_WIDTH;
|
||||
Environment::height = Environment::CONST_DEFAULT_HEIGHT;
|
||||
Environment::computeProjectionDimensions();
|
||||
|
||||
ZL::BindOpenGlFunctions();
|
||||
@@ -104,7 +110,20 @@ namespace ZL
|
||||
loadingTexture = std::make_unique<Texture>(CreateTextureDataFromPng("resources/loading.png", CONST_ZIP_FILE));
|
||||
#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();
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
@@ -146,11 +165,17 @@ namespace ZL
|
||||
|
||||
menuManager.setupMenu();
|
||||
|
||||
menuManager.onMainMenuEntered = [this]() {
|
||||
if (networkClient) {
|
||||
networkClient->Disconnect();
|
||||
networkClient.reset();
|
||||
}
|
||||
};
|
||||
|
||||
menuManager.onSingleplayerPressed = [this](const std::string& nickname, int shipType) {
|
||||
Environment::shipState.nickname = nickname;
|
||||
Environment::shipState.shipType = shipType;
|
||||
|
||||
|
||||
if (Environment::shipState.shipType == 1)
|
||||
{
|
||||
menuManager.uiManager.findButton("shootButton")->state = ButtonState::Disabled;
|
||||
@@ -170,15 +195,14 @@ namespace ZL
|
||||
networkClient = std::unique_ptr<INetworkClient>(localClient);
|
||||
networkClient->Connect("", 0);
|
||||
|
||||
space.resetPlayerState();
|
||||
lastTickCount = 0;
|
||||
spaceGameStarted = 1;
|
||||
};
|
||||
|
||||
menuManager.onMultiplayerPressed = [this](const std::string& nickname, int shipType) {
|
||||
Environment::shipState.nickname = nickname;
|
||||
Environment::shipState.shipType = shipType;
|
||||
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
networkClient = std::make_unique<WebSocketClientEmscripten>();
|
||||
networkClient->Connect("localhost", 8081);
|
||||
@@ -186,7 +210,7 @@ namespace ZL
|
||||
networkClient = std::make_unique<WebSocketClient>(taskManager.getIOContext());
|
||||
networkClient->Connect("localhost", 8081);
|
||||
#endif
|
||||
|
||||
|
||||
if (networkClient) {
|
||||
std::string joinMsg = std::string("JOIN:") + nickname + ":" + std::to_string(shipType);
|
||||
networkClient->Send(joinMsg);
|
||||
@@ -195,12 +219,12 @@ namespace ZL
|
||||
|
||||
space.boxCoordsArr.clear();
|
||||
space.boxRenderArr.clear();
|
||||
//space.boxLabels.clear();
|
||||
space.boxAlive.clear();
|
||||
space.serverBoxesApplied = false;
|
||||
|
||||
space.resetPlayerState();
|
||||
connectingStartTicks = SDL_GetTicks();
|
||||
lastTickCount = 0;
|
||||
spaceGameStarted = 1;
|
||||
};
|
||||
|
||||
|
||||
@@ -212,21 +236,10 @@ namespace ZL
|
||||
|
||||
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);
|
||||
|
||||
renderer.shaderManager.PushShader(defaultShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
glEnable(GL_BLEND);
|
||||
menuManager.uiManager.draw(renderer);
|
||||
glDisable(GL_BLEND);
|
||||
@@ -242,17 +255,14 @@ namespace ZL
|
||||
}
|
||||
|
||||
void Game::drawScene() {
|
||||
//For low quality:
|
||||
glViewport(0, 0, Environment::width, Environment::height);
|
||||
//For high quality:
|
||||
//glViewport(0, 0, Environment::projectionWidth, Environment::projectionHeight);
|
||||
if (!loadingCompleted) {
|
||||
drawLoading();
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
if (spaceGameStarted) {
|
||||
if (menuManager.shouldRenderSpace()) {
|
||||
space.drawScene();
|
||||
}
|
||||
else
|
||||
@@ -266,24 +276,17 @@ namespace ZL
|
||||
|
||||
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);
|
||||
|
||||
renderer.shaderManager.PushShader(defaultShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
//float width = Environment::projectionWidth;
|
||||
//float height = Environment::projectionHeight;
|
||||
float width = Environment::projectionWidth;
|
||||
float height = Environment::projectionHeight;
|
||||
|
||||
renderer.PushProjectionMatrix(
|
||||
0, 1,
|
||||
0, 1,
|
||||
-width * 0.5f, width*0.5f,
|
||||
-height * 0.5f, height * 0.5f,
|
||||
-10, 10);
|
||||
|
||||
renderer.PushMatrix();
|
||||
@@ -294,9 +297,6 @@ namespace ZL
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
}
|
||||
@@ -336,7 +336,7 @@ namespace ZL
|
||||
//throw std::runtime_error("Synchronization is lost");
|
||||
}
|
||||
|
||||
if (spaceGameStarted) {
|
||||
if (menuManager.shouldRenderSpace()) {
|
||||
space.processTickCount(newTickCount, delta);
|
||||
}
|
||||
menuManager.uiManager.update(static_cast<float>(delta));
|
||||
@@ -348,11 +348,13 @@ namespace ZL
|
||||
//SDL_GL_MakeCurrent(ZL::Environment::window, glContext);
|
||||
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);
|
||||
|
||||
//processTickCount();
|
||||
drawScene();
|
||||
processTickCount();
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(50));
|
||||
|
||||
SDL_GL_SwapWindow(ZL::Environment::window);
|
||||
}
|
||||
@@ -386,51 +388,55 @@ namespace ZL
|
||||
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(mx, my);
|
||||
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(mx, my);
|
||||
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(mx, my);
|
||||
handleMotion(static_cast<int64_t>(event.tfinger.fingerId), mx, my);
|
||||
}
|
||||
#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) {
|
||||
// Преобразуем экранные пиксели в проекционные единицы
|
||||
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);
|
||||
|
||||
if (event.type == SDL_MOUSEBUTTONDOWN) handleDown(mx, my);
|
||||
else handleUp(mx, my);
|
||||
if (event.type == SDL_MOUSEBUTTONDOWN) handleDown(ZL::UiManager::MOUSE_FINGER_ID, 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) {
|
||||
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);
|
||||
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) {
|
||||
static const float zoomstep = 2.0f;
|
||||
if (event.wheel.y > 0) {
|
||||
@@ -459,8 +465,8 @@ namespace ZL
|
||||
}
|
||||
|
||||
if (event.type == SDL_KEYUP) {
|
||||
if (event.key.keysym.sym == SDLK_a) {
|
||||
//Environment::shipState.position = { 9466.15820, 1046.00159, 18531.2090 };
|
||||
if (event.key.keysym.sym == SDLK_r) {
|
||||
std::cout << "Camera position: x=" << x << " y=" << y << " z=" << z << std::endl;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -475,6 +481,22 @@ namespace ZL
|
||||
}
|
||||
//#endif
|
||||
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
|
||||
auto* wsBase = dynamic_cast<ZL::WebSocketClientBase*>(networkClient.get());
|
||||
if (wsBase) {
|
||||
@@ -503,67 +525,58 @@ namespace ZL
|
||||
}
|
||||
mainThreadHandler.processMainThreadTasks();
|
||||
|
||||
if (spaceGameStarted) {
|
||||
if (menuManager.shouldRenderSpace()) {
|
||||
space.update();
|
||||
}
|
||||
}
|
||||
|
||||
void Game::handleDown(int mx, int my)
|
||||
void Game::handleDown(int64_t fingerId, int mx, int my)
|
||||
{
|
||||
int uiX = mx;
|
||||
int uiY = Environment::projectionHeight - my;
|
||||
|
||||
menuManager.uiManager.onMouseDown(uiX, uiY);
|
||||
menuManager.uiManager.onTouchDown(fingerId, uiX, uiY);
|
||||
|
||||
bool uiHandled = false;
|
||||
|
||||
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) {
|
||||
if (!menuManager.uiManager.isUiInteractionForFinger(fingerId)) {
|
||||
if (menuManager.shouldRenderSpace()) {
|
||||
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 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 (spaceGameStarted) {
|
||||
if (!wasUiInteraction) {
|
||||
if (menuManager.shouldRenderSpace()) {
|
||||
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 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 (spaceGameStarted) {
|
||||
if (!wasUiInteraction) {
|
||||
if (menuManager.shouldRenderSpace()) {
|
||||
space.handleMotion(mx, my);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
+6
-5
@@ -13,6 +13,7 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <memory>
|
||||
#include <cstdint>
|
||||
#include <render/TextRenderer.h>
|
||||
#include "MenuManager.h"
|
||||
#include "Space.h"
|
||||
@@ -50,9 +51,9 @@ namespace ZL {
|
||||
void drawUI();
|
||||
void drawUnderMainMenu();
|
||||
void drawLoading();
|
||||
void handleDown(int mx, int my);
|
||||
void handleUp(int mx, int my);
|
||||
void handleMotion(int mx, int my);
|
||||
void handleDown(int64_t fingerId, int mx, int my);
|
||||
void handleUp(int64_t fingerId, int mx, int my);
|
||||
void handleMotion(int64_t fingerId, int mx, int my);
|
||||
|
||||
#ifdef EMSCRIPTEN
|
||||
static Game* s_instance;
|
||||
@@ -65,14 +66,14 @@ namespace ZL {
|
||||
|
||||
int64_t newTickCount;
|
||||
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_MAX_TIME_INTERVAL = 1000;
|
||||
|
||||
MenuManager menuManager;
|
||||
Space space;
|
||||
|
||||
int spaceGameStarted = 0;
|
||||
};
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
#include "GameConstants.h"
|
||||
|
||||
namespace ZL
|
||||
{
|
||||
const std::string defaultShaderName = "default";
|
||||
const std::string envShaderName = "env";
|
||||
const std::string textureUniformName = "Texture";
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
+212
-260
@@ -1,5 +1,5 @@
|
||||
#include "MenuManager.h"
|
||||
|
||||
#include "MenuManager.h"
|
||||
#include <iostream>
|
||||
|
||||
namespace ZL {
|
||||
|
||||
@@ -10,294 +10,246 @@ namespace ZL {
|
||||
|
||||
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);
|
||||
|
||||
settingsSavedRoot = loadUiFromFile("resources/config/settings.json", renderer, CONST_ZIP_FILE);
|
||||
bool MenuManager::shouldRenderSpace() const
|
||||
{
|
||||
return state == GameState::Gameplay
|
||||
|| state == GameState::GameOver
|
||||
|| state == GameState::ConnectionLost;
|
||||
}
|
||||
|
||||
multiplayerSavedRoot = loadUiFromFile("resources/config/multiplayer_menu.json", renderer, CONST_ZIP_FILE);
|
||||
|
||||
gameOverSavedRoot = loadUiFromFile("resources/config/game_over.json", renderer, CONST_ZIP_FILE);
|
||||
|
||||
auto shipSelectionRoot = loadUiFromFile("resources/config/ship_selection_menu.json", renderer, CONST_ZIP_FILE);
|
||||
std::function<void()> loadGameplayUI;
|
||||
loadGameplayUI = [this]() {
|
||||
uiManager.replaceRoot(uiSavedRoot);
|
||||
// ── State: MainMenu ──────────────────────────────────────────────────────
|
||||
|
||||
auto velocityTv = uiManager.findTextView("velocityText");
|
||||
if (velocityTv) {
|
||||
velocityTv->rect.x = 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;
|
||||
}
|
||||
void MenuManager::enterMainMenu()
|
||||
{
|
||||
state = GameState::MainMenu;
|
||||
uiManager.replaceRoot(mainMenuRoot);
|
||||
|
||||
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;
|
||||
}
|
||||
});
|
||||
if (onMainMenuEntered) onMainMenuEntered();
|
||||
|
||||
uiManager.setAnimationCallback("exitButton", "bgScroll", [this]() {
|
||||
std::cerr << "Exit button bgScroll animation finished" << std::endl;
|
||||
g_exitBgAnimating = false;
|
||||
});
|
||||
|
||||
uiManager.setButtonCallback("playButton", [this](const std::string& name) {
|
||||
std::cerr << "Play button pressed: " << name << std::endl;
|
||||
});
|
||||
|
||||
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;
|
||||
if (newVel > 4)
|
||||
{
|
||||
newVel = 4;
|
||||
}
|
||||
onVelocityChanged(newVel);
|
||||
});
|
||||
uiManager.setButtonCallback("minusButton", [this](const std::string& name) {
|
||||
int newVel = Environment::shipState.selectedVelocity-1;
|
||||
if (newVel < 0)
|
||||
{
|
||||
newVel = 0;
|
||||
}
|
||||
onVelocityChanged(newVel);
|
||||
});
|
||||
uiManager.setSliderCallback("velocitySlider", [this](const std::string& name, float value) {
|
||||
|
||||
int newVel = roundf(value * 10);
|
||||
if (newVel > 2)
|
||||
{
|
||||
newVel = 2;
|
||||
}
|
||||
|
||||
if (newVel != Environment::shipState.selectedVelocity) {
|
||||
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("singleButton", [this](const std::string&) {
|
||||
enterShipSelectionSingle();
|
||||
});
|
||||
|
||||
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("multiplayerButton", [this](const std::string&) {
|
||||
enterShipSelectionMulti();
|
||||
});
|
||||
}
|
||||
|
||||
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);
|
||||
});
|
||||
// ── State: ShipSelectionSingle ───────────────────────────────────────────
|
||||
|
||||
uiManager.setButtonCallback("backButton", [this](const std::string& btnName) {
|
||||
uiManager.popMenu();
|
||||
});
|
||||
}
|
||||
else {
|
||||
std::cerr << "Failed to push ship selection menu\n";
|
||||
}
|
||||
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("multiplayerButton2", [this, shipSelectionRoot, loadGameplayUI](const std::string& name) {
|
||||
std::cerr << "Multiplayer button pressed → opening multiplayer menu\n";
|
||||
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.startAnimationOnNode("playButton", "buttonsExit");
|
||||
uiManager.startAnimationOnNode("settingsButton", "buttonsExit");
|
||||
uiManager.startAnimationOnNode("multiplayerButton", "buttonsExit");
|
||||
uiManager.startAnimationOnNode("exitButton", "buttonsExit");
|
||||
uiManager.setButtonCallback("backButton", [this](const std::string&) {
|
||||
enterMainMenu();
|
||||
});
|
||||
}
|
||||
|
||||
if (uiManager.pushMenuFromSavedRoot(multiplayerSavedRoot)) {
|
||||
// ── State: ShipSelectionMulti ─────────────────────────────────────────────
|
||||
|
||||
uiManager.setButtonCallback("connectButton", [this](const std::string& buttonName) {
|
||||
std::string serverAddress = uiManager.getTextFieldValue("serverInputField");
|
||||
void MenuManager::enterShipSelectionMulti()
|
||||
{
|
||||
state = GameState::ShipSelectionMulti;
|
||||
uiManager.replaceRoot(shipSelectionRoot);
|
||||
|
||||
if (serverAddress.empty()) {
|
||||
uiManager.setText("statusText", "Please enter server address");
|
||||
return;
|
||||
}
|
||||
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.setText("statusText", "Connecting to " + serverAddress + "...");
|
||||
std::cerr << "Connecting to server: " << serverAddress << std::endl;
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
uiManager.setButtonCallback("backButton", [this](const std::string& buttonName) {
|
||||
uiManager.popMenu();
|
||||
});
|
||||
// ── State: Connecting ────────────────────────────────────────────────────
|
||||
|
||||
uiManager.setTextFieldCallback("serverInputField",
|
||||
[this](const std::string& fieldName, const std::string& newText) {
|
||||
std::cout << "Server input field changed to: " << newText << std::endl;
|
||||
});
|
||||
void MenuManager::enterConnecting()
|
||||
{
|
||||
state = GameState::Connecting;
|
||||
uiManager.replaceRoot(connectingRoot);
|
||||
// No interactive elements — just a static "Connecting..." image
|
||||
}
|
||||
|
||||
std::cerr << "Multiplayer menu loaded successfully\n";
|
||||
// ── 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 velocityTv = uiManager.findTextView("velocityText");
|
||||
if (velocityTv) {
|
||||
velocityTv->rect.x = 10.0f;
|
||||
velocityTv->rect.y = static_cast<float>(Environment::height) - velocityTv->rect.h - 10.0f;
|
||||
}
|
||||
|
||||
//uiManager.startAnimationOnNode("backgroundNode", "bgScroll");
|
||||
|
||||
uiManager.setButtonPressCallback("shootButton", [this](const std::string&) {
|
||||
if (onFirePressed) onFirePressed();
|
||||
});
|
||||
uiManager.setButtonPressCallback("shootButton2", [this](const std::string&) {
|
||||
if (onFirePressed) onFirePressed();
|
||||
});
|
||||
uiManager.setButtonPressCallback("plusButton", [this](const std::string&) {
|
||||
int newVel = Environment::shipState.selectedVelocity + 1;
|
||||
if (newVel > 4) newVel = 4;
|
||||
uiManager.findButton("minusButton")->state = ButtonState::Normal;
|
||||
if (newVel == 4)
|
||||
{
|
||||
uiManager.findButton("plusButton")->state = ButtonState::Disabled;
|
||||
}
|
||||
else {
|
||||
std::cerr << "Failed to load multiplayer menu\n";
|
||||
else
|
||||
{
|
||||
uiManager.findButton("plusButton")->state = ButtonState::Normal;
|
||||
}
|
||||
std::cerr << "Single button pressed: " << name << " -> open ship selection UI\n";
|
||||
if (!shipSelectionRoot) {
|
||||
std::cerr << "Failed to load ship selection UI\n";
|
||||
return;
|
||||
if (onVelocityChanged) onVelocityChanged(newVel);
|
||||
});
|
||||
uiManager.setButtonPressCallback("minusButton", [this](const std::string&) {
|
||||
int newVel = Environment::shipState.selectedVelocity - 1;
|
||||
if (newVel < 0) newVel = 0;
|
||||
uiManager.findButton("plusButton")->state = ButtonState::Normal;
|
||||
if (newVel == 0)
|
||||
{
|
||||
uiManager.findButton("minusButton")->state = ButtonState::Disabled;
|
||||
}
|
||||
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
|
||||
{
|
||||
uiManager.findButton("minusButton")->state = ButtonState::Normal;
|
||||
}
|
||||
else {
|
||||
std::cerr << "Failed to push ship selection menu\n";
|
||||
if (onVelocityChanged) onVelocityChanged(newVel);
|
||||
});
|
||||
uiManager.setSliderCallback("velocitySlider", [this](const std::string&, float value) {
|
||||
int newVel = static_cast<int>(roundf(value * 10));
|
||||
if (newVel > 2) newVel = 2;
|
||||
if (newVel != Environment::shipState.selectedVelocity) {
|
||||
if (onVelocityChanged) onVelocityChanged(newVel);
|
||||
}
|
||||
});
|
||||
uiManager.setButtonCallback("exitButton", [](const std::string& name) {
|
||||
std::cerr << "Exit from main menu pressed: " << name << " -> exiting\n";
|
||||
Environment::exitGameLoop = true;
|
||||
});*/
|
||||
}
|
||||
|
||||
// ── State: GameOver ──────────────────────────────────────────────────────
|
||||
|
||||
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&) {
|
||||
enterMainMenu();
|
||||
});
|
||||
}
|
||||
|
||||
// ── State: ConnectionLost ─────────────────────────────────────────────────
|
||||
|
||||
void MenuManager::enterConnectionLost()
|
||||
{
|
||||
state = GameState::ConnectionLost;
|
||||
uiManager.replaceRoot(connectionLostRoot);
|
||||
|
||||
uiManager.setButtonCallback("reconnectButton", [this](const std::string&) {
|
||||
// TODO: reconnect logic
|
||||
});
|
||||
uiManager.setButtonCallback("exitServerButton", [this](const std::string&) {
|
||||
enterMainMenu();
|
||||
});
|
||||
}
|
||||
|
||||
// ── Public event API ──────────────────────────────────────────────────────
|
||||
|
||||
void MenuManager::notifyConnected()
|
||||
{
|
||||
if (state == GameState::Connecting) {
|
||||
enterGameplay();
|
||||
}
|
||||
}
|
||||
|
||||
void MenuManager::notifyConnectionFailed()
|
||||
{
|
||||
if (state == GameState::Connecting) {
|
||||
enterConnectionFailed();
|
||||
}
|
||||
}
|
||||
|
||||
void MenuManager::showGameOver(int score)
|
||||
{
|
||||
if (!uiGameOverShown) {
|
||||
if (uiManager.pushMenuFromSavedRoot(gameOverSavedRoot)) {
|
||||
uiManager.setText("scoreText", std::string("Score: ") + std::to_string(score));
|
||||
|
||||
uiManager.setButtonCallback("restartButton", [this](const std::string& name) {
|
||||
uiManager.setText("scoreText", "");
|
||||
uiGameOverShown = false;
|
||||
uiManager.popMenu();
|
||||
if (onRestartPressed) onRestartPressed();
|
||||
});
|
||||
|
||||
uiManager.setButtonCallback("gameOverExitButton", [this](const std::string& name) {
|
||||
Environment::exitGameLoop = true;
|
||||
});
|
||||
|
||||
uiGameOverShown = true;
|
||||
}
|
||||
else {
|
||||
std::cerr << "Failed to load game_over.json\n";
|
||||
}
|
||||
if (state == GameState::Gameplay) {
|
||||
enterGameOver(score);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MenuManager::showConnectionLost()
|
||||
{
|
||||
if (state == GameState::Gameplay) {
|
||||
enterConnectionLost();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ZL
|
||||
+50
-16
@@ -1,4 +1,4 @@
|
||||
#pragma once
|
||||
#pragma once
|
||||
#include "render/Renderer.h"
|
||||
#include "Environment.h"
|
||||
#include "render/TextureManager.h"
|
||||
@@ -7,37 +7,71 @@
|
||||
namespace ZL {
|
||||
|
||||
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:
|
||||
Renderer& renderer;
|
||||
std::shared_ptr<UiNode> uiSavedRoot;
|
||||
std::shared_ptr<UiNode> gameOverSavedRoot;
|
||||
std::shared_ptr<UiNode> settingsSavedRoot;
|
||||
std::shared_ptr<UiNode> multiplayerSavedRoot;
|
||||
|
||||
// Pre-loaded UI roots (loaded once in setupMenu)
|
||||
std::shared_ptr<UiNode> mainMenuRoot;
|
||||
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:
|
||||
bool uiGameOverShown = false;
|
||||
bool g_exitBgAnimating = false;
|
||||
|
||||
UiManager uiManager;
|
||||
|
||||
MenuManager(Renderer& iRenderer);
|
||||
|
||||
void setupMenu();
|
||||
|
||||
//void showGameOver();
|
||||
void showGameOver(int score);
|
||||
// Returns true for states where Space should render and run (Gameplay, GameOver, ConnectionLost)
|
||||
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(float)> onVelocityChanged;
|
||||
std::function<void()> onFirePressed;
|
||||
|
||||
std::function<void(const std::string&, int)> onSingleplayerPressed;
|
||||
std::function<void(const std::string&, int)> onMultiplayerPressed;
|
||||
|
||||
};
|
||||
};
|
||||
|
||||
} // namespace ZL
|
||||
+131
-142
@@ -25,12 +25,16 @@
|
||||
#include "network/LocalClient.h"
|
||||
#endif
|
||||
|
||||
#include "GameConstants.h"
|
||||
|
||||
namespace ZL
|
||||
{
|
||||
|
||||
extern const char* CONST_ZIP_FILE;
|
||||
|
||||
extern float x;
|
||||
extern float y;
|
||||
extern float z;
|
||||
|
||||
Eigen::Quaternionf generateRandomQuaternion(std::mt19937& gen)
|
||||
{
|
||||
@@ -252,20 +256,32 @@ namespace ZL
|
||||
Space::~Space() {
|
||||
}
|
||||
|
||||
void Space::resetPlayerState()
|
||||
{
|
||||
shipAlive = true;
|
||||
gameOver = false;
|
||||
showExplosion = false;
|
||||
explosionEmitter.setEmissionPoints(std::vector<Vector3f>());
|
||||
Environment::shipState.position = Vector3f{ 0, 0, 45000.f };
|
||||
Environment::shipState.velocity = 0.0f;
|
||||
Environment::shipState.selectedVelocity = 0;
|
||||
Environment::shipState.rotation = Eigen::Matrix3f::Identity();
|
||||
Environment::inverseShipMatrix = Eigen::Matrix3f::Identity();
|
||||
Environment::zoom = DEFAULT_ZOOM;
|
||||
Environment::tapDownHold = false;
|
||||
playerScore = 0;
|
||||
if (menuManager.uiManager.findButton("minusButton"))
|
||||
{
|
||||
menuManager.uiManager.findButton("minusButton")->state = ButtonState::Disabled;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void Space::setup() {
|
||||
|
||||
|
||||
menuManager.onRestartPressed = [this]() {
|
||||
this->shipAlive = true;
|
||||
this->gameOver = false;
|
||||
this->showExplosion = false;
|
||||
this->explosionEmitter.setEmissionPoints(std::vector<Vector3f>());
|
||||
Environment::shipState.position = Vector3f{ 0, 0, 45000.f };
|
||||
Environment::shipState.velocity = 0.0f;
|
||||
Environment::shipState.rotation = Eigen::Matrix3f::Identity();
|
||||
Environment::inverseShipMatrix = Eigen::Matrix3f::Identity();
|
||||
Environment::zoom = DEFAULT_ZOOM;
|
||||
Environment::tapDownHold = false;
|
||||
resetPlayerState();
|
||||
|
||||
if (networkClient) {
|
||||
try {
|
||||
@@ -276,7 +292,6 @@ namespace ZL
|
||||
std::cerr << "Client: Failed to send RESPAWN\n";
|
||||
}
|
||||
}
|
||||
this->playerScore = 0;
|
||||
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 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 explosionCfgLoaded = explosionEmitter.loadFromJsonFile("resources/config/explosion_config.json", renderer, CONST_ZIP_FILE);
|
||||
explosionEmitter.setEmissionPoints(std::vector<Vector3f>());
|
||||
@@ -413,17 +431,13 @@ namespace ZL
|
||||
|
||||
void Space::drawCubemap(float skyPercent)
|
||||
{
|
||||
static const std::string defaultShaderName = "default";
|
||||
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 envSkyShaderName = "env_sky";
|
||||
static const std::string skyPercentUniformName = "skyPercent";
|
||||
|
||||
renderer.shaderManager.PushShader(envShaderName);
|
||||
renderer.shaderManager.PushShader(envSkyShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.RenderUniform1f(skyPercentUniformName, skyPercent);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||
@@ -471,24 +485,14 @@ namespace ZL
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
}
|
||||
|
||||
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.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||
@@ -509,15 +513,17 @@ namespace ZL
|
||||
glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(spaceship);
|
||||
}
|
||||
|
||||
|
||||
drawShipSparkEmitters();
|
||||
}
|
||||
|
||||
renderer.PopMatrix();
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||
|
||||
renderer.shaderManager.PushShader("default");
|
||||
renderer.shaderManager.PushShader(defaultShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
renderer.PushMatrix();
|
||||
@@ -527,62 +533,29 @@ namespace ZL
|
||||
renderer.TranslateMatrix(-Environment::shipState.position);
|
||||
for (const auto& p : projectiles) {
|
||||
if (p && p->isActive()) {
|
||||
//p->draw(renderer);
|
||||
p->projectileEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height);
|
||||
}
|
||||
}
|
||||
renderer.PopMatrix();
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
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) {
|
||||
explosionEmitter.draw(renderer, Environment::zoom, Environment::width, Environment::height, false);
|
||||
}
|
||||
|
||||
//glBindTexture(GL_TEXTURE_2D, basePlatformTexture->getTexID());
|
||||
//renderer.DrawVertexRenderStruct(basePlatform);
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
}
|
||||
|
||||
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.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||
@@ -601,31 +574,23 @@ namespace ZL
|
||||
renderer.RotateMatrix(boxCoordsArr[i].m);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, boxTexture->getTexID());
|
||||
//glBindTexture(GL_TEXTURE_2D, rockTexture->getTexID());
|
||||
renderer.DrawVertexRenderStruct(boxRenderArr[i]);
|
||||
|
||||
renderer.PopMatrix();
|
||||
}
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
}
|
||||
|
||||
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);
|
||||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||
|
||||
glViewport(0, 0, Environment::width, Environment::height);
|
||||
|
||||
prepareSparkEmittersForDraw();
|
||||
|
||||
CheckGlError();
|
||||
|
||||
float skyPercent = 0.0;
|
||||
@@ -663,17 +628,9 @@ namespace ZL
|
||||
}
|
||||
|
||||
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.RenderUniform1i(textureUniformName, 0);
|
||||
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5,
|
||||
static_cast<float>(Environment::width) / static_cast<float>(Environment::height),
|
||||
Environment::CONST_Z_NEAR, Environment::CONST_Z_FAR);
|
||||
@@ -714,7 +671,6 @@ namespace ZL
|
||||
renderer.LoadIdentity();
|
||||
|
||||
renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom });
|
||||
//renderer.TranslateMatrix({ 0, -6.f, 0 }); //Ship camera offset
|
||||
renderer.RotateMatrix(Environment::inverseShipMatrix);
|
||||
renderer.TranslateMatrix(-Environment::shipState.position);
|
||||
|
||||
@@ -736,8 +692,6 @@ namespace ZL
|
||||
}
|
||||
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
renderer.shaderManager.PopShader();
|
||||
|
||||
CheckGlError();
|
||||
@@ -991,17 +945,11 @@ namespace ZL
|
||||
renderer.PushMatrix();
|
||||
renderer.LoadIdentity();
|
||||
|
||||
renderer.EnableVertexAttribArray("vPosition");
|
||||
renderer.EnableVertexAttribArray("vColor");
|
||||
|
||||
Eigen::Vector4f uColor(crosshairCfg.color.x(), crosshairCfg.color.y(), crosshairCfg.color.z(), crosshairCfg.alpha);
|
||||
renderer.RenderUniform4fv("uColor", uColor.data());
|
||||
|
||||
renderer.DrawVertexRenderStruct(crosshairMesh);
|
||||
|
||||
renderer.DisableVertexAttribArray("vPosition");
|
||||
renderer.DisableVertexAttribArray("vColor");
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.shaderManager.PopShader();
|
||||
@@ -1330,7 +1278,6 @@ namespace ZL
|
||||
renderer.PushMatrix();
|
||||
renderer.LoadIdentity();
|
||||
|
||||
renderer.EnableVertexAttribArray("vPosition");
|
||||
renderer.RenderUniform4fv("uColor", enemyColor.data());
|
||||
|
||||
// рамки
|
||||
@@ -1353,7 +1300,6 @@ namespace ZL
|
||||
drawLeadRing2D(lx, ly);
|
||||
}
|
||||
|
||||
renderer.DisableVertexAttribArray("vPosition");
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.shaderManager.PopShader();
|
||||
@@ -1439,7 +1385,6 @@ namespace ZL
|
||||
renderer.PushMatrix();
|
||||
renderer.LoadIdentity();
|
||||
|
||||
renderer.EnableVertexAttribArray("vPosition");
|
||||
renderer.RenderUniform4fv("uColor", enemyColor.data());
|
||||
|
||||
// стрелка
|
||||
@@ -1457,7 +1402,6 @@ namespace ZL
|
||||
drawLeadRing2D(lx, ly);
|
||||
}
|
||||
|
||||
renderer.DisableVertexAttribArray("vPosition");
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.shaderManager.PopShader();
|
||||
@@ -1476,23 +1420,93 @@ namespace ZL
|
||||
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) {
|
||||
|
||||
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)
|
||||
{
|
||||
firePressed = false;
|
||||
@@ -1580,7 +1594,7 @@ namespace ZL
|
||||
|
||||
std::string msg = "UPD:" + std::to_string(now_ms) + ":" + Environment::shipState.formPingMessageContent();
|
||||
networkClient->Send(msg);
|
||||
std::cout << "Sending: " << msg << std::endl;
|
||||
//std::cout << "Sending: " << msg << std::endl;
|
||||
}
|
||||
|
||||
long long leftoverDelta = delta;
|
||||
@@ -1624,6 +1638,8 @@ namespace ZL
|
||||
remotePlayerStates[id] = playerState;
|
||||
}
|
||||
|
||||
updateSparkEmitters(static_cast<float>(delta));
|
||||
|
||||
for (auto& p : projectiles) {
|
||||
if (p && p->isActive()) {
|
||||
p->update(static_cast<float>(delta), renderer);
|
||||
@@ -1634,42 +1650,11 @@ namespace ZL
|
||||
for (const auto& p : projectiles) {
|
||||
if (p && p->isActive()) {
|
||||
Vector3f worldPos = p->getPosition();
|
||||
//Vector3f rel = worldPos - Environment::shipState.position;
|
||||
//Vector3f camPos = Environment::inverseShipMatrix * rel;
|
||||
p->projectileEmitter.setEmissionPoints({ worldPos });
|
||||
p->projectileEmitter.emit();
|
||||
p->projectileEmitter.resetEmissionPoints({ worldPos });
|
||||
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));
|
||||
if (showExplosion) {
|
||||
@@ -1690,6 +1675,7 @@ namespace ZL
|
||||
|
||||
shipAlive = false;
|
||||
gameOver = true;
|
||||
Environment::shipState.selectedVelocity = 0;
|
||||
Environment::shipState.velocity = 0.0f;
|
||||
showExplosion = true;
|
||||
|
||||
@@ -1780,6 +1766,8 @@ namespace ZL
|
||||
}
|
||||
}
|
||||
|
||||
planetObject.update(static_cast<float>(delta));
|
||||
|
||||
// update velocity text
|
||||
|
||||
if (shipAlive && !gameOver) {
|
||||
@@ -1831,7 +1819,7 @@ namespace ZL
|
||||
gameOver = true;
|
||||
Environment::shipState.velocity = 0.0f;
|
||||
std::cout << "Client: Lost connection to server\n";
|
||||
menuManager.showGameOver(this->playerScore);
|
||||
menuManager.showConnectionLost();
|
||||
}
|
||||
|
||||
auto pending = networkClient->getPendingProjectiles();
|
||||
@@ -1927,6 +1915,7 @@ namespace ZL
|
||||
for (int pid : disconnects) {
|
||||
remotePlayerStates.erase(pid);
|
||||
deadRemotePlayers.erase(pid);
|
||||
remoteShipSparkEmitters.erase(pid);
|
||||
if (trackedTargetId == pid) {
|
||||
trackedTargetId = -1;
|
||||
targetAcquireAnim = 0.f;
|
||||
|
||||
+7
-1
@@ -66,6 +66,7 @@ namespace ZL {
|
||||
std::unique_ptr<TextRenderer> textRenderer;
|
||||
|
||||
std::unordered_map<int, ClientState> remotePlayerStates;
|
||||
std::unordered_map<int, SparkEmitter> remoteShipSparkEmitters;
|
||||
|
||||
float newShipVelocity = 0;
|
||||
|
||||
@@ -98,7 +99,7 @@ namespace ZL {
|
||||
float projectileCooldownMs = 500.0f;
|
||||
int64_t lastProjectileFireTime = 0;
|
||||
int maxProjectiles = 500;
|
||||
std::vector<Vector3f> shipLocalEmissionPoints;
|
||||
//std::vector<Vector3f> shipLocalEmissionPoints;
|
||||
|
||||
|
||||
bool shipAlive = true;
|
||||
@@ -141,8 +142,13 @@ namespace ZL {
|
||||
void drawTargetHud(); // рисует рамку или стрелку
|
||||
int pickTargetId() const; // ???????? ???? (????: ????????? ????? ????????? ?????)
|
||||
|
||||
void resetPlayerState();
|
||||
void clearTextRendererCache();
|
||||
|
||||
void updateSparkEmitters(float deltaMs);
|
||||
void prepareSparkEmittersForDraw();
|
||||
void drawShipSparkEmitters();
|
||||
|
||||
// Crosshair HUD
|
||||
struct CrosshairConfig {
|
||||
bool enabled = true;
|
||||
|
||||
+77
-59
@@ -8,6 +8,7 @@
|
||||
#include "Environment.h"
|
||||
#include <stdexcept>
|
||||
#include "utils/Utils.h"
|
||||
#include "GameConstants.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
@@ -25,12 +26,12 @@ namespace ZL {
|
||||
sparkQuad.data = VertexDataStruct();
|
||||
}
|
||||
|
||||
SparkEmitter::SparkEmitter(const SparkEmitter& copyFrom)
|
||||
SparkEmitter::SparkEmitter(const SparkEmitter& copyFrom)
|
||||
: particles(copyFrom.particles), emissionPoints(copyFrom.emissionPoints),
|
||||
lastEmissionTime(copyFrom.lastEmissionTime), emissionRate(copyFrom.emissionRate),
|
||||
isActive(copyFrom.isActive), drawPositions(copyFrom.drawPositions),
|
||||
drawTexCoords(copyFrom.drawTexCoords), drawDataDirty(copyFrom.drawDataDirty),
|
||||
sparkQuad(copyFrom.sparkQuad), texture(copyFrom.texture),
|
||||
drawTexCoords(copyFrom.drawTexCoords), drawDataDirty(true),
|
||||
texture(copyFrom.texture),
|
||||
maxParticles(copyFrom.maxParticles), particleSize(copyFrom.particleSize),
|
||||
biasX(copyFrom.biasX), speedRange(copyFrom.speedRange),
|
||||
zSpeedRange(copyFrom.zSpeedRange),
|
||||
@@ -39,6 +40,8 @@ namespace ZL {
|
||||
shaderProgramName(copyFrom.shaderProgramName),
|
||||
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;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
draw(renderer, zoom, screenWidth, screenHeight, true);
|
||||
@@ -185,46 +200,24 @@ namespace ZL {
|
||||
throw std::runtime_error("Failed to load spark emitter config file 2!");
|
||||
}
|
||||
|
||||
prepareDrawData(withRotation);
|
||||
|
||||
if (drawPositions.empty()) {
|
||||
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.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
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);
|
||||
renderer.SetMatrix();
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, texture->getTexID());
|
||||
|
||||
glEnable(GL_BLEND);
|
||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE);
|
||||
|
||||
renderer.PushMatrix();
|
||||
//renderer.LoadIdentity();
|
||||
//renderer.TranslateMatrix({ 0, 0, -1.0f * zoom });
|
||||
|
||||
//renderer.PushMatrix();
|
||||
renderer.DrawVertexRenderStruct(sparkQuad);
|
||||
|
||||
renderer.PopMatrix();
|
||||
//renderer.PopProjectionMatrix();
|
||||
//renderer.PopMatrix();
|
||||
|
||||
glDisable(GL_BLEND);
|
||||
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
renderer.shaderManager.PopShader();
|
||||
}
|
||||
|
||||
@@ -237,9 +230,19 @@ namespace ZL {
|
||||
auto elapsed = std::chrono::duration_cast<std::chrono::milliseconds>(
|
||||
currentTime - lastEmissionTime).count();
|
||||
|
||||
if (isActive && elapsed >= emissionRate) {
|
||||
emit();
|
||||
lastEmissionTime = currentTime;
|
||||
if (isActive && elapsed >= static_cast<long long>(emissionRate)) {
|
||||
int emitCount = static_cast<int>(elapsed / emissionRate);
|
||||
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;
|
||||
}
|
||||
|
||||
@@ -278,7 +281,7 @@ namespace ZL {
|
||||
}
|
||||
}
|
||||
|
||||
void SparkEmitter::emit() {
|
||||
void SparkEmitter::emit(float ageMs, float lerpT) {
|
||||
if (!configured) {
|
||||
throw std::runtime_error("Failed to load spark emitter config file 4!");
|
||||
}
|
||||
@@ -286,7 +289,30 @@ namespace ZL {
|
||||
if (emissionPoints.empty()) return;
|
||||
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;
|
||||
|
||||
for (auto& particle : particles) {
|
||||
@@ -294,8 +320,9 @@ namespace ZL {
|
||||
initParticle(particle, i);
|
||||
particle.active = true;
|
||||
particle.lifeTime = 0;
|
||||
particle.position = emissionPoints[i];
|
||||
particle.position = birthPos;
|
||||
particle.emitterIndex = i;
|
||||
applyAge(particle, ageMs);
|
||||
particleFound = true;
|
||||
emitted = true;
|
||||
break;
|
||||
@@ -304,11 +331,11 @@ namespace ZL {
|
||||
|
||||
if (!particleFound && !particles.empty()) {
|
||||
size_t oldestIndex = 0;
|
||||
float maxLifeTime = 0;
|
||||
float maxLifeRatio = 0;
|
||||
|
||||
for (size_t j = 0; j < particles.size(); ++j) {
|
||||
if (particles[j].lifeTime > maxLifeTime) {
|
||||
maxLifeTime = particles[j].lifeTime;
|
||||
if (particles[j].lifeTime > maxLifeRatio) {
|
||||
maxLifeRatio = particles[j].lifeTime;
|
||||
oldestIndex = j;
|
||||
}
|
||||
}
|
||||
@@ -316,8 +343,9 @@ namespace ZL {
|
||||
initParticle(particles[oldestIndex], i);
|
||||
particles[oldestIndex].active = true;
|
||||
particles[oldestIndex].lifeTime = 0;
|
||||
particles[oldestIndex].position = emissionPoints[i];
|
||||
particles[oldestIndex].position = birthPos;
|
||||
particles[oldestIndex].emitterIndex = i;
|
||||
applyAge(particles[oldestIndex], ageMs);
|
||||
emitted = true;
|
||||
}
|
||||
}
|
||||
@@ -328,6 +356,14 @@ namespace ZL {
|
||||
}
|
||||
|
||||
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;
|
||||
drawDataDirty = true;
|
||||
}
|
||||
@@ -495,8 +531,9 @@ namespace ZL {
|
||||
std::cout << "Total emission points: " << emissionPoints.size() << std::endl;
|
||||
}
|
||||
else {
|
||||
std::cerr << "Emission points parsed but empty" << std::endl;
|
||||
throw std::runtime_error("Failed to load spark emitter config file 10!");
|
||||
setEmissionPoints({});
|
||||
std::cout << "Emission points parsed but empty" << std::endl;
|
||||
//throw std::runtime_error("Failed to load spark emitter config file 10!");
|
||||
}
|
||||
}
|
||||
else {
|
||||
@@ -583,25 +620,6 @@ namespace ZL {
|
||||
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;
|
||||
configured = true;
|
||||
std::cout << "SparkEmitter configuration loaded successfully!" << std::endl;
|
||||
|
||||
+6
-1
@@ -26,6 +26,7 @@ namespace ZL {
|
||||
private:
|
||||
std::vector<SparkParticle> particles;
|
||||
std::vector<Vector3f> emissionPoints;
|
||||
std::vector<Vector3f> prevEmissionPoints;
|
||||
std::chrono::steady_clock::time_point lastEmissionTime;
|
||||
float emissionRate;
|
||||
bool isActive;
|
||||
@@ -62,6 +63,7 @@ namespace ZL {
|
||||
float rate = 100.0f);
|
||||
|
||||
void setEmissionPoints(const std::vector<Vector3f>& positions);
|
||||
void resetEmissionPoints(const std::vector<Vector3f>& positions);
|
||||
void setTexture(std::shared_ptr<Texture> tex);
|
||||
void setEmissionRate(float rate) { emissionRate = rate; }
|
||||
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 = "");
|
||||
|
||||
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, bool withRotation);
|
||||
|
||||
+146
-49
@@ -4,6 +4,7 @@
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
#include "GameConstants.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
@@ -61,23 +62,13 @@ namespace ZL {
|
||||
}
|
||||
if (!(*tex)) return;
|
||||
|
||||
static const std::string vPositionName = "vPosition";
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
|
||||
renderer.PushMatrix();
|
||||
renderer.TranslateMatrix({ animOffsetX, animOffsetY, 0.0f });
|
||||
renderer.ScaleMatrix({ animScaleX, animScaleY, 1.0f });
|
||||
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, (*tex)->getTexID());
|
||||
renderer.DrawVertexRenderStruct(mesh);
|
||||
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
renderer.PopMatrix();
|
||||
}
|
||||
|
||||
@@ -148,14 +139,7 @@ namespace ZL {
|
||||
}
|
||||
|
||||
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.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
if (texTrack) {
|
||||
glBindTexture(GL_TEXTURE_2D, texTrack->getTexID());
|
||||
renderer.DrawVertexRenderStruct(trackMesh);
|
||||
@@ -164,9 +148,44 @@ namespace ZL {
|
||||
glBindTexture(GL_TEXTURE_2D, texKnob->getTexID());
|
||||
renderer.DrawVertexRenderStruct(knobMesh);
|
||||
}
|
||||
}
|
||||
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
void UiStaticImage::buildMesh() {
|
||||
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 {
|
||||
@@ -249,6 +268,7 @@ namespace ZL {
|
||||
if (j.contains("horizontal_gravity")) {
|
||||
std::string hg = j["horizontal_gravity"].get<std::string>();
|
||||
if (hg == "right") node->layoutSettings.hGravity = HorizontalGravity::Right;
|
||||
else if (hg == "center") node->layoutSettings.hGravity = HorizontalGravity::Center;
|
||||
else node->layoutSettings.hGravity = HorizontalGravity::Left;
|
||||
}
|
||||
|
||||
@@ -256,6 +276,7 @@ namespace ZL {
|
||||
if (j.contains("vertical_gravity")) {
|
||||
std::string vg = j["vertical_gravity"].get<std::string>();
|
||||
if (vg == "bottom") node->layoutSettings.vGravity = VerticalGravity::Bottom;
|
||||
else if (vg == "center") node->layoutSettings.vGravity = VerticalGravity::Center;
|
||||
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") {
|
||||
auto tv = std::make_shared<UiTextView>();
|
||||
|
||||
@@ -492,6 +539,7 @@ namespace ZL {
|
||||
sliders.clear();
|
||||
textViews.clear();
|
||||
textFields.clear();
|
||||
staticImages.clear();
|
||||
collectButtonsAndSliders(root);
|
||||
|
||||
nodeActiveAnims.clear();
|
||||
@@ -503,6 +551,9 @@ namespace ZL {
|
||||
s->buildTrackMesh();
|
||||
s->buildKnobMesh();
|
||||
}
|
||||
for (auto& img : staticImages) {
|
||||
img->buildMesh();
|
||||
}
|
||||
}
|
||||
|
||||
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) {
|
||||
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) {
|
||||
fLY = currentH - childH - child->localY;
|
||||
}
|
||||
else if (child->layoutSettings.vGravity == VerticalGravity::Center) {
|
||||
fLY = (currentH - childH) / 2.0f + child->localY;
|
||||
}
|
||||
|
||||
// Передаем рассчитанные 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;
|
||||
// Аналогично для курсора и фонового меша
|
||||
}
|
||||
|
||||
// 5. Обновляем статическое изображение
|
||||
if (node->staticImage) {
|
||||
node->staticImage->rect = node->screenRect;
|
||||
node->staticImage->buildMesh();
|
||||
}
|
||||
}
|
||||
|
||||
void UiManager::updateAllLayouts() {
|
||||
@@ -690,6 +753,9 @@ namespace ZL {
|
||||
if (node->textField) {
|
||||
textFields.push_back(node->textField);
|
||||
}
|
||||
if (node->staticImage) {
|
||||
staticImages.push_back(node->staticImage);
|
||||
}
|
||||
for (auto& c : node->children) collectButtonsAndSliders(c);
|
||||
}
|
||||
|
||||
@@ -703,6 +769,16 @@ namespace ZL {
|
||||
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,
|
||||
const std::string& trackPath, const std::string& knobPath, float initialValue, bool vertical) {
|
||||
|
||||
@@ -788,8 +864,9 @@ namespace ZL {
|
||||
prev.buttons = buttons;
|
||||
prev.sliders = sliders;
|
||||
prev.textFields = textFields;
|
||||
prev.pressedButton = pressedButton;
|
||||
prev.pressedSlider = pressedSlider;
|
||||
prev.staticImages = staticImages;
|
||||
prev.pressedButtons = pressedButtons;
|
||||
prev.pressedSliders = pressedSliders;
|
||||
prev.focusedTextField = focusedTextField;
|
||||
prev.path = "";
|
||||
|
||||
@@ -838,8 +915,9 @@ namespace ZL {
|
||||
buttons = s.buttons;
|
||||
sliders = s.sliders;
|
||||
textFields = s.textFields;
|
||||
pressedButton = s.pressedButton;
|
||||
pressedSlider = s.pressedSlider;
|
||||
staticImages = s.staticImages;
|
||||
pressedButtons = s.pressedButtons;
|
||||
pressedSliders = s.pressedSliders;
|
||||
focusedTextField = s.focusedTextField;
|
||||
|
||||
animCallbacks = s.animCallbacks;
|
||||
@@ -872,6 +950,9 @@ namespace ZL {
|
||||
renderer.PushMatrix();
|
||||
renderer.LoadIdentity();
|
||||
|
||||
for (const auto& img : staticImages) {
|
||||
img->draw(renderer);
|
||||
}
|
||||
for (const auto& b : buttons) {
|
||||
b->draw(renderer);
|
||||
}
|
||||
@@ -1051,21 +1132,25 @@ namespace ZL {
|
||||
}
|
||||
}
|
||||
|
||||
void UiManager::onMouseMove(int x, int y) {
|
||||
for (auto& b : buttons) {
|
||||
if (b->state != ButtonState::Disabled)
|
||||
{
|
||||
if (b->rect.containsConsideringBorder((float)x, (float)y, b->border)) {
|
||||
if (b->state != ButtonState::Pressed) b->state = ButtonState::Hover;
|
||||
}
|
||||
else {
|
||||
if (b->state != ButtonState::Pressed) b->state = ButtonState::Normal;
|
||||
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) {
|
||||
if (b->state != ButtonState::Disabled)
|
||||
{
|
||||
if (b->rect.containsConsideringBorder((float)x, (float)y, b->border)) {
|
||||
if (b->state != ButtonState::Pressed) b->state = ButtonState::Hover;
|
||||
}
|
||||
else {
|
||||
if (b->state != ButtonState::Pressed) b->state = ButtonState::Normal;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pressedSlider) {
|
||||
auto s = pressedSlider;
|
||||
auto it = pressedSliders.find(fingerId);
|
||||
if (it != pressedSliders.end()) {
|
||||
auto s = it->second;
|
||||
float t;
|
||||
if (s->vertical) {
|
||||
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) {
|
||||
if (b->state != ButtonState::Disabled)
|
||||
{
|
||||
if (b->rect.containsConsideringBorder((float)x, (float)y, b->border)) {
|
||||
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) {
|
||||
if (s->rect.contains((float)x, (float)y)) {
|
||||
pressedSlider = s;
|
||||
pressedSliders[fingerId] = s;
|
||||
float t;
|
||||
if (s->vertical) {
|
||||
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;
|
||||
|
||||
for (auto& b : buttons) {
|
||||
if (!b) continue;
|
||||
bool contains = b->rect.contains((float)x, (float)y);
|
||||
|
||||
if (b->state == ButtonState::Pressed) {
|
||||
if (contains && pressedButton == b) {
|
||||
clicked.push_back(b);
|
||||
auto btnIt = pressedButtons.find(fingerId);
|
||||
if (btnIt != pressedButtons.end()) {
|
||||
auto b = btnIt->second;
|
||||
if (b) {
|
||||
bool contains = b->rect.contains((float)x, (float)y);
|
||||
if (b->state == ButtonState::Pressed) {
|
||||
if (contains) {
|
||||
clicked.push_back(b);
|
||||
}
|
||||
// On mouse: leave Hover if still over button. On touch: always Normal.
|
||||
b->state = (contains && fingerId == MOUSE_FINGER_ID) ? ButtonState::Hover : ButtonState::Normal;
|
||||
}
|
||||
b->state = contains ? ButtonState::Hover : ButtonState::Normal;
|
||||
}
|
||||
pressedButtons.erase(btnIt);
|
||||
}
|
||||
|
||||
pressedSliders.erase(fingerId);
|
||||
|
||||
for (auto& b : clicked) {
|
||||
if (b->onClick) {
|
||||
b->onClick(b->name);
|
||||
}
|
||||
}
|
||||
|
||||
pressedButton.reset();
|
||||
if (pressedSlider) pressedSlider.reset();
|
||||
}
|
||||
|
||||
void UiManager::onKeyPress(unsigned char key) {
|
||||
@@ -1261,6 +1351,13 @@ namespace ZL {
|
||||
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) {
|
||||
for (auto& tv : textViews) {
|
||||
if (tv->name == name) return tv;
|
||||
|
||||
+46
-8
@@ -10,6 +10,7 @@
|
||||
#include <memory>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <cstdint>
|
||||
|
||||
namespace ZL {
|
||||
|
||||
@@ -60,11 +61,13 @@ namespace ZL {
|
||||
|
||||
enum class HorizontalGravity {
|
||||
Left,
|
||||
Center,
|
||||
Right
|
||||
};
|
||||
|
||||
enum class VerticalGravity {
|
||||
Bottom, // Обычно в OpenGL Y растет вверх, так что низ - это 0
|
||||
Center,
|
||||
Top
|
||||
};
|
||||
|
||||
@@ -91,6 +94,7 @@ namespace ZL {
|
||||
VertexRenderStruct mesh;
|
||||
|
||||
std::function<void(const std::string&)> onClick;
|
||||
std::function<void(const std::string&)> onPress; // fires on touch/mouse down
|
||||
|
||||
// animation runtime
|
||||
float animOffsetX = 0.0f;
|
||||
@@ -159,6 +163,17 @@ namespace ZL {
|
||||
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 {
|
||||
std::string name;
|
||||
LayoutType layoutType = LayoutType::Frame;
|
||||
@@ -185,6 +200,7 @@ namespace ZL {
|
||||
std::shared_ptr<UiSlider> slider;
|
||||
std::shared_ptr<UiTextView> textView;
|
||||
std::shared_ptr<UiTextField> textField;
|
||||
std::shared_ptr<UiStaticImage> staticImage;
|
||||
|
||||
// Анимации
|
||||
struct AnimStep {
|
||||
@@ -210,19 +226,35 @@ namespace ZL {
|
||||
public:
|
||||
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 loadFromFile(const std::string& path, Renderer& renderer, const std::string& zipFile = "");
|
||||
|
||||
void draw(Renderer& renderer);
|
||||
|
||||
void onMouseMove(int x, int y);
|
||||
void onMouseDown(int x, int y);
|
||||
void onMouseUp(int x, int y);
|
||||
// Multi-touch methods (used directly for touch events with per-finger IDs)
|
||||
void onTouchDown(int64_t fingerId, 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 onKeyBackspace();
|
||||
|
||||
// Returns true if any finger is currently interacting with UI
|
||||
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() {
|
||||
@@ -241,6 +273,7 @@ namespace ZL {
|
||||
std::shared_ptr<UiButton> findButton(const std::string& name);
|
||||
|
||||
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,
|
||||
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);
|
||||
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 pushMenuFromSavedRoot(std::shared_ptr<UiNode> newRoot);
|
||||
bool popMenu();
|
||||
@@ -301,12 +336,14 @@ namespace ZL {
|
||||
std::vector<std::shared_ptr<UiSlider>> sliders;
|
||||
std::vector<std::shared_ptr<UiTextView>> textViews;
|
||||
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::pair<std::string, std::string>, std::function<void()>> animCallbacks; // key: (nodeName, animName)
|
||||
|
||||
std::shared_ptr<UiButton> pressedButton;
|
||||
std::shared_ptr<UiSlider> pressedSlider;
|
||||
// Per-finger tracking for multi-touch support
|
||||
std::map<int64_t, std::shared_ptr<UiButton>> pressedButtons;
|
||||
std::map<int64_t, std::shared_ptr<UiSlider>> pressedSliders;
|
||||
std::shared_ptr<UiTextField> focusedTextField;
|
||||
|
||||
struct MenuState {
|
||||
@@ -314,8 +351,9 @@ namespace ZL {
|
||||
std::vector<std::shared_ptr<UiButton>> buttons;
|
||||
std::vector<std::shared_ptr<UiSlider>> sliders;
|
||||
std::vector<std::shared_ptr<UiTextField>> textFields;
|
||||
std::shared_ptr<UiButton> pressedButton;
|
||||
std::shared_ptr<UiSlider> pressedSlider;
|
||||
std::vector<std::shared_ptr<UiStaticImage>> staticImages;
|
||||
std::map<int64_t, std::shared_ptr<UiButton>> pressedButtons;
|
||||
std::map<int64_t, std::shared_ptr<UiSlider>> pressedSliders;
|
||||
std::shared_ptr<UiTextField> focusedTextField;
|
||||
std::string path;
|
||||
std::map<std::pair<std::string, std::string>, std::function<void()>> animCallbacks;
|
||||
|
||||
+4
-68
@@ -68,10 +68,6 @@ static void applyResize(int logicalW, int logicalH) {
|
||||
SDL_SetWindowSize(ZL::Environment::window, physicalW, physicalH);
|
||||
}
|
||||
|
||||
// Обновляем ваши внутренние переменные окружения
|
||||
ZL::Environment::width = physicalW;
|
||||
ZL::Environment::height = physicalH;
|
||||
|
||||
// Пушим событие, чтобы движок пересчитал матрицы проекции
|
||||
SDL_Event e = {};
|
||||
e.type = SDL_WINDOWEVENT;
|
||||
@@ -131,7 +127,11 @@ int main(int argc, char* argv[]) {
|
||||
// канваса и отправит SDL_WINDOWEVENT_RESIZED для настройки проекции.
|
||||
applyResize(canvasW, canvasH);
|
||||
|
||||
// Prevent mouse clicks from generating fake SDL_FINGERDOWN events (desktop browser)
|
||||
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);
|
||||
|
||||
@@ -240,68 +240,6 @@ int main(int argc, char *argv[]) {
|
||||
|
||||
ZL::Environment::width = CONST_WIDTH;
|
||||
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) {
|
||||
SDL_Log("SDL init failed: %s", SDL_GetError());
|
||||
return 1;
|
||||
@@ -327,8 +265,6 @@ int main(int argc, char *argv[]) {
|
||||
game.update();
|
||||
SDL_Delay(2);
|
||||
}
|
||||
//#endif
|
||||
|
||||
}
|
||||
catch (const std::exception& e)
|
||||
{
|
||||
|
||||
@@ -34,6 +34,7 @@ namespace ZL {
|
||||
public:
|
||||
virtual ~INetworkClient() = default;
|
||||
virtual void Connect(const std::string& host, uint16_t port) = 0;
|
||||
virtual void Disconnect() {}
|
||||
virtual void Send(const std::string& message) = 0;
|
||||
virtual bool IsConnected() const = 0;
|
||||
virtual void Poll() = 0; // ƒл¤ обработки вход¤щих пакетов
|
||||
|
||||
@@ -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() {
|
||||
ws_->async_read(buffer_, [this](boost::beast::error_code ec, std::size_t bytes) {
|
||||
if (!ec) {
|
||||
|
||||
@@ -54,6 +54,7 @@ namespace ZL {
|
||||
{}
|
||||
|
||||
void Connect(const std::string& host, uint16_t port) override;
|
||||
void Disconnect() override;
|
||||
|
||||
void Poll() override;
|
||||
|
||||
|
||||
@@ -26,6 +26,15 @@ namespace ZL {
|
||||
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() {
|
||||
std::lock_guard<std::mutex> lock(outgoingMutex);
|
||||
if (!socket_) return;
|
||||
|
||||
@@ -28,6 +28,7 @@ namespace ZL {
|
||||
virtual ~WebSocketClientEmscripten() = default;
|
||||
|
||||
void Connect(const std::string& host, uint16_t port) override;
|
||||
void Disconnect() override;
|
||||
void Send(const std::string& message) override;
|
||||
void Poll() override;
|
||||
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "StoneObject.h"
|
||||
#include "utils/TaskManager.h"
|
||||
#include "TextModel.h"
|
||||
#include "GameConstants.h"
|
||||
|
||||
namespace ZL {
|
||||
|
||||
@@ -185,16 +186,10 @@ namespace ZL {
|
||||
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
||||
|
||||
|
||||
static const std::string defaultShaderName2 = "planetBake";
|
||||
static const std::string vPositionName = "vPosition";
|
||||
static const std::string vTexCoordName = "vTexCoord";
|
||||
static const std::string textureUniformName = "Texture";
|
||||
static const std::string planetBakeShaderName = "planetBake";
|
||||
|
||||
|
||||
renderer.shaderManager.PushShader(defaultShaderName2);
|
||||
renderer.shaderManager.PushShader(planetBakeShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
Triangle tr = planetData.getLodLevel().triangles[0];
|
||||
|
||||
@@ -260,8 +255,6 @@ namespace ZL {
|
||||
glDisable(GL_CULL_FACE); // Не забываем выключить, чтобы не сломать остальной рендер
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
}
|
||||
@@ -298,23 +291,12 @@ namespace ZL {
|
||||
|
||||
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";
|
||||
|
||||
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);
|
||||
auto zRange = planetData.calculateZRange(dist);
|
||||
@@ -335,10 +317,9 @@ namespace ZL {
|
||||
|
||||
const Matrix4f viewMatrix = renderer.GetCurrentModelViewMatrix();
|
||||
|
||||
renderer.RenderUniform1i("Texture", 0);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.RenderUniform1i("BakedTexture", 1);
|
||||
|
||||
|
||||
Triangle tr = planetData.getLodLevel().triangles[0]; // Берем базовый треугольник
|
||||
Matrix3f mr = GetRotationForTriangle(tr); // Та же матрица, что и при запекании
|
||||
|
||||
@@ -376,12 +357,6 @@ namespace ZL {
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
renderer.DisableVertexAttribArray(vNormalName);
|
||||
renderer.DisableVertexAttribArray("vTangent");
|
||||
renderer.DisableVertexAttribArray("vBinormal");
|
||||
renderer.DisableVertexAttribArray(vColorName);
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
|
||||
@@ -390,20 +365,10 @@ namespace ZL {
|
||||
|
||||
void PlanetObject::drawStones(Renderer& renderer)
|
||||
{
|
||||
static const std::string defaultShaderName2 = "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";
|
||||
static const std::string planetStoneShaderName = "planetStone";
|
||||
|
||||
renderer.shaderManager.PushShader(defaultShaderName2);
|
||||
renderer.shaderManager.PushShader(planetStoneShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vColorName);
|
||||
renderer.EnableVertexAttribArray(vNormalName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
|
||||
float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipState.position);
|
||||
auto zRange = planetData.calculateZRange(dist);
|
||||
@@ -468,10 +433,6 @@ namespace ZL {
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
renderer.DisableVertexAttribArray(vNormalName);
|
||||
renderer.DisableVertexAttribArray(vColorName);
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
|
||||
@@ -480,16 +441,10 @@ namespace ZL {
|
||||
|
||||
void PlanetObject::drawAtmosphere(Renderer& renderer) {
|
||||
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);
|
||||
glDepthMask(GL_FALSE);
|
||||
|
||||
renderer.shaderManager.PushShader(defaultShaderName);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vNormalName);
|
||||
|
||||
float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipState.position);
|
||||
auto zRange = planetData.calculateZRange(dist);
|
||||
float currentZNear = zRange.first;
|
||||
@@ -571,9 +526,6 @@ namespace ZL {
|
||||
glDepthMask(GL_TRUE);
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
|
||||
renderer.DisableVertexAttribArray(vNormalName);
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
|
||||
@@ -581,20 +533,8 @@ namespace ZL {
|
||||
|
||||
void PlanetObject::drawCamp(Renderer& renderer)
|
||||
{
|
||||
static const std::string defaultShaderName2 = "default";
|
||||
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(defaultShaderName);
|
||||
renderer.RenderUniform1i(textureUniformName, 0);
|
||||
renderer.EnableVertexAttribArray(vPositionName);
|
||||
renderer.EnableVertexAttribArray(vColorName);
|
||||
renderer.EnableVertexAttribArray(vNormalName);
|
||||
renderer.EnableVertexAttribArray(vTexCoordName);
|
||||
|
||||
|
||||
float dist = planetData.distanceToPlanetSurfaceFast(Environment::shipState.position);
|
||||
auto zRange = planetData.calculateZRange(dist);
|
||||
@@ -655,10 +595,6 @@ namespace ZL {
|
||||
|
||||
renderer.PopMatrix();
|
||||
renderer.PopProjectionMatrix();
|
||||
renderer.DisableVertexAttribArray(vTexCoordName);
|
||||
renderer.DisableVertexAttribArray(vNormalName);
|
||||
renderer.DisableVertexAttribArray(vColorName);
|
||||
renderer.DisableVertexAttribArray(vPositionName);
|
||||
renderer.shaderManager.PopShader();
|
||||
CheckGlError();
|
||||
|
||||
|
||||
+24
-54
@@ -50,17 +50,14 @@ namespace ZL {
|
||||
|
||||
Matrix4f r;
|
||||
|
||||
// ���������������
|
||||
r.data()[0] = 2.f / width;
|
||||
r.data()[5] = 2.f / height;
|
||||
r.data()[10] = -1.f / depthRange;
|
||||
|
||||
// ��������� �������������� �����������
|
||||
r.data()[1] = r.data()[2] = r.data()[3] = 0;
|
||||
r.data()[4] = r.data()[6] = r.data()[7] = 0;
|
||||
r.data()[8] = r.data()[9] = r.data()[11] = 0;
|
||||
|
||||
// ���������� (��������)
|
||||
r.data()[12] = -(xmax + xmin) / width;
|
||||
r.data()[13] = -(ymax + ymin) / height;
|
||||
r.data()[14] = zNear / depthRange;
|
||||
@@ -384,7 +381,7 @@ namespace ZL {
|
||||
|
||||
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)
|
||||
{
|
||||
@@ -395,7 +392,7 @@ namespace ZL {
|
||||
|
||||
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)
|
||||
@@ -407,7 +404,7 @@ namespace ZL {
|
||||
|
||||
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)
|
||||
@@ -419,7 +416,7 @@ namespace ZL {
|
||||
|
||||
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)
|
||||
@@ -431,7 +428,7 @@ namespace ZL {
|
||||
|
||||
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)
|
||||
@@ -443,7 +440,7 @@ namespace ZL {
|
||||
|
||||
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!!!!");
|
||||
}
|
||||
SetMatrix();
|
||||
}
|
||||
|
||||
void Renderer::LoadIdentity()
|
||||
@@ -703,19 +701,7 @@ namespace ZL {
|
||||
Matrix4f m = Matrix4f::Identity();
|
||||
|
||||
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;
|
||||
|
||||
if (ModelviewMatrixStack.size() == 0)
|
||||
@@ -733,17 +719,7 @@ namespace ZL {
|
||||
void Renderer::RotateMatrix(const Matrix3f& m3)
|
||||
{
|
||||
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 = ModelviewMatrixStack.top() * m;
|
||||
@@ -782,22 +758,6 @@ namespace ZL {
|
||||
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)
|
||||
{
|
||||
auto shader = shaderManager.GetCurrentShader();
|
||||
@@ -887,8 +847,25 @@ namespace ZL {
|
||||
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)
|
||||
{
|
||||
#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 vTangent("vTangent");
|
||||
static const std::string vBinormal("vBinormal");
|
||||
@@ -902,7 +879,6 @@ namespace ZL {
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.normalVBO->getBuffer());
|
||||
VertexAttribPointer3fv(vNormal, 0, NULL);
|
||||
EnableVertexAttribArray(vNormal);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -912,7 +888,6 @@ namespace ZL {
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.tangentVBO->getBuffer());
|
||||
VertexAttribPointer3fv(vTangent, 0, NULL);
|
||||
EnableVertexAttribArray(vTangent);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -922,7 +897,6 @@ namespace ZL {
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.binormalVBO->getBuffer());
|
||||
VertexAttribPointer3fv(vBinormal, 0, NULL);
|
||||
EnableVertexAttribArray(vBinormal);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -932,7 +906,6 @@ namespace ZL {
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.colorVBO->getBuffer());
|
||||
VertexAttribPointer3fv(vColor, 0, NULL);
|
||||
EnableVertexAttribArray(vColor);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -942,7 +915,6 @@ namespace ZL {
|
||||
{
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.texCoordVBO->getBuffer());
|
||||
VertexAttribPointer2fv(vTexCoord, 0, NULL);
|
||||
EnableVertexAttribArray(vTexCoord);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -951,8 +923,6 @@ namespace ZL {
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, VertexRenderStruct.positionVBO->getBuffer());
|
||||
VertexAttribPointer3fv(vPosition, 0, NULL);
|
||||
EnableVertexAttribArray(vPosition);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, static_cast<GLsizei>(VertexRenderStruct.data.PositionData.size()));
|
||||
}
|
||||
|
||||
|
||||
@@ -127,13 +127,6 @@ namespace ZL {
|
||||
|
||||
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 RenderUniformMatrix4fv(const std::string& uniformName, bool transpose, const float* 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 DisableVertexAttribArray(const std::string& attribName);
|
||||
|
||||
void DrawVertexRenderStruct(const VertexRenderStruct& VertexRenderStruct);
|
||||
};
|
||||
|
||||
|
||||
@@ -167,7 +167,6 @@ namespace ZL {
|
||||
fragmentShader = readTextFile(fragmentShaderFileName);
|
||||
}
|
||||
|
||||
///std::cout << "Shader: "<< vertexShader << std::endl;
|
||||
shaderResourceMap[shaderName] = std::make_shared<ShaderResource>(vertexShader,
|
||||
fragmentShader);
|
||||
}
|
||||
@@ -181,9 +180,26 @@ namespace ZL {
|
||||
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);
|
||||
|
||||
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!");
|
||||
}
|
||||
|
||||
auto& prevShaderAttribList = shaderResourceMap[shaderStack.top()]->attribList;
|
||||
for (auto& attrib : prevShaderAttribList)
|
||||
{
|
||||
glDisableVertexAttribArray(attrib.second);
|
||||
}
|
||||
|
||||
shaderStack.pop();
|
||||
|
||||
if (shaderStack.size() == 0) {
|
||||
glUseProgram(0);
|
||||
} 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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace ZL {
|
||||
|
||||
void PushShader(const std::string& shaderName);
|
||||
void PopShader();
|
||||
void EnableVertexAttribArrays();
|
||||
|
||||
std::shared_ptr<ShaderResource> GetCurrentShader();
|
||||
};
|
||||
|
||||
@@ -380,10 +380,6 @@ void TextRenderer::drawText(const std::string& text, float x, float y, float sca
|
||||
glActiveTexture(GL_TEXTURE0);
|
||||
glBindTexture(GL_TEXTURE_2D, atlasTexture->getTexID());
|
||||
|
||||
|
||||
r->EnableVertexAttribArray("vPosition");
|
||||
r->EnableVertexAttribArray("vTexCoord");
|
||||
|
||||
//for (size_t i = 0; i < text.length(); ++i) {
|
||||
// auto it = glyphs.find(text[i]);
|
||||
// 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);
|
||||
//}
|
||||
r->DrawVertexRenderStruct(cached.mesh);
|
||||
|
||||
r->DisableVertexAttribArray("vPosition");
|
||||
r->DisableVertexAttribArray("vTexCoord");
|
||||
r->shaderManager.PopShader();
|
||||
|
||||
// Сброс бинда текстуры не обязателен, но можно для чистоты
|
||||
|
||||
Reference in new issue
Block a user