Rework API graphique Vulkan - EnTT pour ECS + Chargement modèle 3D assimp + SDL3 pour events input et fenetre + mesh texture camera transform ok + attention tous les assets nouveaus ne sont pas commités et il y a du code test en dur dans scene addentity + restructuration globale

This commit is contained in:
Tom Ray
2026-03-14 20:24:17 +01:00
parent 7c352bc280
commit 6695d46bcd
672 changed files with 238656 additions and 1821 deletions

View File

@@ -4,7 +4,7 @@
#include <fstream>
namespace CosmicCore {
namespace CosmicConfig {
CModuleConfig CConfiguration::moduleConfiguration;

View File

@@ -3,7 +3,7 @@
#include "nlohmann/json_fwd.hpp"
#include <filesystem>
namespace CosmicCore {
namespace CosmicConfig {
class CModuleConfig{
private:
std::filesystem::path modulesDirectory;

View File

@@ -27,7 +27,7 @@ namespace CosmicCore {
CAbstractComponent(CEntity& entity): m_owningEntity(entity){};
virtual ~CAbstractComponent() = default;
CEntity& getEntity() {
CEntity getEntity() const {
return m_owningEntity;
}

View File

@@ -1,10 +0,0 @@
#ifndef CABSTRACTCAMERA_HPP
#define CABSTRACTCAMERA_HPP
#include "../CAbstractComponent.hpp"
namespace CosmicCore {
class CAbstractCamera: CAbstractComponent
{
};
}
#endif

View File

@@ -0,0 +1,153 @@
#ifndef CCAMERA_HPP
#define CCAMERA_HPP
#include "../CAbstractComponent.hpp"
//pour vulkan depth 0-1 (opengl [-1,1])
#define GLM_FORCE_DEPTH_ZERO_TO_ONE
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
#include "../../Graphics/API/VulkanImpl.hpp"
#include "../Geometry/CTransform.hpp"
namespace CosmicCore {
class CCamera : public CAbstractComponent {
private:
// paramètres de la caméra
float m_fov = 45.0f;
float m_near = 0.1f;
float m_far = 1000.0f;
float m_aspect = 16.0f / 9.0f;
// matrices calculées
glm::mat4 m_view = glm::mat4(1.0f);
glm::mat4 m_projection = glm::mat4(1.0f);
// GPU
struct CameraUBOData {
glm::mat4 view;
glm::mat4 projection;
};
std::array<VMABuffer, MAX_FRAMES_IN_FLIGHT> m_uniformBuffers;
std::array<void*, MAX_FRAMES_IN_FLIGHT> m_mappedData{};
std::array<ManagedDescriptorSet, MAX_FRAMES_IN_FLIGHT> m_descriptorSets;
void recalcProjection() {
m_projection = glm::perspective(glm::radians(m_fov), m_aspect, m_near, m_far);
// Vulkan a l'axe Y inversé par rapport à OpenGL
m_projection[1][1] *= -1;
}
public:
CCamera(CEntity& entity) : CAbstractComponent(entity) {
recalcProjection();
}
~CCamera(){
destroy();
}
void setFov(float fov) {
m_fov = fov;
recalcProjection();
}
void setAspect(float aspect) {
m_aspect = aspect;
recalcProjection();
}
void setNearFar(float near, float far) {
m_near = near;
m_far = far;
recalcProjection();
}
// getters
glm::mat4 getView(const CTransform& transform) const {
glm::quat q = transform.getOrientation();
glm::vec3 position = transform.getCenter();
// rotation inverse (conjugué du quaternion) + translation inverse
glm::mat4 rotInverse = glm::toMat4(glm::conjugate(q));
glm::mat4 transInverse = glm::translate(glm::mat4(1.0f), -position);
return rotInverse * transInverse;
}
glm::mat4 getProjection() const { return m_projection; }
// GPU
void initUniformBuffer(VmaAllocator allocator) {
VulkanImpl* api = dynamic_cast<VulkanImpl*>(GraphicsAPI::getAPI().get());
for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
VkBufferCreateInfo bufferInfo{};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = sizeof(CameraUBOData);
bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
VmaAllocationCreateInfo allocInfo{};
allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
VmaAllocationInfo info{};
vmaCreateBuffer(allocator, &bufferInfo, &allocInfo,
&m_uniformBuffers[i].buffer,
&m_uniformBuffers[i].allocation,
&info);
m_mappedData[i] = info.pMappedData;
m_descriptorSets[i] = api->getDescriptorPoolManager().allocate(
*api->getCameraLayout()
);
vk::DescriptorBufferInfo descriptorBufferInfo{
vk::Buffer(m_uniformBuffers[i].buffer),
0,
sizeof(CameraUBOData)
};
vk::WriteDescriptorSet descriptorWrite{
*m_descriptorSets[i].set,
0, 0, 1,
vk::DescriptorType::eUniformBuffer,
{}, &descriptorBufferInfo
};
static_cast<vk::raii::Device*>(api->getDevice())->updateDescriptorSets(descriptorWrite, {});
}
}
void destroyUniformBuffer(VmaAllocator allocator) {
VulkanImpl* api = dynamic_cast<VulkanImpl*>(GraphicsAPI::getAPI().get());
for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
api->getDescriptorPoolManager().free(m_descriptorSets[i]);
vmaDestroyBuffer(allocator, m_uniformBuffers[i].buffer,
m_uniformBuffers[i].allocation);
}
}
void updateUniformBuffer(uint32_t frameIndex, const CTransform& transform) {
CameraUBOData data{ getView(transform), m_projection };
memcpy(m_mappedData[frameIndex], &data, sizeof(data));
}
vk::raii::DescriptorSet& getDescriptorSet(uint32_t frameIndex) {
return m_descriptorSets[frameIndex].set;
}
void destroy()
{
VulkanImpl* api = dynamic_cast<VulkanImpl*>(GraphicsAPI::getAPI().get());
for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
api->destroyBuffer(m_uniformBuffers[i], api->getCurrentFrameIndex());
api->destroyDescriptorSet(m_descriptorSets[i], api->getCurrentFrameIndex());
}
}
nlohmann::json to_json(){};
};
} // namespace CosmicCore
#endif

View File

@@ -1,5 +1,6 @@
#include "CTransform.hpp"
#include "../../Graphics/API/VulkanImpl.hpp"
#include "../Relationships/CRelationship.hpp"
namespace CosmicCore
{
@@ -22,7 +23,7 @@ namespace CosmicCore
CTransform::CTransform(CEntity& entity) : CAbstractComponent(entity),
m_center(0.0f, 0.0f, 0.0f),
m_scale(1.0f, 1.0f, 1.0f),
m_orientation(),
m_orientation(glm::identity<glm::quat>()),
m_observers() {
calcTranslation();
calcRotation();
@@ -41,6 +42,11 @@ namespace CosmicCore
calcTranformation();
}
CTransform::~CTransform()
{
destroyUniformBuffer();
}
glm::mat4 CTransform::getTranslation(void) const {
return m_translation;
}
@@ -58,17 +64,18 @@ namespace CosmicCore
}
glm::mat4 CTransform::getInheritedTransformation(void) const {
/*const auto& entity = getEntity();
if(entity)
{
if (entity->getParent().expired()) {
return m_transformation;
}
else {
auto p = entity->getParent().lock();
return p->getTransform().getInheritedTransformation() * m_transformation;
}
}*/
auto& registry = getEntity().getRegistry();
if (!registry().all_of<CRelationship>(*getEntity()))
return m_transformation;
auto& rel = registry().get<CRelationship>(*getEntity());
if (rel.getParent() == entt::null)
return m_transformation;
auto& parentTransform = registry().get<CTransform>(rel.getParent());
return parentTransform.getInheritedTransformation() * m_transformation;
}
glm::vec3 CTransform::getCenter(void) const {
@@ -158,7 +165,7 @@ namespace CosmicCore
}
}
void CTransform::forward(glm::vec3 value) {
void CTransform::forward(glm::vec3 value) {
glm::vec3 relValue = m_orientation * value;
m_center += relValue;
calcTranslation();
@@ -177,4 +184,47 @@ namespace CosmicCore
{
//TODO
}
void CTransform::updateUniformBuffer(uint32_t frameIndex) {
auto data{ getInheritedTransformation() }; // utilise la transformation héritée
memcpy(m_mappedData[frameIndex], &data, sizeof(data));
}
void CTransform::initUniformBuffer(VmaAllocator allocator) {
VulkanImpl* api = dynamic_cast<VulkanImpl*>(GraphicsAPI::getAPI().get());
for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
VkBufferCreateInfo bufferInfo{};
bufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
bufferInfo.size = sizeof(glm::mat4);
bufferInfo.usage = VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT;
VmaAllocationCreateInfo allocInfo{};
allocInfo.usage = VMA_MEMORY_USAGE_CPU_TO_GPU;
allocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
VmaAllocationInfo info{};
vmaCreateBuffer(allocator, &bufferInfo, &allocInfo,
&m_uniformBuffers[i].buffer,
&m_uniformBuffers[i].allocation,
&info);
m_mappedData[i] = info.pMappedData;
m_descriptorSets[i] = api->getDescriptorPoolManager().allocate(api->getTransformLayout());
vk::DescriptorBufferInfo descriptorBufferInfo{vk::Buffer(m_uniformBuffers[i].buffer), 0, sizeof(glm::mat4)};
vk::WriteDescriptorSet descriptorWrite{m_descriptorSets[i].set, 0, 0,1, vk::DescriptorType::eUniformBuffer, {}, &descriptorBufferInfo};
static_cast<vk::raii::Device*>(api->getDevice())->updateDescriptorSets(descriptorWrite, {});
}
}
void CTransform::destroyUniformBuffer() {
VulkanImpl* api = dynamic_cast<VulkanImpl*>(GraphicsAPI::getAPI().get());
for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
api->destroyBuffer(m_uniformBuffers[i], api->getCurrentFrameIndex());
api->destroyDescriptorSet(m_descriptorSets[i], api->getCurrentFrameIndex());
}
}
}

View File

@@ -11,6 +11,9 @@
#include <glm/gtc/quaternion.hpp>
#include <glm/gtx/quaternion.hpp>
#include "../../Graphics/API/VMABuffer.hpp"
#include "../../Graphics/API/ManagedDescriptorSet.hpp"
namespace CosmicCore
{
/**
@@ -79,6 +82,10 @@ namespace CosmicCore
* @brief Compute the full transformation of the object.
*/
void calcTranformation(void);
std::array<VMABuffer, MAX_FRAMES_IN_FLIGHT> m_uniformBuffers;
std::array<void*, MAX_FRAMES_IN_FLIGHT> m_mappedData{};
std::array<ManagedDescriptorSet, MAX_FRAMES_IN_FLIGHT> m_descriptorSets;
public:
/**
@@ -87,6 +94,13 @@ namespace CosmicCore
*/
CTransform(CEntity& m_entity);
~CTransform();
CTransform(CTransform&&) = default;
CTransform& operator=(CTransform&&) = default;
CTransform(const CTransform&) = delete;
CTransform& operator=(const CTransform&) = delete;
/**
* @brief CTransform's constructor.
* @param[in, out] m_entity The entity to which the transform belongs.
@@ -240,6 +254,17 @@ namespace CosmicCore
t.setScale(glm::vec3(j["Scale"]["x"], j["Scale"]["y"], j["Scale"]["z"]));
return t;
};
void initUniformBuffer(VmaAllocator allocator);
void destroyUniformBuffer();
void updateUniformBuffer(uint32_t frameIndex);
VMABuffer& getUniformBuffer(uint32_t frameIndex) {
return m_uniformBuffers[frameIndex];
};
vk::raii::DescriptorSet& getDescriptorSet(uint32_t frameIndex) {
return m_descriptorSets[frameIndex].set;
};
};
}
#endif

View File

@@ -6,7 +6,6 @@ namespace CosmicCore {
{
public:
CAbstractRenderer(CEntity& e): CAbstractComponent(e){};
virtual void render() = 0;
};
}
#endif

View File

@@ -1,78 +0,0 @@
#ifndef CMODEL_HPP
#define CMODEL_HPP
#include "Material/SMaterial.hpp"
#include "Mesh/CMesh.hpp"
#include <vector>
#include <glm/glm.hpp>
/**
* @brief Class representing a 3D model.
*/
class CModel {
private:
/**
* @brief The meshes, a vector which contains all the meshes of the object.
*/
std::vector<CMesh*> m_meshes;
/**
* @brief A boolean representing the loading state of the model.
*/
bool m_loaded;
public:
/**
* @brief CModel's default constructor, disabled.
*/
CModel(void) = delete;
/**
* @brief CModel constructor.
* @param meshes : The list of the meshes of the object.
*/
CModel(std::vector<CMesh*> meshes);
/**
* @brief CModel's destructor.
*/
~CModel(void);
/**
* @brief Load the model in the GPU.
*/
void load(void);
/**
* @brief Render the model on the screen.
* @param[in] model The transform of the object.
* @param[in] view The view of the object.
* @param[in] projection The projection of the object.
* @param[in] lightPos The light's position.
* @param[in] intensity The light's intensity.
*/
void draw(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 lightPos, float intensity);
/**
* @brief Getter to the meshes of the model.
* @return A vector which represent the list of meshes of the model, it's a direct reference to the member m_meshes.
*/
std::vector<CMesh*>& getMeshes(void);
/**
* @brief Setter to the meshes.
* @param[in] meshes The list of meshes to set to the model.
*/
void setMeshes(std::vector<CMesh*> meshes);
/**
* @brief Getter to m_loaded member, say if the model is loaded or not.
* @return A boolean representing the state of the model, loaded or not.
*/
bool isLoaded(void);
};
#endif

View File

@@ -0,0 +1,3 @@
#include "CRenderer.hpp"
namespace CosmicCore {
}

View File

@@ -0,0 +1,18 @@
#ifndef CTESTRENDERER_HPP
#define CTESTRENDERER_HPP
#include "CAbstractRenderer.hpp"
#include "../../Graphics/Data/CModel.hpp"
namespace CosmicCore {
class CRenderer: public CAbstractRenderer
{
CModel* m_model = nullptr;
public:
CRenderer() = delete;
CRenderer(CEntity& e): CAbstractRenderer(e){};
CRenderer(CEntity& e, CModel* mod): CAbstractRenderer(e), m_model(mod){};
nlohmann::json to_json() override{return nlohmann::json();};
CModel* getModel(){return m_model;};
};
}
#endif

View File

@@ -1,10 +0,0 @@
#include "CTestRenderer.hpp"
#include <iostream>
namespace CosmicCore {
void CTestRenderer::render()
{
int a = 2*25;
int b = a +2;
std::cout << b << std::endl;
};
}

View File

@@ -1,17 +0,0 @@
#ifndef CTESTRENDERER_HPP
#define CTESTRENDERER_HPP
#include "CAbstractRenderer.hpp"
namespace CosmicCore {
class CTestRenderer: public CAbstractRenderer
{
public:
CTestRenderer() = delete;
CTestRenderer(CEntity& e): CAbstractRenderer(e){};
void render() override;
nlohmann::json to_json(){return nlohmann::json();};
};
}
#endif

View File

@@ -1,39 +0,0 @@
#ifndef SMATERIAL_HPP
#define SMATERIAL_HPP
#include "../Shader/CShader.hpp"
#include "../Texture/CAbstractTexture.hpp"
#include "SColor.hpp"
#include <vector>
/**
* @file SMaterial.hpp
* @brief File for the material struct.
*/
/**
* @brief The struct material.
*/
typedef struct SMaterial {
/**
* @brief List of textures for the material.
*/
std::vector<CAbstractTexture*> m_textures;
/**
* @brief List of colors for the material.
*/
std::vector<SColor> m_colors;
/**
* @brief The shader used to render.
*/
CShader* m_shader = nullptr;
~SMaterial() { for (unsigned int i = 0; i < m_textures.size(); ++i) {
delete m_textures[i];
} };
} SMaterial;
#endif

View File

@@ -1,216 +0,0 @@
#include "CMesh.hpp"
void CMesh::bindMaterial(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 lightPos, float intensity) {
// Test the material.
if (m_material == nullptr) {
throw CLogicException("This mesh is not linked to a material.");
}
// Active the shader.
m_material->m_shader->use();
// Give the matrix to the shader.
m_material->m_shader->setMat4("model", model);
m_material->m_shader->setMat4("view", view);
m_material->m_shader->setMat4("projection", projection);
m_material->m_shader->setVec3("lightPos", lightPos);
m_material->m_shader->setFloat("intensity", intensity);
// Counter for each Texture Type :
unsigned int countTex[TEXTURE_TYPE_NUMBER];
for (unsigned int i = 0; i < TEXTURE_TYPE_NUMBER; i++) {
countTex[i] = 0;
}
// For each texture in the material :
for (unsigned int i = 0; i < m_material->m_textures.size(); i++) {
// Active the shader unit.
glActiveTexture(GL_TEXTURE0 + i);
// Retrieve texture name.
std::string name;
switch (m_material->m_textures[i]->getType()) {
case TEXTURE_DIFFUSE:
name = "textureDiffuse" + std::to_string(countTex[0]);
countTex[0]++;
break;
case TEXTURE_SPECULAR:
name = "textureSpecular" + std::to_string(countTex[1]);
countTex[1]++;
break;
case TEXTURE_NORMAL:
name = "textureNormal" + std::to_string(countTex[2]);
countTex[2]++;
break;
case TEXTURE_HEIGHT:
name = "textureHeight" + std::to_string(countTex[3]);
countTex[3]++;
break;
default:
break;
}
// Get the uniform storage space of the shader.
glUniform1i(glGetUniformLocation(m_material->m_shader->getId(), name.c_str()), i);
// And finally bind the texture.
glBindTexture(GL_TEXTURE_2D, m_material->m_textures[i]->getId());
}
// Always good practice to set everything back to defaults once configured.
glActiveTexture(GL_TEXTURE0);
// Counter for each color Type :
unsigned int countCol[COLOR_TYPE_NUMBER];
for (unsigned int i = 0; i < COLOR_TYPE_NUMBER; i++) {
countCol[i] = 0;
}
// For each color in the material :
for (unsigned int i = 0; i < m_material->m_colors.size(); i++) {
// Retrieve texture name.
std::string name;
switch (m_material->m_colors[i].m_type) {
case COLOR_DIFFUSE:
name = "colorDiffuse" + std::to_string(countCol[0]);
countCol[0]++;
break;
case COLOR_SPECULAR:
name = "colorSpecular" + std::to_string(countCol[1]);
countCol[1]++;
break;
default:
break;
}
// Give the color as a vector 4.
m_material->m_shader->setVec4(name, m_material->m_colors[i].m_vector);
}
// Active the shader.
//m_material->m_shader->use();
}
CMesh::CMesh(void) :
m_vertexes(),
m_indexes(),
m_material(nullptr),
m_vertexBufferObject(0),
m_elementBufferObject(0),
m_vertexArrayObject(0) {
}
CMesh::~CMesh(void) {
// Delete the VAO.
if (m_vertexArrayObject != 0) {
glDeleteVertexArrays(1, &m_vertexArrayObject);
}
if (m_material != nullptr)
{
delete m_material;
}
}
std::vector<SVertex>& CMesh::getVertexes(void) {
return m_vertexes;
}
std::vector<unsigned int>& CMesh::getIndexes(void) {
return m_indexes;
}
SMaterial* CMesh::getMaterial(void) {
return m_material;
}
void CMesh::setMaterial(SMaterial* material) {
m_material = material;
}
void CMesh::setVertices(std::vector<SVertex> vertices)
{
m_vertexes = vertices;
}
void CMesh::setIndexes(std::vector<unsigned int> indexes)
{
m_indexes = indexes;
}
void CMesh::load(void) {
if (m_vertexes.empty() || m_indexes.empty()) {
throw CLogicException("This mesh do no contain vertex data.");
}
// Create the VAO.
glGenVertexArrays(1, &m_vertexArrayObject);
// Create the VBO.
glGenBuffers(1, &m_vertexBufferObject);
// Create the EBO.
glGenBuffers(1, &m_elementBufferObject);
// Open the VAO.
glBindVertexArray(m_vertexArrayObject);
// Open the VBO, and link it to the VAO.
glBindBuffer(GL_ARRAY_BUFFER, m_vertexBufferObject);
// Give the block of memory of vertexes vector (so, it works like a c list), and the struct is transparent du to their conception).
glBufferData(GL_ARRAY_BUFFER, m_vertexes.size() * sizeof(SVertex), &m_vertexes[0], GL_STATIC_DRAW);
// Open the EBO, and link it to the VAO.
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_elementBufferObject);
// Give the block of memory of indexes vector (so, it works like a c list), and the struct is transparent du to their conception).
glBufferData(GL_ELEMENT_ARRAY_BUFFER, m_indexes.size() * sizeof(unsigned int), &m_indexes[0], GL_STATIC_DRAW);
// Set the vertex attribute pointers.
// Vertex Positions.
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (void*)0);
// Vertex normals.
glEnableVertexAttribArray(1);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (void*)offsetof(SVertex, m_normal));
// Vertex texture coords.
glEnableVertexAttribArray(2);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(SVertex), (void*)offsetof(SVertex, m_texCoords));
// Vertex tangent.
glEnableVertexAttribArray(3);
glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (void*)offsetof(SVertex, m_tangent));
// Vertex bitangent.
glEnableVertexAttribArray(4);
glVertexAttribPointer(4, 3, GL_FLOAT, GL_FALSE, sizeof(SVertex), (void*)offsetof(SVertex, m_bitangent));
// Unbind the VAO.
glBindVertexArray(0);
}
void CMesh::draw(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 lightPos, float intensity) {
if (m_vertexArrayObject == 0) {
throw CLogicException("This mesh is not loaded in GPU, you can not draw it.");
}
// Bind the material.
bindMaterial(model, view, projection, lightPos, intensity);
// Enable the vertex array object, so the shader use the vertex attribute in this vao.
glBindVertexArray(m_vertexArrayObject);
// Render the triangles in the vertex array object.
glDrawElements(GL_TRIANGLES, (GLsizei)m_indexes.size(), GL_UNSIGNED_INT, 0);
// Disable the vertex array object.
glBindVertexArray(0);
}

View File

@@ -1,132 +0,0 @@
#ifndef CMESH_HPP
#define CMESH_HPP
#include "../Material/SMaterial.hpp"
#include "../Texture/CAbstractTexture.hpp"
#include "SVertex.hpp"
#include "../../../Controller/Exception/CLogicException.hpp"
#ifdef WIN32
#include <gl/glew.h>
#else
#include <GL/glew.h>
#endif
#include <vector>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
/**
* @file CMesh.hpp
* @brief File for the mesh struct.
*/
/**
* @brief Class CMesh, used to represent a mesh, a set of vertex (which can be indexed), ready to be drawn.
*/
class CMesh {
private:
/**
* @brief List of the vertices of the mesh.
*/
std::vector<SVertex> m_vertexes;
/**
* @brief List of the indices of the mesh.
*/
std::vector<unsigned int> m_indexes;
/**
* @brief A pointer to the material containing textures, colors and the shader used for the mesh.
*/
SMaterial* m_material;
/**
* @brief The vertex buffer.
*/
unsigned int m_vertexBufferObject;
/**
* @brief The index buffer.
*/
unsigned int m_elementBufferObject;
/**
* @brief Vertex array object, all the data.
*/
unsigned int m_vertexArrayObject;
/**
* @brief Apply material to use for drawing.
* @param[in] model the model matrix.
* @param[in] view the view matrix.
* @param[in] projection the projection matrix.
* @param[in] lightPos the position of the light source.
* @param[in] intensity the intensity of the light source.
*/
void bindMaterial(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 lightPos, float intensity);
public:
/**
* @brief the constructor.
*/
CMesh(void);
/**
* @brief the destructor.
*/
~CMesh(void);
/**
* @brief The vertex array getter.
* @return std::vector<SVertex>&, A reference to the list of vertex.
*/
std::vector<SVertex>& getVertexes(void);
/**
* @brief The index array getter.
* @return std::vector<unsigned int>&, A reference to the list of index.
*/
std::vector<unsigned int>& getIndexes(void);
/**
* @brief The material getter.
* @return SMaterial*, the material.
*/
SMaterial* getMaterial(void);
/**
* @brief The material setter.
* @param[in] material the wanted material.
*/
void setMaterial(SMaterial* material);
/**
* @brief The vertex setter.
* @param[in] vertices list of the vertices to give to the GPU.
*/
void setVertices(std::vector<SVertex> vertices);
/**
* @brief The indexes setter.
* @param[in] indexes list of the indexes for the index buffer
*/
void setIndexes(std::vector<unsigned int> indexes);
/**
* @brief Load the mesh in GPU.
*/
void load(void);
/**
* @brief draw the mesh.
* @param[in] model the model matrix.
* @param[in] view the view matrix.
* @param[in] projection the projection matrix.
* @param[in] lightPos the position of the light source.
* @param[in] intensity the intensity of the light source.
*/
void draw(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 lightPos, float intensity);
};
#endif

View File

@@ -1,48 +0,0 @@
#ifndef SVERTEX_HPP
#define SVERTEX_HPP
#include <glm/glm.hpp>
/**
* @file SVertex.hpp
* @brief File for the vertex struct.
*/
/**
* @brief the struct Vertex, use to represent vertex and vertex attribute.
*/
typedef struct {
/**
* @brief Position attribute.
* 3D vector.
*/
glm::vec3 m_position;
/**
* @brief Normal attribute.
* 3D vector.
*/
glm::vec3 m_normal;
/**
* @brief Texture coordinates attribute.
* 2D vector.
*/
glm::vec2 m_texCoords;
/**
* @brief Tangent attribute.
* 3D vector.
*/
glm::vec3 m_tangent;
/**
* @brief Bitangent attribute.
* 3D vector (perpendicular to m_tangent vector).
*/
glm::vec3 m_bitangent;
// m_normal, m_tangent, m_bitangent are supposed to create a vector base to compute normal map.
} SVertex;
#endif

View File

@@ -1,18 +0,0 @@
#include "CAbstractTexture.hpp"
void CAbstractTexture::setId(unsigned int newId) {
m_glId = newId;
}
CAbstractTexture::CAbstractTexture(ETextureType type) :
m_glId(0),
m_type(type) {
}
unsigned int CAbstractTexture::getId(void) {
return m_glId;
}
ETextureType CAbstractTexture::getType(void) {
return m_type;
}

View File

@@ -1,72 +0,0 @@
#ifndef CABSTRACTTEXTURE_HPP
#define CABSTRACTTEXTURE_HPP
#define TEXTURE_TYPE_NUMBER 4
/**
* @brief enum representing every type of texture available.
*/
enum ETextureType {
TEXTURE_DIFFUSE,
TEXTURE_SPECULAR,
TEXTURE_NORMAL,
TEXTURE_HEIGHT,
};
/**
* @brief Class representing a texture.
*/
class CAbstractTexture {
private:
/**
* @brief OpenGL ID.
*/
unsigned int m_glId;
/**
* @brief The texture's type.
*/
ETextureType m_type;
protected:
/**
* @brief Setter to the m_glId member.
* @param newId : OpenGL id to set.
*/
void setId(unsigned int newId);
public:
/**
* @brief CAbstractTexture's default constructor, disabled.
*/
CAbstractTexture(void) = delete;
/**
* @brief CAbstractTexture's constructor.
* @param[in] type The texture's type.
*/
CAbstractTexture(ETextureType type);
virtual ~CAbstractTexture() {};
/**
* @brief Getter to the m_glId member.
* @return The m_glId member.
*/
unsigned int getId(void);
/**
* @brief Getter to the texture's type.
* @return The texture's type.
*/
ETextureType getType(void);
/**
* @brief Load the texture in the GPU (uses only redefined function in the child classes).
*/
virtual void init(void) = 0;
};
#endif

View File

@@ -1,74 +0,0 @@
#include "CImageTexture.hpp"
CImageTexture::CImageTexture(ETextureType type, std::string filePath) :
CAbstractTexture(type),
m_filePath(filePath) {
}
std::string CImageTexture::getFilePath(void) {
return m_filePath;
}
void CImageTexture::setFilePath(std::string filePath) {
m_filePath = filePath;
}
void CImageTexture::init(void) {
// Read the image file.
SDL_Surface* sdlSurface = IMG_Load(m_filePath.c_str());
if (sdlSurface == NULL) {
throw CLibException(std::string("Image file \"") + m_filePath + std::string("\" can not be opened : ") + std::string(SDL_GetError()));
}
// Create the id.
unsigned int id;
glGenTextures(1, &id);
setId(id);
// Image format.
GLenum internalFormat(0);
GLenum externalFormat(0);
if (sdlSurface->format->BytesPerPixel == 3) {
// We use RGB as internal format.
internalFormat = GL_RGB;
// Choose the external format.
if (sdlSurface->format->Rmask == 0xff)
externalFormat = GL_RGB;
else
externalFormat = GL_BGR;
}
else if (sdlSurface->format->BytesPerPixel == 4) {
// We use RGBA as internal format.
internalFormat = GL_RGBA;
// Choose the external format.
if (sdlSurface->format->Rmask == 0xff)
externalFormat = GL_RGBA;
else
externalFormat = GL_BGRA;
}
else {
SDL_FreeSurface(sdlSurface);
throw CRuntimeException("Unknow image internal format.");
}
// Lock the texture to use it.
glBindTexture(GL_TEXTURE_2D, getId());
// Fill the GL texture.
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, sdlSurface->w, sdlSurface->h, 0, externalFormat, GL_UNSIGNED_BYTE, sdlSurface->pixels);
// Set filters : the near texture have a linear filter.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
// The far texture have a nearest filter, meaning no filter.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
// Unlock the texture.
glBindTexture(GL_TEXTURE_2D, 0);
// Free the surface.
SDL_FreeSurface(sdlSurface);
}

View File

@@ -1,31 +0,0 @@
#ifndef CIMAGETEXTURE_HPP
#define CIMAGETEXTURE_HPP
#include "../../../Controller/Exception/CLibException.hpp"
#include "../../../Controller/Exception/CRuntimeException.hpp"
#include "../../../Controller/Exception/CLogicException.hpp"
#include "CAbstractTexture.hpp"
#include <string>
#include <SDL.h>
#include <SDL_image.h>
#ifdef WIN32
#include <gl/glew.h>
#else
#include <GL/glew.h>
#endif
class CImageTexture : public CAbstractTexture {
private:
// Path of the file.
std::string m_filePath;
public:
CImageTexture(void) = delete;
~CImageTexture(void) {};
CImageTexture(ETextureType type, std::string filePath);
std::string getFilePath(void);
void setFilePath(std::string filePath);
virtual void init(void);
};
#endif

View File

@@ -0,0 +1,29 @@
#ifndef CRELATIONSHIP_HPP
#define CRELATIONSHIP_HPP
#include "../CAbstractComponent.hpp"
#include "nlohmann/json_fwd.hpp"
#include <string>
#include <vector>
namespace CosmicCore {
class CRelationship : public CAbstractComponent{
private:
EntityId parent = entt::null;
std::vector<EntityId> children;
public:
CRelationship(CEntity& entity): CAbstractComponent(entity){}
CRelationship(CEntity& entity, EntityId p): CAbstractComponent(entity), parent(p){}
CRelationship(CEntity& entity, std::vector<EntityId> childs): CAbstractComponent(entity), children(childs){}
CRelationship(CEntity& entity, EntityId p, std::vector<EntityId> childs): CAbstractComponent(entity), parent(p), children(childs){}
nlohmann::json to_json(){return nlohmann::json();}
void setParent(EntityId par){parent = par;}
void addChild(EntityId child){children.emplace_back(child);}
EntityId getParent(){return parent;}
std::vector<EntityId>& getChildren(){return children;}
};
}
#endif

View File

@@ -1,86 +0,0 @@
#include "CContext.hpp"
bool CContext::m_screenSaver = false;
void CContext::init(unsigned int sdlFlags, unsigned int imageFlags) {
// Log initialisation.
initLog();
DEBUG_LOG(trace, "Kernel", "Context", "Log initialized!")
// SDL Initialization.
DEBUG_LOG(trace, "Kernel", "Context", "SDL initialization...")
if (SDL_Init(sdlFlags) < 0) {
SDL_Quit();
HandleException(CLibException(std::string("Unable to initialize SDL: ") + SDL_GetError()), true);
}
DEBUG_LOG(trace, "Kernel", "Context", "SDL initialized!")
// SDL_Image Initialization.
int initted = IMG_Init(imageFlags);
DEBUG_LOG(trace, "Kernel", "Context", "SDL_Image initialization...")
if ((initted & imageFlags) != imageFlags) {
HandleException(CLibException(std::string("Unable to initialize SDL Image: ") + IMG_GetError()), true);
}
DEBUG_LOG(trace, "Kernel", "Context", "SDL_Image initialized!")
// SDL_TTF Initialization.
DEBUG_LOG(trace, "Kernel", "Context", "SDL_TTF initialization...")
if (TTF_Init() == -1) {
HandleException(CLibException(std::string("Unable to initialize SDL TTF: ") + TTF_GetError()), true);
}
DEBUG_LOG(trace, "Kernel", "Context", "SDL_TTF initialized!")
}
bool CContext::isScreenSaverEnable(void) {
return m_screenSaver;
}
void CContext::setScreenSaverEnable(bool newScreenSaver) {
m_screenSaver = newScreenSaver;
if (m_screenSaver) {
SDL_EnableScreenSaver();
}
else {
SDL_DisableScreenSaver();
}
}
void CContext::quit(void) {
TTF_Quit();
IMG_Quit();
SDL_Quit();
}
void CContext::initLog(void) {
static const std::string COMMON_FMT("[%TimeStamp%][%Severity%]%Message%");
boost::log::register_simple_formatter_factory< boost::log::trivial::severity_level, char >("Severity");
// Output message to console.
boost::log::add_console_log(
std::cout,
boost::log::keywords::format = COMMON_FMT,
boost::log::keywords::auto_flush = true
);
// Output message to file, rotates when file reached 1mb or at midnight every day. Each log file
// is capped at 1mb and total is 50mb.
boost::log::add_file_log(
boost::log::keywords::file_name = LOG_FILE,
boost::log::keywords::rotation_size = LOG_ROTATION_SIZE,
boost::log::keywords::max_size = LOG_MAX_SIZE,
boost::log::keywords::time_based_rotation = boost::log::sinks::file::rotation_at_time_point(0, 0, 0),
boost::log::keywords::format = COMMON_FMT,
boost::log::keywords::auto_flush = true
);
boost::log::add_common_attributes();
// Only output message with INFO or higher severity in Release.
#ifndef _DEBUG
boost::log::core::get()->set_filter(
boost::log::trivial::severity >= boost::log::trivial::info
);
#endif
}

View File

@@ -1,72 +0,0 @@
#ifndef CCONTEXT_HPP
#define CCONTEXT_HPP
#include "../Controller/Exception/CLibException.hpp"
#include "../Controller/Exception/CExceptionManager.hpp"
#define BOOST_LOG_DYN_LINK 1
#include <boost/log/trivial.hpp>
#include <boost/log/utility/setup.hpp>
#include <SDL.h>
#ifdef WIN32
#include <SDL_Image.h>
#else
#include <SDL_image.h>
#endif
#include <SDL_ttf.h>
#include <string>
#ifdef _DEBUG
#define DEBUG_LOG(level, object, component, message) \
BOOST_LOG_TRIVIAL(level) << "[" << object << "]" << "[" << component << "] : " << message;
#else
#define DEBUG_LOG(level, object, component, message)
#endif
#define ERROR_LOG(level, object, component, message) \
BOOST_LOG_TRIVIAL(level) << "[" << object << "]" << "[" << component << "] : " << message;
#define LOG_FILE "CosmicEngine_%3N.log"
#define LOG_ROTATION_SIZE 1 * 1024 * 1024
#define LOG_MAX_SIZE 50 * 1024 * 1024
/**
* @file CContext.hpp
* @brief File of CContext, a class reprensenting a SDL context, using SDL2 lib.
*/
/**
* @brief Class reprensenting a SDL context, using SDL2 lib.
*/
class CContext {
private:
// Say if the screenSaver is enabled.
static bool m_screenSaver;
public:
CContext(void) = delete;
static void init(unsigned int sdlFlags, unsigned int imageFlags);
static void quit(void);
/**
* @brief Say if the screen saver is enabled.
* @return bool, a boolean which say the screen saver status.
*/
static bool isScreenSaverEnable(void);
/**
* @brief Set the screen saver status.
* @param[in] newScreenSaver New value of screen saver status.
*/
static void setScreenSaverEnable(bool newScreenSaver);
private:
/**
* @brief Init the logging system.
*/
static void initLog(void);
};
#endif

View File

@@ -1,119 +0,0 @@
#ifndef CGAMEWINDOW_HPP
#define CGAMEWINDOW_HPP
#include "CWindow.hpp"
#include "../../Controller/Exception/CLibException.hpp"
#include "../../Controller/Exception/CLogicException.hpp"
#include <cstdlib>
#include <string>
#include <utility>
#include <exception>
#include <stdexcept>
#include <SDL.h>
#ifdef WIN32
#include <SDL_Image.h>
#else
#include <SDL_image.h>
#endif
/**
* @file CGameWindow.hpp
* @brief File of CGameWindow, a class reprensenting a OpenGL Window, using SDL2 lib.
*/
/**
* @brief Class reprensenting a OpenGL Window, using SDL2 lib.
*/
class CGameWindow : public CWindow {
private:
// Say if the mouse is grabbed.
bool m_grabCursor;
// Say if the mouse is in relative mode.
bool m_relativeCursor;
// The anti-aliasing.
unsigned char m_msaa;
public:
CGameWindow(void) = delete;
CGameWindow(const CGameWindow& param) = delete;
CGameWindow& operator=(const CGameWindow& param) = delete;
/**
* @brief The default constructor, build a non visible window with size of widthxheight.
* @param[in] title The title of the window.
* @param[in] iconPath The iconPath of the window.
* @param[in] width The width of the window.
* @param[in] height The height of the window.
* @param[in] resizable The define the resizable property of the window.
* @param[in] fullscreen The define the fullscreen property of the window.
* @param[in] sdlFlags Allow to add SDL flags.
* @param[in] imageFlags Allow to add SDL_Image flags.
*/
CGameWindow(std::string title, std::string iconPath, unsigned int width, unsigned int height, bool resizable, bool fullscreen);
CGameWindow(std::string title, SDL_Window* window);
/**
* @brief The destructor.
*/
~CGameWindow(void);
/**
* @brief Say if the mouse is grabbed.
* @return bool, a boolean which say the mouse grab status.
*/
bool isCursorGrabbed(void) const;
/**
* @brief Set the mouse grab status.
* @param[in] newMouseGrab New value of mouse grab status.
*/
void setCursorGrabbed(bool newMouseGrab);
/**
* @brief Say if the mouse is relative.
* @return bool, a boolean which say the mouse relative status.
*/
bool isCursorRelative(void) const;
/**
* @brief Set the mouse relative status, if true, the cursor grabb is also forced to true if not.
* @param[in] newMouseRelative New value of mouse relative status.
*/
void setCursorRelative(bool newMouseRelative);
/**
* @brief Get the MSAA value.
* @return unsigned char, the MSAA value.
*/
unsigned char getAntiAliasing(void) const;
/**
* @brief Set the MSAA of the window.
* @param[in] newMsaa New value of MSAA, must be 2, 4, 8, 16.
* @post if newMsaa not equal 2, 4, 8, 16, the value is set to 0.
*/
void setAntiAliasing(unsigned char newMsaa);
/**
* @brief Launched before the creation of the window, usefull for setting OpenGL attribute.
*/
virtual void preinitialization();
/**
* @brief Launched after the creation of the window, usefull for setting others attribute.
*/
virtual void postinitialization();
/**
* @brief Get the OpenGLContext of the window.
* @return SDL_GLContext the OpenGL context of the window, in SDL2 format, we need to destroy it after using, with SDL_GL_DeleteContext(SDL_GLContext);.
* @post Give a error if the window is not initialized.
*/
SDL_GLContext getOpenGLContext(void);
};
#endif

View File

@@ -1,204 +0,0 @@
#ifndef CWINDOW_HPP
#define CWINDOW_HPP
#include "../../Controller/Exception/CLibException.hpp"
#include "../../Controller/Exception/CLogicException.hpp"
#include <cstdlib>
#include <string>
#include <utility>
#include <exception>
#include <stdexcept>
#include <SDL.h>
#ifdef WIN32
#include <SDL_Image.h>
#else
#include <SDL_image.h>
#endif
/**
* @file CWindow.hpp
* @brief File of CWindow, a class reprensenting a Window, using SDL2 lib.
*/
/**
* @brief Class reprensenting a Window, using SDL2 lib.
*/
class CWindow {
private:
// The title of the window.
std::string m_title;
// The path to the icon.
std::string m_iconPath;
// First is the width, second is the height.
std::pair<unsigned int, unsigned int> m_size;
// Say if the window is fullscreen.
bool m_fullscreen;
// Say if the window is visible.
bool m_visible;
// Say if the window is resizable.
bool m_resizable;
// SDL flags for creating the window.
unsigned int m_sdlFlags;
// The pointer to the window.
SDL_Window* m_pwindow;
public:
CWindow(void) = delete;
CWindow(const CWindow& param) = delete;
CWindow& operator=(const CWindow& param) = delete;
/**
* @brief The default constructor, build a non visible window with size of widthxheight.
* @param[in] title The title of the window.
* @param[in] iconPath The iconPath of the window.
* @param[in] width The width of the window.
* @param[in] height The height of the window.
* @param[in] sdlFlags Allow to add SDL flags.
*/
CWindow(std::string title, std::string iconPath, unsigned int width, unsigned int height, bool resizable, bool fullscreen, unsigned int sdlFlags);
/**
* @brief The default constructor, build a non visible window with size of widthxheight.
* @param[in] title The title of the window.
* @param[in] The window to embed the game in.
* @param[in] sdlFlags Allow to add SDL flags.
* @param[in] imageFlags Allow to add SDL_Image flags.
*/
CWindow(std::string title, SDL_Window* window, unsigned int sdlFlags, unsigned int imageFlags);
/**
* @brief The destructor.
*/
~CWindow(void);
/**
* @brief Get the SDL_Window* of the window.
* @return SDL_Window The window, in SDL2 format.
*/
SDL_Window* getWindow(void);
void setWindow(SDL_Window* window){m_pwindow = window; };
/**
* @brief Say if the window is fullscreen.
* @return bool, a boolean which say the fullscreen status.
*/
bool isFullscreen(void) const;
/**
* @brief Set the fullscreen status.
* @param[in] newFullscreen New value of fullscreen status.
*/
void setFullscreen(bool newFullscreen);
/**
* @brief Say if the window is visible.
* @return bool, a boolean which say the visible status.
*/
bool isVisible(void) const;
/**
* @brief Set the visibility status.
* @param[in] newVisible New value of visibility status.
*/
void setVisible(bool newVisible);
/**
* @brief Get the window icon path.
* @return std::string, the path.
*/
std::string getIconPath(void) const;
/**
* @brief Get the window title.
* @return std::string, the title.
*/
std::string getTitle(void) const;
/**
* @brief Change the window title.
* @param[in] newTitle New title of the window.
*/
void setTitle(std::string newTitle);
/**
* @brief Change the window icon.
* @param[in] newIconPath New icon path of the window.
*/
void setIconPath(std::string newIconPath);
/**
* @brief Get the window width.
* @return unsigned int, the window width (in pixel).
*/
unsigned int getWidth(void) const;
/**
* @brief Get the window height.
* @return unsigned int, the window height (in pixel).
*/
unsigned int getHeight(void) const;
/**
* @brief Get the window size.
* @return std::pair<unsigned int, unsigned int>, the window size (in pixel).
*/
std::pair<unsigned int, unsigned int> getSize(void) const;
/**
* @brief Set the window size.
* @param[in] newSize New value of window size.
*/
void setSize(std::pair<unsigned int, unsigned int> newSize);
/**
* @brief Set the window size.
* @param[in] newWidth New value of window width.
* @param[in] newHeight New value of window height.
*/
void setSize(unsigned int newWidth, unsigned int newHeight);
/**
* @brief Say if the window is resizable.
* @return bool, a boolean which say the resizable status.
*/
bool isResizable(void) const;
/**
* @brief Set the rezisable status.
* @param[in] newResizable New value of rezisable status.
*/
void setResizable(bool newResizable);
/**
* @brief Say if the window is initialized.
* @return bool, a boolean which say the initialization status.
*/
bool isInitialized(void) const;
/**
* @brief Initialize the window.
* @post Give a error if the windows is already init.
*/
void initialization();
/**
* @brief Launched before the creation of the window, usefull for setting OpenGL attribute.
*/
virtual void preinitialization() = 0;
/**
* @brief Launched after the creation of the window, usefull for setting others attribute.
*/
virtual void postinitialization() = 0;
};
#endif

View File

@@ -6,20 +6,20 @@
namespace CosmicCore
{
CEntity::CEntity(ECManager& registry, EntityId handle) : CSerializable(), m_registryReference(registry), m_handle(handle)
CEntity::CEntity(EntityComponentManager& registry, EntityId handle, CScene* scene) : CSerializable(), m_scene(scene), m_registryReference(registry), m_handle(handle)
{
}
CEntity::CEntity(const CEntity& cop): m_registryReference(cop.m_registryReference), m_handle(cop.m_handle){
CEntity::CEntity(const CEntity& cop): m_scene(cop.m_scene), m_registryReference(cop.m_registryReference), m_handle(cop.m_handle){
}
std::weak_ptr<CScene> CEntity::getScene()
CScene* CEntity::getScene()
{
return m_scene;
}
void CEntity::setScene(std::weak_ptr<CScene> s)
void CEntity::setScene(CScene* s)
{
m_scene = s;
}

View File

@@ -4,24 +4,22 @@
#include <forward_list>
#include <memory>
#include "../Utils/CSerializable.hpp"
#include <entt/entt.hpp>
#include "../Systems/EntityComponentManager.hpp"
namespace CosmicCore
{
class CScene;
class CEntity : public CSerializable {
using ECManager = entt::registry;
using EntityId = entt::entity;
private:
/**
* @brief A pointer to the scene containing the entity.
*/
std::weak_ptr<CScene> m_scene;
CScene* m_scene;
ECManager& m_registryReference;
EntityComponentManager& m_registryReference;
EntityId m_handle;
@@ -32,7 +30,7 @@ namespace CosmicCore
*/
CEntity() = delete;
CEntity(ECManager& registry, EntityId handle);
CEntity(EntityComponentManager& registry, EntityId handle, CScene* scene);
CEntity(const CEntity& cop);
/**
@@ -49,26 +47,34 @@ namespace CosmicCore
template<typename compType, typename... Args>
void addComponent(std::forward_list<Args...> args)
{
m_registryReference.emplace<compType>(m_handle, *this, args);
m_registryReference().emplace<compType>(m_handle, *this, args);
}
template<typename compType>
void addComponent()
{
m_registryReference.emplace<compType>(m_handle, *this);
m_registryReference().emplace<compType>(m_handle, *this);
}
EntityComponentManager& getRegistry(){return m_registryReference;};
/**
* @brief Getter to the entity's scene.
* @return The pointer m_scene.
*/
std::weak_ptr<CScene> getScene();
CScene* getScene();
/**
* @brief Setter of the scene.
* @param[in, out] e The scene in which the entity will be set.
*/
void setScene(std::weak_ptr<CScene> s);
void setScene(CScene* s);
EntityId operator*(){
return m_handle;
}
//TODO GET COMPONENT VECTOR OF SPECIFIC TYPE ? si utile
nlohmann::json to_json();
};

View File

@@ -1,7 +1,7 @@
#include "CException.hpp"
void CException::makeFullMessage(void) {
std::stringstream sstring;
/*std::stringstream sstring;
sstring << "Error : " << m_code << std::endl << m_message << std::endl;
boost::stacktrace::stacktrace stacktrace = boost::stacktrace::stacktrace();
std::size_t frames = stacktrace.size();
@@ -17,7 +17,7 @@ void CException::makeFullMessage(void) {
sstring << " (" << stacktrace[i].address() << ')' << std::endl;
}
m_fullMessage = sstring.str();
m_fullMessage = sstring.str();*/
}
CException::CException(void) noexcept :

View File

@@ -3,8 +3,6 @@
#include <exception>
#include <string>
#include <sstream>
#include <boost/stacktrace.hpp>
/**
* @file CException.hpp

View File

@@ -1,6 +1,6 @@
#include "CExceptionManager.hpp"
void HandleException(const CException& e, bool fatal) {
/*void HandleException(const CException& e, bool fatal) {
std::string windowMessage(e.getMessage());
windowMessage += "\nException reported in \"";
@@ -31,4 +31,4 @@ void HandleException(const CException& e, bool fatal) {
// It's fatal, so we quit.
exit(EXIT_FAILURE);
}
}
}*/

View File

@@ -2,10 +2,6 @@
#define CEXCEPTIONMANAGER_HPP
#include "CException.hpp"
#include "../File/CFileManager.hpp"
#include <cstdlib>
#include <SDL.h>
/**
* @file CExceptionManager.hpp

View File

@@ -0,0 +1 @@
#define MAX_FRAMES_IN_FLIGHT 2

View File

@@ -0,0 +1,54 @@
#ifndef DELETIONQUEUE_HPP
#define DELETIONQUEUE_HPP
#include <cstdint>
#include <functional>
#include <deque>
#include <array>
#include "Constants.hpp"
class DeletionQueue {
private:
// une queue par frame + une queue immédiate
std::array<std::deque<std::function<void()>>, MAX_FRAMES_IN_FLIGHT> m_frameQueues;
std::deque<std::function<void()>> m_immediateQueue;
public:
// destruction différée - attendre MAX_FRAMES_IN_FLIGHT frames
void push(uint32_t currentFrame, std::function<void()>&& func) {
// on enfile dans la frame "opposée" pour attendre un cycle complet
uint32_t targetFrame = (currentFrame + MAX_FRAMES_IN_FLIGHT - 1) % MAX_FRAMES_IN_FLIGHT;
m_frameQueues[targetFrame].push_back(std::move(func));
}
// destruction immédiate - device.waitIdle() doit avoir été appelé avant
void pushImmediate(std::function<void()>&& func) {
m_immediateQueue.push_back(std::move(func));
}
// appelé au début de chaque frame - détruit les ressources de cette frame
void flush(uint32_t frameIndex) {
auto& queue = m_frameQueues[frameIndex];
while (!queue.empty()) {
queue.front()();
queue.pop_front();
}
}
// appelé à la fermeture - détruit tout
void flushAll() {
// vider toutes les frame queues
for (auto& queue : m_frameQueues) {
while (!queue.empty()) {
queue.front()();
queue.pop_front();
}
}
// vider la queue immédiate
while (!m_immediateQueue.empty()) {
m_immediateQueue.front()();
m_immediateQueue.pop_front();
}
}
};
#endif

View File

@@ -0,0 +1,10 @@
#include "GraphicsAPI.hpp"
#include "VulkanImpl.hpp"
#include <memory>
std::unique_ptr<GraphicsAPI> GraphicsAPI::impl = nullptr;
void GraphicsAPI::initAPI(){
//todo check config for chosen api
impl = std::make_unique<VulkanImpl>();
}

View File

@@ -0,0 +1,33 @@
#ifndef GRAPHICAPI_HPP
#define GRAPHICAPI_HPP
#include <SDL3/SDL_video.h>
#include <memory>
#include "../Shader/CShadersManager.hpp"
#include "../Data/CResourceManager.hpp"
enum class GraphicsBackend{
Vulkan,
OpenGL,
Metal
};
class GraphicsAPI{
static std::unique_ptr<GraphicsAPI> impl;
protected:
CShadersManager shadermanager;
CResourceManager resourceManager;
public:
static void initAPI();
static std::unique_ptr<GraphicsAPI>& getAPI(){return impl;};
virtual void init(SDL_Window* window) = 0;
virtual void cleanup() = 0;
virtual ~GraphicsAPI(){};
virtual void* getDevice() = 0;
virtual void drawFrame() = 0;
CShadersManager& getShaderManager(){return shadermanager;};
CResourceManager& getResourceManager(){return resourceManager;};
};
#endif

View File

@@ -0,0 +1,21 @@
#ifndef MANAGEDDESCRIPTORSET_HPP
#define MANAGEDDESCRIPTORSET_HPP
#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_raii.hpp>
#define MAX_FRAMES_IN_FLIGHT 2
struct ManagedDescriptorSet {
vk::raii::DescriptorSet set = nullptr;
VkDescriptorPool ownerPool = VK_NULL_HANDLE;
ManagedDescriptorSet() = default;
ManagedDescriptorSet(ManagedDescriptorSet&&) = default;
ManagedDescriptorSet& operator=(ManagedDescriptorSet&&) = default;
ManagedDescriptorSet(const ManagedDescriptorSet&) = delete;
ManagedDescriptorSet& operator=(const ManagedDescriptorSet&) = delete;
};
#endif

View File

@@ -0,0 +1,15 @@
#ifndef VMABUFFER_HPP
#define VMABUFFER_HPP
#include "vk_mem_alloc.h"
typedef struct vmaBufferStruct {
VkBuffer buffer = VK_NULL_HANDLE;
VmaAllocation allocation = VK_NULL_HANDLE;
void destroy(VmaAllocator allocator) {
vmaDestroyBuffer(allocator, buffer, allocation);
}
}VMABuffer;
#endif

View File

@@ -0,0 +1,2 @@
#define VMA_IMPLEMENTATION
#include "vk_mem_alloc.h"

View File

@@ -0,0 +1,789 @@
#include "VulkanImpl.hpp"
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_video.h>
#include <SDL3/SDL_vulkan.h>
#include <iostream>
#include <memory>
#include <vector>
#include <vulkan/vulkan.hpp>
#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_raii.hpp>
#include "../../Kernel/CKernel.hpp"
#include "DeletionQueue.hpp"
#include "vulkan/vulkan.hpp"
static uint32_t chooseSwapMinImageCount(vk::SurfaceCapabilitiesKHR const &surfaceCapabilities)
{
auto minImageCount = std::max(3u, surfaceCapabilities.minImageCount);
if ((0 < surfaceCapabilities.maxImageCount) && (surfaceCapabilities.maxImageCount < minImageCount))
{
minImageCount = surfaceCapabilities.maxImageCount;
}
return minImageCount;
}
static vk::SurfaceFormatKHR chooseSwapSurfaceFormat(std::vector<vk::SurfaceFormatKHR> const &availableFormats)
{
assert(!availableFormats.empty());
const auto formatIt = std::ranges::find_if(
availableFormats,
[](const auto &format) { return format.format == vk::Format::eB8G8R8A8Srgb && format.colorSpace == vk::ColorSpaceKHR::eSrgbNonlinear; });
return formatIt != availableFormats.end() ? *formatIt : availableFormats[0];
}
static vk::PresentModeKHR chooseSwapPresentMode(const std::vector<vk::PresentModeKHR> &availablePresentModes)
{
assert(std::ranges::any_of(availablePresentModes, [](auto presentMode) { return presentMode == vk::PresentModeKHR::eFifo; }));
return std::ranges::any_of(availablePresentModes,
[](const vk::PresentModeKHR value) { return vk::PresentModeKHR::eMailbox == value; }) ?
vk::PresentModeKHR::eMailbox :
vk::PresentModeKHR::eFifo;
}
vk::Extent2D chooseSwapExtent(const vk::SurfaceCapabilitiesKHR &capabilities, SDL_Window* window)
{
if (capabilities.currentExtent.width != 0xFFFFFFFF)
{
return capabilities.currentExtent;
}
int width, height;
SDL_GetWindowSizeInPixels(window, &width, &height);
return {
std::clamp<uint32_t>(width, capabilities.minImageExtent.width, capabilities.maxImageExtent.width),
std::clamp<uint32_t>(height, capabilities.minImageExtent.height, capabilities.maxImageExtent.height)};
}
void VulkanImpl::init(SDL_Window* window){
m_window = window;
createInstance();
createSurface();
pickPhysicalDevice();
createLogicalDevice();
//getShaders after creating device
shadermanager.create();
shadermanager.compile();
createSwapChain();
createImageViews();
createDescriptorSetLayouts();
//createGraphicsPipeline();
createDepthResources();
createCommandPool();
createDescriptorPool();
createDefaultTexture();
createCommandBuffer();
createSyncObjects();
}
void VulkanImpl::cleanup(){
device.waitIdle();
// 1. détruire les ressources dans le ResourceManager
// (buffers, pipelines, descriptor sets...)
m_deletionQueue.flushAll();
CosmicCore::CKernel::m_kernel->cleanup();
resourceManager.cleanup();
shadermanager.cleanup();
m_deletionQueue.flushAll();
// 2. sync objects
inFlightFences.clear();
renderFinishedSemaphores.clear();
presentCompleteSemaphores.clear();
// 3. command buffers puis command pool
commandBuffers.clear();
commandPool = nullptr;
// 4. swapchain
cleanupSwapChain();
// descriptor set layouts + pipeline layout avant le device
defaultPipelineLayoutInfo = nullptr;
cameraLayout = nullptr;
transformLayout = nullptr;
materialLayout = nullptr;
VmaTotalStatistics stats;
vmaCalculateStatistics(allocator, &stats);
if (stats.total.statistics.allocationCount > 0) {
std::cout << "VMA: " << stats.total.statistics.allocationCount
<< " allocations non libérées !" << std::endl;
std::cout << "VMA: " << stats.total.statistics.allocationBytes
<< " bytes non libérés" << std::endl;
}
//Vulkan memory allocator
vmaDestroyAllocator(allocator);
// 5. surface
surface = nullptr;
// 6. device en avant-dernier
device = nullptr;
// 7. instance en dernier
instance = nullptr;
}
void VulkanImpl::createInstance(){
constexpr vk::ApplicationInfo appInfo{ "CosmicEngine",
VK_MAKE_VERSION( 1, 0, 0 ),
"No Engine",
VK_MAKE_VERSION( 1, 0, 0 ),
vk::ApiVersion13};
uint32_t sdl_extensions_count = 0;
const char* const* sdl_extensions = SDL_Vulkan_GetInstanceExtensions(&sdl_extensions_count);
auto extensionProp = context.enumerateInstanceExtensionProperties();
for (uint32_t i = 0; i < sdl_extensions_count; ++i)
{
if (std::ranges::none_of(extensionProp,
[sdlExtension = sdl_extensions[i]](auto const& extensionProperty)
{ return strcmp(extensionProperty.extensionName, sdlExtension) == 0; }))
{
throw std::runtime_error("Required SDL extension not supported: " + std::string(sdl_extensions[i]));
}
}
// Get the required layers
std::vector<char const*> requiredLayers;
if (enableValidationLayers)
{
requiredLayers.assign(validationLayers.begin(), validationLayers.end());
}
// Check if the required layers are supported by the Vulkan implementation.
auto layerProperties = context.enumerateInstanceLayerProperties();
auto unsupportedLayerIt = std::ranges::find_if(requiredLayers,
[&layerProperties](auto const &requiredLayer) {
return std::ranges::none_of(layerProperties,
[requiredLayer](auto const &layerProperty) { return strcmp(layerProperty.layerName, requiredLayer) == 0; });
});
if (unsupportedLayerIt != requiredLayers.end())
{
throw std::runtime_error("Required layer not supported: " + std::string(*unsupportedLayerIt));
}
vk::InstanceCreateInfo createInfo{{},&appInfo, static_cast<uint32_t>(requiredLayers.size()), requiredLayers.data(), sdl_extensions_count, sdl_extensions};
instance = vk::raii::Instance(context, createInfo);
}
void VulkanImpl::pickPhysicalDevice()
{
std::vector<vk::raii::PhysicalDevice> devices = instance.enumeratePhysicalDevices();
const auto devIter = std::ranges::find_if(
devices,
[&](auto const &device) {
// Check if the device supports the Vulkan 1.3 API version
bool supportsVulkan1_3 = device.getProperties().apiVersion >= VK_API_VERSION_1_3;
// Check if any of the queue families support graphics operations
auto queueFamilies = device.getQueueFamilyProperties();
bool supportsGraphics =
std::ranges::any_of(queueFamilies, [](auto const &qfp) { return !!(qfp.queueFlags & vk::QueueFlagBits::eGraphics); });
// Check if all required device extensions are available
auto availableDeviceExtensions = device.enumerateDeviceExtensionProperties();
bool supportsAllRequiredExtensions =
std::ranges::all_of(requiredDeviceExtension,
[&availableDeviceExtensions](auto const &requiredDeviceExtension) {
return std::ranges::any_of(availableDeviceExtensions,
[requiredDeviceExtension](auto const &availableDeviceExtension) { return strcmp(availableDeviceExtension.extensionName, requiredDeviceExtension) == 0; });
});
auto features = device.template getFeatures2<vk::PhysicalDeviceFeatures2, vk::PhysicalDeviceVulkan13Features, vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>();
bool supportsRequiredFeatures = features.template get<vk::PhysicalDeviceVulkan13Features>().dynamicRendering &&
features.template get<vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT>().extendedDynamicState;
return supportsVulkan1_3 && supportsGraphics && supportsAllRequiredExtensions && supportsRequiredFeatures;
});
if (devIter != devices.end())
{
physicalDevice = *devIter;
}
else
{
throw std::runtime_error("failed to find a suitable GPU!");
}
}
void VulkanImpl::createLogicalDevice()
{
// find the index of the first queue family that supports graphics
std::vector<vk::QueueFamilyProperties> queueFamilyProperties = physicalDevice.getQueueFamilyProperties();
// get the first index into queueFamilyProperties which supports graphics
auto graphicsQueueFamilyProperty = std::ranges::find_if(queueFamilyProperties, [](auto const &qfp) { return (qfp.queueFlags & vk::QueueFlagBits::eGraphics) != static_cast<vk::QueueFlags>(0); });
assert(graphicsQueueFamilyProperty != queueFamilyProperties.end() && "No graphics queue family found!");
auto graphicsIndex = static_cast<uint32_t>(std::distance(queueFamilyProperties.begin(), graphicsQueueFamilyProperty));
// determine a queueFamilyIndex that supports present
// first check if the graphicsIndex is good enough
auto presentIndex = physicalDevice.getSurfaceSupportKHR( graphicsIndex, *surface )
? graphicsIndex
: static_cast<uint32_t>( queueFamilyProperties.size() );
if ( presentIndex == queueFamilyProperties.size() )
{
// the graphicsIndex doesn't support present -> look for another family index that supports both
// graphics and present
for ( size_t i = 0; i < queueFamilyProperties.size(); i++ )
{
if ( ( queueFamilyProperties[i].queueFlags & vk::QueueFlagBits::eGraphics ) &&
physicalDevice.getSurfaceSupportKHR( static_cast<uint32_t>( i ), *surface ) )
{
graphicsIndex = static_cast<uint32_t>( i );
presentIndex = graphicsIndex;
queueIndex = graphicsIndex;
break;
}
}
if ( presentIndex == queueFamilyProperties.size() )
{
// there's nothing like a single family index that supports both graphics and present -> look for another
// family index that supports present
for ( size_t i = 0; i < queueFamilyProperties.size(); i++ )
{
if ( physicalDevice.getSurfaceSupportKHR( static_cast<uint32_t>( i ), *surface ) )
{
presentIndex = static_cast<uint32_t>( i );
break;
}
}
}
}
if ( ( graphicsIndex == queueFamilyProperties.size() ) || ( presentIndex == queueFamilyProperties.size() ) )
{
throw std::runtime_error( "Could not find a queue for graphics or present -> terminating" );
}
queueIndex = graphicsIndex;
// query for Vulkan 1.3 features
auto features = physicalDevice.getFeatures2();
vk::PhysicalDeviceVulkan11Features vulkan11Features;
vulkan11Features.shaderDrawParameters = vk::True;
vk::PhysicalDeviceVulkan13Features vulkan13Features;
vk::PhysicalDeviceExtendedDynamicStateFeaturesEXT extendedDynamicStateFeatures;
vulkan13Features.dynamicRendering = vk::True;
vulkan13Features.synchronization2 = vk::True;
extendedDynamicStateFeatures.extendedDynamicState = vk::True;
vulkan11Features.pNext = &vulkan13Features;
vulkan13Features.pNext = &extendedDynamicStateFeatures;
features.pNext = &vulkan11Features;
// create a Device
float queuePriority = 0.5f;
vk::DeviceQueueCreateInfo deviceQueueCreateInfo{{},
graphicsIndex,
1,
&queuePriority};
vk::DeviceCreateInfo deviceCreateInfo{{},
1,
&deviceQueueCreateInfo,
{},
{},
static_cast<uint32_t>(requiredDeviceExtension.size()),
requiredDeviceExtension.data(),
{},
&features
};
device = vk::raii::Device(physicalDevice, deviceCreateInfo);
graphicsQueue = vk::raii::Queue(device, graphicsIndex, 0);
presentQueue = vk::raii::Queue( device, presentIndex, 0 );
VmaAllocatorCreateInfo allocatorInfo{};
allocatorInfo.physicalDevice = *physicalDevice;
allocatorInfo.device = *device;
allocatorInfo.instance = *instance;
allocatorInfo.vulkanApiVersion = VK_API_VERSION_1_3;
vmaCreateAllocator(&allocatorInfo, &allocator);
}
void VulkanImpl::createSurface()
{
VkSurfaceKHR _surface;
if (!SDL_Vulkan_CreateSurface(m_window, *instance, nullptr, &_surface)) {
throw std::runtime_error("failed to create window surface!");
}
surface = vk::raii::SurfaceKHR(instance, _surface);
}
void VulkanImpl::createSwapChain()
{
auto surfaceCapabilities = physicalDevice.getSurfaceCapabilitiesKHR(*surface);
swapChainExtent = chooseSwapExtent(surfaceCapabilities, m_window);
swapChainSurfaceFormat = chooseSwapSurfaceFormat(physicalDevice.getSurfaceFormatsKHR(*surface));
vk::SwapchainCreateInfoKHR swapChainCreateInfo{ {},
*surface,
chooseSwapMinImageCount(surfaceCapabilities),
swapChainSurfaceFormat.format,
swapChainSurfaceFormat.colorSpace,
swapChainExtent,
1,
vk::ImageUsageFlagBits::eColorAttachment,
vk::SharingMode::eExclusive,
{},
surfaceCapabilities.currentTransform,
vk::CompositeAlphaFlagBitsKHR::eOpaque,
chooseSwapPresentMode(physicalDevice.getSurfacePresentModesKHR(*surface)),
true};
swapChain = vk::raii::SwapchainKHR(device, swapChainCreateInfo);
swapChainImages = swapChain.getImages();
}
void VulkanImpl::createImageViews()
{
vk::ImageViewCreateInfo imageViewCreateInfo{
{},
{},
vk::ImageViewType::e2D,
swapChainSurfaceFormat.format,
{},
{vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}
};
for (auto& image : swapChainImages)
{
imageViewCreateInfo.image = image;
swapChainImageViews.emplace_back(device, imageViewCreateInfo);
}
}
vk::raii::ImageView VulkanImpl::createImageView(vk::raii::Image& image, vk::Format format, vk::ImageAspectFlags aspectFlags)
{
vk::ImageViewCreateInfo imageViewCreateInfo{
{},
image,
vk::ImageViewType::e2D,
format,
{},
{aspectFlags, 0, 1, 0, 1}
};
return vk::raii::ImageView(device, imageViewCreateInfo);
}
void VulkanImpl::createCommandPool()
{
vk::CommandPoolCreateInfo poolInfo{vk::CommandPoolCreateFlagBits::eResetCommandBuffer, queueIndex};
commandPool = vk::raii::CommandPool(device, poolInfo);
}
void VulkanImpl::createCommandBuffer()
{
vk::CommandBufferAllocateInfo allocInfo{commandPool, vk::CommandBufferLevel::ePrimary, MAX_FRAMES_IN_FLIGHT};
commandBuffers = vk::raii::CommandBuffers(device, allocInfo);
}
void VulkanImpl::recordCommandBuffer(uint32_t imageIndex)
{
auto &commandBuffer = commandBuffers[frameIndex];
commandBuffer.begin({});
// Before starting rendering, transition the swapchain image to COLOR_ATTACHMENT_OPTIMAL
transitionImageLayout(
swapChainImages[imageIndex],
vk::ImageLayout::eUndefined,
vk::ImageLayout::eColorAttachmentOptimal,
{}, // srcAccessMask (no need to wait for previous operations)
vk::AccessFlagBits2::eColorAttachmentWrite, // dstAccessMask
vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage
vk::PipelineStageFlagBits2::eColorAttachmentOutput, // dstStage
vk::ImageAspectFlagBits::eColor
);
// Transition depth image to depth attachment optimal layout
transitionImageLayout(
depthImage,
vk::ImageLayout::eUndefined,
vk::ImageLayout::eDepthAttachmentOptimal,
vk::AccessFlagBits2::eDepthStencilAttachmentWrite,
vk::AccessFlagBits2::eDepthStencilAttachmentWrite,
vk::PipelineStageFlagBits2::eEarlyFragmentTests | vk::PipelineStageFlagBits2::eLateFragmentTests,
vk::PipelineStageFlagBits2::eEarlyFragmentTests | vk::PipelineStageFlagBits2::eLateFragmentTests,
vk::ImageAspectFlagBits::eDepth);
vk::ClearValue clearColor = vk::ClearColorValue(0.0f, 0.0f, 0.0f, 1.0f);
vk::ClearValue clearDepth = vk::ClearDepthStencilValue(1.0f, 0);
//color
vk::RenderingAttachmentInfo attachmentInfo = {
swapChainImageViews[imageIndex],
vk::ImageLayout::eColorAttachmentOptimal,
{},
{},
{},
vk::AttachmentLoadOp::eClear,
vk::AttachmentStoreOp::eStore,
clearColor
};
//depth
vk::RenderingAttachmentInfo depthAttachmentInfo = {
depthImageView,
vk::ImageLayout::eDepthAttachmentOptimal,
{},
{},
{},
vk::AttachmentLoadOp::eClear,
vk::AttachmentStoreOp::eDontCare,
clearDepth};
vk::RenderingInfo renderingInfo = {{},{{0, 0}, swapChainExtent},
1,
{},
1,
&attachmentInfo,
&depthAttachmentInfo};
commandBuffer.beginRendering(renderingInfo);
commandBuffer.setViewport(0, vk::Viewport(0.0f, 0.0f, static_cast<float>(swapChainExtent.width), static_cast<float>(swapChainExtent.height), 0.0f, 1.0f));
commandBuffer.setScissor(0, vk::Rect2D(vk::Offset2D(0, 0), swapChainExtent));
CosmicCore::CKernel::m_kernel->getActiveScene()->render(commandBuffer, frameIndex);
commandBuffer.endRendering();
// After rendering, transition the swapchain image to PRESENT_SRC
transitionImageLayout(
swapChainImages[imageIndex],
vk::ImageLayout::eColorAttachmentOptimal,
vk::ImageLayout::ePresentSrcKHR,
vk::AccessFlagBits2::eColorAttachmentWrite, // srcAccessMask
{}, // dstAccessMask
vk::PipelineStageFlagBits2::eColorAttachmentOutput, // srcStage
vk::PipelineStageFlagBits2::eBottomOfPipe, // dstStage
vk::ImageAspectFlagBits::eColor
);
commandBuffer.end();
}
void VulkanImpl::transitionImageLayout(
vk::Image image,
vk::ImageLayout old_layout,
vk::ImageLayout new_layout,
vk::AccessFlags2 src_access_mask,
vk::AccessFlags2 dst_access_mask,
vk::PipelineStageFlags2 src_stage_mask,
vk::PipelineStageFlags2 dst_stage_mask, vk::ImageAspectFlags image_aspect_flags)
{
vk::ImageMemoryBarrier2 barrier = {src_stage_mask, src_access_mask, dst_stage_mask, dst_access_mask, old_layout, new_layout, VK_QUEUE_FAMILY_IGNORED, VK_QUEUE_FAMILY_IGNORED, image, {image_aspect_flags,0,1,0,1}};
vk::DependencyInfo dependency_info = {{},{},{},{}, {}, 1,&barrier};
commandBuffers[frameIndex].pipelineBarrier2(dependency_info);
}
void VulkanImpl::createSyncObjects()
{
for (size_t i = 0; i < swapChainImages.size(); i++)
{
renderFinishedSemaphores.emplace_back(device, vk::SemaphoreCreateInfo());
}
for (size_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++)
{
presentCompleteSemaphores.emplace_back(device, vk::SemaphoreCreateInfo());
inFlightFences.emplace_back(device, vk::FenceCreateInfo{vk::FenceCreateFlagBits::eSignaled});
}
}
void VulkanImpl::drawFrame()
{
auto fenceResult = device.waitForFences(*inFlightFences[frameIndex], vk::True, UINT64_MAX);
m_deletionQueue.flush(frameIndex); // détruit les ressources de cette frame
if (fenceResult != vk::Result::eSuccess)
{
throw std::runtime_error("failed to wait for fence!");
}
device.resetFences(*inFlightFences[frameIndex]);
auto [result, imageIndex] = swapChain.acquireNextImage(UINT64_MAX, *presentCompleteSemaphores[frameIndex], nullptr);
commandBuffers[frameIndex].reset();
recordCommandBuffer(imageIndex);
vk::PipelineStageFlags waitDestinationStageMask(vk::PipelineStageFlagBits::eColorAttachmentOutput);
const vk::SubmitInfo submitInfo{1, &*presentCompleteSemaphores[frameIndex], &waitDestinationStageMask, 1, &*commandBuffers[frameIndex], 1, &*renderFinishedSemaphores[imageIndex]};
presentQueue.submit(submitInfo, *inFlightFences[frameIndex]);
const vk::PresentInfoKHR presentInfoKHR{1, &*renderFinishedSemaphores[imageIndex], 1, &*swapChain, &imageIndex};
result = presentQueue.presentKHR(presentInfoKHR);
// Due to VULKAN_HPP_HANDLE_ERROR_OUT_OF_DATE_AS_SUCCESS being defined, eErrorOutOfDateKHR can be checked as a result
// here and does not need to be caught by an exception.
if ((result == vk::Result::eSuboptimalKHR) || (result == vk::Result::eErrorOutOfDateKHR) || framebufferResized)
{
framebufferResized = false;
recreateSwapChain();
}
else
{
// There are no other success codes than eSuccess; on any error code, presentKHR already threw an exception.
assert(result == vk::Result::eSuccess);
}
frameIndex = (frameIndex + 1) % MAX_FRAMES_IN_FLIGHT;
}
void VulkanImpl::cleanupSwapChain()
{
depthImageView = nullptr;
depthImage = nullptr;
depthImageMemory = nullptr;
swapChainImageViews.clear();
swapChain = nullptr;
swapChainImages.clear();
}
void VulkanImpl::recreateSwapChain()
{
int width = 0, height = 0;
SDL_GetWindowSizeInPixels(m_window, &width, &height);
while (width == 0 || height == 0) {
SDL_GetWindowSizeInPixels(m_window, &width, &height);
SDL_WaitEvent(nullptr);
}
device.waitIdle();
cleanupSwapChain();
createSwapChain();
createImageViews();
createDepthResources();
}
uint32_t VulkanImpl::findMemoryType(uint32_t typeFilter, vk::MemoryPropertyFlags properties)
{
vk::PhysicalDeviceMemoryProperties memProperties = physicalDevice.getMemoryProperties();
for (uint32_t i = 0; i < memProperties.memoryTypeCount; i++)
{
if ((typeFilter & (1 << i)) && (memProperties.memoryTypes[i].propertyFlags & properties) == properties)
{
return i;
}
}
throw std::runtime_error("failed to find suitable memory type!");
}
void VulkanImpl::copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size) {
vk::raii::CommandBuffer commandCopyBuffer = beginSingleTimeCommands();
commandCopyBuffer.copyBuffer(vk::Buffer(src), vk::Buffer(dst), vk::BufferCopy(0, 0, size));
endSingleTimeCommands(commandCopyBuffer);
}
void VulkanImpl::createDescriptorSetLayouts()
{
// set 0 - Camera : un UBO en vertex shader
vk::DescriptorSetLayoutBinding cameraBinding{
0, // binding
vk::DescriptorType::eUniformBuffer, // type
1, // count
vk::ShaderStageFlagBits::eVertex, // stage
nullptr
};
cameraLayout = vk::raii::DescriptorSetLayout(
device,
vk::DescriptorSetLayoutCreateInfo{{}, 1, &cameraBinding}
);
// set 1 - Transform : un UBO en vertex shader
vk::DescriptorSetLayoutBinding transformBinding{
0,
vk::DescriptorType::eUniformBuffer,
1,
vk::ShaderStageFlagBits::eVertex,
nullptr
};
transformLayout = vk::raii::DescriptorSetLayout(
device,
vk::DescriptorSetLayoutCreateInfo{{}, 1, &transformBinding}
);
// set 2 - Material : un UBO + deux samplers en fragment shader
std::array<vk::DescriptorSetLayoutBinding, 3> materialBindings{{
{0, vk::DescriptorType::eUniformBuffer, 1, vk::ShaderStageFlagBits::eFragment, nullptr},
{1, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment, nullptr},
{2, vk::DescriptorType::eCombinedImageSampler, 1, vk::ShaderStageFlagBits::eFragment, nullptr},
}};
materialLayout = vk::raii::DescriptorSetLayout(
device,
vk::DescriptorSetLayoutCreateInfo{{},
static_cast<uint32_t>(materialBindings.size()),
materialBindings.data()}
);
std::array<vk::DescriptorSetLayout, 3> layouts{
*cameraLayout,
*transformLayout,
*materialLayout
};
vk::PipelineLayoutCreateInfo layoutInfo{{},
static_cast<uint32_t>(layouts.size()),
layouts.data()
};
defaultPipelineLayoutInfo = vk::raii::PipelineLayout(device, layoutInfo);
}
//Fonction d'ajout de descriptor set qui regarde la taille de la pool, si la pool est dépassée, on ajoute une pool 2x plus grande
void VulkanImpl::createDescriptorPool()
{
descriptorPoolManager.init(device);
}
void VulkanImpl::createDepthResources()
{
vk::Format depthFormat = findDepthFormat();
createImage(swapChainExtent.width, swapChainExtent.height, depthFormat, vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eDepthStencilAttachment, vk::MemoryPropertyFlagBits::eDeviceLocal, depthImage, depthImageMemory);
depthImageView = createImageView(depthImage, depthFormat, vk::ImageAspectFlagBits::eDepth);
}
vk::Format VulkanImpl::findSupportedFormat(const std::vector<vk::Format>& candidates, vk::ImageTiling tiling, vk::FormatFeatureFlags features)
{
for (const auto format : candidates) {
vk::FormatProperties props = physicalDevice.getFormatProperties(format);
if (tiling == vk::ImageTiling::eLinear && (props.linearTilingFeatures & features) == features) {
return format;
}
if (tiling == vk::ImageTiling::eOptimal && (props.optimalTilingFeatures & features) == features) {
return format;
}
}
throw std::runtime_error("failed to find supported format!");
}
vk::Format VulkanImpl::findDepthFormat() {
return findSupportedFormat(
{vk::Format::eD32Sfloat, vk::Format::eD32SfloatS8Uint, vk::Format::eD24UnormS8Uint},
vk::ImageTiling::eOptimal,
vk::FormatFeatureFlagBits::eDepthStencilAttachment
);
}
bool VulkanImpl::hasStencilComponent(vk::Format format) {
return format == vk::Format::eD32SfloatS8Uint || format == vk::Format::eD24UnormS8Uint;
}
void VulkanImpl::createImage(uint32_t width, uint32_t height, vk::Format format, vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::MemoryPropertyFlags properties, vk::raii::Image &image, vk::raii::DeviceMemory &imageMemory)
{
vk::ImageCreateInfo imageInfo{{},vk::ImageType::e2D, format, {width, height, 1}, 1, 1, vk::SampleCountFlagBits::e1, tiling, usage, vk::SharingMode::eExclusive};
image = vk::raii::Image(device, imageInfo);
vk::MemoryRequirements memRequirements = image.getMemoryRequirements();
vk::MemoryAllocateInfo allocInfo{memRequirements.size,
findMemoryType(memRequirements.memoryTypeBits, properties)};
imageMemory = vk::raii::DeviceMemory(device, allocInfo);
image.bindMemory(imageMemory, 0);
}
vk::raii::CommandBuffer VulkanImpl::beginSingleTimeCommands() {
vk::CommandBufferAllocateInfo allocInfo{ commandPool, vk::CommandBufferLevel::ePrimary, 1 };
vk::raii::CommandBuffer commandBuffer = std::move(device.allocateCommandBuffers(allocInfo).front());
vk::CommandBufferBeginInfo beginInfo{ vk::CommandBufferUsageFlagBits::eOneTimeSubmit };
commandBuffer.begin(beginInfo);
return commandBuffer;
}
void VulkanImpl::endSingleTimeCommands(vk::raii::CommandBuffer& commandBuffer) {
commandBuffer.end();
vk::SubmitInfo submitInfo{{},{},{},1, &*commandBuffer };
graphicsQueue.submit(submitInfo, nullptr);
graphicsQueue.waitIdle();
}
void VulkanImpl::transitionImageLayout(vk::Image image, vk::ImageLayout oldLayout, vk::ImageLayout newLayout)
{
auto commandBuffer = beginSingleTimeCommands();
vk::ImageMemoryBarrier barrier{{},{},oldLayout, newLayout,{}, {}, image, {vk::ImageAspectFlagBits::eColor, 0, 1, 0, 1}};
vk::PipelineStageFlags sourceStage;
vk::PipelineStageFlags destinationStage;
if (oldLayout == vk::ImageLayout::eUndefined && newLayout == vk::ImageLayout::eTransferDstOptimal)
{
barrier.srcAccessMask = {};
barrier.dstAccessMask = vk::AccessFlagBits::eTransferWrite;
sourceStage = vk::PipelineStageFlagBits::eTopOfPipe;
destinationStage = vk::PipelineStageFlagBits::eTransfer;
}
else if (oldLayout == vk::ImageLayout::eTransferDstOptimal && newLayout == vk::ImageLayout::eShaderReadOnlyOptimal)
{
barrier.srcAccessMask = vk::AccessFlagBits::eTransferWrite;
barrier.dstAccessMask = vk::AccessFlagBits::eShaderRead;
sourceStage = vk::PipelineStageFlagBits::eTransfer;
destinationStage = vk::PipelineStageFlagBits::eFragmentShader;
}
else
{
throw std::invalid_argument("unsupported layout transition!");
}
commandBuffer.pipelineBarrier(sourceStage, destinationStage, {}, {}, nullptr, barrier);
endSingleTimeCommands(commandBuffer);
}
void VulkanImpl::copyBufferToImage(const vk::raii::Buffer &buffer, vk::raii::Image &image, uint32_t width, uint32_t height)
{
auto commandBuffer = beginSingleTimeCommands();
vk::BufferImageCopy region{0, 0, 0, {vk::ImageAspectFlagBits::eColor, 0, 0, 1}, {0, 0, 0}, {width, height, 1}};
commandBuffer.copyBufferToImage(buffer, image, vk::ImageLayout::eTransferDstOptimal, {region});
endSingleTimeCommands(commandBuffer);
}
void VulkanImpl::destroyBuffer(VMABuffer& buffer, uint32_t frame) {
VmaAllocator& alloc = allocator;
VkBuffer& buf = buffer.buffer;
VmaAllocation& mem = buffer.allocation;
m_deletionQueue.push(frame, [alloc, buf, mem]() {
vmaDestroyBuffer(alloc, buf, mem);
});
buffer.buffer = VK_NULL_HANDLE;
buffer.allocation = VK_NULL_HANDLE;
}
// destruction d'un descriptor set
void VulkanImpl::destroyDescriptorSet(ManagedDescriptorSet& set, uint32_t frame) {
auto s = std::make_shared<ManagedDescriptorSet>(std::move(set));
m_deletionQueue.push(frame, [&dpm = descriptorPoolManager, s]() mutable {
dpm.free(*s);
});
}
void VulkanImpl::destroyPipeline(vk::raii::Pipeline& pipeline, vk::raii::PipelineLayout& layout)
{
auto p = std::make_shared<vk::raii::Pipeline>(std::move(pipeline));
auto pl = std::make_shared<vk::raii::PipelineLayout>(std::move(layout));
m_deletionQueue.push(frameIndex, [p, pl]() mutable {
p = nullptr;
pl = nullptr;
});
}
void VulkanImpl::createDefaultTexture()
{
auto def = std::make_unique<CTexture>("");
def.get()->initDefaultTexture();
m_defaultTexture = def.get();
getResourceManager().getTextureManager().addTexture("default", std::move(def));
}

View File

@@ -0,0 +1,226 @@
#ifndef VULKANIMPL_HPP
#define VULKANIMPL_HPP
#include "GraphicsAPI.hpp"
#include "DeletionQueue.hpp"
#include <vector>
#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_raii.hpp>
#include "vk_mem_alloc.h"
#include "vulkan/vulkan.hpp"
#include "ManagedDescriptorSet.hpp"
const std::vector<char const*> validationLayers = {
"VK_LAYER_KHRONOS_validation"
};
#ifdef NDEBUG
constexpr bool enableValidationLayers = false;
#else
constexpr bool enableValidationLayers = true;
#endif
class DescriptorAllocator {
struct Pool {
vk::raii::DescriptorPool pool = nullptr;
uint32_t capacity = 0;
uint32_t allocated = 0;
bool isFull() const { return allocated >= capacity; }
bool isEmpty() const { return allocated == 0; }
};
vk::raii::Device* m_device = nullptr;
uint32_t m_baseSize = 64;
std::vector<Pool> m_pools;
Pool createPool(uint32_t size) {
std::vector<vk::DescriptorPoolSize> sizes = {
{vk::DescriptorType::eUniformBuffer, size * 2},
{vk::DescriptorType::eCombinedImageSampler, size * 2},
};
Pool p;
p.capacity = size;
p.pool = vk::raii::DescriptorPool(*m_device,
vk::DescriptorPoolCreateInfo{
vk::DescriptorPoolCreateFlagBits::eFreeDescriptorSet,
size,
static_cast<uint32_t>(sizes.size()),
sizes.data()
}
);
return p;
}
Pool& getAvailablePool() {
// cherche une pool non pleine
for (auto& p : m_pools)
if (!p.isFull()) return p;
//nouvelle pool x2
uint32_t newSize = m_pools.empty()
? m_baseSize
: m_pools.back().capacity * 2;
return m_pools.emplace_back(createPool(newSize));
}
public:
void init(vk::raii::Device& device) { m_device = &device; }
ManagedDescriptorSet allocate(vk::DescriptorSetLayout layout) {
auto& p = getAvailablePool();
vk::DescriptorSetAllocateInfo allocInfo{*p.pool, 1, &layout};
auto sets = m_device->allocateDescriptorSets(allocInfo);
p.allocated++;
ManagedDescriptorSet mds;
mds.set = std::move(sets[0]);
mds.ownerPool = *p.pool;
return mds;
}
void free(ManagedDescriptorSet& man) {
// retrouve la pool du set pour décrémenter
VkDescriptorPool rawPool = man.ownerPool; // handle de la pool parente
man.set = nullptr; // libère vk::raii free
for (auto it = m_pools.begin(); it != m_pools.end(); ++it) {
if (*it->pool == rawPool) {
it->allocated--;
if (it->isEmpty())
m_pools.erase(it);
return;
}
}
}
};
class VulkanImpl: public GraphicsAPI{
private:
vk::raii::Context context;
vk::raii::Instance instance = nullptr;
vk::raii::PhysicalDevice physicalDevice = nullptr;
std::vector<const char *> requiredDeviceExtension = {
vk::KHRSwapchainExtensionName};
vk::raii::Device device = nullptr;
vk::raii::Queue graphicsQueue = nullptr;
vk::raii::Queue presentQueue = nullptr;
uint32_t queueIndex = ~0;
vk::raii::SurfaceKHR surface = nullptr;
vk::raii::SwapchainKHR swapChain = nullptr;
std::vector<vk::Image> swapChainImages;
vk::SurfaceFormatKHR swapChainSurfaceFormat;
vk::Extent2D swapChainExtent;
std::vector<vk::raii::ImageView> swapChainImageViews;
vk::raii::CommandPool commandPool = nullptr;
std::vector<vk::raii::CommandBuffer> commandBuffers;
std::vector<vk::raii::Semaphore> presentCompleteSemaphores;
std::vector<vk::raii::Semaphore> renderFinishedSemaphores;
std::vector<vk::raii::Fence> inFlightFences;
uint32_t frameIndex = 0;
SDL_Window* m_window;
bool framebufferResized = false;
VmaAllocator allocator = nullptr;
vk::raii::DescriptorSetLayout cameraLayout = nullptr; // set 0
vk::raii::DescriptorSetLayout transformLayout = nullptr; // set 1
vk::raii::DescriptorSetLayout materialLayout = nullptr; // set 2
DescriptorAllocator descriptorPoolManager;
vk::raii::PipelineLayout defaultPipelineLayoutInfo = nullptr;
vk::raii::Image depthImage = nullptr;
vk::raii::DeviceMemory depthImageMemory = nullptr;
vk::raii::ImageView depthImageView = nullptr;
DeletionQueue m_deletionQueue;
CTexture* m_defaultTexture = nullptr;
public:
virtual ~VulkanImpl(){};
void init(SDL_Window* window) override;
void cleanup()override;
void createInstance();
void pickPhysicalDevice();
void createLogicalDevice();
void createSurface();
void createSwapChain();
void createImageViews();
//void createGraphicsPipeline();
void createCommandPool();
void createCommandBuffer();
void createSyncObjects();
void drawFrame() override;
void recreateSwapChain();
void createDescriptorSetLayouts();
void cleanupSwapChain();
void createDepthResources();
void transitionImageLayout(vk::Image image, vk::ImageLayout old_layout, vk::ImageLayout new_layout, vk::AccessFlags2 src_access_mask, vk::AccessFlags2 dst_access_mask, vk::PipelineStageFlags2 src_stage_mask, vk::PipelineStageFlags2 dst_stage_mask, vk::ImageAspectFlags image_aspect_flags);
void transitionImageLayout(vk::Image image, vk::ImageLayout oldLayout, vk::ImageLayout newLayout);
void recordCommandBuffer(uint32_t imageIndex);
void* getDevice()override {return &device;};
uint32_t findMemoryType(uint32_t typeFilter, vk::MemoryPropertyFlags properties);
vk::SurfaceFormatKHR& getSwapChainFormat(){return swapChainSurfaceFormat;};
uint32_t getGraphicsQueueIndex() const { return queueIndex; }
vk::Extent2D getSwapChainExtent() const { return swapChainExtent; }
// accès au command buffer courant pour que le Renderer puisse enregistrer
vk::raii::CommandBuffer& getCurrentCommandBuffer();
// accès à l'image view courante pour le color attachment
vk::raii::ImageView& getCurrentSwapChainImageView();
// pour que le Renderer sache quelle frame est en cours
uint32_t getCurrentFrameIndex() const { return frameIndex; }
VmaAllocator getAllocator() { return allocator; }
vk::raii::PhysicalDevice& getPhysicalDevice() { return physicalDevice; }
vk::raii::DescriptorSetLayout& getCameraLayout() { return cameraLayout; }
vk::raii::DescriptorSetLayout& getTransformLayout() { return transformLayout; }
vk::raii::DescriptorSetLayout& getMaterialLayout() { return materialLayout; }
void copyBuffer(VkBuffer src, VkBuffer dst, VkDeviceSize size);
vk::Format findSupportedFormat(const std::vector<vk::Format>& candidates, vk::ImageTiling tiling, vk::FormatFeatureFlags features);
vk::Format findDepthFormat();
bool hasStencilComponent(vk::Format format);
void createImage(uint32_t width, uint32_t height, vk::Format format, vk::ImageTiling tiling, vk::ImageUsageFlags usage, vk::MemoryPropertyFlags properties, vk::raii::Image &image, vk::raii::DeviceMemory &imageMemory);
DescriptorAllocator& getDescriptorPoolManager(){return descriptorPoolManager;};
void createDescriptorPool();
vk::raii::CommandBuffer beginSingleTimeCommands();
void endSingleTimeCommands(vk::raii::CommandBuffer& commandBuffer);
vk::raii::ImageView createImageView(vk::raii::Image& image, vk::Format format, vk::ImageAspectFlags aspectFlags);
void copyBufferToImage(const vk::raii::Buffer &buffer, vk::raii::Image &image, uint32_t width, uint32_t height);
void destroyBuffer(VMABuffer& buffer, uint32_t frameIndex);
void destroyDescriptorSet(ManagedDescriptorSet& set, uint32_t frameIndex);
void destroyPipeline(vk::raii::Pipeline& pipeline, vk::raii::PipelineLayout& layout);
vk::raii::PipelineLayout& getDefaultPipelineLayout(){return defaultPipelineLayoutInfo;};
DeletionQueue& getDeletionQueue(){return m_deletionQueue;};
CTexture* getDefaultTexture() { return m_defaultTexture; }
void createDefaultTexture();
};
#endif

View File

@@ -0,0 +1,42 @@
#include "CContext.hpp"
#include "API/GraphicsAPI.hpp"
#include <SDL3/SDL_init.h>
#include <SDL3_image/SDL_image.h>
bool CContext::m_screenSaver = false;
void CContext::init(SDL_InitFlags sdlFlags) {
// Log initialisation.
initLog();
// SDL Initialization.
if (SDL_Init(sdlFlags)) {
SDL_Quit();
//HandleException(CLibException(std::string("Unable to initialize SDL: ") + SDL_GetError()), true);
}
GraphicsAPI::initAPI();
}
bool CContext::isScreenSaverEnable(void) {
return m_screenSaver;
}
void CContext::setScreenSaverEnable(bool newScreenSaver) {
m_screenSaver = newScreenSaver;
if (m_screenSaver) {
SDL_EnableScreenSaver();
}
else {
SDL_DisableScreenSaver();
}
}
void CContext::quit(void) {
SDL_Quit();
}
void CContext::initLog(void) {
//todo
}

View File

@@ -0,0 +1,34 @@
#ifndef CCONTEXT_HPP
#define CCONTEXT_HPP
#include <SDL3/SDL.h>
#include <SDL3/SDL_init.h>
#include <SDL3_image/SDL_image.h>
#define LOG_FILE "CosmicEngine_%3N.log"
#define LOG_ROTATION_SIZE 1 * 1024 * 1024
#define LOG_MAX_SIZE 50 * 1024 * 1024
class CContext {
private:
// Say if the screenSaver is enabled.
static bool m_screenSaver;
public:
CContext(void) = delete;
static void init(SDL_InitFlags sdlFlags);
static void quit(void);
static bool isScreenSaverEnable(void);
static void setScreenSaverEnable(bool newScreenSaver);
private:
static void initLog(void);
};
#endif

View File

@@ -6,10 +6,6 @@ CModel::CModel(std::vector<CMesh*> meshes) :
}
CModel::~CModel(void) {
for (unsigned int i = 0; i < m_meshes.size(); i++)
{
delete m_meshes[i];
}
}
void CModel::load(void) {
@@ -21,12 +17,12 @@ void CModel::load(void) {
m_loaded = true;
}
void CModel::draw(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 lightPos, float intensity) {
/*void CModel::draw(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 lightPos, float intensity) {
// For each meshes of the model.
for (unsigned int i = 0; i < m_meshes.size(); i++) {
m_meshes[i]->draw(model, view, projection, lightPos, intensity);
}
}
}*/
std::vector<CMesh*>& CModel::getMeshes()
{

View File

@@ -0,0 +1,34 @@
#ifndef CMODEL_HPP
#define CMODEL_HPP
#include "Mesh/CMesh.hpp"
#include <glm/glm.hpp>
class CModel {
private:
std::vector<CMesh*> m_meshes;
bool m_loaded;
public:
CModel(void) = delete;
CModel(std::vector<CMesh*> meshes);
~CModel(void);
void load(void);
//void draw(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 lightPos, float intensity);
std::vector<CMesh*>& getMeshes(void);
void setMeshes(std::vector<CMesh*> meshes);
bool isLoaded(void);
};
#endif

View File

@@ -0,0 +1,151 @@
#include "CModelLoader.hpp"
#include "../API/GraphicsAPI.hpp"
#include <memory>
CModel* CModelLoader::loadModel(std::string fileName, CResourceManager& rm)
{
Assimp::Importer importer;
const aiScene* scene = importer.ReadFile(fileName,
aiProcess_Triangulate |
aiProcess_FlipUVs |
aiProcess_CalcTangentSpace |
aiProcess_GenNormals
);
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
throw std::runtime_error("Assimp: " + std::string(importer.GetErrorString()));
// dossier de base pour les textures relatives
std::vector<CMesh*> meshes;
processNode(scene->mRootNode, scene, fileName, rm, meshes);
// crée et enregistre le model
auto model = std::make_unique<CModel>(meshes);
auto* ptr = model.get();
rm.getModelManager().addModel(fileName,std::move(model));
return ptr;
}
void CModelLoader::processNode(aiNode* node, const aiScene* scene, const std::string& directory, CResourceManager& rm, std::vector<CMesh*>& meshes)
{
// process all the node's meshes (if any)
for (uint32_t i = 0; i < node->mNumMeshes; i++) {
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
meshes.push_back(processMesh(mesh, scene, directory, rm));
}
// then do the same for each of its children
for (uint32_t i = 0; i < node->mNumChildren; i++) {
processNode(node->mChildren[i], scene, directory, rm, meshes);
}
}
CMesh* CModelLoader::processMesh(aiMesh* mesh, const aiScene* scene, const std::string& directory, CResourceManager& rm)
{
std::vector<SVertex> vertices;
std::vector<uint32_t> indices;
// vertices
for (uint32_t i = 0; i < mesh->mNumVertices; i++) {
SVertex vertex{};
vertex.m_position = {
mesh->mVertices[i].x,
mesh->mVertices[i].y,
mesh->mVertices[i].z
};
vertex.m_normal = mesh->HasNormals() ?
glm::vec3(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z) :
glm::vec3(0.0f);
vertex.m_texCoords = mesh->mTextureCoords[0] ?
glm::vec2(mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y) :
glm::vec2(0.0f);
vertex.m_tangent = mesh->HasTangentsAndBitangents() ?
glm::vec3(mesh->mTangents[i].x, mesh->mTangents[i].y, mesh->mTangents[i].z) :
glm::vec3(0.0f);
vertex.m_bitangent = mesh->HasTangentsAndBitangents() ?
glm::vec3(mesh->mBitangents[i].x, mesh->mBitangents[i].y, mesh->mBitangents[i].z) :
glm::vec3(0.0f);
vertices.push_back(vertex);
}
// indices
for (uint32_t i = 0; i < mesh->mNumFaces; i++) {
aiFace face = mesh->mFaces[i];
for (uint32_t j = 0; j < face.mNumIndices; j++)
indices.push_back(face.mIndices[j]);
}
// material
CMaterial* material = nullptr;
if (mesh->mMaterialIndex >= 0) {
material = processMaterial(
scene->mMaterials[mesh->mMaterialIndex],
directory,
rm
);
}
// crée et enregistre le mesh
auto newMesh = std::make_unique<CMesh>();
newMesh->setVertices(vertices);
newMesh->setIndexes(indices);
if (material) newMesh->setMaterial(material);
newMesh->load();
auto* ptr = newMesh.get();
rm.getMeshManager().addMesh(directory, std::move(newMesh));
return ptr;
}
CMaterial* CModelLoader::processMaterial(aiMaterial* mat, const std::string& directory, CResourceManager& rm)
{
auto newMat = std::make_unique<CMaterial>();
// albedo
if (mat->GetTextureCount(aiTextureType_DIFFUSE) > 0) {
aiString path;
mat->GetTexture(aiTextureType_DIFFUSE, 0, &path);
newMat->textureAlbedo = loadTexture(
directory + "/" + path.C_Str(), rm
);
}
// normal
if (mat->GetTextureCount(aiTextureType_NORMALS) > 0) {
aiString path;
mat->GetTexture(aiTextureType_NORMALS, 0, &path);
newMat->textureNormal = loadTexture(
directory + "/" + path.C_Str(), rm
);
}
auto shader = GraphicsAPI::getAPI()->getShaderManager().get("triangle");
newMat->shader = static_cast<CShaderImplVulkan*>(shader);
newMat->build();
auto* ptr = newMat.get();
rm.getMaterialManager().addMaterial(directory, std::move(newMat));
return ptr;
}
CTexture* CModelLoader::loadTexture(const std::string& directory, CResourceManager& rm)
{
auto text = rm.getTextureManager().get(directory);
if(rm.getTextureManager().get(directory))
{
return text.value();
}
else {
auto tex = std::make_unique<CTexture>(directory);
tex->init();
auto* ptr = tex.get();
rm.getTextureManager().addTexture(directory, std::move(tex));
return ptr;
}
}

View File

@@ -5,18 +5,15 @@
#include <assimp/Importer.hpp>
#include <assimp/scene.h>
#include <assimp/postprocess.h>
#include "../../Model/Graphic/Texture/CImageTexture.hpp"
#include <vector>
#include <iostream>
#include "../../Model/Graphic/Mesh/CMesh.hpp"
#include "../../Model/Graphic/CModel.hpp"
#include "../../Model/Node/CScene.hpp"
#include "../../Controller/CKernel.hpp"
#include "../../Context/CContext.hpp"
#include "CResourceManager.hpp"
#include "Mesh/CMesh.hpp"
#include "Texture/CTexture.hpp"
/**
* @brief Class allowing to load models from obj files.
*/
#include <filesystem>
class CModelLoader {
private:
/**
@@ -26,7 +23,7 @@ private:
* @param[in] meshes The mesh list.
* @param[in] material A pointer to a material. It's optionnal and override the obj's material.
*/
static void processNode(aiNode* node, const aiScene* scene, std::vector<CMesh*>* meshes, SMaterial* material);
static void processNode(aiNode* node, const aiScene* scene, const std::string& directory, CResourceManager& rm, std::vector<CMesh*>& meshes);
/**
* @brief Compute every meshes.
@@ -35,7 +32,7 @@ private:
* @param[in] meshes The list of meshes.
* @param[in] material A pointer to a material. It's optionnal and override the obj's material.
*/
static void processMesh(aiMesh* mesh, const aiScene* scene, std::vector<CMesh*>* meshes, SMaterial* material);
static CMesh* processMesh(aiMesh* mesh, const aiScene* scene, const std::string& directory, CResourceManager& rm);
/**
* @brief Load Textures from the obj file.
@@ -43,7 +40,9 @@ private:
* @param[in] type The assimp's texture type.
* @param[in] typeName The texture's type.
*/
static std::vector<CImageTexture*> loadMaterialTextures(aiMaterial* mat, aiTextureType type, ETextureType typeName);
static CTexture* loadTexture(const std::string& directory, CResourceManager& rm);
static CMaterial* processMaterial(aiMaterial* mat, const std::string& directory, CResourceManager& rm);
public:
/**
@@ -52,7 +51,7 @@ public:
* @param[in] material Pointer to a material. It's optionnal and override the obj's material.
* @return A dynamically allocated CModel.
*/
static CModel* loadModel(std::string fileName, SMaterial* material);
static CModel* loadModel(std::string filename, CResourceManager& rm);
};

View File

@@ -0,0 +1,32 @@
#ifndef CMODELMANAGER_HPP
#define CMODELMANAGER_HPP
#include "CModel.hpp"
#include <list>
#include <memory>
class CModelManager
{
public:
std::list<std::unique_ptr<CModel>> loadedModel;
std::unordered_map<std::string, CModel*> modelsMap;
void addModel(std::string name, std::unique_ptr<CModel>&& model)
{
loadedModel.push_back(std::move(model));
modelsMap[name] = loadedModel.back().get();
}
std::optional<CModel*> get(std::string name)
{
auto find = modelsMap.find(name);
if(find != modelsMap.end())
{
return find->second;
}
else {
return nullptr;
}
}
};
#endif

View File

@@ -0,0 +1,28 @@
#ifndef CRESOURCEMANAGER_HPP
#define CRESOURCEMANAGER_HPP
#include "CModelManager.hpp"
#include "Mesh/CMeshManager.hpp"
#include "Material/CMaterialManager.hpp"
#include "Texture/CTextureManager.hpp"
class CResourceManager{
private:
CModelManager modelManager;
CMeshManager meshManager;
CMaterialManager materialManager;
CTextureManager textureManager;
public:
CModelManager& getModelManager() { return modelManager; }
CMeshManager& getMeshManager() { return meshManager; }
CMaterialManager& getMaterialManager() { return materialManager; }
CTextureManager& getTextureManager() {return textureManager;}
void cleanup(){
materialManager.loadedMaterials.clear();
meshManager.loadedMeshes.clear();
modelManager.loadedModel.clear();
textureManager.loadedTextures.clear();
};
};
#endif

View File

@@ -1,4 +1,4 @@
#include "CTextTexture.hpp"
/*#include "CTextTexture.hpp"
CTextTexture::CTextTexture(ETextureType type, std::string filePath, std::string text, unsigned int fontSize, glm::vec3 fontColor, glm::bvec4 fontStyle) :
CAbstractTexture(type),
@@ -108,4 +108,4 @@ void CTextTexture::init(void) {
// Free the surface.
SDL_FreeSurface(sdlSurface);
}
}*/

View File

@@ -1,4 +1,4 @@
#ifndef CTEXTTEXTURE_HPP
/*#ifndef CTEXTTEXTURE_HPP
#define CTEXTTEXTURE_HPP
#include "../../../Controller/Exception/CLibException.hpp"
@@ -44,4 +44,4 @@ public:
virtual void init(void);
};
#endif
#endif*/

View File

@@ -0,0 +1,137 @@
#include "CMaterial.hpp"
#include "../Mesh/SVertex.hpp"
#include "../../API/VulkanImpl.hpp"
#include <vulkan/vulkan_core.h>
void CMaterial::build()
{
if(isInit)
{
destroy();
}
VulkanImpl* api = dynamic_cast<VulkanImpl*>(GraphicsAPI::getAPI().get());
auto* device= static_cast<vk::raii::Device*>(api->getDevice());
auto shaderStages = shader->getShaderStages(0, vk::ShaderStageFlagBits::eVertex, vk::ShaderStageFlagBits::eFragment);
auto bindingDescription = Vertex::getBindingDescription();
auto attributeDescriptions = Vertex::getAttributeDescriptions();
vk::PipelineVertexInputStateCreateInfo vertexInputInfo{{}, 1, &bindingDescription, static_cast<uint32_t>(attributeDescriptions.size()), attributeDescriptions.data()};
vk::PipelineInputAssemblyStateCreateInfo inputAssembly{{},vk::PrimitiveTopology::eTriangleList};
vk::PipelineViewportStateCreateInfo viewportState{{},1, {},1};
vk::PipelineRasterizationStateCreateInfo rasterizer{{},vk::False, vk::False, vk::PolygonMode::eFill,vk::CullModeFlagBits::eBack, vk::FrontFace::eCounterClockwise, vk::False, {}, {}, 1.0f, 1.0f};
vk::PipelineMultisampleStateCreateInfo multisampling{{}, vk::SampleCountFlagBits::e1, vk::False};
vk::PipelineColorBlendAttachmentState colorBlendAttachment{vk::False, {}, {}, {}, {}, {}, {}, vk::ColorComponentFlagBits::eR | vk::ColorComponentFlagBits::eG | vk::ColorComponentFlagBits::eB | vk::ColorComponentFlagBits::eA};
vk::PipelineColorBlendStateCreateInfo colorBlending{{},vk::False, vk::LogicOp::eCopy, 1, &colorBlendAttachment};
vk::PipelineDepthStencilStateCreateInfo depthStencil{{},
vk::True,
vk::True,
vk::CompareOp::eLess,
vk::False,
vk::False};
std::vector dynamicStates = {
vk::DynamicState::eViewport,
vk::DynamicState::eScissor};
vk::PipelineDynamicStateCreateInfo dynamicState{{}, static_cast<uint32_t>(dynamicStates.size()), dynamicStates.data()};
std::array<vk::DescriptorSetLayout, 3> layouts{
*api->getCameraLayout(), // set 0
*api->getTransformLayout(), // set 1
*api->getMaterialLayout() // set 2
};
vk::PipelineLayoutCreateInfo pipelineLayoutInfo{{},3,layouts.data(), 0};
pipelineLayout = vk::raii::PipelineLayout(*static_cast<vk::raii::Device*>(api->getDevice()), pipelineLayoutInfo);
vk::StructureChain<vk::GraphicsPipelineCreateInfo, vk::PipelineRenderingCreateInfo> pipelineCreateInfoChain = {
{{},
2,
shaderStages.data(),
&vertexInputInfo,
&inputAssembly,
{},
&viewportState,
&rasterizer,
&multisampling,
&depthStencil,
&colorBlending,
&dynamicState,
pipelineLayout,
nullptr
},
{{},
1,
&api->getSwapChainFormat().format,
api->findDepthFormat()
}
};
pipeline = vk::raii::Pipeline(*static_cast<vk::raii::Device*>(api->getDevice()), nullptr, pipelineCreateInfoChain.get<vk::GraphicsPipelineCreateInfo>());
// descriptor sets du material (set 2)
for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
m_descriptorSets[i] = api->getDescriptorPoolManager().allocate(
*api->getMaterialLayout()
);
std::vector<vk::WriteDescriptorSet> writes;
// binding 1 : albedo (si présent)
vk::DescriptorImageInfo albedoInfo;
if (textureAlbedo) {
albedoInfo = {
*textureAlbedo->getSampler(),
*textureAlbedo->getImageView(),
vk::ImageLayout::eShaderReadOnlyOptimal
};
writes.push_back({
*m_descriptorSets[i].set,
1, 0, 1,
vk::DescriptorType::eCombinedImageSampler,
&albedoInfo
});
}
else {
albedoInfo = {
api->getDefaultTexture()->getSampler(),
api->getDefaultTexture()->getImageView(),
vk::ImageLayout::eShaderReadOnlyOptimal
};
writes.push_back({
*m_descriptorSets[i].set,
1, 0, 1,
vk::DescriptorType::eCombinedImageSampler,
&albedoInfo
});
}
if (!writes.empty())
device->updateDescriptorSets(writes, {});
}
isInit = true;
}
CMaterial::~CMaterial()
{
destroy();
}
void CMaterial::destroy()
{
VulkanImpl* api = dynamic_cast<VulkanImpl*>(GraphicsAPI::getAPI().get());
uint32_t currentFrame = api->getCurrentFrameIndex();
api->destroyPipeline(pipeline, pipelineLayout);
// descriptor sets
for (uint32_t i = 0; i < MAX_FRAMES_IN_FLIGHT; i++) {
api->destroyDescriptorSet(m_descriptorSets[i], i);
}
}

View File

@@ -0,0 +1,30 @@
#ifndef SMATERIAL_HPP
#define SMATERIAL_HPP
#include "../../Shader/Implementations/CShaderImplVulkan.hpp"
#include "../../API/ManagedDescriptorSet.hpp"
#include "SColor.hpp"
#include "../Texture/CTexture.hpp"
class CMaterial {
public:
~CMaterial();
void destroy();
bool isInit = false;
SColor m_color;
CTexture* textureAlbedo = nullptr;
CTexture* textureNormal = nullptr;
CShaderImplVulkan* shader;
vk::raii::PipelineLayout pipelineLayout = nullptr;
vk::raii::Pipeline pipeline = nullptr;
std::array<ManagedDescriptorSet, MAX_FRAMES_IN_FLIGHT> m_descriptorSets;
void build();
vk::raii::Pipeline& getPipeline(){return pipeline;};
vk::raii::PipelineLayout& getPipelineLayout(){return pipelineLayout;};
vk::raii::DescriptorSet& getDescriptorSet(uint32_t frameIndex) {
return m_descriptorSets[frameIndex].set;
}
};
#endif

View File

@@ -0,0 +1,31 @@
#ifndef CMATERIALMANAGER_HPP
#define CMATERIALMANAGER_HPP
#include "CMaterial.hpp"
#include <list>
#include <memory>
#include <unordered_map>
class CMaterialManager
{
public:
std::list<std::unique_ptr<CMaterial>> loadedMaterials;
std::unordered_map<std::string, CMaterial*> materialsMap;
void addMaterial(std::string name, std::unique_ptr<CMaterial>&& mat)
{
loadedMaterials.push_back(std::move(mat));
materialsMap[name] = loadedMaterials.back().get();
}
std::optional<CMaterial*> get(std::string name)
{
auto find = materialsMap.find(name);
if(find != materialsMap.end())
{
return find->second;
}
else {
return nullptr;
}
}
};
#endif

View File

@@ -0,0 +1,107 @@
#include "CMesh.hpp"
#include "../../API/VulkanImpl.hpp"
#include <vulkan/vulkan_core.h>
#include <vulkan/vulkan_raii.hpp>
CMesh::CMesh(void) :
m_vertexes() {
}
CMesh::~CMesh(void) {
destroy();
}
void CMesh::destroy()
{
VulkanImpl* api = dynamic_cast<VulkanImpl*>(GraphicsAPI::getAPI().get());
api->destroyBuffer(vertexIndexBuffer, api->getCurrentFrameIndex());
/*if (api && vertexIndexBuffer.buffer != VK_NULL_HANDLE)
vmaDestroyBuffer(api->getAllocator(), vertexIndexBuffer.buffer, vertexIndexBuffer.allocation);*/
}
std::vector<SVertex>& CMesh::getVertices(void) {
return m_vertexes;
}
void CMesh::setVertices(std::vector<SVertex> vertices)
{
m_vertexes = vertices;
}
void CMesh::setIndexes(std::vector<uint32_t> indexes){
m_indexes = indexes;
}
std::vector<uint32_t>& CMesh::getIndexes(void){
return m_indexes;
}
/*void CMesh::load(void) {
vk::BufferCreateInfo bufferInfo{{},sizeof(m_vertexes[0]) * m_vertexes.size(), vk::BufferUsageFlagBits::eVertexBuffer, vk::SharingMode::eExclusive};
VulkanImpl* api = dynamic_cast<VulkanImpl*>(GraphicsAPI::getAPI().get());
vertexBuffer = vk::raii::Buffer(*static_cast<vk::raii::Device*>(api->getDevice()), bufferInfo);
vk::MemoryRequirements memRequirements = vertexBuffer.getMemoryRequirements();
vk::MemoryAllocateInfo memoryAllocateInfo{memRequirements.size, api->findMemoryType(memRequirements.memoryTypeBits, vk::MemoryPropertyFlagBits::eHostVisible | vk::MemoryPropertyFlagBits::eHostCoherent)};
vertexBufferMemory = vk::raii::DeviceMemory(*static_cast<vk::raii::Device*>(api->getDevice()), memoryAllocateInfo);
vertexBuffer.bindMemory(*vertexBufferMemory, 0);
void *data = vertexBufferMemory.mapMemory(0, bufferInfo.size);
memcpy(data, m_vertexes.data(), bufferInfo.size);
vertexBufferMemory.unmapMemory();
}*/
void CMesh::load(void) {
VulkanImpl* api = dynamic_cast<VulkanImpl*>(GraphicsAPI::getAPI().get());
VmaAllocator allocator = api->getAllocator();
VkDeviceSize vertexSize = sizeof(m_vertexes[0]) * m_vertexes.size();
VkDeviceSize indexSize = sizeof(m_indexes[0]) * m_indexes.size();
VkDeviceSize totalSize = vertexSize + indexSize;
// 1. staging buffer - CPU visible, temporaire
VkBufferCreateInfo stagingBufferInfo{};
stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
stagingBufferInfo.size = totalSize;
stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
VmaAllocationCreateInfo stagingAllocInfo{};
stagingAllocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
stagingAllocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
VMABuffer stagingBuffer;
VmaAllocationInfo stagingInfo{};
vmaCreateBuffer(allocator, &stagingBufferInfo, &stagingAllocInfo,
&stagingBuffer.buffer, &stagingBuffer.allocation, &stagingInfo);
// 2. copie des données CPU → staging
memcpy(stagingInfo.pMappedData, m_vertexes.data(), vertexSize);
memcpy((char*)stagingInfo.pMappedData + vertexSize, m_indexes.data(), indexSize);
vmaFlushAllocation(allocator, stagingBuffer.allocation, 0, VK_WHOLE_SIZE);
// 3. vertex buffer final - DEVICE_LOCAL, rapide
VkBufferCreateInfo vertexBufferInfo{};
vertexBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
vertexBufferInfo.size = totalSize;
vertexBufferInfo.usage = VK_BUFFER_USAGE_VERTEX_BUFFER_BIT
| VK_BUFFER_USAGE_INDEX_BUFFER_BIT
| VK_BUFFER_USAGE_TRANSFER_DST_BIT;
VmaAllocationCreateInfo vertexAllocInfo{};
vertexAllocInfo.usage = VMA_MEMORY_USAGE_GPU_ONLY;
vmaCreateBuffer(allocator, &vertexBufferInfo, &vertexAllocInfo,
&vertexIndexBuffer.buffer, &vertexIndexBuffer.allocation, nullptr);
// 4. copie GPU staging → vertex buffer via command buffer
api->copyBuffer(stagingBuffer.buffer, vertexIndexBuffer.buffer, totalSize);
m_vertexOffset = 0;
m_indexOffset = vertexSize;
m_indexCount = m_indexes.size();
// 5. détruire le staging buffer
vmaDestroyBuffer(allocator, stagingBuffer.buffer, stagingBuffer.allocation);
}
/*void CMesh::draw(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 lightPos, float intensity) {
}*/

View File

@@ -0,0 +1,53 @@
#ifndef CMESH_HPP
#define CMESH_HPP
#include "SVertex.hpp"
#include "../Material/CMaterial.hpp"
#include <cstdint>
#include <vector>
#include <vulkan/vulkan_raii.hpp>
#define GLM_ENABLE_EXPERIMENTAL
#include <glm/glm.hpp>
#include "../../API/VMABuffer.hpp"
class CMesh {
private:
std::vector<Vertex> m_vertexes;
std::vector<uint32_t> m_indexes;
VMABuffer vertexIndexBuffer;
VkDeviceSize m_vertexOffset = 0;
VkDeviceSize m_indexOffset = 0;
uint32_t m_indexCount = 0;
CMaterial* m_material;
public:
CMesh(void);
~CMesh(void);
std::vector<SVertex>& getVertices(void);
std::vector<uint32_t>& getIndexes(void);
void setVertices(std::vector<SVertex> vertices);
void setIndexes(std::vector<uint32_t> indexes);
void setMaterial(CMaterial* mat){m_material = mat;};
void load(void);
//void draw(glm::mat4 model, glm::mat4 view, glm::mat4 projection, glm::vec3 lightPos, float intensity);
CMaterial* getMaterial(){return m_material;};
VMABuffer& getVertexIndexBuffer(){return vertexIndexBuffer;};
VkDeviceSize getVertexOffset(){return m_vertexOffset;}
VkDeviceSize getIndexOffset(){return m_indexOffset;};
uint32_t getIndexCount(){return m_indexCount;};
void destroy();
};
#endif

View File

@@ -0,0 +1,31 @@
#ifndef CMESHMANAGER_HPP
#define CMESHMANAGER_HPP
#include "CMesh.hpp"
#include <list>
#include <memory>
class CMeshManager
{
public:
std::list<std::unique_ptr<CMesh>> loadedMeshes;
std::unordered_map<std::string, CMesh*> meshesMap;
void addMesh(std::string name, std::unique_ptr<CMesh>&& mesh)
{
loadedMeshes.push_back(std::move(mesh));
meshesMap[name] = loadedMeshes.back().get();
}
std::optional<CMesh*> get(std::string name)
{
auto find = meshesMap.find(name);
if(find != meshesMap.end())
{
return find->second;
}
else {
return nullptr;
}
}
};
#endif

View File

@@ -0,0 +1,70 @@
#ifndef SVERTEX_HPP
#define SVERTEX_HPP
#include "vulkan/vulkan.hpp"
#include <glm/glm.hpp>
/**
* @file SVertex.hpp
* @brief File for the vertex struct.
*/
/**
* @brief the struct Vertex, use to represent vertex and vertex attribute.
*/
typedef struct SVertex{
/**
* @brief Position attribute.
* 3D vector.
*/
glm::vec3 m_position;
/**
* @brief Position attribute.
* 3D vector.
*/
glm::vec4 m_color;
/**
* @brief Normal attribute.
* 3D vector.
*/
glm::vec3 m_normal;
/**
* @brief Texture coordinates attribute.
* 2D vector.
*/
glm::vec2 m_texCoords;
/**
* @brief Tangent attribute.
* 3D vector.
*/
glm::vec3 m_tangent;
/**
* @brief Bitangent attribute.
* 3D vector (perpendicular to m_tangent vector).
*/
glm::vec3 m_bitangent;
// m_normal, m_tangent, m_bitangent are supposed to create a vector base to compute normal map.
static vk::VertexInputBindingDescription getBindingDescription() {
return { 0, sizeof(SVertex), vk::VertexInputRate::eVertex };
}
static std::array<vk::VertexInputAttributeDescription, 6> getAttributeDescriptions() {
return {
vk::VertexInputAttributeDescription( 0, 0, vk::Format::eR32G32B32Sfloat, offsetof(SVertex, m_position) ),
vk::VertexInputAttributeDescription( 1, 0, vk::Format::eR32G32B32A32Sfloat, offsetof(SVertex, m_color) ),
vk::VertexInputAttributeDescription( 2, 0, vk::Format::eR32G32B32Sfloat, offsetof(SVertex, m_normal) ),
vk::VertexInputAttributeDescription( 3, 0, vk::Format::eR32G32Sfloat, offsetof(SVertex, m_texCoords) ),
vk::VertexInputAttributeDescription( 4, 0, vk::Format::eR32G32B32Sfloat, offsetof(SVertex, m_tangent) ),
vk::VertexInputAttributeDescription( 5, 0, vk::Format::eR32G32B32Sfloat, offsetof(SVertex, m_bitangent) )
};
}
} Vertex;
#endif

View File

@@ -0,0 +1,219 @@
#include "CTexture.hpp"
#include "../../API/VulkanImpl.hpp"
CTexture::CTexture(std::string filePath) :
m_filePath(filePath) {
}
std::string CTexture::getFilePath(void) {
return m_filePath;
}
void CTexture::setFilePath(std::string filePath) {
m_filePath = filePath;
}
void CTexture::init(void) {
VulkanImpl* api = dynamic_cast<VulkanImpl*>(GraphicsAPI::getAPI().get());
auto* device= static_cast<vk::raii::Device*>(api->getDevice());
// Read the image file.
SDL_Surface* sdlSurface = IMG_Load(m_filePath.c_str());
if(sdlSurface == nullptr)
{
//error here
}
SDL_PixelFormat sdlFormat = sdlSurface->format;
SDL_Surface* converted = nullptr;
if (sdlFormat == SDL_PIXELFORMAT_RGBA32) {
// déjà RGBA, pas de conversion
converted = sdlSurface;
m_format = vk::Format::eR8G8B8A8Srgb;
} else if (sdlFormat == SDL_PIXELFORMAT_BGRA32) {
// déjà BGRA, pas de conversion mais format différent
converted = sdlSurface;
m_format = vk::Format::eB8G8R8A8Srgb;
} else {
// tout autre format → on force RGBA32
converted = SDL_ConvertSurface(sdlSurface, SDL_PIXELFORMAT_RGBA32);
if (!converted)
throw std::runtime_error("Failed to convert surface: " + m_filePath);
SDL_DestroySurface(sdlSurface);
m_format = vk::Format::eR8G8B8A8Srgb;
}
m_width = converted->w;
m_height = converted->h;
VkDeviceSize imageSize = m_width * m_height * 4;
// 2. staging buffer
VkBufferCreateInfo stagingBufferInfo{};
stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
stagingBufferInfo.size = imageSize;
stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
VmaAllocationCreateInfo stagingAllocInfo{};
stagingAllocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
stagingAllocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
VMABuffer stagingBuffer;
VmaAllocationInfo stagingInfo{};
vmaCreateBuffer(api->getAllocator(), &stagingBufferInfo, &stagingAllocInfo,
&stagingBuffer.buffer, &stagingBuffer.allocation, &stagingInfo);
memcpy(stagingInfo.pMappedData, converted->pixels, imageSize);
// Free the surface.
SDL_DestroySurface(converted);
// 3. crée l'image GPU
api->createImage(
m_width, m_height,
m_format,
vk::ImageTiling::eOptimal,
vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled,
vk::MemoryPropertyFlagBits::eDeviceLocal,
m_textureImage,
m_textureImageMemory
);
// 4. transitions et copie
api->transitionImageLayout(m_textureImage,
vk::ImageLayout::eUndefined,
vk::ImageLayout::eTransferDstOptimal);
{
auto cmd = api->beginSingleTimeCommands();
vk::BufferImageCopy region{
0, 0, 0,
{vk::ImageAspectFlagBits::eColor, 0, 0, 1},
{0, 0, 0},
{static_cast<uint32_t>(m_width), static_cast<uint32_t>(m_height), 1}
};
cmd.copyBufferToImage(
vk::Buffer(stagingBuffer.buffer),
m_textureImage,
vk::ImageLayout::eTransferDstOptimal,
region
);
api->endSingleTimeCommands(cmd);
}
api->transitionImageLayout(m_textureImage,
vk::ImageLayout::eTransferDstOptimal,
vk::ImageLayout::eShaderReadOnlyOptimal);
vmaDestroyBuffer(api->getAllocator(), stagingBuffer.buffer, stagingBuffer.allocation);
// 5. image view
m_imageView = api->createImageView(m_textureImage, m_format, vk::ImageAspectFlagBits::eColor);
// 6. sampler
vk::SamplerCreateInfo samplerInfo{};
samplerInfo.magFilter = vk::Filter::eLinear;
samplerInfo.minFilter = vk::Filter::eLinear;
samplerInfo.addressModeU = vk::SamplerAddressMode::eRepeat;
samplerInfo.addressModeV = vk::SamplerAddressMode::eRepeat;
samplerInfo.addressModeW = vk::SamplerAddressMode::eRepeat;
samplerInfo.anisotropyEnable = vk::True;
samplerInfo.maxAnisotropy = api->getPhysicalDevice().getProperties().limits.maxSamplerAnisotropy;
samplerInfo.borderColor = vk::BorderColor::eIntOpaqueBlack;
samplerInfo.unnormalizedCoordinates = vk::False;
samplerInfo.compareEnable = vk::False;
samplerInfo.mipmapMode = vk::SamplerMipmapMode::eLinear;
m_sampler = vk::raii::Sampler(*device, samplerInfo);
}
void CTexture::initDefaultTexture()
{
VulkanImpl* api = dynamic_cast<VulkanImpl*>(GraphicsAPI::getAPI().get());
auto* device= static_cast<vk::raii::Device*>(api->getDevice());
// pixel blanc 1x1 RGBA
uint32_t whitePixel = 0x00000ff0;
uint32_t width = 1;
uint32_t height = 1;
VkDeviceSize imageSize = sizeof(uint32_t);
// staging buffer
VkBufferCreateInfo stagingBufferInfo{};
stagingBufferInfo.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
stagingBufferInfo.size = imageSize;
stagingBufferInfo.usage = VK_BUFFER_USAGE_TRANSFER_SRC_BIT;
VmaAllocationCreateInfo stagingAllocInfo{};
stagingAllocInfo.usage = VMA_MEMORY_USAGE_CPU_ONLY;
stagingAllocInfo.flags = VMA_ALLOCATION_CREATE_MAPPED_BIT;
VMABuffer stagingBuffer;
VmaAllocationInfo stagingInfo{};
vmaCreateBuffer(api->getAllocator(), &stagingBufferInfo, &stagingAllocInfo,
&stagingBuffer.buffer, &stagingBuffer.allocation, &stagingInfo);
memcpy(stagingInfo.pMappedData, &whitePixel, imageSize);
// image GPU
api->createImage(width, height,
vk::Format::eR8G8B8A8Srgb,
vk::ImageTiling::eOptimal,
vk::ImageUsageFlagBits::eTransferDst | vk::ImageUsageFlagBits::eSampled,
vk::MemoryPropertyFlagBits::eDeviceLocal,
m_textureImage,
m_textureImageMemory
);
api->transitionImageLayout(m_textureImage,
vk::ImageLayout::eUndefined,
vk::ImageLayout::eTransferDstOptimal);
{
auto cmd = api->beginSingleTimeCommands();
vk::BufferImageCopy region{
0, 0, 0,
{vk::ImageAspectFlagBits::eColor, 0, 0, 1},
{0, 0, 0},
{width, height, 1}
};
cmd.copyBufferToImage(
vk::Buffer(stagingBuffer.buffer),
m_textureImage,
vk::ImageLayout::eTransferDstOptimal,
region
);
api->endSingleTimeCommands(cmd);
}
api->transitionImageLayout(m_textureImage,
vk::ImageLayout::eTransferDstOptimal,
vk::ImageLayout::eShaderReadOnlyOptimal);
vmaDestroyBuffer(api->getAllocator(), stagingBuffer.buffer, stagingBuffer.allocation);
// image view
m_imageView = api->createImageView(
m_textureImage,
vk::Format::eR8G8B8A8Srgb,
vk::ImageAspectFlagBits::eColor
);
// sampler
vk::SamplerCreateInfo samplerInfo{};
samplerInfo.magFilter = vk::Filter::eLinear;
samplerInfo.minFilter = vk::Filter::eLinear;
samplerInfo.addressModeU = vk::SamplerAddressMode::eRepeat;
samplerInfo.addressModeV = vk::SamplerAddressMode::eRepeat;
samplerInfo.addressModeW = vk::SamplerAddressMode::eRepeat;
samplerInfo.anisotropyEnable = vk::False;
samplerInfo.maxAnisotropy = 1.0f;
samplerInfo.borderColor = vk::BorderColor::eIntOpaqueBlack;
samplerInfo.unnormalizedCoordinates = vk::False;
samplerInfo.compareEnable = vk::False;
samplerInfo.mipmapMode = vk::SamplerMipmapMode::eLinear;
m_sampler = vk::raii::Sampler(*device, samplerInfo);
}

View File

@@ -0,0 +1,45 @@
#ifndef CTEXTURE_HPP
#define CTEXTURE_HPP
#include <SDL3/SDL.h>
#include <SDL3_image/SDL_image.h>
#include <string>
#include <vulkan/vulkan_raii.hpp>
class CTexture{
private:
// Path of the file.
std::string m_filePath;
vk::raii::Image m_textureImage = nullptr;
vk::raii::DeviceMemory m_textureImageMemory = nullptr;
vk::raii::ImageView m_imageView = nullptr;
vk::raii::Sampler m_sampler = nullptr;
uint32_t m_width = 0;
uint32_t m_height = 0;
vk::Format m_format = vk::Format::eR8G8B8A8Srgb;
public:
CTexture(void) = delete;
CTexture(const CTexture&) = delete;
CTexture& operator=(const CTexture&) = delete;
~CTexture(void) {
m_sampler = nullptr;
m_imageView = nullptr;
m_textureImage = nullptr;
m_textureImageMemory = nullptr;
};
CTexture(std::string filePath);
std::string getFilePath(void);
void setFilePath(std::string filePath);
void init(void);
void initDefaultTexture();
vk::raii::ImageView& getImageView() { return m_imageView; }
vk::raii::Sampler& getSampler() { return m_sampler; }
uint32_t getWidth() const { return m_width; }
uint32_t getHeight() const { return m_height; }
};
#endif

View File

@@ -0,0 +1,32 @@
#ifndef CTEXTUREMANAGER_HPP
#define CTEXTUREMANAGER_HPP
#include "CTexture.hpp"
#include <list>
#include <memory>
#include <optional>
#include <unordered_map>
class CTextureManager
{
public:
std::list<std::unique_ptr<CTexture>> loadedTextures;
std::unordered_map<std::string, CTexture*> texturesMap;
void addTexture(std::string name, std::unique_ptr<CTexture>&& text)
{
loadedTextures.push_back(std::move(text));
texturesMap[name] = loadedTextures.back().get();
}
std::optional<CTexture*> get(std::string name)
{
auto find = texturesMap.find(name);
if(find != texturesMap.end())
{
return find->second;
}
else {
return nullptr;
}
}
};
#endif

View File

@@ -1,24 +1,17 @@
#include "CShadersManager.hpp"
#include "CShaderFactory.hpp"
#include "../CKernel.hpp"
#include <boost/filesystem.hpp>
CShadersManager::CShadersManager(void) :m_shadersMap(), m_shaderList(nullptr) {
#include <filesystem>
#include <fstream>
#include <unordered_map>
#include "../../../Utils/Factory/CShaderFactory.hpp"
CShadersManager::CShadersManager(void) :m_shadersMap() {
}
CShadersManager::~CShadersManager(void) {
for (std::pair<const std::string, CShader*>& it : m_shadersMap)
{
delete it.second;
}
free(m_shaderList);
}
CShader* CShadersManager::get(std::string name) const {
std::map<std::string, CShader*>::const_iterator it = m_shadersMap.find(name);
std::unordered_map<std::string, CShader*>::const_iterator it = m_shadersMap.find(name);
if (it == m_shadersMap.end()) {
return nullptr;
}
@@ -28,60 +21,33 @@ CShader* CShadersManager::get(std::string name) const {
}
void CShadersManager::create(void) {
if (std::filesystem::is_directory(CEngineConfiguration::configuration->getGlobalShadersPath())) {
for (std::filesystem::directory_iterator itr(CEngineConfiguration::configuration->getGlobalShadersPath()); itr != std::filesystem::directory_iterator(); ++itr) {
std::filesystem::path shaderDir = std::filesystem::absolute(SHADERS_FOLDER);
if (std::filesystem::is_directory(shaderDir)) {
for (std::filesystem::directory_iterator itr(shaderDir); itr != std::filesystem::directory_iterator(); ++itr) {
if (std::filesystem::is_regular_file(itr->status())) {
DEBUG_LOG(trace, "Kernel", "ShadersManager", "Shader : " + itr->path().string() + " found.")
CFileManager jsonfm(itr->path().string());
std::string json = jsonfm.read();
std::ifstream jsonfm(itr->path().string());
try {
nlohmann::json shaderJson = nlohmann::json::parse(json);
std::string name = shaderJson["name"];
std::string vert = shaderJson["vert"];
std::string frag = shaderJson["frag"];
CShader* newShader = CShaderFactory::createShader(CKernel::m_kernel ,name, CEngineConfiguration::configuration->getGlobalShadersPath().string() + std::string("/") + vert, CEngineConfiguration::configuration->getGlobalShadersPath().string() + std::string("/") + frag);
m_shadersMap.insert(std::pair<std::string, CShader*>(name, newShader));
auto shader = CosmicUtils::CShaderFactory::create(itr->path().stem(), itr->path());
shaders.push_back(std::move(shader));
m_shadersMap.insert(std::make_pair(itr->path().stem(), shaders.back().get()));
}
catch (std::exception& e) {
throw CJsonException(std::string("Failed to parse and retrieve data from the json file ") + itr->path().string() + ": " + e.what());
//throw CJsonException(std::string("Failed to parse and retrieve data from the json file ") + itr->path().string() + ": " + e.what());
}
DEBUG_LOG(trace, "Kernel", "ShadersManager", "Shader : " + itr->path().string() + " successfully retrieved.")
}
}
m_shaderList = (CShader**)malloc(sizeof(CShader*) * m_shadersMap.size());
if (m_shaderList == NULL) {
throw CRuntimeException("unable to alloc shaders list");
}
unsigned int i = 0;
for (std::pair<std::string, CShader*> it : m_shadersMap)
{
m_shaderList[i] = it.second;
i++;
}
}
else {
throw CFileException(std::string("Failed to find the shaders folder : ") + CKernel::m_kernel->getEngineConfig()->getGlobalShadersPath().string());
//throw CFileException(std::string("Failed to find the shaders folder : ") + CKernel::m_kernel->getEngineConfig()->getGlobalShadersPath().string());
}
}
void CShadersManager::compile(void) {
DEBUG_LOG(trace, "Kernel", "ShadersManager", "Starting compiling shaders files.");
unsigned int nbShader = m_shadersMap.size();
for (unsigned int i = 0; i < nbShader; i++)
for (auto& el: shaders)
{
m_shaderList[i]->init();
el->init();
}
DEBUG_LOG(trace, "Kernel", "ShadersManager", "All shaders are ready to use.")
}

View File

@@ -1,68 +1,45 @@
#ifndef CSHADERSMANAGER_HPP
#define CSHADERSMANAGER_HPP
#include <list>
#include <string>
#include <cstdlib>
#include <map>
#include <nlohmann/json.hpp>
#include <unordered_map>
#include "../../Model/Graphic/Shader/CShader.hpp"
#include "../../Context/CContext.hpp"
#include "CShader.hpp"
#include "../Exception/CJsonException.hpp"
#include "../Exception/CFileException.hpp"
#include "../Exception/CRuntimeException.hpp"
#define SHADERS_FOLDER "assets/shaders/slang/spv"
/*#ifdef WIN32
#define SHADERS_FOLDER "../assets/shaders"
#else
#define SHADERS_FOLDER "../../assets/shaders"
#endif*/
/**
* @brief Class to manage shaders.
*/
class CShadersManager {
private:
/**
* @brief map to store in a proper way the shaders.
*/
std::map<std::string, CShader*> m_shadersMap;
std::list<std::unique_ptr<CShader>> shaders;
std::unordered_map<std::string, CShader*> m_shadersMap;
CShader** m_shaderList;
public:
/**
* @brief constructor.
*/
CShadersManager(void);
CShadersManager(const CShadersManager& param) = delete;
/**
* @brief destructor, destroy the shaders of the list.
*/
~CShadersManager(void);
CShadersManager& operator=(const CShadersManager& param) = delete;
/**
* @brief get a shader by its name.
* @param[in] name shader name.
* @return the shader.
*/
CShader* get(std::string name) const;
/**
* @brief compile and link all the shaders to make them ready to use.
*/
std::list<std::unique_ptr<CShader>>::const_iterator beginShaders(){return shaders.cbegin();};
std::list<std::unique_ptr<CShader>>::const_iterator endShaders(){return shaders.cend();};
void compile(void);
/**
* @brief search the folder assets/shaders and create the shaders specifieds by a json file.
* @post throw an FileException if the shaders folder is not found.
*/
void create(void);
void cleanup(){
shaders.clear();
}
};
#endif

View File

@@ -0,0 +1,106 @@
#include "CShaderImplVulkan.hpp"
#include "vulkan/vulkan.hpp"
#include "../../API/GraphicsAPI.hpp"
#include <cstdint>
#include <filesystem>
#include <fstream>
#include <vulkan/vulkan_raii.hpp>
#include <spirv_reflect.h>
CShaderImplVulkan::CShaderImplVulkan(std::string name, std::filesystem::path spvPath): m_name(name), spirvPath(spvPath)
{
}
std::string CShaderImplVulkan::getName(void) const {
return m_name;
}
void CShaderImplVulkan::setName(std::string name) {
m_name = name;
}
void CShaderImplVulkan::init()
{
std::ifstream fileShader(spirvPath, std::ios::binary | std::ios::ate);
size_t fileSize = fileShader.tellg();
fileShader.seekg(0);
std::vector<uint32_t> spirv(fileSize / sizeof(uint32_t));
fileShader.read(reinterpret_cast<char*>(spirv.data()), fileSize);
//spirv.push_back('\0');
//fileSize++;
fileShader.close();
vk::ShaderModuleCreateInfo createInfo{ {},fileSize,spirv.data() };
shaderModule = vk::raii::ShaderModule(*static_cast<vk::raii::Device*>(GraphicsAPI::getAPI()->getDevice()), createInfo);
SpvReflectShaderModule module;
SpvReflectResult result = spvReflectCreateShaderModule(
spirv.size() * sizeof(uint32_t),
spirv.data(),
&module
);
assert(result == SPV_REFLECT_RESULT_SUCCESS);
uint32_t entryPointCount = module.entry_point_count;
for (uint32_t i = 0; i < entryPointCount; i++) {
const SpvReflectEntryPoint& entry = module.entry_points[i];
switch (entry.shader_stage) {
case SPV_REFLECT_SHADER_STAGE_VERTEX_BIT:
stageEntryPoints[vk::ShaderStageFlagBits::eVertex].push_back(entry.name);
break;
case SPV_REFLECT_SHADER_STAGE_FRAGMENT_BIT:
stageEntryPoints[vk::ShaderStageFlagBits::eFragment].push_back(entry.name);
break;
case SPV_REFLECT_SHADER_STAGE_GEOMETRY_BIT:
stageEntryPoints[vk::ShaderStageFlagBits::eGeometry].push_back(entry.name);
break;
case SPV_REFLECT_SHADER_STAGE_TESSELLATION_CONTROL_BIT:
stageEntryPoints[vk::ShaderStageFlagBits::eTessellationControl].push_back(entry.name);
break;
case SPV_REFLECT_SHADER_STAGE_TESSELLATION_EVALUATION_BIT:
stageEntryPoints[vk::ShaderStageFlagBits::eTessellationEvaluation].push_back(entry.name);
break;
case SPV_REFLECT_SHADER_STAGE_COMPUTE_BIT:
stageEntryPoints[vk::ShaderStageFlagBits::eCompute].push_back(entry.name);
break;
default:
continue;
}
}
spvReflectDestroyShaderModule(&module);
}
void CShaderImplVulkan::setBool(const std::string& name, bool value) const
{
}
void CShaderImplVulkan::setInt(const std::string& name, int value) const
{
}
void CShaderImplVulkan::setFloat(const std::string& name, float value) const
{
}
void CShaderImplVulkan::setMat2(const std::string& name, glm::mat2 value) const {
}
void CShaderImplVulkan::setMat3(const std::string& name, glm::mat3 value) const {
}
void CShaderImplVulkan::setMat4(const std::string& name, glm::mat4 value) const {
}
void CShaderImplVulkan::setVec2(const std::string& name, glm::vec2 value) const {
}
void CShaderImplVulkan::setVec3(const std::string& name, glm::vec3 value) const {
}
void CShaderImplVulkan::setVec4(const std::string& name, glm::vec4 value) const {
}

View File

@@ -0,0 +1,99 @@
#ifndef CSHADEROPENGLIMPLHPP
#define CSHADEROPENGLIMPLHPP
#include "../CShader.hpp"
#include "vulkan/vulkan.hpp"
#include <filesystem>
#include <string>
#include <unordered_map>
#include <vulkan/vulkan_raii.hpp>
/**
* @file CShaderImplVulkan.hpp
* @brief File of CShaderImplVulkan, a Vulkan impl. of CShader to manage shader program.
*/
/**
* @brief a Vulkan impl. of CShader to manage shader program.
*/
class CShaderImplVulkan : public CShader {
private:
std::string m_name;
std::filesystem::path spirvPath;
vk::raii::ShaderModule shaderModule = nullptr;
vk::raii::Device* device = nullptr;
std::unordered_map<vk::ShaderStageFlagBits,std::vector<std::string>> stageEntryPoints;
public:
CShaderImplVulkan() = delete;
CShaderImplVulkan(std::string name, std::string vertexPath, std::string fragmentPath) = delete;
CShaderImplVulkan(std::string name, std::string vertexPath, std::string fragmentPath, std::string geomPath) = delete;
CShaderImplVulkan(std::string name, std::filesystem::path spvPath);
virtual unsigned int getId(void) const {return 0;};
virtual std::string getName(void) const;
virtual std::string getVertexPath(void) const {return "";};
virtual std::string getGeomPath(void) const{return "";};
virtual std::string getFragmentPath(void) const {return "";};
virtual void setName(std::string name);
virtual void setVertexPath(std::string vp) {};
virtual void setGeomPath(std::string gp) {};
virtual void setFragmentPath(std::string fp) {};
virtual bool isReady(void) const {return true;};
virtual bool hasGeom(void) const {return true;};
virtual void use(void) {};
virtual void init(void);
template <typename... Flags>
std::vector<vk::PipelineShaderStageCreateInfo> getShaderStages(unsigned int offset = 0, Flags... flagBits)
{
std::vector<vk::PipelineShaderStageCreateInfo> pipe;
for(auto el : std::initializer_list<vk::ShaderStageFlagBits>{ flagBits... })
{
//todo assert exists
std::string& entry = stageEntryPoints[el][offset];
vk::PipelineShaderStageCreateInfo info{{}, el, shaderModule, entry.c_str() };//todo check specialized info ?
pipe.push_back(info);
}
return pipe;
}
virtual void setBool(const std::string& name, bool value) const;
virtual void setInt(const std::string& name, int value) const;
virtual void setFloat(const std::string& name, float value) const;
virtual void setMat2(const std::string& name, glm::mat2 value) const;
virtual void setMat3(const std::string& name, glm::mat3 value) const;
virtual void setMat4(const std::string& name, glm::mat4 value) const;
virtual void setVec2(const std::string& name, glm::vec2 value) const;
virtual void setVec3(const std::string& name, glm::vec3 value) const;
virtual void setVec4(const std::string& name, glm::vec4 value) const;
};
#endif

View File

@@ -1,14 +1,16 @@
#include "CGameWindow.hpp"
#include <SDL3/SDL_mouse.h>
#include <SDL3/SDL_video.h>
CGameWindow::CGameWindow(std::string title, std::string iconPath, unsigned int width, unsigned int height, bool resizable, bool fullscreen) :
CWindow(title, iconPath, width, height, false, false, SDL_WINDOW_OPENGL),
CWindow(title, iconPath, width, height, false, false, SDL_WINDOW_VULKAN),
m_grabCursor(false),
m_relativeCursor(false),
m_msaa(0) {
}
CGameWindow::CGameWindow(std::string title, SDL_Window* window) :
CWindow(title, window, SDL_WINDOW_OPENGL, 0),
CWindow(title, window, SDL_WINDOW_VULKAN),
m_grabCursor(false),
m_relativeCursor(false),
m_msaa(0) {
@@ -17,18 +19,18 @@ CGameWindow::CGameWindow(std::string title, SDL_Window* window) :
CGameWindow::~CGameWindow(void) {
}
SDL_GLContext CGameWindow::getOpenGLContext(void) {
/*SDL_GLContext CGameWindow::getOpenGLContext(void) {
if (getWindow() == nullptr) {
throw CLogicException("The window must be initialized before using this method !");
//throw CLogicException("The window must be initialized before using this method !");
}
else {
SDL_GLContext out = SDL_GL_CreateContext(getWindow());
if (out == nullptr) {
throw CLibException(std::string("Unable to create OpenGL context: ") + SDL_GetError());
//throw CLibException(std::string("Unable to create OpenGL context: ") + SDL_GetError());
}
return out;
}
}
}*/
bool CGameWindow::isCursorGrabbed(void) const {
return m_grabCursor;
@@ -43,10 +45,10 @@ void CGameWindow::setCursorGrabbed(bool newMouseGrab) {
if (getWindow() != nullptr) {
if (m_grabCursor) {
SDL_SetWindowGrab(getWindow(), SDL_TRUE);
SDL_SetWindowMouseGrab(getWindow(), true);
}
else {
SDL_SetWindowGrab(getWindow(), SDL_FALSE);
SDL_SetWindowMouseGrab(getWindow(), false);
}
}
}
@@ -64,10 +66,10 @@ void CGameWindow::setCursorRelative(bool newMouseRelative) {
if (getWindow() != nullptr) {
if (m_relativeCursor) {
SDL_SetRelativeMouseMode(SDL_TRUE);
SDL_SetWindowRelativeMouseMode(getWindow(), true);
}
else {
SDL_SetRelativeMouseMode(SDL_FALSE);
SDL_SetWindowRelativeMouseMode(getWindow(), false);
}
}
}
@@ -78,7 +80,7 @@ unsigned char CGameWindow::getAntiAliasing(void) const {
void CGameWindow::setAntiAliasing(unsigned char newMsaa) {
if (getWindow() != nullptr) {
throw CLogicException("The window must be uninitialized before using this method !");
//throw CLogicException("The window must be uninitialized before using this method !");
}
else {
if (newMsaa == 2 || newMsaa == 4 || newMsaa == 8 || newMsaa == 16) {
@@ -92,7 +94,7 @@ void CGameWindow::setAntiAliasing(unsigned char newMsaa) {
void CGameWindow::preinitialization(void) {
// We want OpenGL version 3.3.
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
/*SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3);
SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 1);
// Anti-aliasing Configuration.
@@ -108,7 +110,8 @@ void CGameWindow::preinitialization(void) {
SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1);
// Depht Buffer.
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);
SDL_GL_SetAttribute(SDL_GL_DEPTH_SIZE, 24);*/
//TODO init graphic generic (opengl vulkan etc.... commence par vulkan ?)
}
@@ -116,17 +119,17 @@ void CGameWindow::postinitialization(void) {
// Set the cursorGrab property.
if (m_grabCursor) {
SDL_SetWindowGrab(getWindow(), SDL_TRUE);
SDL_SetWindowMouseGrab(getWindow(), true);
}
else {
SDL_SetWindowGrab(getWindow(), SDL_FALSE);
SDL_SetWindowMouseGrab(getWindow(), false);
}
// Set the cursorRelative property.
if (m_relativeCursor) {
SDL_SetRelativeMouseMode(SDL_TRUE);
SDL_SetWindowRelativeMouseMode(getWindow(), true);
}
else {
SDL_SetRelativeMouseMode(SDL_FALSE);
SDL_SetWindowRelativeMouseMode(getWindow(), false);
}
}

View File

@@ -0,0 +1,49 @@
#ifndef CGAMEWINDOW_HPP
#define CGAMEWINDOW_HPP
#include "CWindow.hpp"
#include <string>
class CGameWindow : public CWindow {
private:
// Say if the mouse is grabbed.
bool m_grabCursor;
// Say if the mouse is in relative mode.
bool m_relativeCursor;
// The anti-aliasing.
unsigned char m_msaa;
public:
CGameWindow(void) = delete;
CGameWindow(const CGameWindow& param) = delete;
CGameWindow& operator=(const CGameWindow& param) = delete;
CGameWindow(std::string title, std::string iconPath, unsigned int width, unsigned int height, bool resizable, bool fullscreen);
CGameWindow(std::string title, SDL_Window* window);
~CGameWindow(void);
bool isCursorGrabbed(void) const;
void setCursorGrabbed(bool newMouseGrab);
bool isCursorRelative(void) const;
void setCursorRelative(bool newMouseRelative);
unsigned char getAntiAliasing(void) const;
void setAntiAliasing(unsigned char newMsaa);
virtual void preinitialization();
virtual void postinitialization();
//SDL_GLContext getOpenGLContext(void);
};
#endif

View File

@@ -1,4 +1,4 @@
#include "CLoadingWindow.hpp"
/*#include "CLoadingWindow.hpp"
CLoadingWindow::CLoadingWindow(std::string title, std::string iconPath, std::string splashPath, unsigned int width, unsigned int height) :
CWindow(title, iconPath, width, height, false, false, SDL_WINDOW_BORDERLESS | SDL_WINDOW_ALWAYS_ON_TOP),
@@ -37,4 +37,4 @@ void CLoadingWindow::postinitialization(void) {
SDL_RenderCopy(renderer, tex, NULL, NULL);
SDL_RenderPresent(renderer);
}
}
}*/

View File

@@ -1,4 +1,4 @@
#ifndef CLOADINGWINDOW_HPP
/*#ifndef CLOADINGWINDOW_HPP
#define CLOADINGWINDOW_HPP
#include "CWindow.hpp"
@@ -17,14 +17,6 @@
#include <SDL_image.h>
#endif
/**
* @file CLoadingWindow.hpp
* @brief File of CWindow, a class reprensenting a loading Window, using SDL2 lib.
*/
/**
* @brief Class reprensenting a loading Window, using SDL2 lib.
*/
class CLoadingWindow : public CWindow {
private:
// The path to the splash image.
@@ -38,30 +30,13 @@ public:
CLoadingWindow(const CLoadingWindow& param) = delete;
CLoadingWindow& operator=(const CLoadingWindow& param) = delete;
/**
* @brief The default constructor, build a non visible window with size of widthxheight.
* @param[in] title The title of the window.
* @param[in] iconPath The iconPath of the window.
* @param[in] splashPath The splashPath of the window.
* @param[in] width The width of the window.
* @param[in] height The height of the window.
*/
CLoadingWindow(std::string title, std::string iconPath, std::string splashPath, unsigned int width, unsigned int height);
/**
* @brief The destructor.
*/
~CLoadingWindow(void);
/**
* @brief Launched before the creation of the window, usefull for setting OpenGL attribute.
*/
virtual void preinitialization();
/**
* @brief Launched after the creation of the window, usefull for setting others attribute.
*/
virtual void postinitialization();
};
#endif
#endif*/

View File

@@ -1,20 +1,21 @@
#include "CWindow.hpp"
CWindow::CWindow(std::string title, std::string iconPath, unsigned int width, unsigned int height, bool resizable, bool fullscreen, unsigned int sdlFlags) :
#include <SDL3/SDL_surface.h>
#include <SDL3/SDL_video.h>
#include "../API/GraphicsAPI.hpp"
CWindow::CWindow(std::string title, std::string iconPath, unsigned int width, unsigned int height, bool resizable, bool fullscreen, SDL_WindowFlags sdlFlags) :
m_title(title),
m_iconPath(iconPath),
m_size(width, height),
m_visible(false),
m_fullscreen(fullscreen),
m_visible(false),
m_resizable(resizable),
m_sdlFlags(sdlFlags) {
m_pwindow = nullptr;
}
CWindow::CWindow(std::string title, SDL_Window* window, unsigned int sdlFlags, unsigned int imageFlags): m_sdlFlags(sdlFlags), m_size(600,400)
CWindow::CWindow(std::string title, SDL_Window* window, SDL_WindowFlags sdlFlags): m_title(title), m_size(600,400), m_sdlFlags(sdlFlags), m_pwindow(window)
{
m_title = title;
m_pwindow = window;
}
CWindow::~CWindow(void) {
@@ -65,7 +66,7 @@ void CWindow::setIconPath(std::string newIconPath) {
image = IMG_Load(m_iconPath.c_str());
if (image != nullptr) {
SDL_SetWindowIcon(m_pwindow, image);
SDL_FreeSurface(image);
SDL_DestroySurface(image);
}
}
}
@@ -105,10 +106,10 @@ void CWindow::setResizable(bool newResizable) {
m_resizable = newResizable;
if (m_pwindow != nullptr) {
if (m_resizable) {
SDL_SetWindowResizable(m_pwindow, SDL_TRUE);
SDL_SetWindowResizable(m_pwindow, true);
}
else {
SDL_SetWindowResizable(m_pwindow, SDL_FALSE);
SDL_SetWindowResizable(m_pwindow, true);
}
}
}
@@ -139,11 +140,11 @@ void CWindow::initialization(void) {
preinitialization();
// Création de la fenetre.
m_pwindow = SDL_CreateWindow(m_title.c_str(), SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED, m_size.first, m_size.second, SDL_WINDOW_HIDDEN | m_sdlFlags);
m_pwindow = SDL_CreateWindow(m_title.c_str(), m_size.first, m_size.second, SDL_WINDOW_HIDDEN | m_sdlFlags);
// Handle error.
if (m_pwindow == nullptr) {
throw CLibException(std::string("Unable to create window: ") + SDL_GetError());
//throw CLibException(std::string("Unable to create window: ") + SDL_GetError());//todo exceptions
}
// Set the icon.
@@ -151,15 +152,18 @@ void CWindow::initialization(void) {
image = IMG_Load(m_iconPath.c_str());
if (image != nullptr) {
SDL_SetWindowIcon(m_pwindow, image);
SDL_FreeSurface(image);
SDL_DestroySurface(image);
}
GraphicsAPI::getAPI()->init(m_pwindow);
// Set the rezisable property.
if (m_resizable) {
SDL_SetWindowResizable(m_pwindow, SDL_TRUE);
SDL_SetWindowResizable(m_pwindow, true);
}
else {
SDL_SetWindowResizable(m_pwindow, SDL_FALSE);
SDL_SetWindowResizable(m_pwindow, false);
}
// Set the fullscreen property.

View File

@@ -0,0 +1,95 @@
#ifndef CWINDOW_HPP
#define CWINDOW_HPP
#include <SDL3/SDL_render.h>
#define SDL_MAIN_USE_CALLBACKS // This is necessary for the new callbacks API. To use the legacy API, don't define this.
#include <string>
#include <utility>
#include <SDL3/SDL.h>
#include <SDL3/SDL_video.h>
#include <SDL3_image/SDL_image.h>
class CWindow {
private:
// The title of the window.
std::string m_title;
// The path to the icon.
std::string m_iconPath;
// First is the width, second is the height.
std::pair<unsigned int, unsigned int> m_size;
// Say if the window is fullscreen.
bool m_fullscreen;
// Say if the window is visible.
bool m_visible;
// Say if the window is resizable.
bool m_resizable;
// SDL flags for creating the window.
SDL_WindowFlags m_sdlFlags;
// The pointer to the window.
SDL_Window* m_pwindow;
public:
CWindow(void) = delete;
CWindow(const CWindow& param) = delete;
CWindow& operator=(const CWindow& param) = delete;
CWindow(std::string title, std::string iconPath, unsigned int width, unsigned int height, bool resizable, bool fullscreen, SDL_WindowFlags sdlFlags);
CWindow(std::string title, SDL_Window* window, SDL_WindowFlags sdlFlags);
~CWindow(void);
SDL_Window* getWindow(void);
void setWindow(SDL_Window* window){m_pwindow = window; };
bool isFullscreen(void) const;
void setFullscreen(bool newFullscreen);
bool isVisible(void) const;
void setVisible(bool newVisible);
std::string getIconPath(void) const;
std::string getTitle(void) const;
void setTitle(std::string newTitle);
void setIconPath(std::string newIconPath);
unsigned int getWidth(void) const;
unsigned int getHeight(void) const;
std::pair<unsigned int, unsigned int> getSize(void) const;
void setSize(std::pair<unsigned int, unsigned int> newSize);
void setSize(unsigned int newWidth, unsigned int newHeight);
bool isResizable(void) const;
void setResizable(bool newResizable);
bool isInitialized(void) const;
void initialization();
virtual void preinitialization() = 0;
virtual void postinitialization() = 0;
};
#endif

View File

@@ -1,5 +1,5 @@
#include "CInput.hpp"
/*
#include "../CKernel.hpp"
#include <iostream>
@@ -162,4 +162,4 @@ void CInput::onKKeyDown(unsigned int which) {
void CInput::onKKeyUp(unsigned int which) {
(void)which;
}
}*/

View File

@@ -1,17 +1,17 @@
#ifndef CINPUT_HPP
#define CINPUT_HPP
#include "../../Model/Input/CMouse.hpp"
/*#include "../../Model/Input/CMouse.hpp"
#include "../../Model/Input/CKeyboard.hpp"
#include "../../Model/Input/CController.hpp"
#include "../Exception/CException.hpp"
#include "../../Model/Observer/CKeyObserver.hpp"
#include "../Exception/CExceptionManager.hpp"
#include "../CKernel.fwd.hpp"
#include "../CKernel.fwd.hpp"*/
#include <SDL.h>
/*#include <SDL.h>
#include <utility>
#include <map>
#include <map>*/
/**
* @file CInput.hpp
@@ -21,38 +21,38 @@
/**
* @brief Class to handle all input event.
*/
class CInput : public CKeyObserver {
private:
/*class CInput : public CKeyObserver {
private:*/
// A pointer to the game.
CKernel* m_kernel;
//CKernel* m_kernel;
// The event handler.
SDL_Event m_event;
//SDL_Event m_event;
// The mouse model.
CMouse m_mouse;
//CMouse m_mouse;
// The keyboard model.
CKeyboard m_keyboard;
//CKeyboard m_keyboard;
// The controllers model, sorted by id.
std::map<unsigned int, CController*> m_controllers;
//std::map<unsigned int, CController*> m_controllers;
public:
/*public:
CInput(void) = delete;
CInput(const CInput& param) = delete;
CInput& operator=(const CInput& param) = delete;
CInput& operator=(const CInput& param) = delete;*/
/**
* @brief The usage constructor.
* @param[in] game A pointer to the game object, to handle specific event, like quit.
*/
CInput(CKernel* game);
//CInput(CKernel* game);
/**
* @brief The destructor.
*/
~CInput(void);
//~CInput(void);
/**
* @brief Function to handle all event of the game, SDL and CGame must be initialized. This function is call once per game frame.
@@ -63,38 +63,38 @@ public:
* @brief The keyboard getter.
* @return CKeyboard*, The keyboard.
*/
CKeyboard* getKeyboard(void);
//CKeyboard* getKeyboard(void);
/**
* @brief The mouse getter.
* @return CMouse*, The mouse.
*/
CMouse* getMouse(void);
//CMouse* getMouse(void);
/**
* @brief The controller getter.
* @param[in] id The id of the wanted controller.
* @return CController*, The controller.
*/
CController* getController(unsigned int id);
//CController* getController(unsigned int id);
/**
* @brief The controllers getter.
* @return std::map<unsigned int, CController*>, All the controllers, ordered by id.
*/
std::map<unsigned int, CController*> getControllers(void);
//std::map<unsigned int, CController*> getControllers(void);
/**
* @brief Handle key down event.
* @param[in] which The code of the key.
*/
virtual void onKKeyDown(unsigned int which);
/*virtual void onKKeyDown(unsigned int which);*/
/**
* @brief Handle key down event.
* @param[in] which The code of the key.
*/
virtual void onKKeyUp(unsigned int which);
};
//virtual void onKKeyUp(unsigned int which);
//};
#endif

View File

@@ -1,16 +1,23 @@
#include "CKernel.hpp"
#include <chrono>
#include <SDL3/SDL_events.h>
#include <SDL3/SDL_init.h>
#include <SDL3/SDL_keycode.h>
#include <SDL3/SDL_render.h>
#include <SDL3/SDL_timer.h>
#include <SDL3/SDL_video.h>
#include <iostream>
#include <memory>
#include <string>
#include "../../Configurations/Configuration/CConfiguration.hpp"
#include "../../Modules/Module/CModuleLoader.hpp"
#include "../Component/Graphics/CTestRenderer.hpp"
//CKernel* CKernel::m_kernel;
#include "../Graphics/CContext.hpp"
#include "../Graphics/API/GraphicsAPI.hpp"
#include "../Scene/CScene.hpp"
#include "../Entity/CEntity.hpp"
#include "../Component/Camera/CCamera.hpp"
//CShader* CKernel::m_mainShader;
// #define NAME "Cosmic Engine"
// #define LOGO "../assets/spaceEngineIcon.png"
#define LOGO "assets/spaceEngineIcon.png"
// #define SPLASH "../assets/shrekt.png"
// #define SPLASH_HEIGHT 512
// #define SPLASH_WIDTH 512
@@ -18,21 +25,19 @@
// #define GAME_WIDTH 640
namespace CosmicCore {
CKernel* CKernel::m_kernel;
CKernel::CKernel(std::string name, std::string gameName) :
m_gameName(gameName)
m_gameName(gameName), m_window(gameName, LOGO, 1270, 720, true, false)
{
//m_kernel = this;
//CContext::init(SDL_INIT_EVENTS | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC,IMG_INIT_PNG | IMG_INIT_JPG);
m_activeScene = std::make_unique<CScene>("Scene1");
m_kernel = this;
CContext::init(SDL_INIT_VIDEO | SDL_INIT_EVENTS | SDL_INIT_JOYSTICK | SDL_INIT_HAPTIC);
}
CKernel::~CKernel()
{
/*for(std::pair<const std::string, CScene*>& scenePair : m_sceneList)
{
delete scenePair.second;
}*/
}
/*void CKernel::setContext(SDL_GLContext context)
@@ -40,10 +45,10 @@ namespace CosmicCore {
m_GLcontext = context;
}*/
/*CScene* CKernel::getActiveScene()
CScene* CKernel::getActiveScene()
{
return m_activeScene;
}*/
}
/*void CKernel::initGL()
{
@@ -59,11 +64,16 @@ namespace CosmicCore {
void CKernel::start(bool isPreview) {
//DEBUG_LOG(trace, "Kernel", "Context", "Starting " + m_gameName + "...")
CConfiguration::init();
//CosmicConfig::CConfiguration::init();
//CComponentFactory::registerStandardProvidedAbstractComponents();
std::cout << CModuleLoader::loadAll() << std::endl;
//std::cout << CModuleLoader::loadAll() << std::endl;
if(!isPreview)
{
m_window.initialization();
m_sceneMap["TestScene"] = std::make_unique<CScene>("Scene1");
m_activeScene = m_sceneMap["TestScene"].get();
m_activeScene->addEntity("TestEntity", "Description");
// Open the splash window.
//DEBUG_LOG(trace, "Kernel", "Context", "Loading splash window...")
//m_loadingWindow.setVisible(true);
@@ -131,88 +141,92 @@ namespace CosmicCore {
}
void CKernel::loop() {
while(1)
{
int addOrNot = 0;
std::cout << "Create test renderer to add to the scene via an entity ?" << std::endl;
std::cin >> addOrNot;
if(addOrNot == 1)
{
auto entity = m_activeScene->addEntity("test1", "testDesc");
entity.addComponent<CTestRenderer>();
std::cout << "nb Entities : " << m_activeScene->getNumEntity() << std::endl;
}
else if(addOrNot == 2)
{
//m_activeScene.get()->getEntityComponentManager().getEntities().clear();
//m_activeScene.get()->getEntityComponentManager().addComponent<CTestRenderer>(m_activeScene.get()->getEntityComponentManager().getEntities().size()-1, EComponentType::COMPONENT_RENDERER);
}
m_activeScene->render();
}
/*unsigned int frameRate(1000 / m_config.getTargetedFramerate());
unsigned int frameRate(1000 / 144);
unsigned int beginIterationTime(0);
unsigned int endIterationTime(0);
unsigned int spendedIterationTime(0);
unsigned int lastFrame = 0;
// Activation du Depth Buffer
glEnable(GL_DEPTH_TEST);
//lancement des scripts
unsigned int numEntities = m_activeScene->getNumEntity();
for (unsigned int i = 0; i < numEntities; i++)
{
unsigned int numComponents = m_activeScene->getEntity(i)->getComponents(EComponentType::COMPONENT_SCRIPT).size();
for (unsigned int j = 0; j < numComponents; j++)
{
((CAbstractScript*)(m_activeScene->getEntity(i)->getComponents(EComponentType::COMPONENT_SCRIPT)[j]))->start();
}
}
m_window.setVisible(true);
m_window.setResizable(true);
while (!m_finished) {
// Define the starting time.
beginIterationTime = SDL_GetTicks();
// Compute the delta time.
unsigned int currentFrame = beginIterationTime;
m_deltaTime = currentFrame - lastFrame;
lastFrame = currentFrame;
// Update event system.
m_inputHandler.updateEvent();
//m_inputHandler.updateEvent();
// ####### start render #######
SDL_Event event;
while (SDL_PollEvent(&event))
{
if (event.type == SDL_EVENT_QUIT)
m_finished = true;
if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(m_window.getWindow()))
m_finished = true;
if (event.type == SDL_EVENT_KEY_DOWN) {
// Handle key press
SDL_Keycode keyPressed = event.key.key;
auto entities = m_activeScene->getECManager().registry.view<CCamera, CTransform>();
auto& ent = m_activeScene->getECManager().registry.get<CTransform>(entities.front());
switch (keyPressed) {
case SDLK_Z:
ent.forward({0.0f, 0.0f, -0.05f});
break;
case SDLK_Q:
ent.forward({-0.05f, 0.0f, 0.0f});
break;
case SDLK_S:
ent.forward({0.0f, 0.0f, 0.05f});
break;
case SDLK_D:
ent.forward({0.05f, 0.0f, 0.0f});
break;
case SDLK_LCTRL:
ent.forward({0.0f, -0.05f, 0.0f});
break;
case SDLK_LSHIFT:
ent.forward({0.0f, 0.05f, 0.0f});
break;
default:
break;
}
// Nettoyage de l'<27>cran.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Update des scripts.
m_activeScene->updateScript();
// Actualisation du monde physique.
//todo fonction wrap => pour rendre valide même si c'est pas ODE
dSpaceCollide(m_activeScene->getTangibleWorld()->getSpace(), m_activeScene->getTangibleWorld(), &(m_activeScene->getTangibleWorld())->callback);
m_activeScene->getTangibleWorld()->updateWorld(0.12f);
// Rendu.
m_activeScene->render();
// Actualisation de la fen<65>tre.
SDL_GL_SwapWindow(m_window.getWindow());
// Process the key pressed
}
if(event.type == SDL_EVENT_MOUSE_MOTION)
{
auto entities = m_activeScene->getECManager().registry.view<CCamera, CTransform>();
auto& ent = m_activeScene->getECManager().registry.get<CTransform>(entities.front());
static const float sensitivity = 0.1f;
// yaw : rotation autour de Y global (axe monde)
ent.rotate(glm::vec3(0.0f, 1.0f, 0.0f), glm::radians(-event.motion.xrel * sensitivity));
// pitch : rotation autour de X local (axe de la caméra)
ent.rotate(glm::vec3(1.0f, 0.0f, 0.0f), glm::radians(-event.motion.yrel * sensitivity));
}
}
if(m_activeScene)
GraphicsAPI::getAPI()->drawFrame();
// ####### end render #######
// Compute the end and spended time .
endIterationTime = SDL_GetTicks();
spendedIterationTime = endIterationTime - beginIterationTime;
spendedIterationTime = endIterationTime - beginIterationTime;
// If need, we pause the programm to have the right fps amount.
if (spendedIterationTime < frameRate) {
SDL_Delay(frameRate - spendedIterationTime);
}
}
if(m_isOriginOfContext)
CContext::quit();*/
GraphicsAPI::getAPI()->cleanup();
CContext::quit();
}
void CKernel::quit() {

View File

@@ -8,7 +8,7 @@
#include <glm/gtc/type_ptr.hpp>
//#include "../Context/CContext.hpp"
//#include "../Context/Window/CGameWindow.hpp"
#include "../Graphics/Window/CGameWindow.hpp"
//#include "../Context/Window/CLoadingWindow.hpp"
//#include "../Controller/Configuration/CGameConfiguration.hpp"
@@ -46,15 +46,15 @@ namespace CosmicCore {
// The windows.
//CLoadingWindow m_loadingWindow;
//CGameWindow m_window;
CGameWindow m_window;
// Global game var.
bool m_finished;
unsigned int m_deltaTime;
// The Scenes.
std::unique_ptr<CScene> m_activeScene;
//std::map<std::string, CScene*> m_sceneList;
CScene* m_activeScene;
std::map<std::string, std::unique_ptr<CScene>> m_sceneMap;
//CInput m_inputHandler;
//SDL_GLContext m_GLcontext;
@@ -66,7 +66,7 @@ namespace CosmicCore {
/**
* @brief A pointer to the simulation which is accessible from anywhere.
*/
//static CKernel* m_kernel;
static CKernel* m_kernel;
/**
* @brief A pointer to the shader used, accessible from anywhere.
@@ -86,7 +86,8 @@ namespace CosmicCore {
//void addScene(std::shared_ptr<CScene>& scene);
//void setActiveScene(std::string scene);
//void setContext(SDL_GLContext context);
//CScene* getActiveScene();
CScene* getActiveScene();
void cleanup(){m_sceneMap.clear();};
//unsigned int getNbScene() { return m_sceneList.size(); };
//std::map<std::string, CScene*>& getScenes() { return m_sceneList; };

View File

@@ -1,9 +1,15 @@
#include "CScene.hpp"
#include "nlohmann/json_fwd.hpp"
#include "../Component/Graphics/CTestRenderer.hpp"
//#include "../../Controller/Exception/CRuntimeException.hpp"
//#include "Components/CAbstractScript.hpp"
#include "../Entity/CEntity.hpp"
#include "../Component/Graphics/CRenderer.hpp"
#include "../Component/Meta/CMetaData.hpp"
#include "../Component/Geometry/CTransform.hpp"
#include "../Component/Camera/CCamera.hpp"
#include "../Component/Relationships/CRelationship.hpp"
#include "../Graphics/API/GraphicsAPI.hpp"
#include "../Graphics/Data/CModelLoader.hpp"
#include <memory>
#include <vector>
namespace CosmicCore {
CScene::CScene(std::string name) : CSerializable(),
@@ -15,8 +21,52 @@ namespace CosmicCore {
return m_name;
}
CEntity CScene::addEntity(std::string name, std::string description){
VulkanImpl* api = dynamic_cast<VulkanImpl*>(GraphicsAPI::getAPI().get());
auto handle = m_ecManager.registry.create();
CEntity handler(m_ecManager, handle, this);
m_ecManager().emplace<CTransform>(handle, handler);
m_ecManager().emplace<CMetaData>(handle, handler, std::move(name), std::move(description));
auto& rM = GraphicsAPI::getAPI()->getResourceManager();
auto model = CModelLoader::loadModel("assets/models/cube.glb", rM);
rM.getTextureManager().loadedTextures.push_back(std::make_unique<CTexture>("assets/shrekt.png"));
auto texture = rM.getTextureManager().loadedTextures.back().get();
texture->init();
for(auto& mesh : model->getMeshes())
{
mesh->getMaterial()->textureAlbedo = texture;
mesh->getMaterial()->build();
}
m_ecManager().emplace<CRenderer>(handle, handler, model);
auto& tr = m_ecManager.registry.get<CTransform>(handle);
tr.initUniformBuffer(dynamic_cast<VulkanImpl*>(GraphicsAPI::getAPI().get())->getAllocator());
tr.updateUniformBuffer(0);
tr.updateUniformBuffer(1);
auto camHandle = m_ecManager.registry.create();
CEntity handlerCam(m_ecManager, camHandle, this);
auto& transform = m_ecManager().emplace<CTransform>(camHandle, handlerCam);
auto& cam = m_ecManager.registry.emplace<CCamera>(camHandle, handlerCam);
m_ecManager.registry.emplace<CRelationship>(camHandle, handlerCam, std::vector<EntityId>{handle});
m_ecManager.registry.emplace<CRelationship>(handle, handler, camHandle);
transform.setCenter({0.0f, 0.9f, 3.0f});
cam.setAspect((float)api->getSwapChainExtent().width / api->getSwapChainExtent().height);
cam.initUniformBuffer(api->getAllocator());
cam.updateUniformBuffer(0, transform);
cam.updateUniformBuffer(1, transform);
return handler;
}
unsigned int CScene::getNumEntity(void) const {
return this->m_ecManager.view<CMetaData>()->size();
return m_ecManager().view<CMetaData>()->size();
}
void CScene::removeEntity(unsigned int index, bool destroy)
@@ -24,24 +74,57 @@ namespace CosmicCore {
}
void CScene::render(){
auto renderers = m_ecManager.view<CTestRenderer>();
for(auto beg = renderers->begin(); beg != renderers->end(); ++beg)
{
beg->render();
}
//std::chrono::steady_clock::time_point begin1 = std::chrono::steady_clock::now();
//auto eh = m_ecManager.create();
//m_ecManager.emplace<CTestRenderer>(eh, nullptr);
//std::chrono::steady_clock::time_point end1 = std::chrono::steady_clock::now();
//std::cout << "added entity and comptest : " <<std::chrono::duration_cast<std::chrono::seconds>(end1 - begin1).count() << std::endl;
//static unsigned int entitynb = 0;
//entitynb++;
//std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now();
//m_ecManager.view<CTestRenderer>().each([](auto e, CTestRenderer& comp){comp.render();});
//std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now();
//std::cout << "render func : " << std::chrono::duration_cast<std::chrono::seconds>(end - begin).count() << std::endl;
//std::cout << "nb : " << entitynb << std::endl;
void CScene::render(vk::raii::CommandBuffer& cmd, uint32_t frameIndex){
auto entities = m_ecManager.registry.view<CRenderer, CTransform>();
VulkanImpl* api = dynamic_cast<VulkanImpl*>(GraphicsAPI::getAPI().get());
auto cam = m_ecManager.registry.view<CCamera, CTransform>();
auto& camera = m_ecManager.registry.get<CCamera>(cam.front());
auto& transform = m_ecManager.registry.get<CTransform>(cam.front());
camera.updateUniformBuffer(frameIndex, transform);
cmd.bindDescriptorSets(
vk::PipelineBindPoint::eGraphics,
api->getDefaultPipelineLayout(), // layout du pipeline
0,
*camera.getDescriptorSet(frameIndex),
{}
);
for (auto& entity : entities) {
auto model = m_ecManager.registry.get<CRenderer>(entity).getModel();
auto& transform = m_ecManager.registry.get<CTransform>(entity);
transform.updateUniformBuffer(frameIndex);
//trier meshes par matérial ?
// bind transform UBO (set = 1)
cmd.bindDescriptorSets(
vk::PipelineBindPoint::eGraphics,
api->getDefaultPipelineLayout(), // layout du pipeline
1, // set = 1
*transform.getDescriptorSet(frameIndex),
{}
);
for (auto& mesh : model->getMeshes()) {
// ne rebind le pipeline que si le material change
//if (mesh.getMaterial() != boundMaterial) {
//boundMaterial = mesh.getMaterial();
cmd.bindPipeline(vk::PipelineBindPoint::eGraphics,
*mesh->getMaterial()->getPipeline());
cmd.bindDescriptorSets(vk::PipelineBindPoint::eGraphics,
*mesh->getMaterial()->getPipelineLayout(),
2,
*mesh->getMaterial()->getDescriptorSet(frameIndex),
{});
//}
cmd.bindVertexBuffers(0, vk::Buffer(mesh->getVertexIndexBuffer().buffer), mesh->getVertexOffset());
cmd.bindIndexBuffer(vk::Buffer(mesh->getVertexIndexBuffer().buffer), mesh->getIndexOffset(), vk::IndexType::eUint32);
cmd.drawIndexed(mesh->getIndexCount(), 1, 0, 0, 0);
}
}
}
// void CScene::setMask(unsigned int mask)

View File

@@ -1,37 +1,32 @@
#ifndef CSCENE_HPP
#define CSCENE_HPP
#include "../Component/Geometry/CTransform.hpp"
#include "../Component/Meta/CMetaData.hpp"
#include <entt/entt.hpp>
#include "../Systems/EntityComponentManager.hpp"
#include "../Utils/CSerializable.hpp"
#include <string>
#include <vulkan/vulkan_raii.hpp>
namespace CosmicCore {;
namespace CosmicCore {
class CEntity;
class CScene : public CSerializable {
using ECManager = entt::registry;
private:
// The name of the scene.
std::string m_name;
ECManager m_ecManager;
EntityComponentManager m_ecManager;
public:
CScene() = delete;
CScene(std::string name);
~CScene() = default;
virtual ~CScene() = default;
unsigned int getNumEntity() const;
CEntity addEntity(std::string name, std::string description){
auto handle = m_ecManager.create();
CEntity handler(m_ecManager, handle);
m_ecManager.emplace<CTransform>(handle, handler);
m_ecManager.emplace<CMetaData>(handle, handler, std::move(name), std::move(description));
return handler;
}
CEntity addEntity(std::string name, std::string description);
std::string getName() const;
EntityComponentManager& getECManager(){return m_ecManager;};
void removeEntity(unsigned int index, bool destroy = true);
//CEntity* getActiveCamera();
@@ -73,7 +68,7 @@ namespace CosmicCore {;
*/
//unsigned int getMask();
void render();
void render(vk::raii::CommandBuffer& cmd, uint32_t frameIndex);
//void updateScript();
nlohmann::json to_json();

View File

@@ -0,0 +1,26 @@
#ifndef ENTITYCOMPONENTMANAGER_HPP
#define ENTITYCOMPONENTMANAGER_HPP
#include <entt/entt.hpp>
namespace CosmicCore {
using ECManager = entt::registry;
using EntityId = entt::entity;
class EntityComponentManager{
public:
ECManager registry;
ECManager& operator()(){
return registry;
}
const ECManager& operator()() const {
return registry;
}
};
};
#endif

View File

@@ -1,6 +1,6 @@
#include "CFileManager.hpp"
void CFileManager::open(const char mode) {
/*void CFileManager::open(const char mode) {
DEBUG_LOG(trace, "Kernel", "FileManager", "file " + m_filePath + " opened.")
switch (mode) {
@@ -59,4 +59,4 @@ std::string CFileManager::read(void) {
close();
return out;
}
}*/

View File

@@ -1,14 +1,8 @@
#ifndef CFILEMANAGER_HPP
#define CFILEMANAGER_HPP
#include "../Exception/CFileException.hpp"
#include "../../Context/CContext.hpp"
#include <cstdio>
#include <string>
#include <stdexcept>
/**
* @file CFileManager.hpp

View File

@@ -1,150 +0,0 @@
#include "CModelLoader.hpp"
#include <iostream>
CModel* CModelLoader::loadModel(std::string fileName, SMaterial* material)
{
Assimp::Importer import;
const aiScene* scene = import.ReadFile(fileName, aiProcess_Triangulate | aiProcess_FlipUVs | aiProcess_MakeLeftHanded | aiProcess_FlipWindingOrder | aiProcess_JoinIdenticalVertices);
if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode)
{
std::cout << std::string(import.GetErrorString()) << std::endl;
DEBUG_LOG(trace, "Kernel", "ModelLoader", std::string("Assimp error : ") + std::string(import.GetErrorString()))
return nullptr;
}
std::vector<CMesh*> meshes;
processNode(scene->mRootNode, scene, &meshes, material);
CModel* model = new CModel(meshes);
model->load();
return model;
}
void CModelLoader::processNode(aiNode* node, const aiScene* scene, std::vector<CMesh*>* meshes, SMaterial* material)
{
// process all the node's meshes (if any)
for (unsigned int i = 0; i < node->mNumMeshes; i++)
{
aiMesh* mesh = scene->mMeshes[node->mMeshes[i]];
processMesh(mesh, scene, meshes, material);
}
// then do the same for each of its children
for (unsigned int i = 0; i < node->mNumChildren; i++)
{
processNode(node->mChildren[i], scene, meshes, material);
}
}
void CModelLoader::processMesh(aiMesh* mesh, const aiScene* scene, std::vector<CMesh*>* meshes, SMaterial* material)
{
std::vector<SVertex> vertices;
std::vector<unsigned int> indices;
SVertex vertex;
for (unsigned int i = 0; i < mesh->mNumVertices; i++)
{
vertex.m_position = glm::vec3(mesh->mVertices[i].x, mesh->mVertices[i].y, mesh->mVertices[i].z);
vertex.m_normal = glm::vec3(mesh->mNormals[i].x, mesh->mNormals[i].y, mesh->mNormals[i].z);
if (mesh->mTextureCoords[0]) // if the mesh contains texture coordinates
{
vertex.m_texCoords.x = mesh->mTextureCoords[0][i].x;
vertex.m_texCoords.y = mesh->mTextureCoords[0][i].y;
}
else
{
vertex.m_texCoords = glm::vec2(0.0f, 0.0f);
}
if (mesh->mBitangents)// if the mesh contains bitangent coordinates
{
vertex.m_bitangent.x = mesh->mBitangents->x;
vertex.m_bitangent.y = mesh->mBitangents->y;
vertex.m_bitangent.z = mesh->mBitangents->z;
}
else
{
vertex.m_bitangent = glm::vec3(0.0f, 0.0f, 0.0f);
}
if (mesh->mTangents)// if the mesh contains tangent coordinates
{
vertex.m_tangent.x = mesh->mTangents->x;
vertex.m_tangent.y = mesh->mTangents->y;
vertex.m_tangent.z = mesh->mTangents->z;
}
else
{
vertex.m_tangent = glm::vec3(0.0f, 0.0f, 0.0f);
}
vertices.push_back(vertex);
}
// process indices
for (unsigned int i = 0; i < mesh->mNumFaces; i++)
{
aiFace face = mesh->mFaces[i];
for (unsigned int j = 0; j < face.mNumIndices; j++)
indices.push_back(face.mIndices[j]);
}
// process material
std::vector<CImageTexture*> diffuseMaps;
std::vector<CImageTexture*> specularMaps;
std::vector<CAbstractTexture*> textures;
SMaterial* mat = new SMaterial;
if (mesh->mMaterialIndex >= 0 && material == nullptr)
{
aiMaterial* amaterial = scene->mMaterials[mesh->mMaterialIndex];
diffuseMaps = loadMaterialTextures(amaterial,
aiTextureType_DIFFUSE, ETextureType::TEXTURE_DIFFUSE);
specularMaps = loadMaterialTextures(amaterial,
aiTextureType_SPECULAR, ETextureType::TEXTURE_SPECULAR);
for (size_t i = 0; i < diffuseMaps.size(); i++)
{
textures.push_back((CAbstractTexture*)diffuseMaps[i]);
}
for (size_t j = 0; j < specularMaps.size(); j++)
{
textures.push_back((CAbstractTexture*)specularMaps[j]);
}
std::vector<SColor> colorsC; //= { {glm::vec4(1.0f, 1.0f, 1.0f, 1.0f), EColorType::COLOR_DIFFUSE} };
aiColor4D color(0.0f, 0.0f, 0.0f, 0.0f);
amaterial->Get(AI_MATKEY_COLOR_DIFFUSE, color);
SColor diffuseColor = { glm::vec4(color.r, color.g, color.b, color.a), EColorType::COLOR_DIFFUSE };
colorsC.push_back(diffuseColor);
*mat = { textures, colorsC, CKernel::m_mainShader };
}
else// if the material is given, override the material of the wavefront obj file
{
delete mat;
mat = material;
}
CMesh* m = new CMesh();
m->setMaterial(mat);
m->setIndexes(indices);
m->setVertices(vertices);
meshes->push_back(m);
}
std::vector<CImageTexture*> CModelLoader::loadMaterialTextures(aiMaterial* mat, aiTextureType type, ETextureType typeName)
{
std::vector<CImageTexture*> textures;
for (unsigned int i = 0; i < mat->GetTextureCount(type); i++)
{
aiString str;
mat->GetTexture(type, i, &str);
CImageTexture* text = new CImageTexture(typeName, str.C_Str());
text->init();//Load the texture in GPU before adding it the texture list
textures.push_back(text);
}
return textures;
}

View File

@@ -1,5 +1,5 @@
#include "CModuleLoader.hpp"
namespace CosmicCore {
/*namespace CosmicCore {
std::vector<void*> CModuleLoader::handles;
}
}*/

View File

@@ -4,7 +4,7 @@
#include <dlfcn.h>
#include <iostream>
#include <filesystem>
#include "../Configuration/CConfiguration.hpp"
/*#include "../../../Configurations/Configuration/CConfiguration.hpp"
namespace CosmicCore
{
class CModuleLoader {
@@ -62,5 +62,5 @@ namespace CosmicCore
return 0;
}
};
}
}*/
#endif

View File

@@ -1,36 +1,5 @@
#include "CShaderFactory.hpp"
#include "../CKernel.hpp"
#include "../../Specific/Graphic/OpenGLImpl/CShaderOpenGLImpl.hpp"
CShader* CShaderFactory::createShader(CKernel* e, std::string name, std::string vertexPath, std::string fragmentPath) {
if (e == nullptr) {
throw CLogicException("CKernel is null");
}
return createShader(e->getEngineConfig()->getGraphicImplementation(), name, vertexPath, fragmentPath);
}
CShader* CShaderFactory::createShader(CKernel* e, std::string name, std::string vertexPath, std::string fragmentPath, std::string geomPath) {
if (e == nullptr) {
throw CLogicException("CKernel is null");
}
return createShader(e->getEngineConfig()->getGraphicImplementation(), name, vertexPath, fragmentPath, geomPath);
}
CShader* CShaderFactory::createShader(EGraphicImplementation e, std::string name, std::string vertexPath, std::string fragmentPath) {
switch (e) {
case EGraphicImplementation::GRAPHIC_OPENGL:
return new CShaderOpenGLImpl(name, vertexPath, fragmentPath);
break;
}
throw CLogicException("Unexpected error while creating shader");
}
CShader* CShaderFactory::createShader(EGraphicImplementation e, std::string name, std::string vertexPath, std::string fragmentPath, std::string geomPath) {
switch (e) {
case EGraphicImplementation::GRAPHIC_OPENGL:
return new CShaderOpenGLImpl(name, vertexPath, fragmentPath, geomPath);
break;
}
throw CLogicException("Unexpected error while creating shader");
namespace CosmicUtils {
GraphicsBackend CShaderFactory::m_backend = GraphicsBackend::Vulkan;
}

View File

@@ -1,18 +1,27 @@
#ifndef CSHADERFACTORY_HPP
#define CSHADERFACTORY_HPP
#include "../Configuration/EImplementations.hpp"
#include "../../Model/Graphic/Shader/CShader.hpp"
#include "../CKernel.fwd.hpp"
#include "../../Core/Graphics/Shader/CShader.hpp"
#include "../../Core/Graphics/API/GraphicsAPI.hpp"
#include "../../Core/Graphics/Shader/Implementations/CShaderImplVulkan.hpp"
namespace CShaderFactory {
CShader* createShader(CKernel* e, std::string name, std::string vertexPath, std::string fragmentPath);
#include <cstddef>
#include <filesystem>
#include <memory>
namespace CosmicUtils {
CShader* createShader(EGraphicImplementation e, std::string name, std::string vertexPath, std::string fragmentPath);
CShader* createShader(CKernel* e, std::string name, std::string vertexPath, std::string fragmentPath, std::string geomPath);
CShader* createShader(EGraphicImplementation e, std::string name, std::string vertexPath, std::string fragmentPath, std::string geomPath);
class CShaderFactory{
static GraphicsBackend m_backend;
public:
static std::unique_ptr<CShader> create(std::string name, std::filesystem::path path) {
switch (m_backend) {
case GraphicsBackend::Vulkan: return std::make_unique<CShaderImplVulkan>(name, path);
case GraphicsBackend::OpenGL: return nullptr;
case GraphicsBackend::Metal: return nullptr;
break;
}
}
};
}
#endif

View File

@@ -1,6 +1,6 @@
#include "ComponentFactory.hpp"
namespace CosmicCore {
/*namespace CosmicCore {
CComponentFactory& globalComponentFactory = CComponentFactory::instance();
CComponentFactory& CComponentFactory::instance() {
@@ -8,4 +8,4 @@ namespace CosmicCore {
return factory;
}
}
*/

View File

@@ -6,10 +6,10 @@
#include <stdexcept>
#include <typeindex>
#include <utility>
#include "../Component/CAbstractComponent.hpp"
//#include "../Component/CAbstractComponent.hpp"
//TODO modifier pour la scène soit obligatoire, sans scène pas d'entité, sans entité pas de composants
namespace CosmicCore
/*namespace CosmicCore
{
class CEntity;
class CComponentFactory {
@@ -91,5 +91,5 @@ namespace CosmicCore
extern CComponentFactory& globalComponentFactory;
}
*/
#endif

View File

@@ -27,7 +27,6 @@ int main(int argc, char** argv) {
// test();
using namespace CosmicCore;
CKernel g("Mon jeu", "Jeu");
//CScene s("Scene1");
g.start();
g.loop();