#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 context) -> bool { auto mdlContext = std::dynamic_pointer_cast(context); auto thisResource = dynamic_cast(context->CurrentResource); std::map, 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(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(); auto winman = CEngine::GetInstance()->Components.GetComponentTyped(); auto& _renderer = winman->Renderer; auto renderer = dynamic_cast(_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(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 context) -> bool { auto mdlContext = std::dynamic_pointer_cast(context); auto thisResource = dynamic_cast(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(); auto winman = CEngine::GetInstance()->Components.GetComponentTyped(); auto& _renderer = winman->Renderer; auto renderer = dynamic_cast(_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(_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()) { 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 vertexBuffer; std::vector indexBuffer; std::map, 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(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 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 CGL430Model::CreatePipelineContext(const std::filesystem::path& path) { return std::make_shared(this, path); } void CGL430Model::V_Draw() { auto resman = CEngine::GetInstance()->Components.GetComponentTyped(); auto winman = CEngine::GetInstance()->Components.GetComponentTyped(); auto& _renderer = winman->Renderer; auto renderer = dynamic_cast(_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);