diff --git a/App/GameLayer.cpp b/App/GameLayer.cpp index 646b56f4a76d6ed0e61160c6011897b583e2e09b..d6b7e6b22f659c35ab652baf1e6a3c5a1717173a 100644 --- a/App/GameLayer.cpp +++ b/App/GameLayer.cpp @@ -2,38 +2,37 @@ /// @author Armin Co /// +#include <thread> +#include <string> +#include <memory> #include <GL/gl3w.h> #include <GLFW/glfw3.h> - #include <imgui.h> - #include <glm/gtc/type_ptr.hpp> #include <glm/gtc/matrix_transform.hpp> - #include <GuiCore/Glyphs.hpp> #include <GuiCore/Input.hpp> #include <GuiCore/Timer.hpp> - +#include <QPong/Utils.hpp> #include "GameLayer.hpp" #include "Log.hpp" -#include <QPong/Utils.hpp> -#include <string> -#include <thread> const std::string vertexShaderPath = "assets/shaders/particle.vert.glsl"; const std::string fragmentShaderPath = "assets/shaders/particle.frag.glsl"; -const QPong::Particle::Properties initialParticleSettings = { +constexpr QPong::Particle::Properties initialParticleSettings = { .size = 512, .position = {0.0, 0.0, 0.0}, .momentum = {0.0, 0.0, 0.0}, .sharpness = 64.0, .startValue = 0.01, - .hbar = 0.000125 + .hbar = 0.000125, + .threads = 8, + .game = true }; -const QPong::Particle::GameOptions initialOptions = { +constexpr QPong::Particle::GameOptions initialOptions = { .potentialsEnabled = true, .absorbtionEnabled = true, .momentumEnabled = false @@ -42,29 +41,36 @@ const QPong::Particle::GameOptions initialOptions = { QPong::GameLayer::GameLayer(int resolution, int threads) :Layer("GameLayer") , m_arraySize{resolution} - , m_propagate{false} , m_leftBat(-0.8, 0.0, Key::W, Key::S) , m_rightBat(0.8, 0.0, Key::Up, Key::Down) + , m_propagate{false} , m_options{initialOptions} , m_properties {initialParticleSettings} , m_speedScale{5.0f} , m_randomMomentum {true} , m_gaming {true} { + srand(time(nullptr)); + m_properties.size = resolution; m_properties.threads = threads; m_memorySize = sizeof(fftw_complex) * m_properties.elements(); - Log::get()->debug("Creating GameLayer"); - - srand(time(NULL)); + constexpr int indicesPerQuad { 6 }; // two triangles m_numberOfQuads = (m_arraySize - 1) * (m_arraySize - 1); - constexpr int indicesPerQuad{6}; // two triangles m_numberOfIndices = m_numberOfQuads * indicesPerQuad; m_staticBorderPotential = new float[m_properties.elements()]; m_dynamicPotential = new float[m_properties.elements()]; - m_particle = std::make_unique<Particle>(m_properties, m_options, m_playerOne, m_playerTwo, m_leftBat, m_rightBat, m_staticBorderPotential, m_dynamicPotential); + m_particle = std::make_unique<Particle>( + m_properties, + m_options, + m_playerOne, + m_playerTwo, + m_leftBat, + m_rightBat, + m_staticBorderPotential, + m_dynamicPotential); } void QPong::GameLayer::onAttach() @@ -76,7 +82,8 @@ void QPong::GameLayer::onAttach() fragmentShaderPath); // static verticie positions - m_particleViewPositions = new float[m_properties.elements() * 3]; + constexpr int pointsPerPosition { 3 }; + m_particleViewPositions = new float[m_properties.elements() * pointsPerPosition]; calculatePointPositions(m_particleViewPositions, m_arraySize); // Vertex array to store all buffers @@ -86,18 +93,18 @@ void QPong::GameLayer::onAttach() // Buffer of all point locations glGenBuffers(1, &m_pointsBuffer); glBindBuffer(GL_ARRAY_BUFFER, m_pointsBuffer); - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 3 * m_properties.elements(), m_particleViewPositions, GL_DYNAMIC_DRAW); + glBufferData(GL_ARRAY_BUFFER, sizeof(float) * pointsPerPosition * m_properties.elements(), m_particleViewPositions, GL_DYNAMIC_DRAW); glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(float) * 3, 0); + glVertexAttribPointer(0, pointsPerPosition, GL_FLOAT, GL_FALSE, sizeof(float) * pointsPerPosition, 0); // Setup indies buffer - uint32_t *indices = new uint32_t[m_numberOfIndices]; - calculateTriangleIndices(indices, m_arraySize); + // uint32_t *indices = new uint32_t[m_numberOfIndices]; + std::unique_ptr<uint32_t[]> indices (new uint32_t[m_numberOfIndices]()); + calculateTriangleIndices(indices.get(), m_arraySize); glGenBuffers(1, &m_indicesBuffer); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_indicesBuffer); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * m_numberOfIndices, indices, GL_STATIC_DRAW); - delete (indices); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(uint32_t) * m_numberOfIndices, indices.get(), GL_STATIC_DRAW); glGenBuffers(1, &m_colorBuffer); glBindBuffer(GL_ARRAY_BUFFER, m_colorBuffer); @@ -135,7 +142,7 @@ void QPong::GameLayer::onDetach() delete (m_staticBorderPotential); } -void QPong::GameLayer::onEvent(GuiCore::Event &event) +void QPong::GameLayer::onEvent([[maybe_unused]] GuiCore::Event &event) { } @@ -146,20 +153,27 @@ void QPong::GameLayer::reset() if (m_randomMomentum) { - int xRand = rand() % 64; - int yRand = rand() % 32; + const int xRand = rand() % 64; + const int yRand = rand() % 32; int positive = rand() % 2; - m_properties.momentum.x = (1.0f - (2.0f * positive)) * (1.0 + (float)xRand / 120.0f); + m_properties.momentum.x = (1.0f - (2.0f * positive)) * (1.0 + static_cast<float>(xRand) / 120.0f); positive = rand() % 2; - m_properties.momentum.y = (1.0f - (2.0f * positive)) * (1.0 + (float)yRand / 120.0f); + m_properties.momentum.y = (1.0f - (2.0f * positive)) * (1.0 + static_cast<float>(yRand) / 120.0f); } m_options.game = m_gaming; - m_particle.reset(new Particle(m_properties, m_options, m_playerOne, m_playerTwo, m_leftBat, m_rightBat, m_staticBorderPotential, m_dynamicPotential)); + m_particle.reset(new Particle( + m_properties, + m_options, + m_playerOne, + m_playerTwo, + m_leftBat, + m_rightBat, + m_staticBorderPotential, + m_dynamicPotential)); m_restart = false; m_gameCounts = true; m_particle->update(0.0); - Log::get()->debug("GameLayer reset done"); } void QPong::GameLayer::onUpdate(GuiCore::Timestep ts) @@ -168,21 +182,23 @@ void QPong::GameLayer::onUpdate(GuiCore::Timestep ts) { reset(); } + if (m_propagate) { m_leftBat.onUpdate(ts); m_rightBat.onUpdate(ts); m_particle->update(ts.getSeconds() * m_speedScale); + constexpr double gameWonThreshold { 35.0 }; if (m_gameCounts) { - if (m_playerOne.getCurrentGameScore() > 35.0) + if (m_playerOne.getCurrentGameScore() > gameWonThreshold) { m_playerOne.gameWon(); m_gameCounts = false; m_propagate = false; } - if (m_playerTwo.getCurrentGameScore() > 35.0) + if (m_playerTwo.getCurrentGameScore() > gameWonThreshold) { m_playerTwo.gameWon(); m_gameCounts = false; @@ -237,7 +253,6 @@ void QPong::GameLayer::onGuiRender() { // GUI settings for the particle ImGui::Begin("Particle Settings"); - ImGui::DragFloat2("Start Position", glm::value_ptr(m_properties.position), 0.01f, -1.0f, 1.0f); // Select initial momentum for particle at restart @@ -249,6 +264,7 @@ void QPong::GameLayer::onGuiRender() { m_properties.sharpness = sharpness; } + // Select hbar, changes apply on the fly. float hbar = m_properties.hbar; if (ImGui::DragFloat("hbar", &hbar, 0.0000001f, 0.0000001f, 1.0f, "%.7f")) @@ -307,6 +323,6 @@ void QPong::GameLayer::onGuiRender() m_options.momentumEnabled = true; m_restart = true; } - ImGui::End(); -} \ No newline at end of file +} + diff --git a/App/MainMenuLayer.cpp b/App/MainMenuLayer.cpp index 83fff45473f2eaa8192ae805dd618531b257443b..0bbcf8e5b94f1b597756d5bdd6a105aaa6e2b8c2 100644 --- a/App/MainMenuLayer.cpp +++ b/App/MainMenuLayer.cpp @@ -3,24 +3,26 @@ /// #include "MainMenuLayer.hpp" - +#include <math.h> #include <imgui.h> +#include <glm/gtc/type_ptr.hpp> #include <GuiCore/Application.hpp> #include "Log.hpp" - #include "GameLayer.hpp" -#include <glm/gtc/type_ptr.hpp> using namespace QPong; MainMenuLayer::MainMenuLayer() - : m_selectedResolution {512} - , m_powOfResolution {9} + : m_powOfResolution {9} + , m_selectedResolution {512} , m_forceIndividualResolution {false} , m_checkboxThreads {true} , m_workerThreads {8} , m_resetOnce {false} + , m_gameLayer {nullptr} , m_gameAttached {false} + , m_fps {0.0} + , m_backgroundColor {0.12f, 0.12f, 0.12f} { } @@ -30,7 +32,6 @@ void MainMenuLayer::onAttach() glDepthFunc(GL_LESS); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - m_backgroundColor = {0.15f, 0.15f, 0.15f}; createNewGame(); } @@ -42,7 +43,7 @@ void MainMenuLayer::onDetach() void MainMenuLayer::createNewGame() { m_resetOnce = false; - if (m_gameAttached) + if (m_gameAttached == true) { GuiCore::Application::get().popLayer(m_gameLayer); m_gameAttached = false; @@ -54,7 +55,8 @@ void MainMenuLayer::createNewGame() void MainMenuLayer::onUpdate(GuiCore::Timestep ts) { - m_fps = 1000.0f / ts.getMilliseconds(); + constexpr float oneSecond_ms { 1000.0f }; + m_fps = oneSecond_ms / ts.getMilliseconds(); glClearColor(m_backgroundColor.r, m_backgroundColor.g, m_backgroundColor.b, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); @@ -64,8 +66,6 @@ void MainMenuLayer::onUpdate(GuiCore::Timestep ts) } } -#include <math.h> - void MainMenuLayer::guiShowFPS() { ImGui::Text("FPS: %3.1f", m_fps); @@ -94,14 +94,15 @@ void MainMenuLayer::guiSelectResolution() } m_powOfResolution = (m_powOfResolution < minPowOfResolution) ? minPowOfResolution : m_powOfResolution; m_powOfResolution = (m_powOfResolution > maxPowOfResolution) ? maxPowOfResolution : m_powOfResolution; - m_selectedResolution = std::pow<int>(2, m_powOfResolution); } else { + constexpr int minResolution { 32 }; constexpr int maxResolution = std::pow<int>(2, maxPowOfResolution); - ImGui::DragInt("Forced Resolution", &m_selectedResolution, 1, 32, maxResolution); + ImGui::DragInt("Forced Resolution", &m_selectedResolution, 1, minResolution, maxResolution); } + ImGui::Checkbox("Force other resolution", &m_forceIndividualResolution); if (ImGui::IsItemHovered()) { @@ -111,15 +112,21 @@ void MainMenuLayer::guiSelectResolution() void MainMenuLayer::guiResetGame() { - if (ImGui::Button("Reset Game")){ m_resetOnce = true; } + if (ImGui::Button("Reset Game")) + { + m_resetOnce = true; + } - if (ImGui::IsItemHovered()) { + if (ImGui::IsItemHovered()) + { ImGui::SetTooltip("Reinitialise Simulation with selected array resolution."); } } void MainMenuLayer::guiNumberOfThreads() { + constexpr int minWorkerThreadCount { 1 }; + constexpr int maxWOrkerThreadCoutn { 32 }; std::stringstream checkbox; checkbox << "Use multiple threads [" << m_workerThreads << "]"; ImGui::Checkbox(checkbox.str().c_str(), &m_checkboxThreads); @@ -134,31 +141,27 @@ void MainMenuLayer::guiNumberOfThreads() { m_workerThreads++; } - m_workerThreads = (m_workerThreads < 1) ? 1 : m_workerThreads; - m_workerThreads = (m_workerThreads > 32) ? 32 : m_workerThreads; + m_workerThreads = (m_workerThreads < minWorkerThreadCount) ? minWorkerThreadCount : m_workerThreads; + m_workerThreads = (m_workerThreads > maxWOrkerThreadCoutn) ? maxWOrkerThreadCoutn : m_workerThreads; } else { - m_workerThreads = 1; + m_workerThreads = minWorkerThreadCount; } } void MainMenuLayer::onGuiRender() { - // Main menu controls and info ImGui::Begin("Main Menu"); - guiShowFPS(); guiSelectResolution(); guiResetGame(); guiNumberOfThreads(); - - ImGui::ColorEdit3("Background Color", glm::value_ptr(m_backgroundColor)); - ImGui::End(); } -void MainMenuLayer::onEvent(GuiCore::Event &event) +void MainMenuLayer::onEvent([[maybe_unused]] GuiCore::Event &event) { } + diff --git a/App/MainMenuLayer.hpp b/App/MainMenuLayer.hpp index 4657b9afe41b9740289074969d6a7edfbe6625d1..f8403c8e8ede727b5989db1ff9b49dbf0f7c67bc 100644 --- a/App/MainMenuLayer.hpp +++ b/App/MainMenuLayer.hpp @@ -34,7 +34,6 @@ private: void guiResetGame(); void guiNumberOfThreads(); - // Resolution int m_powOfResolution; ///< choose only from resolutions with 2^pow int m_selectedResolution; ///< selected res in the gui bool m_forceIndividualResolution; ///< Override resoultion @@ -48,4 +47,4 @@ private: glm::vec3 m_backgroundColor; }; } -#endif \ No newline at end of file +#endif diff --git a/App/Window.cpp b/App/Window.cpp index 5e20adb3de76a10731a4bb297efff1a9f683eadf..fd8cadee923f9d42bcc414f7c482bb9f96206bb9 100644 --- a/App/Window.cpp +++ b/App/Window.cpp @@ -15,6 +15,9 @@ static bool s_GLFW_Initialized = false; static void GLFWErrorCallback(int error, const char *description) { /// @todo add GuiCore::Logger + // + GuiCore::Log::get()->error("{}", error); + GuiCore::Log::get()->error("{}", description); } GuiCore::IWindow* GuiCore::IWindow::create(const WindowProperties &properties) @@ -60,7 +63,7 @@ void Window::setup(const GuiCore::WindowProperties &properties) glfwSetWindowSizeCallback(m_window, [](GLFWwindow * window, int width, int height) { - Data &data = *(Data*)glfwGetWindowUserPointer(window); + Data &data = *(static_cast<Data*>(glfwGetWindowUserPointer(window))); data.width = width; data.height = height; @@ -71,7 +74,7 @@ void Window::setup(const GuiCore::WindowProperties &properties) using namespace GuiCore; glfwSetWindowCloseCallback(m_window, [](GLFWwindow* window) { - Data &data = *(Data*)glfwGetWindowUserPointer(window); + Data &data = *(static_cast<Data*>(glfwGetWindowUserPointer(window))); WindowCloseEvent event; data.eventCallback(event); }); @@ -125,4 +128,4 @@ void Window::setEventCallback(const std::function<void(GuiCore::Event&)> callbac { GuiCore::Log::get()->trace("Window::setEventCallback"); m_data.eventCallback = callback; -} \ No newline at end of file +} diff --git a/Dockerfile b/Dockerfile index ca9f57560d6b0554db09841daa0324704b1fb5e6..24f08cb4fe17b4815754e319a954b4f058c10c15 100644 --- a/Dockerfile +++ b/Dockerfile @@ -22,9 +22,22 @@ RUN apt-get install -y \ # Specify the wokring directory WORKDIR /usr/src/qpong/build +RUN mkdir -p /usr/src/qpong/App && \ + mkdir -p /usr/src/qpong/QPong && \ + mkdir -p /usr/src/qpong/GuiCore && \ + touch /usr/src/qpong/App/CMakeLists.txt && \ + touch /usr/src/qpong/QPong/CMakeLists.txt && \ + touch /usr/src/qpong/GuiCore/CMakeLists.txt +FROM qpongbase as qponglibs +COPY ./libs /usr/src/qpong/libs +COPY ./CMakeLists.txt /usr/src/qpong/ +COPY ./ImGuiSrc /usr/src/qpong/ImGuiSrc +RUN cmake .. && make spdlog ImGuiSrc -FROM qpongbase AS qpongbuild - -COPY . /usr/src/qpong +FROM qponglibs AS qpongbuild +COPY ./App /usr/src/qpong/App +COPY ./QPong /usr/src/qpong/QPong +COPY ./GuiCore /usr/src/qpong/GuiCore RUN cmake .. && make -j2 + diff --git a/GuiCore/ImGuiLayer.cpp b/GuiCore/ImGuiLayer.cpp index 568b96ac91488311bbdec22b1945eeb46daad445..63c044e9957b7ec791c308186ee7fca7570c51fe 100644 --- a/GuiCore/ImGuiLayer.cpp +++ b/GuiCore/ImGuiLayer.cpp @@ -59,7 +59,9 @@ void ImGuiLayer::end() { ImGuiIO& io = ImGui::GetIO(); Application& app = Application::get(); - io.DisplaySize = ImVec2((float)app.getWindow().getWidth(), (float)app.getWindow().getHeight()); + io.DisplaySize = ImVec2( + static_cast<float>(app.getWindow().getWidth()), + static_cast<float>(app.getWindow().getHeight())); ImGui::Render(); ImGui_ImplOpenGL3_RenderDrawData(ImGui::GetDrawData()); @@ -70,7 +72,7 @@ void ImGuiLayer::onEvent(Event &event) } -bool ImGuiLayer::onMouseButtonPressed(Event &event) +bool ImGuiLayer::onMouseButtonPressed([[maybe_unused]] Event &event) { return false; } diff --git a/GuiCore/Layer.cpp b/GuiCore/Layer.cpp index 152287f27ad277e5c9bde934bc0f923589e90f75..2aac3005b98e9f4dc3d12ffb0c55c23d827202b9 100644 --- a/GuiCore/Layer.cpp +++ b/GuiCore/Layer.cpp @@ -15,6 +15,14 @@ namespace GuiCore { } + void Layer::onUpdate([[maybe_unused]] Timestep ts) + { + } + + void Layer::onEvent([[maybe_unused]] Event &event) + { + } + const std::string &Layer::getName() const { return m_debugName; diff --git a/GuiCore/Layer.hpp b/GuiCore/Layer.hpp index 73687a1cb8568c263caed48cb8b99a03066b7809..54d165d5876a5bec898491f18095cd12f1447214 100644 --- a/GuiCore/Layer.hpp +++ b/GuiCore/Layer.hpp @@ -20,16 +20,16 @@ namespace GuiCore virtual void onAttach() {} virtual void onDetach() {} - virtual void onUpdate(Timestep ts) {} + virtual void onUpdate(Timestep ts); virtual void onGuiRender() {} - virtual void onEvent(Event &event){} + virtual void onEvent(Event &event); const std::string &getName() const; protected: std::string m_debugName; }; - } -#endif \ No newline at end of file +#endif + diff --git a/QPong/Particle.cpp b/QPong/Particle.cpp index 6b0dc32c34a383417cf04e1b885f28ccd5b97e19..ae1f9ee40faa675488c99e15941679ab7c237bde 100644 --- a/QPong/Particle.cpp +++ b/QPong/Particle.cpp @@ -332,4 +332,4 @@ void Particle::update(double dt) double Particle::getTimeFFT() const { return m_timeFFT; -} \ No newline at end of file +}