From da8946e9ef6b4b486e12c0c35b3c858c9713b904 Mon Sep 17 00:00:00 2001 From: unknown Date: Thu, 11 Dec 2025 15:13:35 +0600 Subject: [PATCH 1/4] moving ship --- Environment.cpp | 2 +- Game.cpp | 61 +++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 50 insertions(+), 13 deletions(-) diff --git a/Environment.cpp b/Environment.cpp index 342edc6..bf53c8f 100644 --- a/Environment.cpp +++ b/Environment.cpp @@ -8,7 +8,7 @@ namespace ZL { int Environment::windowHeaderHeight = 0; int Environment::width = 0; int Environment::height = 0; -float Environment::zoom = 6.f; +float Environment::zoom = 20.f; bool Environment::leftPressed = false; bool Environment::rightPressed = false; diff --git a/Game.cpp b/Game.cpp index 75e9130..ca20430 100755 --- a/Game.cpp +++ b/Game.cpp @@ -17,6 +17,8 @@ namespace ZL const char* CONST_ZIP_FILE = ""; #endif + Matrix3f rotateShipMat = Matrix3f::Identity(); + Vector4f generateRandomQuaternion(std::mt19937& gen) { // @@ -310,6 +312,9 @@ void Game::drawShip() renderer.LoadIdentity(); renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); + renderer.RotateMatrix(Environment::inverseShipMatrix); + + renderer.RotateMatrix(rotateShipMat); glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID()); @@ -364,6 +369,7 @@ void Game::drawBoxes() renderer.shaderManager.PopShader(); CheckGlError(); } + void Game::UpdateVolumeKnob() { float musicVolumeBarButtonButtonCenterY = volumeBarMinY + musicVolume * (volumeBarMaxY - volumeBarMinY); @@ -454,7 +460,7 @@ void Game::drawScene() { drawShip(); drawBoxes(); - drawUI(); + //drawUI(); CheckGlError(); } @@ -482,6 +488,32 @@ void Game::processTickCount() { if (abs(diffy) > 5.0 || abs(diffx) > 5.0) //threshold { + float velocity = sqrtf(diffx * diffx + diffy * diffy); + + Environment::shipVelocity = velocity * delta / 100; + + Vector3f direction = { diffx, 0, -diffy }; + + Vector3f origin = { 0,0, -1 }; + + float dir_module = sqrtf(diffx * diffx + diffy * diffy); + + float scalar = direction.v[0] * origin.v[0] + direction.v[1] * origin.v[1]+ direction.v[2] * origin.v[2]; + + float angle = acos(scalar / dir_module); + + Vector4f quat = { + 0, + 1 * sin(angle / 2), + 0, + cos(angle / 2) + + }; + + rotateShipMat = QuatToMatrix(quat); + + + /* float rotationPower = sqrtf(diffx * diffx + diffy * diffy); //std::cout << rotationPower << std::endl; @@ -502,14 +534,20 @@ void Game::processTickCount() { Environment::shipMatrix = MultMatrixMatrix(Environment::shipMatrix, rotateMat); Environment::inverseShipMatrix = InverseMatrix(Environment::shipMatrix); - + */ + } + else + { + Environment::shipVelocity = 0; } } if (fabs(Environment::shipVelocity) > 0.01f) { Vector3f velocityDirection = { 0,0, -Environment::shipVelocity*delta / 1000.f }; - Vector3f velocityDirectionAdjusted = MultMatrixVector(Environment::shipMatrix, velocityDirection); + + + Vector3f velocityDirectionAdjusted = MultMatrixVector(rotateShipMat, velocityDirection); Environment::shipPosition = Environment::shipPosition + velocityDirectionAdjusted; } @@ -546,12 +584,12 @@ void Game::update() { std::cout << mx << " " << my << '\n'; int uiX = mx; int uiY = Environment::height - my; - if (uiX >= volumeBarMinX && uiX <= volumeBarMaxX && - uiY >= volumeBarMinY && uiY <= volumeBarMaxY) { - isDraggingVolume = true; - UpdateVolumeFromMouse(mx, my); + + if (false) + { } - else { + else + { Environment::tapDownHold = true; // Environment::tapDownStartPos.v[0] = event.button.x; @@ -561,21 +599,19 @@ void Game::update() { Environment::tapDownCurrentPos.v[1] = event.button.y; } + } else if (event.type == SDL_MOUSEBUTTONUP) { // 2. isDraggingVolume = false; Environment::tapDownHold = false; + Environment::shipVelocity = 0; } else if (event.type == SDL_MOUSEMOTION) { // 3. int mx = event.motion.x; int my = event.motion.y; - if (isDraggingVolume) { - // - UpdateVolumeFromMouse(mx, my); - } if (Environment::tapDownHold) { // , Environment::tapDownCurrentPos.v[0] = event.motion.x; @@ -596,6 +632,7 @@ void Game::update() { } else if (event.type == SDL_KEYUP) { + if (event.key.keysym.sym == SDLK_i) { Environment::shipVelocity += 1.f; From 47fe0c471921d1da3439a8a9f2328085d0a38d69 Mon Sep 17 00:00:00 2001 From: Ariari04 Date: Thu, 11 Dec 2025 21:14:39 +0600 Subject: [PATCH 2/4] added ship control --- Game.cpp | 20 ++++---------------- 1 file changed, 4 insertions(+), 16 deletions(-) diff --git a/Game.cpp b/Game.cpp index ca20430..81e6275 100755 --- a/Game.cpp +++ b/Game.cpp @@ -492,23 +492,11 @@ void Game::processTickCount() { Environment::shipVelocity = velocity * delta / 100; - Vector3f direction = { diffx, 0, -diffy }; + Vector3f dir = { -diffx, 0, diffy }; + float angle = atan2(dir.v[0], -dir.v[2]); // [-pi, pi] + Vector4f quat = { 0, sin(angle * 0.5f), 0, cos(angle * 0.5f) }; + rotateShipMat = QuatToMatrix(quat); - Vector3f origin = { 0,0, -1 }; - - float dir_module = sqrtf(diffx * diffx + diffy * diffy); - - float scalar = direction.v[0] * origin.v[0] + direction.v[1] * origin.v[1]+ direction.v[2] * origin.v[2]; - - float angle = acos(scalar / dir_module); - - Vector4f quat = { - 0, - 1 * sin(angle / 2), - 0, - cos(angle / 2) - - }; rotateShipMat = QuatToMatrix(quat); From 96deb8b3938d882b40383bce660778096d086786 Mon Sep 17 00:00:00 2001 From: Ariari04 Date: Mon, 29 Dec 2025 18:59:06 +0600 Subject: [PATCH 3/4] corrected moving ship added moving camera --- Game.cpp | 1333 ++++++++++++++++++++++++++++-------------------------- Game.h | 168 +++---- 2 files changed, 783 insertions(+), 718 deletions(-) diff --git a/Game.cpp b/Game.cpp index 81e6275..3d80da7 100755 --- a/Game.cpp +++ b/Game.cpp @@ -1,637 +1,698 @@ -#include "Game.h" -#include "AnimatedModel.h" -#include "BoneAnimatedModel.h" -#include "Utils.h" -#include "OpenGlExtensions.h" -#include -#include "TextureManager.h" -#include "TextModel.h" -#include -#include - -namespace ZL -{ -#ifdef EMSCRIPTEN - const char* CONST_ZIP_FILE = "space-game001.zip"; -#else - const char* CONST_ZIP_FILE = ""; -#endif - - Matrix3f rotateShipMat = Matrix3f::Identity(); - - Vector4f generateRandomQuaternion(std::mt19937& gen) - { - // - std::normal_distribution<> distrib(0.0, 1.0); - - // N(0, 1). - // 4D- (.. ). - Vector4f randomQuat = { - (float)distrib(gen), - (float)distrib(gen), - (float)distrib(gen), - (float)distrib(gen) - }; - - return randomQuat.normalized(); - } - - - // --- --- - std::vector generateRandomBoxCoords(int N) - { - // - const float MIN_DISTANCE = 3.0f; - const float MIN_DISTANCE_SQUARED = MIN_DISTANCE * MIN_DISTANCE; // - const float MIN_COORD = -100.0f; - const float MAX_COORD = 100.0f; - const int MAX_ATTEMPTS = 1000; // , - - std::vector boxCoordsArr; - boxCoordsArr.reserve(N); // - - // 1. - // Mersenne Twister (mt19937) - std::random_device rd; - std::mt19937 gen(rd()); - - // 2. [MIN_COORD, MAX_COORD] - std::uniform_real_distribution<> distrib(MIN_COORD, MAX_COORD); - - int generatedCount = 0; - - while (generatedCount < N) - { - bool accepted = false; - int attempts = 0; - - // - while (!accepted && attempts < MAX_ATTEMPTS) - { - // - Vector3f newPos( - (float)distrib(gen), - (float)distrib(gen), - (float)distrib(gen) - ); - - // - accepted = true; // , , - for (const auto& existingBox : boxCoordsArr) - { - // - Vector3f diff = newPos - existingBox.pos; - - // - float distanceSquared = diff.squaredNorm(); - - // - if (distanceSquared < MIN_DISTANCE_SQUARED) - { - accepted = false; // , - break; // , - } - } - - if (accepted) - { - // 2. - Vector4f randomQuat = generateRandomQuaternion(gen); - - // 3. - Matrix3f randomMatrix = QuatToMatrix(randomQuat); - - // 4. - boxCoordsArr.emplace_back(BoxCoords{ newPos, randomMatrix }); - generatedCount++; - } - attempts++; - } - - // , , - // , N . - if (!accepted) { - std::cerr << ": " << N << " . : " << generatedCount << std::endl; - break; - } - } - - return boxCoordsArr; - } - -Game::Game() - : window(nullptr) - , glContext(nullptr) - , newTickCount(0) - , lastTickCount(0) -{ -} - -Game::~Game() { - if (glContext) { - SDL_GL_DeleteContext(glContext); - } - if (window) { - SDL_DestroyWindow(window); - } - SDL_Quit(); -} - -void Game::setup() { - glContext = SDL_GL_CreateContext(ZL::Environment::window); - - ZL::BindOpenGlFunctions(); - ZL::CheckGlError(); - - // Initialize renderer - -#ifdef EMSCRIPTEN - renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_web.fragment", CONST_ZIP_FILE); - renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_web.fragment", CONST_ZIP_FILE); - renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_web.fragment", CONST_ZIP_FILE); - -#else - renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE); - renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_desktop.fragment", CONST_ZIP_FILE); - renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_desktop.fragment", CONST_ZIP_FILE); - -#endif - - cubemapTexture = std::make_shared( - std::array{ - CreateTextureDataFromBmp24("./resources/sky/space_rt.bmp", CONST_ZIP_FILE), - CreateTextureDataFromBmp24("./resources/sky/space_lf.bmp", CONST_ZIP_FILE), - CreateTextureDataFromBmp24("./resources/sky/space_up.bmp", CONST_ZIP_FILE), - CreateTextureDataFromBmp24("./resources/sky/space_dn.bmp", CONST_ZIP_FILE), - CreateTextureDataFromBmp24("./resources/sky/space_bk.bmp", CONST_ZIP_FILE), - CreateTextureDataFromBmp24("./resources/sky/space_ft.bmp", CONST_ZIP_FILE) - }); - - - cubemap.data = ZL::CreateCubemap(500); - cubemap.RefreshVBO(); - - //Load texture - spaceshipTexture = std::make_unique(CreateTextureDataFromPng("./resources/DefaultMaterial_BaseColor.png", CONST_ZIP_FILE)); - spaceshipBase = LoadFromTextFile02("./resources/spaceship005.txt", CONST_ZIP_FILE); - spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0))); - //spaceshipBase.Move(Vector3f{ -0.52998, -13, 0 }); - spaceshipBase.Move(Vector3f{ -0.52998, -10, 10 }); - - spaceship.AssignFrom(spaceshipBase); - spaceship.RefreshVBO(); - - //Boxes - boxTexture = std::make_unique(CreateTextureDataFromPng("./resources/box/box.png", CONST_ZIP_FILE)); - boxBase = LoadFromTextFile02("./resources/box/box.txt", CONST_ZIP_FILE); - - boxCoordsArr = generateRandomBoxCoords(50); - - boxRenderArr.resize(boxCoordsArr.size()); - - for (int i = 0; i < boxCoordsArr.size(); i++) - { - boxRenderArr[i].AssignFrom(boxBase); - boxRenderArr[i].RefreshVBO(); - } - - - buttonTexture = std::make_unique(CreateTextureDataFromPng("./resources/button.png", CONST_ZIP_FILE)); - - button.data.PositionData.push_back({ 100, 100, 0 }); - button.data.PositionData.push_back({ 100, 150, 0 }); - button.data.PositionData.push_back({ 300, 150, 0 }); - button.data.PositionData.push_back({ 100, 100, 0 }); - button.data.PositionData.push_back({ 300, 150, 0 }); - button.data.PositionData.push_back({ 300, 100, 0 }); - - button.data.TexCoordData.push_back({ 0,0 }); - button.data.TexCoordData.push_back({ 0,1 }); - button.data.TexCoordData.push_back({ 1,1 }); - button.data.TexCoordData.push_back({ 0,0 }); - button.data.TexCoordData.push_back({ 1,1 }); - button.data.TexCoordData.push_back({ 1,0 }); - - button.RefreshVBO(); - - musicVolumeBarTexture = std::make_unique(CreateTextureDataFromPng("./resources/musicVolumeBarTexture.png", CONST_ZIP_FILE)); - - musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 }); - musicVolumeBar.data.PositionData.push_back({ 1190, 600, 0 }); - musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 }); - musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 }); - musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 }); - musicVolumeBar.data.PositionData.push_back({ 1200, 100, 0 }); - - musicVolumeBar.data.TexCoordData.push_back({ 0,0 }); - musicVolumeBar.data.TexCoordData.push_back({ 0,1 }); - musicVolumeBar.data.TexCoordData.push_back({ 1,1 }); - musicVolumeBar.data.TexCoordData.push_back({ 0,0 }); - musicVolumeBar.data.TexCoordData.push_back({ 1,1 }); - musicVolumeBar.data.TexCoordData.push_back({ 1,0 }); - - musicVolumeBar.RefreshVBO(); - - - musicVolumeBarButtonTexture = std::make_unique(CreateTextureDataFromPng("./resources/musicVolumeBarButton.png", CONST_ZIP_FILE)); - - float musicVolumeBarButtonButtonCenterY = 350.0f; - - musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 }); - musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 }); - musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 }); - musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 }); - musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 }); - musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 }); - - musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 }); - musicVolumeBarButton.data.TexCoordData.push_back({ 0,1 }); - musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 }); - musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 }); - musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 }); - musicVolumeBarButton.data.TexCoordData.push_back({ 1,0 }); - - musicVolumeBarButton.RefreshVBO(); - renderer.InitOpenGL(); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - -} - -void Game::drawCubemap() -{ - 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(envShaderName); - renderer.RenderUniform1i(textureUniformName, 0); - renderer.EnableVertexAttribArray(vPositionName); - renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, - static_cast(Environment::width) / static_cast(Environment::height), - 1, 1000); - renderer.PushMatrix(); - renderer.LoadIdentity(); - renderer.RotateMatrix(Environment::inverseShipMatrix); - - CheckGlError(); - - glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture->getTexID()); - renderer.DrawVertexRenderStruct(cubemap); - - CheckGlError(); - - - renderer.PopMatrix(); - renderer.PopProjectionMatrix(); - renderer.DisableVertexAttribArray(vPositionName); - - renderer.shaderManager.PopShader(); - CheckGlError(); -} - -void Game::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(Environment::width) / static_cast(Environment::height), - 1, 1000); - renderer.PushMatrix(); - - renderer.LoadIdentity(); - renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); - renderer.RotateMatrix(Environment::inverseShipMatrix); - - renderer.RotateMatrix(rotateShipMat); - - - glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID()); - renderer.DrawVertexRenderStruct(spaceship); - - renderer.PopMatrix(); - renderer.PopProjectionMatrix(); - renderer.DisableVertexAttribArray(vPositionName); - renderer.DisableVertexAttribArray(vTexCoordName); - - renderer.shaderManager.PopShader(); - CheckGlError(); -} - -void Game::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(Environment::width) / static_cast(Environment::height), - 1, 1000); - - for (int i = 0; i < boxCoordsArr.size(); i++) - { - renderer.PushMatrix(); - - renderer.LoadIdentity(); - renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); - renderer.RotateMatrix(Environment::inverseShipMatrix); - renderer.TranslateMatrix(-Environment::shipPosition); - renderer.TranslateMatrix(boxCoordsArr[i].pos); - renderer.RotateMatrix(boxCoordsArr[i].m); - - glBindTexture(GL_TEXTURE_2D, boxTexture->getTexID()); - renderer.DrawVertexRenderStruct(boxRenderArr[i]); - - renderer.PopMatrix(); - } - renderer.PopProjectionMatrix(); - renderer.DisableVertexAttribArray(vPositionName); - renderer.DisableVertexAttribArray(vTexCoordName); - - renderer.shaderManager.PopShader(); - CheckGlError(); -} - -void Game::UpdateVolumeKnob() { - float musicVolumeBarButtonButtonCenterY = volumeBarMinY + musicVolume * (volumeBarMaxY - volumeBarMinY); - - auto& pos = musicVolumeBarButton.data.PositionData; - - pos[0] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 }; - pos[1] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 }; - pos[2] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 }; - pos[3] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 }; - pos[4] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 }; - pos[5] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 }; - - musicVolumeBarButton.RefreshVBO(); - -} - -void Game::UpdateVolumeFromMouse(int mouseX, int mouseY) { - - int uiX = mouseX; - int uiY = Environment::height - mouseY; - Environment::shipVelocity = (musicVolume - 0.2) * (20.0); - if (uiY < volumeBarMinY || uiY > volumeBarMaxY) - { - return; - } - - float t = (uiY - volumeBarMinY) / (volumeBarMaxY - volumeBarMinY); - if (t < 0.0f) t = 0.0f; - if (t > 1.0f) t = 1.0f; - musicVolume = t; - UpdateVolumeKnob(); -} -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.PushProjectionMatrix(Environment::width, Environment::height, -1, 1); - renderer.PushMatrix(); - - renderer.LoadIdentity(); - - - glBindTexture(GL_TEXTURE_2D, buttonTexture->getTexID()); - renderer.DrawVertexRenderStruct(button); - - glBindTexture(GL_TEXTURE_2D, musicVolumeBarTexture->getTexID()); - renderer.DrawVertexRenderStruct(musicVolumeBar); - - glBindTexture(GL_TEXTURE_2D, musicVolumeBarButtonTexture->getTexID()); - renderer.DrawVertexRenderStruct(musicVolumeBarButton); - - renderer.PopMatrix(); - renderer.PopProjectionMatrix(); - renderer.DisableVertexAttribArray(vPositionName); - renderer.DisableVertexAttribArray(vTexCoordName); - - renderer.shaderManager.PopShader(); - CheckGlError(); -} - -void Game::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, 0.5f, 1.0f, 1.0f); - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - - glViewport(0, 0, Environment::width, Environment::height); - - CheckGlError(); - - drawCubemap(); - drawShip(); - drawBoxes(); - - //drawUI(); - - CheckGlError(); -} - -void Game::processTickCount() { - - if (lastTickCount == 0) { - lastTickCount = SDL_GetTicks64(); - return; - } - - newTickCount = SDL_GetTicks64(); - if (newTickCount - lastTickCount > CONST_TIMER_INTERVAL) { - size_t delta = (newTickCount - lastTickCount > CONST_MAX_TIME_INTERVAL) ? - CONST_MAX_TIME_INTERVAL : newTickCount - lastTickCount; - - //gameObjects.updateScene(delta); - - if (Environment::tapDownHold) { - - float diffx = Environment::tapDownCurrentPos.v[0] - Environment::tapDownStartPos.v[0]; - float diffy = Environment::tapDownCurrentPos.v[1] - Environment::tapDownStartPos.v[1]; - - - if (abs(diffy) > 5.0 || abs(diffx) > 5.0) //threshold - { - - float velocity = sqrtf(diffx * diffx + diffy * diffy); - - Environment::shipVelocity = velocity * delta / 100; - - Vector3f dir = { -diffx, 0, diffy }; - float angle = atan2(dir.v[0], -dir.v[2]); // [-pi, pi] - Vector4f quat = { 0, sin(angle * 0.5f), 0, cos(angle * 0.5f) }; - rotateShipMat = QuatToMatrix(quat); - - - rotateShipMat = QuatToMatrix(quat); - - - /* - float rotationPower = sqrtf(diffx * diffx + diffy * diffy); - - //std::cout << rotationPower << std::endl; - - float deltaAlpha = rotationPower * delta * M_PI / 500000.f; - - Vector3f rotationDirection = { diffy, diffx, 0 }; - - rotationDirection = rotationDirection.normalized(); - - Vector4f rotateQuat = { - rotationDirection.v[0] * sin(deltaAlpha * 0.5f), - rotationDirection.v[1] * sin(deltaAlpha * 0.5f), - rotationDirection.v[2] * sin(deltaAlpha * 0.5f), - cos(deltaAlpha * 0.5f) }; - - Matrix3f rotateMat = QuatToMatrix(rotateQuat); - - Environment::shipMatrix = MultMatrixMatrix(Environment::shipMatrix, rotateMat); - Environment::inverseShipMatrix = InverseMatrix(Environment::shipMatrix); - */ - } - else - { - Environment::shipVelocity = 0; - } - } - - if (fabs(Environment::shipVelocity) > 0.01f) - { - Vector3f velocityDirection = { 0,0, -Environment::shipVelocity*delta / 1000.f }; - - - Vector3f velocityDirectionAdjusted = MultMatrixVector(rotateShipMat, velocityDirection); - - Environment::shipPosition = Environment::shipPosition + velocityDirectionAdjusted; - } - - lastTickCount = newTickCount; - } -} - -void Game::render() { - SDL_GL_MakeCurrent(ZL::Environment::window, glContext); - ZL::CheckGlError(); - - glClearColor(0.0f, 1.0f, 0.0f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - drawScene(); - processTickCount(); - - SDL_GL_SwapWindow(ZL::Environment::window); -} -void Game::update() { - SDL_Event event; - while (SDL_PollEvent(&event)) { - if (event.type == SDL_QUIT) { - Environment::exitGameLoop = true; - - } - else if (event.type == SDL_MOUSEBUTTONDOWN) { - // 1. - - int mx = event.button.x; - int my = event.button.y; - - std::cout << mx << " " << my << '\n'; - int uiX = mx; - int uiY = Environment::height - my; - - if (false) - { - } - else - { - Environment::tapDownHold = true; - // - Environment::tapDownStartPos.v[0] = event.button.x; - Environment::tapDownStartPos.v[1] = event.button.y; - // - Environment::tapDownCurrentPos.v[0] = event.button.x; - Environment::tapDownCurrentPos.v[1] = event.button.y; - } - - - } - else if (event.type == SDL_MOUSEBUTTONUP) { - // 2. - isDraggingVolume = false; - Environment::tapDownHold = false; - Environment::shipVelocity = 0; - } - else if (event.type == SDL_MOUSEMOTION) { - // 3. - int mx = event.motion.x; - int my = event.motion.y; - - if (Environment::tapDownHold) { - // , - Environment::tapDownCurrentPos.v[0] = event.motion.x; - Environment::tapDownCurrentPos.v[1] = event.motion.y; - } - } - else if (event.type == SDL_MOUSEWHEEL) { - static const float zoomstep = 2.0f; - if (event.wheel.y > 0) { - Environment::zoom -= zoomstep; - } - else if (event.wheel.y < 0) { - Environment::zoom += zoomstep; - } - if (Environment::zoom < zoomstep) { - Environment::zoom = zoomstep; - } - } - else if (event.type == SDL_KEYUP) - { - - if (event.key.keysym.sym == SDLK_i) - { - Environment::shipVelocity += 1.f; - } - if (event.key.keysym.sym == SDLK_k) - { - Environment::shipVelocity -= 1.f; - } - } - } - render(); -} - +#include "Game.h" +#include "AnimatedModel.h" +#include "BoneAnimatedModel.h" +#include "Utils.h" +#include "OpenGlExtensions.h" +#include +#include "TextureManager.h" +#include "TextModel.h" +#include +#include + +namespace ZL +{ +#ifdef EMSCRIPTEN + const char* CONST_ZIP_FILE = "space-game001.zip"; +#else + const char* CONST_ZIP_FILE = ""; +#endif + + Matrix3f rotateShipMat = Matrix3f::Identity(); + + Vector4f generateRandomQuaternion(std::mt19937& gen) + { + // Распределение для генерации случайных координат кватерниона + std::normal_distribution<> distrib(0.0, 1.0); + + // Генерируем четыре случайных числа из нормального распределения N(0, 1). + // Нормализация этого вектора дает равномерное распределение по 4D-сфере (т.е. кватернион единичной длины). + Vector4f randomQuat = { + (float)distrib(gen), + (float)distrib(gen), + (float)distrib(gen), + (float)distrib(gen) + }; + + return randomQuat.normalized(); + } + + + // --- Основная функция генерации --- + std::vector generateRandomBoxCoords(int N) + { + // Константы + const float MIN_DISTANCE = 3.0f; + const float MIN_DISTANCE_SQUARED = MIN_DISTANCE * MIN_DISTANCE; // Работаем с квадратом расстояния + const float MIN_COORD = -100.0f; + const float MAX_COORD = 100.0f; + const int MAX_ATTEMPTS = 1000; // Ограничение на количество попыток, чтобы избежать бесконечного цикла + + std::vector boxCoordsArr; + boxCoordsArr.reserve(N); // Резервируем память + + // 1. Инициализация генератора псевдослучайных чисел + // Используем Mersenne Twister (mt19937) как высококачественный генератор + std::random_device rd; + std::mt19937 gen(rd()); + + // 2. Определение равномерного распределения для координат [MIN_COORD, MAX_COORD] + std::uniform_real_distribution<> distrib(MIN_COORD, MAX_COORD); + + int generatedCount = 0; + + while (generatedCount < N) + { + bool accepted = false; + int attempts = 0; + + // Попытка найти подходящие координаты + while (!accepted && attempts < MAX_ATTEMPTS) + { + // Генерируем новые случайные координаты + Vector3f newPos( + (float)distrib(gen), + (float)distrib(gen), + (float)distrib(gen) + ); + + // Проверка расстояния до всех уже существующих объектов + accepted = true; // Предполагаем, что подходит, пока не доказано обратное + for (const auto& existingBox : boxCoordsArr) + { + // Расчет вектора разности + Vector3f diff = newPos - existingBox.pos; + + // Расчет квадрата расстояния + float distanceSquared = diff.squaredNorm(); + + // Если квадрат расстояния меньше квадрата минимального расстояния + if (distanceSquared < MIN_DISTANCE_SQUARED) + { + accepted = false; // Отклоняем, слишком близко + break; // Нет смысла проверять дальше, если одно нарушение найдено + } + } + + if (accepted) + { + // 2. Генерируем случайный кватернион + Vector4f randomQuat = generateRandomQuaternion(gen); + + // 3. Преобразуем его в матрицу вращения + Matrix3f randomMatrix = QuatToMatrix(randomQuat); + + // 4. Добавляем объект с новой случайной матрицей + boxCoordsArr.emplace_back(BoxCoords{ newPos, randomMatrix }); + generatedCount++; + } + attempts++; + } + + // Если превышено максимальное количество попыток, выходим из цикла, + // чтобы избежать зависания, если N слишком велико или диапазон слишком мал. + if (!accepted) { + std::cerr << "Предупреждение: Не удалось сгенерировать " << N << " объектов. Сгенерировано: " << generatedCount << std::endl; + break; + } + } + + return boxCoordsArr; + } + +Game::Game() + : window(nullptr) + , glContext(nullptr) + , newTickCount(0) + , lastTickCount(0) +{ +} + +Game::~Game() { + if (glContext) { + SDL_GL_DeleteContext(glContext); + } + if (window) { + SDL_DestroyWindow(window); + } + SDL_Quit(); +} + +void Game::setup() { + glContext = SDL_GL_CreateContext(ZL::Environment::window); + + ZL::BindOpenGlFunctions(); + ZL::CheckGlError(); + + // Initialize renderer + +#ifdef EMSCRIPTEN + renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_web.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_web.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_web.fragment", CONST_ZIP_FILE); + +#else + renderer.shaderManager.AddShaderFromFiles("default", "./shaders/default.vertex", "./shaders/default_desktop.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("defaultColor", "./shaders/defaultColor.vertex", "./shaders/defaultColor_desktop.fragment", CONST_ZIP_FILE); + renderer.shaderManager.AddShaderFromFiles("env", "./shaders/env.vertex", "./shaders/env_desktop.fragment", CONST_ZIP_FILE); + +#endif + + cubemapTexture = std::make_shared( + std::array{ + CreateTextureDataFromBmp24("./resources/sky/space_rt.bmp", CONST_ZIP_FILE), + CreateTextureDataFromBmp24("./resources/sky/space_lf.bmp", CONST_ZIP_FILE), + CreateTextureDataFromBmp24("./resources/sky/space_up.bmp", CONST_ZIP_FILE), + CreateTextureDataFromBmp24("./resources/sky/space_dn.bmp", CONST_ZIP_FILE), + CreateTextureDataFromBmp24("./resources/sky/space_bk.bmp", CONST_ZIP_FILE), + CreateTextureDataFromBmp24("./resources/sky/space_ft.bmp", CONST_ZIP_FILE) + }); + + + cubemap.data = ZL::CreateCubemap(500); + cubemap.RefreshVBO(); + + //Load texture + spaceshipTexture = std::make_unique(CreateTextureDataFromPng("./resources/DefaultMaterial_BaseColor.png", CONST_ZIP_FILE)); + spaceshipBase = LoadFromTextFile02("./resources/spaceship005.txt", CONST_ZIP_FILE); + spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0))); + //spaceshipBase.Move(Vector3f{ -0.52998, -13, 0 }); + spaceshipBase.Move(Vector3f{ -0.52998, -10, 10 }); + + spaceship.AssignFrom(spaceshipBase); + spaceship.RefreshVBO(); + + //Boxes + boxTexture = std::make_unique(CreateTextureDataFromPng("./resources/box/box.png", CONST_ZIP_FILE)); + boxBase = LoadFromTextFile02("./resources/box/box.txt", CONST_ZIP_FILE); + + boxCoordsArr = generateRandomBoxCoords(50); + + boxRenderArr.resize(boxCoordsArr.size()); + + for (int i = 0; i < boxCoordsArr.size(); i++) + { + boxRenderArr[i].AssignFrom(boxBase); + boxRenderArr[i].RefreshVBO(); + } + + + buttonTexture = std::make_unique(CreateTextureDataFromPng("./resources/button.png", CONST_ZIP_FILE)); + + button.data.PositionData.push_back({ 100, 100, 0 }); + button.data.PositionData.push_back({ 100, 150, 0 }); + button.data.PositionData.push_back({ 300, 150, 0 }); + button.data.PositionData.push_back({ 100, 100, 0 }); + button.data.PositionData.push_back({ 300, 150, 0 }); + button.data.PositionData.push_back({ 300, 100, 0 }); + + button.data.TexCoordData.push_back({ 0,0 }); + button.data.TexCoordData.push_back({ 0,1 }); + button.data.TexCoordData.push_back({ 1,1 }); + button.data.TexCoordData.push_back({ 0,0 }); + button.data.TexCoordData.push_back({ 1,1 }); + button.data.TexCoordData.push_back({ 1,0 }); + + button.RefreshVBO(); + + musicVolumeBarTexture = std::make_unique(CreateTextureDataFromPng("./resources/musicVolumeBarTexture.png", CONST_ZIP_FILE)); + + musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 }); + musicVolumeBar.data.PositionData.push_back({ 1190, 600, 0 }); + musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 }); + musicVolumeBar.data.PositionData.push_back({ 1190, 100, 0 }); + musicVolumeBar.data.PositionData.push_back({ 1200, 600, 0 }); + musicVolumeBar.data.PositionData.push_back({ 1200, 100, 0 }); + + musicVolumeBar.data.TexCoordData.push_back({ 0,0 }); + musicVolumeBar.data.TexCoordData.push_back({ 0,1 }); + musicVolumeBar.data.TexCoordData.push_back({ 1,1 }); + musicVolumeBar.data.TexCoordData.push_back({ 0,0 }); + musicVolumeBar.data.TexCoordData.push_back({ 1,1 }); + musicVolumeBar.data.TexCoordData.push_back({ 1,0 }); + + musicVolumeBar.RefreshVBO(); + + + musicVolumeBarButtonTexture = std::make_unique(CreateTextureDataFromPng("./resources/musicVolumeBarButton.png", CONST_ZIP_FILE)); + + float musicVolumeBarButtonButtonCenterY = 350.0f; + + musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 }); + musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 }); + musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 }); + musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 }); + musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 }); + musicVolumeBarButton.data.PositionData.push_back({ musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 }); + + musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 }); + musicVolumeBarButton.data.TexCoordData.push_back({ 0,1 }); + musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 }); + musicVolumeBarButton.data.TexCoordData.push_back({ 0,0 }); + musicVolumeBarButton.data.TexCoordData.push_back({ 1,1 }); + musicVolumeBarButton.data.TexCoordData.push_back({ 1,0 }); + + musicVolumeBarButton.RefreshVBO(); + renderer.InitOpenGL(); + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + +} + +void Game::drawCubemap() +{ + 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(envShaderName); + renderer.RenderUniform1i(textureUniformName, 0); + renderer.EnableVertexAttribArray(vPositionName); + renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, + static_cast(Environment::width) / static_cast(Environment::height), + 1, 1000); + renderer.PushMatrix(); + renderer.LoadIdentity(); + renderer.RotateMatrix(Environment::inverseShipMatrix); + + CheckGlError(); + + glBindTexture(GL_TEXTURE_CUBE_MAP, cubemapTexture->getTexID()); + renderer.DrawVertexRenderStruct(cubemap); + + CheckGlError(); + + + renderer.PopMatrix(); + renderer.PopProjectionMatrix(); + renderer.DisableVertexAttribArray(vPositionName); + + renderer.shaderManager.PopShader(); + CheckGlError(); +} + +void Game::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(Environment::width) / static_cast(Environment::height), + 1, 1000); + renderer.PushMatrix(); + + renderer.LoadIdentity(); + renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); + + // Используем зафиксированную камеру для отрисовки, если lock активен + // Это обеспечит правильную ориентацию модели относительно начальной позиции камеры + if (shipMoveLockActive) { + Matrix3f inverseLockedCamera = InverseMatrix(lockedCameraMat); + renderer.RotateMatrix(inverseLockedCamera); + } else { + renderer.RotateMatrix(Environment::inverseShipMatrix); + } + + renderer.RotateMatrix(rotateShipMat); + + // Компенсируем начальный поворот модели на 90° вокруг Y, чтобы модель смотрела в направлении движения + // Модель изначально повёрнута на M_PI / 2.0 вокруг Y, поэтому добавляем компенсацию + Vector4f correctionQuat = QuatFromRotateAroundY(M_PI / 2.0f); + renderer.RotateMatrix(correctionQuat); + + + glBindTexture(GL_TEXTURE_2D, spaceshipTexture->getTexID()); + renderer.DrawVertexRenderStruct(spaceship); + + renderer.PopMatrix(); + renderer.PopProjectionMatrix(); + renderer.DisableVertexAttribArray(vPositionName); + renderer.DisableVertexAttribArray(vTexCoordName); + + renderer.shaderManager.PopShader(); + CheckGlError(); +} + +void Game::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(Environment::width) / static_cast(Environment::height), + 1, 1000); + + for (int i = 0; i < boxCoordsArr.size(); i++) + { + renderer.PushMatrix(); + + renderer.LoadIdentity(); + renderer.TranslateMatrix({ 0,0, -1.0f * Environment::zoom }); + renderer.RotateMatrix(Environment::inverseShipMatrix); + renderer.TranslateMatrix(-Environment::shipPosition); + renderer.TranslateMatrix(boxCoordsArr[i].pos); + renderer.RotateMatrix(boxCoordsArr[i].m); + + glBindTexture(GL_TEXTURE_2D, boxTexture->getTexID()); + renderer.DrawVertexRenderStruct(boxRenderArr[i]); + + renderer.PopMatrix(); + } + renderer.PopProjectionMatrix(); + renderer.DisableVertexAttribArray(vPositionName); + renderer.DisableVertexAttribArray(vTexCoordName); + + renderer.shaderManager.PopShader(); + CheckGlError(); +} + +void Game::UpdateVolumeKnob() { + float musicVolumeBarButtonButtonCenterY = volumeBarMinY + musicVolume * (volumeBarMaxY - volumeBarMinY); + + auto& pos = musicVolumeBarButton.data.PositionData; + + pos[0] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 }; + pos[1] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 }; + pos[2] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 }; + pos[3] = { musicVolumeBarButtonButtonCenterX - musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 }; + pos[4] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY + musicVolumeBarButtonButtonRadius, 0 }; + pos[5] = { musicVolumeBarButtonButtonCenterX + musicVolumeBarButtonButtonRadius, musicVolumeBarButtonButtonCenterY - musicVolumeBarButtonButtonRadius, 0 }; + + musicVolumeBarButton.RefreshVBO(); + +} + +void Game::UpdateVolumeFromMouse(int mouseX, int mouseY) { + + int uiX = mouseX; + int uiY = Environment::height - mouseY; + Environment::shipVelocity = (musicVolume - 0.2) * (20.0); + if (uiY < volumeBarMinY || uiY > volumeBarMaxY) + { + return; + } + + float t = (uiY - volumeBarMinY) / (volumeBarMaxY - volumeBarMinY); + if (t < 0.0f) t = 0.0f; + if (t > 1.0f) t = 1.0f; + musicVolume = t; + UpdateVolumeKnob(); +} +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.PushProjectionMatrix(Environment::width, Environment::height, -1, 1); + renderer.PushMatrix(); + + renderer.LoadIdentity(); + + + glBindTexture(GL_TEXTURE_2D, buttonTexture->getTexID()); + renderer.DrawVertexRenderStruct(button); + + glBindTexture(GL_TEXTURE_2D, musicVolumeBarTexture->getTexID()); + renderer.DrawVertexRenderStruct(musicVolumeBar); + + glBindTexture(GL_TEXTURE_2D, musicVolumeBarButtonTexture->getTexID()); + renderer.DrawVertexRenderStruct(musicVolumeBarButton); + + renderer.PopMatrix(); + renderer.PopProjectionMatrix(); + renderer.DisableVertexAttribArray(vPositionName); + renderer.DisableVertexAttribArray(vTexCoordName); + + renderer.shaderManager.PopShader(); + CheckGlError(); +} + +void Game::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, 0.5f, 1.0f, 1.0f); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + glViewport(0, 0, Environment::width, Environment::height); + + CheckGlError(); + + drawCubemap(); + drawShip(); + drawBoxes(); + + //drawUI(); + + CheckGlError(); +} + +void Game::processTickCount() { + + if (lastTickCount == 0) { + lastTickCount = SDL_GetTicks64(); + return; + } + + newTickCount = SDL_GetTicks64(); + if (newTickCount - lastTickCount > CONST_TIMER_INTERVAL) { + size_t delta = (newTickCount - lastTickCount > CONST_MAX_TIME_INTERVAL) ? + CONST_MAX_TIME_INTERVAL : newTickCount - lastTickCount; + + //gameObjects.updateScene(delta); + + if (Environment::tapDownHold) { + + float diffx = Environment::tapDownCurrentPos.v[0] - Environment::tapDownStartPos.v[0]; + float diffy = Environment::tapDownCurrentPos.v[1] - Environment::tapDownStartPos.v[1]; + + if (isDraggingShip) { + // Движение корабля + if (abs(diffy) > 5.0 || abs(diffx) > 5.0) //threshold + { + float velocity = sqrtf(diffx * diffx + diffy * diffy); + + Environment::shipVelocity = velocity * delta / 100; + + // SDL screen Y направлен вниз, поэтому инвертируем diffy + // Движение по -Z (вперёд в локальных координатах камеры) + // diffx: вправо = положительное, влево = отрицательное + // diffy: вниз = положительное, вверх = отрицательное (в SDL) + // Для логики: вверх на экране (отрицательный diffy) = движение вперёд (-Z) + // Вправо на экране (положительный diffx) = поворот вправо (вокруг +Y) + + // Вычисляем угол поворота вокруг Y (горизонтальный поворот) + // atan2(x, z) где x - это -diffx (инвертированное для правильного направления), z - это -diffy (вверх/вниз, инвертированное) + // Вверх (diffy < 0) должно давать угол 0 (вперёд), вправо (diffx > 0) должно давать правильное направление + float angleY = atan2(-diffx, -diffy); // угол поворота вокруг Y (инвертируем diffx для правильного направления) + + // Создаём кватернион для поворота вокруг Y (горизонтальный поворот) + Vector4f quat = { 0, sin(angleY * 0.5f), 0, cos(angleY * 0.5f) }; + rotateShipMat = QuatToMatrix(quat); + + // Фиксируем ориентацию камеры при первом реальном движении + if (!shipMoveLockActive) { + lockedCameraMat = Environment::shipMatrix; + shipMoveLockActive = true; + } + } + else + { + Environment::shipVelocity = 0; + } + } + else if (isDraggingCamera) { + // Вращение камеры + if (abs(diffy) > 5.0 || abs(diffx) > 5.0) //threshold + { + float rotationPower = sqrtf(diffx * diffx + diffy * diffy); + + float deltaAlpha = rotationPower * delta * M_PI / 500000.f; + + Vector3f rotationDirection = { diffy, diffx, 0 }; + + rotationDirection = rotationDirection.normalized(); + + Vector4f rotateQuat = { + rotationDirection.v[0] * sin(deltaAlpha * 0.5f), + rotationDirection.v[1] * sin(deltaAlpha * 0.5f), + rotationDirection.v[2] * sin(deltaAlpha * 0.5f), + cos(deltaAlpha * 0.5f) }; + + Matrix3f rotateMat = QuatToMatrix(rotateQuat); + + Environment::shipMatrix = MultMatrixMatrix(Environment::shipMatrix, rotateMat); + Environment::inverseShipMatrix = InverseMatrix(Environment::shipMatrix); + + // Обновляем начальную позицию для плавного вращения + Environment::tapDownStartPos.v[0] = Environment::tapDownCurrentPos.v[0]; + Environment::tapDownStartPos.v[1] = Environment::tapDownCurrentPos.v[1]; + } + } + } + + if (fabs(Environment::shipVelocity) > 0.01f) + { + // Получаем локальное перемещение в координатах камеры + Vector3f localMove = MultMatrixVector(rotateShipMat, Vector3f{0, 0, -Environment::shipVelocity * delta / 1000.f}); + + // Выбираем матрицу камеры: зафиксированную (если lock активен) или текущую + Matrix3f camMat = shipMoveLockActive ? lockedCameraMat : Environment::shipMatrix; + + // Переводим локальное перемещение в мировые координаты + Vector3f worldMove = MultMatrixVector(camMat, localMove); + + Environment::shipPosition = Environment::shipPosition + worldMove; + } + + lastTickCount = newTickCount; + } +} + +void Game::render() { + SDL_GL_MakeCurrent(ZL::Environment::window, glContext); + ZL::CheckGlError(); + + glClearColor(0.0f, 1.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + drawScene(); + processTickCount(); + + SDL_GL_SwapWindow(ZL::Environment::window); +} +void Game::update() { + SDL_Event event; + while (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) { + Environment::exitGameLoop = true; + + } + else if (event.type == SDL_MOUSEBUTTONDOWN) { + // 1. Обработка нажатия кнопки мыши + + int mx = event.button.x; + int my = event.button.y; + + std::cout << mx << " " << my << '\n'; + int uiX = mx; + int uiY = Environment::height - my; + + if (mx < 400 && my > 400) + { + Environment::tapDownHold = true; + isDraggingShip = true; + isDraggingCamera = false; + // Сбрасываем lock при новом нажатии, чтобы новый drag снова фиксировал камеру при первом движении + shipMoveLockActive = false; + // Координаты начального нажатия + Environment::tapDownStartPos.v[0] = event.button.x; + Environment::tapDownStartPos.v[1] = event.button.y; + // Начальная позиция также становится текущей + Environment::tapDownCurrentPos.v[0] = event.button.x; + Environment::tapDownCurrentPos.v[1] = event.button.y; + } + else + { + Environment::tapDownHold = true; + isDraggingShip = false; + isDraggingCamera = true; + // Координаты начального нажатия + Environment::tapDownStartPos.v[0] = event.button.x; + Environment::tapDownStartPos.v[1] = event.button.y; + // Начальная позиция также становится текущей + Environment::tapDownCurrentPos.v[0] = event.button.x; + Environment::tapDownCurrentPos.v[1] = event.button.y; + } + + + } + else if (event.type == SDL_MOUSEBUTTONUP) { + // 2. Обработка отпускания кнопки мыши + isDraggingVolume = false; + Environment::tapDownHold = false; + Environment::shipVelocity = 0; + + // Сбрасываем lock камеры при отпускании мыши + shipMoveLockActive = false; + + // Если была повернута камера, синхронизируем ориентацию корабля с камерой + // Корабль должен смотреть в том же направлении, что и камера (без дополнительного вращения) + if (isDraggingCamera) { + rotateShipMat = Matrix3f::Identity(); + } + + isDraggingShip = false; + isDraggingCamera = false; + } + else if (event.type == SDL_MOUSEMOTION) { + // 3. Обработка перемещения мыши + int mx = event.motion.x; + int my = event.motion.y; + + if (Environment::tapDownHold) { + // Обновление текущей позиции, если кнопка удерживается + Environment::tapDownCurrentPos.v[0] = event.motion.x; + Environment::tapDownCurrentPos.v[1] = event.motion.y; + } + } + else if (event.type == SDL_MOUSEWHEEL) { + static const float zoomstep = 2.0f; + if (event.wheel.y > 0) { + Environment::zoom -= zoomstep; + } + else if (event.wheel.y < 0) { + Environment::zoom += zoomstep; + } + if (Environment::zoom < zoomstep) { + Environment::zoom = zoomstep; + } + } + else if (event.type == SDL_KEYUP) + { + + if (event.key.keysym.sym == SDLK_i) + { + Environment::shipVelocity += 1.f; + } + if (event.key.keysym.sym == SDLK_k) + { + Environment::shipVelocity -= 1.f; + } + } + } + render(); +} + } // namespace ZL \ No newline at end of file diff --git a/Game.h b/Game.h index 34b608a..c21474d 100755 --- a/Game.h +++ b/Game.h @@ -1,83 +1,87 @@ -#pragma once - -#include "OpenGlExtensions.h" -#include "Renderer.h" -#include "Environment.h" -#include "TextureManager.h" - -namespace ZL { - - - struct BoxCoords - { - Vector3f pos; - Matrix3f m; - }; - - -class Game { -public: - Game(); - ~Game(); - - void setup(); - void update(); - void render(); - - bool shouldExit() const { return Environment::exitGameLoop; } - -private: - void processTickCount(); - void drawScene(); - void drawCubemap(); - void drawShip(); - void drawBoxes(); - void drawUI(); - - SDL_Window* window; - SDL_GLContext glContext; - Renderer renderer; - - size_t newTickCount; - size_t lastTickCount; - - static const size_t CONST_TIMER_INTERVAL = 10; - static const size_t CONST_MAX_TIME_INTERVAL = 1000; - - std::shared_ptr spaceshipTexture; - std::shared_ptr cubemapTexture; - VertexDataStruct spaceshipBase; - VertexRenderStruct spaceship; - - VertexRenderStruct cubemap; - - std::shared_ptr boxTexture; - VertexDataStruct boxBase; - - std::vector boxCoordsArr; - std::vector boxRenderArr; - - - std::shared_ptr buttonTexture; - VertexRenderStruct button; - - std::shared_ptr musicVolumeBarTexture; - VertexRenderStruct musicVolumeBar; - - std::shared_ptr musicVolumeBarButtonTexture; - VertexRenderStruct musicVolumeBarButton; - - - bool isDraggingVolume = false; - float musicVolume = 1.0f; - float volumeBarMinX = 1190.0f; - float volumeBarMaxX = 1200.0f; - float volumeBarMinY = 100.0f; - float volumeBarMaxY = 600.0f; - float musicVolumeBarButtonButtonCenterX = 1195.0f; - float musicVolumeBarButtonButtonRadius = 25.0f; - void UpdateVolumeFromMouse(int mouseX, int mouseY); - void UpdateVolumeKnob(); -}; - +#pragma once + +#include "OpenGlExtensions.h" +#include "Renderer.h" +#include "Environment.h" +#include "TextureManager.h" + +namespace ZL { + + + struct BoxCoords + { + Vector3f pos; + Matrix3f m; + }; + + +class Game { +public: + Game(); + ~Game(); + + void setup(); + void update(); + void render(); + + bool shouldExit() const { return Environment::exitGameLoop; } + +private: + void processTickCount(); + void drawScene(); + void drawCubemap(); + void drawShip(); + void drawBoxes(); + void drawUI(); + + SDL_Window* window; + SDL_GLContext glContext; + Renderer renderer; + + size_t newTickCount; + size_t lastTickCount; + + static const size_t CONST_TIMER_INTERVAL = 10; + static const size_t CONST_MAX_TIME_INTERVAL = 1000; + + std::shared_ptr spaceshipTexture; + std::shared_ptr cubemapTexture; + VertexDataStruct spaceshipBase; + VertexRenderStruct spaceship; + + VertexRenderStruct cubemap; + + std::shared_ptr boxTexture; + VertexDataStruct boxBase; + + std::vector boxCoordsArr; + std::vector boxRenderArr; + + + std::shared_ptr buttonTexture; + VertexRenderStruct button; + + std::shared_ptr musicVolumeBarTexture; + VertexRenderStruct musicVolumeBar; + + std::shared_ptr musicVolumeBarButtonTexture; + VertexRenderStruct musicVolumeBarButton; + + + bool isDraggingVolume = false; + bool isDraggingShip = false; + bool isDraggingCamera = false; + bool shipMoveLockActive = false; + Matrix3f lockedCameraMat = Matrix3f::Identity(); + float musicVolume = 1.0f; + float volumeBarMinX = 1190.0f; + float volumeBarMaxX = 1200.0f; + float volumeBarMinY = 100.0f; + float volumeBarMaxY = 600.0f; + float musicVolumeBarButtonButtonCenterX = 1195.0f; + float musicVolumeBarButtonButtonRadius = 25.0f; + void UpdateVolumeFromMouse(int mouseX, int mouseY); + void UpdateVolumeKnob(); +}; + } // namespace ZL \ No newline at end of file From 2ad6ebf38de4b1d7f3f84a592e0f2f8d41d6a75f Mon Sep 17 00:00:00 2001 From: Ariari04 Date: Mon, 12 Jan 2026 14:41:24 +0600 Subject: [PATCH 4/4] added all --- Game.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Game.cpp b/Game.cpp index 3d80da7..7a91db5 100755 --- a/Game.cpp +++ b/Game.cpp @@ -175,8 +175,8 @@ void Game::setup() { spaceshipTexture = std::make_unique(CreateTextureDataFromPng("./resources/DefaultMaterial_BaseColor.png", CONST_ZIP_FILE)); spaceshipBase = LoadFromTextFile02("./resources/spaceship005.txt", CONST_ZIP_FILE); spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0))); - //spaceshipBase.Move(Vector3f{ -0.52998, -13, 0 }); spaceshipBase.Move(Vector3f{ -0.52998, -10, 10 }); + spaceshipBase.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundY(M_PI / 2.0))); spaceship.AssignFrom(spaceshipBase); spaceship.RefreshVBO(); @@ -316,8 +316,8 @@ void Game::drawShip() // Используем зафиксированную камеру для отрисовки, если lock активен // Это обеспечит правильную ориентацию модели относительно начальной позиции камеры if (shipMoveLockActive) { - Matrix3f inverseLockedCamera = InverseMatrix(lockedCameraMat); - renderer.RotateMatrix(inverseLockedCamera); + ///Matrix3f inverseLockedCamera = InverseMatrix(lockedCameraMat); + renderer.RotateMatrix(lockedCameraMat); } else { renderer.RotateMatrix(Environment::inverseShipMatrix); } @@ -568,7 +568,7 @@ void Game::processTickCount() { Vector3f localMove = MultMatrixVector(rotateShipMat, Vector3f{0, 0, -Environment::shipVelocity * delta / 1000.f}); // Выбираем матрицу камеры: зафиксированную (если lock активен) или текущую - Matrix3f camMat = shipMoveLockActive ? lockedCameraMat : Environment::shipMatrix; + Matrix3f camMat = lockedCameraMat;//////shipMoveLockActive ? lockedCameraMat : Environment::shipMatrix; // Переводим локальное перемещение в мировые координаты Vector3f worldMove = MultMatrixVector(camMat, localMove);