diff --git a/Environment.cpp b/Environment.cpp index 0bb9b23..31d6782 100644 --- a/Environment.cpp +++ b/Environment.cpp @@ -1,5 +1,7 @@ #include "Environment.h" +namespace ZL { + int Environment::windowHeaderHeight = 0; int Environment::width = 0; int Environment::height = 0; @@ -12,3 +14,5 @@ bool Environment::downPressed = false; Vector3f Environment::cameraShift = {0, 0, 0}; Vector3f Environment::characterPos = {0, 0, 0}; + +} // namespace ZL diff --git a/Environment.h b/Environment.h index f0dc366..30c554d 100644 --- a/Environment.h +++ b/Environment.h @@ -1,6 +1,8 @@ #pragma once #include "Math.h" +namespace ZL { + class Environment { public: static int windowHeaderHeight; @@ -13,6 +15,8 @@ public: static bool upPressed; static bool downPressed; - static ZL::Vector3f cameraShift; - static ZL::Vector3f characterPos; + static Vector3f cameraShift; + static Vector3f characterPos; }; + +} // namespace ZL diff --git a/Game.cpp b/Game.cpp index 4b1f617..655150d 100755 --- a/Game.cpp +++ b/Game.cpp @@ -1,8 +1,206 @@ #include "Game.h" #include "AnimatedModel.h" #include "BoneAnimatedModel.h" +#include "Utils.h" +#include "Inventory.h" // Add this include +#include +#include namespace ZL { -} \ No newline at end of file +void Game::worldToScreenCoordinates(Vector3f objectPos, + Matrix4f projectionModelView, + int screenWidth, int screenHeight, + int& screenX, int& screenY) { + + Vector4f inx = { objectPos.v[0], objectPos.v[1], objectPos.v[2], 1.0f}; + Vector4f clipCoords = MultMatrixVector(projectionModelView, inx); + + float ndcX = clipCoords.v[0] / clipCoords.v[3]; + float ndcY = clipCoords.v[1] / clipCoords.v[3]; + + screenX = (int)((ndcX + 1.0f) * 0.5f * screenWidth); + screenY = (int)((1.0f + ndcY) * 0.5f * screenHeight); +} + +Game::Game() : window(nullptr), glContext(nullptr), exitGameLoop(false), + newTickCount(0), lastTickCount(0) { +} + +Game::~Game() { + if (glContext) { + SDL_GL_DeleteContext(glContext); + } + if (window) { + SDL_DestroyWindow(window); + } + SDL_Quit(); +} + +void Game::setup() { + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_EVENTS) != 0) { + SDL_Log("Failed to initialize SDL: %s", SDL_GetError()); + return; + } + + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); + SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); + + window = SDL_CreateWindow("Game", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, + Environment::width, Environment::height, SDL_WINDOW_OPENGL); + + glContext = SDL_GL_CreateContext(window); + + ZL::BindOpenGlFunctions(); + ZL::CheckGlError(); + + // Initialize renderer + renderer.shaderManager.AddShaderFromFiles("default", "./default.vertex", "./default.fragment"); + renderer.shaderManager.AddShaderFromFiles("defaultColor", "./defaultColor.vertex", "./defaultColor.fragment"); + renderer.InitOpenGL(); + + // Initialize game objects + gameObjects.initialize(); +} + +void Game::drawScene() { + static const std::string defaultShaderName = "default"; + static const std::string vPositionName = "vPosition"; + static const std::string vTexCoordName = "vTexCoord"; + static const std::string textureUniformName = "Texture"; + + glClearColor(0.3f, 0.3f, 0.3f, 1.0f); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + glViewport(0, 0, Environment::width, Environment::height); + + renderer.shaderManager.PushShader(defaultShaderName); + renderer.RenderUniform1i(textureUniformName, 0); + + renderer.EnableVertexAttribArray(vPositionName); + renderer.EnableVertexAttribArray(vTexCoordName); + + // 3D Scene rendering + { + renderer.PushPerspectiveProjectionMatrix(1.0 / 1.5, + static_cast(Environment::width) / static_cast(Environment::height), + 50, 10000); + renderer.PushMatrix(); + + renderer.LoadIdentity(); + renderer.TranslateMatrix({ 0,0, -100 * Environment::zoom }); + + float t = 0.3; + renderer.RotateMatrix(QuatFromRotateAroundX(t * M_PI / 2.0)); + + // Draw cone + glBindTexture(GL_TEXTURE_2D, gameObjects.coneTexturePtr->getTexID()); + renderer.DrawVertexRenderStruct(gameObjects.coneMeshMutable); + + renderer.TranslateMatrix(Environment::cameraShift); + + // Draw active objects + for (auto& ao : gameObjects.activeObjects) { + renderer.PushMatrix(); + renderer.TranslateMatrix(ao.objectPos); + glBindTexture(GL_TEXTURE_2D, ao.activeObjectTexturePtr->getTexID()); + renderer.DrawVertexRenderStruct(ao.activeObjectMeshMutable); + renderer.PopMatrix(); + } + + // Draw room + glBindTexture(GL_TEXTURE_2D, gameObjects.roomTexturePtr->getTexID()); + renderer.DrawVertexRenderStruct(gameObjects.textMeshMutable); + + auto latestProjectionModelView = renderer.GetProjectionModelViewMatrix(); + + renderer.PopMatrix(); + renderer.PopProjectionMatrix(); + + // 2D UI rendering + renderer.PushProjectionMatrix(static_cast(Environment::width), + static_cast(Environment::height)); + renderer.PushMatrix(); + renderer.LoadIdentity(); + + // Draw highlighted objects UI + for (auto& ao : gameObjects.activeObjects) { + if (ao.highlighted) { + int screenX, screenY; + worldToScreenCoordinates(ao.objectPos, latestProjectionModelView, + Environment::width, Environment::height, screenX, screenY); + renderer.PushMatrix(); + renderer.TranslateMatrix(Vector3f{screenX + 0.f, screenY + 0.f, 0.0f}); + glBindTexture(GL_TEXTURE_2D, ao.activeObjectScreenTexturePtr->getTexID()); + renderer.DrawVertexRenderStruct(ao.activeObjectScreenMeshMutable); + renderer.PopMatrix(); + } + } + + // Draw inventory + const auto& inventory = ZL::ReturnInventory(); + for (size_t i = 0; i < inventory.size(); ++i) { + renderer.PushMatrix(); + float xPos = Environment::width - gameObjects.INVENTORY_MARGIN - gameObjects.INVENTORY_ICON_SIZE; + float yPos = gameObjects.INVENTORY_MARGIN + i * (gameObjects.INVENTORY_ICON_SIZE + gameObjects.INVENTORY_MARGIN); + renderer.TranslateMatrix(Vector3f{xPos, yPos, 0.0f}); + glBindTexture(GL_TEXTURE_2D, inventory[i].texture->getTexID()); + renderer.DrawVertexRenderStruct(gameObjects.inventoryIconMeshMutable); + renderer.PopMatrix(); + } + + renderer.PopMatrix(); + renderer.PopProjectionMatrix(); + } + + renderer.DisableVertexAttribArray(vPositionName); + renderer.DisableVertexAttribArray(vTexCoordName); + renderer.shaderManager.PopShader(); + + 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.update(); + + lastTickCount = newTickCount; + } +} + +void Game::render() { + SDL_GL_MakeCurrent(window, glContext); + ZL::CheckGlError(); + + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + drawScene(); + processTickCount(); + + SDL_GL_SwapWindow(window); +} + +void Game::update() { + SDL_Event event; + while (SDL_PollEvent(&event)) { + if (event.type == SDL_QUIT) { + exitGameLoop = true; + } + gameObjects.handleEvent(event); + } + render(); +} + +} // namespace ZL \ No newline at end of file diff --git a/Game.h b/Game.h index 66c4804..73898d1 100755 --- a/Game.h +++ b/Game.h @@ -5,6 +5,8 @@ #include "Renderer.h" #include "Environment.h" +namespace ZL { + class Game { public: Game(); @@ -20,10 +22,14 @@ public: private: void processTickCount(); void drawScene(); + void worldToScreenCoordinates(Vector3f objectPos, + Matrix4f projectionModelView, + int screenWidth, int screenHeight, + int& screenX, int& screenY); SDL_Window* window; SDL_GLContext glContext; - ZL::Renderer renderer; + Renderer renderer; GameObjectManager gameObjects; bool exitGameLoop; @@ -32,4 +38,6 @@ private: static const size_t CONST_TIMER_INTERVAL = 10; static const size_t CONST_MAX_TIME_INTERVAL = 1000; -}; \ No newline at end of file +}; + +} // namespace ZL \ No newline at end of file diff --git a/GameObjectManager.cpp b/GameObjectManager.cpp index 5577188..87426b6 100644 --- a/GameObjectManager.cpp +++ b/GameObjectManager.cpp @@ -1,12 +1,181 @@ #include "GameObjectManager.h" +#include "Environment.h" +#include "ObjLoader.h" +#include "Inventory.h" +#include "TextModel.h" // Add this include for LoadFromTextFile + +namespace ZL { const float GameObjectManager::INVENTORY_ICON_SIZE = 32.0f; const float GameObjectManager::INVENTORY_MARGIN = 10.0f; void GameObjectManager::initialize() { - // Implementation coming from main.cpp setup() + // Load textures + roomTexturePtr = std::make_shared(CreateTextureDataFromBmp24("./Kitchen_ceramics.bmp")); + coneTexturePtr = std::make_shared(CreateTextureDataFromBmp24("./conus.bmp")); + + // Load models + colorCubeMesh = CreateCube3D(5.0); + colorCubeMeshMutable.data = CreateCube3D(5.0); + colorCubeMeshMutable.RefreshVBO(); + + testObjMesh = LoadFromObjFile("./chair_01.obj"); + testObjMesh.Scale(10); + testObjMesh.SwapZandY(); + testObjMeshMutable.data = testObjMesh; + testObjMeshMutable.RefreshVBO(); + + textMesh = ZL::LoadFromTextFile("./mesh001.txt"); // Add ZL:: namespace + coneMesh = ZL::LoadFromTextFile("./cone001.txt"); // Add ZL:: namespace + coneMesh.Scale(200); + + textMeshMutable.AssignFrom(textMesh); + textMeshMutable.RefreshVBO(); + coneMeshMutable.AssignFrom(coneMesh); + coneMeshMutable.RefreshVBO(); + + // Load bone animations + bx.LoadFromFile("mesh_armature_and_animation_data.txt"); + + // Create active object + ActiveObject ao1; + ao1.activeObjectMesh = ZL::LoadFromTextFile("./book001.txt"); // Add ZL:: namespace + ao1.activeObjectMesh.Scale(4); + ao1.activeObjectMeshMutable.AssignFrom(ao1.activeObjectMesh); + ao1.activeObjectMeshMutable.RefreshVBO(); + ao1.objectPos = Vector3f{50, 0, -300}; + ao1.activeObjectTexturePtr = std::make_shared(CreateTextureDataFromBmp24("./book03.bmp")); + ao1.activeObjectScreenTexturePtr = std::make_shared(CreateTextureDataFromBmp24("./aoscreen01.bmp")); + ao1.activeObjectScreenMesh = CreateRect2D({ 0.f, 0.f }, { 64.f, 64.f }, 0.5); + ao1.activeObjectScreenMeshMutable.AssignFrom(ao1.activeObjectScreenMesh); + ao1.activeObjectScreenMeshMutable.RefreshVBO(); + activeObjects.push_back(ao1); + + // Initialize audio + audioPlayer = std::make_unique(); + if (audioPlayer) { + audioPlayer->playMusic("Symphony No.6 (1st movement).ogg"); + } + + // Initialize inventory + inventoryIconMesh = CreateRect2D( + {0.0f, 0.0f}, + {INVENTORY_ICON_SIZE/2, INVENTORY_ICON_SIZE/2}, + 0.5f + ); + inventoryIconMeshMutable.AssignFrom(inventoryIconMesh); + inventoryIconMeshMutable.RefreshVBO(); + + // Add test items to inventory + auto testRoomTexture = std::make_shared(CreateTextureDataFromBmp24("./Kitchen_ceramics.bmp")); + auto testConeTexture = std::make_shared(CreateTextureDataFromBmp24("./conus.bmp")); + AddItemToInventory("RoomCeramics", testRoomTexture); + AddItemToInventory("Cone", testConeTexture); } void GameObjectManager::update() { - // Implementation coming from main.cpp update() + updateScene(16); // Добавим фиксированный timestep для обновления сцены } + +void GameObjectManager::handleEvent(const SDL_Event& event) { + if (event.type == SDL_MOUSEBUTTONDOWN) { + bx.Interpolate(animationCounter); + animationCounter += 2; + } + else if (event.type == SDL_MOUSEWHEEL) { + static const float zoomstep = 1.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_KEYDOWN) { + switch (event.key.keysym.sym) { + case SDLK_LEFT: + case SDLK_a: + Environment::leftPressed = true; + if (audioPlayer) { + audioPlayer->playSound("Звук-Идут-по-земле.ogg"); + } + break; + case SDLK_RIGHT: + case SDLK_d: + Environment::rightPressed = true; + if (audioPlayer) { + audioPlayer->playSound("Звук-Идут-по-земле.ogg"); + } + break; + case SDLK_UP: + case SDLK_w: + Environment::upPressed = true; + if (audioPlayer) { + audioPlayer->playSound("Звук-Идут-по-земле.ogg"); + } + break; + case SDLK_DOWN: + case SDLK_s: + Environment::downPressed = true; + if (audioPlayer) { + audioPlayer->playSound("Звук-Идут-по-земле.ogg"); + } + break; + // ...handle other keys... + } + } + else if (event.type == SDL_KEYUP) { + switch (event.key.keysym.sym) { + case SDLK_LEFT: + case SDLK_a: + Environment::leftPressed = false; + break; + case SDLK_RIGHT: + case SDLK_d: + Environment::rightPressed = false; + break; + case SDLK_UP: + case SDLK_w: + Environment::upPressed = false; + break; + case SDLK_DOWN: + case SDLK_s: + Environment::downPressed = false; + break; + } + } +} + +void GameObjectManager::updateScene(size_t ms) { + const float SPEED = 0.1f; + if (Environment::leftPressed) { + Environment::cameraShift.v[0] += SPEED * ms; + } + if (Environment::rightPressed) { + Environment::cameraShift.v[0] -= SPEED * ms; + } + if (Environment::upPressed) { + Environment::cameraShift.v[2] += SPEED * ms; + } + if (Environment::downPressed) { + Environment::cameraShift.v[2] -= SPEED * ms; + } + + Environment::characterPos.v[0] = -Environment::cameraShift.v[0]; + Environment::characterPos.v[1] = -Environment::cameraShift.v[1]; + Environment::characterPos.v[2] = -Environment::cameraShift.v[2]; + + for (auto& ao : activeObjects) { + float dist = sqrtf( + pow(Environment::characterPos.v[0] - ao.objectPos.v[0], 2) + + pow(Environment::characterPos.v[1] - ao.objectPos.v[1], 2) + + pow(Environment::characterPos.v[2] - ao.objectPos.v[2], 2) + ); + ao.highlighted = (dist < 50.f); + } +} + +} // namespace ZL diff --git a/GameObjectManager.h b/GameObjectManager.h index 1e56e1f..e998d50 100644 --- a/GameObjectManager.h +++ b/GameObjectManager.h @@ -5,11 +5,16 @@ #include #include #include "ActiveObject.h" +#include + +namespace ZL { class GameObjectManager { public: void initialize(); void update(); + void handleEvent(const SDL_Event& event); + void updateScene(size_t ms); std::shared_ptr testObjTexturePtr; std::shared_ptr roomTexturePtr; @@ -38,4 +43,9 @@ public: static const float INVENTORY_ICON_SIZE; static const float INVENTORY_MARGIN; + +private: + int animationCounter = 0; }; + +} // namespace ZL diff --git a/main.cpp b/main.cpp index e13e50b..4aa257e 100755 --- a/main.cpp +++ b/main.cpp @@ -541,19 +541,20 @@ namespace ZL }; #include "Game.h" +#include "Environment.h" int main(int argc, char* argv[]) { constexpr int CONST_WIDTH = 1280; constexpr int CONST_HEIGHT = 720; - Environment::width = CONST_WIDTH; - Environment::height = CONST_HEIGHT; + ZL::Environment::width = CONST_WIDTH; + ZL::Environment::height = CONST_HEIGHT; - Game game; + ZL::Game game; game.setup(); #ifdef EMSCRIPTEN - emscripten_set_main_loop([]() { game.update(); }, 0, 1); + emscripten_set_main_loop([](){ game.update(); }, 0, 1); #else while (!game.shouldExit()) { game.update();