Skip to content
Snippets Groups Projects
Commit c3028183 authored by Armin Co's avatar Armin Co
Browse files

Game update

- random initial momentum
- if momentum is diabled show particle in the middle
- removed threads from rendering
- precalculation for every array index
- logging is disabled by default
parent 9be59975
No related branches found
No related tags found
No related merge requests found
......@@ -5,6 +5,11 @@ set(CMAKE_CXX_STANDARD 20)
set(CMAKE_BUILD_TYPE Release)
set(CMAKE_CXX_FLAGS "-O3")
option(LOG_DEBUG_INFO "Enable logging t console" OFF)
if(LOG_DEBUG_INFO)
add_compile_definitions(ENABLE_LOG_DEBUG_INFO)
endif(LOG_DEBUG_INFO)
# Check for PkgConfig
find_package(PkgConfig REQUIRED)
......
......@@ -7,6 +7,7 @@ add_library(GuiCore
Layer.cpp
LayerStack.cpp
Log.cpp
Timer.cpp
Timestep.cpp
Glyphs.cpp
)
......
......@@ -44,7 +44,7 @@ void GuiCore::Glyphs::setup()
}
FT_Face face;
if (FT_New_Face(ft, "assets/arial.ttf", 0, &face))
if (FT_New_Face(ft, "assets/Font.ttf", 0, &face))
{
GuiCore::Log::get()->error("ERROR::FREETYPE: Failed to load font");
}
......
......@@ -18,7 +18,7 @@ namespace GuiCore
uint32_t width;
uint32_t height;
WindowProperties(const std::string &t = "Application", uint32_t w = 1280, uint32_t h = 720)
WindowProperties(const std::string &t = "Application", uint32_t w = 1920, uint32_t h = 1080)
: title{t}
, width{w}
, height{h}
......
......@@ -37,7 +37,7 @@ void ImGuiLayer::onAttach()
GLFWwindow *window = static_cast<GLFWwindow*>(app.getWindow().getNativeWindow());
ImGui_ImplGlfw_InitForOpenGL(window, true);
ImGui_ImplOpenGL3_Init("#version 410");
ImGui_ImplOpenGL3_Init("#version 330");
}
......
......@@ -14,7 +14,11 @@ namespace GuiCore
{
spdlog::set_pattern("%^[%T] %n: %v%$");
s_logger = spdlog::stdout_color_mt("GuiCore");
#ifdef ENABLE_LOG_DEBUG_INFO
s_logger->set_level(spdlog::level::trace);
#else
s_logger->set_level(spdlog::level::info);
#endif
}
std::shared_ptr<spdlog::logger> Log::get()
......
......@@ -2,7 +2,6 @@ add_executable( QPongApp
GameLayer.cpp
Log.cpp
MainMenuLayer.cpp
PlayingLayer.cpp
QPongApp.cpp
Window.cpp
)
......
......@@ -13,6 +13,7 @@
#include <GuiCore/Log.hpp>
#include <GuiCore/Input.hpp>
#include <GuiCore/Glyphs.hpp>
#include <GuiCore/Timer.hpp>
#include "GameLayer.hpp"
#include "Log.hpp"
......@@ -109,13 +110,16 @@ double QPong::GameLayer::Bat::getX() const
QPong::GameLayer::GameLayer(QPong::GameLayer::Properties props)
:Layer("GameLayer")
, m_vertexShaderPath{"assets/shaders/test.vert.glsl"}
, m_fragmentShaderPath{"assets/shaders/test.frag.glsl"}
, m_vertexShaderPath{"assets/shaders/particle.vert.glsl"}
, m_fragmentShaderPath{"assets/shaders/particle.frag.glsl"}
, m_arraySize{props.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_speedScale{3.0f}
, m_randomMomentum {true}
{
srand (time(NULL));
m_arrayElements = m_arraySize * m_arraySize;
m_numberOfQuads = (m_arraySize - 1) * (m_arraySize - 1);
m_numberOfIndices = m_numberOfQuads * 6;
......@@ -129,35 +133,41 @@ QPong::GameLayer::GameLayer(QPong::GameLayer::Properties props)
m_initialParticleProperties.pointUnsharpness = 60.0;
m_initialParticleProperties.startValue = 0.01;
m_initialParticleProperties.hbar = 0.0002;
}
void QPong::GameLayer::calculatePointPositions(float *positions)
{
float xMin {-3.0f};
float xMax {0.0f};
float yMin {-1.5f};
float yMax {1.5f};
constexpr float size{3.175f};
constexpr float xOffset{0.0f};
constexpr float yOffset{-0.175f};
constexpr float width{size};
constexpr float xMin{-width / 2.0};
constexpr float xMax{width / 2.0};
constexpr float height{width};
constexpr float yMin{-height / 2.0};
constexpr float yMax{(height / 2.0)};
float dx = (xMax - xMin) / (m_arraySize - 1.0f); // "spacing"
float dy = (yMax - yMin) / (m_arraySize - 1.0f);
{
uint32_t i {0}; // array index
for (int yId{0}; yId < m_arraySize; ++yId)
{
for (int xId{0}; xId < m_arraySize; ++xId)
{
positions[i++] = xMin + (static_cast<float>(xId) * dx); // x-Pos
positions[i++] = yMax - (static_cast<float>(yId) * dy); // y-Pos
positions[i++] = xMin + xOffset + (static_cast<float>(xId) * dx); // x-Pos
positions[i++] = yMax + yOffset - (static_cast<float>(yId) * dy); // y-Pos
positions[i++] = 0.0f; // z-Pos
}
}
}
}
void QPong::GameLayer::calculateMomentumViewPositions(float *positions)
{
float xMin {2.2f};
float xMax {0.2f};
constexpr float xOffset {1.5f}; // has to be the same as in the shader
float xMin {2.2f + xOffset};
float xMax {0.2f + xOffset};
float yMin {-1.0f};
float yMax {1.0f};
float dx = (xMax - xMin) / (m_arraySize - 1.0f); // "spacing"
......@@ -199,7 +209,7 @@ void QPong::GameLayer::calculateBorderPotential(float *potential)
double y {0.0};
for (int i {0}; i < m_arrayElements; ++i)
{
y = yAtIndex(i);
y = m_yAt[i];
float pot = pow2(y) * pow2(y) * pow2(y) * pow2(y) * pow2(y) * pow2(y) * pow2(y) * 0.02;
potential[i] = pot;
}
......@@ -259,8 +269,8 @@ void QPong::GameLayer::initialiseParticleMomentum()
double x{0.0};
for (auto i {0}; i < m_arrayElements; ++i)
{
x = xAtIndex(i);
y = yAtIndex(i);
x = m_xAt[i];
y = m_yAt[i];
m_psi[i] = A0 * exp( ci / hbar * ( x * px0 + y * py0) - lambda * (pow2(x-x0) + pow2(y-y0)));
sum += pow2(std::real(m_psi[i])) + pow2(std::imag(m_psi[i]));
}
......@@ -294,8 +304,8 @@ void QPong::GameLayer::applyPotentials(int indexBegin, int indexEnd, double dt)
if (m_potentialsEnabled)
{
potSum = 0.0;
x = xAtIndex(i);
y = yAtIndex(i);
x = m_xAt[i];
y = m_yAt[i];
if (m_removeParticleEnabled)
{
if (x < m_leftBat.getX())
......@@ -334,8 +344,8 @@ void QPong::GameLayer::moveForward(int indexBegin, int indexEnd, double dt)
const double N = 1.0 / static_cast<double>(m_arrayElements);
for (int i{indexBegin}; i<indexEnd; ++i)
{
px = pxAtIndex(i);
py = pyAtIndex(i);
px = m_pxAt[i];
py = m_pyAt[i];
double E = (pow2(px) + pow2(py)) / (2.0 * m);
m_psi[i] *= exp(-ci * dt / hbar * E) * N;
}
......@@ -374,52 +384,40 @@ void QPong::GameLayer::updateMomentumView(int indexBegin, int indexEnd)
void QPong::GameLayer::propagateStep(double dt)
{
std::vector<std::thread> workers;
workers.reserve(m_renderingThreadsNumber);
for (auto workerId{0}; workerId < m_renderingThreadsNumber; ++workerId)
{
int begin = workerId * (m_arrayElements / m_renderingThreadsNumber);
int end = (workerId + 1) * (m_arrayElements / m_renderingThreadsNumber);
workers.emplace_back(&QPong::GameLayer::applyPotentials, this, begin, end, dt);
}
for (auto &worker : workers)
applyPotentials(0, m_arrayElements, dt);
{
worker.join();
}
GuiCore::Timer t("fftw_execute(forward)");
fftw_execute(m_planForward);
workers.clear();
for (auto workerId{0}; workerId < m_renderingThreadsNumber; ++workerId)
{
int begin = workerId * (m_arrayElements / m_renderingThreadsNumber);
int end = (workerId + 1) * (m_arrayElements / m_renderingThreadsNumber);
workers.emplace_back(&QPong::GameLayer::moveForward, this, begin, end, dt);
}
for (auto &worker : workers)
{
worker.join();
}
if (m_renderMomentum)
{
workers.clear();
for (auto workerId{0}; workerId < m_renderingThreadsNumber; ++workerId)
{
int begin = workerId * (m_arrayElements / m_renderingThreadsNumber);
int end = (workerId + 1) * (m_arrayElements / m_renderingThreadsNumber);
workers.emplace_back(&QPong::GameLayer::updateMomentumView, this, begin, end);
}
for (auto &worker : workers)
{
worker.join();
}
}
moveForward(0, m_arrayElements, dt);
updateMomentumView(0, m_arrayElements);
{
GuiCore::Timer t("fftw_execute(backwards");
fftw_execute(m_planBackwards);
}
}
void QPong::GameLayer::onAttach()
{
GuiCore::Timer timer("GameLayer::onAttach()");
GuiCore::Glyphs::setup();
m_xAt = new double[m_arrayElements];
m_yAt = new double[m_arrayElements];
m_pxAt = new double[m_arrayElements];
m_pyAt = new double[m_arrayElements];
for (int i {0}; i < m_arrayElements; ++i)
{
m_xAt[i] = xAtIndex(i);
m_yAt[i] = yAtIndex(i);
m_pxAt[i] = pxAtIndex(i);
m_pyAt[i] = pyAtIndex(i);
}
m_renderMomentum = false;
m_removeParticleEnabled = true;
m_potentialsEnabled = true;
......@@ -484,12 +482,13 @@ void QPong::GameLayer::onAttach()
m_viewProjectionPosition = glm::ortho(-3.2f, 3.2f, -1.8f, 1.8f, -1.0f, 1.0f);
m_viewProjectionLocation = glGetUniformLocation(m_shader->getRendererID(), "u_viewProjection");
m_showPotentialsLocation = glGetUniformLocation(m_shader->getRendererID(), "u_showPotential");
m_isMomentumEnabled = glGetUniformLocation(m_shader->getRendererID(), "u_isMomentumEnabled");
fftw_init_threads();
m_planForward = fftw_plan_dft_2d(m_arraySize, m_arraySize, (fftw_complex *)m_psi, (fftw_complex *)m_psi, FFTW_FORWARD, FFTW_MEASURE);
m_planBackwards = fftw_plan_dft_2d(m_arraySize, m_arraySize, (fftw_complex *)m_psi, (fftw_complex *)m_psi, FFTW_BACKWARD, FFTW_MEASURE);
initialiseParticleMomentum();
reset();
}
void QPong::GameLayer::onDetach()
......@@ -502,6 +501,10 @@ void QPong::GameLayer::onDetach()
delete(m_momentum);
delete(m_dynamicPotential);
delete(m_staticBorderPotential);
delete(m_xAt);
delete(m_yAt);
delete(m_pxAt);
delete(m_pyAt);
}
void QPong::GameLayer::onEvent(GuiCore::Event& event)
......@@ -510,6 +513,15 @@ void QPong::GameLayer::onEvent(GuiCore::Event& event)
void QPong::GameLayer::reset()
{
if (m_randomMomentum)
{
int xRand = rand() % 100;
int yRand = rand() % 100;
int positive = rand() % 2;
m_initialParticleProperties.momentum.x = (1.0f - (2.0f * positive)) * (1.0 + (float)xRand / 120.0f);
positive = rand() % 2;
m_initialParticleProperties.momentum.y = (1.0f - (2.0f * positive)) * (1.0 + (float)yRand / 120.0f);
}
initialiseParticleMomentum();
m_restart = false;
m_gameCounts = true;
......@@ -520,7 +532,6 @@ void QPong::GameLayer::reset()
void QPong::GameLayer::onUpdate(GuiCore::Timestep ts)
{
GuiCore::Glyphs::renderText("QPong", -0.31f, 1.59f, 0.005f, glm::vec3(0.5f, 0.9f, 0.9f));
if (m_restart)
{
reset();
......@@ -559,7 +570,8 @@ void QPong::GameLayer::onUpdate(GuiCore::Timestep ts)
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(float) * m_arrayElements, m_dynamicPotential);
glUseProgram(m_shader->getRendererID());
glUniform1i(m_showPotentialsLocation, 1);
glUniform1i(m_showPotentialsLocation, static_cast<int>(m_potentialsEnabled));
glUniform1i(m_isMomentumEnabled, static_cast<int>(m_renderMomentum));
glUniformMatrix4fv(m_viewProjectionLocation, 1, GL_FALSE, &m_viewProjectionPosition[0][0]);
glBindVertexArray(m_vertexArray);
glDrawElements(GL_TRIANGLES, m_numberOfIndices, GL_UNSIGNED_INT, nullptr);
......@@ -581,7 +593,7 @@ void QPong::GameLayer::onUpdate(GuiCore::Timestep ts)
std::stringstream totalScore;
totalScore << m_playerOne.totalScore << " : " << m_playerTwo.totalScore;
GuiCore::Glyphs::renderText(totalScore.str(), -1.82f, 1.52f, 0.0075f, {1.0, 1.0, 1.0});
GuiCore::Glyphs::renderText(totalScore.str(), -0.32f, 1.45f, 0.0075f, {1.0, 1.0, 1.0});
}
void QPong::GameLayer::onGuiRender()
......@@ -591,6 +603,7 @@ void QPong::GameLayer::onGuiRender()
// Select initial momentum for particle at restart
ImGui::DragFloat2("Momentum [x,y]", glm::value_ptr(m_initialParticleProperties.momentum), 0.01f, -3.0f, 3.0f);
ImGui::Checkbox("Random Momentum", &m_randomMomentum);
float pointUnsharpness = m_initialParticleProperties.pointUnsharpness;
if (ImGui::DragFloat("Sharpness", &pointUnsharpness, 1.0f, 5.0f, 1000.0f))
......
......@@ -109,9 +109,15 @@ private:
float *m_staticBorderPotential;
float *m_dynamicPotential;
double *m_xAt;
double *m_yAt;
double *m_pxAt;
double *m_pyAt;
glm::mat4 m_viewProjectionPosition;
int m_viewProjectionLocation;
GLuint m_showPotentialsLocation;
GLuint m_isMomentumEnabled;
ParticleProps m_initialParticleProperties;
double m_particleAbsouluteSumStart;
......@@ -127,6 +133,7 @@ private:
bool m_restart;
bool m_propagate;
bool m_renderMomentum;
bool m_randomMomentum;
bool m_removeParticleEnabled;
bool m_potentialsEnabled;
int m_renderingThreadsNumber {8};
......
......@@ -14,7 +14,7 @@ void Log::setup()
{
spdlog::set_pattern("%^[%T] %n: %v%$");
s_logger = spdlog::stdout_color_mt("QPong");
s_logger->set_level(spdlog::level::trace);
s_logger->set_level(spdlog::level::info);
}
std::shared_ptr<spdlog::logger> Log::get()
......
......@@ -14,6 +14,8 @@ using namespace QPong;
MainMenuLayer::MainMenuLayer()
: m_selectedResolution {512}
, m_powOfResolution {9}
, m_forceIndividualResolution {false}
, m_resetOnce {false}
, m_gameAttached {false}
{
......@@ -49,7 +51,7 @@ void MainMenuLayer::createNewGame()
void MainMenuLayer::onUpdate(GuiCore::Timestep ts)
{
m_fps = 1000.0 / ts.getMilliseconds();
m_fps = 1000.0f / ts.getMilliseconds();
glClearColor(m_backgroundColor.r, m_backgroundColor.g, m_backgroundColor.b, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
......@@ -57,19 +59,74 @@ void MainMenuLayer::onUpdate(GuiCore::Timestep ts)
{
createNewGame();
}
}
void MainMenuLayer::onGuiRender()
#include <math.h>
void MainMenuLayer::guiShowFPS()
{
ImGui::Begin("Main Menu");
ImGui::Text("FPS: %3.1f", m_fps);
ImGui::DragInt("Resolution", &m_selectedResolution, 16, 16, 1088);
ImGui::ColorEdit3("Background Color", glm::value_ptr(m_backgroundColor));
if (ImGui::Button("Reset")){ m_resetOnce = true; }
}
void MainMenuLayer::guiSelectResolution()
{
constexpr int minPowOfResolution {4};
constexpr int maxPowOfResolution {12};
if (!m_forceIndividualResolution)
{
std::stringstream ssRes;
ssRes << "Array resoultion: ";
ssRes << m_selectedResolution << "x" << m_selectedResolution << std::endl;
ImGui::Text(ssRes.str().c_str());
if (ImGui::Button("Lower Resolution"))
{
m_powOfResolution--;
}
ImGui::SameLine();
if (ImGui::Button("Higher Resolution"))
{
m_powOfResolution++;
}
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 maxResolution = std::pow<int>(2, maxPowOfResolution);
ImGui::DragInt("Forced Resolution", &m_selectedResolution, 1, 32, maxResolution);
}
ImGui::Checkbox("Force other resolution", &m_forceIndividualResolution);
if (ImGui::IsItemHovered())
{
ImGui::SetTooltip("Warning!\nSelecting other resoultions can decrease the performance significantly.");
}
}
void MainMenuLayer::guiResetGame()
{
if (ImGui::Button("Reset Game")){ m_resetOnce = true; }
if (ImGui::IsItemHovered()) {
ImGui::SetTooltip("Reinitialise Simulation with selected array resolution.");
}
}
void MainMenuLayer::onGuiRender()
{
// Main menu controls and info
ImGui::Begin("Main Menu");
guiShowFPS();
guiSelectResolution();
guiResetGame();
ImGui::ColorEdit3("Background Color", glm::value_ptr(m_backgroundColor));
ImGui::End();
}
......
......@@ -29,7 +29,15 @@ public:
private:
void createNewGame();
void guiShowFPS();
void guiSelectResolution();
void guiResetGame();
// Resolution
int m_powOfResolution; ///< choose only from resolutions with 2^pow
int m_selectedResolution; ///< selected res in the gui
bool m_forceIndividualResolution; ///< Override resoultion
bool m_resetOnce; ///< restart simulation if set
std::shared_ptr<GuiCore::Layer> m_gameLayer; ///< holds ref to the game
bool m_gameAttached;
......
/// @file PlayingLayer.cpp
/// @author Armin Co
///
#include "PlayingLayer.hpp"
#include <imgui/imgui.h>
#include <GuiCore/Input.hpp>
#include "Log.hpp"
using namespace QPong;
PlayingLayer::PlayingLayer()
{
}
void PlayingLayer::onAttach()
{
}
void PlayingLayer::onEvent(GuiCore::Event &event)
{
}
void PlayingLayer::onUpdate(GuiCore::Timestep ts)
{
if (GuiCore::Input::isKeyPressed(Key::Right)) Log::get()->debug("Key [Right]");
if (GuiCore::Input::isKeyPressed(Key::Left)) Log::get()->debug("Key [Left]");
if (GuiCore::Input::isKeyPressed(Key::Down)) Log::get()->debug("Key Down]");
if (GuiCore::Input::isKeyPressed(Key::Up)) Log::get()->debug("Key [Up]");
}
void PlayingLayer::onGuiRender()
{
ImGui::Begin("PlayingLayer");
ImGui::Text("Test");
ImGui::End();
}
void PlayingLayer::onDetach()
{
}
/// @file PlayingLayer.hpp
/// @authro _Armin Co
///
#ifndef QPONG_PLAYING_LAYER_HPP
#define QPONG_PLAYING_LAYER_HPP
#include <GuiCore/Layer.hpp>
namespace QPong
{
class PlayingLayer : public GuiCore::Layer
{
public:
PlayingLayer();
virtual ~PlayingLayer(){};
virtual void onAttach() override;
virtual void onDetach() override;
virtual void onUpdate(GuiCore::Timestep ts) override;
virtual void onGuiRender() override;
virtual void onEvent(GuiCore::Event &event) override;
private:
bool m_startNow;
struct Player
{
int totalScore;
};
};
}
#endif
\ No newline at end of file
......@@ -8,7 +8,6 @@
#include "MainMenuLayer.hpp"
#include "GameLayer.hpp"
#include "PlayingLayer.hpp"
#include "Log.hpp"
class App : public GuiCore::Application
{
......@@ -25,7 +24,7 @@ int main()
{
std::unique_ptr<App> app = std::make_unique<App>();
QPong::Log::get()->info("Starting App!");
QPong::Log::get()->info("Have fun!");
app->run();
return 0;
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment