diff options
Diffstat (limited to 'old/core')
-rw-r--r-- | old/core/AssetManager.cpp | 181 | ||||
-rw-r--r-- | old/core/AssetManager.hpp | 75 | ||||
-rw-r--r-- | old/core/Core.cpp | 457 | ||||
-rw-r--r-- | old/core/Core.hpp | 95 | ||||
-rw-r--r-- | old/core/Event.cpp | 76 | ||||
-rw-r--r-- | old/core/Event.hpp | 96 |
6 files changed, 980 insertions, 0 deletions
diff --git a/old/core/AssetManager.cpp b/old/core/AssetManager.cpp new file mode 100644 index 0000000..258f5d9 --- /dev/null +++ b/old/core/AssetManager.cpp @@ -0,0 +1,181 @@ +#include "AssetManager.hpp" + +namespace fs = std::experimental::filesystem; + +//const fs::path pathToAssets = "./assets/"; +//const fs::path pathToAssetsList = "./items.json"; +//const fs::path pathToTextureIndex = "./textures.json"; +const std::string pathToAssetsList = "./items.json"; +const std::string pathToTextureIndex = "./textures.json"; + +AssetManager::AssetManager() { + LoadIds(); + LoadTextureResources(); +} + +void AssetManager::LoadIds() { + std::ifstream in(pathToAssetsList); + nlohmann::json index; + in >> index; + for (auto &it:index) { + int id = it["type"].get<int>(); + int state = it["meta"].get<int>(); + std::string blockName = it["text_type"].get<std::string>(); + assetIds[blockName] = Block(id, state); + } + LOG(INFO) << "Loaded " << assetIds.size() << " ids"; +} + +AssetManager::~AssetManager() { + delete textureAtlas; +} + +//TODO: This function must be replaced with runtime texture atlas generating +void AssetManager::LoadTextureResources() { + std::ifstream in(pathToTextureIndex); + nlohmann::json index; + in >> index; + std::string filename = index["meta"]["image"].get<std::string>(); + float textureWidth = index["meta"]["size"]["w"].get<int>(); + float textureHeight = index["meta"]["size"]["h"].get<int>(); + for (auto &it:index["frames"]) { + auto frame = it["frame"]; + TextureCoordinates coord; + coord.x = frame["x"].get<int>() / textureWidth; + coord.y = frame["y"].get<int>() / textureHeight; + coord.w = frame["w"].get<int>() / textureWidth; + coord.h = frame["h"].get<int>() / textureHeight; + std::string assetName = it["filename"].get<std::string>(); + assetName.insert(0, "minecraft/textures/"); + assetName.erase(assetName.length() - 4); + assetTextures[assetName] = coord; + } + + textureAtlas = new Texture(filename); + LOG(INFO) << "Texture atlas id is " << textureAtlas->texture; +} + +TextureCoordinates AssetManager::GetTextureByAssetName(std::string AssetName) { + if (assetTextures.find(AssetName) != assetTextures.end()) + return assetTextures[AssetName]; + else + return TextureCoordinates{-1, -1, -1, -1}; +} + +std::string AssetManager::GetTextureAssetNameByBlockId(BlockTextureId block) { + //Block sides: 0 - bottom, 1 - top, 2 - north, 3 - south, 4 - west, 5 - east 6 - every side + const std::map<BlockTextureId, std::string> lookupTable = { + {BlockTextureId(0, 0), "minecraft/textures/blocks/air"}, + {BlockTextureId(1, 0), "minecraft/textures/blocks/stone"}, + {BlockTextureId(1, 1), "minecraft/textures/blocks/stone_granite"}, + + {BlockTextureId(2, 0, 0), "minecraft/textures/blocks/dirt"}, + {BlockTextureId(2, 0, 1), "minecraft/textures/blocks/grass_top"}, + {BlockTextureId(2, 0, 2), "minecraft/textures/blocks/grass_side"}, + {BlockTextureId(2, 0, 3), "minecraft/textures/blocks/grass_side"}, + {BlockTextureId(2, 0, 4), "minecraft/textures/blocks/grass_side"}, + {BlockTextureId(2, 0, 5), "minecraft/textures/blocks/grass_side"}, + + {BlockTextureId(3, 0), "minecraft/textures/blocks/dirt"}, + {BlockTextureId(4, 0), "minecraft/textures/blocks/cobblestone"}, + {BlockTextureId(5, 0), "minecraft/textures/blocks/planks"}, + + {BlockTextureId(7, 0), "minecraft/textures/blocks/bedrock"}, + + {BlockTextureId(17, 0, 0), "minecraft/textures/blocks/log_oak_top"}, + {BlockTextureId(17, 0, 1), "minecraft/textures/blocks/log_oak_top"}, + {BlockTextureId(17, 0, 2), "minecraft/textures/blocks/log_oak"}, + {BlockTextureId(17, 0, 3), "minecraft/textures/blocks/log_oak"}, + {BlockTextureId(17, 0, 4), "minecraft/textures/blocks/log_oak"}, + {BlockTextureId(17, 0, 5), "minecraft/textures/blocks/log_oak"}, + + {BlockTextureId(17, 1, 0), "minecraft/textures/blocks/log_spruce_top"}, + {BlockTextureId(17, 1, 1), "minecraft/textures/blocks/log_spruce_top"}, + {BlockTextureId(17, 1, 2), "minecraft/textures/blocks/log_spruce"}, + {BlockTextureId(17, 1, 3), "minecraft/textures/blocks/log_spruce"}, + {BlockTextureId(17, 1, 4), "minecraft/textures/blocks/log_spruce"}, + {BlockTextureId(17, 1, 5), "minecraft/textures/blocks/log_spruce"}, + + {BlockTextureId(17, 2, 0), "minecraft/textures/blocks/log_birch_top"}, + {BlockTextureId(17, 2, 1), "minecraft/textures/blocks/log_birch_top"}, + {BlockTextureId(17, 2, 2), "minecraft/textures/blocks/log_birch"}, + {BlockTextureId(17, 2, 3), "minecraft/textures/blocks/log_birch"}, + {BlockTextureId(17, 2, 4), "minecraft/textures/blocks/log_birch"}, + {BlockTextureId(17, 2, 5), "minecraft/textures/blocks/log_birch"}, + + {BlockTextureId(17, 3, 0), "minecraft/textures/blocks/log_jungle_top"}, + {BlockTextureId(17, 3, 1), "minecraft/textures/blocks/log_jungle_top"}, + {BlockTextureId(17, 3, 2), "minecraft/textures/blocks/log_jungle"}, + {BlockTextureId(17, 3, 3), "minecraft/textures/blocks/log_jungle"}, + {BlockTextureId(17, 3, 4), "minecraft/textures/blocks/log_jungle"}, + {BlockTextureId(17, 3, 5), "minecraft/textures/blocks/log_jungle"}, + + {BlockTextureId(18, 0), "minecraft/textures/blocks/leaves_oak"}, + {BlockTextureId(18, 1), "minecraft/textures/blocks/leaves_spruce"}, + {BlockTextureId(18, 2), "minecraft/textures/blocks/leaves_birch"}, + {BlockTextureId(18, 3), "minecraft/textures/blocks/leaves_jungle"}, + + {BlockTextureId(61, 0, 0), "minecraft/textures/blocks/furnace_side"}, + {BlockTextureId(61, 0, 1), "minecraft/textures/blocks/furnace_top"}, + {BlockTextureId(61, 0, 2), "minecraft/textures/blocks/furnace_front_off"}, + {BlockTextureId(61, 0, 3), "minecraft/textures/blocks/furnace_side"}, + {BlockTextureId(61, 0, 4), "minecraft/textures/blocks/furnace_side"}, + {BlockTextureId(61, 0, 5), "minecraft/textures/blocks/furnace_side"}, + + {BlockTextureId(62, 0, 0), "minecraft/textures/blocks/furnace_side"}, + {BlockTextureId(62, 0, 1), "minecraft/textures/blocks/furnace_top"}, + {BlockTextureId(62, 0, 2), "minecraft/textures/blocks/furnace_front_on"}, + {BlockTextureId(62, 0, 3), "minecraft/textures/blocks/furnace_side"}, + {BlockTextureId(62, 0, 4), "minecraft/textures/blocks/furnace_side"}, + {BlockTextureId(62, 0, 5), "minecraft/textures/blocks/furnace_side"}, + + + {BlockTextureId(31, 0), "minecraft/textures/blocks/deadbush"}, + {BlockTextureId(31, 1), "minecraft/textures/blocks/tallgrass"}, + {BlockTextureId(31, 2), "minecraft/textures/blocks/fern"}, + }; + auto ret = lookupTable.find(block); + if (ret == lookupTable.end()) + return ""; + else + return ret->second; +} + +GLuint AssetManager::GetTextureAtlas() { + return textureAtlas->texture; +} + +TextureCoordinates AssetManager::GetTextureByBlock(BlockTextureId block) { + std::string assetName = this->GetTextureAssetNameByBlockId(block); + return this->GetTextureByAssetName(assetName); +} + +const std::map<BlockTextureId, glm::vec4> &AssetManager::GetTextureAtlasIndexes() { + if (!textureAtlasIndexes.empty()) + return textureAtlasIndexes; + + LOG(INFO) << "Initializing texture atlas..."; + for (int id = 1; id < 128; id++) { + for (int state = 0; state < 16; state++) { + BlockTextureId blockTextureId(id, state, 6); + if (!this->GetTextureByBlock(blockTextureId) && + !this->GetTextureByBlock(BlockTextureId(id, state, 0))) { + continue; + } + if (this->GetTextureByBlock(blockTextureId)) { + for (int i = 0; i < 6; i++) { + TextureCoordinates tc = this->GetTextureByBlock(BlockTextureId(id, state, 6)); + textureAtlasIndexes[BlockTextureId(id, state, i)] = glm::vec4(tc.x, tc.y, tc.w, tc.h); + } + } else { + for (int i = 0; i < 6; i++) { + TextureCoordinates tc = this->GetTextureByBlock(BlockTextureId(id, state, i)); + textureAtlasIndexes[BlockTextureId(id, state, i)] = glm::vec4(tc.x, tc.y, tc.w, tc.h); + } + } + } + } + LOG(INFO) << "Created " << textureAtlasIndexes.size() << " texture indexes"; + + return textureAtlasIndexes; +} diff --git a/old/core/AssetManager.hpp b/old/core/AssetManager.hpp new file mode 100644 index 0000000..667140a --- /dev/null +++ b/old/core/AssetManager.hpp @@ -0,0 +1,75 @@ +#pragma once + +#include <experimental/filesystem> +#include <map> + +#include <GL/glew.h> +#include <glm/vec4.hpp> +#include <nlohmann/json.hpp> + +#include "../world/Block.hpp" +#include "../graphics/Texture.hpp" + +struct TextureCoordinates { + TextureCoordinates(float x = -1, float y = -1, float w = -1, float h = -1) : x(x), y(y), w(w), h(h) {} + + bool operator==(const TextureCoordinates &rhs) const { + return x == rhs.x && + y == rhs.y && + w == rhs.w && + h == rhs.h; + } + + explicit operator bool() const { + return !(*this == TextureCoordinates(-1, -1, -1, -1)); + } + + float x, y, w, h; +}; + +struct BlockTextureId { + //Block sides: 0 - bottom, 1 - top, 2 - north, 3 - south, 4 - west, 5 - east 6 - every side + BlockTextureId(int id = 0, int state = 0, int side = 6) : id(id), state(state), side(side) {} + + int id:9; + int state:4; + int side:3; + + + bool operator<(const BlockTextureId &rhs) const { + if (id < rhs.id) + return true; + if (rhs.id < id) + return false; + if (state < rhs.state) + return true; + if (rhs.state < state) + return false; + return side < rhs.side; + } +}; + +class AssetManager { + Texture *textureAtlas; + std::map<std::string, Block> assetIds; + std::map<std::string, TextureCoordinates> assetTextures; + std::map<BlockTextureId,glm::vec4> textureAtlasIndexes; +public: + AssetManager(); + + ~AssetManager(); + + void LoadTextureResources(); + + TextureCoordinates GetTextureByAssetName(std::string AssetName); + + std::string GetTextureAssetNameByBlockId(BlockTextureId block); + + GLuint GetTextureAtlas(); + + const std::map<BlockTextureId,glm::vec4> &GetTextureAtlasIndexes(); + + void LoadIds(); + + TextureCoordinates GetTextureByBlock(BlockTextureId block); +}; diff --git a/old/core/Core.cpp b/old/core/Core.cpp new file mode 100644 index 0000000..e98d204 --- /dev/null +++ b/old/core/Core.cpp @@ -0,0 +1,457 @@ +#include "Core.hpp" + +//Core::Core():toRenderMutex("toRender"),availableChunksMutex("availableChunks") { +Core::Core() { + LOG(INFO) << "Core initializing..."; + InitSfml(900, 450, "AltCraft"); + glCheckError(); + InitGlew(); + glCheckError(); + client = new NetworkClient("127.0.0.1", 25565, "HelloOne", isRunning); + gameState = new GameState(client, isRunning); + gameStateLoopThread = std::thread(&Core::UpdateGameState, this); + sectionUpdateLoopThread = std::thread(&Core::UpdateSections, this); + assetManager = new AssetManager; + PrepareToRendering(); + LOG(INFO) << "Core is initialized"; + glCheckError(); +} + +Core::~Core() { + LOG(INFO) << "Core stopping..."; + gameStateLoopThread.join(); + sectionUpdateLoopThread.join(); + delete shader; + delete gameState; + delete client; + delete assetManager; + delete window; + LOG(INFO) << "Core is stopped"; +} + +void Core::Exec() { + LOG(INFO) << "Main loop is executing!"; + isRunning = true; + while (isRunning) { + static sf::Clock clock, clock1; + deltaTime = clock.getElapsedTime().asSeconds(); + absTime = clock1.getElapsedTime().asSeconds(); + clock.restart(); + + static bool alreadyDone = false; + if (gameState->g_IsGameStarted && !alreadyDone) { + alreadyDone = true; + UpdateChunksToRender(); + } + + std::ostringstream toWindow; + auto camPos = gameState->Position(); + auto velPos = glm::vec3(gameState->g_PlayerVelocityX, gameState->g_PlayerVelocityY, + gameState->g_PlayerVelocityZ); + toWindow << std::setprecision(2) << std::fixed; + toWindow << "Pos: " << camPos.x << ", " << camPos.y << ", " << camPos.z << "; "; + toWindow << "Health: " << gameState->g_PlayerHealth << "; "; + //toWindow << "OG: " << gameState->g_OnGround << "; "; + toWindow << "Vel: " << velPos.x << ", " << velPos.y << ", " << velPos.z << "; "; + toWindow << "FPS: " << (1.0f / deltaTime) << " "; + toWindow << " (" << deltaTime * 1000 << "ms); "; + toWindow << "Tickrate: " << tickRate << " (" << (1.0 / tickRate * 1000) << "ms); "; + toWindow << "Sections: " << sectionRate << " (" << (1.0 / sectionRate * 1000) << "ms); "; + window->setTitle(toWindow.str()); + + HandleEvents(); + if (isMouseCaptured) HandleMouseCapture(); + glCheckError(); + + RenderFrame(); + if (isRendersShouldBeCreated) { + availableChunksMutex.lock(); + for (auto &it:renders) { + auto pair = std::make_pair(it, RenderSection(&gameState->world, it)); + availableChunks.insert(pair); + } + renders.clear(); + availableChunksMutex.unlock(); + isRendersShouldBeCreated = false; + waitRendersCreated.notify_all(); + } + + } +} + +void Core::RenderFrame() { + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + switch (currentState) { + case MainMenu: + //RenderGui(MenuScreen); + break; + case Loading: + //RenderGui(LoadingScreen); + break; + case Playing: + RenderWorld(); + //RenderGui(HUD); + break; + case PauseMenu: + RenderWorld(); + //RenderGui(PauseGui); + break; + } + + window->display(); +} + +void Core::InitSfml(unsigned int WinWidth, unsigned int WinHeight, std::string WinTitle) { + LOG(INFO) << "Creating window: " << WinWidth << "x" << WinHeight << " \"" << WinTitle << "\""; + sf::ContextSettings contextSetting; + contextSetting.majorVersion = 3; + contextSetting.minorVersion = 3; + contextSetting.attributeFlags = contextSetting.Core; + contextSetting.depthBits = 24; + window = new sf::Window(sf::VideoMode(WinWidth, WinHeight), WinTitle, sf::Style::Default, contextSetting); + glCheckError(); + //window->setVerticalSyncEnabled(true); + //window->setPosition(sf::Vector2i(sf::VideoMode::getDesktopMode().width / 2, sf::VideoMode::getDesktopMode().height / 2)); + window->setPosition(sf::Vector2i(sf::VideoMode::getDesktopMode().width / 2 - window->getSize().x / 2, + sf::VideoMode::getDesktopMode().height / 2 - window->getSize().y / 2)); + + SetMouseCapture(false); +} + +void Core::InitGlew() { + LOG(INFO) << "Initializing GLEW"; + glewExperimental = GL_TRUE; + GLenum glewStatus = glewInit(); + glCheckError(); + if (glewStatus != GLEW_OK) { + LOG(FATAL) << "Failed to initialize GLEW: " << glewGetErrorString(glewStatus); + } + glViewport(0, 0, width(), height()); + glEnable(GL_DEPTH_TEST); + glEnable(GL_CULL_FACE); + glCullFace(GL_BACK); + glFrontFace(GL_CCW); + //glEnable(GL_BLEND); + //glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + glCheckError(); +} + +unsigned int Core::width() { + return window->getSize().x; +} + +unsigned int Core::height() { + return window->getSize().y; +} + +void Core::HandleEvents() { + sf::Event event; + while (window->pollEvent(event)) { + switch (event.type) { + case sf::Event::Closed: + LOG(INFO) << "Received close event by window closing"; + isRunning = false; + break; + case sf::Event::Resized: + glViewport(0, 0, width(), height()); + break; + case sf::Event::KeyPressed: + if (!window->hasFocus()) break; + switch (event.key.code) { + case sf::Keyboard::Escape: + LOG(INFO) << "Received close event by esc"; + isRunning = false; + break; + case sf::Keyboard::T: + SetMouseCapture(!isMouseCaptured); + break; + case sf::Keyboard::L: + ChunkDistance++; + LOG(INFO) << "Increased render distance: " << ChunkDistance; + break; + case sf::Keyboard::K: + if (ChunkDistance > 1) { + ChunkDistance--; + LOG(INFO) << "Decreased render distance: " << ChunkDistance; + } + break; + default: + break; + } + default: + break; + } + } + if (window->hasFocus()) { + if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) gameState->HandleMovement(GameState::FORWARD, deltaTime); + if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) gameState->HandleMovement(GameState::BACKWARD, deltaTime); + if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) gameState->HandleMovement(GameState::LEFT, deltaTime); + if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) gameState->HandleMovement(GameState::RIGHT, deltaTime); + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space)) gameState->HandleMovement(GameState::JUMP, deltaTime); + UpdateChunksToRender(); + } +} + +void Core::HandleMouseCapture() { + sf::Vector2i mousePos = sf::Mouse::getPosition(*window); + sf::Vector2i center = sf::Vector2i(window->getSize().x / 2, window->getSize().y / 2); + sf::Mouse::setPosition(center, *window); + mouseXDelta = (mousePos - center).x, mouseYDelta = (center - mousePos).y; + const float Sensetivity = 0.7f; + gameState->HandleRotation(mouseXDelta * Sensetivity, mouseYDelta * Sensetivity); + //camera.ProcessMouseMovement(mouseXDelta, mouseYDelta); +} + +void Core::RenderWorld() { + shader->Use(); + glCheckError(); + + GLint projectionLoc = glGetUniformLocation(shader->Program, "projection"); + GLint viewLoc = glGetUniformLocation(shader->Program, "view"); + GLint timeLoc = glGetUniformLocation(shader->Program, "time"); + glm::mat4 projection = glm::perspective(45.0f, (float) width() / (float) height(), 0.1f, 10000000.0f); + glm::mat4 view = gameState->GetViewMatrix(); + glUniformMatrix4fv(projectionLoc, 1, GL_FALSE, glm::value_ptr(projection)); + glUniformMatrix4fv(viewLoc, 1, GL_FALSE, glm::value_ptr(view)); + glUniform1f(timeLoc, absTime); + glUniform2f(glGetUniformLocation(shader->Program, "windowSize"), width(), height()); + + glCheckError(); + + toRenderMutex.lock(); + for (auto &render : toRender) { + availableChunksMutex.lock(); + auto iterator = availableChunks.find(render); + if (iterator == availableChunks.end()) { + availableChunksMutex.unlock(); + continue; + } + /*Section §ion = *iterator->second.GetSection(); + //availableChunksMutex.unlock(); + + std::vector<Vector> sectionCorners = { + Vector(0, 0, 0), + Vector(0, 0, 16), + Vector(0, 16, 0), + Vector(0, 16, 16), + Vector(16, 0, 0), + Vector(16, 0, 16), + Vector(16, 16, 0), + Vector(16, 16, 16), + }; + bool isBreak = true; + glm::mat4 vp = projection * view; + for (auto &it:sectionCorners) { + glm::vec3 point(section.GetPosition().GetX() * 16 + it.GetX(), + section.GetPosition().GetY() * 16 + it.GetY(), + section.GetPosition().GetZ() * 16 + it.GetZ()); + glm::vec4 p = vp * glm::vec4(point, 1); + glm::vec3 res = glm::vec3(p) / p.w; + if (res.x < 1 && res.x > -1 && res.y < 1 && res.y > -1 && res.z > 0) { + isBreak = false; + break; + } + } + if (isBreak && glm::length(gameState->Position() - + glm::vec3(section.GetPosition().GetX() * 16, + section.GetPosition().GetY() * 16, + section.GetPosition().GetZ() * 16)) > 30.0f) { + availableChunksMutex.unlock(); + continue; + } + //availableChunksMutex.lock();*/ + iterator->second.Render(renderState); + availableChunksMutex.unlock(); + } + toRenderMutex.unlock(); + glCheckError(); +} + +void Core::SetMouseCapture(bool IsCaptured) { + window->setMouseCursorVisible(!isMouseCaptured); + sf::Mouse::setPosition(sf::Vector2i(window->getSize().x / 2, window->getSize().y / 2), *window); + isMouseCaptured = IsCaptured; + window->setMouseCursorVisible(!IsCaptured); +} + +void Core::PrepareToRendering() { + shader = new Shader("./shaders/face.vs", "./shaders/face.fs"); + shader->Use(); + + //TextureAtlas texture + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, assetManager->GetTextureAtlas()); + glUniform1i(glGetUniformLocation(shader->Program, "textureAtlas"), 0); +} + +void Core::UpdateChunksToRender() { + return; + Vector playerChunk = Vector(floor(gameState->g_PlayerX / 16.0f), 0, floor(gameState->g_PlayerZ / 16.0f)); + static Vector previousPlayerChunk = playerChunk; + static bool firstTime = true; + static int previousRenderDistance = ChunkDistance; + if (previousPlayerChunk == playerChunk && !firstTime && ChunkDistance == previousRenderDistance) { + return; + } + previousPlayerChunk = playerChunk; + previousRenderDistance = ChunkDistance; + toRender.clear(); + for (auto &it:gameState->world.GetSectionsList()) { + Vector chunkPosition = it; + chunkPosition.SetY(0); + Vector delta = chunkPosition - playerChunk; + if (delta.GetMagnitude() > ChunkDistance) continue; + toRender.push_back(it); + } + for (auto &it:toRender) { + if (availableChunks.find(it) == availableChunks.end()) { + auto pair = std::make_pair(it, RenderSection(&gameState->world, it)); + pair.second.UpdateState(assetManager->GetTextureAtlasIndexes()); + availableChunks.insert(pair); + } else { + //availableChunks.find(it)->second.UpdateState(); + } + } + if (firstTime) LOG(INFO) << "Chunks to render: " << toRender.size() << " of " << availableChunks.size(); + firstTime = false; +} + +void Core::UpdateGameState() { + el::Helpers::setThreadName("Game"); + LOG(INFO) << "GameState thread is started"; + sf::Clock delta; + while (isRunning) { + float deltaTime = delta.getElapsedTime().asSeconds(); + delta.restart(); + gameState->Update(deltaTime); + const double targetDelta = 1 / 60.0; + std::chrono::duration<double, std::ratio<1, 1>> timeToSleep(targetDelta - delta.getElapsedTime().asSeconds()); + std::this_thread::sleep_for(timeToSleep); + tickRate = 1 / delta.getElapsedTime().asSeconds(); + } + LOG(INFO) << "GameState thread is stopped"; +} + +void Core::UpdateSections() { + glm::vec3 playerPosition = gameState->Position(); + float playerPitch = gameState->Pitch(); + float playerYaw = gameState->Yaw(); + sf::Clock delta; + std::vector<Vector> chunksToRender; + auto currentSectionIterator = chunksToRender.begin(); + while (isRunning) { + delta.restart(); + if (glm::length(glm::distance(gameState->Position(), playerPosition)) > 5.0f) { + chunksToRender.clear(); + playerPosition = gameState->Position(); + Vector playerChunk = Vector(floor(playerPosition.x / 16.0f), 0, floor(playerPosition.z / 16.0f)); + for (auto &it:gameState->world.GetSectionsList()) { + Vector chunkPosition = it; + chunkPosition.SetY(0); + Vector delta = chunkPosition - playerChunk; + if (delta.GetMagnitude() > ChunkDistance) continue; + chunksToRender.push_back(it); + } + std::sort(chunksToRender.begin(), chunksToRender.end(), [playerChunk](auto first, auto second) { + glm::vec3 fDistance = first - playerChunk; + glm::vec3 sDistance = second - playerChunk; + return glm::length(fDistance) < glm::length(sDistance); + }); + for (auto &it:chunksToRender) { + availableChunksMutex.lock(); + if (availableChunks.find(it) == availableChunks.end()) { + availableChunksMutex.unlock(); + renders.push_back(it); + } else + availableChunksMutex.unlock(); + } + if (!renders.empty()) { + std::mutex mutex; + std::unique_lock<std::mutex> lock(mutex); + isRendersShouldBeCreated = true; + while (isRendersShouldBeCreated) + waitRendersCreated.wait(lock); + } + currentSectionIterator = chunksToRender.begin(); + toRenderMutex.lock(); + toRender = chunksToRender; + toRenderMutex.unlock(); + } + if (currentSectionIterator != chunksToRender.end()) { + availableChunksMutex.lock(); + auto iterator = availableChunks.find(*currentSectionIterator); + if (iterator != availableChunks.end() && iterator->second.IsNeedUpdate()) { + RenderSection rs = std::move(iterator->second); + availableChunks.erase(iterator); + auto pair = std::make_pair(*currentSectionIterator, rs); + availableChunksMutex.unlock(); + + pair.second.UpdateState(assetManager->GetTextureAtlasIndexes()); + + availableChunksMutex.lock(); + availableChunks.insert(pair); + } + availableChunksMutex.unlock(); + currentSectionIterator = std::next(currentSectionIterator); + } + if (gameState->Pitch() != playerPitch || gameState->Yaw() != playerYaw) { + playerPitch = gameState->Pitch(); + playerYaw = gameState->Yaw(); + const std::vector<Vector> sectionCorners = { + Vector(0, 0, 0), + Vector(0, 0, 16), + Vector(0, 16, 0), + Vector(0, 16, 16), + Vector(16, 0, 0), + Vector(16, 0, 16), + Vector(16, 16, 0), + Vector(16, 16, 16), + }; + const glm::mat4 projection = glm::perspective(45.0f, (float)width() / (float)height(), 0.1f, 10000000.0f); + const glm::mat4 view = gameState->GetViewMatrix(); + const glm::mat4 vp = projection * view; + for (auto& section: toRender) { + bool isCulled = true; + for (auto &it : sectionCorners) { + glm::vec3 point(section.GetX() * 16 + it.GetX(), + section.GetY() * 16 + it.GetY(), + section.GetZ() * 16 + it.GetZ()); + glm::vec4 p = vp * glm::vec4(point, 1); + glm::vec3 res = glm::vec3(p) / p.w; + if (res.x < 1 && res.x > -1 && res.y < 1 && res.y > -1 && res.z > 0) { + isCulled = false; + break; + } + } + bool isVisible = !isCulled || glm::length(gameState->Position() - + glm::vec3(section.GetX() * 16, section.GetY() * 16, section.GetZ() * 16)) < 30.0f; + availableChunksMutex.lock(); + auto iter = availableChunks.find(section); + if (iter != availableChunks.end()) + iter->second.SetEnabled(isVisible); + availableChunksMutex.unlock(); + + } + } + using namespace std::chrono_literals; + std::this_thread::sleep_for(5ms); + sectionRate = delta.getElapsedTime().asSeconds(); + delta.restart(); + } +} + +MyMutex::MyMutex(std::string name) { + str = name; +} + +void MyMutex::lock() { + LOG(WARNING) << "Thread " << std::this_thread::get_id() << " locked mutex " << str; + mtx.lock(); +} + +void MyMutex::unlock() { + LOG(WARNING) << "Thread " << std::this_thread::get_id() << " unlocked mutex " << str; + mtx.unlock(); +}
\ No newline at end of file diff --git a/old/core/Core.hpp b/old/core/Core.hpp new file mode 100644 index 0000000..aaa143f --- /dev/null +++ b/old/core/Core.hpp @@ -0,0 +1,95 @@ +#pragma once + +#include <iomanip> +#include <tuple> + +#include <easylogging++.h> +#include <GL/glew.h> +#include <glm/gtc/type_ptr.hpp> +#include <SFML/Window.hpp> + +#include "../world/GameState.hpp" +#include "AssetManager.hpp" +#include "../graphics/Shader.hpp" +#include "../graphics/Gui.hpp" +#include "../graphics/RenderSection.hpp" +#include "../network/NetworkClient.hpp" + +struct MyMutex { + std::mutex mtx; + std::string str; + MyMutex(std::string name); + void lock(); + void unlock(); +}; + +class Core { + GameState *gameState; + NetworkClient *client; + sf::Window *window; + AssetManager *assetManager; + bool isMouseCaptured = false; + bool isRunning = true; + enum { + MainMenu, + Loading, + Playing, + PauseMenu, + } currentState = Playing; + float mouseXDelta, mouseYDelta; + float deltaTime; + float absTime; + + void RenderWorld(); + + void HandleMouseCapture(); + + void HandleEvents(); + + void InitSfml(unsigned int WinWidth, unsigned int WinHeight, std::string WinTitle); + + void InitGlew(); + + void SetMouseCapture(bool IsCaptured); + + void PrepareToRendering(); + + void RenderFrame(); + + unsigned int width(); + + unsigned int height(); + + void UpdateChunksToRender(); + + void UpdateGameState(); + + void UpdateSections(); + + std::thread gameStateLoopThread; + std::thread sectionUpdateLoopThread; + + Shader *shader; + //Cube verticies, Cube VAO, Cube UVs, TextureIndexes UboTextureIndexes, TextureData UboTextureIndexes, TextureData2 UboTextureIndexes, Blocks VBO, Models VBO, Line VAO, Lines VBO + bool isRendersShouldBeCreated=false; + std::condition_variable waitRendersCreated; + std::vector<Vector> renders; + std::mutex toRenderMutex; + std::vector<Vector> toRender; + std::map<Vector, RenderSection> availableChunks; + std::mutex availableChunksMutex; + + int ChunkDistance = 3; + + RenderState renderState; + + double tickRate = 0; + double sectionRate = 0; + +public: + Core(); + + ~Core(); + + void Exec(); +}; diff --git a/old/core/Event.cpp b/old/core/Event.cpp new file mode 100644 index 0000000..3b2cc7f --- /dev/null +++ b/old/core/Event.cpp @@ -0,0 +1,76 @@ +#include "Event.hpp" +#include <easylogging++.h> + +std::queue <Event> EventAgregator::eventsToHandle; +std::mutex EventAgregator::queueMutex; +bool EventAgregator::isStarted = false; +std::vector<EventListener*> EventAgregator::listeners; +std::mutex EventAgregator::listenersMutex; + +void EventAgregator::EventHandlingLoop() { + while (true) { + queueMutex.lock(); + if (!eventsToHandle.empty()) { + auto queue = eventsToHandle; + while (!eventsToHandle.empty()) + eventsToHandle.pop(); + queueMutex.unlock(); + + while (!queue.empty()) { + auto event = queue.front(); + listenersMutex.lock(); + for (auto& listener : listeners) { + LOG(INFO)<<"Listener notified about event"; + listener->PushEvent(event); + } + listenersMutex.unlock(); + queue.pop(); + } + + queueMutex.lock(); + } + queueMutex.unlock(); + } +} + +void EventAgregator::RegisterListener(EventListener &listener) { + listenersMutex.lock(); + LOG(INFO)<<"Registered handler "<<&listener; + listeners.push_back(&listener); + listenersMutex.unlock(); +} + +void EventAgregator::UnregisterListener(EventListener &listener) { + listenersMutex.lock(); + LOG(INFO)<<"Unregistered handler "<<&listener; + listeners.erase(std::find(listeners.begin(), listeners.end(), &listener)); + listenersMutex.unlock(); +} + + + +EventListener::EventListener() { + EventAgregator::RegisterListener(*this); +} + +EventListener::~EventListener() { + EventAgregator::UnregisterListener(*this); +} + +void EventListener::PushEvent(Event event) { + eventsMutex.lock(); + LOG(INFO)<<"Pushed event to queue"; + events.push(event); + eventsMutex.unlock(); +} + +/*void EventListener::RegisterHandler(EventType type, std::function<void(void*)> handler) { + handlers[type] = handler; +}*/ + +bool EventListener::IsEventsQueueIsNotEmpty() { + eventsMutex.lock(); + bool value = !events.empty(); + eventsMutex.unlock(); + return value; +}
\ No newline at end of file diff --git a/old/core/Event.hpp b/old/core/Event.hpp new file mode 100644 index 0000000..a8de1f3 --- /dev/null +++ b/old/core/Event.hpp @@ -0,0 +1,96 @@ +#pragma once + +#include <queue> +#include <map> +#include <thread> +#include <mutex> +#include <condition_variable> +#include <chrono> +#include <variant> +#include <functional> + +#include "../Vector.hpp" + +enum class EventType { + Echo, + ChunkChanged, +}; + +struct EchoData { + std::chrono::time_point<std::chrono::high_resolution_clock> time; +}; + +struct ChunkChangedData { + Vector chunkPosition; +}; + +using EventData = std::variant<EchoData, ChunkChangedData>; + +struct Event { + EventType type; + EventData data; +}; + +class EventListener { + friend class EventAgregator; + + using HandlerFunc = std::function<void(EventData)>; + + std::map<EventType, HandlerFunc> handlers; //TODO: There must be more elegant solution than std::variant of all data + + std::mutex eventsMutex; + + std::queue<Event> events; + + void PushEvent(Event event); + +public: + EventListener(); + ~EventListener(); + bool IsEventsQueueIsNotEmpty(); + + void RegisterHandler(EventType type, HandlerFunc handler) { + handlers[type] = handler; + } + + void HandleEvent() { + eventsMutex.lock(); + if (events.empty()) { + eventsMutex.unlock(); + return; + } + Event event = events.front(); + events.pop(); + eventsMutex.unlock(); + auto function = handlers[event.type]; + function(event.data); + } +}; + +class EventAgregator { + friend EventListener; + + EventAgregator() = default; + static std::queue<Event> eventsToHandle; + static std::mutex queueMutex; + static bool isStarted; + static std::vector<EventListener *> listeners; + static std::mutex listenersMutex; + + static void EventHandlingLoop(); + + static void RegisterListener(EventListener &listener); + static void UnregisterListener(EventListener &listener); + +public: + static void PushEvent(EventType type, EventData data) { + if (!isStarted) { + isStarted = true; + std::thread(&EventAgregator::EventHandlingLoop).detach(); + } + Event event; + event.type = type; + event.data = data; + eventsToHandle.push(event); + } +};
\ No newline at end of file |