diff --git a/AimGL/CMakeSettings.json b/AimGL/CMakeSettings.json new file mode 100644 index 0000000..0c5fbf9 --- /dev/null +++ b/AimGL/CMakeSettings.json @@ -0,0 +1,27 @@ +{ + "configurations": [ + { + "name": "x64-Debug", + "generator": "Ninja", + "configurationType": "Debug", + "inheritEnvironments": [ "msvc_x64_x64" ], + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "" + }, + { + "name": "x64-Release", + "generator": "Ninja", + "configurationType": "RelWithDebInfo", + "buildRoot": "${projectDir}\\out\\build\\${name}", + "installRoot": "${projectDir}\\out\\install\\${name}", + "cmakeCommandArgs": "", + "buildCommandArgs": "", + "ctestCommandArgs": "", + "inheritEnvironments": [ "msvc_x64_x64" ], + "variables": [] + } + ] +} \ No newline at end of file diff --git a/AimGL/resources/Shaders/Graphics/Sprite.fs b/AimGL/resources/Shaders/Graphics/Sprite.fs new file mode 100644 index 0000000..4804d00 --- /dev/null +++ b/AimGL/resources/Shaders/Graphics/Sprite.fs @@ -0,0 +1,15 @@ +#version 330 core + +in vec2 TexCoords; +out vec4 color; + +uniform sampler2D spriteTexture; +uniform float opacity = 0.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/Sprite.vs b/AimGL/resources/Shaders/Graphics/Sprite.vs new file mode 100644 index 0000000..d062eca --- /dev/null +++ b/AimGL/resources/Shaders/Graphics/Sprite.vs @@ -0,0 +1,17 @@ +#version 330 core + +layout(location = 0) in vec2 position; // Vertex position +layout(location = 1) in vec2 texCoords; // Texture coordinates + +out vec2 TexCoords; + +uniform mat4 model; +uniform mat4 projection = mat4(1.0); // For 2D it is identity +uniform mat4 windowProjection; + +void main() +{ + TexCoords = texCoords; + mat4 mvp = windowProjection * model; + gl_Position = mvp * vec4(position, 0.0, 1.0); +} \ No newline at end of file diff --git a/AimGL/resources/Shaders/basic.fs b/AimGL/resources/Shaders/basic.fs index 8379ff8..a081fad 100644 --- a/AimGL/resources/Shaders/basic.fs +++ b/AimGL/resources/Shaders/basic.fs @@ -1,7 +1,12 @@ #version 330 core out vec4 FragColor; + +in vec3 ourColor; +in vec2 TexCoord; + +uniform sampler2D ourTexture; void main() { - FragColor = vec4(0.5,0.5,0.1,1); -} \ No newline at end of file + FragColor = texture(ourTexture, TexCoord); +} \ No newline at end of file diff --git a/AimGL/resources/Shaders/basic.vs b/AimGL/resources/Shaders/basic.vs index cdd6dd3..311ec24 100644 --- a/AimGL/resources/Shaders/basic.vs +++ b/AimGL/resources/Shaders/basic.vs @@ -1,7 +1,14 @@ #version 330 core layout (location = 0) in vec3 aPos; +layout (location = 1) in vec3 aColor; +layout (location = 2) in vec2 aTexCoord; + +out vec3 ourColor; +out vec2 TexCoord; void main() { - gl_Position = vec4(aPos.x, aPos.y, aPos.z, 1.0); + gl_Position = vec4(aPos, 1.0); + ourColor = aColor; + TexCoord = aTexCoord; } \ No newline at end of file diff --git a/AimGL/resources/Textures/dead-inside.png b/AimGL/resources/Textures/dead-inside.png new file mode 100644 index 0000000..afed2a8 Binary files /dev/null and b/AimGL/resources/Textures/dead-inside.png differ diff --git a/AimGL/src/CMakeLists.txt b/AimGL/src/CMakeLists.txt index 3aaf340..bca4bbe 100644 --- a/AimGL/src/CMakeLists.txt +++ b/AimGL/src/CMakeLists.txt @@ -14,11 +14,18 @@ target_precompile_headers(AimGLSrc PUBLIC pch.h) set(CUSTOM_INCLUDES_DIR ${CMAKE_CURRENT_BINARY_DIR}/custom_includes) file(MAKE_DIRECTORY ${CUSTOM_INCLUDES_DIR}) -configure_file( - ${FETCHCONTENT_BASE_DIR}/minitrace-src/minitrace.h +set(CUSTOM_INCLUDES + ${FETCHCONTENT_BASE_DIR}/minitrace-src/minitrace.h + ${FETCHCONTENT_BASE_DIR}/stb-src/stb_image.h +) + +foreach(HEADER ${CUSTOM_INCLUDES}) + configure_file( + ${HEADER} ${CUSTOM_INCLUDES_DIR} COPYONLY -) + ) +endforeach() target_include_directories(AimGLSrc PUBLIC ${FETCHCONTENT_BASE_DIR}/glew-src/include diff --git a/AimGL/src/CMakeLists_Sources.txt b/AimGL/src/CMakeLists_Sources.txt index a589e9c..c28e5a4 100644 --- a/AimGL/src/CMakeLists_Sources.txt +++ b/AimGL/src/CMakeLists_Sources.txt @@ -10,7 +10,10 @@ set(PROJECT_SOURCES Renderer3D/VertexArray.cpp Renderer3D/VertexBuffer.cpp Renderer3D/OpenglUtils.cpp + Renderer3D/Texture.cpp + Renderer3D/Sprite2D.cpp States/State.cpp States/StateStack.cpp - States/CustomStates/SampleState.cpp + States/CustomStates/LogoState.cpp + States/CustomStates/ExitGameState.cpp ) \ No newline at end of file diff --git a/AimGL/src/Game.cpp b/AimGL/src/Game.cpp index 9daa61a..4f1667c 100644 --- a/AimGL/src/Game.cpp +++ b/AimGL/src/Game.cpp @@ -1,5 +1,6 @@ #include "Game.h" -#include "States/CustomStates/SampleState.h" +#include "States/CustomStates/ExitGameState.h" +#include "States/CustomStates/LogoState.h" #include "constants.h" #include "pch.h" @@ -59,11 +60,15 @@ Game::Game() throw std::runtime_error("Failed to initialize GLEW"); } + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + // Setup all application-flow states - mAppStack.saveState(State_ID::SampleState, *mGameWindow); + mAppStack.saveState(State_ID::LogoState, *mGameWindow); + mAppStack.saveState(State_ID::ExitGameState); // Initial state of the statestack is TitleState - mAppStack.push(State_ID::SampleState); + mAppStack.push(State_ID::LogoState); } void Game::run() @@ -215,7 +220,7 @@ void Game::update(const sf::Time& deltaTime) void Game::render() { MTR_SCOPE("Game", "Game::render"); - glClearColor(0.43f, 0.69f, 1.0f, 1.0f); + glClearColor(0.f, 0.f, 0.0f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // draw the application diff --git a/AimGL/src/Renderer3D/Renderer3D.cpp b/AimGL/src/Renderer3D/Renderer3D.cpp index c74cfb4..3d7ac1c 100644 --- a/AimGL/src/Renderer3D/Renderer3D.cpp +++ b/AimGL/src/Renderer3D/Renderer3D.cpp @@ -1,12 +1,22 @@ #include "Renderer3D.h" #include "pch.h" +Renderer3D::Renderer3D(sf::Window& window) + : mWindow(window) +{ +} + void Renderer3D::draw(const VertexArray& va, const IndexBuffer& ib, const Shader& shader, const DrawMode& drawMode) const { + //mWindow.setActive(true); shader.bind(); va.bind(); ib.bind(); + float aspectRatio = static_cast(mWindow.getSize().x) / mWindow.getSize().y; + + glm::mat4 windowProjection = glm::ortho(0.f, static_cast(mWindow.getSize().x), 0.f, static_cast(mWindow.getSize().y)); + shader.setUniform("windowProjection", windowProjection); 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 180a35c..8b2ab9d 100644 --- a/AimGL/src/Renderer3D/Renderer3D.h +++ b/AimGL/src/Renderer3D/Renderer3D.h @@ -17,6 +17,8 @@ class Renderer3D Quads }; + Renderer3D(sf::Window& window); + /** * Draws the data given in VertexArray, IndexBuffer to the screen using the interpretation given * in Shader. @@ -29,4 +31,5 @@ class Renderer3D private: unsigned toOpenGl(const DrawMode& drawMode) const; + sf::Window& mWindow; }; \ No newline at end of file diff --git a/AimGL/src/Renderer3D/Shader.cpp b/AimGL/src/Renderer3D/Shader.cpp index af7015b..1242b49 100644 --- a/AimGL/src/Renderer3D/Shader.cpp +++ b/AimGL/src/Renderer3D/Shader.cpp @@ -28,47 +28,52 @@ void Shader::unbind() const GLCall(glUseProgram(0)); } -void Shader::setUniform(const std::string& name, float f1, float f2, float f3, float f4) +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, float f1, float f2, float f3, float f4) const { GLCall(glUniform4f(getUniformLocation(name), f1, f2, f3, f4)); } -void Shader::setUniform(const std::string& name, float f1, float f2, float f3) +void Shader::setUniform(const std::string& name, float f1, float f2, float f3) const { GLCall(glUniform3f(getUniformLocation(name), f1, f2, f3)); } -void Shader::setUniform(const std::string& name, float f1, float f2) +void Shader::setUniform(const std::string& name, float f1, float f2) const { GLCall(glUniform2f(getUniformLocation(name), f1, f2)); } -void Shader::setUniform(const std::string& name, float f1) +void Shader::setUniform(const std::string& name, float f1) const { GLCall(glUniform1f(getUniformLocation(name), f1)); } -void Shader::setUniform(const std::string& name, int i1, int i2, int i3, int i4) +void Shader::setUniform(const std::string& name, int i1, int i2, int i3, int i4) const { GLCall(glUniform4i(getUniformLocation(name), i1, i2, i3, i4)); } -void Shader::setUniform(const std::string& name, int i1, int i2, int i3) +void Shader::setUniform(const std::string& name, int i1, int i2, int i3) const { GLCall(glUniform3i(getUniformLocation(name), i1, i2, i3)); } -void Shader::setUniform(const std::string& name, int i1, int i2) +void Shader::setUniform(const std::string& name, int i1, int i2) const { GLCall(glUniform2i(getUniformLocation(name), i1, i2)); } -void Shader::setUniform(const std::string& name, int i1) +void Shader::setUniform(const std::string& name, int i1) const { GLCall(glUniform1i(getUniformLocation(name), i1)); } -unsigned Shader::getUniformLocation(const std::string& name) +unsigned Shader::getUniformLocation(const std::string& name) const { if (mUniformLocationCache.find(name) != mUniformLocationCache.end()) { diff --git a/AimGL/src/Renderer3D/Shader.h b/AimGL/src/Renderer3D/Shader.h index eeabb76..2dbc1e7 100644 --- a/AimGL/src/Renderer3D/Shader.h +++ b/AimGL/src/Renderer3D/Shader.h @@ -63,14 +63,15 @@ class Shader */ void unbind() const; - void setUniform(const std::string& name, float f1, float f2, float f3, float f4); - void setUniform(const std::string& name, float f1, float f2, float f3); - void setUniform(const std::string& name, float f1, float f2); - void setUniform(const std::string& name, float f1); - void setUniform(const std::string& name, int i1, int i2, int i3, int i4); - void setUniform(const std::string& name, int i1, int i2, int i3); - void setUniform(const std::string& name, int i1, int i2); - void setUniform(const std::string& name, int i1); + void setUniform(const std::string& name, glm::mat4 mat) 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; + void setUniform(const std::string& name, float f1) const; + void setUniform(const std::string& name, int i1, int i2, int i3, int i4) const; + void setUniform(const std::string& name, int i1, int i2, int i3) const; + void setUniform(const std::string& name, int i1, int i2) const; + void setUniform(const std::string& name, int i1) const; private: @@ -113,7 +114,7 @@ class Shader * \param name Name of uniform * \return Location, or -1 in case of failure */ - unsigned getUniformLocation(const std::string& name); + unsigned getUniformLocation(const std::string& name) const; /** * \brief Creates a shader based on shader types and source code @@ -138,7 +139,7 @@ class Shader private: unsigned int mRendererId; - std::unordered_map mUniformLocationCache; + mutable std::unordered_map mUniformLocationCache; }; /** diff --git a/AimGL/src/Renderer3D/Sprite2D.cpp b/AimGL/src/Renderer3D/Sprite2D.cpp new file mode 100644 index 0000000..185d6a1 --- /dev/null +++ b/AimGL/src/Renderer3D/Sprite2D.cpp @@ -0,0 +1,107 @@ +#include "Sprite2D.h" +#include "pch.h" + +Sprite2D::Sprite2D(const Texture& texture) + : mTexture(texture) + , mShader{{ShaderType::VertexShader, "resources/Shaders/Graphics/Sprite.vs"}, + {ShaderType::FragmentShader, "resources/Shaders/Graphics/Sprite.fs"}} + , mPosition(0.0f) + , mScale(1.0f) + , mRotation(0.f) +{ + + initializeBuffers(); + setScale(1); + setPosition({0.f, 0.f}); +} + +void Sprite2D::initializeBuffers() +{ + float vertices[] = { + // positions // texture coords + 1.f, 1.f, 1.0f, 1.0f,// top right + 1.f, -1.f, 1.0f, 0.0f,// bottom right + -1.f, -1.f, 0.0f, 0.0f,// bottom left + -1.f, 1.f, 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(2); + mBufferLayout.push(2); + mVAO.setBuffer(mVBO, mBufferLayout); + mVAO.unbind(); +} + +void Sprite2D::draw(const Renderer3D& target) const +{ + // Prepare transformations + mShader.bind(); + mTexture.bind(0); + target.draw(mVAO, mEBO, mShader); +} + +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)); + mShader.bind(); + mShader.setUniform("model", model); + mShader.unbind(); +} + +void Sprite2D::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{mTexture.width(), mTexture.height(), 0.f}; + break; + } + updateModel(); +} + +void Sprite2D::setScale(float newScale) +{ + mScale = {mTexture.width(), mTexture.height()}; + mScale *= newScale; +} + +void Sprite2D::setRotation(float angle) +{ + mRotation = angle; +} + +void Sprite2D::setOpacity(float opacity) +{ + mOpacity = opacity; + mShader.bind(); + mShader.setUniform("opacity", mOpacity); + mShader.unbind(); +} + +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/Sprite2D.h b/AimGL/src/Renderer3D/Sprite2D.h new file mode 100644 index 0000000..b02447d --- /dev/null +++ b/AimGL/src/Renderer3D/Sprite2D.h @@ -0,0 +1,98 @@ +#pragma once +#include "BufferLayout.h" +#include "Renderer3D.h" +#include "Shader.h" +#include "Texture.h" +#include "VertexArray.h" +#include "VertexBuffer.h" + +/** + * \brief A representation of a texture that has its own transformation. + */ +class Sprite2D +{ +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 + */ + Sprite2D(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; + + /** + * \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 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); + + /** + * \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; + float mRotation; + float mOpacity; +}; diff --git a/AimGL/src/Renderer3D/Texture.cpp b/AimGL/src/Renderer3D/Texture.cpp new file mode 100644 index 0000000..cb55eeb --- /dev/null +++ b/AimGL/src/Renderer3D/Texture.cpp @@ -0,0 +1,71 @@ +#include "Texture.h" +#include "pch.h" + +#include "Renderer3D/OpenglUtils.h" + +#define STB_IMAGE_IMPLEMENTATION +#include "stb_image.h" + +Texture::Texture(const std::string& filePath) + : mTextureId(0) + , mFilePath(filePath) + , mData(nullptr) + , mWidth(0) + , mHeight(0) + , mNrChannels(0) +{ + stbi_set_flip_vertically_on_load(true); + mData = stbi_load(filePath.c_str(), &mWidth, &mHeight, &mNrChannels, 0); + GLCall(glGenTextures(1, &mTextureId)); + GLCall(glBindTexture(GL_TEXTURE_2D, mTextureId)); + + GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR)); + GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR)); + GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE)); + GLCall(glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE)); + + if (mData) + { + GLCall(glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, mWidth, mHeight, 0, GL_RGBA, + GL_UNSIGNED_BYTE, mData)); + GLCall(glGenerateMipmap(GL_TEXTURE_2D)); + mAspectRatio = static_cast(mWidth) / static_cast(mHeight); + unbind(); + } + else + { + spdlog::error("Failed to load a texture: {}", filePath); + } + stbi_image_free(mData); +}; + +Texture::~Texture() +{ + GLCall(glDeleteTextures(1, &mTextureId)); +} + +void Texture::bind(unsigned int slot) const +{ + GLCall(glActiveTexture(GL_TEXTURE0 + slot)); + GLCall(glBindTexture(GL_TEXTURE_2D, mTextureId)); +} + +void Texture::unbind() const +{ + GLCall(glBindTexture(GL_TEXTURE_2D, 0)); +} + +int Texture::width() const +{ + return mWidth; +} + +int Texture::height() const +{ + return mHeight; +} + +float Texture::aspectRatio() const +{ + return mAspectRatio; +} diff --git a/AimGL/src/Renderer3D/Texture.h b/AimGL/src/Renderer3D/Texture.h index 300fb2b..51b8920 100644 --- a/AimGL/src/Renderer3D/Texture.h +++ b/AimGL/src/Renderer3D/Texture.h @@ -1,6 +1,55 @@ #pragma once - +/** + * \brief The image, closed in a buffer, lives on the graphics card. + */ class Texture { +public: + /** + * \brief Creates a texture based on the file path to image + * \param filePath Path to the image + */ + Texture(const std::string& filePath); + + /** + * \brief Removes texture + */ + ~Texture(); + + /** + * \brief Binds a texture for rendering + * \param slot Slot to which the texture will be binded (can be obtained from the shader level) + */ + void bind(unsigned int slot = 0) const; + + /** + * \brief Unbinds the texture from rendering + */ + void unbind() const; + + /** + * \brief Returns the width of the texture + * \return Width of the texture + */ + int width() const; + + /** + * \brief Returns the height of the texture + * \return Height of the texture + */ + int height() const; + + /** + * \brief Returns the aspect ratio of the image + * \return Aspect ratio of the image + */ + float aspectRatio() const; + +private: + unsigned int mTextureId; + std::string mFilePath; + unsigned char* mData; + float mAspectRatio; + int mWidth, mHeight, mNrChannels; }; \ No newline at end of file diff --git a/AimGL/src/States/CustomStates/ExitGameState.cpp b/AimGL/src/States/CustomStates/ExitGameState.cpp new file mode 100644 index 0000000..5c2fd20 --- /dev/null +++ b/AimGL/src/States/CustomStates/ExitGameState.cpp @@ -0,0 +1,7 @@ +#include "ExitGameState.h" +#include "pch.h" + +ExitGameState::ExitGameState(StateStack& stack) + : State(stack) +{ +} \ No newline at end of file diff --git a/AimGL/src/States/CustomStates/ExitGameState.h b/AimGL/src/States/CustomStates/ExitGameState.h new file mode 100644 index 0000000..3f9c70b --- /dev/null +++ b/AimGL/src/States/CustomStates/ExitGameState.h @@ -0,0 +1,14 @@ +#pragma once + +#include "States/State.h" + +class StateStack; + +/** + * @brief The state in which the player wants to close the game + */ +class ExitGameState : public State +{ +public: + explicit ExitGameState(StateStack& stack); +}; \ No newline at end of file diff --git a/AimGL/src/States/CustomStates/LogoState.cpp b/AimGL/src/States/CustomStates/LogoState.cpp new file mode 100644 index 0000000..c00db22 --- /dev/null +++ b/AimGL/src/States/CustomStates/LogoState.cpp @@ -0,0 +1,69 @@ +#include "LogoState.h" +#include "States/StateStack.h" +#include "pch.h" + +LogoState::LogoState(StateStack& stack, sf::Window& window) + : State(stack) + , mWindow(window) + , mLogoTexture("resources/Textures/logo.png") + , mLogo(mLogoTexture) + , mRenderer3D(window) + , mPhase(Phase::FadeIn) +{ + 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); +} + +void LogoState::draw(sf::Window& target) const +{ + MTR_SCOPE("SampleState", "SampleState::draw"); + mLogo.draw(mRenderer3D); +} + +bool LogoState::fixedUpdate(const float& deltaTime) +{ + MTR_SCOPE("SampleState", "SampleState::fixedUpdate"); + return true; +} + +bool LogoState::update(const float& deltaTime) +{ + MTR_SCOPE("SampleState", "SampleState::update"); + switch (mPhase) + { + case Phase::FadeIn: + mLogo.setOpacity((mClock.getElapsedTime().asSeconds() / 2.f) - 0.2f); + if (mClock.getElapsedTime().asSeconds() > 3.f) + { + mPhase = Phase::Fadeout; + mClock.restart(); + } + break; + + case Phase::Fadeout: + mLogo.setOpacity(2.f - mClock.getElapsedTime().asSeconds() / 2.f); + if (mClock.getElapsedTime().asSeconds() > 4.f) + { + requestPop(); + requestPush(State_ID::ExitGameState); + } + break; + } + return true; +} + +bool LogoState::handleEvent(const sf::Event& event) +{ + MTR_SCOPE("SampleState", "SampleState::handleEvent"); + return true; +} + +bool LogoState::updateImGui(const float& deltaTime) +{ + MTR_SCOPE("SampleState", "SampleState::updateImGui"); + ImGui::ShowDemoWindow(); + return true; +} diff --git a/AimGL/src/States/CustomStates/SampleState.h b/AimGL/src/States/CustomStates/LogoState.h similarity index 68% rename from AimGL/src/States/CustomStates/SampleState.h rename to AimGL/src/States/CustomStates/LogoState.h index ca209b8..6fcfe41 100644 --- a/AimGL/src/States/CustomStates/SampleState.h +++ b/AimGL/src/States/CustomStates/LogoState.h @@ -1,22 +1,18 @@ #pragma once -#include "Renderer3D/BufferLayout.h" -#include "Renderer3D/IndexBuffer.h" #include "Renderer3D/Renderer3D.h" -#include "Renderer3D/Shader.h" -#include "Renderer3D/Texture.h" -#include "Renderer3D/VertexArray.h" +#include "Renderer3D/Sprite2D.h" #include "States/State.h" class StateStack; /** - * \brief .... + * \brief Game state drawing the game logo */ -class SampleState : public State +class LogoState : public State { public: - SampleState(StateStack& stack, sf::Window& window); + LogoState(StateStack& stack, sf::Window& window); /** * \brief Draws only this state to the passed target @@ -50,11 +46,22 @@ class SampleState : public State bool updateImGui(const float& deltaTime) override; private: - Renderer3D render3D; - Texture mLogo; - VertexArray mVao; - VertexBuffer mVbo; - IndexBuffer mEbo; - BufferLayout mBufferLayout; - Shader mShader; + /** + * \brief This state is divided into two states: + * the state in which the logo fades in and + * the state in which the logo fades out. + */ + enum class Phase + { + FadeIn, + Fadeout + }; + +private: + Renderer3D mRenderer3D; + Texture mLogoTexture; + Sprite2D mLogo; + sf::Clock mClock; + sf::Window& mWindow; + Phase mPhase; }; diff --git a/AimGL/src/States/CustomStates/SampleState.cpp b/AimGL/src/States/CustomStates/SampleState.cpp deleted file mode 100644 index 6f2e2db..0000000 --- a/AimGL/src/States/CustomStates/SampleState.cpp +++ /dev/null @@ -1,56 +0,0 @@ -#include "SampleState.h" -#include "pch.h" - -float verticestest[] = { - 0.5f, 0.5f, 0.0f,// top right - 0.5f, -0.5f, 0.0f,// bottom right - -0.5f, -0.5f, 0.0f,// bottom left - -0.5f, 0.5f, 0.0f // top left -}; -unsigned int indicestest[] = { - // note that we start from 0! - 0, 1, 3,// first Triangle - 1, 2, 3 // second Triangle -}; - -SampleState::SampleState(StateStack& stack, sf::Window& window) - : State(stack) - , mShader{{ShaderType::VertexShader, "resources/Shaders/basic.vs"}, - {ShaderType::FragmentShader, "resources/Shaders/basic.fs"}} -{ - mVbo.setBuffer(verticestest, sizeof(verticestest)); - mEbo.setBuffer(indicestest, sizeof(indicestest)); - mBufferLayout.push(3); - mVao.setBuffer(mVbo, mBufferLayout); -} - -void SampleState::draw(sf::Window& target) const -{ - MTR_SCOPE("SampleState", "SampleState::draw"); - render3D.draw(mVao, mEbo, mShader); -} - -bool SampleState::fixedUpdate(const float& deltaTime) -{ - MTR_SCOPE("SampleState", "SampleState::fixedUpdate"); - return true; -} - -bool SampleState::update(const float& deltaTime) -{ - MTR_SCOPE("SampleState", "SampleState::update"); - return true; -} - -bool SampleState::handleEvent(const sf::Event& event) -{ - MTR_SCOPE("SampleState", "SampleState::handleEvent"); - return true; -} - -bool SampleState::updateImGui(const float& deltaTime) -{ - MTR_SCOPE("SampleState", "SampleState::updateImGui"); - ImGui::ShowDemoWindow(); - return true; -} diff --git a/AimGL/src/States/StateStack.cpp b/AimGL/src/States/StateStack.cpp index 683e848..c6cde3c 100644 --- a/AimGL/src/States/StateStack.cpp +++ b/AimGL/src/States/StateStack.cpp @@ -20,12 +20,19 @@ void StateStack::applyChanges() switch (change.operation) { case Perform::Push: + spdlog::info("[StateStack] Pushing state: {}", toString(change.stateID)); mStack.push_back({change.stateID, createState(change.stateID)}); break; - case Perform::Pop: mStack.pop_back(); break; + case Perform::Pop: + spdlog::info("[StateStack] Poping state from the top ({})", toString(top())); + mStack.pop_back(); + break; - case Perform::Clear: mStack.clear(); break; + case Perform::Clear: + spdlog::info("[StateStack] Clearing the StateStack"); + mStack.clear(); + break; } } mChangesQueue.clear(); @@ -149,5 +156,6 @@ State_ID StateStack::top() const void StateStack::forceInstantClear() { + spdlog::warn("[StateStack] Statestack is forced to clear all its states instantly"); mStack.clear(); } diff --git a/AimGL/src/States/States.h b/AimGL/src/States/States.h index 9968b08..ecd2b0a 100644 --- a/AimGL/src/States/States.h +++ b/AimGL/src/States/States.h @@ -8,12 +8,33 @@ enum class State_ID { // === Application flow states === // None, - SampleState, + LogoState, GameState, PauseState, ExitGameState }; +/** + * \brief Converts state identifier to text + * \param stateId State identifier + * \return Textual representation of the state + */ +inline std::string toString(State_ID stateId) +{ + switch (stateId) + { + + case State_ID::None: return "None"; + case State_ID::LogoState: return "LogoState"; + case State_ID::GameState: return "GameState"; + case State_ID::PauseState: return "PauseState"; + case State_ID::ExitGameState: return "ExitGameState"; + default: + spdlog::warn("I was unable to perform the ID to text conversion."); + return "Unknown State_ID"; + } +} + #endif \ No newline at end of file diff --git a/AimGL/src/pch.h b/AimGL/src/pch.h index 84627dc..dfe0c1f 100644 --- a/AimGL/src/pch.h +++ b/AimGL/src/pch.h @@ -16,7 +16,7 @@ // OpenGL #include -#include +#include #include #include #include diff --git a/AimGL/vendor/CMakeLists.txt b/AimGL/vendor/CMakeLists.txt index 18f1951..966fd53 100644 --- a/AimGL/vendor/CMakeLists.txt +++ b/AimGL/vendor/CMakeLists.txt @@ -9,4 +9,5 @@ add_subdirectory(glew) add_subdirectory(spdlog) add_subdirectory(result) add_subdirectory(entt) -add_subdirectory(minitrace) \ No newline at end of file +add_subdirectory(minitrace) +add_subdirectory(stb) \ No newline at end of file diff --git a/AimGL/vendor/stb/CMakeLists.txt b/AimGL/vendor/stb/CMakeLists.txt new file mode 100644 index 0000000..f455400 --- /dev/null +++ b/AimGL/vendor/stb/CMakeLists.txt @@ -0,0 +1,10 @@ +message(STATUS "Fetching stb...") + +FetchContent_Declare( + stb + GIT_REPOSITORY https://github.com/nothings/stb + GIT_TAG beebb24b945efdea3b9bba23affb8eb3ba8982e7 +) +FetchContent_MakeAvailable(stb) + +message(STATUS "stb Fetched!") \ No newline at end of file