← Back to file list Raw

src/CGL430Model.cpp

#include "CGL430Model.h"
#include "CEngine.h"
#include "CWindowManager.h"
#include "CResourcesManager.h"
#include "COpenGL430Renderer.h"
#include "CConVarManager.h"
CGL430ModelLoadingContext::CGL430ModelLoadingContext(CResource* _current_resource, const std::filesystem::path& _path) : CModelLoadingContext(_current_resource, _path) { }
CGL430Model::CGL430Model()
{
auto& callback = GetLoadPipelineSetupCallback();
if(callback.IsEmpty())
{
callback += [](CLoadPipeline& pipeline)
{
pipeline.push_back //build model data for gpu (async)
(
{
[](std::shared_ptr<CLoadingContext> context) -> bool
{
auto mdlContext = std::dynamic_pointer_cast<CGL430ModelLoadingContext>(context);
auto thisResource = dynamic_cast<CGL430Model*>(context->CurrentResource);
std::map<std::tuple<uint64_t, uint64_t, uint64_t, int>, unsigned int> vertexMap;
unsigned int currentIndex = 0;
for (const auto& tri : mdlContext->LoadInfo.Triangles)
{
for (int i = 0; i < 3; i++)
{
uint64_t vIdx = tri.VertexIndex[i];
uint64_t nIdx = tri.NormalIndex[i];
uint64_t tIdx = tri.UvIndex[i];
auto key = std::make_tuple(vIdx, nIdx, tIdx, tri.MaterialIndex);
auto it = vertexMap.find(key);
if (it == vertexMap.end())
{
const auto& v = mdlContext->LoadInfo.Vertices[vIdx];
CGL430ModelLoadingContext::PackedVertex pv;
pv.Position = v.Position;
pv.Normal = (nIdx < mdlContext->LoadInfo.Normals.size()) ? mdlContext->LoadInfo.Normals[nIdx] : glm::vec3(0);
pv.TexCoord = (tIdx < mdlContext->LoadInfo.UvCoords.size()) ? mdlContext->LoadInfo.UvCoords[tIdx] : glm::vec2(0);
int count = std::min<int>(v.Bones.size(), 4);
for (int j = 0; j < count; j++)
{
pv.BoneIds[j] = v.Bones[j].BoneIndex;
pv.BoneWeights[j] = v.Bones[j].Weight;
}
mdlContext->vertexBuffer.push_back(pv);
mdlContext->indexBuffer.push_back(currentIndex);
vertexMap[key] = currentIndex++;
}
else
{
mdlContext->indexBuffer.push_back(it->second);
}
}
}
mdlContext->indexCount = mdlContext->indexBuffer.size();
thisResource->indexCount = mdlContext->indexCount;
auto resman = CEngine::GetInstance()->Components.GetComponentTyped<CResourcesManager>();
auto winman = CEngine::GetInstance()->Components.GetComponentTyped<CWindowManager>();
auto& _renderer = winman->Renderer;
auto renderer = dynamic_cast<COpenGL430Renderer*>(_renderer.get());
for(auto& res : context->RequiredResources)
{
if(res && res->GetType() == renderer->GetMaterialType())
{
//res->Wait(); NO WAITING IN ASYNC THREAD
auto material = std::dynamic_pointer_cast<CGL430Material>(res);
thisResource->UsedMaterials.push_back(material);
}
}
mdlContext->materialPerTriangle.reserve(mdlContext->LoadInfo.Triangles.size());
for (const auto& tri : mdlContext->LoadInfo.Triangles)
{
std::string matName = mdlContext->LoadInfo.MaterialsList.at(tri.MaterialIndex);
auto it = std::find_if(thisResource->UsedMaterials.begin(), thisResource->UsedMaterials.end(), [&matName](auto mat) -> bool
{
return mat->Name == matName;
});
int id = renderer->GetMaterialIndex(it->get());
mdlContext->materialPerTriangle.push_back(id);
}
return true;
},
true //async (is_async)
}
);
pipeline.push_back //upload model data to gpu (sync)
(
{
[](std::shared_ptr<CLoadingContext> context) -> bool
{
auto mdlContext = std::dynamic_pointer_cast<CGL430ModelLoadingContext>(context);
auto thisResource = dynamic_cast<CGL430Model*>(context->CurrentResource);
using PackedVertex = CGL430ModelLoadingContext::PackedVertex;
glGenVertexArrays(1, &thisResource->vao);
glBindVertexArray(thisResource->vao);
glGenBuffers(1, &thisResource->vbo);
glBindBuffer(GL_ARRAY_BUFFER, thisResource->vbo);
glBufferData(GL_ARRAY_BUFFER, mdlContext->vertexBuffer.size() * sizeof(PackedVertex), mdlContext->vertexBuffer.data(), GL_STATIC_DRAW);
glGenBuffers(1, &thisResource->ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, thisResource->ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, mdlContext->indexBuffer.size() * sizeof(unsigned int), mdlContext->indexBuffer.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(PackedVertex), (void*)offsetof(PackedVertex, Position));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(PackedVertex), (void*)offsetof(PackedVertex, Normal));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(PackedVertex), (void*)offsetof(PackedVertex, TexCoord));
glEnableVertexAttribArray(2);
glVertexAttribIPointer(3, 4, GL_INT, sizeof(PackedVertex), (void*)offsetof(PackedVertex, BoneIds));
glEnableVertexAttribArray(3);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(PackedVertex), (void*)offsetof(PackedVertex, BoneWeights));
glEnableVertexAttribArray(4);
glBindVertexArray(0);
glGenBuffers(1, &thisResource->materialSSBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, thisResource->materialSSBO);
glBufferData(GL_SHADER_STORAGE_BUFFER, mdlContext->materialPerTriangle.size() * sizeof(int), mdlContext->materialPerTriangle.data(), GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, thisResource->materialSSBO); //TODO change binding
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
return true;
},
false //sync (is_async)
}
);
};
}
}
int CGL430Model::LoadMaterial(const std::string& name)
{
std::string materialName = std::filesystem::path(name).stem().string();
auto resman = CEngine::GetInstance()->Components.GetComponentTyped<CResourcesManager>();
auto winman = CEngine::GetInstance()->Components.GetComponentTyped<CWindowManager>();
auto& _renderer = winman->Renderer;
auto renderer = dynamic_cast<COpenGL430Renderer*>(_renderer.get());
auto it = std::find_if(UsedMaterials.begin(), UsedMaterials.end(), [&materialName](auto mat) -> bool
{
return mat->Name == materialName;
});
if(it != UsedMaterials.end()) { return renderer->GetMaterialIndex(it->get()); }
auto _material = resman->GetOrCreate(renderer->GetMaterialType(), name);
if(!_material)
{
Log::ErrInstance() << "Can't load material " << name << "\n";
}
auto material = std::dynamic_pointer_cast<CGL430Material>(_material);
UsedMaterials.push_back(material);
int ret = renderer->GetMaterialIndex(material.get());
return ret;
}
void CGL430Model::V_Load(const CModelLoadInfo& loadinfo)
{
if(!CEngine::GetInstance()->Components.IsComponentPresent<CWindowManager>()) { return; }
struct PackedVertex
{
glm::vec3 Position;
glm::vec3 Normal;
glm::vec2 TexCoord;
glm::ivec4 BoneIds = { 0, 0, 0, 0 };
glm::vec4 BoneWeights = { 0.0f, 0.0f, 0.0f, 0.0f };
};
std::vector<PackedVertex> vertexBuffer;
std::vector<unsigned int> indexBuffer;
std::map<std::tuple<uint64_t, uint64_t, uint64_t, int>, unsigned int> vertexMap;
unsigned int currentIndex = 0;
for (const auto& tri : loadinfo.Triangles)
{
for (int i = 0; i < 3; i++)
{
uint64_t vIdx = tri.VertexIndex[i];
uint64_t nIdx = tri.NormalIndex[i];
uint64_t tIdx = tri.UvIndex[i];
auto key = std::make_tuple(vIdx, nIdx, tIdx, tri.MaterialIndex);
auto it = vertexMap.find(key);
if (it == vertexMap.end())
{
const auto& v = loadinfo.Vertices[vIdx];
PackedVertex pv;
pv.Position = v.Position;
pv.Normal = (nIdx < loadinfo.Normals.size()) ? loadinfo.Normals[nIdx] : glm::vec3(0);
pv.TexCoord = (tIdx < loadinfo.UvCoords.size()) ? loadinfo.UvCoords[tIdx] : glm::vec2(0);
int count = std::min<int>(v.Bones.size(), 4);
for (int j = 0; j < count; j++)
{
pv.BoneIds[j] = v.Bones[j].BoneIndex;
pv.BoneWeights[j] = v.Bones[j].Weight;
}
vertexBuffer.push_back(pv);
indexBuffer.push_back(currentIndex);
vertexMap[key] = currentIndex++;
}
else
{
indexBuffer.push_back(it->second);
}
}
}
indexCount = indexBuffer.size();
Log::Instance() << "Model indexCount is " << indexCount << "\n";
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
glGenBuffers(1, &vbo);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, vertexBuffer.size() * sizeof(PackedVertex), vertexBuffer.data(), GL_STATIC_DRAW);
glGenBuffers(1, &ebo);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indexBuffer.size() * sizeof(unsigned int), indexBuffer.data(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(PackedVertex), (void*)offsetof(PackedVertex, Position));
glEnableVertexAttribArray(0);
glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(PackedVertex), (void*)offsetof(PackedVertex, Normal));
glEnableVertexAttribArray(1);
glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, sizeof(PackedVertex), (void*)offsetof(PackedVertex, TexCoord));
glEnableVertexAttribArray(2);
glVertexAttribIPointer(3, 4, GL_INT, sizeof(PackedVertex), (void*)offsetof(PackedVertex, BoneIds));
glEnableVertexAttribArray(3);
glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, sizeof(PackedVertex), (void*)offsetof(PackedVertex, BoneWeights));
glEnableVertexAttribArray(4);
glBindVertexArray(0);
std::vector<int> materialPerTriangle;
materialPerTriangle.reserve(loadinfo.Triangles.size());
for (const auto& tri : loadinfo.Triangles)
{
int id = LoadMaterial(loadinfo.MaterialsList.at(tri.MaterialIndex) + ".emtl");
materialPerTriangle.push_back(id);
}
glGenBuffers(1, &materialSSBO);
glBindBuffer(GL_SHADER_STORAGE_BUFFER, materialSSBO);
glBufferData(GL_SHADER_STORAGE_BUFFER, materialPerTriangle.size() * sizeof(int), materialPerTriangle.data(), GL_STATIC_DRAW);
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, materialSSBO); //TODO change binding
glBindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
}
std::shared_ptr<CLoadingContext> CGL430Model::CreatePipelineContext(const std::filesystem::path& path)
{
return std::make_shared<CGL430ModelLoadingContext>(this, path);
}
void CGL430Model::V_Draw()
{
auto resman = CEngine::GetInstance()->Components.GetComponentTyped<CResourcesManager>();
auto winman = CEngine::GetInstance()->Components.GetComponentTyped<CWindowManager>();
auto& _renderer = winman->Renderer;
auto renderer = dynamic_cast<COpenGL430Renderer*>(_renderer.get());
//renderer->S_Default.Bind(); //TODO unnecessary binding
glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 2, materialSSBO);
renderer->BindMaterialsSSBO();
glBindVertexArray(vao);
glDrawElements(GL_TRIANGLES, indexCount, GL_UNSIGNED_INT, 0);
glBindVertexArray(0);
//Log::Instance() << "drawn\n";
}
void CGL430Model::Unload() //TODO RAII
{
if (ebo)
{
glDeleteBuffers(1, &ebo);
ebo = 0;
}
if (vbo)
{
glDeleteBuffers(1, &vbo);
vbo = 0;
}
if (vao)
{
glDeleteVertexArrays(1, &vao);
vao = 0;
}
if (materialSSBO)
{
glDeleteBuffers(1, &materialSSBO);
materialSSBO = 0;
}
if (bonesSSBO)
{
glDeleteBuffers(1, &bonesSSBO);
bonesSSBO = 0;
}
indexCount = 0;
}
CGL430Model::~CGL430Model()
{
Unload();
}
LINK_RESOURCE_TO_CLASS(CGL430Model, gl430model);