Skip to content

Commit

Permalink
Refactored renderer, fixed UV
Browse files Browse the repository at this point in the history
  • Loading branch information
DronCode committed Oct 11, 2023
1 parent 72cc846 commit 13ebe2e
Show file tree
Hide file tree
Showing 17 changed files with 1,044 additions and 498 deletions.
140 changes: 140 additions & 0 deletions BMEdit/Editor/Include/Render/Camera.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
#pragma once

#include <glm/gtc/matrix_transform.hpp>
#include <glm/vec3.hpp>
#include <glm/mat4x4.hpp>
#include <glm/mat3x3.hpp>
#include <glm/glm.hpp>


namespace render
{
// Defines several possible options for camera movement. Used as abstraction to stay away from window-system specific input methods
enum Camera_Movement {
FORWARD,
BACKWARD,
LEFT,
RIGHT
};

// Default camera values
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;

/**
* @credits https://learnopengl.com/Getting-started/Camera
*/
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;

// constructor with vectors
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();
}

// constructor with scalar values
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();
}

void setPosition(const glm::vec3& position)
{
Position = position;
updateCameraVectors();
}

// returns the view matrix calculated using Euler Angles and the LookAt Matrix
glm::mat4 getViewMatrix()
{
return glm::lookAt(Position, Position + Front, Up);
}

// processes input received from any keyboard-like input system. Accepts input parameter in the form of camera defined ENUM (to abstract it from windowing systems)
void processKeyboard(Camera_Movement direction, float deltaTime, float moveScale = 1.f)
{
float velocity = MovementSpeed * deltaTime * moveScale;
if (direction == FORWARD)
Position -= Front * velocity;
if (direction == BACKWARD)
Position += Front * velocity;
if (direction == LEFT)
Position -= Right * velocity;
if (direction == RIGHT)
Position += Right * velocity;
}

// processes input received from a mouse input system. Expects the offset value in both the x and y direction.
void processMouseMovement(float xoffset, float yoffset, GLboolean constrainPitch = true)
{
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();
}

// processes input received from a mouse scroll-wheel event. Only requires input on the vertical wheel-axis
void processMouseScroll(float yoffset)
{
Zoom -= (float)yoffset;
if (Zoom < 1.0f)
Zoom = 1.0f;
if (Zoom > 45.0f)
Zoom = 45.0f;
}

private:
// calculates the front vector from the Camera's (updated) Euler Angles
void updateCameraVectors()
{
// calculate the new Front vector
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);
// also re-calculate the Right and Up vector
Right = glm::normalize(glm::cross(Front, WorldUp)); // normalize the vectors, because their length gets closer to 0 the more you look up or down which results in slower movement.
Up = glm::normalize(glm::cross(Right, Front));
}
};
}
9 changes: 9 additions & 0 deletions BMEdit/Editor/Include/Render/GLResource.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
#pragma once

#include <QOpenGLFunctions>


namespace render
{
static constexpr GLuint kInvalidResource = 0xFDEADC0D;
}
17 changes: 17 additions & 0 deletions BMEdit/Editor/Include/Render/GlacierVertex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
#pragma once

#include <Render/VertexFormatDescription.h>
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>


namespace render
{
struct GlacierVertex
{
glm::vec3 vPos {};
glm::vec2 vUV {};

static const VertexFormatDescription g_FormatDescription;
};
}
141 changes: 141 additions & 0 deletions BMEdit/Editor/Include/Render/Model.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
#pragma once

#include <QOpenGLFunctions_3_3_Core>
#include <Render/VertexFormatDescription.h>
#include <Render/RenderTopology.h>
#include <GameLib/BoundingBox.h>
#include <Render/GLResource.h>
#include <cstdint>
#include <vector>


namespace render
{
class Mesh
{
private:
VertexFormatDescription m_vertexFormat {};
uint32_t m_maxVerticesNr { 0u };
uint32_t m_maxIndicesNr { 0u };
bool m_bIsDynamic { false };

public:
GLuint vao { kInvalidResource };
GLuint vbo { kInvalidResource };
GLuint ibo { kInvalidResource };
GLuint glTextureId { kInvalidResource }; /// Render OpenGL texture resource handle
uint16_t materialId { 0 }; /// Id of material from Glacier mesh (just copy)

int trianglesCount { 0 };

[[nodiscard]] bool isDynamic() const { return m_bIsDynamic; }

/**
* @brief Construct and upload vertex data into VAO + VBO + IBO
* @note For dynamic buffers allowed to use upload(...) method. Otherwise it will do nothing
* @tparam TVertex
* @param gapi
* @param vertexFormat
* @param vertices
* @param indices
* @param bIsDynamic
* @return
*/
template <typename TVertex>
bool setup(QOpenGLFunctions_3_3_Core* gapi, const VertexFormatDescription& vertexFormat, const std::vector<TVertex>& vertices, const std::vector<uint16_t>& indices, bool bIsDynamic)
{
if (vao != kInvalidResource || vbo != kInvalidResource || ibo != kInvalidResource)
{
assert(false && "Need discard resource before create a new one!");
return false;
}

if (!gapi || vertexFormat.getEntries().empty() || vertices.empty())
return false;

return setup(gapi,
vertexFormat,
reinterpret_cast<const uint8_t*>(vertices.data()), static_cast<uint32_t>(vertices.size()),
indices.empty() ? nullptr : reinterpret_cast<const uint8_t*>(indices.data()), indices.empty() ? 0 : static_cast<uint32_t>(indices.size()),
bIsDynamic);
}

/**
* @brief Update vertex and index buffer (able to update only vertex buffer, but unable to update only index buffer because it may be a root of inconsistent)
* @note This method will return false when not enough space in buffer (initialized at setup)!
* @note This method will return false when user trying to upload index buffer without initialise index buffer in setup!
* @tparam TVertex
* @param gapi
* @param vertices
* @param indices
* @return
*/
template <typename TVertex>
bool update(QOpenGLFunctions_3_3_Core* gapi, uint32_t verticesOffset, const std::vector<TVertex>& vertices, uint32_t indicesOffset = 0, const std::vector<uint16_t>& indices = {})
{
if (!gapi || vertices.empty())
return false;

if (!m_bIsDynamic)
return false;

if (vao == kInvalidResource || vbo == kInvalidResource)
{
assert(false && "Call setup() before update!");
return false;
}

return update(gapi,
verticesOffset, reinterpret_cast<const uint8_t*>(vertices.data()), static_cast<uint32_t>(vertices.size()),
indicesOffset, indices.empty() ? nullptr : reinterpret_cast<const uint8_t*>(indices.data()), indices.empty() ? 0 : static_cast<uint32_t>(indices.size()));
}

/**
* @brief Discard all resources and makes object invalid
* @param gapi
*/
void discard(QOpenGLFunctions_3_3_Core* gapi);

/**
* @brief Do render of mesh
* @param gapi
* @param topology - which element topology stored inside buffer
*/
void render(QOpenGLFunctions_3_3_Core* gapi, RenderTopology topology = RenderTopology::RT_TRIANGLES) const;

private:
/**
* @brief Create & upload vertices & indices into a single mesh
* @param gapi
* @param vertexFormat
* @param vertices
* @param verticesCount
* @param indices
* @param indicesCount
* @return true if everything is ok
*/
bool setup(QOpenGLFunctions_3_3_Core* gapi, const VertexFormatDescription& vertexFormat, const uint8_t* vertices, uint32_t verticesCount, const uint8_t* indices, uint32_t indicesCount, bool bDynamic);

/**
* @brief Update vertex & index buffer (or only vertex buffer)
* @param gapi
* @param verticesOffset
* @param vertices
* @param verticesCount
* @param indices
* @param indicesCount
* @param indicesOffset
* @return
*/
bool update(QOpenGLFunctions_3_3_Core* gapi, uint32_t verticesOffset, const uint8_t* vertices, uint32_t verticesCount, uint32_t indicesOffset, const uint8_t* indices, uint32_t indicesCount);
};

struct Model
{
std::vector<Mesh> meshes {};
gamelib::BoundingBox boundingBox {};
[[maybe_unused]] uint32_t chunkId {0u};

void discard(QOpenGLFunctions_3_3_Core* gapi);
};
}
19 changes: 19 additions & 0 deletions BMEdit/Editor/Include/Render/RenderTopology.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
#pragma once

#include <cstdint>


namespace render
{
enum class RenderTopology : uint8_t
{
RT_NONE = 0,
RT_POINTS,
RT_LINES,
RT_LINE_STRIP,
RT_LINE_LOOP,
RT_TRIANGLES,
RT_TRIANGLE_STRIP,
RT_TRIANGLE_FAN
};
}
46 changes: 46 additions & 0 deletions BMEdit/Editor/Include/Render/Shader.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
#pragma once

#include <QOpenGLFunctions_3_3_Core>
#include <Render/GLResource.h>
#include <glm/vec2.hpp>
#include <glm/vec3.hpp>
#include <glm/vec4.hpp>
#include <glm/mat3x3.hpp>
#include <glm/mat4x4.hpp>


namespace render
{
struct Shader
{
GLuint vertexProgramId { kInvalidResource };
GLuint fragmentProgramId { kInvalidResource };
GLuint programId { kInvalidResource };

Shader() = default;

void discard(QOpenGLFunctions_3_3_Core* gapi);

void bind(QOpenGLFunctions_3_3_Core* gapi);

void unbind(QOpenGLFunctions_3_3_Core* gapi);

bool compile(QOpenGLFunctions_3_3_Core* gapi, const std::string& vertexProgram, const std::string& fragmentProgram, std::string& error);

void setUniform(QOpenGLFunctions_3_3_Core* gapi, const std::string& id, float s);
void setUniform(QOpenGLFunctions_3_3_Core* gapi, const std::string& id, std::int32_t s);
void setUniform(QOpenGLFunctions_3_3_Core* gapi, const std::string& id, const glm::vec2& v);
void setUniform(QOpenGLFunctions_3_3_Core* gapi, const std::string& id, const glm::ivec2& v);
void setUniform(QOpenGLFunctions_3_3_Core* gapi, const std::string& id, const glm::vec3& v);
void setUniform(QOpenGLFunctions_3_3_Core* gapi, const std::string& id, const glm::vec4& v);
void setUniform(QOpenGLFunctions_3_3_Core* gapi, const std::string& id, const glm::mat3& v);
void setUniform(QOpenGLFunctions_3_3_Core* gapi, const std::string& id, const glm::mat4& v);
GLint resolveLocation(QOpenGLFunctions_3_3_Core* gapi, const std::string& id);

private:
bool compileUnit(QOpenGLFunctions_3_3_Core* gapi, GLuint unitId, GLenum unitType, const std::string& unitSource, std::string& error);

private:
std::map<std::string, GLint> m_locationsCache;
};
}
13 changes: 13 additions & 0 deletions BMEdit/Editor/Include/Render/ShaderConstants.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#pragma once


namespace render
{
struct ShaderConstants
{
static constexpr const char* kModelTransform = "i_uTransform.model";
static constexpr const char* kCameraProjection = "i_uCamera.proj";
static constexpr const char* kCameraView = "i_uCamera.view";
static constexpr const char* kCameraResolution = "i_uCamera.resolution";
};
}
Loading

0 comments on commit 13ebe2e

Please sign in to comment.