Skip to content

Commit

Permalink
refactor: added lepus::engine::objects::Mesh and lepus::gfx::GLMesh (#37
Browse files Browse the repository at this point in the history
)

* refactor: added early Mesh and GLMesh class

* chore: fixed missing header on linux

* refactor: replaced single global VBO/IBO in ApiGL with GLMesh

* chore: removed unnecessary header include

* chore: fixed header path

* chore: fixed incorrect type qualifiers

* refactor: added GLMesh copy/move constructors

* docs: added comments

* chore: fixed typo in CMakeLists

* docs: update comment

* fix: fixed wrong index count in GraphicsApiGL::Draw()

* fix: fixed extra copy
  • Loading branch information
tomezpl authored Dec 31, 2023
1 parent 27a0b40 commit 71ff1ad
Show file tree
Hide file tree
Showing 8 changed files with 693 additions and 201 deletions.
17 changes: 11 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,9 @@ include_directories(${CMAKE_SOURCE_DIR}/3rdparty/imgui)
add_executable(LepusDemo src/examples/demo/DemoApp.h src/examples/demo/main.cpp)

# LepusUtility
file(GLOB_RECURSE LEPUSUTILITY_HEADERS ${LEPUS_SRC_DIR}/utility/*.h ${LEPUS_SRC_DIR}/utility/**/*.h)
add_custom_target(LepusUtility SOURCES ${LEPUSUTILITY_HEADERS})
source_group(TREE ${LEPUS_SRC_DIR}/utility FILES ${LEPUSUTILITY_HEADERS})
# file(GLOB_RECURSE LEPUSUTILITY_HEADERS ${LEPUS_SRC_DIR}/utility/*.h ${LEPUS_SRC_DIR}/utility/**/*.h)
# add_custom_target(LepusUtility SOURCES ${LEPUSUTILITY_HEADERS})
# source_group(TREE ${LEPUS_SRC_DIR}/utility FILES ${LEPUSUTILITY_HEADERS})

# LepusGfx shaders
file(GLOB LEPUS3D_SHADERS_SRC ${CMAKE_SOURCE_DIR}/Content/GLSL/*.frag ${CMAKE_SOURCE_DIR}/Content/GLSL/*.vert)
Expand All @@ -90,6 +90,11 @@ file(GLOB_RECURSE LepusEngine_SRC ${LEPUS_SRC_DIR}/engine/*.h ${LEPUS_SRC_DIR}/e
add_library(LepusEngine ${LepusEngine_SRC})
source_group(TREE ${LEPUS_SRC_DIR}/engine FILES ${LepusEngine_SRC})

# LepusUtility sources
file(GLOB_RECURSE LepusUtility_SRC ${LEPUS_SRC_DIR}/utility/*.h ${LEPUS_SRC_DIR}/utility/*.cpp ${LEPUS_SRC_DIR}/utility/**/*.h ${LEPUS_SRC_DIR}/utility/**/*.cpp)
add_library(LepusUtility ${LepusUtility_SRC})
source_group(TREE ${LEPUS_SRC_DIR}/utility FILES ${LepusUtility_SRC})

# LepusSystem sources
file(GLOB_RECURSE LepusSystem_SRC ${LEPUS_SRC_DIR}/system/*.h ${LEPUS_SRC_DIR}/system/*.cpp ${LEPUS_SRC_DIR}/system/**/*.h ${LEPUS_SRC_DIR}/system/**/*.cpp)
add_library(LepusSystem ${LepusSystem_SRC})
Expand Down Expand Up @@ -155,8 +160,8 @@ if(OpenGL::GL)
elseif(OpenGL::OpenGL)
set(GL_LIBRARY OpenGL::OpenGL)
endif(OpenGL::GL)
target_link_libraries(LepusGfx PRIVATE GL3W glfw ${GL_LIBRARY} DearImgui LepusEngine LepusSystem)
target_link_libraries(LepusDemo PRIVATE DearImgui LepusGfx LepusEngine)
target_link_libraries(LepusGfx PRIVATE GL3W glfw ${GL_LIBRARY} DearImgui LepusEngine LepusUtility LepusSystem)
target_link_libraries(LepusDemo PRIVATE DearImgui LepusGfx LepusUtility LepusEngine)

# Copy content (models, GLSL, etc.)
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/Content)
Expand Down Expand Up @@ -230,4 +235,4 @@ else()
foreach(Target IN LISTS LepusTargets)
target_compile_options(${Target} PRIVATE -Wall -Wextra -Wpedantic)
endforeach()
endif()
endif()
298 changes: 298 additions & 0 deletions src/lepus/engine/Objects/Mesh.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,298 @@
#ifndef LEPUS_ENGINE_OBJECTS_MESH
#define LEPUS_ENGINE_OBJECTS_MESH

#include <cstdlib>
#include <memory>
#include <lepus/utility/Primitives.h>

namespace lepus
{
namespace engine
{
/// @brief Different vertex formats supported by the engine.
enum MeshVertexFormat
{
/// @brief (Default) 3 positional components (XYZ) for each vertex
VVV,
Invalid
};

namespace objects
{
/// @brief Base class for Mesh data in the engine.
///
/// Can be specialised for different parts of the engine (e.g.rendering, physics) by inheriting and adding API-specific logic as needed.
class Mesh
{
private:
/// @brief The vertex format used by the mesh data.
MeshVertexFormat m_Format = MeshVertexFormat::Invalid;

/// @brief Vertex data
void* m_Vertices = nullptr;
size_t m_szVertices = 0;

/// @brief Index data (optional, but common enough to be included in the base class for simplicity's sake)
uint32_t* m_Indices = nullptr;
size_t m_IndexCount = 0;

/// @brief Does this Mesh own the vertex/index data? If true, this Mesh will delete the data when Dispose is called.
bool m_OwnData = false;

/// @brief Is the Mesh indexed?
bool m_IsIndexed = false;

protected:
inline void CopyInternal(const Mesh& other)
{
m_Format = other.m_Format;
m_Vertices = other.m_Vertices;
m_szVertices = other.m_szVertices;
m_IndexCount = other.m_IndexCount;
m_Indices = other.m_Indices;
m_IsIndexed = other.m_IsIndexed;

// We're not making a copy of the data, so we don't own it.
// TODO: Add some kind of reference counting via a resource manager, so if we copy an existing mesh, its data doesn't get disposed until its copies are.
m_OwnData = false;
}

/// @brief Always called after constructing a new Mesh instance (excluding move/copy ctors).
inline virtual void InitInternal()
{

}

inline void MoveInternal(Mesh& other)
{
m_Format = other.m_Format;

m_Vertices = other.m_Vertices;
m_szVertices = other.m_szVertices;

m_Indices = other.m_Indices;
m_IndexCount = other.m_IndexCount;

m_IsIndexed = other.m_IsIndexed;
m_OwnData = other.m_OwnData;

other.m_Format = MeshVertexFormat::Invalid;
other.m_IndexCount = 0;
other.m_szVertices = 0;
other.m_Indices = nullptr;
other.m_Vertices = nullptr;
other.m_OwnData = false;
other.m_IsIndexed = false;
}

#define LEPUS_MESH_CONSTRUCTOR(MeshClass) \
public:\
inline MeshClass(lepus::engine::MeshVertexFormat format = lepus::engine::MeshVertexFormat::VVV) {Init(format);} \
inline MeshClass(const lepus::utility::Primitive& primitive, bool copy = false) {Init((void*)primitive.GetVertices(), primitive.VertexBufferSize(), lepus::engine::MeshVertexFormat::VVV, (uint32_t*)primitive.GetIndices(), primitive.IndexCount(), copy);} \
inline MeshClass(void* vertices, size_t szVertices, lepus::engine::MeshVertexFormat format = lepus::engine::MeshVertexFormat::VVV, uint32_t* indices = nullptr, size_t indexCount = 0, bool copy = false) {Init(vertices, szVertices, format, indices, indexCount, copy);} \
inline virtual ~MeshClass() {Dispose();}

LEPUS_MESH_CONSTRUCTOR(Mesh);

public:

/// @brief Copy constructor
/// @param other Mesh object to copy
Mesh(const Mesh& other)
{
CopyInternal(other);
}

/// @brief Copy assignment
/// @param other Mesh object to copy
/// @return
Mesh& operator=(const Mesh& other)
{
CopyInternal(other);
return *this;
}

/// @brief Move constructor
/// @param other Rvalue to initialise the Mesh object with.
Mesh(Mesh&& other)
{
m_Format = MeshVertexFormat::Invalid;
m_Vertices = nullptr;
m_szVertices = 0;
m_OwnData = false;
m_Indices = nullptr;
m_IndexCount = 0;
m_IsIndexed = false;

*this = std::move(other);
}

/// @brief Move assignment
/// @param other Mesh rvalue to assign
/// @return The current object with vertices, indices and any metadata from the rvalue.
Mesh& operator=(Mesh&& other)
{
// Prevent self-assignment.
if (this != &other)
{
// Make sure our data is disposed first if necessary so memory doesn't leak.
Dispose();

MoveInternal(other);
}

return *this;
}

/// @brief Default constructor. Initialises an empty mesh with just a vertex format and no vertices.
/// @param format Vertex format to use.
inline void Init(MeshVertexFormat format = MeshVertexFormat::VVV)
{
m_Format = format;
m_OwnData = false;
m_IsIndexed = false;
m_szVertices = 0;
m_IndexCount = 0;
m_Vertices = nullptr;
m_Indices = nullptr;

InitInternal();
}

/// @brief Initialises the Mesh with geometry data from a built-in primitive.
/// @param primitive A built-in primitive instance from LepusUtility.
/// @param copy Should the data be copied?
inline void Init(const lepus::utility::Primitive& primitive, bool copy = false)
{
Init((void*)primitive.GetVertices(), primitive.VertexBufferSize(), MeshVertexFormat::VVV, (uint32_t*)primitive.GetIndices(), primitive.IndexCount(), copy);
}

/// @brief Initialises the Mesh with provided geometry data.
/// @param vertices Vertex data
/// @param szVertices Size of the vertex data (in bytes)
/// @param format Vertex data format
/// @param indices Index data. Optional - pass nullptr for non-indexed.
/// @param indexCount Number of indices.
/// @param copy Should the data be copied?
inline void Init(void* vertices, size_t szVertices, MeshVertexFormat format = MeshVertexFormat::VVV, uint32_t* indices = nullptr, size_t indexCount = 0, bool copy = false)
{
m_Format = format;
m_IsIndexed = indexCount > 0 && indices != nullptr;
m_szVertices = szVertices;

if (copy)
{
m_Vertices = malloc(szVertices);
memcpy(m_Vertices, vertices, szVertices);

if (m_IsIndexed)
{
m_IndexCount = indexCount;
m_Indices = new uint32_t[indexCount];
memcpy(m_Indices, indices, indexCount * sizeof(uint32_t));
}

m_OwnData = true;
}
else
{
m_Vertices = vertices;

if (m_IsIndexed)
{
m_IndexCount = indexCount;
m_Indices = indices;
}

m_OwnData = false;
}

InitInternal();
}

/// @brief Gets the vertex format used by this Mesh.
/// @return The MeshVertexFormat this Mesh was initialised with.
inline MeshVertexFormat GetFormat() const { return m_Format; }

/// @brief Gets the pointer to vertex data used by this Mesh.
/// @return A constant pointer to the vertex data.
const void* GetVertices() const
{
return m_Vertices;
}

/// @brief Gets the pointer to index data used by this Mesh.
/// @return A constant pointer to the index data.
const uint32_t* GetIndices() const
{
return m_Indices;
}

/// @brief Gets the size of a single vertex based on the vertex format used by this Mesh.
/// @return An unsigned 8-bit integer defining a single vertex size.
uint8_t GetSingleVertexSize() const
{
switch (m_Format)
{
case MeshVertexFormat::VVV:
return sizeof(float) * 3;
case MeshVertexFormat::Invalid:
default:
return 0;
}
}

/// @brief Gets the number of vertices in this Mesh.
/// @return An unsigned 64-bit integer defining the number of vertices (TODO: that's a maximum of 18,446,744,073,709,551,615 vertices... do we really need 64-bit for that?)
size_t inline VertexCount() const
{
return m_szVertices / GetSingleVertexSize();
}

/// @brief Gets the size of the vertex data.
/// @return An unsigned 64-bit integer defining the size of the vertex data (in bytes).
size_t inline VertexBufferSize() const
{
return m_szVertices;
}

/// @brief Gets the size of the index data.
/// @return An unsigned 64-bit integer defining the size of the index data (in bytes).
size_t inline IndexBufferSize() const
{
return m_IndexCount * sizeof(uint32_t);
}

/// @brief Gets the number of indices in this Mesh.
/// @return An unsigned 64-bit integer defining the number of indices that make up this Mesh (TODO: again, isn't 64 bits overkill?)
size_t inline IndexCount() const
{
return m_IndexCount;
}

/// @brief Releases any resources and data held by this Mesh as needed.
inline virtual void Dispose()
{
if (m_OwnData)
{
if (m_Vertices)
{
free(m_Vertices);
m_Vertices = nullptr;
m_szVertices = 0;
}

if (m_Indices)
{
delete[] m_Indices;
m_Indices = nullptr;
m_IndexCount = 0;
}
}
}
};
}
}
}

#endif
9 changes: 5 additions & 4 deletions src/lepus/gfx/GraphicsEngine/Apis/ApiGL.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
#include <unordered_map>

#include "ApiGL/Bindings.h"
#include "ApiGL/Types/GLMesh.h"

namespace lepus
{
Expand Down Expand Up @@ -64,16 +65,17 @@ namespace lepus
{
friend class GraphicsApiGLOptions;
private:
static const uint8_t _meshCount = 2;
struct
{
/// @brief Handle to the vertex array objects.
GLuint vao;

/// @brief Handle to the global VBO.
GLuint vbo;
GLuint vbo[_meshCount] = { 0, 0 };

/// @brief Handle to the global IBO.
GLuint ibo;
GLuint ibo[_meshCount] = { 0, 0 };

/// @brief List with all uniforms used by the API.
// TODO: Change to array - might get better cache/locality to improve access times.
Expand All @@ -86,8 +88,7 @@ namespace lepus

GLuint m_Programs[GraphicsApiGLOptions::ProgramCount];

// TODO: separate
LepusUtility::Primitive m_CubeGeometry = LepusUtility::Primitives::Cube();
GLMesh m_Meshes[_meshCount];

private:
void SetupVertexArrays();
Expand Down
Loading

0 comments on commit 71ff1ad

Please sign in to comment.