diff --git a/Block Forge.vcxproj b/Block Forge.vcxproj index ec927c6b..2d07703c 100644 --- a/Block Forge.vcxproj +++ b/Block Forge.vcxproj @@ -150,24 +150,27 @@ + + + - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + @@ -176,58 +179,66 @@ - + - - - - - - - - + + + + + + + + + + + + + + + + - - - - - - - - - + + + + + + + + + - - - - - + + + + + - - - - - - - - - + + + + + + + + + + - - - - - - - + + + + + + @@ -238,17 +249,16 @@ - + - - - - - - - + + + + + + diff --git a/Block Forge.vcxproj.user b/Block Forge.vcxproj.user index ae53a810..07b8d691 100644 --- a/Block Forge.vcxproj.user +++ b/Block Forge.vcxproj.user @@ -4,11 +4,11 @@ true - --trace + --debug WindowsLocalDebugger - --trace + --debug WindowsLocalDebugger \ No newline at end of file diff --git a/Doxyfile b/Doxyfile index 658f50d7..72e57ea7 100644 --- a/Doxyfile +++ b/Doxyfile @@ -47,7 +47,7 @@ PROJECT_NAME = "Block Forge" # could be handy for archiving the generated documentation or if some version # control system is used. -PROJECT_NUMBER = v0.5 +PROJECT_NUMBER = v0.6 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer a diff --git a/src/Application/Application.cpp b/src/Application/Application.cpp index 5d307240..e25f76a5 100644 --- a/src/Application/Application.cpp +++ b/src/Application/Application.cpp @@ -1,7 +1,7 @@ #include "Application.h" #include "Core/EngineExceptions.h" -#include "Sandbox/Sandbox.h" +#include "LayerStack/Stack/SandboxStack.h" // As a static member of class this variable // must be here initialized @@ -15,6 +15,7 @@ void Application::WindowResizeEvent(GLFWwindow* const, const int width, const in _window.SetHeight(static_cast(height)); } + void Application::CentralizeWindow() const { const auto& x = _fullscreenWidth / 2 - _window.GetWidth() / 2; @@ -67,13 +68,18 @@ void Application::Initialize() ); } - glfwSetFramebufferSizeCallback(_window.GetHandle(), WindowResizeEvent); + SetCallbacks(); CentralizeWindow(); _log.Info("Block Forge initialized!"); } +void Application::SetCallbacks() +{ + glfwSetFramebufferSizeCallback(_window.GetHandle(), WindowResizeEvent); +} + Application::Application(const std::string& filenameWithSettings) { _settings.Load(filenameWithSettings); @@ -87,8 +93,22 @@ void Application::Run() { Initialize(); - const auto sandbox = std::make_unique(_window); - sandbox->Run(); + const auto sandbox = SandboxStack(_window); + _hid.DisableCursor(); + + while(!glfwWindowShouldClose(_window.GetHandle())) + { + if (_window.GetWidth() <= 0 || _window.GetHeight() <= 0) continue; + + glClearColor(0.07f, 0.13f, 0.17f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + sandbox.Update(); + sandbox.ProcessEvents(_hid); + + glfwSwapBuffers(_window.GetHandle()); + glfwPollEvents(); + } _log.Info("Quitting..."); diff --git a/src/Application/Application.h b/src/Application/Application.h index 50562aff..a4d8cc74 100644 --- a/src/Application/Application.h +++ b/src/Application/Application.h @@ -2,6 +2,7 @@ #include "Core/Log.h" #include "Core/Metadata.h" #include "Window.h" +#include "HID/HumanInterfaceDevice.h" /// @class Application /// @brief Represents the application context. @@ -12,16 +13,20 @@ class Application { static Window _window; + HumanInterfaceDevice _hid{_window}; Log& _log = Log::Get(); + Metadata _settings; size_t _fullscreenWidth{}; size_t _fullscreenHeight{}; static void WindowResizeEvent(GLFWwindow*, int width, int height); + void CentralizeWindow() const; void Initialize(); + static void SetCallbacks(); public: diff --git a/src/Application/HID/HumanInterfaceDevice.cpp b/src/Application/HID/HumanInterfaceDevice.cpp new file mode 100644 index 00000000..275270ca --- /dev/null +++ b/src/Application/HID/HumanInterfaceDevice.cpp @@ -0,0 +1,91 @@ +#include "HumanInterfaceDevice.h" + +int HumanInterfaceDevice::GetState(const KeyboardKey& key) const +{ + return glfwGetKey(_window.GetHandle(), static_cast(key)); +} + +int HumanInterfaceDevice::GetState(const MouseButton& button) const +{ + return glfwGetMouseButton(_window.GetHandle(), static_cast(button)); +} + +HumanInterfaceDevice::HumanInterfaceDevice(Window& window) : _window(window) +{ +} + +bool HumanInterfaceDevice::IsPressed(const KeyboardKey& key) const +{ + if (GetState(key) == GLFW_PRESS) + { + return true; + } + + return false; +} + +bool HumanInterfaceDevice::IsPressedOnce(const KeyboardKey& key) +{ + if (GetState(key) == GLFW_PRESS && _onceHandledKeyboardKeys.find(key) == _onceHandledKeyboardKeys.end()) + { + _onceHandledKeyboardKeys.insert(key); + return IsPressed(key); + } + + if (GetState(key) == GLFW_RELEASE) + { + _onceHandledKeyboardKeys.erase(key); + } + + return false; +} + +bool HumanInterfaceDevice::IsPressed(const MouseButton& button) const +{ + if (GetState(button) == GLFW_PRESS) + { + return true; + } + + return false; +} + +bool HumanInterfaceDevice::IsPressedOnce(const MouseButton& button) +{ + if (GetState(button) == GLFW_PRESS && _onceHandledMouseButtons.find(button) == _onceHandledMouseButtons.end()) + { + _onceHandledMouseButtons.insert(button); + return IsPressed(button); + } + + if (GetState(button) == GLFW_RELEASE) + { + _onceHandledMouseButtons.erase(button); + } + + return false; +} + +std::pair HumanInterfaceDevice::GetCursorPosition() const +{ + double x; + double y; + glfwGetCursorPos(_window.GetHandle(), &x, &y); + + return {x, y}; +} + +void HumanInterfaceDevice::SetCursorPosition(const double x, const double y) const +{ + glfwSetCursorPos(_window.GetHandle(), x, y); +} + +void HumanInterfaceDevice::EnableCursor() const +{ + glfwSetInputMode(_window.GetHandle(), GLFW_CURSOR, GLFW_CURSOR_NORMAL); +} + +void HumanInterfaceDevice::DisableCursor() const +{ + glfwSetInputMode(_window.GetHandle(), GLFW_CURSOR, GLFW_CURSOR_DISABLED); +} diff --git a/src/Application/Sandbox/Events/HumanInterfaceDevice.h b/src/Application/HID/HumanInterfaceDevice.h similarity index 71% rename from src/Application/Sandbox/Events/HumanInterfaceDevice.h rename to src/Application/HID/HumanInterfaceDevice.h index 626bd6be..a724f74a 100644 --- a/src/Application/Sandbox/Events/HumanInterfaceDevice.h +++ b/src/Application/HID/HumanInterfaceDevice.h @@ -1,7 +1,10 @@ #pragma once #include + #include "Core/Log.h" #include "KeyCodes.h" +#include "Application/Window.h" + /// @class HumanInterfaceDevice /// @brief Handles and defines input devices. @@ -9,20 +12,19 @@ class HumanInterfaceDevice { Log& _log = Log::Get(); - GLFWwindow* _window; + Window& _window; + std::unordered_set _onceHandledKeyboardKeys; std::unordered_set _onceHandledMouseButtons; - std::string KeyDescription(const KeyboardKey& key) const; - std::string ButtonDescription(const MouseButton& button) const; - int GetState(const KeyboardKey& key) const; int GetState(const MouseButton& button) const; public: + /// @brief The constructor. /// @param window - The window in which the simulation is played. - explicit HumanInterfaceDevice(GLFWwindow* window); + explicit HumanInterfaceDevice(Window& window); /// @brief Checks if the requested key is pressed. /// @param key - The key from keyboard. @@ -34,11 +36,6 @@ class HumanInterfaceDevice /// @return Returns true is the key is pressed and was not before, otherwise false. bool IsPressedOnce(const KeyboardKey& key); - /// @brief Checks if the requested key is released. - /// @param key - The key from keyboard. - /// @return Returns true is the key is released, otherwise false. - bool IsReleased(const KeyboardKey& key) const; - /// @brief Checks if the requested button is pressed. /// @param button - The button from mouse. /// @return Returns true is the button is pressed, otherwise false. @@ -49,8 +46,17 @@ class HumanInterfaceDevice /// @return Returns true is the button is pressed and was not before, otherwise false. bool IsPressedOnce(const MouseButton& button); - /// @brief Checks if the requested button is released. - /// @param button - The button from keyboard. - /// @return Returns true is the button is released, otherwise false. - bool IsReleased(const MouseButton& button) const; + /// @brief Returns the current cursor position. + std::pair GetCursorPosition() const; + + /// @brief Sets the cursor position to the desired location. + /// @param x - Cursor X location. + /// @param y - Cursor Y location. + void SetCursorPosition(double x, double y) const; + + /// @brief Enables cursor making it visible. + void EnableCursor() const; + + /// @brief Disables cursor making it invisible. + void DisableCursor() const; }; \ No newline at end of file diff --git a/src/Application/Sandbox/Events/KeyCodes.h b/src/Application/HID/KeyCodes.h similarity index 100% rename from src/Application/Sandbox/Events/KeyCodes.h rename to src/Application/HID/KeyCodes.h diff --git a/src/Application/Layer/Layer.h b/src/Application/Layer/Layer.h new file mode 100644 index 00000000..3d3992b7 --- /dev/null +++ b/src/Application/Layer/Layer.h @@ -0,0 +1,62 @@ +#pragma once + +/// @class Layer +/// @brief Represents a layer that is used by the layer stack. +/// @see LayerStack +class Layer +{ + bool _isLocked = false; + +protected: + + /// @brief Locks the layer, so the next ones won't be processed + /// by the OnEvent() method. + void LockLayer() + { + _isLocked = true; + } + + /// @brief Unlocks the layer. + void UnlockLayer() + { + _isLocked = false; + } + +public: + Layer() = default; + + /// @brief Copy constructor. + Layer(const Layer&) = default; + + /// @brief Move constructor. + Layer(Layer&&) = default; + Layer& operator=(const Layer&) = delete; + Layer& operator=(Layer&&) = delete; + + /// @brief This method is responsible for drawing data on the screen. + /// @details This method is used basically for rendering. + /// Add the functionality that handles drawing every frame. + virtual void OnUpdate() = 0; + + /// @brief This method is used to handle events. + /// @details This method should be used when you want to declare functionality that is strongly related to this layer. + /// For example, when you are playing a simulation and you pause the game. + /// Then you may want to freeze input events that are related to this layer, + /// but you would like to render the content of this layer. + /// + /// Using this method, you can tell it to freeze when necessary and + /// use the OnUpdate() method to render continuously. + /// @param hid - Reference to the Human Interface Device. + virtual void OnEvent(HumanInterfaceDevice& hid) = 0; + + /// @brief Checks if this layer is locked. + /// @details If the layer is locked, + /// it means that the lower layers from the layer stack should be skipped. + bool IsLocked() const + { + return _isLocked; + } + + virtual ~Layer() = default; +}; + diff --git a/src/Application/Layer/PauseMenu/PauseMenuLayer.h b/src/Application/Layer/PauseMenu/PauseMenuLayer.h new file mode 100644 index 00000000..335e1850 --- /dev/null +++ b/src/Application/Layer/PauseMenu/PauseMenuLayer.h @@ -0,0 +1,33 @@ +#pragma once +#include "Application/HID/HumanInterfaceDevice.h" +#include "Application/Layer/Layer.h" + +/// @class PauseMenuLayer +/// @brief Represents the pause menu. +class PauseMenuLayer final : public Layer +{ +public: + + void OnUpdate() override + { + // For now there is nothing to render. + // That's why this method is empty. + } + + void OnEvent(HumanInterfaceDevice& hid) override + { + if (hid.IsPressedOnce(KeyboardKey::escape)) + { + if (IsLocked()) + { + hid.DisableCursor(); + + UnlockLayer(); + return; + } + + hid.EnableCursor(); + LockLayer(); + } + } +}; diff --git a/src/Application/Layer/Sandbox/Camera.cpp b/src/Application/Layer/Sandbox/Camera.cpp new file mode 100644 index 00000000..99ab16f9 --- /dev/null +++ b/src/Application/Layer/Sandbox/Camera.cpp @@ -0,0 +1,164 @@ +#include "Camera.h" + +void Camera::Update() +{ + // ReSharper disable once CppInitializedValueIsAlwaysRewritten + auto view = glm::mat4(1.0f); + view = lookAt(_position, _position + _orientation, _upVector); + + const float aspectRatio = static_cast(_window.GetWidth()) / static_cast(_window.GetHeight()); + + // ReSharper disable once CppInitializedValueIsAlwaysRewritten + auto projection = glm::mat4(1.0f); + projection = glm::perspective(glm::radians(_fieldOfView), aspectRatio, _nearPane, _farPane); + + _orthographicProjection = projection * view; +} + +void Camera::HandleHorizontalMovement(const HumanInterfaceDevice& hid) +{ + if (hid.IsPressed(_left)) + { + _position += _speed * -normalize(cross(_orientation, _upVector)); + } + if (hid.IsPressed(_right)) + { + _position += _speed * normalize(cross(_orientation, _upVector)); + } + if (hid.IsPressed(_forward)) + { + _position += _speed * _orientation; + } + if (hid.IsPressed(_backward)) + { + _position += _speed * -_orientation; + } +} + +void Camera::HandleVerticalMovement(const HumanInterfaceDevice& hid) +{ + if (hid.IsPressed(_up)) + { + _position += _speed * _upVector; + } + if (hid.IsPressed(_down)) + { + _position += _speed * -_upVector; + } +} + +void Camera::HandleSpeed(const float boostSpeed, const HumanInterfaceDevice& hid) +{ + _speed = hid.IsPressed(_boost) ? boostSpeed : _defaultSpeed; +} + +void Camera::UpdateCursorMovement(const HumanInterfaceDevice& hid) +{ + const auto& mousePosition = hid.GetCursorPosition(); + const auto& mouseX = mousePosition.first; + const auto& mouseY = mousePosition.second; + + const auto& middleAxisX = mouseX / 2.0; + const auto& middleAxisY = mouseY / 2.0; + + const float xAxisRotation = _sensitivity * (static_cast(middleAxisY) / static_cast(_window.GetHeight())); + const float yAxisRotation = _sensitivity * (static_cast(middleAxisX) / static_cast(_window.GetWidth())); + + const auto orientation = rotate(_orientation, glm::radians(-xAxisRotation), normalize(cross(_orientation, _upVector))); + const auto angleWithXAxis = abs(angle(orientation, _upVector) - glm::radians(90.0f)); + + // This prevents the barrel roll situation when looking up + if (angleWithXAxis < glm::radians(85.0f)) + { + _orientation = orientation; + } + + _orientation = rotate(_orientation, glm::radians(-yAxisRotation), _upVector); + + hid.SetCursorPosition(middleAxisX, middleAxisY); +} + +Camera::Camera(Window& window, const glm::vec3 position) + : _window(window), + _position(position) +{ +} + +void Camera::Bind(Shader const& shader) const +{ + shader.Load(); + glUniformMatrix4fv(glGetUniformLocation(shader.GetProgram(), "camera"), 1, GL_FALSE, value_ptr(_orthographicProjection)); +} + +void Camera::HandleInput(const HumanInterfaceDevice& hid) +{ + HandleHorizontalMovement(hid); + HandleVerticalMovement(hid); + HandleSpeed(0.4f, hid); + UpdateCursorMovement(hid); +} + +glm::vec3 Camera::GetPosition() const +{ + return _position; +} + +inline float Camera::GetDefaultSpeed() const +{ + return _defaultSpeed; +} + +inline void Camera::SetDefaultSpeed(const float defaultSpeed) +{ + _defaultSpeed = defaultSpeed; +} + +inline float Camera::GetSpeed() const +{ + return _speed; +} + +inline void Camera::SetSpeed(const float speed) +{ + _speed = speed; +} + +inline float Camera::GetSensitivity() const +{ + return _sensitivity; +} + +inline void Camera::SetSensitivity(const float sensitivity) +{ + _sensitivity = sensitivity; +} + +inline float Camera::GetFieldOfView() const +{ + return _fieldOfView; +} + +inline void Camera::SetFieldOfView(const float fieldOfView) +{ + _fieldOfView = fieldOfView; +} + +inline float Camera::GetNearPane() const +{ + return _nearPane; +} + +inline void Camera::SetNearPane(const float nearPane) +{ + _nearPane = nearPane; +} + +inline float Camera::GetFarPane() const +{ + return _farPane; +} + +inline void Camera::SetFarPane(const float farPane) +{ + _farPane = farPane; +} \ No newline at end of file diff --git a/src/Application/Sandbox/Camera.h b/src/Application/Layer/Sandbox/Camera.h similarity index 74% rename from src/Application/Sandbox/Camera.h rename to src/Application/Layer/Sandbox/Camera.h index fbd37187..59084ad1 100644 --- a/src/Application/Sandbox/Camera.h +++ b/src/Application/Layer/Sandbox/Camera.h @@ -4,9 +4,9 @@ #include #include -#include "Events/HumanInterfaceDevice.h" #include "Model/Mesh/Geometry/Shader.h" -#include "Application/Window.h" +#include "Application/HID/HumanInterfaceDevice.h" + /// @class Camera /// @brief Handles input to allow spectating the world. @@ -18,7 +18,7 @@ class Camera glm::vec3 _position{}; glm::vec3 _orientation = glm::vec3(0.0f, 0.0f, -1.0f); - glm::vec3 _up = glm::vec3(0.0f, 1.0f, 0.0f); + glm::vec3 _upVector = glm::vec3(0.0f, 1.0f, 0.0f); glm::mat4 _orthographicProjection = glm::mat4(1.0f); float _defaultSpeed = 0.1f; @@ -28,20 +28,26 @@ class Camera float _nearPane = 0.1f; float _farPane = 100.0f; - HumanInterfaceDevice& _hid; - bool _isPaused = false; + const KeyboardKey _left = KeyboardKey::a; + const KeyboardKey _right = KeyboardKey::d; + const KeyboardKey _forward = KeyboardKey::w; + const KeyboardKey _backward = KeyboardKey::s; + + const KeyboardKey _up = KeyboardKey::space; + const KeyboardKey _down = KeyboardKey::leftCtrl; + + const KeyboardKey _boost = KeyboardKey::leftShift; - void HandleHorizontalMovement(const KeyboardKey& left, const KeyboardKey& right, const KeyboardKey& forward, const KeyboardKey& backward); - void HandleVerticalMovement(const KeyboardKey& up, const KeyboardKey& down); - void HandleSpeed(const KeyboardKey& boost, float boostSpeed); - void HandleCursorMovement(); + void HandleHorizontalMovement(const HumanInterfaceDevice& hid); + void HandleVerticalMovement(const HumanInterfaceDevice& hid); + void HandleSpeed(float boostSpeed, const HumanInterfaceDevice& hid); + void UpdateCursorMovement(const HumanInterfaceDevice& hid); public: /// @brief The constructor. /// @param window - Reference to the application window. /// @param position - Spawn point of the camera. - /// @param hid - Pointer to the HID handler. - Camera(Window& window, glm::vec3 position, HumanInterfaceDevice& hid); + Camera(Window& window, glm::vec3 position); /// @brief Update the camera orthogonal projection settings. void Update(); @@ -51,18 +57,13 @@ class Camera void Bind(Shader const& shader) const; /// @brief Captures input and moves the camera accordingly. - void HandleInput(); + /// @param hid - Reference to the Human Interface Device controller. + void HandleInput(const HumanInterfaceDevice& hid); /// @brief Get camera position. /// @return Returns 3D vector representation. glm::vec3 GetPosition() const; - /// @brief Get width. - size_t GetWidth() const; - - /// @brief Get height. - size_t GetHeight() const; - /// @brief Get default speed. /// @details The default speed is the normal speed of the camera. float GetDefaultSpeed() const; diff --git a/src/Application/Layer/Sandbox/Model/BlockFaceModel.cpp b/src/Application/Layer/Sandbox/Model/BlockFaceModel.cpp new file mode 100644 index 00000000..b7ff6d9b --- /dev/null +++ b/src/Application/Layer/Sandbox/Model/BlockFaceModel.cpp @@ -0,0 +1,10 @@ +#include "BlockFaceModel.h" + +BlockFaceModel::BlockFaceModel(const std::array& uvTextureCoordinates) : _textureCoordinates(uvTextureCoordinates) +{ +} + +std::array& BlockFaceModel::GetUvCoordinates() +{ + return _textureCoordinates; +} diff --git a/src/Application/Layer/Sandbox/Model/BlockFaceModel.h b/src/Application/Layer/Sandbox/Model/BlockFaceModel.h new file mode 100644 index 00000000..0318f58e --- /dev/null +++ b/src/Application/Layer/Sandbox/Model/BlockFaceModel.h @@ -0,0 +1,18 @@ +#pragma once +#include "Mesh/Mesh.h" + +/// @class BlockFaceModel +/// @brief Represents face of a @see BlockModel. +class BlockFaceModel +{ + std::array _textureCoordinates{}; + +public: + + /// @brief The constructor. + /// @param uvTextureCoordinates - UV texture coordinates. + explicit BlockFaceModel(const std::array& uvTextureCoordinates); + + /// @brief Returns the uv coordinates associated with the face model. + std::array& GetUvCoordinates(); +}; diff --git a/src/Application/Layer/Sandbox/Model/BlockModel.h b/src/Application/Layer/Sandbox/Model/BlockModel.h new file mode 100644 index 00000000..0241259d --- /dev/null +++ b/src/Application/Layer/Sandbox/Model/BlockModel.h @@ -0,0 +1,71 @@ +#pragma once +#include "BlockFaceModel.h" + +/// @brief Container for the face models of a block. +struct BlockFaces +{ + /// @brief Model of the block front face. + BlockFaceModel front; + + /// @brief Model of the block back face. + BlockFaceModel back; + + /// @brief Model of the block left face. + BlockFaceModel left; + + /// @brief Model of the block right face. + BlockFaceModel right; + + /// @brief Model of the block top face. + BlockFaceModel top; + + /// @brief Model of the block bottom face. + BlockFaceModel bottom; +}; + + +/// @brief Represents visibility of the faces. +struct FacesVisibility +{ + /// @brief Answers the question "Is the front face of this block visible?". + bool front; + + /// @brief Answers the question "Is the back face of this block visible?". + bool back; + + /// @brief Answers the question "Is the left face of this block visible?". + bool left; + + /// @brief Answers the question "Is the right face of this block visible?". + bool right; + + /// @brief Answers the question "Is the top face of this block visible?". + bool top; + + /// @brief Answers the question "Is the bottom face of this block visible?". + bool bottom; +}; + +/// @class BlockModel +/// @brief Represents a graphical model of a block. +/// @note This class is not an actual model. +/// More like container for the @see BlockFaceModel objects. But it suits well it's definition and +/// has functionality that makes sense. +class BlockModel +{ + BlockFaces _blockFaces; + +public: + + /// @brief The constructor. + /// @param faces - The faces of the block. + explicit BlockModel(const BlockFaces& faces) + : _blockFaces(faces) + {} + + /// @brief Returns the faces data of the block. + BlockFaces& GetFaces() + { + return _blockFaces; + } +}; \ No newline at end of file diff --git a/src/Application/Layer/Sandbox/Model/Mesh/DynamicMesh.cpp b/src/Application/Layer/Sandbox/Model/Mesh/DynamicMesh.cpp new file mode 100644 index 00000000..7418a784 --- /dev/null +++ b/src/Application/Layer/Sandbox/Model/Mesh/DynamicMesh.cpp @@ -0,0 +1,79 @@ +#include "DynamicMesh.h" + +#include "Application/Layer/Sandbox/World/Biomes/Biome.h" + +std::vector DynamicMesh::GenerateIndicesFromPattern(const std::vector& pattern, const size_t& maxVerticesAmount) const +{ + std::vector indices; + for (size_t i = 0; i < maxVerticesAmount; ++i) + { + const auto& multiplier = i * _indicesInOneInstance; + + constexpr auto indicesInOneTriangle = 3; + for (auto j = 0; j < _indicesInPatternAmount / indicesInOneTriangle; ++j) + { + indices.emplace_back(pattern[j] + static_cast(multiplier)); + } + } + + return indices; +} + +DynamicMesh::DynamicMesh( + std::vector vertices, + const std::vector& indicesPattern, + Shader& shader, + const size_t& maxInstancesAmount) : _shader(shader), _vertices(std::move(vertices)) +{ + constexpr auto indexesInOneTriangle = 3; + _indicesInPatternAmount = static_cast(indicesPattern.size()) * indexesInOneTriangle; + + const auto& triangleWithMaxValue = std::max_element( + indicesPattern.begin(), + indicesPattern.end(), + [](const TriangleIndexes &a, const TriangleIndexes &b) + { + return std::max({a.x, a.y, a.z}) < std::max({b.x, b.y, b.z}); + } + ); + _indicesInOneInstance = std::max({triangleWithMaxValue->x, triangleWithMaxValue->y, triangleWithMaxValue->z}) + 1; + + const auto& indices = GenerateIndicesFromPattern(indicesPattern, maxInstancesAmount); + + GetVao().Bind(); + _vbo = std::make_unique(sizeof(Vertex), maxInstancesAmount * _indicesInOneInstance); + const auto ebo = ElementBuffer(indices); + + constexpr auto stride = sizeof(Vertex) / sizeof(float); + constexpr auto vector2dSize = 2; + constexpr auto vector3dSize = 3; + + GetVao().Link(*_vbo, 0, vector3dSize, stride, 0); + GetVao().Link(*_vbo, 1, vector2dSize, stride, vector3dSize); + + GetVao().Unbind(); + _vbo->Unbind(); + ebo.Unbind(); +} + +void DynamicMesh::Update(const std::vector& vertices) +{ + _vertices = vertices; + + _vbo->Bind(); + glBufferSubData(GL_ARRAY_BUFFER, 0, static_cast(_vertices.size()) * static_cast(sizeof(Vertex)), _vertices.data()); + _vbo->Unbind(); +} + +void DynamicMesh::Draw(const Texture& texture, const Camera& camera) +{ + if (_vertices.empty()) return; + + camera.Bind(_shader); + + GetVao().Bind(); + texture.Bind(_shader); + glDrawElements(GL_TRIANGLES, static_cast(_vertices.size()) / _indicesInOneInstance * _indicesInPatternAmount, GL_UNSIGNED_INT, nullptr); + texture.Unbind(); + GetVao().Unbind(); +} diff --git a/src/Application/Layer/Sandbox/Model/Mesh/DynamicMesh.h b/src/Application/Layer/Sandbox/Model/Mesh/DynamicMesh.h new file mode 100644 index 00000000..a010543c --- /dev/null +++ b/src/Application/Layer/Sandbox/Model/Mesh/DynamicMesh.h @@ -0,0 +1,37 @@ +#pragma once +#include "Mesh.h" + +/// @class DynamicMesh +/// @brief Represents a dynamic mesh of a Model. +/// @details Dynamic mesh is a mesh that it's vertices could be changed in a runtime. +/// @note If your object won't change its structure, you should use StaticMesh. +class DynamicMesh final : protected Mesh +{ + std::unique_ptr _vbo; + + Shader& _shader; + std::vector _vertices; + GLsizei _indicesInPatternAmount{}; + GLsizei _indicesInOneInstance{}; + + std::vector GenerateIndicesFromPattern(const std::vector& pattern, const size_t& maxVerticesAmount) const; + +public: + + /// @brief The constructor. + /// @param vertices - The vertices of the mesh. + /// @param indicesPattern - The indices pattern sequence of the vertices position (to replicate for allocating the buffer). + /// @param shader - The shader that the mesh is using. + /// @param maxInstancesAmount - Amount of maximum possible instances to create within this mesh. + DynamicMesh(std::vector vertices, const std::vector& indicesPattern, Shader& shader, const size_t& maxInstancesAmount); + + /// @brief Rebuilds the mesh. + /// @param vertices - new mesh vertices. + void Update(const std::vector& vertices); + + /// @brief Draws the mesh. + /// @param texture - The texture to cover the mesh. + /// @param camera - It is used to bind a shader to see the drawn mesh. + void Draw(const Texture& texture, const Camera& camera); +}; + diff --git a/src/Application/Sandbox/Model/Mesh/Geometry/ElementBuffer.cpp b/src/Application/Layer/Sandbox/Model/Mesh/Geometry/ElementBuffer.cpp similarity index 92% rename from src/Application/Sandbox/Model/Mesh/Geometry/ElementBuffer.cpp rename to src/Application/Layer/Sandbox/Model/Mesh/Geometry/ElementBuffer.cpp index ed48185d..ee847d3b 100644 --- a/src/Application/Sandbox/Model/Mesh/Geometry/ElementBuffer.cpp +++ b/src/Application/Layer/Sandbox/Model/Mesh/Geometry/ElementBuffer.cpp @@ -5,7 +5,7 @@ ElementBuffer::ElementBuffer(const std::vector& indices) const auto verticesDataSize = static_cast(indices.size()) * static_cast(sizeof(TriangleIndexes)); glGenBuffers(1, &_bufferRef); - Bind(); + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _bufferRef); glBufferData(GL_ELEMENT_ARRAY_BUFFER, verticesDataSize, indices.data(), GL_STATIC_DRAW); } diff --git a/src/Application/Sandbox/Model/Mesh/Geometry/ElementBuffer.h b/src/Application/Layer/Sandbox/Model/Mesh/Geometry/ElementBuffer.h similarity index 100% rename from src/Application/Sandbox/Model/Mesh/Geometry/ElementBuffer.h rename to src/Application/Layer/Sandbox/Model/Mesh/Geometry/ElementBuffer.h diff --git a/src/Application/Sandbox/Model/Mesh/Geometry/Shader.cpp b/src/Application/Layer/Sandbox/Model/Mesh/Geometry/Shader.cpp similarity index 94% rename from src/Application/Sandbox/Model/Mesh/Geometry/Shader.cpp rename to src/Application/Layer/Sandbox/Model/Mesh/Geometry/Shader.cpp index 0dbda64f..ae890b1a 100644 --- a/src/Application/Sandbox/Model/Mesh/Geometry/Shader.cpp +++ b/src/Application/Layer/Sandbox/Model/Mesh/Geometry/Shader.cpp @@ -19,7 +19,7 @@ std::string Shader::GetFileContents(const std::string& filename) const contents.resize(static_cast(file.tellg())); file.seekg(0, std::ios::beg); - file.read(&contents[0], contents.size()); // NOLINT(readability-container-data-pointer) + file.read(&contents[0], static_cast(contents.size())); // NOLINT(readability-container-data-pointer) file.close(); return contents; diff --git a/src/Application/Sandbox/Model/Mesh/Geometry/Shader.h b/src/Application/Layer/Sandbox/Model/Mesh/Geometry/Shader.h similarity index 100% rename from src/Application/Sandbox/Model/Mesh/Geometry/Shader.h rename to src/Application/Layer/Sandbox/Model/Mesh/Geometry/Shader.h diff --git a/src/Application/Sandbox/Model/Mesh/Geometry/Structures.h b/src/Application/Layer/Sandbox/Model/Mesh/Geometry/Structures.h similarity index 58% rename from src/Application/Sandbox/Model/Mesh/Geometry/Structures.h rename to src/Application/Layer/Sandbox/Model/Mesh/Geometry/Structures.h index 0fdbf214..3d857aa5 100644 --- a/src/Application/Sandbox/Model/Mesh/Geometry/Structures.h +++ b/src/Application/Layer/Sandbox/Model/Mesh/Geometry/Structures.h @@ -9,17 +9,23 @@ using Matrix = glm::mat4; /// @brief The group of indexes that represent the indices of the mesh. using TriangleIndexes = glm::ivec3; -/// @brief A position in space of the object. -using Position = glm::vec3; +/// @brief A position of an object. +using Position = glm::ivec3; + +/// @brief A point in the 3D space. +using Point3D = glm::vec3; /// @brief A point in the 2D space. using Point = glm::vec2; +/// @brief Tells how many vertices a quad (two triangles connected by a hypotenuse) has. +constexpr size_t VerticesInQuad = 4; + /// @brief Represent a single vertex that is used by the shader. struct Vertex { - /// @brief The position of the vertex in space. - Position position; + /// @brief The position of the vertex in the mesh. + Point3D position; /// @brief The texture UV coordinate. Point uvCoordinate; diff --git a/src/Application/Sandbox/Model/Mesh/Geometry/VertexArray.cpp b/src/Application/Layer/Sandbox/Model/Mesh/Geometry/VertexArray.cpp similarity index 88% rename from src/Application/Sandbox/Model/Mesh/Geometry/VertexArray.cpp rename to src/Application/Layer/Sandbox/Model/Mesh/Geometry/VertexArray.cpp index 34d7fd88..f4461b3c 100644 --- a/src/Application/Sandbox/Model/Mesh/Geometry/VertexArray.cpp +++ b/src/Application/Layer/Sandbox/Model/Mesh/Geometry/VertexArray.cpp @@ -11,14 +11,15 @@ VertexArray::VertexArray() void VertexArray::Link(const VertexBuffer& vbo, const GLuint layout, const GLint size, const GLsizei stride, const GLint offset) const { vbo.Bind(); + glVertexAttribPointer( layout, size, GL_FLOAT, GL_FALSE, static_cast(stride * sizeof(float)), - reinterpret_cast(offset * sizeof(float)) + reinterpret_cast(offset * sizeof(float)) // NOLINT(performance-no-int-to-ptr) ); - glEnableVertexAttribArray(layout); + vbo.Unbind(); } diff --git a/src/Application/Sandbox/Model/Mesh/Geometry/VertexArray.h b/src/Application/Layer/Sandbox/Model/Mesh/Geometry/VertexArray.h similarity index 100% rename from src/Application/Sandbox/Model/Mesh/Geometry/VertexArray.h rename to src/Application/Layer/Sandbox/Model/Mesh/Geometry/VertexArray.h diff --git a/src/Application/Sandbox/Model/Mesh/Geometry/VertexBuffer.cpp b/src/Application/Layer/Sandbox/Model/Mesh/Geometry/VertexBuffer.cpp similarity index 67% rename from src/Application/Sandbox/Model/Mesh/Geometry/VertexBuffer.cpp rename to src/Application/Layer/Sandbox/Model/Mesh/Geometry/VertexBuffer.cpp index bacae7ba..0764a2e4 100644 --- a/src/Application/Sandbox/Model/Mesh/Geometry/VertexBuffer.cpp +++ b/src/Application/Layer/Sandbox/Model/Mesh/Geometry/VertexBuffer.cpp @@ -11,6 +11,13 @@ VertexBuffer::VertexBuffer(const std::vector& vertices) glBufferData(GL_ARRAY_BUFFER, verticesSize, vertices.data(), GL_STATIC_DRAW); } +VertexBuffer::VertexBuffer(const size_t& vertexSize, const size_t& maxAmountOfVertices) +{ + glGenBuffers(1, &_bufferRef); + glBindBuffer(GL_ARRAY_BUFFER, _bufferRef); + glBufferData(GL_ARRAY_BUFFER, static_cast(vertexSize) * static_cast(maxAmountOfVertices), nullptr, GL_DYNAMIC_DRAW); +} + void VertexBuffer::Bind() const { glBindBuffer(GL_ARRAY_BUFFER, _bufferRef); diff --git a/src/Application/Sandbox/Model/Mesh/Geometry/VertexBuffer.h b/src/Application/Layer/Sandbox/Model/Mesh/Geometry/VertexBuffer.h similarity index 64% rename from src/Application/Sandbox/Model/Mesh/Geometry/VertexBuffer.h rename to src/Application/Layer/Sandbox/Model/Mesh/Geometry/VertexBuffer.h index d5ec9a9e..fda9b30d 100644 --- a/src/Application/Sandbox/Model/Mesh/Geometry/VertexBuffer.h +++ b/src/Application/Layer/Sandbox/Model/Mesh/Geometry/VertexBuffer.h @@ -12,8 +12,15 @@ class VertexBuffer public: /// @brief The constructor creates VBO, binds it immediately and sets its data. + /// @warning This constructor creates **STATIC** vertex buffer object. + /// It's meant to represent single objects or to be used with instancing. explicit VertexBuffer(const std::vector& vertices); + /// @brief The constructor creates VBO, binds it immediately and sets its data. + /// @warning This constructor **allocates** **DYNAMIC** vertex buffer object. + /// It's meant to be flexible and it's empty! + explicit VertexBuffer(const size_t& vertexSize, const size_t& maxAmountOfVertices); + VertexBuffer(const VertexBuffer&) = delete; /// @brief Move constructor. diff --git a/src/Application/Layer/Sandbox/Model/Mesh/Mesh.h b/src/Application/Layer/Sandbox/Model/Mesh/Mesh.h new file mode 100644 index 00000000..2d98a0a5 --- /dev/null +++ b/src/Application/Layer/Sandbox/Model/Mesh/Mesh.h @@ -0,0 +1,26 @@ +// ReSharper disable CppUnusedIncludeDirective +#pragma once +#include "Geometry/Structures.h" +#include "Geometry/Shader.h" +#include "Geometry/VertexArray.h" +#include "Geometry/ElementBuffer.h" +#include "Application/Layer/Sandbox/Camera.h" +#include "Application/Layer/Sandbox/Model/Surface/Texture.h" + +/// @class Mesh +/// @brief The interface for the classes which purpose is to create mesh for the models. +class Mesh // NOLINT(cppcoreguidelines-special-member-functions) +{ + /// @brief Vertex array object of the meshes. + VertexArray _vao; + +public: + + /// @brief Returns mesh Vertex Array Object. + VertexArray& GetVao() + { + return _vao; + } + + virtual ~Mesh() = default; +}; \ No newline at end of file diff --git a/src/Application/Sandbox/Model/Mesh/Mesh.cpp b/src/Application/Layer/Sandbox/Model/Mesh/StaticMesh.cpp similarity index 54% rename from src/Application/Sandbox/Model/Mesh/Mesh.cpp rename to src/Application/Layer/Sandbox/Model/Mesh/StaticMesh.cpp index fc9ff040..7db11655 100644 --- a/src/Application/Sandbox/Model/Mesh/Mesh.cpp +++ b/src/Application/Layer/Sandbox/Model/Mesh/StaticMesh.cpp @@ -1,12 +1,12 @@ -#include "Mesh.h" +#include "StaticMesh.h" -Mesh::Mesh(const std::vector& vertices, const std::vector& indices, Shader& shader) +StaticMesh::StaticMesh(const std::vector& vertices, const std::vector& indices, Shader& shader) : _shader(shader) { constexpr auto indexesInOneTriangle = 3; _indicesAmount = static_cast(indices.size()) * indexesInOneTriangle; - _vao.Bind(); + GetVao().Bind(); const auto vbo = VertexBuffer(vertices); const auto ebo = ElementBuffer(indices); @@ -14,24 +14,29 @@ Mesh::Mesh(const std::vector& vertices, const std::vectormesh of a @see Model. -class Mesh +/// @class StaticMesh +/// @brief Represents a static mesh of a Model. +/// @details Static mesh is a mesh that it's vertices will never change. +class StaticMesh final : protected Mesh { - VertexArray _vao; Shader& _shader; GLsizei _indicesAmount{}; @@ -20,12 +15,12 @@ class Mesh /// @param vertices - The vertices of the mesh. /// @param indices - The indices sequence of the vertices position. /// @param shader - The shader that the mesh is using. - Mesh(const std::vector& vertices, const std::vector& indices, Shader& shader); + StaticMesh(const std::vector& vertices, const std::vector& indices, Shader& shader); /// @brief Draws the mesh. /// @param origin - A position in the world to place the mesh. /// @param texture - The texture to cover the mesh. /// @param camera - It is used to bind a shader to see the drawn mesh. - void Draw(const Position& origin, const Texture& texture, const Camera& camera) const; + void Draw(const Position& origin, const Texture& texture, const Camera& camera); }; diff --git a/src/Application/Sandbox/Model/Surface/Texture.cpp b/src/Application/Layer/Sandbox/Model/Surface/Texture.cpp similarity index 100% rename from src/Application/Sandbox/Model/Surface/Texture.cpp rename to src/Application/Layer/Sandbox/Model/Surface/Texture.cpp diff --git a/src/Application/Sandbox/Model/Surface/Texture.h b/src/Application/Layer/Sandbox/Model/Surface/Texture.h similarity index 89% rename from src/Application/Sandbox/Model/Surface/Texture.h rename to src/Application/Layer/Sandbox/Model/Surface/Texture.h index 30b02b5b..d2dcbf50 100644 --- a/src/Application/Sandbox/Model/Surface/Texture.h +++ b/src/Application/Layer/Sandbox/Model/Surface/Texture.h @@ -1,6 +1,6 @@ #pragma once -#include "Application/Sandbox/Model/Mesh/Geometry/Shader.h" -#include "Application/Sandbox/Model/Mesh/Geometry/Structures.h" +#include "Application/Layer/Sandbox/Model/Mesh/Geometry/Shader.h" +#include "Application/Layer/Sandbox/Model/Mesh/Geometry/Structures.h" /// @class Texture /// @brief Texture represents an image that is displayed on the @see Mesh. diff --git a/src/Application/Sandbox/Model/Surface/TextureAtlas.cpp b/src/Application/Layer/Sandbox/Model/Surface/TextureAtlas.cpp similarity index 63% rename from src/Application/Sandbox/Model/Surface/TextureAtlas.cpp rename to src/Application/Layer/Sandbox/Model/Surface/TextureAtlas.cpp index ac4bbbca..595f5adf 100644 --- a/src/Application/Sandbox/Model/Surface/TextureAtlas.cpp +++ b/src/Application/Layer/Sandbox/Model/Surface/TextureAtlas.cpp @@ -1,17 +1,13 @@ #include "TextureAtlas.h" -TextureAtlas::TextureAtlas(const std::string& filenameWithImage, const size_t spriteSize) : Texture(filenameWithImage), _spriteSize(spriteSize) -{ -} - -void TextureAtlas::SetSprite(std::vector& vertices, const unsigned x, const unsigned y, const bool flip) +std::array TextureAtlas::GetTextureCoordinatesAt(const unsigned x, const unsigned y) { const auto& width = GetWidth(); const auto& height = GetHeight(); const auto invertedY = height / _spriteSize - y - 1; - const std::array textureCoords = + const std::array textureCoords = {{ { static_cast(x) * static_cast(_spriteSize) / static_cast(width), @@ -31,12 +27,22 @@ void TextureAtlas::SetSprite(std::vector& vertices, const unsigned x, co } }}; - constexpr auto verticesAmount = 4; - for (auto i = 0; i < verticesAmount; ++i) + return textureCoords; +} + +TextureAtlas::TextureAtlas(const std::string& filenameWithImage, const size_t spriteSize) : Texture(filenameWithImage), _spriteSize(spriteSize) +{ +} + +void TextureAtlas::SetSprite(std::vector& vertices, const unsigned x, const unsigned y, const bool flip) +{ + const auto& textureCoords = GetTextureCoordinatesAt(x, y); + + for (size_t i = 0; i < VerticesInQuad; ++i) { if (flip) { - vertices.at((i + verticesAmount - 1) % verticesAmount).uvCoordinate = textureCoords[i]; + vertices.at((i + VerticesInQuad - 1) % VerticesInQuad).uvCoordinate = textureCoords[i]; } else { @@ -44,3 +50,19 @@ void TextureAtlas::SetSprite(std::vector& vertices, const unsigned x, co } } } + +void TextureAtlas::SetSprite(std::array& textureUvCoordinates, const unsigned x, const unsigned y, const bool flip) +{ + const auto& textureCoords = GetTextureCoordinatesAt(x, y); + + if (!flip) + { + textureUvCoordinates = textureCoords; + return; + } + + for (size_t i = 0; i < VerticesInQuad; ++i) + { + textureUvCoordinates[(i + VerticesInQuad - 1) % VerticesInQuad] = textureCoords[i]; + } +} diff --git a/src/Application/Sandbox/Model/Surface/TextureAtlas.h b/src/Application/Layer/Sandbox/Model/Surface/TextureAtlas.h similarity index 63% rename from src/Application/Sandbox/Model/Surface/TextureAtlas.h rename to src/Application/Layer/Sandbox/Model/Surface/TextureAtlas.h index 2b3bd086..983423c6 100644 --- a/src/Application/Sandbox/Model/Surface/TextureAtlas.h +++ b/src/Application/Layer/Sandbox/Model/Surface/TextureAtlas.h @@ -6,6 +6,7 @@ class TextureAtlas : public Texture { size_t _spriteSize; + std::array GetTextureCoordinatesAt(unsigned x, unsigned y); public: @@ -20,5 +21,12 @@ class TextureAtlas : public Texture /// @param y - The row index of the texture. /// @param flip - If true, it flips the texture coordinates 180 degrees. void SetSprite(std::vector& vertices, unsigned x, unsigned y, bool flip = false); + + /// @brief Sets the vertices according to the sprite from the texture atlas. + /// @param textureUvCoordinates - UV coordinates of a texture. + /// @param x - The column index of the texture. + /// @param y - The row index of the texture. + /// @param flip - If true, it flips the texture coordinates 180 degrees. + void SetSprite(std::array& textureUvCoordinates, unsigned x, unsigned y, bool flip = false); }; diff --git a/src/Application/Sandbox/Noise/Noise.h b/src/Application/Layer/Sandbox/Noise/Noise.h similarity index 100% rename from src/Application/Sandbox/Noise/Noise.h rename to src/Application/Layer/Sandbox/Noise/Noise.h diff --git a/src/Application/Sandbox/Noise/Noise2D.cpp b/src/Application/Layer/Sandbox/Noise/Noise2D.cpp similarity index 100% rename from src/Application/Sandbox/Noise/Noise2D.cpp rename to src/Application/Layer/Sandbox/Noise/Noise2D.cpp diff --git a/src/Application/Sandbox/Noise/Noise2D.h b/src/Application/Layer/Sandbox/Noise/Noise2D.h similarity index 95% rename from src/Application/Sandbox/Noise/Noise2D.h rename to src/Application/Layer/Sandbox/Noise/Noise2D.h index 9de8560b..cc44d6b2 100644 --- a/src/Application/Sandbox/Noise/Noise2D.h +++ b/src/Application/Layer/Sandbox/Noise/Noise2D.h @@ -2,7 +2,7 @@ #include #include "Noise.h" -#include "Application/Sandbox/World/Chunks/Structure/ChunkFrame.h" +#include "Application/Layer/Sandbox/World/Chunks/Structure/ChunkFrame.h" /// @class Noise2D /// @brief Used for gathering data from the defined 2D noise. diff --git a/src/Application/Sandbox/Noise/Noise3D.cpp b/src/Application/Layer/Sandbox/Noise/Noise3D.cpp similarity index 100% rename from src/Application/Sandbox/Noise/Noise3D.cpp rename to src/Application/Layer/Sandbox/Noise/Noise3D.cpp diff --git a/src/Application/Sandbox/Noise/Noise3D.h b/src/Application/Layer/Sandbox/Noise/Noise3D.h similarity index 95% rename from src/Application/Sandbox/Noise/Noise3D.h rename to src/Application/Layer/Sandbox/Noise/Noise3D.h index 1554932a..ae5efea0 100644 --- a/src/Application/Sandbox/Noise/Noise3D.h +++ b/src/Application/Layer/Sandbox/Noise/Noise3D.h @@ -2,8 +2,8 @@ #include #include "Noise.h" -#include "Application/Sandbox/Model/Mesh/Geometry/Structures.h" -#include "Application/Sandbox/World/Chunks/Structure/ChunkFrame.h" +#include "Application/Layer/Sandbox/Model/Mesh/Geometry/Structures.h" +#include "Application/Layer/Sandbox/World/Chunks/Structure/ChunkFrame.h" /// @class Noise3D diff --git a/src/Application/Layer/Sandbox/SandboxLayer.h b/src/Application/Layer/Sandbox/SandboxLayer.h new file mode 100644 index 00000000..40386674 --- /dev/null +++ b/src/Application/Layer/Sandbox/SandboxLayer.h @@ -0,0 +1,66 @@ +#pragma once +#include + +#include "Application/Layer/Layer.h" +#include "Application/Layer/Sandbox/Camera.h" +#include "Application/Layer/Sandbox/Utils/FPSCounter.h" +#include "Application/Layer/Sandbox/World/WorldGenerator.h" +#include "Application/Layer/Sandbox/World/Chunks/ChunkPlacer.h" +#include "Application/Layer/Sandbox/World/Chunks/ChunkRenderer.h" + +/// @class SandboxLayer +/// @brief Represents sandbox that is played as an simulation. +class SandboxLayer final : public Layer +{ + std::unique_ptr _camera{}; + std::unique_ptr _chunkPlacer{}; + std::unique_ptr _fpsCounter{}; + + std::shared_ptr _worldGenerator; + +public: + + SandboxLayer(const SandboxLayer&) = delete; + SandboxLayer(SandboxLayer&&) = delete; + SandboxLayer& operator=(const SandboxLayer&) = delete; + SandboxLayer& operator=(SandboxLayer&&) = delete; + + /// @brief The constructor. + /// @param window - Reference to the window. + explicit SandboxLayer(Window& window) + { + glEnable(GL_DEPTH_TEST); + + constexpr auto worldSeed = 69; + constexpr auto chunkSize = 32; + constexpr auto renderDistance = 2; + + _camera = std::make_unique(window, glm::vec3(0.0f, 0.0f, 0.0f)); + _worldGenerator = std::make_shared(worldSeed); + + _chunkPlacer = std::make_unique(OrderType::tiltedCube, chunkSize, renderDistance, _camera->GetPosition()); + _chunkPlacer->Bind(_worldGenerator); + + _fpsCounter = std::make_unique(); + } + + void OnUpdate() override + { + const ChunkRenderer chunkRenderer; + + _camera->Update(); + chunkRenderer.Render(_chunkPlacer->GetChunks(), *_camera); + _fpsCounter->Update(); + } + + void OnEvent(HumanInterfaceDevice& hid) override + { + _camera->HandleInput(hid); + _chunkPlacer->Update(_camera->GetPosition()); + } + + ~SandboxLayer() override + { + gltTerminate(); + } +}; diff --git a/src/Application/Sandbox/Utils/FPSCounter.cpp b/src/Application/Layer/Sandbox/Utils/FPSCounter.cpp similarity index 100% rename from src/Application/Sandbox/Utils/FPSCounter.cpp rename to src/Application/Layer/Sandbox/Utils/FPSCounter.cpp diff --git a/src/Application/Sandbox/Utils/FPSCounter.h b/src/Application/Layer/Sandbox/Utils/FPSCounter.h similarity index 100% rename from src/Application/Sandbox/Utils/FPSCounter.h rename to src/Application/Layer/Sandbox/Utils/FPSCounter.h diff --git a/src/Application/Sandbox/World.h b/src/Application/Layer/Sandbox/World.h similarity index 100% rename from src/Application/Sandbox/World.h rename to src/Application/Layer/Sandbox/World.h diff --git a/src/Application/Sandbox/World/Biomes/Biome.cpp b/src/Application/Layer/Sandbox/World/Biomes/Biome.cpp similarity index 97% rename from src/Application/Sandbox/World/Biomes/Biome.cpp rename to src/Application/Layer/Sandbox/World/Biomes/Biome.cpp index b768335b..daddb690 100644 --- a/src/Application/Sandbox/World/Biomes/Biome.cpp +++ b/src/Application/Layer/Sandbox/World/Biomes/Biome.cpp @@ -22,7 +22,7 @@ void Biome::SetBlockAccordingToNoise(ChunkBlocks& blocks, const glm::ivec3 origi _blocksMap.Get(_depthLevel[blockIndex].second) }; - blocks.block[origin] = blockData; + blocks[origin] = blockData; } Biome::Biome(std::string name, const Noise3D& noise, std::vector> depthLevels, BlockMap& blocksMap) diff --git a/src/Application/Sandbox/World/Biomes/Biome.h b/src/Application/Layer/Sandbox/World/Biomes/Biome.h similarity index 89% rename from src/Application/Sandbox/World/Biomes/Biome.h rename to src/Application/Layer/Sandbox/World/Biomes/Biome.h index 75bac5f2..6b6634d3 100644 --- a/src/Application/Sandbox/World/Biomes/Biome.h +++ b/src/Application/Layer/Sandbox/World/Biomes/Biome.h @@ -1,7 +1,7 @@ #pragma once -#include "Application/Sandbox/Noise/Noise3D.h" -#include "Application/Sandbox/World/Blocks/BlockMap.h" -#include "Application/Sandbox/World/Chunks/Structure/ChunkBlocks.h" +#include "Application/Layer/Sandbox/Noise/Noise3D.h" +#include "Application/Layer/Sandbox/World/Blocks/BlockMap.h" +#include "Application/Layer/Sandbox/World/Chunks/Structure/ChunkBlocks.h" /// @class Biome /// @brief Represents biome that could be used for terrain generation. diff --git a/src/Application/Sandbox/World/Biomes/BiomePlacer.cpp b/src/Application/Layer/Sandbox/World/Biomes/BiomePlacer.cpp similarity index 100% rename from src/Application/Sandbox/World/Biomes/BiomePlacer.cpp rename to src/Application/Layer/Sandbox/World/Biomes/BiomePlacer.cpp diff --git a/src/Application/Sandbox/World/Biomes/BiomePlacer.h b/src/Application/Layer/Sandbox/World/Biomes/BiomePlacer.h similarity index 96% rename from src/Application/Sandbox/World/Biomes/BiomePlacer.h rename to src/Application/Layer/Sandbox/World/Biomes/BiomePlacer.h index da62a5f4..c2d08f4e 100644 --- a/src/Application/Sandbox/World/Biomes/BiomePlacer.h +++ b/src/Application/Layer/Sandbox/World/Biomes/BiomePlacer.h @@ -1,6 +1,6 @@ #pragma once #include "Biome.h" -#include "Application/Sandbox/Noise/Noise2D.h" +#include "Application/Layer/Sandbox/Noise/Noise2D.h" /// @class BiomePlacer /// @brief Places biomes according to the biomes map. diff --git a/src/Application/Sandbox/World/Biomes/BiomeProvider.cpp b/src/Application/Layer/Sandbox/World/Biomes/BiomeProvider.cpp similarity index 100% rename from src/Application/Sandbox/World/Biomes/BiomeProvider.cpp rename to src/Application/Layer/Sandbox/World/Biomes/BiomeProvider.cpp diff --git a/src/Application/Sandbox/World/Biomes/BiomeProvider.h b/src/Application/Layer/Sandbox/World/Biomes/BiomeProvider.h similarity index 96% rename from src/Application/Sandbox/World/Biomes/BiomeProvider.h rename to src/Application/Layer/Sandbox/World/Biomes/BiomeProvider.h index 021967a7..29411c2c 100644 --- a/src/Application/Sandbox/World/Biomes/BiomeProvider.h +++ b/src/Application/Layer/Sandbox/World/Biomes/BiomeProvider.h @@ -1,7 +1,7 @@ #pragma once #include "Biome.h" #include "Core/Metadata.h" -#include "Application/Sandbox/Noise/Noise2D.h" +#include "Application/Layer/Sandbox/Noise/Noise2D.h" /// @class BiomeProvider /// @brief Provides the biomes specified in the JSON file. diff --git a/src/Application/Layer/Sandbox/World/Blocks/BlockBuilder.cpp b/src/Application/Layer/Sandbox/World/Blocks/BlockBuilder.cpp new file mode 100644 index 00000000..70e1f398 --- /dev/null +++ b/src/Application/Layer/Sandbox/World/Blocks/BlockBuilder.cpp @@ -0,0 +1,41 @@ +#include "BlockBuilder.h" + + +void BlockBuilder::DetermineAndSetFaceTexture(const std::string& face, const int x, const int y, TextureAtlas& textureAtlas) const +{ + if (face == "front") textureAtlas.SetSprite(_facesTextureCoordinates->front, x, y, false); + if (face == "back") textureAtlas.SetSprite(_facesTextureCoordinates->back, x, y, true); + if (face == "left") textureAtlas.SetSprite(_facesTextureCoordinates->left, x, y, true); + if (face == "right") textureAtlas.SetSprite(_facesTextureCoordinates->right, x, y, false); + if (face == "top") textureAtlas.SetSprite(_facesTextureCoordinates->top, x, y, false); + if (face == "bottom") textureAtlas.SetSprite(_facesTextureCoordinates->bottom, x, y, true); +} + +BlockModel BlockBuilder::Build(const JsonData& blockData, TextureAtlas& textureAtlas) const +{ + for (const auto& textureData : blockData["textures"]) + { + // ReSharper disable once CppZeroConstantCanBeReplacedWithNullptr + const int x = textureData["location"].value("column", 0); + // ReSharper disable once CppZeroConstantCanBeReplacedWithNullptr + const int y = textureData["location"].value("row", 0); + + for (const auto& face : textureData["faces"]) + { + DetermineAndSetFaceTexture(face, x, y, textureAtlas); + } + } + + const BlockFaces faces + { + BlockFaceModel(_facesTextureCoordinates->front), + BlockFaceModel(_facesTextureCoordinates->back), + BlockFaceModel(_facesTextureCoordinates->left), + BlockFaceModel(_facesTextureCoordinates->right), + BlockFaceModel(_facesTextureCoordinates->top), + BlockFaceModel(_facesTextureCoordinates->bottom) + }; + + return BlockModel(faces); +} + diff --git a/src/Application/Layer/Sandbox/World/Blocks/BlockBuilder.h b/src/Application/Layer/Sandbox/World/Blocks/BlockBuilder.h new file mode 100644 index 00000000..2c02a567 --- /dev/null +++ b/src/Application/Layer/Sandbox/World/Blocks/BlockBuilder.h @@ -0,0 +1,91 @@ +#pragma once +#include "Core/Metadata.h" +#include "Application/Layer/Sandbox/Model/BlockModel.h" +#include "Application/Layer/Sandbox/Model/Surface/TextureAtlas.h" + +/// @class BlockBuilder +/// @brief A factory that builds and outputs blocks based on their metadata. +class BlockBuilder +{ + struct FacesUvTextureCoordinates + { + std::array front + { + Point{0.0f, 0.0f}, + Point{1.0f, 0.0f}, + Point{1.0f, 1.0f}, + Point{0.0f, 1.0f}, + }; + + std::array back + { + Point{0.0f, 0.0f}, + Point{1.0f, 0.0f}, + Point{1.0f, 1.0f}, + Point{0.0f, 1.0f}, + }; + + std::array left + { + Point{0.0f, 0.0f}, + Point{1.0f, 0.0f}, + Point{1.0f, 1.0f}, + Point{0.0f, 1.0f}, + }; + + std::array right + { + Point{0.0f, 0.0f}, + Point{1.0f, 0.0f}, + Point{1.0f, 1.0f}, + Point{0.0f, 1.0f}, + }; + + std::array top + { + Point{0.0f, 0.0f}, + Point{1.0f, 0.0f}, + Point{1.0f, 1.0f}, + Point{0.0f, 1.0f}, + }; + + std::array bottom + { + Point{0.0f, 0.0f}, + Point{1.0f, 0.0f}, + Point{1.0f, 1.0f}, + Point{0.0f, 1.0f}, + }; + }; + + struct FaceMeshes + { + std::unique_ptr front; + std::unique_ptr back; + std::unique_ptr left; + std::unique_ptr right; + std::unique_ptr top; + std::unique_ptr bottom; + }; + + struct FaceTextures + { + std::shared_ptr front; + std::shared_ptr back; + std::shared_ptr left; + std::shared_ptr right; + std::shared_ptr top; + std::shared_ptr bottom; + }; + + std::shared_ptr _facesTextureCoordinates = std::make_shared(); + + void DetermineAndSetFaceTexture(const std::string& face, int x, int y, TextureAtlas& textureAtlas) const; + +public: + + /// @brief Builds block based on the data. + /// @param blockData - Metadata of the block to be built. + /// @param textureAtlas - Texture atlas related to the block data. + BlockModel Build(const JsonData& blockData, TextureAtlas& textureAtlas) const; +}; diff --git a/src/Application/Sandbox/World/Blocks/BlockMap.h b/src/Application/Layer/Sandbox/World/Blocks/BlockMap.h similarity index 50% rename from src/Application/Sandbox/World/Blocks/BlockMap.h rename to src/Application/Layer/Sandbox/World/Blocks/BlockMap.h index b511ec8c..7a5a1b92 100644 --- a/src/Application/Sandbox/World/Blocks/BlockMap.h +++ b/src/Application/Layer/Sandbox/World/Blocks/BlockMap.h @@ -1,23 +1,20 @@ #pragma once #include "BlockProvider.h" -#include "Application/Sandbox/Model/BlockModel.h" +#include "Application/Layer/Sandbox/Model/BlockModel.h" +#include "Application/Layer/Sandbox/Model/Surface/TextureAtlas.h" /// @class BlockMap /// @brief Represents a map of the blocks that could be used to place in the chunks. class BlockMap { - Shader _blockShader = Shader("src/Data/Shaders/Block.vert", "src/Data/Shaders/Block.frag"); - std::vector _faceIndices - { - TriangleIndexes{0, 1, 2}, - TriangleIndexes{2, 3, 0} - }; + std::shared_ptr _blockTextures{}; std::unordered_map> _blockTypes; + Shader _blockShader{"src/Data/Shaders/Block.vert", "src/Data/Shaders/Block.frag"}; public: /// @brief Copy constructor. - BlockMap(const BlockMap&) = default; + BlockMap(const BlockMap&) = delete; /// @brief Move constructor. BlockMap(BlockMap&&) noexcept = default; @@ -33,7 +30,12 @@ class BlockMap explicit BlockMap(const std::string& filenameWithBlocksData) { auto blockProvider = BlockProvider(filenameWithBlocksData); - _blockTypes = blockProvider.GetBlocks(_faceIndices, _blockShader); + + const auto& textureName = blockProvider.GetTextureAtlasFilename(); + const auto& textureSlotSize = blockProvider.GetTextureAtlasSlotSize(); + + _blockTextures = std::make_shared(textureName, textureSlotSize); + _blockTypes = blockProvider.GetBlocks(*_blockTextures); } /// @brief Returns the block model based on it's name. @@ -43,5 +45,23 @@ class BlockMap return _blockTypes.at(blockName); } + /// @brief An operator that allows to get the block by its key in a convenient way. + std::shared_ptr& operator[](const std::string& blockName) + { + return _blockTypes.at(blockName); + } + + /// @brief Returns the texture atlas that is used in this map. + std::shared_ptr& GetBlocksTexture() + { + return _blockTextures; + } + + /// @brief Returns the blocks shader. + Shader& GetBlocksShader() + { + return _blockShader; + } + ~BlockMap() = default; }; diff --git a/src/Application/Sandbox/World/Blocks/BlockProvider.cpp b/src/Application/Layer/Sandbox/World/Blocks/BlockProvider.cpp similarity index 57% rename from src/Application/Sandbox/World/Blocks/BlockProvider.cpp rename to src/Application/Layer/Sandbox/World/Blocks/BlockProvider.cpp index 4391b406..f03c2a94 100644 --- a/src/Application/Sandbox/World/Blocks/BlockProvider.cpp +++ b/src/Application/Layer/Sandbox/World/Blocks/BlockProvider.cpp @@ -8,23 +8,31 @@ BlockProvider::BlockProvider(const std::string& filenameWithBlocksData) } std::unordered_map> BlockProvider::GetBlocks( - std::vector& blockIndices, - Shader& blockShader, + TextureAtlas& blocksTextureAtlas, const std::string& blocksSetName) { const auto blocksSet = _blocksMetadata.GetJsonObject(blocksSetName); - - const std::string textureAtlasName = blocksSet.value("atlas", ""); - const size_t slotSize = blocksSet.value("slotSize", 0); - - auto builder = BlockBuilder(textureAtlasName, slotSize, blockIndices, blockShader); auto blocks = std::unordered_map>(); for (const auto& blockData : blocksSet["blocks"]) { const std::string name = blockData.value("block", "unknown"); - blocks[name] = std::make_shared(builder.Build(blockData)); + const BlockBuilder builder; + + blocks[name] = std::make_shared(builder.Build(blockData, blocksTextureAtlas)); } return blocks; } + +std::string BlockProvider::GetTextureAtlasFilename(const std::string& blocksSetName) +{ + const auto blocksSet = _blocksMetadata.GetJsonObject(blocksSetName); + return blocksSet.value("atlas", ""); +} + +size_t BlockProvider::GetTextureAtlasSlotSize(const std::string& blocksSetName) +{ + const auto blocksSet = _blocksMetadata.GetJsonObject(blocksSetName); + return blocksSet.value("slotSize", 0); +} diff --git a/src/Application/Layer/Sandbox/World/Blocks/BlockProvider.h b/src/Application/Layer/Sandbox/World/Blocks/BlockProvider.h new file mode 100644 index 00000000..f7b8e4e0 --- /dev/null +++ b/src/Application/Layer/Sandbox/World/Blocks/BlockProvider.h @@ -0,0 +1,31 @@ +#pragma once +#include "Core/Metadata.h" +#include "Application/Layer/Sandbox/Model/BlockModel.h" +#include "Application/Layer/Sandbox/Model/Surface/TextureAtlas.h" + +/// @class BlockProvider +/// @brief Provides all the blocks mentioned in the file. +class BlockProvider +{ + Metadata _blocksMetadata; + +public: + + /// @brief The constructor. + /// @param filenameWithBlocksData - Path to the JSON file containing the blocks metadata. + explicit BlockProvider(const std::string& filenameWithBlocksData); + + /// @brief Provides the map of the built blocks. + /// @param blocksTextureAtlas - Texture atlas of the blocks to be built. + /// @param blocksSetName - Name of the blocks set that is used for this particular block map. + std::unordered_map> GetBlocks(TextureAtlas& blocksTextureAtlas, const std::string& blocksSetName = "default"); + + /// @brief Returns texture atlas filename of the blocks set. + /// @param blocksSetName - Name of the blocks set. + std::string GetTextureAtlasFilename(const std::string& blocksSetName = "default"); + + /// @brief Returns the sprite size defined in the set data. + /// @param blocksSetName - Name of the blocks set. + size_t GetTextureAtlasSlotSize(const std::string& blocksSetName = "default"); +}; + diff --git a/src/Application/Layer/Sandbox/World/Chunks/ChunkBuilder.cpp b/src/Application/Layer/Sandbox/World/Chunks/ChunkBuilder.cpp new file mode 100644 index 00000000..ce27bd67 --- /dev/null +++ b/src/Application/Layer/Sandbox/World/Chunks/ChunkBuilder.cpp @@ -0,0 +1,14 @@ +#include "ChunkBuilder.h" + +#include "Application/Layer/Sandbox/World/Biomes/Biome.h" + +// ReSharper disable once CppMemberFunctionMayBeStatic +std::unique_ptr ChunkBuilder::Build(const Position origin, const size_t& size, WorldGenerator& generator) const +{ + const auto chunkFrame = ChunkFrame{origin, size}; + ChunkBlocks chunkBlocks; + + generator.PaintChunk(chunkFrame, chunkBlocks); + + return std::make_unique(chunkBlocks, generator.GetBlockMap().GetBlocksTexture(), size, generator.GetBlockMap().GetBlocksShader()); +} diff --git a/src/Application/Layer/Sandbox/World/Chunks/ChunkBuilder.h b/src/Application/Layer/Sandbox/World/Chunks/ChunkBuilder.h new file mode 100644 index 00000000..eb54c8bb --- /dev/null +++ b/src/Application/Layer/Sandbox/World/Chunks/ChunkBuilder.h @@ -0,0 +1,17 @@ +#pragma once +#include "Application/Layer/Sandbox/World/WorldGenerator.h" +#include "Structure/Chunk.h" + +/// @class ChunkBuilder +/// @brief Builds chunks. +class ChunkBuilder +{ +public: + + /// @brief Builds the chunk. + /// @param origin - origin of the chunk. + /// @param size - size of the chunks edge. + /// @param generator - the world generator that chunk uses to generate it's content. + std::unique_ptr Build(Position origin, const size_t& size, WorldGenerator& generator) const; +}; + diff --git a/src/Application/Layer/Sandbox/World/Chunks/ChunkPlacer.cpp b/src/Application/Layer/Sandbox/World/Chunks/ChunkPlacer.cpp new file mode 100644 index 00000000..097e9a5e --- /dev/null +++ b/src/Application/Layer/Sandbox/World/Chunks/ChunkPlacer.cpp @@ -0,0 +1,123 @@ +#include "ChunkPlacer.h" + +std::vector ChunkPlacer::Subtract(const std::vector& aSet, const std::vector& bSet) +{ + std::vector result; + + for (const auto& value : aSet) + { + if (std::find(bSet.begin(), bSet.end(), value) == bSet.end()) + { + result.emplace_back(value); + } + } + + return result; +} + +Position ChunkPlacer::GetNormalizedPosition(const Point3D& position, const size_t& chunkSize) const +{ + auto normalizedPosition = position; + + normalizedPosition /= chunkSize; + + normalizedPosition.x = floor(normalizedPosition.x); + normalizedPosition.y = floor(normalizedPosition.y); + normalizedPosition.z = floor(normalizedPosition.z); + + return {normalizedPosition}; +} + +std::string ChunkPlacer::PositionToString(const Position& position) const +{ + return std::to_string(position.x) + ", " + + std::to_string(position.y) + ", " + + std::to_string(position.z); +} + +void ChunkPlacer::RemoveStaleChunks(const std::vector& currentChunksOrigins) +{ + std::vector staleChunksOrigins; + + for (const auto& chunkData : _loadedChunks) + { + const auto origin = chunkData.first; + if (std::find(currentChunksOrigins.begin(), currentChunksOrigins.end(), origin) == currentChunksOrigins.end()) + { + staleChunksOrigins.emplace_back(origin); + } + } + + for (const auto& origin : staleChunksOrigins) + { + _log.Trace("Removed chunk: " + PositionToString(origin)); + _loadedChunks.erase(origin); + } + + _log.Debug("Finished removing stale chunks!"); +} + +void ChunkPlacer::AddNewChunks(const std::vector& currentChunksOrigins) +{ + for (const auto& origin : currentChunksOrigins) + { + if (_loadedChunks.find(origin) == _loadedChunks.end()) + { + _log.Trace("Added chunk: " + PositionToString(origin)); + _loadedChunks[origin] = _chunkBuilder.Build(origin, _order->GetChunkSize(), *_generator); + } + } + + _log.Debug("Finished adding new chunks!"); +} + +void ChunkPlacer::UpdateChunksAround(const Position& normalizedOrigin) +{ + const auto currentChunksAroundOrigins = _order->GetChunksAround(normalizedOrigin); + + RemoveStaleChunks(currentChunksAroundOrigins); + AddNewChunks(currentChunksAroundOrigins); +} + +ChunkPlacer::ChunkPlacer(const OrderType orderType, const size_t chunkSize, const size_t renderDistance, const Position& initPosition) +{ + _previousNormalizedPosition = GetNormalizedPosition(initPosition, chunkSize); + + switch (orderType) + { + case OrderType::cube: + _order = std::make_unique(renderDistance, chunkSize); + break; + + case OrderType::diamond: + _order = std::make_unique(renderDistance, chunkSize); + break; + + case OrderType::tiltedCube: + _order = std::make_unique(renderDistance, chunkSize); + break; + } +} + +void ChunkPlacer::Update(const Position& position) +{ + const auto currentNormalizedPosition = GetNormalizedPosition(position, _order->GetChunkSize()); + + if (currentNormalizedPosition != _previousNormalizedPosition) + { + _previousNormalizedPosition = currentNormalizedPosition; + UpdateChunksAround(currentNormalizedPosition); + + _log.Trace("Normalized position: " + PositionToString(currentNormalizedPosition)); + } +} + +void ChunkPlacer::Bind(std::shared_ptr generator) +{ + _generator = std::move(generator); +} + +std::unordered_map>& ChunkPlacer::GetChunks() +{ + return _loadedChunks; +} diff --git a/src/Application/Layer/Sandbox/World/Chunks/ChunkPlacer.h b/src/Application/Layer/Sandbox/World/Chunks/ChunkPlacer.h new file mode 100644 index 00000000..a61dfc8e --- /dev/null +++ b/src/Application/Layer/Sandbox/World/Chunks/ChunkPlacer.h @@ -0,0 +1,53 @@ +#pragma once +#include "ChunkBuilder.h" +#include "Application/Layer/Sandbox/Camera.h" +#include "Application/Layer/Sandbox/World/WorldGenerator.h" +#include "OrderType/OrderTypes.h" +#include "Structure/Chunk.h" + +/// @class ChunkPlacer +/// @brief Handles placing the chunks around the camera. +/// @details This class handles @see Chunk objects and manages them for optimal experience. +class ChunkPlacer +{ + Log& _log = Log::Get(); + ChunkBuilder _chunkBuilder; + + std::shared_ptr _generator; + std::unique_ptr _order; + + Position _previousNormalizedPosition = {}; + std::unordered_map> _loadedChunks = {}; + + static std::vector Subtract(const std::vector& aSet, const std::vector& bSet); + Position GetNormalizedPosition(const Point3D& position, const size_t& chunkSize) const; + std::string PositionToString(const Position& position) const; + + void RemoveStaleChunks(const std::vector& currentChunksOrigins); + void AddNewChunks(const std::vector& currentChunksOrigins); + + void UpdateChunksAround(const Position& normalizedOrigin); + +public: + + /// @brief The constructor. + /// @param orderType - the way the chunks will be generated. + /// @param chunkSize - the size of the generated chunks. + /// @param renderDistance - specifies the maximum distance from the camera to render. + /// @param initPosition - position in space from where initialize the chunk placer. + ChunkPlacer(OrderType orderType, size_t chunkSize, size_t renderDistance, const Position& initPosition); + + /// @brief Updates the chunk placer to adapt to the current frame. + /// @param position - Position around which chunks are going to be placed. + void Update(const Position& position); + + /// @brief Binds world generator to the chunk placer. + /// @details The world generator is used to define how the world is generated, when + /// this class handles only displaying it in an optimal way. + /// @param generator - reference to the world generator. + void Bind(std::shared_ptr generator); + + /// @brief Returns the map of placed chunks. + std::unordered_map>& GetChunks(); +}; + diff --git a/src/Application/Layer/Sandbox/World/Chunks/ChunkRenderer.cpp b/src/Application/Layer/Sandbox/World/Chunks/ChunkRenderer.cpp new file mode 100644 index 00000000..3e89cfcd --- /dev/null +++ b/src/Application/Layer/Sandbox/World/Chunks/ChunkRenderer.cpp @@ -0,0 +1,20 @@ +#include "ChunkRenderer.h" + +ChunkRenderer::ChunkRenderer() +{ + glCullFace(GL_FRONT); + glFrontFace(GL_CCW); +} + +// ReSharper disable once CppMemberFunctionMayBeStatic +void ChunkRenderer::Render(const std::unordered_map>& chunks, const Camera& camera) const +{ + glEnable(GL_CULL_FACE); + + for (const auto& chunk : chunks) + { + chunk.second->Draw(camera); + } + + glDisable(GL_CULL_FACE); +} diff --git a/src/Application/Layer/Sandbox/World/Chunks/ChunkRenderer.h b/src/Application/Layer/Sandbox/World/Chunks/ChunkRenderer.h new file mode 100644 index 00000000..43e75fb4 --- /dev/null +++ b/src/Application/Layer/Sandbox/World/Chunks/ChunkRenderer.h @@ -0,0 +1,23 @@ +#pragma once +#include "ChunkPlacer.h" + +/// @class ChunkRenderer +/// @brief Supports rendering chunks. +/// @details This class is responsible for rendering chunks around the camera by using the algorithms +/// specified in the @see Order. +class ChunkRenderer +{ + Log& _log = Log::Get(); + +public: + + /// @brief The constructor. + ChunkRenderer(); + + /// @brief Renders loaded chunks. + /// @param camera - A reference to the camera around which the objects are rendered. + /// @param chunks - Chunks to render with their positions on the map. + void Render(const std::unordered_map>& chunks, const Camera& camera) const; +}; + + diff --git a/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/CubeView.cpp b/src/Application/Layer/Sandbox/World/Chunks/OrderType/CubeOrder.cpp similarity index 78% rename from src/Application/Sandbox/World/Chunks/Rendring/RenderViews/CubeView.cpp rename to src/Application/Layer/Sandbox/World/Chunks/OrderType/CubeOrder.cpp index 59e7ee03..a85da5ed 100644 --- a/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/CubeView.cpp +++ b/src/Application/Layer/Sandbox/World/Chunks/OrderType/CubeOrder.cpp @@ -1,12 +1,12 @@ -#include "CubeView.h" +#include "CubeOrder.h" -size_t CubeView::GetChunksAmount() +size_t CubeOrder::GetChunksAmount() { const auto& chunkSize = GetChunkSize(); return chunkSize * chunkSize * chunkSize; } -std::vector CubeView::GetChunksAround(const glm::ivec3 normalizedOrigin) +std::vector CubeOrder::GetChunksAround(const glm::ivec3 normalizedOrigin) { std::vector chunksPositions; diff --git a/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/CubeView.h b/src/Application/Layer/Sandbox/World/Chunks/OrderType/CubeOrder.h similarity index 52% rename from src/Application/Sandbox/World/Chunks/Rendring/RenderViews/CubeView.h rename to src/Application/Layer/Sandbox/World/Chunks/OrderType/CubeOrder.h index 090d2b20..c735435e 100644 --- a/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/CubeView.h +++ b/src/Application/Layer/Sandbox/World/Chunks/OrderType/CubeOrder.h @@ -1,13 +1,13 @@ #pragma once -#include "RenderView.h" +#include "Order.h" -/// @class CubeView -/// @brief Provides an algorithm that the renderer renders chunks in as a cube. +/// @class CubeOrder +/// @brief Provides an algorithm for the ChunkPlacer to place the chunks in a cube manner. /// @details Basically this algorithm returns origins formed in a cube. -class CubeView final : public RenderView +class CubeOrder final : public Order { public: - using RenderView::RenderView; + using Order::Order; size_t GetChunksAmount() override; std::vector GetChunksAround(glm::ivec3 normalizedOrigin) override; diff --git a/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/DiamondView.cpp b/src/Application/Layer/Sandbox/World/Chunks/OrderType/DiamondOrder.cpp similarity index 76% rename from src/Application/Sandbox/World/Chunks/Rendring/RenderViews/DiamondView.cpp rename to src/Application/Layer/Sandbox/World/Chunks/OrderType/DiamondOrder.cpp index 82b4adf1..4d52fb2e 100644 --- a/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/DiamondView.cpp +++ b/src/Application/Layer/Sandbox/World/Chunks/OrderType/DiamondOrder.cpp @@ -1,6 +1,6 @@ -#include "DiamondView.h" +#include "DiamondOrder.h" -size_t DiamondView::CountChunksRecursive(const size_t level) +size_t DiamondOrder::CountChunksRecursive(const size_t level) { const auto result = 4 * level; @@ -8,12 +8,12 @@ size_t DiamondView::CountChunksRecursive(const size_t level) return result + CountChunksRecursive(level - 1); } -size_t DiamondView::GetChunksAmount() +size_t DiamondOrder::GetChunksAmount() { return CountChunksRecursive(GetRenderDistance()); } -std::vector DiamondView::GetChunksAround(const glm::ivec3 normalizedOrigin) +std::vector DiamondOrder::GetChunksAround(const glm::ivec3 normalizedOrigin) { std::vector chunksPositions; diff --git a/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/DiamondView.h b/src/Application/Layer/Sandbox/World/Chunks/OrderType/DiamondOrder.h similarity index 58% rename from src/Application/Sandbox/World/Chunks/Rendring/RenderViews/DiamondView.h rename to src/Application/Layer/Sandbox/World/Chunks/OrderType/DiamondOrder.h index eb5c21fe..d81834ee 100644 --- a/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/DiamondView.h +++ b/src/Application/Layer/Sandbox/World/Chunks/OrderType/DiamondOrder.h @@ -1,15 +1,15 @@ #pragma once -#include "RenderView.h" +#include "Order.h" -/// @class DiamondView -/// @brief Provides an algorithm that the renderer renders chunks in as a diamond. +/// @class DiamondOrder +/// @brief Provides an algorithm for the ChunkPlacer to place the chunks in a diamond manner. /// @note Here is the explanation. -class DiamondView final : public RenderView +class DiamondOrder final : public Order { static size_t CountChunksRecursive(size_t level); public: - using RenderView::RenderView; + using Order::Order; size_t GetChunksAmount() override; std::vector GetChunksAround(glm::ivec3 normalizedOrigin) override; diff --git a/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/RenderView.h b/src/Application/Layer/Sandbox/World/Chunks/OrderType/Order.h similarity index 77% rename from src/Application/Sandbox/World/Chunks/Rendring/RenderViews/RenderView.h rename to src/Application/Layer/Sandbox/World/Chunks/OrderType/Order.h index b00d62ec..a6eecd48 100644 --- a/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/RenderView.h +++ b/src/Application/Layer/Sandbox/World/Chunks/OrderType/Order.h @@ -2,11 +2,11 @@ #include #include -/// @class RenderView -/// @brief The base class for creating render views. -/// @details A render view is a class providing the algorithm, by which -/// the chunks are rendered. -class RenderView // NOLINT(cppcoreguidelines-special-member-functions) +/// @class Order +/// @brief The base class for creating placing order types. +/// @details An order type is a class providing an algorithm, by which +/// the chunks are placer by the ChunkPlacer. +class Order // NOLINT(cppcoreguidelines-special-member-functions) { size_t _renderDistance; size_t _chunkSize; @@ -16,7 +16,7 @@ class RenderView // NOLINT(cppcoreguidelines-special-member-functions) /// @brief The constructor. /// @param renderDistance - the maximum distance from the camera to render. /// @param chunkSize - the size of the generated chunks. - RenderView(const size_t& renderDistance, const size_t& chunkSize) + Order(const size_t& renderDistance, const size_t& chunkSize) : _renderDistance(renderDistance), _chunkSize(chunkSize) {} @@ -53,5 +53,5 @@ class RenderView // NOLINT(cppcoreguidelines-special-member-functions) /// @brief Get the amount of chunks that could be generated on the current render distance settings. virtual std::vector GetChunksAround(glm::ivec3 normalizedOrigin) = 0; - virtual ~RenderView() = default; + virtual ~Order() = default; }; diff --git a/src/Application/Layer/Sandbox/World/Chunks/OrderType/OrderTypes.h b/src/Application/Layer/Sandbox/World/Chunks/OrderType/OrderTypes.h new file mode 100644 index 00000000..513d7e74 --- /dev/null +++ b/src/Application/Layer/Sandbox/World/Chunks/OrderType/OrderTypes.h @@ -0,0 +1,12 @@ +// ReSharper disable CppUnusedIncludeDirective +#pragma once +#include "CubeOrder.h" +#include "DiamondOrder.h" +#include "TiltedCubeOrder.h" + +enum class OrderType +{ + cube = 0, + diamond, + tiltedCube +}; \ No newline at end of file diff --git a/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/TiltedCube.cpp b/src/Application/Layer/Sandbox/World/Chunks/OrderType/TiltedCubeOrder.cpp similarity index 77% rename from src/Application/Sandbox/World/Chunks/Rendring/RenderViews/TiltedCube.cpp rename to src/Application/Layer/Sandbox/World/Chunks/OrderType/TiltedCubeOrder.cpp index b89ee218..57be7e4c 100644 --- a/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/TiltedCube.cpp +++ b/src/Application/Layer/Sandbox/World/Chunks/OrderType/TiltedCubeOrder.cpp @@ -1,12 +1,12 @@ -#include "TiltedCube.h" +#include "TiltedCubeOrder.h" -size_t TiltedCube::GetChunksAmount() +size_t TiltedCubeOrder::GetChunksAmount() { const auto& r = GetChunkSize(); return (r + 1) * ((r + 1) * (r + 1) + r * r); } -std::vector TiltedCube::GetChunksAround(const glm::ivec3 normalizedOrigin) +std::vector TiltedCubeOrder::GetChunksAround(const glm::ivec3 normalizedOrigin) { std::vector chunksPositions; diff --git a/src/Application/Layer/Sandbox/World/Chunks/OrderType/TiltedCubeOrder.h b/src/Application/Layer/Sandbox/World/Chunks/OrderType/TiltedCubeOrder.h new file mode 100644 index 00000000..6d7de627 --- /dev/null +++ b/src/Application/Layer/Sandbox/World/Chunks/OrderType/TiltedCubeOrder.h @@ -0,0 +1,15 @@ +#pragma once +#include "Order.h" + +/// @class TiltedCubeOrder +/// @brief Provides an algorithm for the ChunkPlacer to place the chunks in a tilted cube manner. +/// @details A tilted cube is just a regular cube that it's edges are pointing cardinal directions. +class TiltedCubeOrder final : public Order +{ +public: + using Order::Order; + + size_t GetChunksAmount() override; + std::vector GetChunksAround(glm::ivec3 normalizedOrigin) override; +}; + diff --git a/src/Application/Layer/Sandbox/World/Chunks/Structure/Chunk.cpp b/src/Application/Layer/Sandbox/World/Chunks/Structure/Chunk.cpp new file mode 100644 index 00000000..395666ba --- /dev/null +++ b/src/Application/Layer/Sandbox/World/Chunks/Structure/Chunk.cpp @@ -0,0 +1,18 @@ +#include "Chunk.h" + + +Chunk::Chunk(const size_t& size, std::shared_ptr blocksTexture, Shader& shader) : + _mesh(ChunkMesh(shader, size)), _blockTexture(std::move(blocksTexture)) +{ +} + +Chunk::Chunk(ChunkBlocks blocks, std::shared_ptr blocksTexture, const size_t& size, Shader& shader) : _mesh(ChunkMesh(shader, size)), _blockTexture( + std::move(blocksTexture)), _blocks(std::move(blocks)) +{ + _mesh.Rebuild(_blocks); +} + +void Chunk::Draw(const Camera& camera) const +{ + _mesh.Draw(*_blockTexture, camera); +} diff --git a/src/Application/Layer/Sandbox/World/Chunks/Structure/Chunk.h b/src/Application/Layer/Sandbox/World/Chunks/Structure/Chunk.h new file mode 100644 index 00000000..3e78c4ee --- /dev/null +++ b/src/Application/Layer/Sandbox/World/Chunks/Structure/Chunk.h @@ -0,0 +1,37 @@ +#pragma once +#include "Application/Layer/Sandbox/Camera.h" +#include "ChunkBlocks.h" +#include "ChunkMesh.h" +#include "Application/Layer/Sandbox/Model/Mesh/DynamicMesh.h" + +/// @class Chunk +/// @brief Represents a single chunk placed in the world +/// @details This class handles managing the generated chunk at the certain position. +class Chunk +{ + ChunkMesh _mesh; + std::shared_ptr _blockTexture; + ChunkBlocks _blocks; + +public: + + /// @brief The constructor. + /// @param size - Size of the chunk edge. + /// @param blocksTexture - Texture atlas of the blocks inside the chunk. + /// @param shader - Reference to the blocks shader. + explicit Chunk(const size_t& size, std::shared_ptr blocksTexture, Shader& shader); + + /// @brief The constructor. + /// @details The chunk on initialization knows it's position, the structure to render (blocks) + /// and the player position for proper displaying blocks while the player is moving. + /// @param blocks - The blocks inside the chunk. + /// @param blocksTexture - Texture atlas of the blocks inside the chunk. + /// @param size - Size of the chunks edge. + /// @param shader - Reference to the blocks shader. + explicit Chunk(ChunkBlocks blocks, std::shared_ptr blocksTexture, const size_t& size, Shader& shader); + + /// @brief Draws the chunk in the world. + /// @param camera - reference to the camera so that the blocks could be seen. + void Draw(const Camera& camera) const; +}; + diff --git a/src/Application/Sandbox/World/Chunks/Structure/ChunkBlocks.h b/src/Application/Layer/Sandbox/World/Chunks/Structure/ChunkBlocks.h similarity index 55% rename from src/Application/Sandbox/World/Chunks/Structure/ChunkBlocks.h rename to src/Application/Layer/Sandbox/World/Chunks/Structure/ChunkBlocks.h index 6689692b..10792b1b 100644 --- a/src/Application/Sandbox/World/Chunks/Structure/ChunkBlocks.h +++ b/src/Application/Layer/Sandbox/World/Chunks/Structure/ChunkBlocks.h @@ -1,5 +1,5 @@ #pragma once -#include "Application/Sandbox/Model/BlockModel.h" +#include "Application/Layer/Sandbox/Model/BlockModel.h" /// @brief Contains the information about a certain block and the visibility of its faces. struct BlockVisibility @@ -22,43 +22,19 @@ template <> struct std::hash { /// @brief Definition of how to handle the passed origin as a key in the map. - size_t operator()(const Position &origin) const noexcept + size_t operator()(const Position& origin) const noexcept { return std::hash() ( - std::to_string(origin.x) + - std::to_string(origin.y) + + std::to_string(origin.x) + "." + + std::to_string(origin.y) + "." + std::to_string(origin.z) ); } }; -/// @class ChunkBlocks /// @brief A structure that represents the body of typical chunk. Blocks and their visibility. -class ChunkBlocks -{ -public: - - /// @brief The constructor. - ChunkBlocks() = default; - - /// @brief Copy constructor. - ChunkBlocks(const ChunkBlocks&) = default; - - /// @brief Move constructor. - ChunkBlocks(ChunkBlocks&&) noexcept = default; - - /// @brief Copy assignment constructor. - ChunkBlocks &operator=(const ChunkBlocks &) = default; - - /// @brief Move assignment constructor. - ChunkBlocks &operator=(ChunkBlocks &&) noexcept = default; - - /// @brief Map with blocks that are placed inside the chunk. - /// @details This map contains all blocks that are included in the chunk - /// and maps the location of the block as a key, and it's model and - /// faces visibility as a key. - std::unordered_map block; - - ~ChunkBlocks() = default; -}; +/// @details This map contains all blocks that are included in the chunk +/// and maps the location of the block as a key, and it's model and +/// faces visibility as a key. +using ChunkBlocks = std::unordered_map; diff --git a/src/Application/Sandbox/World/Chunks/Structure/ChunkFrame.h b/src/Application/Layer/Sandbox/World/Chunks/Structure/ChunkFrame.h similarity index 100% rename from src/Application/Sandbox/World/Chunks/Structure/ChunkFrame.h rename to src/Application/Layer/Sandbox/World/Chunks/Structure/ChunkFrame.h diff --git a/src/Application/Layer/Sandbox/World/Chunks/Structure/ChunkMesh.cpp b/src/Application/Layer/Sandbox/World/Chunks/Structure/ChunkMesh.cpp new file mode 100644 index 00000000..1fa8b0b2 --- /dev/null +++ b/src/Application/Layer/Sandbox/World/Chunks/Structure/ChunkMesh.cpp @@ -0,0 +1,52 @@ +#include "ChunkMesh.h" + +void ChunkMesh::AddFaceToMesh( + const Position& origin, + const std::array& faceVertices, + const std::array& faceTextureCoordinates, + std::vector& mesh) +{ + constexpr auto quadVerticesCount = 4; + for (auto i = 0; i < quadVerticesCount; ++i) + { + mesh.emplace_back(Vertex{faceVertices[i] + Point3D(origin), faceTextureCoordinates[i]}); + } +} + +ChunkMesh::ChunkMesh(Shader& blockShader, const size_t& sizeOfChunk) : _blockShader(blockShader) +{ + const std::vector indicesPattern = + { + TriangleIndexes{0, 1, 2}, + TriangleIndexes{2, 3, 0} + }; + const auto maxInstancesAmount = sizeOfChunk * sizeOfChunk * sizeOfChunk; + + _mesh = std::make_unique(std::vector(), indicesPattern, _blockShader, maxInstancesAmount); +} + +void ChunkMesh::Rebuild(const ChunkBlocks& blocks) const +{ + std::vector vertices; + + for (const auto& block : blocks) + { + auto& origin = block.first; + auto& faceModels = block.second.model->GetFaces(); + const auto& facesVisibility = block.second.visibility; + + if (facesVisibility.front) AddFaceToMesh(origin, _faceVertices.front, faceModels.front.GetUvCoordinates(), vertices); + if (facesVisibility.back) AddFaceToMesh(origin, _faceVertices.back, faceModels.back.GetUvCoordinates(), vertices); + if (facesVisibility.left) AddFaceToMesh(origin, _faceVertices.left, faceModels.left.GetUvCoordinates(), vertices); + if (facesVisibility.right) AddFaceToMesh(origin, _faceVertices.right, faceModels.right.GetUvCoordinates(), vertices); + if (facesVisibility.top) AddFaceToMesh(origin, _faceVertices.top, faceModels.top.GetUvCoordinates(), vertices); + if (facesVisibility.bottom) AddFaceToMesh(origin, _faceVertices.bottom, faceModels.bottom.GetUvCoordinates(), vertices); + } + + _mesh->Update(vertices); +} + +void ChunkMesh::Draw(const Texture& blocksTexture, const Camera& camera) const +{ + _mesh->Draw(blocksTexture, camera); +} diff --git a/src/Application/Layer/Sandbox/World/Chunks/Structure/ChunkMesh.h b/src/Application/Layer/Sandbox/World/Chunks/Structure/ChunkMesh.h new file mode 100644 index 00000000..437d2943 --- /dev/null +++ b/src/Application/Layer/Sandbox/World/Chunks/Structure/ChunkMesh.h @@ -0,0 +1,94 @@ +#pragma once +#include "ChunkBlocks.h" +#include "Application/Layer/Sandbox/Model/Mesh/DynamicMesh.h" + +/// @class ChunkMesh +/// @brief Represents the chunk mesh and manages it in a runtime. +class ChunkMesh +{ + std::unique_ptr _mesh = nullptr; + Shader& _blockShader; + + struct FaceVertices + { + std::array front + { + { + Point3D{0.0f, 0.0f, 0.0f}, + Point3D{1.0f, 0.0f, 0.0f}, + Point3D{1.0f, 1.0f, 0.0f}, + Point3D{0.0f, 1.0f, 0.0f} + } + }; + + std::array back + { + { + Point3D{0.0f, 0.0f, 1.0f}, + Point3D{0.0f, 1.0f, 1.0f}, + Point3D{1.0f, 1.0f, 1.0f}, + Point3D{1.0f, 0.0f, 1.0f} + } + }; + + std::array left + { + { + Point3D{0.0f, 0.0f, 0.0f}, + Point3D{0.0f, 1.0f, 0.0f}, + Point3D{0.0f, 1.0f, 1.0f}, + Point3D{0.0f, 0.0f, 1.0f} + } + }; + + std::array right + { + { + Point3D{1.0f, 0.0f, 0.0f}, + Point3D{1.0f, 0.0f, 1.0f}, + Point3D{1.0f, 1.0f, 1.0f}, + Point3D{1.0f, 1.0f, 0.0f} + } + }; + + std::array top + { + { + Point3D{0.0f, 1.0f, 0.0f}, + Point3D{1.0f, 1.0f, 0.0f}, + Point3D{1.0f, 1.0f, 1.0f}, + Point3D{0.0f, 1.0f, 1.0f} + } + }; + + std::array bottom + { + { + Point3D{0.0f, 0.0f, 0.0f}, + Point3D{0.0f, 0.0f, 1.0f}, + Point3D{1.0f, 0.0f, 1.0f}, + Point3D{1.0f, 0.0f, 0.0f}, + } + }; + }; + const FaceVertices _faceVertices; + + static void AddFaceToMesh(const Position& origin, const std::array& faceVertices, const std::array& faceTextureCoordinates, std::vector& mesh); + +public: + + /// @brief The constructor. + /// @param blockShader - Shader of the blocks inside the chunk. + /// @param sizeOfChunk - Size of the chunk edge. + explicit ChunkMesh(Shader& blockShader, const size_t& sizeOfChunk); + + /// @brief Rebuilds the mesh basing on the passed blocks. + /// @param blocks - Blocks inside the chunk. + void Rebuild(const ChunkBlocks& blocks) const; + + /// @brief Renders blocks inside the chunk. + /// @param blocksTexture - The texture that blocks uses. + /// @param camera - Reference to the camera, so the blocks could be seen. + void Draw(const Texture& blocksTexture, const Camera& camera) const; +}; + diff --git a/src/Application/Sandbox/World/WorldGenerator.cpp b/src/Application/Layer/Sandbox/World/WorldGenerator.cpp similarity index 89% rename from src/Application/Sandbox/World/WorldGenerator.cpp rename to src/Application/Layer/Sandbox/World/WorldGenerator.cpp index e7cf7623..c04e8d46 100644 --- a/src/Application/Sandbox/World/WorldGenerator.cpp +++ b/src/Application/Layer/Sandbox/World/WorldGenerator.cpp @@ -16,3 +16,8 @@ void WorldGenerator::PaintChunk(const ChunkFrame& frame, ChunkBlocks& blocks) co _placer->PaintChunk(frame, blocks); WorldGeneratorUtils::OptimizeChunk(frame, blocks, *_placer); } + +BlockMap& WorldGenerator::GetBlockMap() +{ + return _blockMap; +} diff --git a/src/Application/Sandbox/World/WorldGenerator.h b/src/Application/Layer/Sandbox/World/WorldGenerator.h similarity index 90% rename from src/Application/Sandbox/World/WorldGenerator.h rename to src/Application/Layer/Sandbox/World/WorldGenerator.h index e392716e..c4e96c93 100644 --- a/src/Application/Sandbox/World/WorldGenerator.h +++ b/src/Application/Layer/Sandbox/World/WorldGenerator.h @@ -25,4 +25,7 @@ class WorldGenerator /// @param frame - the frame of the chunk. /// @param blocks - the blocks inside the chunk. void PaintChunk(const ChunkFrame& frame, ChunkBlocks& blocks) const; + + /// @brief Returns the map of blocks used by this generator. + BlockMap& GetBlockMap(); }; diff --git a/src/Application/Sandbox/World/WorldGeneratorUtils.cpp b/src/Application/Layer/Sandbox/World/WorldGeneratorUtils.cpp similarity index 81% rename from src/Application/Sandbox/World/WorldGeneratorUtils.cpp rename to src/Application/Layer/Sandbox/World/WorldGeneratorUtils.cpp index 662cbda8..f8da6b3b 100644 --- a/src/Application/Sandbox/World/WorldGeneratorUtils.cpp +++ b/src/Application/Layer/Sandbox/World/WorldGeneratorUtils.cpp @@ -16,9 +16,9 @@ void WorldGeneratorUtils::OptimizeBlock(const Position& origin, BlockVisibility& factor = -factor; factor *= frameSize; - const int& x = static_cast(factor.x) + static_cast(origin.x) + 1; - const int& y = static_cast(factor.y) + static_cast(origin.y) + 1; - const int& z = static_cast(factor.z) + static_cast(origin.z) + 1; + const int& x = static_cast(factor.x) + origin.x + 1; + const int& y = static_cast(factor.y) + origin.y + 1; + const int& z = static_cast(factor.z) + origin.z + 1; block.visibility = {false, false, false, false, false, false}; @@ -36,7 +36,7 @@ void WorldGeneratorUtils::OptimizeChunk(const ChunkFrame& frame, ChunkBlocks& bl { const auto noise = biomePlacer.GetChunkNoise(frame, 1); - for (auto& block : blocks.block) + for (auto& block : blocks) { OptimizeBlock(block.first, block.second, noise); } diff --git a/src/Application/Sandbox/World/WorldGeneratorUtils.h b/src/Application/Layer/Sandbox/World/WorldGeneratorUtils.h similarity index 100% rename from src/Application/Sandbox/World/WorldGeneratorUtils.h rename to src/Application/Layer/Sandbox/World/WorldGeneratorUtils.h diff --git a/src/Application/LayerStack/LayerStack.h b/src/Application/LayerStack/LayerStack.h new file mode 100644 index 00000000..a573cc12 --- /dev/null +++ b/src/Application/LayerStack/LayerStack.h @@ -0,0 +1,52 @@ +#pragma once +#include +#include + +#include "Application/Layer/Layer.h" + + +/// @class LayerStack +/// @brief Represents the stack that can process layers of content that +/// is displayed on the screen. +/// @details This structure handles the priority of what should be interactive on the screen. +class LayerStack +{ + std::vector> _layers{}; + +public: + + /// @brief Pushes the layer onto the stack. + void Push(std::unique_ptr layer) + { + _layers.emplace_back(std::move(layer)); + } + + /// @brief Pops the layer from the stack. + void Pop() + { + _layers.pop_back(); + } + + /// @brief Calls the OnUpdate() methods of the layers. + void Update() const + { + for (const auto& layer : _layers) + { + layer->OnUpdate(); + } + } + + /// @brief Calls the OnEvent() methods of the layers respecting the lock + /// @param hid - Reference to the Human Interface Device. + void ProcessEvents(HumanInterfaceDevice& hid) const + { + for (auto i = _layers.size(); i > 0; --i) + { + auto& layer = _layers[i - 1]; + + layer->OnEvent(hid); + if (layer->IsLocked()) break; + } + } +}; + diff --git a/src/Application/LayerStack/Stack/SandboxStack.h b/src/Application/LayerStack/Stack/SandboxStack.h new file mode 100644 index 00000000..46749e8b --- /dev/null +++ b/src/Application/LayerStack/Stack/SandboxStack.h @@ -0,0 +1,19 @@ +#pragma once +#include "Application/Layer/PauseMenu/PauseMenuLayer.h" +#include "Application/Layer/Sandbox/SandboxLayer.h" +#include "Application/LayerStack/LayerStack.h" + +/// @class SandboxStack +/// @brief Represents the stack responsible for the full simulation of the sandbox. +class SandboxStack final : public LayerStack +{ +public: + + /// @brief The constructor. + /// @param window - Reference to the window. + explicit SandboxStack(Window& window) + { + Push(std::make_unique(window)); + Push(std::make_unique()); + } +}; diff --git a/src/Application/Sandbox/Camera.cpp b/src/Application/Sandbox/Camera.cpp deleted file mode 100644 index 40eb9a33..00000000 --- a/src/Application/Sandbox/Camera.cpp +++ /dev/null @@ -1,192 +0,0 @@ -#include "Camera.h" - -Camera::Camera(Window& window, const glm::vec3 position, HumanInterfaceDevice& hid) : _window(window), _position(position), _hid(hid) -{ - glfwSetInputMode(_window.GetHandle(), GLFW_CURSOR, GLFW_CURSOR_DISABLED); -} - -void Camera::Update() -{ - // ReSharper disable once CppInitializedValueIsAlwaysRewritten - auto view = glm::mat4(1.0f); - view = lookAt(_position, _position + _orientation, _up); - - const float aspectRatio = static_cast(_window.GetWidth()) / static_cast(_window.GetHeight()); - - // ReSharper disable once CppInitializedValueIsAlwaysRewritten - auto projection = glm::mat4(1.0f); - projection = glm::perspective(glm::radians(_fieldOfView), aspectRatio, _nearPane, _farPane); - - _orthographicProjection = projection * view; -} - -void Camera::HandleHorizontalMovement(const KeyboardKey& left, const KeyboardKey& right, const KeyboardKey& forward, - const KeyboardKey& backward) -{ - if (_hid.IsPressed(left)) - { - _position += _speed * -normalize(cross(_orientation, _up)); - } - if (_hid.IsPressed(right)) - { - _position += _speed * normalize(cross(_orientation, _up)); - } - if (_hid.IsPressed(forward)) - { - _position += _speed * _orientation; - } - if (_hid.IsPressed(backward)) - { - _position += _speed * -_orientation; - } -} - -void Camera::HandleVerticalMovement(const KeyboardKey& up, const KeyboardKey& down) -{ - if (_hid.IsPressed(up)) - { - _position += _speed * _up; - } - if (_hid.IsPressed(down)) - { - _position += _speed * -_up; - } -} - -void Camera::HandleSpeed(const KeyboardKey& boost, const float boostSpeed) -{ - _speed = _hid.IsPressed(boost) ? boostSpeed : _defaultSpeed; -} - -void Camera::HandleCursorMovement() -{ - double mouseX; - double mouseY; - glfwGetCursorPos(_window.GetHandle(), &mouseX, &mouseY); - - const double middleAxisX = static_cast(_window.GetWidth()) / 2.0; - const double middleAxisY = static_cast(_window.GetHeight()) / 2.0; - - const float xAxisRotation = _sensitivity * (static_cast(mouseY - middleAxisY) / static_cast(_window.GetHeight())); - const float yAxisRotation = _sensitivity * (static_cast(mouseX - middleAxisX) / static_cast(_window.GetWidth())); - - const auto orientation = rotate(_orientation, glm::radians(-xAxisRotation), normalize(cross(_orientation, _up))); - const auto angleWithXAxis = abs(angle(orientation, _up) - glm::radians(90.0f)); - - // This prevents the barrel roll situation when looking up - if (angleWithXAxis < glm::radians(85.0f)) - { - _orientation = orientation; - } - - _orientation = rotate(_orientation, glm::radians(-yAxisRotation), _up); - glfwSetCursorPos(_window.GetHandle(), middleAxisX, middleAxisY); -} - -void Camera::Bind(Shader const& shader) const -{ - shader.Load(); - glUniformMatrix4fv(glGetUniformLocation(shader.GetProgram(), "camera"), 1, GL_FALSE, value_ptr(_orthographicProjection)); -} - -void Camera::HandleInput() -{ - - if (_hid.IsPressedOnce(KeyboardKey::escape)) - { - _isPaused = !_isPaused; - if (_isPaused) - { - glfwSetInputMode(_window.GetHandle(), GLFW_CURSOR, GLFW_CURSOR_NORMAL); - } - else - { - glfwSetInputMode(_window.GetHandle(), GLFW_CURSOR, GLFW_CURSOR_DISABLED); - } - } - - if (_isPaused) - { - return; - } - - HandleHorizontalMovement(KeyboardKey::a, KeyboardKey::d, KeyboardKey::w, KeyboardKey::s); - HandleVerticalMovement(KeyboardKey::space, KeyboardKey::leftCtrl); - HandleSpeed(KeyboardKey::leftShift, 0.4f); - HandleCursorMovement(); -} - -glm::vec3 Camera::GetPosition() const -{ - return _position; -} - -inline size_t Camera::GetWidth() const -{ - return _window.GetWidth(); -} - -inline size_t Camera::GetHeight() const -{ - return _window.GetHeight(); -} - -inline float Camera::GetDefaultSpeed() const -{ - return _defaultSpeed; -} - -inline void Camera::SetDefaultSpeed(const float defaultSpeed) -{ - _defaultSpeed = defaultSpeed; -} - -inline float Camera::GetSpeed() const -{ - return _speed; -} - -inline void Camera::SetSpeed(const float speed) -{ - _speed = speed; -} - -inline float Camera::GetSensitivity() const -{ - return _sensitivity; -} - -inline void Camera::SetSensitivity(const float sensitivity) -{ - _sensitivity = sensitivity; -} - -inline float Camera::GetFieldOfView() const -{ - return _fieldOfView; -} - -inline void Camera::SetFieldOfView(const float fieldOfView) -{ - _fieldOfView = fieldOfView; -} - -inline float Camera::GetNearPane() const -{ - return _nearPane; -} - -inline void Camera::SetNearPane(const float nearPane) -{ - _nearPane = nearPane; -} - -inline float Camera::GetFarPane() const -{ - return _farPane; -} - -inline void Camera::SetFarPane(const float farPane) -{ - _farPane = farPane; -} \ No newline at end of file diff --git a/src/Application/Sandbox/Events/HumanInterfaceDevice.cpp b/src/Application/Sandbox/Events/HumanInterfaceDevice.cpp deleted file mode 100644 index a3e74e3e..00000000 --- a/src/Application/Sandbox/Events/HumanInterfaceDevice.cpp +++ /dev/null @@ -1,112 +0,0 @@ -#include "HumanInterfaceDevice.h" - -std::string HumanInterfaceDevice::KeyDescription(const KeyboardKey& key) const -{ - switch(key) - { - case KeyboardKey::a: return "A"; - case KeyboardKey::d: return "D"; - case KeyboardKey::s: return "S"; - case KeyboardKey::w: return "W"; - - case KeyboardKey::escape: return "ESC"; - case KeyboardKey::space: return "SPACE"; - case KeyboardKey::leftShift: return "LEFT SHIFT"; - case KeyboardKey::rightShift: return "RIGHT SHIFT"; - case KeyboardKey::leftCtrl: return "LEFT CTRL"; - case KeyboardKey::rightCtrl: return "RIGHT CTRL"; - } - - _log.Warn("Key code " + std::to_string(static_cast(key)) + " description not found!"); - return std::to_string(static_cast(key)); -} - -std::string HumanInterfaceDevice::ButtonDescription(const MouseButton& button) const -{ - switch(button) - { - case MouseButton::left: return "LEFT BUTTON"; - case MouseButton::right: return "RIGHT BUTTON"; - } - - _log.Warn("Button code " + std::to_string(static_cast(button)) + " description not found!"); - return std::to_string(static_cast(button)); -} - -int HumanInterfaceDevice::GetState(const KeyboardKey& key) const -{ - return glfwGetKey(_window, static_cast(key)); -} - -int HumanInterfaceDevice::GetState(const MouseButton& button) const -{ - return glfwGetMouseButton(_window, static_cast(button)); -} - -HumanInterfaceDevice::HumanInterfaceDevice(GLFWwindow* window) : _window(window) -{ -} - -bool HumanInterfaceDevice::IsPressed(const KeyboardKey& key) const -{ - if (GetState(key) == GLFW_PRESS) - { - _log.Trace("Key pressed: " + KeyDescription(key)); - return true; - } - - return false; -} - -bool HumanInterfaceDevice::IsPressedOnce(const KeyboardKey& key) -{ - if (GetState(key) == GLFW_PRESS && _onceHandledKeyboardKeys.find(key) == _onceHandledKeyboardKeys.end()) - { - _onceHandledKeyboardKeys.insert(key); - return IsPressed(key); - } - - if (IsReleased(key)) - { - _onceHandledKeyboardKeys.erase(key); - } - - return false; -} - -bool HumanInterfaceDevice::IsReleased(const KeyboardKey& key) const -{ - return GetState(key) == GLFW_RELEASE; -} - -bool HumanInterfaceDevice::IsPressed(const MouseButton& button) const -{ - if (GetState(button) == GLFW_PRESS) - { - _log.Trace("Button pressed: " + ButtonDescription(button)); - return true; - } - - return false; -} - -bool HumanInterfaceDevice::IsPressedOnce(const MouseButton& button) -{ - if (GetState(button) == GLFW_PRESS && _onceHandledMouseButtons.find(button) == _onceHandledMouseButtons.end()) - { - _onceHandledMouseButtons.insert(button); - return IsPressed(button); - } - - if (IsReleased(button)) - { - _onceHandledMouseButtons.erase(button); - } - - return false; -} - -bool HumanInterfaceDevice::IsReleased(const MouseButton& button) const -{ - return GetState(button) == GLFW_RELEASE; -} diff --git a/src/Application/Sandbox/Model/BlockFaceModel.cpp b/src/Application/Sandbox/Model/BlockFaceModel.cpp deleted file mode 100644 index ab5c707c..00000000 --- a/src/Application/Sandbox/Model/BlockFaceModel.cpp +++ /dev/null @@ -1,12 +0,0 @@ -#include "BlockFaceModel.h" - -BlockFaceModel::BlockFaceModel(std::unique_ptr& mesh, std::shared_ptr texture) -{ - _mesh = std::move(mesh); - _texture = std::move(texture); -} - -void BlockFaceModel::Draw(const glm::vec3& origin, const Camera& camera) const -{ - _mesh->Draw(origin, *_texture, camera); -} diff --git a/src/Application/Sandbox/Model/BlockFaceModel.h b/src/Application/Sandbox/Model/BlockFaceModel.h deleted file mode 100644 index 49a6ebb9..00000000 --- a/src/Application/Sandbox/Model/BlockFaceModel.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once -#include - -#include "Mesh/Mesh.h" - -/// @class BlockFaceModel -/// @brief Represents face of a @see BlockModel. -class BlockFaceModel -{ - std::unique_ptr _mesh; - std::shared_ptr _texture; - -public: - - /// @brief The constructor. - /// @param mesh - The mesh of the model. - /// @param texture - The texture that the model is covered with. - BlockFaceModel(std::unique_ptr& mesh, std::shared_ptr texture); - - /// @brief Draws the face of a block. - /// @param origin - A position in the world to place the model. - /// @param camera - It is used to bind a shader to see the drawn model. - void Draw(const Position& origin, const Camera& camera) const; -}; diff --git a/src/Application/Sandbox/Model/BlockModel.h b/src/Application/Sandbox/Model/BlockModel.h deleted file mode 100644 index 2c9e447e..00000000 --- a/src/Application/Sandbox/Model/BlockModel.h +++ /dev/null @@ -1,114 +0,0 @@ -#pragma once -#include "BlockFaceModel.h" -#include "Application/Sandbox/Camera.h" - -/// @brief Container for the face models of a block. -struct BlockFaces -{ - /// @brief Model of the block front face. - BlockFaceModel front; - - /// @brief Model of the block back face. - BlockFaceModel back; - - /// @brief Model of the block left face. - BlockFaceModel left; - - /// @brief Model of the block right face. - BlockFaceModel right; - - /// @brief Model of the block top face. - BlockFaceModel top; - - /// @brief Model of the block bottom face. - BlockFaceModel bottom; -}; - - -/// @brief Represents visibility of the faces. -struct FacesVisibility -{ - /// @brief Answers the question "Is the front face of this block visible?". - bool front; - - /// @brief Answers the question "Is the back face of this block visible?". - bool back; - - /// @brief Answers the question "Is the left face of this block visible?". - bool left; - - /// @brief Answers the question "Is the right face of this block visible?". - bool right; - - /// @brief Answers the question "Is the top face of this block visible?". - bool top; - - /// @brief Answers the question "Is the bottom face of this block visible?". - bool bottom; -}; - -/// @class BlockModel -/// @brief Represents a graphical model of a block. -/// @note This class is not an actual model. -/// More like container for the @see BlockFaceModel objects. But it suits well it's definition and -/// has functionality that makes sense. -class BlockModel -{ - BlockFaces _blockFaces; - -public: - - /// @brief The constructor. - /// @param faces - The faces of the block. - explicit BlockModel(BlockFaces faces) - : _blockFaces(std::move(faces)) - {} - - /// @brief Draws the front face. - /// @param origin - A position in the world to place the mesh. - /// @param camera - It is used to bind a shader to see the drawn model. - void DrawFrontFace(const Position& origin, const Camera& camera) const - { - _blockFaces.front.Draw(origin, camera); - } - - /// @brief Draws the back face. - /// @param origin - A position in the world to place the mesh. - /// @param camera - It is used to bind a shader to see the drawn model. - void DrawBackFace(const Position& origin, const Camera& camera) const - { - _blockFaces.back.Draw(origin, camera); - } - - /// @brief Draws the left face. - /// @param origin - A position in the world to place the mesh. - /// @param camera - It is used to bind a shader to see the drawn model. - void DrawLeftFace(const Position& origin, const Camera& camera) const - { - _blockFaces.left.Draw(origin, camera); - } - - /// @brief Draws the right face. - /// @param origin - A position in the world to place the mesh. - /// @param camera - It is used to bind a shader to see the drawn model. - void DrawRightFace(const Position& origin, const Camera& camera) const - { - _blockFaces.right.Draw(origin, camera); - } - - /// @brief Draws the top face. - /// @param origin - A position in the world to place the mesh. - /// @param camera - It is used to bind a shader to see the drawn model. - void DrawTopFace(const Position& origin, const Camera& camera) const - { - _blockFaces.top.Draw(origin, camera); - } - - /// @brief Draws the bottom face. - /// @param origin - A position in the world to place the mesh. - /// @param camera - It is used to bind a shader to see the drawn model. - void DrawBottomFace(const Position& origin, const Camera& camera) const - { - _blockFaces.bottom.Draw(origin, camera); - } -}; \ No newline at end of file diff --git a/src/Application/Sandbox/Sandbox.cpp b/src/Application/Sandbox/Sandbox.cpp deleted file mode 100644 index d5f28cff..00000000 --- a/src/Application/Sandbox/Sandbox.cpp +++ /dev/null @@ -1,53 +0,0 @@ -#include "Sandbox.h" - -#include "Camera.h" -#include "Events/HumanInterfaceDevice.h" -#include "World/WorldGenerator.h" -#include "Utils/FPSCounter.h" -#include "World/Chunks/Rendring/ChunkPlacer.h" - - -Sandbox::Sandbox(Window& window) : _window(window) -{ -} - -void Sandbox::Run() const -{ - _log.Info("Launching simulation..."); - - HumanInterfaceDevice hid(_window.GetHandle()); - Camera camera(_window, glm::vec3(0.0f, 0.0f, 0.0f), hid); - - auto worldGenerator = std::make_shared(69); - - ChunkPlacer chunkPlacer(RenderViewType::cube, 8, 1, camera); - chunkPlacer.Bind(worldGenerator); - - FPSCounter counter; - - glEnable(GL_DEPTH_TEST); - - while(!glfwWindowShouldClose(_window.GetHandle())) - { - glfwPollEvents(); - - if (_window.GetWidth() <= 0 || _window.GetHeight() <= 0) - { - continue; - } - - glClearColor(0.07f, 0.13f, 0.17f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - camera.Update(); - camera.HandleInput(); - chunkPlacer.Update(); - counter.Update(); - - glfwSwapBuffers(_window.GetHandle()); - } - - glDisable(GL_DEPTH_TEST); - - gltTerminate(); -} diff --git a/src/Application/Sandbox/Sandbox.h b/src/Application/Sandbox/Sandbox.h deleted file mode 100644 index fca1be1d..00000000 --- a/src/Application/Sandbox/Sandbox.h +++ /dev/null @@ -1,22 +0,0 @@ -#pragma once -#include "Core/Log.h" -#include "Application/Window.h" - -/// @class Sandbox -/// @brief Class where the world is projected. -/// @details This class handles displaying the world or so to say the actual simulation. -class Sandbox -{ - Log& _log = Log::Get(); - Window& _window; - -public: - - /// @brief The constructor. - /// @param window - Reference to the window settings. - explicit Sandbox(Window& window); - - /// @brief Initializes the simulation. - void Run() const; -}; - diff --git a/src/Application/Sandbox/World/Blocks/BlockBuilder.cpp b/src/Application/Sandbox/World/Blocks/BlockBuilder.cpp deleted file mode 100644 index 2aa20d4a..00000000 --- a/src/Application/Sandbox/World/Blocks/BlockBuilder.cpp +++ /dev/null @@ -1,64 +0,0 @@ -#include "BlockBuilder.h" - -void BlockBuilder::SetFaceTexture( - std::vector& face, - const int x, - const int y, - const bool flipTexture) const -{ - _textureAtlas->SetSprite(face, x, y, flipTexture); -} - -void BlockBuilder::DetermineAndSetFaceTexture(const std::string& face, const int x, const int y) const -{ - if (face == "front") SetFaceTexture(_faceVertices->front, x, y, false); - if (face == "back") SetFaceTexture(_faceVertices->back, x, y, true); - if (face == "left") SetFaceTexture(_faceVertices->left, x, y, true); - if (face == "right") SetFaceTexture(_faceVertices->right, x, y, false); - if (face == "top") SetFaceTexture(_faceVertices->top, x, y, false); - if (face == "bottom") SetFaceTexture(_faceVertices->bottom, x, y, true); -} - -BlockBuilder::BlockBuilder(const std::string& textureAtlasFilename, const size_t spriteSize, std::vector& blockIndices, Shader& blockShader) - : _faceIndices(blockIndices), - _textureAtlas(std::make_shared(textureAtlasFilename, spriteSize)), - _blockShader(blockShader) -{ -} - -BlockModel BlockBuilder::Build(const JsonData& blockData) -{ - for (const auto& textureData : blockData["textures"]) - { - const int x = textureData["location"].value("column", 0); - const int y = textureData["location"].value("row", 0); - - for (const auto& face : textureData["faces"]) - { - DetermineAndSetFaceTexture(face, x, y); - } - } - - FaceMeshes faceMeshes - { - std::make_unique(_faceVertices->front, _faceIndices, _blockShader), - std::make_unique(_faceVertices->back, _faceIndices, _blockShader), - std::make_unique(_faceVertices->left, _faceIndices, _blockShader), - std::make_unique(_faceVertices->right, _faceIndices, _blockShader), - std::make_unique(_faceVertices->top, _faceIndices, _blockShader), - std::make_unique(_faceVertices->bottom, _faceIndices, _blockShader) - }; - - BlockFaces faces - { - BlockFaceModel(faceMeshes.front, _textureAtlas), - BlockFaceModel(faceMeshes.back, _textureAtlas), - BlockFaceModel(faceMeshes.left, _textureAtlas), - BlockFaceModel(faceMeshes.right, _textureAtlas), - BlockFaceModel(faceMeshes.top, _textureAtlas), - BlockFaceModel(faceMeshes.bottom, _textureAtlas) - }; - - return BlockModel(std::move(faces)); -} - diff --git a/src/Application/Sandbox/World/Blocks/BlockBuilder.h b/src/Application/Sandbox/World/Blocks/BlockBuilder.h deleted file mode 100644 index 663f3660..00000000 --- a/src/Application/Sandbox/World/Blocks/BlockBuilder.h +++ /dev/null @@ -1,102 +0,0 @@ -#pragma once -#include "Core/Metadata.h" -#include "Application/Sandbox/Model/BlockModel.h" -#include "Application/Sandbox/Model/Mesh/Geometry/Shader.h" -#include "Application/Sandbox/Model/Surface/TextureAtlas.h" - -/// @class BlockBuilder -/// @brief A factory that builds and outputs blocks based on their metadata. -class BlockBuilder -{ - struct FaceVertices - { - std::vector front - { - Vertex{Position{0.0f, 0.0f, 0.0f}, Point{0.0f, 0.0f}}, - Vertex{Position{1.0f, 0.0f, 0.0f}, Point{1.0f, 0.0f}}, - Vertex{Position{1.0f, 1.0f, 0.0f}, Point{1.0f, 1.0f}}, - Vertex{Position{0.0f, 1.0f, 0.0f}, Point{0.0f, 1.0f}}, - }; - - std::vector back - { - Vertex{Position{0.0f, 0.0f, 1.0f}, Point{0.0f, 0.0f}}, - Vertex{Position{0.0f, 1.0f, 1.0f}, Point{1.0f, 0.0f}}, - Vertex{Position{1.0f, 1.0f, 1.0f}, Point{1.0f, 1.0f}}, - Vertex{Position{1.0f, 0.0f, 1.0f}, Point{0.0f, 1.0f}}, - }; - - std::vector left - { - Vertex{Position{0.0f, 0.0f, 0.0f}, Point{0.0f, 0.0f}}, - Vertex{Position{0.0f, 1.0f, 0.0f}, Point{1.0f, 0.0f}}, - Vertex{Position{0.0f, 1.0f, 1.0f}, Point{1.0f, 1.0f}}, - Vertex{Position{0.0f, 0.0f, 1.0f}, Point{0.0f, 1.0f}}, - }; - - std::vector right - { - Vertex{Position{1.0f, 0.0f, 0.0f}, Point{0.0f, 0.0f}}, - Vertex{Position{1.0f, 0.0f, 1.0f}, Point{1.0f, 0.0f}}, - Vertex{Position{1.0f, 1.0f, 1.0f}, Point{1.0f, 1.0f}}, - Vertex{Position{1.0f, 1.0f, 0.0f}, Point{0.0f, 1.0f}}, - }; - - std::vector top - { - Vertex{Position{0.0f, 1.0f, 0.0f}, Point{0.0f, 0.0f}}, - Vertex{Position{1.0f, 1.0f, 0.0f}, Point{1.0f, 0.0f}}, - Vertex{Position{1.0f, 1.0f, 1.0f}, Point{1.0f, 1.0f}}, - Vertex{Position{0.0f, 1.0f, 1.0f}, Point{0.0f, 1.0f}}, - }; - - std::vector bottom - { - Vertex{Position{0.0f, 0.0f, 0.0f}, Point{0.0f, 0.0f}}, - Vertex{Position{0.0f, 0.0f, 1.0f}, Point{1.0f, 0.0f}}, - Vertex{Position{1.0f, 0.0f, 1.0f}, Point{1.0f, 1.0f}}, - Vertex{Position{1.0f, 0.0f, 0.0f}, Point{0.0f, 1.0f}}, - }; - }; - - struct FaceMeshes - { - std::unique_ptr front; - std::unique_ptr back; - std::unique_ptr left; - std::unique_ptr right; - std::unique_ptr top; - std::unique_ptr bottom; - }; - - struct FaceTextures - { - std::shared_ptr front; - std::shared_ptr back; - std::shared_ptr left; - std::shared_ptr right; - std::shared_ptr top; - std::shared_ptr bottom; - }; - - std::shared_ptr _faceVertices = std::make_shared(); - std::vector& _faceIndices; - std::shared_ptr _textureAtlas; - Shader& _blockShader; - - void SetFaceTexture(std::vector& face, int x, int y, bool flipTexture) const; - void DetermineAndSetFaceTexture(const std::string& face, int x, int y) const; - -public: - - /// The constructor. - /// @param textureAtlasFilename - Path of the file containing the texture atlas of blocks. - /// @param spriteSize - The size of the sprite. - /// @param blockIndices - Indices of a block (for optimization purposes). - /// @param blockShader - Shader of a block (for optimization purposes). - explicit BlockBuilder(const std::string& textureAtlasFilename, size_t spriteSize, std::vector& blockIndices, Shader& blockShader); - - /// @brief Builds block based on the data. - /// @param blockData - metadata of the block to be built. - BlockModel Build(const JsonData& blockData); -}; diff --git a/src/Application/Sandbox/World/Blocks/BlockProvider.h b/src/Application/Sandbox/World/Blocks/BlockProvider.h deleted file mode 100644 index bc88a6f2..00000000 --- a/src/Application/Sandbox/World/Blocks/BlockProvider.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once -#include "Core/Metadata.h" -#include "Application/Sandbox/Model/BlockModel.h" - -/// @class BlockProvider -/// @brief Provides all the blocks mentioned in the file. -class BlockProvider -{ - Metadata _blocksMetadata; - -public: - - /// @brief The constructor. - /// @param filenameWithBlocksData - Path to the JSON file containing the blocks metadata. - explicit BlockProvider(const std::string& filenameWithBlocksData); - - /// @brief Provides the map of the built blocks. - /// @param blockIndices - Indices of a block (for optimization purposes). - /// @param blockShader - Shader of a block (for optimization purposes). - /// @param blocksSetName - Name of the blocks set that is used for this particular block map. - std::unordered_map> GetBlocks(std::vector& blockIndices, Shader& blockShader, const std::string& blocksSetName = "default"); -}; - diff --git a/src/Application/Sandbox/World/Chunks/Rendring/ChunkPlacer.cpp b/src/Application/Sandbox/World/Chunks/Rendring/ChunkPlacer.cpp deleted file mode 100644 index b84fa479..00000000 --- a/src/Application/Sandbox/World/Chunks/Rendring/ChunkPlacer.cpp +++ /dev/null @@ -1,32 +0,0 @@ -#include "ChunkPlacer.h" - -#include "Core/EngineExceptions.h" -#include "RenderViews/RenderViewTypes.h" - -std::unique_ptr ChunkPlacer::GetRenderView(const RenderViewType viewType) -{ - switch (viewType) - { - case RenderViewType::diamond: return std::make_unique(_renderDistance, _chunkSize); - case RenderViewType::cube: return std::make_unique(_renderDistance, _chunkSize); - case RenderViewType::tiltedCube: return std::make_unique(_renderDistance, _chunkSize); - } - - throw UnknownValueException("The provided Render View type is not defined!"); -} - -ChunkPlacer::ChunkPlacer(const RenderViewType viewType, const size_t chunkSize, const size_t renderDistance, Camera& camera) - : _camera(camera), _renderDistance(renderDistance), _chunkSize(chunkSize), _viewType(viewType) -{ -} - -void ChunkPlacer::Update() const -{ - _renderer->Render(); -} - -void ChunkPlacer::Bind(const std::shared_ptr& worldGenerator) -{ - auto view = GetRenderView(_viewType); - _renderer = std::make_unique(*worldGenerator, view, _camera); -} \ No newline at end of file diff --git a/src/Application/Sandbox/World/Chunks/Rendring/ChunkPlacer.h b/src/Application/Sandbox/World/Chunks/Rendring/ChunkPlacer.h deleted file mode 100644 index bf145721..00000000 --- a/src/Application/Sandbox/World/Chunks/Rendring/ChunkPlacer.h +++ /dev/null @@ -1,40 +0,0 @@ -#pragma once -#include "Application/Sandbox/Camera.h" -#include "ChunkRenderer.h" -#include "RenderViews/RenderViewTypes.h" - -/// @class ChunkPlacer -/// @brief Handles placing the chunks around the camera. -/// @details This class handles @see Chunk objects and manages them for optimal experience. -class ChunkPlacer -{ - Log& _log = Log::Get(); - - std::unique_ptr _renderer{}; - Camera& _camera; - - size_t _renderDistance; - size_t _chunkSize; - RenderViewType _viewType; - - std::unique_ptr GetRenderView(RenderViewType viewType); - -public: - - /// @brief The constructor. - /// @param viewType - the way the chunks will be generated. - /// @param chunkSize - the size of the generated chunks. - /// @param renderDistance - specifies the maximum distance from the camera to render. - /// @param camera - the object around which the chunks are rendered. - ChunkPlacer(RenderViewType viewType, size_t chunkSize, size_t renderDistance, Camera& camera); - - /// @brief Updates the chunk manager to adapt to the current frame. - void Update() const; - - /// @brief Binds world generator to the chunk manager. - /// @details The world generator is used to define how the world is generated, when - /// this class handles only displaying it in an optimal way. - /// @param worldGenerator - reference to the world generator. - void Bind(const std::shared_ptr& worldGenerator); -}; - diff --git a/src/Application/Sandbox/World/Chunks/Rendring/ChunkRenderer.cpp b/src/Application/Sandbox/World/Chunks/Rendring/ChunkRenderer.cpp deleted file mode 100644 index 7e2ed00d..00000000 --- a/src/Application/Sandbox/World/Chunks/Rendring/ChunkRenderer.cpp +++ /dev/null @@ -1,128 +0,0 @@ -#include "ChunkRenderer.h" - -#include "Core/EngineExceptions.h" - -std::vector ChunkRenderer::Subtract(const std::vector& aSet, const std::vector& bSet) -{ - std::vector result; - - for (const auto& value : aSet) - { - if (std::find(bSet.begin(), bSet.end(), value) == bSet.end()) - { - result.emplace_back(value); - } - } - - return result; -} - -glm::ivec3 ChunkRenderer::GetNormalizedPosition(const glm::vec3& position) const -{ - auto normalizedPosition = position; - - normalizedPosition /= _renderView->GetChunkSize(); - - normalizedPosition.x = floor(normalizedPosition.x); - normalizedPosition.y = floor(normalizedPosition.y); - normalizedPosition.z = floor(normalizedPosition.z); - - return {normalizedPosition}; -} - -std::string ChunkRenderer::PositionToString(const glm::ivec3& position) const -{ - return std::to_string(position.x) + ", " + - std::to_string(position.y) + ", " + - std::to_string(position.z); -} - -void ChunkRenderer::RemoveChunkAt(const glm::ivec3& origin) -{ - const auto outdatedChunk = - std::find_if( - _loadedChunks.begin(), - _loadedChunks.end(), - [&](const std::unique_ptr& chunk) - { - return chunk->GetOrigin() == origin; - } - ); - - if (outdatedChunk == _loadedChunks.end()) - { - throw NotFoundException("The chunk with given origin is not loaded!"); - } - - _log.Trace("Removed chunk: " + PositionToString(origin)); - _loadedChunks.erase(outdatedChunk); -} - -void ChunkRenderer::SpawnChunkAt(const glm::ivec3& origin) -{ - _log.Trace("Added chunk: " + PositionToString(origin)); - - const auto chunkFrame = ChunkFrame{origin, _renderView->GetChunkSize()}; - auto chunkBlocks = ChunkBlocks{}; - _generator.PaintChunk(chunkFrame, chunkBlocks); - - auto chunk = std::make_unique(chunkFrame, std::move(chunkBlocks), _camera); - _loadedChunks.emplace_back(std::move(chunk)); -} - -void ChunkRenderer::RenderChunksAround(const glm::ivec3& normalizedOrigin) -{ - const auto previousChunksAroundOrigins = _loadedChunksOrigins; - const auto currentChunksAroundOrigins = _renderView->GetChunksAround(normalizedOrigin); - - const auto newChunksOrigins = Subtract(currentChunksAroundOrigins, previousChunksAroundOrigins); - const auto outdatedChunksOrigins = Subtract(previousChunksAroundOrigins, currentChunksAroundOrigins); - - for (const auto& outdatedOrigin : outdatedChunksOrigins) - { - RemoveChunkAt(outdatedOrigin); - } - - for (const auto& newOrigin : newChunksOrigins) - { - SpawnChunkAt(newOrigin); - } - - _loadedChunksOrigins = currentChunksAroundOrigins; -} - -ChunkRenderer::ChunkRenderer(WorldGenerator& generator, std::unique_ptr& renderView, Camera& camera) - : _camera(camera), _renderView(std::move(renderView)), _generator(generator), _previousNormalizedPosition(GetNormalizedPosition(camera.GetPosition())) -{ - glCullFace(GL_FRONT); - glFrontFace(GL_CCW); - - RenderChunksAround(_previousNormalizedPosition); -} - -void ChunkRenderer::Render() -{ - const auto currentNormalizedPosition = GetNormalizedPosition(_camera.GetPosition()); - - if (currentNormalizedPosition != _previousNormalizedPosition) - { - _previousNormalizedPosition = currentNormalizedPosition; - RenderChunksAround(currentNormalizedPosition); - - _log.Trace("Normalized position: " + PositionToString(currentNormalizedPosition)); - } - - glEnable(GL_CULL_FACE); - - for (const auto& chunk : _loadedChunks) - { - chunk->Draw(); - } - - glDisable(GL_CULL_FACE); -} - -void ChunkRenderer::SetRenderView(std::unique_ptr& renderView) -{ - _renderView = std::move(renderView); -} diff --git a/src/Application/Sandbox/World/Chunks/Rendring/ChunkRenderer.h b/src/Application/Sandbox/World/Chunks/Rendring/ChunkRenderer.h deleted file mode 100644 index 75ed216f..00000000 --- a/src/Application/Sandbox/World/Chunks/Rendring/ChunkRenderer.h +++ /dev/null @@ -1,50 +0,0 @@ -#pragma once -#include -#include - -#include "RenderViews/RenderView.h" -#include "Application/Sandbox/Camera.h" -#include "Application/Sandbox/World/Chunks/Structure/Chunk.h" -#include "Application/Sandbox/World/WorldGenerator.h" - -/// @class ChunkRenderer -/// @brief Supports rendering chunks. -/// @details This class is responsible for rendering chunks around the camera by using the algorithms -/// specified in the @link RenderView @endlink -class ChunkRenderer -{ - Log& _log = Log::Get(); - - Camera& _camera; - std::unique_ptr _renderView{}; - WorldGenerator& _generator; - - glm::ivec3 _previousNormalizedPosition; - std::vector _loadedChunksOrigins = {}; - std::vector> _loadedChunks = {}; - - static std::vector Subtract(const std::vector& aSet, const std::vector& bSet); - glm::ivec3 GetNormalizedPosition(const glm::vec3& position) const; - std::string PositionToString(const glm::ivec3& position) const; - - void RemoveChunkAt(const glm::ivec3& origin); - void SpawnChunkAt(const glm::ivec3& origin); - void RenderChunksAround(const glm::ivec3& normalizedOrigin); - -public: - - /// @brief The constructor. - /// @param generator - world generator for chunk building. - /// @param renderView - to specify which chunks to render. - /// @param camera - shares a reference point around which the chunks are rendered. - explicit ChunkRenderer(WorldGenerator& generator, std::unique_ptr& renderView, Camera& camera); - - /// @brief Renders loaded chunks. - void Render(); - - /// @brief Sets the render view. - /// @param renderView - render view. - void SetRenderView(std::unique_ptr& renderView); -}; - - diff --git a/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/RenderViewTypes.h b/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/RenderViewTypes.h deleted file mode 100644 index eaf54094..00000000 --- a/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/RenderViewTypes.h +++ /dev/null @@ -1,12 +0,0 @@ -// ReSharper disable CppUnusedIncludeDirective -#pragma once -#include "DiamondView.h" -#include "CubeView.h" -#include "TiltedCube.h" - -enum class RenderViewType -{ - diamond = 0, - cube, - tiltedCube -}; \ No newline at end of file diff --git a/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/TiltedCube.h b/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/TiltedCube.h deleted file mode 100644 index 0f410033..00000000 --- a/src/Application/Sandbox/World/Chunks/Rendring/RenderViews/TiltedCube.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once -#include "RenderView.h" - -/// @class TiltedCube -/// @brief Provides an algorithm that the renderer renders chunks in as a tilted cube. -/// @details A tilted cube is just a cube that it's edges are pointing cardinal directions. -class TiltedCube final : public RenderView -{ -public: - using RenderView::RenderView; - - size_t GetChunksAmount() override; - std::vector GetChunksAround(glm::ivec3 normalizedOrigin) override; -}; - diff --git a/src/Application/Sandbox/World/Chunks/Structure/Chunk.cpp b/src/Application/Sandbox/World/Chunks/Structure/Chunk.cpp deleted file mode 100644 index 7f7d57f6..00000000 --- a/src/Application/Sandbox/World/Chunks/Structure/Chunk.cpp +++ /dev/null @@ -1,30 +0,0 @@ -#include "Chunk.h" - - -Chunk::Chunk(const ChunkFrame& frame, ChunkBlocks blocks, Camera& camera) - : _frame(frame), _blocks(std::move(blocks)), _camera(camera) -{ -} - -void Chunk::Draw() const -{ - for (auto& block : _blocks.block) - { - auto origin = block.first; - - const auto& blockModel = block.second.model; - const auto& faceVisible = block.second.visibility; - - if (faceVisible.front) blockModel->DrawFrontFace(origin, _camera); - if (faceVisible.back) blockModel->DrawBackFace(origin, _camera); - if (faceVisible.left) blockModel->DrawLeftFace(origin, _camera); - if (faceVisible.right) blockModel->DrawRightFace(origin, _camera); - if (faceVisible.top) blockModel->DrawTopFace(origin, _camera); - if (faceVisible.bottom) blockModel->DrawBottomFace(origin, _camera); - } -} - -glm::ivec3 Chunk::GetOrigin() const -{ - return _frame.origin; -} diff --git a/src/Application/Sandbox/World/Chunks/Structure/Chunk.h b/src/Application/Sandbox/World/Chunks/Structure/Chunk.h deleted file mode 100644 index 72e8a899..00000000 --- a/src/Application/Sandbox/World/Chunks/Structure/Chunk.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once -#include - -#include "Application/Sandbox/Camera.h" -#include "ChunkFrame.h" -#include "ChunkBlocks.h" - -/// @class Chunk -/// @brief Represents a single chunk placed in the world -/// @details This class handles managing the generated chunk at the certain position. -class Chunk -{ - ChunkFrame _frame; - ChunkBlocks _blocks; - Camera& _camera; - -public: - /// @brief The constructor. - /// @details The chunk on initialization knows it's position, the structure to render (blocks) - /// and the player position for proper displaying blocks while the player is moving. - /// @param frame - the frame of the chunk. - /// @param blocks - the blocks inside the chunk. - /// @param camera - reference to the camera so that the blocks could be seen. - /// @attention Do **NOT** give the exact origin position You want to have a chunk placed. - /// In the constructor it's implemented to place them respectively to the chunk size. - /// If the defined chunk size is 16 and the origin is (1, 1, 1) the real chunk origin will be (16, 16, 16). - explicit Chunk(const ChunkFrame& frame, ChunkBlocks blocks, Camera& camera); - - /// @brief Draws the chunk in the world. - void Draw() const; - - /// @brief Get the **actual** origin of the chunk. - glm::ivec3 GetOrigin() const; -}; - diff --git a/src/Data/Shaders/Block.vert b/src/Data/Shaders/Block.vert index fc097328..49f91d4f 100644 --- a/src/Data/Shaders/Block.vert +++ b/src/Data/Shaders/Block.vert @@ -4,13 +4,12 @@ layout (location = 0) in vec3 model; layout (location = 1) in vec2 uv; uniform mat4 camera; -uniform mat4 position; out vec2 textureCoordinate; //texture void main() { - gl_Position = camera * position * vec4(model, 1.0); + gl_Position = camera * vec4(model, 1.0); textureCoordinate = uv; //texture } \ No newline at end of file