diff --git a/AimGL/.gitignore b/AimGL/.gitignore index 8a628d1..dadc1de 100644 --- a/AimGL/.gitignore +++ b/AimGL/.gitignore @@ -1,2 +1,3 @@ out/ -.vshistory/ \ No newline at end of file +.vshistory/ +CMakeSettings.json \ No newline at end of file diff --git a/AimGL/resources/Shaders/Graphics/InfiniteGridFloor.fs b/AimGL/resources/Shaders/Graphics/InfiniteGridFloor.fs new file mode 100644 index 0000000..d5b5743 --- /dev/null +++ b/AimGL/resources/Shaders/Graphics/InfiniteGridFloor.fs @@ -0,0 +1,48 @@ +#version 330 core +// THANK YOU https://asliceofrendering.com/scene%20helper/2020/01/05/InfiniteGrid/!!! + +out vec4 FragColor; + +float near = 0.01f; +float far = 20.f; + +in vec3 nearPoint; +in vec3 farPoint; +in mat4 fragView; +in mat4 fragProjection; + +vec4 grid(vec3 fragPos3D, float scale) { + vec2 coord = fragPos3D.xz * scale; + vec2 derivative = fwidth(coord); + vec2 grid = abs(fract(coord - 0.5) - 0.5) / derivative; + float line = min(grid.x, grid.y); + float minimumz = min(derivative.y, 1); + float minimumx = min(derivative.x, 1); + vec4 color = vec4(0.3, 0.3, 0.3, 0.0 + min(line, 1.0)); + return color; +} + +float computeDepth(vec3 position) { + vec4 clip_space_position = fragProjection * fragView * vec4 (position.xyz, 1.0); + return 0.5 + 0.5 * (clip_space_position.z / clip_space_position.w); +} + +float computeLinearDepth(vec3 pos) { + vec4 clip_space_pos = fragProjection * fragView * vec4(pos.xyz, 1.0); + float clip_space_depth = (clip_space_pos.z / clip_space_pos.w) * 2.0 - 1.0; // put back between -1 and 1 + float linearDepth = (2.0 * near * far) / (far + near - clip_space_depth * (far - near)); // get linear value between 0.01 and 100 + return linearDepth / far; // normalize +} + +void main() +{ + float t = -nearPoint.y / (farPoint.y - nearPoint.y); + vec3 fragPos3D = nearPoint + t * (farPoint - nearPoint); + gl_FragDepth = computeDepth(fragPos3D); + + float linearDepth = computeLinearDepth(fragPos3D); + float fading = max(0, (0.5 - linearDepth)); + + FragColor = (grid(fragPos3D, 10) + grid(fragPos3D, 1))* float(t > 0); // adding multiple resolution for the grid + FragColor.a *= fading; +} \ No newline at end of file diff --git a/AimGL/resources/Shaders/Graphics/InfiniteGridFloor.vs b/AimGL/resources/Shaders/Graphics/InfiniteGridFloor.vs new file mode 100644 index 0000000..849cc0f --- /dev/null +++ b/AimGL/resources/Shaders/Graphics/InfiniteGridFloor.vs @@ -0,0 +1,32 @@ +#version 330 +// THANK YOU https://asliceofrendering.com/scene%20helper/2020/01/05/InfiniteGrid/!!! + +uniform mat4 view; +uniform mat4 projection; + +out vec3 nearPoint; +out vec3 farPoint; +out mat4 fragView; +out mat4 fragProjection; + +vec3 UnprojectPoint(float x, float y, float z, mat4 view, mat4 projection) { + mat4 viewInv = inverse(view); + mat4 projInv = inverse(projection); + vec4 unprojectedPoint = viewInv * projInv * vec4(x, y, z, 1.0); + return unprojectedPoint.xyz / unprojectedPoint.w; +} + + +vec3 gridPlane[6] = vec3[]( + vec3(1, 1, 0), vec3(-1, -1, 0), vec3(-1, 1, 0), + vec3(-1, -1, 0), vec3(1, 1, 0), vec3(1, -1, 0) +); + +void main() { + vec3 p = gridPlane[gl_VertexID].xyz; + nearPoint = UnprojectPoint(p.x, p.y, 0.0, view, projection).xyz; // unprojecting on the near plane + farPoint = UnprojectPoint(p.x, p.y, 1.0, view, projection).xyz; // unprojecting on the far plane + gl_Position = vec4(p, 1.0); // using directly the clipped coordinates + fragView = view; + fragProjection = projection; +} \ No newline at end of file diff --git a/AimGL/resources/Shaders/Graphics/Rectangle2D.fs b/AimGL/resources/Shaders/Graphics/Rectangle2D.fs new file mode 100644 index 0000000..efc9592 --- /dev/null +++ b/AimGL/resources/Shaders/Graphics/Rectangle2D.fs @@ -0,0 +1,12 @@ +#version 330 core + +out vec4 FragColor; + +uniform vec4 color = vec4(1,0,0, 1.f); + +void main() +{ + FragColor = color; + if(FragColor.a == 0.0) + discard; +} \ No newline at end of file diff --git a/AimGL/resources/Shaders/Graphics/Rectangle2D.vs b/AimGL/resources/Shaders/Graphics/Rectangle2D.vs new file mode 100644 index 0000000..3bd8dbb --- /dev/null +++ b/AimGL/resources/Shaders/Graphics/Rectangle2D.vs @@ -0,0 +1,13 @@ +#version 330 core + +layout(location = 0) in vec2 position; // Vertex position + +uniform mat4 model; +uniform mat4 projection = mat4(1.0); // For 2D it is identity +uniform mat4 windowOrthoProjection; + +void main() +{ + mat4 mvp = windowOrthoProjection * model; + gl_Position = mvp * vec4(position, 0.0, 1.0); +} \ No newline at end of file diff --git a/AimGL/resources/Shaders/Graphics/Sprite.fs b/AimGL/resources/Shaders/Graphics/Sprite.fs index 4804d00..b4bbfaa 100644 --- a/AimGL/resources/Shaders/Graphics/Sprite.fs +++ b/AimGL/resources/Shaders/Graphics/Sprite.fs @@ -4,7 +4,7 @@ in vec2 TexCoords; out vec4 color; uniform sampler2D spriteTexture; -uniform float opacity = 0.f; +uniform float opacity = 1.f; void main() { diff --git a/AimGL/resources/Shaders/Graphics/Sprite3D.fs b/AimGL/resources/Shaders/Graphics/Sprite3D.fs new file mode 100644 index 0000000..b4bbfaa --- /dev/null +++ b/AimGL/resources/Shaders/Graphics/Sprite3D.fs @@ -0,0 +1,15 @@ +#version 330 core + +in vec2 TexCoords; +out vec4 color; + +uniform sampler2D spriteTexture; +uniform float opacity = 1.f; + +void main() +{ + color = texture(spriteTexture, TexCoords); + color.a = min(color.a, opacity); + if(color.a == 0.0) + discard; +} \ No newline at end of file diff --git a/AimGL/resources/Shaders/Graphics/Sprite3D.vs b/AimGL/resources/Shaders/Graphics/Sprite3D.vs new file mode 100644 index 0000000..82a0860 --- /dev/null +++ b/AimGL/resources/Shaders/Graphics/Sprite3D.vs @@ -0,0 +1,17 @@ +#version 330 core + +layout(location = 0) in vec3 position; // Vertex position +layout(location = 1) in vec2 texCoords; // Texture coordinates + +out vec2 TexCoords; + +uniform mat4 model; +uniform mat4 view; +uniform mat4 projection; + +void main() +{ + TexCoords = texCoords; + mat4 mvp = projection * view * model; + gl_Position = mvp * vec4(position, 1.0); +} \ No newline at end of file diff --git a/AimGL/resources/Textures/logo_background.png b/AimGL/resources/Textures/logo_background.png new file mode 100644 index 0000000..613115a Binary files /dev/null and b/AimGL/resources/Textures/logo_background.png differ diff --git a/AimGL/src/CMakeLists_Sources.txt b/AimGL/src/CMakeLists_Sources.txt index c28e5a4..5407165 100644 --- a/AimGL/src/CMakeLists_Sources.txt +++ b/AimGL/src/CMakeLists_Sources.txt @@ -12,8 +12,13 @@ set(PROJECT_SOURCES Renderer3D/OpenglUtils.cpp Renderer3D/Texture.cpp Renderer3D/Sprite2D.cpp + Renderer3D/Sprite3D.cpp + Renderer3D/Rectangle2D.cpp States/State.cpp States/StateStack.cpp States/CustomStates/LogoState.cpp States/CustomStates/ExitGameState.cpp + States/CustomStates/GameState.cpp + World/Camera.cpp + Utils/Mouse.cpp ) \ No newline at end of file diff --git a/AimGL/src/Game.cpp b/AimGL/src/Game.cpp index 4f1667c..2e2e99d 100644 --- a/AimGL/src/Game.cpp +++ b/AimGL/src/Game.cpp @@ -1,8 +1,10 @@ #include "Game.h" #include "States/CustomStates/ExitGameState.h" #include "States/CustomStates/LogoState.h" +#include "States/CustomStates/GameState.h" #include "constants.h" #include "pch.h" +#include "Utils/Mouse.h" constexpr int FRAMES_PER_SECOND = 120; @@ -60,15 +62,17 @@ Game::Game() throw std::runtime_error("Failed to initialize GLEW"); } + glEnable(GL_DEPTH_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // Setup all application-flow states mAppStack.saveState(State_ID::LogoState, *mGameWindow); mAppStack.saveState(State_ID::ExitGameState); + mAppStack.saveState(State_ID::GameState, *mGameWindow); // Initial state of the statestack is TitleState - mAppStack.push(State_ID::LogoState); + mAppStack.push(State_ID::GameState); } void Game::run() @@ -206,6 +210,7 @@ void Game::update(const sf::Time& deltaTime) { MTR_SCOPE("Game", "Game::update"); auto deltaTimeInSeconds = deltaTime.asSeconds(); + Mouse::update(deltaTimeInSeconds, *mGameWindow); updateImGui(deltaTime); diff --git a/AimGL/src/Renderer3D/Rectangle2D.cpp b/AimGL/src/Renderer3D/Rectangle2D.cpp new file mode 100644 index 0000000..ff4c450 --- /dev/null +++ b/AimGL/src/Renderer3D/Rectangle2D.cpp @@ -0,0 +1,129 @@ +#include "Rectangle2D.h" +#include "pch.h" + +Rectangle2D::Rectangle2D(const glm::vec2 size, const glm::vec4& color) + : mShader{{ShaderType::VertexShader, "resources/Shaders/Graphics/Rectangle2D.vs"}, + {ShaderType::FragmentShader, "resources/Shaders/Graphics/Rectangle2D.fs"}} + , mColor(color) + , mPosition(0.0f) + , mRotation(0.f) + , mDimensions(size) +{ + + initializeBuffers(); + setPosition({0.f, 0.f}, Origin::Center); + + updateColor(); +} + +void Rectangle2D::initializeBuffers() +{ + float vertices[] = { + // positions + 1.f, 1.f, // top right + 1.f, -1.f,// bottom right + -1.f, -1.f,// bottom left + -1.f, 1.f // top left + }; + + unsigned int indices[] = { + 0, 1, 3,// first Triangle + 1, 2, 3 // second Triangle + }; + + mVBO.setBuffer(vertices, sizeof(vertices)); + mEBO.setBuffer(indices, sizeof(indices)); + + mVAO.bind(); + mVBO.bind(); + mBufferLayout.push(2); + mVAO.setBuffer(mVBO, mBufferLayout); + mVAO.unbind(); +} + +void Rectangle2D::draw(const Renderer3D& target) const +{ + target.draw(mVAO, mEBO, mShader); +} + +void Rectangle2D::updateColor() +{ + mShader.bind(); + mShader.setUniform("color", mColor); + mShader.unbind(); +} + +void Rectangle2D::updateModel() +{ + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, glm::vec3(mPosition)); + + // Negative mRotation makes it rotate clockwise for positive angles + model = glm::rotate(model, glm::radians(-mRotation), glm::vec3(0.0f, 0.0f, 1.0f)); + + // Dividing dimensions by two is needed as vertices are from -1 to 1 + model = glm::scale(model, glm::vec3(mDimensions.x / 2.f, mDimensions.y / 2.f, 1.0f)); + mShader.bind(); + mShader.setUniform("model", model); + mShader.unbind(); +} + +void Rectangle2D::setPosition(const glm::vec2& newPosition, Origin origin) +{ + switch (origin) + { + case Origin::Center: mPosition = glm::vec3(newPosition, 0.f); break; + case Origin::LeftBottom: + mPosition = glm::vec3(newPosition, 0.f); + mPosition += glm::vec3{mDimensions.x / 2.f, mDimensions.y / 2.f, 0.f}; + break; + } + updateModel(); +} + +void Rectangle2D::setColor(glm::vec4 color) +{ + mColor = color; + updateColor(); +} + +void Rectangle2D::setRotation(float angle) +{ + mRotation = angle; + updateModel(); +} + +void Rectangle2D::setOpacity(float opacity) +{ + mColor.a = opacity; + updateColor(); +} + +void Rectangle2D::setWidth(float width) +{ + mDimensions.x = width; + updateModel(); +} + +void Rectangle2D::setHeight(float height) +{ + mDimensions.y = height; + updateModel(); +} + +void Rectangle2D::showDebugImGui(std::string name) +{ + name = "[Rectangle2D] " + name; + ImGui::Begin(name.c_str()); + ImGui::SliderFloat4("Color", &mColor[0], 0.0f, 1.0f); + ImGui::SliderFloat2("Position", &mPosition[0], -1500.f, 1500.f); + ImGui::SliderFloat("Rotation", &mRotation, 0.0f, 360.f); + ImGui::End(); + updateModel(); + updateColor(); +} + +float Rectangle2D::opacity() +{ + return mColor.a; +} diff --git a/AimGL/src/Renderer3D/Rectangle2D.h b/AimGL/src/Renderer3D/Rectangle2D.h new file mode 100644 index 0000000..213038f --- /dev/null +++ b/AimGL/src/Renderer3D/Rectangle2D.h @@ -0,0 +1,113 @@ +#pragma once +#include "BufferLayout.h" +#include "Renderer3D.h" +#include "Shader.h" +#include "VertexArray.h" +#include "VertexBuffer.h" + +/** + * \brief A representation of a texture that has its own transformation. + */ +class Rectangle2D +{ +public: + /** + * \brief Determines the point that defines the root of the sprite's position. + * + * For example, setting Origin to Center and setting the position to + * point (0,0) makes the sprite's center at point (0,0). + */ + enum class Origin + { + LeftBottom, + Center + }; + + /** + * \brief TODO: THIS + * \param color TODO: THIS + */ + Rectangle2D(const glm::vec2 size, const glm::vec4& color); + + /** + * \brief Draws a sprite for a given target + * \param target The target to which the sprite is drawn + */ + void draw(const Renderer3D& target) const; + + /** + * \brief Sets the position of the sprite on the screen + * \param newPosition New position to which the sprite will be set + * \param origin Relative to which origin the sprite will be located + */ + void setPosition(const glm::vec2& newPosition, Origin origin = Origin::LeftBottom); + + /** + * \brief Rotates the sprite + * \param angle The angle by which the sprite is to be rotated + */ + void setRotation(float angle); + + /** + * \brief Sets the transparency of the sprite in range 0 - 1 + * \param opacity New sprite transparency in the range of 0 - 1 + */ + void setOpacity(float opacity); + + /** + * \brief TODO: THIS + * \param color TODO: THIS + */ + void setColor(glm::vec4 color); + + /** + * \brief Sets the width of the sprite while the aspect ratio remains preserved + * \param width New sprite width + */ + void setWidth(float width); + + /** + * \brief Sets the height of the sprite while the aspect ratio remains preserved + * \param height New sprite height + */ + void setHeight(float height); + + /** + * \brief TODO: THIS + * \param name TODO: THIS + */ + void showDebugImGui(std::string name = ""); + + /** + * \brief TODO: THIS + * \return TODO: THIS + */ + float opacity(); + +private: + /** + * \brief Updates the model in the shader (model of MVP) + */ + void updateModel(); + + /** + * \brief TODO: THIS + */ + void updateColor(); + + /** + * \brief Prepares buffers to work + */ + void initializeBuffers(); + +private: + VertexArray mVAO; + VertexBuffer mVBO; + IndexBuffer mEBO; + Shader mShader; + BufferLayout mBufferLayout; + glm::vec4 mColor; + glm::vec3 mPosition; + glm::vec2 mDimensions; + float mRotation; +}; diff --git a/AimGL/src/Renderer3D/Renderer3D.cpp b/AimGL/src/Renderer3D/Renderer3D.cpp index e0d4912..24a43bd 100644 --- a/AimGL/src/Renderer3D/Renderer3D.cpp +++ b/AimGL/src/Renderer3D/Renderer3D.cpp @@ -1,5 +1,6 @@ #include "Renderer3D.h" #include "pch.h" +#include "World/Camera.h" Renderer3D::Renderer3D(sf::Window& window) : mWindow(window) @@ -16,6 +17,29 @@ void Renderer3D::draw(const VertexArray& va, const IndexBuffer& ib, const Shader glm::mat4 windowOrthoProjection = glm::ortho(0.f, static_cast(mWindow.getSize().x), 0.f, static_cast(mWindow.getSize().y)); shader.setUniform("windowOrthoProjection", windowOrthoProjection); + + glDisable(GL_DEPTH_TEST); + GLCall(glDrawElements(toOpenGl(drawMode), ib.size(), GL_UNSIGNED_INT, nullptr)); + glEnable(GL_DEPTH_TEST); + +#ifdef _DEBUG + shader.unbind(); + va.unbind(); + ib.unbind(); +#endif +} + +void Renderer3D::draw(const VertexArray& va, const IndexBuffer& ib, const Shader& shader, + const Camera& camera, const DrawMode& drawMode) const +{ + shader.bind(); + va.bind(); + ib.bind(); + + const auto view = camera.view(); + const auto projection = camera.projection(); + shader.setUniform("view", view); + shader.setUniform("projection", projection); GLCall(glDrawElements(toOpenGl(drawMode), ib.size(), GL_UNSIGNED_INT, nullptr)); #ifdef _DEBUG diff --git a/AimGL/src/Renderer3D/Renderer3D.h b/AimGL/src/Renderer3D/Renderer3D.h index 8b2ab9d..faeb94e 100644 --- a/AimGL/src/Renderer3D/Renderer3D.h +++ b/AimGL/src/Renderer3D/Renderer3D.h @@ -4,6 +4,8 @@ #include "Renderer3D/Shader.h" #include "Renderer3D/VertexArray.h" +class Camera; + /** * 3D Renderer allows to draw 3D objects to the screen using appropriate buffers and shaders */ @@ -29,6 +31,9 @@ class Renderer3D void draw(const VertexArray& va, const IndexBuffer& ib, const Shader& shader, const DrawMode& drawMode = DrawMode::Triangles) const; + void draw(const VertexArray& va, const IndexBuffer& ib, const Shader& shader, + const Camera& camera, const DrawMode& drawMode = DrawMode::Triangles) const; + private: unsigned toOpenGl(const DrawMode& drawMode) const; sf::Window& mWindow; diff --git a/AimGL/src/Renderer3D/Shader.cpp b/AimGL/src/Renderer3D/Shader.cpp index 1242b49..adb5bcb 100644 --- a/AimGL/src/Renderer3D/Shader.cpp +++ b/AimGL/src/Renderer3D/Shader.cpp @@ -33,6 +33,11 @@ void Shader::setUniform(const std::string& name, glm::mat4 mat) const GLCall(glUniformMatrix4fv(getUniformLocation(name), 1, GL_FALSE, glm::value_ptr(mat[0]))); } +void Shader::setUniform(const std::string& name, glm::vec4 vec) const +{ + GLCall(glUniform4fv(getUniformLocation(name), 1, glm::value_ptr(vec))); +} + void Shader::setUniform(const std::string& name, float f1, float f2, float f3, float f4) const { GLCall(glUniform4f(getUniformLocation(name), f1, f2, f3, f4)); diff --git a/AimGL/src/Renderer3D/Shader.h b/AimGL/src/Renderer3D/Shader.h index 2dbc1e7..74fe13c 100644 --- a/AimGL/src/Renderer3D/Shader.h +++ b/AimGL/src/Renderer3D/Shader.h @@ -64,6 +64,7 @@ class Shader void unbind() const; void setUniform(const std::string& name, glm::mat4 mat) const; + void setUniform(const std::string& name, glm::vec4 vec) const; void setUniform(const std::string& name, float f1, float f2, float f3, float f4) const; void setUniform(const std::string& name, float f1, float f2, float f3) const; void setUniform(const std::string& name, float f1, float f2) const; diff --git a/AimGL/src/Renderer3D/Sprite2D.cpp b/AimGL/src/Renderer3D/Sprite2D.cpp index 185d6a1..924b0d1 100644 --- a/AimGL/src/Renderer3D/Sprite2D.cpp +++ b/AimGL/src/Renderer3D/Sprite2D.cpp @@ -54,7 +54,7 @@ void Sprite2D::updateModel() glm::mat4 model = glm::mat4(1.0f); model = glm::translate(model, glm::vec3(mPosition)); model = glm::rotate(model, glm::radians(mRotation), glm::vec3(0.0f, 0.0f, 1.0f)); - model = glm::scale(model, glm::vec3(mScale, 1.0f)); + model = glm::scale(model, glm::vec3(mScale / 2.f, 1.0f)); mShader.bind(); mShader.setUniform("model", model); mShader.unbind(); @@ -95,13 +95,11 @@ void Sprite2D::setOpacity(float opacity) void Sprite2D::setWidth(float width) { mScale = {width, width / mTexture.aspectRatio()}; - mScale /= 2.f; updateModel(); } void Sprite2D::setHeight(float height) { mScale = {height * mTexture.aspectRatio(), height}; - mScale /= 2.f; updateModel(); } diff --git a/AimGL/src/Renderer3D/Sprite3D.cpp b/AimGL/src/Renderer3D/Sprite3D.cpp new file mode 100644 index 0000000..1c9f86e --- /dev/null +++ b/AimGL/src/Renderer3D/Sprite3D.cpp @@ -0,0 +1,116 @@ +#include "Sprite3D.h" +#include "Utils/Normalize.h" +#include "World/Camera.h" +#include "pch.h" + +Sprite3D::Sprite3D(const Texture& texture) + : mTexture(texture) + , mShader{{ShaderType::VertexShader, "resources/Shaders/Graphics/Sprite3D.vs"}, + {ShaderType::FragmentShader, "resources/Shaders/Graphics/Sprite3D.fs"}} + , mPosition(0.0f) + , mScale(1.0f) + , mDimensionsNormalized() + , mRotation(0.f, {0.f, 0.f, 1.f}) +{ + auto max = static_cast(std::max(mTexture.width(), mTexture.height())); + mDimensionsNormalized = {normalize(mTexture.width(), 0, max), + normalize(mTexture.height(), 0, max)}; + + initializeBuffers(); + setPosition({0.f, 0.f, 0.f}); +} + +void Sprite3D::initializeBuffers() +{ + float vertices[] = { + // positions // texture coords + 1.f, 1.f, 0.0f, 1.0f, 1.0f,// top right + 1.f, -1.f, 0.0f, 1.0f, 0.0f,// bottom right + -1.f, -1.f, 0.0f, 0.0f, 0.0f,// bottom left + -1.f, 1.f, 0.0f, 0.0f, 1.0f // top left + }; + + unsigned int indices[] = { + 0, 1, 3,// first Triangle + 1, 2, 3 // second Triangle + }; + + mVBO.setBuffer(vertices, sizeof(vertices)); + mEBO.setBuffer(indices, sizeof(indices)); + + mVAO.bind(); + mVBO.bind(); + mBufferLayout.push(3); + mBufferLayout.push(2); + mVAO.setBuffer(mVBO, mBufferLayout); + mVAO.unbind(); +} + +void Sprite3D::draw(const Renderer3D& target, const Camera& camera) const +{ + // Prepare transformations + mShader.bind(); + mTexture.bind(0); + target.draw(mVAO, mEBO, mShader, camera); +} + +void Sprite3D::updateModel() +{ + glm::mat4 model = glm::mat4(1.0f); + model = glm::translate(model, glm::vec3(mPosition)); + model = glm::rotate(model, glm::radians(mRotation.first), mRotation.second); + model = glm::scale(model, glm::vec3(mDimensionsNormalized * mScale / 2.f, 1.0f)); + mShader.bind(); + mShader.setUniform("model", model); + mShader.unbind(); +} + +void Sprite3D::setPosition(const glm::vec3& newPosition, Origin origin) +{ + switch (origin) + { + case Origin::Center: mPosition = newPosition; break; + case Origin::LeftBottom: + mPosition = newPosition; + mPosition += glm::vec3{mDimensionsNormalized.x / 2.f, mDimensionsNormalized.y / 2.f, 0}; + break; + } + updateModel(); +} + +void Sprite3D::setScale(float newScale) +{ + mScale *= newScale; + updateModel(); +} + +void Sprite3D::setRotation(float angle, glm::vec3 axis) +{ + mRotation = {angle, axis}; +} + +void Sprite3D::setOpacity(float opacity) +{ + mOpacity = opacity; + mShader.bind(); + mShader.setUniform("opacity", mOpacity); + mShader.unbind(); +} + +void Sprite3D::setWidth(float width) +{ + auto newDimensionsNotNormalized = {width, width / mTexture.aspectRatio()}; + auto max = static_cast(std::max(mTexture.width(), mTexture.height())); + mDimensionsNormalized = {normalize(mTexture.width(), 0, max), + normalize(mTexture.height(), 0, max)}; + updateModel(); +} + +void Sprite3D::setHeight(float height) +{ + auto newDimensionsNotNormalized = {height * mTexture.aspectRatio(), height}; + auto max = static_cast(std::max(mTexture.width(), mTexture.height())); + mDimensionsNormalized = {normalize(mTexture.width(), 0, max), + normalize(mTexture.height(), 0, max)}; + updateModel(); +} diff --git a/AimGL/src/Renderer3D/Sprite3D.h b/AimGL/src/Renderer3D/Sprite3D.h new file mode 100644 index 0000000..0fd4710 --- /dev/null +++ b/AimGL/src/Renderer3D/Sprite3D.h @@ -0,0 +1,102 @@ +#pragma once +#include "BufferLayout.h" +#include "Renderer3D.h" +#include "Shader.h" +#include "Texture.h" +#include "VertexArray.h" +#include "VertexBuffer.h" + + +class Camera; + +/** + * \brief A representation of a texture that has its own transformation. + */ +class Sprite3D +{ +public: + /** + * \brief Determines the point that defines the root of the sprite's position. + * + * For example, setting Origin to Center and setting the position to + * point (0,0) makes the sprite's center at point (0,0). + */ + enum class Origin + { + LeftBottom, + Center + }; + + /** + * \brief Constructs a sprite from the given texture. + * \param texture Texture from which the sprite is to be created + */ + Sprite3D(const Texture& texture); + + /** + * \brief Draws a sprite for a given target + * \param target The target to which the sprite is drawn + */ + void draw(const Renderer3D& target, const Camera& camera) const; + + /** + * \brief Sets the position of the sprite on the screen + * \param newPosition New position to which the sprite will be set + * \param origin Relative to which origin the sprite will be located + */ + void setPosition(const glm::vec3& newPosition, Origin origin = Origin::LeftBottom); + + /** + * \brief Sets the scale at which the sprite will be drawn + * \param newScale New scale with which the sprite will be drawna + */ + void setScale(float newScale); + + /** + * \brief Rotates the sprite + * \param angle The angle by which the sprite is to be rotated + */ + void setRotation(float angle, glm::vec3 axis); + + /** + * \brief Sets the transparency of the sprite in range 0 - 1 + * \param opacity New sprite transparency in the range of 0 - 1 + */ + void setOpacity(float opacity); + + /** + * \brief Sets the width of the sprite while the aspect ratio remains preserved + * \param width New sprite width + */ + void setWidth(float width); + + /** + * \brief Sets the height of the sprite while the aspect ratio remains preserved + * \param height New sprite height + */ + void setHeight(float height); + +private: + /** + * \brief Updates the model in the shader (model of MVP) + */ + void updateModel(); + + /** + * \brief Prepares buffers to work + */ + void initializeBuffers(); + +private: + VertexArray mVAO; + VertexBuffer mVBO; + IndexBuffer mEBO; + const Texture& mTexture; + Shader mShader; + BufferLayout mBufferLayout; + glm::vec3 mPosition; + glm::vec2 mScale; + glm::vec2 mDimensionsNormalized; + std::pair mRotation; + float mOpacity; +}; diff --git a/AimGL/src/States/CustomStates/GameState.cpp b/AimGL/src/States/CustomStates/GameState.cpp new file mode 100644 index 0000000..9bc36c3 --- /dev/null +++ b/AimGL/src/States/CustomStates/GameState.cpp @@ -0,0 +1,87 @@ +#include "GameState.h" +#include "States/StateStack.h" +#include "Utils/Mouse.h" +#include "pch.h" +#include "Renderer3D/Sprite3D.h" + +GameState::GameState(StateStack& stack, WindowToRender& window) + : State(stack) + , mWindow(window) + , mRenderer3D(mWindow) + , mLogoTexture("resources/Textures/logo_background.png") + , mLogo(mLogoTexture) + , mCamera(window) + , mGameBackground(glm::vec2(1280, 720.f), glm::vec4(0.85f, 0.85f, 0.85f, 1.f)) + , mPhaseInLogoColor({window.getSize().x, window.getSize().y}, {0.067f, 0.11f, 0.18f, 1.1f}) + , mInfiniteGridShader{ + {ShaderType::VertexShader, "resources/Shaders/Graphics/InfiniteGridFloor.vs"}, + {ShaderType::FragmentShader, "resources/Shaders/Graphics/InfiniteGridFloor.fs"}} +{ + Mouse::lockMouseAtCenter(mWindow); + mLogo.setHeight(2.f); + mLogo.setPosition(glm::vec3(0, 0, 0), Sprite3D::Origin::LeftBottom); + mLogo.setOpacity(1); + mGameBackground.setPosition({0, 0}); + mPhaseInLogoColor.setPosition({0, 0}); + mPhaseInClock.restart(); + mCamera.cameraPosition({1, 1.5, 2}); +} + +void GameState::draw(sf::Window& target) const +{ + MTR_SCOPE("GameState", "GameState::draw"); + mGameBackground.draw(mRenderer3D); + mLogo.draw(mRenderer3D, mCamera); + + mInfiniteGridShader.bind(); + const auto view = mCamera.view(); + const auto projection = mCamera.projection(); + mInfiniteGridShader.setUniform("view", view); + mInfiniteGridShader.setUniform("projection", projection); + glDrawArrays(GL_TRIANGLES, 0, 6); + mInfiniteGridShader.unbind(); + + mPhaseInLogoColor.draw(mRenderer3D); +} + +bool GameState::fixedUpdate(const float& deltaTime) +{ + MTR_SCOPE("GameState", "GameState::fixedUpdate"); + mCamera.fixedUpdate(deltaTime); + return true; +} + +bool GameState::update(const float& deltaTime) +{ + MTR_SCOPE("GameState", "GameState::update"); + mCamera.update(deltaTime); + + if (mPhaseInLogoColor.opacity() > 0) + { + mPhaseInLogoColor.setOpacity(mPhaseInLogoColor.opacity() - deltaTime / 4.f); + } + return true; +} + +bool GameState::handleEvent(const sf::Event& event) +{ + MTR_SCOPE("GameState", "GameState::handleEvent"); + mCamera.handleEvent(event); + + if (event.type == sf::Event::KeyPressed) + { + switch (event.key.code) + { + case sf::Keyboard::Escape: Mouse::unlockMouse(mWindow); break; + } + } + return true; +} + +bool GameState::updateImGui(const float& deltaTime) +{ + MTR_SCOPE("GameState", "GameState::updateImGui"); + //mCamera.updateImGui(); + ImGui::ShowDemoWindow(); + return true; +} diff --git a/AimGL/src/States/CustomStates/GameState.h b/AimGL/src/States/CustomStates/GameState.h new file mode 100644 index 0000000..2082f54 --- /dev/null +++ b/AimGL/src/States/CustomStates/GameState.h @@ -0,0 +1,60 @@ +#pragma once + +#include "Renderer3D/Rectangle2D.h" +#include "Renderer3D/Renderer3D.h" +#include "Renderer3D/Sprite3D.h" +#include "States/State.h" +#include "World/Camera.h" + +class StateStack; + +/** + * \brief TODO: THIS + */ +class GameState : public State +{ +public: + GameState(StateStack& stack, WindowToRender& window); + + /** + * \brief Draws only this state to the passed target + * \param target where it should be drawn to + */ + void draw(sf::Window& target) const override; + + + /** + * \brief Updates the state logic at equal intervals independent of the frame rate. + * \param deltaTime Time interval + */ + bool fixedUpdate(const float& deltaTime) override; + + /** + * \brief Updates the game logic dependent, or independent of time, every rendered frame. + * \param deltaTime the time that has passed since the game was last updated. + */ + bool update(const float& deltaTime) override; + + /** + * \brief It takes input (event) from the user and interprets it + * \param event user input + */ + bool handleEvent(const sf::Event& event) override; + + /** + * \brief Updates the imgui logic dependent, or independent of time, every rendered frame. + * \param deltaTime the time that has passed since the game was last updated. + */ + bool updateImGui(const float& deltaTime) override; + +private: + WindowToRender& mWindow; + Renderer3D mRenderer3D; + Texture mLogoTexture; + Sprite3D mLogo; + Camera mCamera; + Rectangle2D mGameBackground; + sf::Clock mPhaseInClock; + Rectangle2D mPhaseInLogoColor; + Shader mInfiniteGridShader; +}; diff --git a/AimGL/src/States/CustomStates/LogoState.cpp b/AimGL/src/States/CustomStates/LogoState.cpp index c00db22..2e51d90 100644 --- a/AimGL/src/States/CustomStates/LogoState.cpp +++ b/AimGL/src/States/CustomStates/LogoState.cpp @@ -5,33 +5,36 @@ LogoState::LogoState(StateStack& stack, sf::Window& window) : State(stack) , mWindow(window) + , mRenderer3D(mWindow) , mLogoTexture("resources/Textures/logo.png") , mLogo(mLogoTexture) - , mRenderer3D(window) , mPhase(Phase::FadeIn) + , mRectangle({window.getSize().x, window.getSize().y}, {0.067f, 0.11f, 0.18f, 1.f}) { mClock.restart(); mLogo.setPosition(glm::vec2(mWindow.getSize().x / 2.f, mWindow.getSize().y / 2.f), Sprite2D::Origin::Center); mLogo.setHeight(mWindow.getSize().y); mLogo.setOpacity(0); + mRectangle.setPosition({0, 0}); } void LogoState::draw(sf::Window& target) const { - MTR_SCOPE("SampleState", "SampleState::draw"); + MTR_SCOPE("LogoState", "LogoState::draw"); + mRectangle.draw(mRenderer3D); mLogo.draw(mRenderer3D); } bool LogoState::fixedUpdate(const float& deltaTime) { - MTR_SCOPE("SampleState", "SampleState::fixedUpdate"); + MTR_SCOPE("LogoState", "LogoState::fixedUpdate"); return true; } bool LogoState::update(const float& deltaTime) { - MTR_SCOPE("SampleState", "SampleState::update"); + MTR_SCOPE("LogoState", "LogoState::update"); switch (mPhase) { case Phase::FadeIn: @@ -48,7 +51,7 @@ bool LogoState::update(const float& deltaTime) if (mClock.getElapsedTime().asSeconds() > 4.f) { requestPop(); - requestPush(State_ID::ExitGameState); + requestPush(State_ID::GameState); } break; } @@ -57,13 +60,13 @@ bool LogoState::update(const float& deltaTime) bool LogoState::handleEvent(const sf::Event& event) { - MTR_SCOPE("SampleState", "SampleState::handleEvent"); + MTR_SCOPE("LogoState", "LogoState::handleEvent"); return true; } bool LogoState::updateImGui(const float& deltaTime) { - MTR_SCOPE("SampleState", "SampleState::updateImGui"); + MTR_SCOPE("LogoState", "LogoState::updateImGui"); ImGui::ShowDemoWindow(); return true; } diff --git a/AimGL/src/States/CustomStates/LogoState.h b/AimGL/src/States/CustomStates/LogoState.h index 6fcfe41..a6baf8d 100644 --- a/AimGL/src/States/CustomStates/LogoState.h +++ b/AimGL/src/States/CustomStates/LogoState.h @@ -1,5 +1,6 @@ #pragma once +#include "Renderer3D/Rectangle2D.h" #include "Renderer3D/Renderer3D.h" #include "Renderer3D/Sprite2D.h" #include "States/State.h" @@ -58,10 +59,11 @@ class LogoState : public State }; private: + sf::Window& mWindow; Renderer3D mRenderer3D; Texture mLogoTexture; Sprite2D mLogo; sf::Clock mClock; - sf::Window& mWindow; Phase mPhase; + Rectangle2D mRectangle; }; diff --git a/AimGL/src/Utils/Mouse.cpp b/AimGL/src/Utils/Mouse.cpp new file mode 100644 index 0000000..1f454a2 --- /dev/null +++ b/AimGL/src/Utils/Mouse.cpp @@ -0,0 +1,68 @@ +#include "Mouse.h" +#include "pch.h" + +#include + +void Mouse::centerMouse(const sf::Window& window) +{ + sf::Mouse::setPosition(sf::Vector2i(window.getSize().x / 2, window.getSize().y / 2), window); +} + +void Mouse::lockMouseAtCenter(sf::Window& window) +{ + if (!isMouseLocked()) + { + mLockedMouse = true; + window.setMouseCursorVisible(false); + centerMouse(window); + } +} + +void Mouse::unlockMouse(sf::Window& window) +{ + if (isMouseLocked()) + { + window.setMouseCursorVisible(true); + mLockedMouse = false; + } +} + +bool Mouse::isMouseLocked() +{ + return mLockedMouse; +} + +sf::Vector2i Mouse::mouseOffset() +{ + return mMouseOffset; +} + +void Mouse::update(const float& deltaTime, const sf::Window& window) +{ + if (isMouseLocked()) + { + const auto windowCenter = sf::Vector2i(window.getSize().x / 2.f, window.getSize().y / 2.f); + mMouseOffset = sf::Mouse::getPosition(window) - windowCenter; + centerMouse(window); + } +} + +void Mouse::handleFirstPersonBehaviour(const sf::Event& event, sf::RenderWindow& gameWindow) +{ + if (event.type == sf::Event::MouseButtonPressed) + { + if (event.key.code == sf::Mouse::Left) + { +#ifdef _DEBUG + if (!ImGui::IsWindowHovered(ImGuiFocusedFlags_AnyWindow) && !ImGui::IsAnyItemActive()) + { + Mouse::lockMouseAtCenter(gameWindow); + } +#endif + } + } + else if (event.type == sf::Event::GainedFocus) + { + Mouse::lockMouseAtCenter(gameWindow); + } +} \ No newline at end of file diff --git a/AimGL/src/Utils/Mouse.h b/AimGL/src/Utils/Mouse.h new file mode 100644 index 0000000..8d766ca --- /dev/null +++ b/AimGL/src/Utils/Mouse.h @@ -0,0 +1,57 @@ +#pragma once +#include "Game.h" + +#include + +/** + * Enhanced mouse behavior allowing much more in the application. + */ +class Mouse : public sf::Mouse +{ +public: + /** + * Centers the mouse relative to the window + * @param window Window relative to which the mouse is centered + */ + static void centerMouse(const sf::Window& window); + + /** + * Locks the cursor in the center of the screen not allowing it to move. + * @param window The window against which the cursor is locked. + */ + static void lockMouseAtCenter(sf::Window& window); + + /** + * Unlocks the mouse when it is locked in the middle of the screen. + * @param window Window against which the mouse is locked + */ + static void unlockMouse(sf::Window& window); + + /** + * Returns information about whether the cursor is locked relative to window. + * @return True if blocked, false otherwise + */ + static bool isMouseLocked(); + + /** + * Offset relative to the center of the window. + * @return + */ + static sf::Vector2i mouseOffset(); + + /** + * Updates the game logic dependent, or independent of time, every rendered frame. + * @param deltaTime the time that has passed since the game was last updated. + * @param window The window relative to which the cursor is drawn + */ + static void update(const float& deltaTime, const sf::Window& window); + + /** + * It handles mouse behavior typical of first-person game controls. + */ + static void handleFirstPersonBehaviour(const sf::Event& event, WindowToRender& gameWindow); + +private: + static inline bool mLockedMouse = false; + inline static sf::Vector2i mMouseOffset; +}; \ No newline at end of file diff --git a/AimGL/src/Utils/Normalize.h b/AimGL/src/Utils/Normalize.h new file mode 100644 index 0000000..a7d24e3 --- /dev/null +++ b/AimGL/src/Utils/Normalize.h @@ -0,0 +1,6 @@ +#pragma once + +float normalize(float value, float min, float max) +{ + return ((value - min) / (max - min)); +} \ No newline at end of file diff --git a/AimGL/src/World/Camera.cpp b/AimGL/src/World/Camera.cpp new file mode 100644 index 0000000..e135abd --- /dev/null +++ b/AimGL/src/World/Camera.cpp @@ -0,0 +1,193 @@ +#include "Camera.h" +#include "pch.h" + +#include +#include +#include +#include +#include + +#include "Utils/Mouse.h" + +Camera::Camera(const WindowToRender& target) + : mRenderTarget(target) +{ + mViewMatrix = glm::lookAt(mCameraPosition, mCameraPosition + mCameraFront, mCameraUp); + + auto targetSize = mRenderTarget.getSize(); + mProjectionMatrix = glm::perspective( + glm::radians(0.0f), static_cast(targetSize.x / targetSize.y), 1.f, 100.f); +} + +void Camera::update(const float& deltaTime) +{ + handleMouseInputs(deltaTime); + + auto width = static_cast(mRenderTarget.getSize().x); + auto height = static_cast(mRenderTarget.getSize().y); + mProjectionMatrix = glm::perspective(glm::radians(mFovCamera), width / height, 0.1f, 10000.f); + mViewMatrix = glm::lookAt(mCameraPosition, mCameraPosition + mCameraFront, mCameraUp); +} + +void Camera::fixedUpdate(const float& deltaTime) +{ + handleKeyboardInputs(deltaTime); +} + +void Camera::handleMouseInputs(const float& deltaTime) +{ + if (Mouse::isMouseLocked() && mAreControlsEnabled) + { + calculateCameraAngles(deltaTime); + keepNaturalPitchRanges(); + calculateCameraDirectionVector(); + } +} + +void Camera::calculateCameraDirectionVector() +{ + glm::vec3 direction; + direction.x = cos(glm::radians(mYaw)) * cos(glm::radians(mPitch)); + direction.y = sin(glm::radians(mPitch)); + direction.z = sin(glm::radians(mYaw)) * cos(glm::radians(mPitch)); + mCameraFront = glm::normalize(direction); + + direction.x = cos(glm::radians(mYaw)); + direction.y = 0; + direction.z = sin(glm::radians(mYaw)); + mCameraFrontWithoutPitch = glm::normalize(direction); +} + +void Camera::calculateCameraAngles(const float& deltaTime) +{ + auto mouseOffset = static_cast(Mouse::mouseOffset()); + + mouseOffset.x *= mCameraSensitivity * deltaTime; + mouseOffset.y *= mCameraSensitivity * deltaTime * -1; + + mYaw += mouseOffset.x; + mPitch += mouseOffset.y; +} + +void Camera::keepNaturalPitchRanges() +{ + if (mPitch > 89.0f) + { + mPitch = 89.0f; + } + if (mPitch < -89.0f) + { + mPitch = -89.0f; + } +} + +void Camera::handleKeyboardInputs(const float& deltaTime) +{ + auto cameraSpeed = this->mCameraSpeed; + cameraSpeed = applyAdditionalCameraAcceleration(cameraSpeed); + handleCameraMovement(deltaTime, cameraSpeed); +} + +void Camera::handleCameraMovement(const float& deltaTime, float cameraSpeed) +{ + if (sf::Keyboard::isKeyPressed(sf::Keyboard::W)) + { + mCameraPosition += cameraSpeed * mCameraFront * deltaTime; + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::S)) + { + mCameraPosition -= cameraSpeed * mCameraFront * deltaTime; + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::D)) + { + mCameraPosition += + glm::normalize(glm::cross(mCameraFront, mCameraUp)) * cameraSpeed * deltaTime; + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::A)) + { + mCameraPosition -= + glm::normalize(glm::cross(mCameraFront, mCameraUp)) * cameraSpeed * deltaTime; + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::Q)) + { + mCameraPosition -= cameraSpeed * mCameraUp * deltaTime; + } + if (sf::Keyboard::isKeyPressed(sf::Keyboard::E)) + { + mCameraPosition += cameraSpeed * mCameraUp * deltaTime; + } +} + +float Camera::applyAdditionalCameraAcceleration(float cameraSpeed) const +{ + if (sf::Keyboard::isKeyPressed(sf::Keyboard::LShift)) + { + cameraSpeed *= 2; + } + return cameraSpeed; +} + +void Camera::handleEvent(const sf::Event& event) +{ + switch (event.type) + { + case sf::Event::MouseWheelMoved: mFovCamera -= event.mouseWheel.delta; break; + } +} + +glm::mat4 Camera::view() const +{ + return mViewMatrix; +} + +glm::mat4 Camera::projection() const +{ + return mProjectionMatrix; +} + +glm::vec3 Camera::cameraPosition() const +{ + return mCameraPosition; +} + +void Camera::updateImGui() +{ + ImGui::Begin("Camera"); + ImGui::SliderFloat3("Translation", &mCameraPosition.x, 0.0f, 960.0f); + ImGui::End(); +} + +glm::vec3 Camera::direction() const +{ + return mCameraFront; +} + +glm::vec3 Camera::rightDirection() const +{ + return glm::cross(mCameraFront, mCameraUp); +} + +glm::vec3 Camera::rightDirectionWithoutPitch() const +{ + return glm::cross(mCameraFrontWithoutPitch, mCameraUp); +} + +glm::vec3 Camera::upwardDirection() const +{ + return mCameraUp; +} + +void Camera::cameraPosition(const glm::vec3& newPosition) +{ + mCameraPosition = newPosition; +} + +glm::vec3 Camera::directionWithoutPitch() const +{ + return mCameraFrontWithoutPitch; +} + +void Camera::toggleControls() +{ + mAreControlsEnabled = !mAreControlsEnabled; +} \ No newline at end of file diff --git a/AimGL/src/World/Camera.h b/AimGL/src/World/Camera.h new file mode 100644 index 0000000..9fa416a --- /dev/null +++ b/AimGL/src/World/Camera.h @@ -0,0 +1,168 @@ +#pragma once +#include "Game.h" + +#include +#include + + +/** + * An in-game camera through which the player views gameplay. + */ +class Camera +{ +public: + Camera(const WindowToRender& target); + + /** + * \brief Updates the camera logic at equal intervals independent of the frame rate. + * \param deltaTime Time interval + */ + void fixedUpdate(const float& deltaTime); + + /** + * Updates the camera logic dependent, or independent of time, every rendered frame. + * \param deltaTime the time that has passed since the game was last updated. + */ + void update(const float& deltaTime); + + /** + * \brief It takes input (event) from the user and interprets it. + * \param event user input + */ + void handleEvent(const sf::Event& event); + + /** + * Returns the view matrix. + * @return View matrix. + */ + glm::mat4 view() const; + + /** + * Returns projection matrix. + * @return Projection matrix. + */ + glm::mat4 projection() const; + + /** + * Returns the current position of the camera. + * @return Current position of the camera. + */ + glm::vec3 cameraPosition() const; + + /** + * @brief Sets the camera position + * @param newPosition The new position on which the camera should be placed. + */ + void cameraPosition(const glm::vec3& newPosition); + + /** + * Camera viewing direction (front). + * @return Returns front camera viewing direction. + */ + glm::vec3 direction() const; + + /** + * Returns the direction of the camera (front) without taking into account the pitch, i.e. the + * up-down rotation of the camera. + * @return Returns front camera viewing direction without pitch (no up-down rotation). + */ + glm::vec3 directionWithoutPitch() const; + + /** + * @brief Returns the right direction of the camera, which is the cross product of the front and + * upward vectors. + * @return Right direction of the camera. + */ + glm::vec3 rightDirection() const; + + /** + * @brief Returns the right direction of the camera without pitch, which is the cross product of + * the front and upward vectors without respecting pitch, that is, the up-and-down rotation of + * the camera. + * @return Right direction of the camera without pitch (without up-and-down rotation of camera) + */ + glm::vec3 rightDirectionWithoutPitch() const; + + /** + * @brief Returns the upward direction of the camera + * @return Upward direction of the camera. + */ + glm::vec3 upwardDirection() const; + + /** + * @brief Activates/deactivates in-game controls + */ + void toggleControls(); + + /** + * \brief Updates the status/logic of the ImGui Debug Menu + */ + void updateImGui(); + +private: + /** + * Handle keyboard behavior such as moving the camera inside the game + * @param deltaTime the time that has passed since the game was last updated. + */ + void handleKeyboardInputs(const float& deltaTime); + + /** + * It changes speed depending on whether the player has pressed + * the button responsible for accelerating the camera. + * + * @param cameraSpeed Base camera speed + * @return Accelerated or base camera speed + */ + float applyAdditionalCameraAcceleration(float cameraSpeed) const; + + /** + * Handles keyboard behavior for the camera, such as moving the camera. + * @param deltaTime the time that has passed since the game was last updated. + * @param cameraSpeed Base camera speed + */ + void handleCameraMovement(const float& deltaTime, float cameraSpeed); + + /** + * Handles mouse behavior for the camera, such as rotating the camera. + * @param deltaTime the time that has passed since the game was last updated. + */ + void handleMouseInputs(const float& deltaTime); + + /** + * It keeps an eye on the intervals for pitch, so that moving the camera is natural + * and takes place within the intervals known by the players. For example, it is + * impossible to perform a 360-degree backflip. + */ + void keepNaturalPitchRanges(); + + /** + * Calculates yaw and pitch for the camera + * @param deltaTime the time that has passed since the game was last updated. + */ + void calculateCameraAngles(const float& deltaTime); + + /** + * Calculates the camera's directional vector, which is the final\ + * vector responsible for the camera's rotation. + */ + void calculateCameraDirectionVector(); + + const WindowToRender& mRenderTarget; + + glm::vec3 mCameraPosition = glm::vec3(0, 0, 0); + glm::vec3 mCameraFront = glm::vec3(0.0f, 0.0f, -1.0f); + glm::vec3 mCameraUp = glm::vec3(0.0f, 1.0f, 0.0f); + glm::vec3 mCameraFrontWithoutPitch = glm::vec3(0.0f, 0.0f, -1.0f); + + float mYaw = -90.f; + float mPitch = 0.f; + float mRoll = 0.f; + + float mCameraSpeed = 5.f; + float mCameraSensitivity = 4.f; + float mFovCamera = 90.0f; + bool mAreControlsEnabled = true; + + glm::mat4 mViewMatrix; + mutable glm::mat4 mProjectionMatrix; +}; diff --git a/AimGL/src/World/InfiniteGridFloor.cpp b/AimGL/src/World/InfiniteGridFloor.cpp new file mode 100644 index 0000000..bcf875a --- /dev/null +++ b/AimGL/src/World/InfiniteGridFloor.cpp @@ -0,0 +1,2 @@ +#include "InfiniteGridFloor.h" +#include "pch.h" \ No newline at end of file diff --git a/AimGL/src/World/InfiniteGridFloor.h b/AimGL/src/World/InfiniteGridFloor.h new file mode 100644 index 0000000..27cea8c --- /dev/null +++ b/AimGL/src/World/InfiniteGridFloor.h @@ -0,0 +1,8 @@ +#pragma once + + + +class InfiniteGridFloor +{ + +}; \ No newline at end of file