diff --git a/AudioPlayerAsync.h b/AudioPlayerAsync.h index 9f29cef..a31e9de 100644 --- a/AudioPlayerAsync.h +++ b/AudioPlayerAsync.h @@ -25,6 +25,8 @@ public: stop = true; } + std::thread worker; + private: std::unique_ptr audioPlayer; //std::mutex audioPlayerMutex; @@ -35,9 +37,6 @@ private: std::string latestSoundName; std::string latestMusicName; - - - std::thread worker; std::mutex mtx; std::condition_variable cv; std::queue> taskQueue; diff --git a/Environment.cpp b/Environment.cpp index 2ccd2fd..b7abe4f 100644 --- a/Environment.cpp +++ b/Environment.cpp @@ -40,4 +40,6 @@ bool Environment::showMouse = false; bool Environment::exitGameLoop = false; +bool Environment::gameIsLoading = true; + } // namespace ZL diff --git a/Environment.h b/Environment.h index 1a52c35..728900e 100644 --- a/Environment.h +++ b/Environment.h @@ -44,6 +44,8 @@ public: static bool showMouse; static bool exitGameLoop; + static bool gameIsLoading; + }; diff --git a/Game.cpp b/Game.cpp index 5e21dce..504f90a 100755 --- a/Game.cpp +++ b/Game.cpp @@ -72,6 +72,24 @@ void Game::drawScene() { } void Game::processTickCount() { + + if (Environment::gameIsLoading) + { + if (gameObjects.loadingFunctions.size() != 0) + { + bool result = gameObjects.loadingFunctions.begin()->operator()(); + if (result) + { + gameObjects.loadingFunctions.erase(gameObjects.loadingFunctions.begin()); + } + } + else + { + Environment::gameIsLoading = false; + } + return; + } + if (lastTickCount == 0) { lastTickCount = SDL_GetTicks64(); return; @@ -105,9 +123,19 @@ void Game::update() { SDL_Event event; while (SDL_PollEvent(&event)) { if (event.type == SDL_QUIT) { + if (gameObjects.loadingThread.joinable()) + { + gameObjects.loadingThread.join(); + } + gameObjects.audioPlayerAsync.exit(); Environment::exitGameLoop = true; + + } + + if (!Environment::gameIsLoading) + { + gameObjects.handleEvent(event); } - gameObjects.handleEvent(event); } render(); diff --git a/GameObjectManager.cpp b/GameObjectManager.cpp index 68dbf3a..b97dd73 100644 --- a/GameObjectManager.cpp +++ b/GameObjectManager.cpp @@ -10,122 +10,169 @@ namespace ZL { const float GameObjectManager::INVENTORY_ICON_SIZE = 44.0f; const float GameObjectManager::INVENTORY_MARGIN = 20.0f; +void GameObjectManager::initializeLoadingScreen() +{ + loadingScreenTexturePtr = std::make_shared(CreateTextureDataFromBmp24("./loading.bmp")); + + loadingScreenMesh = CreateRect2D( + { Environment::width / 2.f, Environment::height / 2.f }, + { Environment::width / 2.f, Environment::height / 2.f }, + 0.5f + ); + loadingScreenMeshMutable.AssignFrom(loadingScreenMesh); + loadingScreenMeshMutable.RefreshVBO(); +} + void GameObjectManager::initialize() { + + initializeLoadingScreen(); + + std::function loadingFunction1 = [this]() + { + + current_room_index = 0; + objects_in_inventory = 0; bearName = ""; current_room_index = 0; objects_in_inventory = 0; - coneTexturePtr = std::make_shared(CreateTextureDataFromBmp24("./conus.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("./textures/mesh_first_room.txt"); - textMesh = ZL::LoadFromTextFile("./oneroom001.txt"); - textMesh.Scale(10); - textMesh.SwapZandY(); - textMesh.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundX(M_PI * 0.5))); - textMesh.Move(Vector3f{0, 93, 0}); - - coneMesh = ZL::LoadFromTextFile("./cone001.txt"); // Add ZL:: namespace - coneMesh.Scale(200); + // Load models + /* + colorCubeMesh = CreateCube3D(5.0); + colorCubeMeshMutable.data = CreateCube3D(5.0); + colorCubeMeshMutable.RefreshVBO(); + */ + return true; + }; - textMeshMutable.AssignFrom(textMesh); - textMeshMutable.RefreshVBO(); - coneMeshMutable.AssignFrom(coneMesh); - coneMeshMutable.RefreshVBO(); + loadingThread = std::thread([this]() { - // Load bone animations - //bx.LoadFromFile("./violetta001.txt"); - violaIdleModel.LoadFromFile("./idleviola001.txt"); - violaWalkModel.LoadFromFile("./walkviolla001.txt"); - // Create active object - - ActiveObject ao1; - ao1.name = "book"; - 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(); + textMesh = ZL::LoadFromTextFile("./oneroom001.txt"); + violaIdleModel.LoadFromFile("./idleviola001.txt"); + violaWalkModel.LoadFromFile("./walkviolla001.txt"); + sideThreadLoadingCompleted = true; + }); - /* - ActiveObject ao2; - ao2.name = "superchair001"; - ao2.activeObjectMesh = ZL::LoadFromTextFile("./superchair001.txt"); // Add ZL:: namespace - ao2.activeObjectMesh.Scale(400); - ao2.activeObjectMesh.SwapZandY(); - ao2.activeObjectMeshMutable.AssignFrom(ao2.activeObjectMesh); - ao2.activeObjectMeshMutable.RefreshVBO(); - ao2.objectPos = Vector3f{ 0, 0, 0 }; - ao2.activeObjectTexturePtr = std::make_shared(CreateTextureDataFromBmp24("./chair_01_Base_Color.bmp")); + std::function loadingFunction2 = [this]() + { + return sideThreadLoadingCompleted; + }; - ao2.activeObjectScreenTexturePtr = std::make_shared(CreateTextureDataFromBmp24("./aoscreen01.bmp")); - ao2.activeObjectScreenMesh = CreateRect2D({ 0.f, 0.f }, { 64.f, 64.f }, 0.5); - ao2.activeObjectScreenMeshMutable.AssignFrom(ao2.activeObjectScreenMesh); - ao2.activeObjectScreenMeshMutable.RefreshVBO(); - */ + std::function loadingFunction3 = [this]() + { + + /* + testObjMesh = LoadFromObjFile("./chair_01.obj"); + testObjMesh.Scale(10); + testObjMesh.SwapZandY(); + testObjMeshMutable.data = testObjMesh; + testObjMeshMutable.RefreshVBO();*/ + + + textMesh.Scale(10); + textMesh.SwapZandY(); + textMesh.RotateByMatrix(QuatToMatrix(QuatFromRotateAroundX(M_PI * 0.5))); + textMesh.Move(Vector3f{ 0, 93, 0 }); + + //coneMesh = ZL::LoadFromTextFile("./cone001.txt"); // Add ZL:: namespace + //coneMesh.Scale(200); + + + textMeshMutable.AssignFrom(textMesh); + textMeshMutable.RefreshVBO(); + //coneMeshMutable.AssignFrom(coneMesh); + //coneMeshMutable.RefreshVBO(); + + + // Create active object + + ActiveObject ao1; + ao1.name = "book"; + 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(); + + /* + ActiveObject ao2; + ao2.name = "superchair001"; + ao2.activeObjectMesh = ZL::LoadFromTextFile("./superchair001.txt"); // Add ZL:: namespace + ao2.activeObjectMesh.Scale(400); + ao2.activeObjectMesh.SwapZandY(); + ao2.activeObjectMeshMutable.AssignFrom(ao2.activeObjectMesh); + ao2.activeObjectMeshMutable.RefreshVBO(); + ao2.objectPos = Vector3f{ 0, 0, 0 }; + ao2.activeObjectTexturePtr = std::make_shared(CreateTextureDataFromBmp24("./chair_01_Base_Color.bmp")); + + ao2.activeObjectScreenTexturePtr = std::make_shared(CreateTextureDataFromBmp24("./aoscreen01.bmp")); + ao2.activeObjectScreenMesh = CreateRect2D({ 0.f, 0.f }, { 64.f, 64.f }, 0.5); + ao2.activeObjectScreenMeshMutable.AssignFrom(ao2.activeObjectScreenMesh); + ao2.activeObjectScreenMeshMutable.RefreshVBO(); + */ - Room room_1; - room_1.roomTexture = std::make_shared(CreateTextureDataFromBmp24("./Material_Base_color_1001.bmp")); - room_1.objects.push_back(ao1); - room_1.sound_name = "Symphony No.6 (1st movement).ogg"; - room_1.roomLogic = createRoom1Logic(); - rooms.push_back(room_1); - aoMgr.addActiveObject(ao1); + Room room_1; + room_1.roomTexture = std::make_shared(CreateTextureDataFromBmp24("./Material_Base_color_1001.bmp")); + room_1.objects.push_back(ao1); + room_1.sound_name = "Symphony No.6 (1st movement).ogg"; + room_1.roomLogic = createRoom1Logic(); + rooms.push_back(room_1); + aoMgr.addActiveObject(ao1); - Room room_2; - room_2.roomTexture = std::make_shared(CreateTextureDataFromBmp24("./background.bmp")); - room_2.sound_name = "Symphony No.6 (1st movement).ogg"; - room_2.roomLogic = createRoom2Logic(); - rooms.push_back(room_2); + Room room_2; + room_2.roomTexture = std::make_shared(CreateTextureDataFromBmp24("./background.bmp")); + room_2.sound_name = "Symphony No.6 (1st movement).ogg"; + room_2.roomLogic = createRoom2Logic(); + rooms.push_back(room_2); - activeObjects = rooms[current_room_index].objects; + activeObjects = rooms[current_room_index].objects; - // Initialize audio - /* - audioPlayer = std::make_unique(); - if (audioPlayer) { - audioPlayer->playMusic(rooms[current_room_index].sound_name); - }*/ - audioPlayerAsync.resetAsync(); - audioPlayerAsync.playMusicAsync(rooms[current_room_index].sound_name); + // Initialize audio + /* + audioPlayer = std::make_unique(); + if (audioPlayer) { + audioPlayer->playMusic(rooms[current_room_index].sound_name); + }*/ + audioPlayerAsync.resetAsync(); + audioPlayerAsync.playMusicAsync(rooms[current_room_index].sound_name); - // Initialize inventory - inventoryIconMesh = CreateRect2D( - {0.0f, 40.0f}, - {INVENTORY_ICON_SIZE/2, INVENTORY_ICON_SIZE/2}, - 0.5f - ); - inventoryIconMeshMutable.AssignFrom(inventoryIconMesh); - inventoryIconMeshMutable.RefreshVBO(); + // Initialize inventory + inventoryIconMesh = CreateRect2D( + { 0.0f, 40.0f }, + { INVENTORY_ICON_SIZE / 2, INVENTORY_ICON_SIZE / 2 }, + 0.5f + ); + inventoryIconMeshMutable.AssignFrom(inventoryIconMesh); + inventoryIconMeshMutable.RefreshVBO(); - roomTexturePtr = rooms[current_room_index].roomTexture; + roomTexturePtr = rooms[current_room_index].roomTexture; - AddItemToInventory("book1", std::make_shared(CreateTextureDataFromBmp24("./Kitchen_ceramics.bmp")), objects_in_inventory+1); - objects_in_inventory++; - AddItemToInventory("book2", std::make_shared(CreateTextureDataFromBmp24("./Kitchen_ceramics.bmp")), objects_in_inventory+1); - objects_in_inventory++; + AddItemToInventory("book1", std::make_shared(CreateTextureDataFromBmp24("./Kitchen_ceramics.bmp")), objects_in_inventory + 1); + objects_in_inventory++; + AddItemToInventory("book2", std::make_shared(CreateTextureDataFromBmp24("./Kitchen_ceramics.bmp")), objects_in_inventory + 1); + objects_in_inventory++; - //SDL_ShowCursor(SDL_DISABLE); - SDL_SetRelativeMouseMode(SDL_TRUE); + //SDL_ShowCursor(SDL_DISABLE); + SDL_SetRelativeMouseMode(SDL_TRUE); + + return true; + + }; + + loadingFunctions.push_back(loadingFunction1); + loadingFunctions.push_back(loadingFunction2); + loadingFunctions.push_back(loadingFunction3); } void GameObjectManager::switch_room(int index){ @@ -233,6 +280,11 @@ void GameObjectManager::handleEvent(const SDL_Event& event) { case SDLK_ESCAPE: case SDLK_q: + if (loadingThread.joinable()) + { + loadingThread.join(); + } + audioPlayerAsync.exit(); Environment::exitGameLoop = true; break; case SDLK_LEFT: @@ -547,35 +599,4 @@ void GameObjectManager::worldToScreenCoordinates(Vector3f objectPos, screenY = (int)((1.0f + ndcY) * 0.5f * screenHeight); } -void GameObjectManager::addRectangle(int x, int y, int width, int height, int r, int g, int b, int borderWidth, int borderR, int borderG, int borderB) { - // Преобразование RGB в диапазон [0,1] для OpenGL - float rf = r / 255.0f; - float gf = g / 255.0f; - float bf = b / 255.0f; - float borderRf = borderR / 255.0f; - float borderGf = borderG / 255.0f; - float borderBf = borderB / 255.0f; - - // Отрисовка заполненного прямоугольника - glColor3f(rf, gf, bf); - glBegin(GL_QUADS); - glVertex2f(x, y); - glVertex2f(x + width, y); - glVertex2f(x + width, y + height); - glVertex2f(x, y + height); - glEnd(); - - // Отрисовка рамки - if (borderWidth > 0) { - glColor3f(borderRf, borderGf, borderBf); - glLineWidth(borderWidth); - glBegin(GL_LINE_LOOP); - glVertex2f(x, y); - glVertex2f(x + width, y); - glVertex2f(x + width, y + height); - glVertex2f(x, y + height); - glEnd(); - } -} - } // namespace ZL diff --git a/GameObjectManager.h b/GameObjectManager.h index 1d6ca25..921cc24 100644 --- a/GameObjectManager.h +++ b/GameObjectManager.h @@ -21,6 +21,7 @@ namespace ZL { class GameObjectManager { public: + void initializeLoadingScreen(); void initialize(); void switch_room(int index); @@ -33,11 +34,11 @@ public: std::shared_ptr roomTexturePtr; std::shared_ptr coneTexturePtr; - ZL::VertexDataStruct colorCubeMesh; - ZL::VertexRenderStruct colorCubeMeshMutable; + //ZL::VertexDataStruct colorCubeMesh; + //ZL::VertexRenderStruct colorCubeMeshMutable; - ZL::VertexDataStruct testObjMesh; - ZL::VertexRenderStruct testObjMeshMutable; + //ZL::VertexDataStruct testObjMesh; + //ZL::VertexRenderStruct testObjMeshMutable; ZL::BoneSystem violaIdleModel; ZL::VertexRenderStruct violaIdleModelMutable; @@ -48,8 +49,8 @@ public: ZL::VertexDataStruct textMesh; ZL::VertexRenderStruct textMeshMutable; - ZL::VertexDataStruct coneMesh; - ZL::VertexRenderStruct coneMeshMutable; + //ZL::VertexDataStruct coneMesh; + //ZL::VertexRenderStruct coneMeshMutable; std::vector activeObjects; std::vector rooms; @@ -69,7 +70,15 @@ public: void addRectangle(int x, int y, int width, int height, int r, int g, int b, int borderWidth, int borderR, int borderG, int borderB); - + + std::shared_ptr loadingScreenTexturePtr; + + ZL::VertexDataStruct loadingScreenMesh; + ZL::VertexRenderStruct loadingScreenMeshMutable; + + std::list> loadingFunctions; + std::thread loadingThread; + bool sideThreadLoadingCompleted = false; private: //int animationCounter = 0; diff --git a/RenderSystem.cpp b/RenderSystem.cpp index 2328ac4..a283d8f 100644 --- a/RenderSystem.cpp +++ b/RenderSystem.cpp @@ -26,20 +26,16 @@ void RenderSystem::drawScene(GameObjectManager& gameObjects) { 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); - */ - drawWorld(gameObjects); - drawUI(gameObjects); - - /*renderer.DisableVertexAttribArray(vPositionName); - renderer.DisableVertexAttribArray(vTexCoordName); - renderer.shaderManager.PopShader();*/ - + if (Environment::gameIsLoading) + { + drawLoadingScreen(gameObjects); + } + else + { + drawWorld(gameObjects); + drawUI(gameObjects); + } CheckGlError(); } @@ -278,6 +274,35 @@ void RenderSystem::drawUI(const GameObjectManager& gameObjects) { renderer.shaderManager.PopShader(); } +void RenderSystem::drawLoadingScreen(const GameObjectManager& gameObjects) +{ + renderer.shaderManager.PushShader("default"); + + // Если шейдер ожидает атрибуты вершин, их нужно включить + static const std::string vPositionName = "vPosition"; + static const std::string vTexCoordName = "vTexCoord"; + renderer.EnableVertexAttribArray(vPositionName); + renderer.EnableVertexAttribArray(vTexCoordName); + + renderer.PushProjectionMatrix(static_cast(Environment::width), + static_cast(Environment::height)); + renderer.PushMatrix(); + renderer.LoadIdentity(); + + glBindTexture(GL_TEXTURE_2D, gameObjects.loadingScreenTexturePtr->getTexID()); + renderer.DrawVertexRenderStruct(gameObjects.loadingScreenMeshMutable); + + renderer.PopMatrix(); + renderer.PopProjectionMatrix(); + + // Выключаем атрибуты, чтобы сохранить баланс + renderer.DisableVertexAttribArray(vPositionName); + renderer.DisableVertexAttribArray(vTexCoordName); + + // Снимаем шейдер, тем самым балансируя стек + renderer.shaderManager.PopShader(); + +} void RenderSystem::worldToScreenCoordinates(Vector3f objectPos, Matrix4f projectionModelView, diff --git a/RenderSystem.h b/RenderSystem.h index 5729320..979cf07 100644 --- a/RenderSystem.h +++ b/RenderSystem.h @@ -24,6 +24,8 @@ private: void drawViola(GameObjectManager& gameObjects); + void drawLoadingScreen(const GameObjectManager& gameObjects); + Renderer renderer; ShaderManager shaderManager; Matrix4f currentProjectionModelView; // Добавлено для хранения матрицы между drawWorld и drawUI diff --git a/loading.bmp b/loading.bmp new file mode 100644 index 0000000..cffbe8f Binary files /dev/null and b/loading.bmp differ