feat(close #14): Implement camera, cube, and input system

This commit is contained in:
Huseyn Ismayilov 2024-08-28 00:24:08 +04:00
parent d80ee75aea
commit 08c63425a3
12 changed files with 364 additions and 63 deletions

View File

@ -1,10 +1,10 @@
#version 330 core
out vec4 fragColor;
out vec4 FragColor;
in vec3 ourColor;
uniform vec3 color;
void main()
{
fragColor = vec4(color, 1.0f) * vec4(ourColor, 1.0f);
FragColor = vec4(ourColor, 1.0) * vec4(color, 1.0);
}

View File

@ -1,13 +1,15 @@
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec3 aColor;
uniform mat4 transform;
layout(location = 0) in vec3 aPos;
layout(location = 1) in vec3 aColor;
out vec3 ourColor;
uniform mat4 model;
uniform mat4 view;
uniform mat4 projection;
void main()
{
gl_Position = transform * vec4(aPos, 1.0f);
gl_Position = projection * view * model * vec4(aPos, 1.0);
ourColor = aColor;
}

65
engine/include/Camera.h Normal file
View File

@ -0,0 +1,65 @@
#pragma once
#include <glad/glad.h>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
enum CameraMovement {
FORWARD,
BACKWARD,
LEFT,
RIGHT,
UP,
DOWN
};
const float YAW = -90.0f;
const float PITCH = 0.0f;
const float SPEED = 2.5f;
const float SENSITIVITY = 0.1f;
const float ZOOM = 45.0f;
class Camera
{
public:
// Camera Attributes
glm::vec3 Position;
glm::vec3 Front;
glm::vec3 Up;
glm::vec3 Right;
glm::vec3 WorldUp;
// Euler Angles
float Yaw;
float Pitch;
// Camera options
float MovementSpeed;
float MouseSensitivity;
float Zoom;
Camera(glm::vec3 position = glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3 up = glm::vec3(0.0f, 1.0f, 0.0f), float yaw = YAW, float pitch = PITCH) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM)
{
Position = position;
WorldUp = up;
Yaw = yaw;
Pitch = pitch;
UpdateCameraVectors();
}
Camera(float posX, float posY, float posZ, float upX, float upY, float upZ, float yaw, float pitch) : Front(glm::vec3(0.0f, 0.0f, -1.0f)), MovementSpeed(SPEED), MouseSensitivity(SENSITIVITY), Zoom(ZOOM)
{
Position = glm::vec3(posX, posY, posZ);
WorldUp = glm::vec3(upX, upY, upZ);
Yaw = yaw;
Pitch = pitch;
UpdateCameraVectors();
}
glm::mat4 GetViewMatrix() const;
glm::mat4 LookAt(glm::vec3 position, glm::vec3 direction, glm::vec3 up);
void ProcessKeyboard(CameraMovement direction, float deltaTime);
void ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true);
void ProcessMouseScroll(float yoffset);
private:
void UpdateCameraVectors();
};

View File

@ -0,0 +1,20 @@
#pragma once
#include <glad/glad.h>
class IndexBuffer
{
public:
IndexBuffer();
~IndexBuffer();
static IndexBuffer Create();
void Bind() const;
static void Unbind();
void SetData(int size, const void* data) const;
void Shutdown() const;
private:
unsigned int m_IBO{};
};

View File

@ -5,19 +5,22 @@
#include <iostream>
#include "VertexArray.h"
#include "VertexBuffer.h"
#include "IndexBuffer.h"
#include "FrameBuffer.h"
#include "Window.h"
#include "Shader.h"
#include "Texture.h"
#include "UI.h"
#include "Camera.h"
struct RendererData
{
VertexArray* m_VAO;
VertexBuffer* m_VBO;
IndexBuffer* m_IBO;
FrameBuffer* m_FBO;
Camera* m_Camera;
Shader* m_Shader;
Texture* m_Texture;
};
class Renderer
@ -37,4 +40,13 @@ private:
static void LoadShaders();
static void SetupBuffers();
static void SetCallbacks();
static void ProcessInput(GLFWwindow* window);
static float deltaTime;
static float lastFrame;
static bool firstMouse;
static float lastX;
static float lastY;
};

View File

@ -8,10 +8,11 @@
struct InspectorData
{
float m_Position[3];
float m_Rotation[3];
float m_Scale[3];
float m_Color[3] = {1.0f, 1.0f, 1.0f};
glm::vec3 m_Position;
glm::vec3 m_Rotation;
glm::vec3 m_Scale = {1.0f, 1.0f, 1.0f};
glm::vec3 m_ShaderColor = {1.0f, 1.0f, 1.0f};
glm::vec3 m_BgColor = {0.0, 0.1f, 0.2f};
};
class UI
@ -37,4 +38,7 @@ public:
private:
static InspectorData s_Data;
static std::string m_Log;
static ImVec4* m_StyleColors;
};

64
engine/src/Camera.cpp Normal file
View File

@ -0,0 +1,64 @@
#include "Camera.h"
glm::mat4 Camera::GetViewMatrix() const
{
return glm::lookAt(Position, Position + Front, Up);
}
void Camera::ProcessKeyboard(CameraMovement direction, float deltaTime)
{
float velocity = MovementSpeed * deltaTime;
if (direction == FORWARD)
Position += Front * velocity;
if (direction == BACKWARD)
Position -= Front * velocity;
if (direction == LEFT)
Position -= Right * velocity;
if (direction == RIGHT)
Position += Right * velocity;
if (direction == UP)
Position += Up * velocity;
if (direction == DOWN)
Position -= Up * velocity;
}
void Camera::ProcessMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch)
{
xoffset *= MouseSensitivity;
yoffset *= MouseSensitivity;
Yaw += xoffset;
Pitch += yoffset;
// make sure that when pitch is out of bounds, screen doesn't get flipped
if (constrainPitch)
{
if (Pitch > 89.0f)
Pitch = 89.0f;
if (Pitch < -89.0f)
Pitch = -89.0f;
}
// update Front, Right and Up Vectors using the updated Euler angles
UpdateCameraVectors();
}
void Camera::ProcessMouseScroll(float yoffset)
{
Zoom -= (float)yoffset;
if (Zoom < 1.0f)
Zoom = 1.0f;
if (Zoom > 45.0f)
Zoom = 45.0f;
}
void Camera::UpdateCameraVectors()
{
glm::vec3 front;
front.x = cos(glm::radians(Yaw)) * cos(glm::radians(Pitch));
front.y = sin(glm::radians(Pitch));
front.z = sin(glm::radians(Yaw)) * cos(glm::radians(Pitch));
Front = glm::normalize(front);
Right = glm::normalize(glm::cross(Front, WorldUp));
Up = glm::normalize(glm::cross(Right, Front));
}

View File

@ -9,7 +9,6 @@ Engine::Engine()
m_Window = new Window();
Renderer::Init();
UI::Init(m_Window->GetWindow());
}
Engine::~Engine()

View File

@ -52,7 +52,7 @@ void FrameBuffer::RescaleFrameBuffer(int width, int height) const
{
m_Texture->Bind();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
Texture::ToImage(width, height, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, m_Texture->GetID(), 0);

View File

@ -0,0 +1,36 @@
#include "IndexBuffer.h"
IndexBuffer::IndexBuffer()
{
glGenBuffers(1, &m_IBO);
}
IndexBuffer::~IndexBuffer()
{
Shutdown();
}
IndexBuffer IndexBuffer::Create()
{
return IndexBuffer{};
}
void IndexBuffer::Bind() const
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_IBO);
}
void IndexBuffer::Unbind()
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
}
void IndexBuffer::SetData(int size, const void* data) const
{
Bind();
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size, data, GL_STATIC_DRAW);
}
void IndexBuffer::Shutdown() const
{
glDeleteBuffers(1, &m_IBO);
}

View File

@ -4,6 +4,33 @@
RendererData Renderer::s_Data;
float Renderer::deltaTime = 0.0f;
float Renderer::lastFrame = 0.0f;
bool Renderer::firstMouse = true;
float Renderer::lastX;
float Renderer::lastY;
float vertices[] = {
-0.5f, -0.5f, -0.5f, 1.0f, 0.0f, 0.0f,
0.5f, -0.5f, -0.5f, 0.0f, 1.0f, 0.0f,
0.5f, 0.5f, -0.5f, 0.0f, 0.0f, 1.0f,
-0.5f, 0.5f, -0.5f, 1.0f, 1.0f, 0.0f,
-0.5f, -0.5f, 0.5f, 0.0f, 1.0f, 1.0f,
0.5f, -0.5f, 0.5f, 1.0f, 0.0f, 1.0f,
0.5f, 0.5f, 0.5f, 1.0f, 1.0f, 1.0f,
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f, 0.0f,
};
unsigned int indices[] = {
0, 1, 2, 2, 3, 0,
4, 5, 6, 6, 7, 4,
0, 1, 5, 5, 4, 0,
2, 3, 7, 7, 6, 2,
0, 3, 7, 7, 4, 0,
1, 2, 6, 6, 5, 1
};
Renderer::Renderer() = default;
Renderer::~Renderer()
@ -13,22 +40,17 @@ Renderer::~Renderer()
void Renderer::Init()
{
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
if (!gladLoadGLLoader(reinterpret_cast<GLADloadproc>(glfwGetProcAddress))) {
std::cerr << "Failed to initialize GLAD" << std::endl;
return;
}
UI::Init(Engine::Get().GetWindow().GetWindow());
s_Data.m_Camera = new Camera(glm::vec3(0.0f, 0.0f, 3.0f));
LoadShaders();
SetupBuffers();
glfwSetWindowSizeCallback(Engine::Get().GetWindow().GetWindow(), [](GLFWwindow* window, int width, int height)
{
SetupBuffers();
});
glfwSetFramebufferSizeCallback(Engine::Get().GetWindow().GetWindow(), [](GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
});
SetCallbacks();
}
RendererData Renderer::GetData()
@ -43,61 +65,144 @@ void Renderer::LoadShaders()
void Renderer::SetupBuffers()
{
float vertices[] = {
0.5f, -0.5f, 0.0f, 1.0f, 0.0f, 0.0f,
-0.5f, -0.5f, 0.0f, 0.0f, 1.0f, 0.0f,
0.0f, 0.5f, 0.0f, 0.0f, 0.0f, 1.0f
};
s_Data.m_FBO = new FrameBuffer();
WindowSize windowSize = Engine::Get().GetWindow().GetSize();
s_Data.m_FBO->AttachTexture(windowSize.Width, windowSize.Height);
s_Data.m_VAO = new VertexArray();
s_Data.m_VBO = new VertexBuffer();
s_Data.m_IBO = new IndexBuffer();
s_Data.m_VAO->Bind();
s_Data.m_VBO->SetData(sizeof(vertices), vertices);
s_Data.m_IBO->SetData(sizeof(indices), indices);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), nullptr);
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), (void*)(3 * sizeof(float)));
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6 * sizeof(float), reinterpret_cast<void*>(3 * sizeof(float)));
glEnableVertexAttribArray(1);
VertexArray::Unbind();
VertexBuffer::Unbind();
IndexBuffer::Unbind();
s_Data.m_FBO = new FrameBuffer();
WindowSize windowSize = Engine::Get().GetWindow().GetSize();
s_Data.m_FBO->AttachTexture(windowSize.Width, windowSize.Height);
FrameBuffer::Unbind();
}
void Renderer::SetCallbacks()
{
glfwSetWindowSizeCallback(Engine::Get().GetWindow().GetWindow(), [](GLFWwindow* window, int width, int height)
{
SetupBuffers();
});
glfwSetFramebufferSizeCallback(Engine::Get().GetWindow().GetWindow(), [](GLFWwindow* window, int width, int height)
{
glViewport(0, 0, width, height);
});
glfwSetScrollCallback(Engine::Get().GetWindow().GetWindow(), [](GLFWwindow* window, double xOffset, double yOffset)
{
s_Data.m_Camera->ProcessMouseScroll(static_cast<float>(yOffset));
});
}
void Renderer::Render() {
auto currentFrame = static_cast<float>(glfwGetTime());
deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
s_Data.m_FBO->Bind();
glfwPollEvents();
glClearColor(0.0f, 0.1f, 0.2f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
ProcessInput(Engine::Get().GetWindow().GetWindow());
glEnable(GL_DEPTH_TEST);
glm::vec3 color = UI::GetData().m_BgColor;
glClearColor(color.x, color.y, color.z, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
UI::Run();
s_Data.m_Shader->Use();
auto transform = glm::mat4(1.0f);
transform = glm::translate(transform, glm::vec3(UI::GetData().m_Position[0], UI::GetData().m_Position[1], UI::GetData().m_Position[2]));
glUniformMatrix4fv(s_Data.m_Shader->GetUniformLocation("transform"), 1, GL_FALSE, glm::value_ptr(transform));
glUniform3fv(s_Data.m_Shader->GetUniformLocation("color"), 1, UI::GetData().m_Color);
auto model = glm::mat4(1.0f);
model = glm::translate(model, UI::GetData().m_Position);
if(glm::length(UI::GetData().m_Rotation) != 0)
model = glm::rotate(model, glm::radians(length(UI::GetData().m_Rotation)), normalize(UI::GetData().m_Rotation));
model = glm::scale(model, UI::GetData().m_Scale);
glm::mat4 view = s_Data.m_Camera->GetViewMatrix();
WindowSize size = Engine::Get().GetWindow().GetSize();
glm::mat4 projection = glm::perspective(glm::radians(45.0f), static_cast<float>(size.Width) / static_cast<float>(size.Height), 0.1f, 100.0f);
glUniformMatrix4fv(s_Data.m_Shader->GetUniformLocation("model"), 1, GL_FALSE, glm::value_ptr(model));
glUniformMatrix4fv(s_Data.m_Shader->GetUniformLocation("view"), 1, GL_FALSE, glm::value_ptr(view));
glUniformMatrix4fv(s_Data.m_Shader->GetUniformLocation("projection"), 1, GL_FALSE, glm::value_ptr(projection));
glUniform3fv(s_Data.m_Shader->GetUniformLocation("color"), 1, glm::value_ptr(UI::GetData().m_ShaderColor));
s_Data.m_VAO->Bind();
glDrawArrays(GL_TRIANGLES, 0, 3);
FrameBuffer::Unbind();
glDrawElements(GL_TRIANGLES, 36, GL_UNSIGNED_INT, nullptr);
glBindFramebuffer(GL_FRAMEBUFFER, 0);
UI::Render(*s_Data.m_FBO);
glfwSwapBuffers(Engine::Get().GetWindow().GetWindow());
}
void Renderer::ProcessInput(GLFWwindow *window)
{
if(glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_2) == GLFW_PRESS)
{
double xPosIn, yPosIn;
glfwGetCursorPos(window, &xPosIn, &yPosIn);
auto xPos = static_cast<float>(xPosIn);
auto yPos = static_cast<float>(yPosIn);
if(firstMouse)
{
lastX = xPos;
lastY = yPos;
firstMouse = false;
}
float xOffset = xPos - lastX;
float yOffset = lastY - yPos;
lastX = xPos;
lastY = yPos;
s_Data.m_Camera->ProcessMouseMovement(xOffset, yOffset);
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED);
}
else
{
glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL);
}
if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS)
s_Data.m_Camera->ProcessKeyboard(FORWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS)
s_Data.m_Camera->ProcessKeyboard(BACKWARD, deltaTime);
if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS)
s_Data.m_Camera->ProcessKeyboard(LEFT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS)
s_Data.m_Camera->ProcessKeyboard(RIGHT, deltaTime);
if (glfwGetKey(window, GLFW_KEY_Q) == GLFW_PRESS)
s_Data.m_Camera->ProcessKeyboard(DOWN, deltaTime);
if (glfwGetKey(window, GLFW_KEY_E) == GLFW_PRESS)
s_Data.m_Camera->ProcessKeyboard(UP, deltaTime);
}
void Renderer::Shutdown()
{
s_Data.m_VAO->Shutdown();
s_Data.m_VBO->Shutdown();
s_Data.m_FBO->Shutdown();
s_Data.m_IBO->Shutdown();
s_Data.m_Shader->Shutdown();
s_Data.m_Texture->Shutdown();
}

View File

@ -5,10 +5,9 @@
#include "FrameBuffer.h"
#include "Window.h"
static ImVec4 m_ClearColor;
static ImVec4* m_StyleColors;
static std::string m_Log;
InspectorData UI::s_Data;
std::string UI::m_Log;
ImVec4* UI::m_StyleColors;
UI::UI()= default;
@ -16,11 +15,10 @@ UI::~UI()= default;
void UI::Init(GLFWwindow* window)
{
m_ClearColor = ImVec4(0.0f, 0.0f, 0.0f, 1.00f);
IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO(); (void)io;
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;
ImGuiStyle& style = ImGui::GetStyle();
@ -48,7 +46,7 @@ void UI::Run()
ImGui_ImplGlfw_NewFrame();
ImGui::NewFrame();
ImGui::DockSpaceOverViewport(ImGui::GetMainViewport());
m_StyleColors[ImGuiCol_DockingEmptyBg] = m_ClearColor;
m_StyleColors[ImGuiCol_DockingEmptyBg] = ImVec4(s_Data.m_BgColor.x, s_Data.m_BgColor.y, s_Data.m_BgColor.z, 1.0f);
}
void UI::Render(const FrameBuffer& sceneBuffer)
@ -109,19 +107,19 @@ void UI::ShowInspector()
{
ImGui::Begin("Inspector");
ImGui::SeparatorText("Triangle");
ImGui::SeparatorText("Cube");
ImGui::BeginGroup();
{
ImGui::Text("Transform");
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(1.0f, 0.0f, 0.0f, 1.0f));
ImGui::DragFloat3("Position", s_Data.m_Position, 0.2f);
ImGui::DragFloat3("Position", glm::value_ptr(s_Data.m_Position), 0.2f);
ImGui::PopStyleColor();
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 1.0f, 0.0f, 1.0f));
ImGui::DragFloat3("Rotation", s_Data.m_Rotation, 0.4f);
ImGui::DragFloat3("Rotation", glm::value_ptr(s_Data.m_Rotation), 0.4f);
ImGui::PopStyleColor();
ImGui::PushStyleColor(ImGuiCol_FrameBg, ImVec4(0.0f, 0.0f, 1.0f, 1.0f));
ImGui::DragFloat3("Scale", s_Data.m_Scale, 0.1f);
ImGui::DragFloat3("Scale", glm::value_ptr(s_Data.m_Scale), 0.1f);
ImGui::PopStyleColor();
}
ImGui::EndGroup();
@ -130,8 +128,8 @@ void UI::ShowInspector()
ImGui::BeginGroup();
ImGui::Text("Colors");
ImGui::ColorEdit3("Shader Color", s_Data.m_Color);
ImGui::ColorEdit3("Clear Color", (float*)&m_ClearColor);
ImGui::ColorEdit3("Shader Color", glm::value_ptr(s_Data.m_ShaderColor));
ImGui::ColorEdit3("Background Color", glm::value_ptr(s_Data.m_BgColor));
ImGui::EndGroup();
ImGui::End();
@ -162,16 +160,12 @@ void UI::ShowScene(const FrameBuffer& sceneBuffer)
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2{0, 0});
ImGui::Begin("Scene");
{
ImGui::BeginChild("GameRender");
ImGui::Image(
(ImTextureID)sceneBuffer.GetFrameTexture()->GetID(),
ImGui::GetContentRegionAvail(),
ImVec2(0, 1),
ImVec2(1, 0)
);
ImGui::EndChild();
}
ImGui::End();
ImGui::PopStyleVar();