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:
40
src/Engine/Core/Graphics/Data/CModel.cpp
Normal file
40
src/Engine/Core/Graphics/Data/CModel.cpp
Normal file
@@ -0,0 +1,40 @@
|
||||
#include "CModel.hpp"
|
||||
|
||||
CModel::CModel(std::vector<CMesh*> meshes) :
|
||||
m_meshes(meshes),
|
||||
m_loaded(false) {
|
||||
}
|
||||
|
||||
CModel::~CModel(void) {
|
||||
}
|
||||
|
||||
void CModel::load(void) {
|
||||
// For each meshes of the model.
|
||||
for (unsigned int i = 0; i < m_meshes.size(); i++) {
|
||||
m_meshes[i]->load();
|
||||
}
|
||||
|
||||
m_loaded = true;
|
||||
}
|
||||
|
||||
/*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()
|
||||
{
|
||||
return m_meshes;
|
||||
}
|
||||
|
||||
void CModel::setMeshes(std::vector<CMesh*> meshes)
|
||||
{
|
||||
m_meshes = meshes;
|
||||
}
|
||||
|
||||
bool CModel::isLoaded()
|
||||
{
|
||||
return m_loaded;
|
||||
}
|
||||
34
src/Engine/Core/Graphics/Data/CModel.hpp
Normal file
34
src/Engine/Core/Graphics/Data/CModel.hpp
Normal 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
|
||||
151
src/Engine/Core/Graphics/Data/CModelLoader.cpp
Normal file
151
src/Engine/Core/Graphics/Data/CModelLoader.cpp
Normal 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;
|
||||
}
|
||||
}
|
||||
58
src/Engine/Core/Graphics/Data/CModelLoader.hpp
Normal file
58
src/Engine/Core/Graphics/Data/CModelLoader.hpp
Normal file
@@ -0,0 +1,58 @@
|
||||
#ifndef CMODELLOADER_HPP
|
||||
#define CMODELLOADER_HPP
|
||||
|
||||
|
||||
#include <assimp/Importer.hpp>
|
||||
#include <assimp/scene.h>
|
||||
#include <assimp/postprocess.h>
|
||||
|
||||
#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:
|
||||
/**
|
||||
* @brief Compute every node in the loaded meshes.
|
||||
* @param[in] node The assimp created node.
|
||||
* @param[in] scene The assimp created scene.
|
||||
* @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, const std::string& directory, CResourceManager& rm, std::vector<CMesh*>& meshes);
|
||||
|
||||
/**
|
||||
* @brief Compute every meshes.
|
||||
* @param[in] mesh The assimp created mesh.
|
||||
* @param[in] scene The assimp created scene.
|
||||
* @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 CMesh* processMesh(aiMesh* mesh, const aiScene* scene, const std::string& directory, CResourceManager& rm);
|
||||
|
||||
/**
|
||||
* @brief Load Textures from the obj file.
|
||||
* @param[in] mat The assimp created material.
|
||||
* @param[in] type The assimp's texture type.
|
||||
* @param[in] typeName The texture's type.
|
||||
*/
|
||||
static CTexture* loadTexture(const std::string& directory, CResourceManager& rm);
|
||||
|
||||
static CMaterial* processMaterial(aiMaterial* mat, const std::string& directory, CResourceManager& rm);
|
||||
public:
|
||||
|
||||
/**
|
||||
* @brief main function of the class, starts loading the obj file.
|
||||
* @param[in] fileName Path to the OBJ file.
|
||||
* @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, CResourceManager& rm);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
32
src/Engine/Core/Graphics/Data/CModelManager.hpp
Normal file
32
src/Engine/Core/Graphics/Data/CModelManager.hpp
Normal 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
|
||||
28
src/Engine/Core/Graphics/Data/CResourceManager.hpp
Normal file
28
src/Engine/Core/Graphics/Data/CResourceManager.hpp
Normal 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
|
||||
111
src/Engine/Core/Graphics/Data/Font/CTextTexture.cpp
Normal file
111
src/Engine/Core/Graphics/Data/Font/CTextTexture.cpp
Normal file
@@ -0,0 +1,111 @@
|
||||
/*#include "CTextTexture.hpp"
|
||||
|
||||
CTextTexture::CTextTexture(ETextureType type, std::string filePath, std::string text, unsigned int fontSize, glm::vec3 fontColor, glm::bvec4 fontStyle) :
|
||||
CAbstractTexture(type),
|
||||
m_fontFilePath(filePath),
|
||||
m_renderText(text),
|
||||
m_fontSize(fontSize),
|
||||
m_fontColor(fontColor),
|
||||
m_fontStyle(fontStyle) {
|
||||
}
|
||||
|
||||
std::string CTextTexture::getFontFilePath(void) {
|
||||
return m_fontFilePath;
|
||||
}
|
||||
|
||||
void CTextTexture::setFontFilePath(std::string filePath) {
|
||||
m_fontFilePath = filePath;
|
||||
}
|
||||
|
||||
std::string CTextTexture::getText(void) {
|
||||
return m_renderText;
|
||||
}
|
||||
|
||||
void CTextTexture::setText(std::string text) {
|
||||
m_renderText = text;
|
||||
}
|
||||
|
||||
void CTextTexture::init(void) {
|
||||
// Read the font file.
|
||||
TTF_Font* font = TTF_OpenFont(m_fontFilePath.c_str(), m_fontSize);
|
||||
|
||||
SDL_Color color;
|
||||
color.r = m_fontColor.x / 255u;
|
||||
color.g = m_fontColor.y / 255u;
|
||||
color.b = m_fontColor.z / 255u;
|
||||
|
||||
int style = TTF_STYLE_NORMAL;
|
||||
if (m_fontStyle.x) {
|
||||
style |= TTF_STYLE_BOLD;
|
||||
}
|
||||
if (m_fontStyle.y) {
|
||||
style |= TTF_STYLE_ITALIC;
|
||||
}
|
||||
if (m_fontStyle.z) {
|
||||
style |= TTF_STYLE_UNDERLINE;
|
||||
}
|
||||
if (m_fontStyle.z) {
|
||||
style |= TTF_STYLE_STRIKETHROUGH;
|
||||
}
|
||||
TTF_SetFontStyle(font, style);
|
||||
|
||||
SDL_Surface* sdlSurface = TTF_RenderText_Blended(font, m_renderText.c_str(), color);
|
||||
|
||||
if (sdlSurface == NULL) {
|
||||
throw CLibException(std::string("Can not render the text : ") + 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 font.
|
||||
TTF_CloseFont(font);
|
||||
|
||||
// Free the surface.
|
||||
SDL_FreeSurface(sdlSurface);
|
||||
}*/
|
||||
47
src/Engine/Core/Graphics/Data/Font/CTextTexture.hpp
Normal file
47
src/Engine/Core/Graphics/Data/Font/CTextTexture.hpp
Normal file
@@ -0,0 +1,47 @@
|
||||
/*#ifndef CTEXTTEXTURE_HPP
|
||||
#define CTEXTTEXTURE_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 <glm/glm.hpp>
|
||||
#include <SDL_ttf.h>
|
||||
#ifdef WIN32
|
||||
#include <gl/glew.h>
|
||||
#else
|
||||
#include <GL/glew.h>
|
||||
#endif
|
||||
|
||||
class CTextTexture : CAbstractTexture {
|
||||
private:
|
||||
// Path of the file.
|
||||
std::string m_fontFilePath;
|
||||
|
||||
// The size of the font.
|
||||
unsigned int m_fontSize;
|
||||
|
||||
// The color of the font.
|
||||
glm::vec3 m_fontColor;
|
||||
|
||||
// The style of the font (x is bold, y is italic, z is underline, w is strikethrough).
|
||||
glm::bvec4 m_fontStyle;
|
||||
|
||||
// The text to render.
|
||||
std::string m_renderText;
|
||||
|
||||
public:
|
||||
CTextTexture(void) = delete;
|
||||
CTextTexture(ETextureType type, std::string filePath, std::string text, unsigned int fontSize, glm::vec3 fontColor, glm::bvec4 fontStyle);
|
||||
~CTextTexture() {};
|
||||
std::string getFontFilePath(void);
|
||||
void setFontFilePath(std::string filePath);
|
||||
std::string getText(void);
|
||||
void setText(std::string text);
|
||||
virtual void init(void);
|
||||
};
|
||||
|
||||
#endif*/
|
||||
137
src/Engine/Core/Graphics/Data/Material/CMaterial.cpp
Normal file
137
src/Engine/Core/Graphics/Data/Material/CMaterial.cpp
Normal 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);
|
||||
}
|
||||
}
|
||||
30
src/Engine/Core/Graphics/Data/Material/CMaterial.hpp
Normal file
30
src/Engine/Core/Graphics/Data/Material/CMaterial.hpp
Normal 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
|
||||
31
src/Engine/Core/Graphics/Data/Material/CMaterialManager.hpp
Normal file
31
src/Engine/Core/Graphics/Data/Material/CMaterialManager.hpp
Normal 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
|
||||
39
src/Engine/Core/Graphics/Data/Material/SColor.hpp
Normal file
39
src/Engine/Core/Graphics/Data/Material/SColor.hpp
Normal file
@@ -0,0 +1,39 @@
|
||||
#ifndef SCOLOR_HPP
|
||||
#define SCOLOR_HPP
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
/**
|
||||
* @file SColor.hpp
|
||||
* @brief File for the color struct of a material.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief the number of type in the enum EColorType.
|
||||
*/
|
||||
#define COLOR_TYPE_NUMBER 2
|
||||
|
||||
/**
|
||||
* @brief The enum for color type in the material.
|
||||
*/
|
||||
enum EColorType {
|
||||
COLOR_DIFFUSE,
|
||||
COLOR_SPECULAR,
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The struct color of the material.
|
||||
*/
|
||||
typedef struct {
|
||||
/**
|
||||
* @brief 4D Vector representing the RGBA color.
|
||||
*/
|
||||
glm::vec4 m_vector;
|
||||
|
||||
/**
|
||||
* @brief The color's type.
|
||||
*/
|
||||
EColorType m_type;
|
||||
} SColor;
|
||||
|
||||
#endif
|
||||
107
src/Engine/Core/Graphics/Data/Mesh/CMesh.cpp
Normal file
107
src/Engine/Core/Graphics/Data/Mesh/CMesh.cpp
Normal 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) {
|
||||
|
||||
}*/
|
||||
53
src/Engine/Core/Graphics/Data/Mesh/CMesh.hpp
Normal file
53
src/Engine/Core/Graphics/Data/Mesh/CMesh.hpp
Normal 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
|
||||
31
src/Engine/Core/Graphics/Data/Mesh/CMeshManager.hpp
Normal file
31
src/Engine/Core/Graphics/Data/Mesh/CMeshManager.hpp
Normal 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
|
||||
70
src/Engine/Core/Graphics/Data/Mesh/SVertex.hpp
Normal file
70
src/Engine/Core/Graphics/Data/Mesh/SVertex.hpp
Normal 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
|
||||
219
src/Engine/Core/Graphics/Data/Texture/CTexture.cpp
Normal file
219
src/Engine/Core/Graphics/Data/Texture/CTexture.cpp
Normal 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);
|
||||
}
|
||||
45
src/Engine/Core/Graphics/Data/Texture/CTexture.hpp
Normal file
45
src/Engine/Core/Graphics/Data/Texture/CTexture.hpp
Normal 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
|
||||
32
src/Engine/Core/Graphics/Data/Texture/CTextureManager.hpp
Normal file
32
src/Engine/Core/Graphics/Data/Texture/CTextureManager.hpp
Normal 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
|
||||
Reference in New Issue
Block a user