#include #include #include #include "ifilesystem.h" #include "log.h" #include "render.h" #include "gpu_buffer.h" #include "shader.h" #include "shadersystem.h" #include "renderdevice.h" #include "modelsystem.h" #include "texturesmanager.h" ModelSystem* g_pModelSystem = nullptr; static InputLayoutDesc_t g_staticVertexLayout[] = { { VERTEXATTR_VEC3, SHADERSEMANTIC_POSITION }, { VERTEXATTR_VEC3, SHADERSEMANTIC_NORMAL }, { VERTEXATTR_VEC2, SHADERSEMANTIC_TEXCOORD }, }; static InputLayoutDesc_t g_skinnedVertexLayout[] = { { VERTEXATTR_VEC3, SHADERSEMANTIC_POSITION }, { VERTEXATTR_VEC3, SHADERSEMANTIC_NORMAL }, { VERTEXATTR_VEC2, SHADERSEMANTIC_TEXCOORD } }; Shader* g_litShader = nullptr; std::string getFileNameWithoutExtension(const std::string& filename) { size_t lastindex = filename.find_last_of("."); if (lastindex != std::string::npos) { return filename.substr(0, lastindex); } return filename; } ModelSystem::ModelSystem() { } ModelSystem::~ModelSystem() { } void ModelSystem::Shutdown() { for (int i = 0; i < m_models.size(); i++) { if (m_models[i].model) { delete m_models[i].model; m_models[i].model = nullptr; } } m_models.clear(); } Model* ModelSystem::LoadModel(const char* filename) { auto it = std::find_if(m_models.begin(), m_models.end(), [=](const ModelEntry& entry) { return strcmp(entry.filename, filename) == 0; }); if (it != m_models.end()) { return it->model; } if (!GetFileSystem()->IsExist(filename)) { Msg("ModelSystem::LoadModel: File '%s' not exist.", filename); return nullptr; } Model* model = new Model(); if (strstr(filename, ".obj")) { model->LoadObj(filename); } else { // Find file extension size_t stringLength = strlen(filename); for (int i = stringLength; i > 0; --i) { if (filename[i] == '.') { stringLength = i; break; } } const char* fileExtension = &filename[stringLength]; Msg("ModelSystem::LoadModel: Unknowed file format '%s'", filename, fileExtension); return nullptr; } ModelEntry entry = {}; strcpy(entry.filename, filename); entry.model = model; m_models.push_back(entry); Msg("Loaded Model '%s'", filename); return model; } Model::Model() { m_data.vb = nullptr; m_data.ib = nullptr; m_AlbedoTexture = nullptr; //m_boundingBox.min = glm::vec3(0.0f); //m_boundingBox.max = glm::vec3(0.0f); } Model::~Model() { m_AlbedoTexture = nullptr; if (m_data.vb) { delete m_data.vb; m_data.vb = nullptr; } } void Model::LoadObj(const char* filename) { Msg("Loading OBJ file %s...", filename); std::vector vertexIndices, uvIndices, normalIndices; std::vector temp_vertices; std::vector temp_uvs; std::vector temp_normals; std::vector out_vertices; std::vector out_uvs; std::vector out_normals; FILE* file = fopen(filename, "r"); if (file == NULL) { Msg("Model::LoadObj: Impossible to open the file !"); return; } while (1) { char lineHeader[128]; // read the first word of the line int res = fscanf(file, "%s", lineHeader); if (res == EOF) break; // EOF = End Of File. Quit the loop. // else : parse lineHeader if (strcmp(lineHeader, "v") == 0) { glm::vec3 vertex; fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z); temp_vertices.push_back(vertex); } else if (strcmp(lineHeader, "vt") == 0) { glm::vec2 uv; fscanf(file, "%f %f\n", &uv.x, &uv.y); uv.y = -uv.y; // Invert V coordinate since we will only use DDS texture, which are inverted. Remove if you want to use TGA or BMP loaders. temp_uvs.push_back(uv); } else if (strcmp(lineHeader, "vn") == 0) { glm::vec3 normal; fscanf(file, "%f %f %f\n", &normal.x, &normal.y, &normal.z); temp_normals.push_back(normal); } else if (strcmp(lineHeader, "f") == 0) { std::string vertex1, vertex2, vertex3; unsigned int vertexIndex[3], uvIndex[3], normalIndex[3]; int matches = fscanf(file, "%d/%d/%d %d/%d/%d %d/%d/%d\n", &vertexIndex[0], &uvIndex[0], &normalIndex[0], &vertexIndex[1], &uvIndex[1], &normalIndex[1], &vertexIndex[2], &uvIndex[2], &normalIndex[2]); if (matches != 9) { Msg("Model::LoadObj: File can't be read by our simple parser :-( Try exporting with other options"); fclose(file); return; } vertexIndices.push_back(vertexIndex[0]); vertexIndices.push_back(vertexIndex[1]); vertexIndices.push_back(vertexIndex[2]); uvIndices.push_back(uvIndex[0]); uvIndices.push_back(uvIndex[1]); uvIndices.push_back(uvIndex[2]); normalIndices.push_back(normalIndex[0]); normalIndices.push_back(normalIndex[1]); normalIndices.push_back(normalIndex[2]); } else { // Probably a comment, eat up the rest of the line char stupidBuffer[1000]; fgets(stupidBuffer, 1000, file); } } // For each vertex of each triangle for (unsigned int i = 0; i < vertexIndices.size(); i++) { // Get the indices of its attributes unsigned int vertexIndex = vertexIndices[i]; unsigned int uvIndex = uvIndices[i]; unsigned int normalIndex = normalIndices[i]; // Get the attributes thanks to the index glm::vec3 vertex = temp_vertices[vertexIndex - 1]; glm::vec2 uv = temp_uvs[uvIndex - 1]; glm::vec3 normal = temp_normals[normalIndex - 1]; // Put the attributes in buffers out_vertices.push_back(vertex); out_uvs.push_back(uv); out_normals.push_back(normal); } fclose(file); m_boundingBox.m_min = glm::vec3(FLT_MAX); m_boundingBox.m_max = glm::vec3(FLT_MIN); // Combine in to the one array std::vector vertices; for (unsigned int i = 0; i < vertexIndices.size(); i++) { // Get the indices of its attributes unsigned int vertexIndex = vertexIndices[i]; unsigned int uvIndex = uvIndices[i]; unsigned int normalIndex = normalIndices[i]; // Get the attributes thanks to the index glm::vec3 vertex = temp_vertices[vertexIndex - 1]; glm::vec2 uv = temp_uvs[uvIndex - 1]; glm::vec3 normal = temp_normals[normalIndex - 1]; StaticMeshVertex vtx = {}; vtx.position = vertex; vtx.normal = normal; vtx.texcoord = uv; vertices.push_back(vtx); m_boundingBox.m_min = glm::min(m_boundingBox.m_min, vertex); m_boundingBox.m_max = glm::max(m_boundingBox.m_max, vertex); } m_Vertices = vertices; m_data.vb = g_pRenderDevice->CreateVertexBuffer(vertices.data(), (int)sizeof(StaticMeshVertex) * (int)vertices.size()); m_data.vbcount = vertices.size(); std::string mtlfilename = getFileNameWithoutExtension(filename); mtlfilename += ".mtl"; LoadMtl(mtlfilename.c_str()); } void Model::LoadMtl(const char* filename) { Msg("Loading MTL file %s...", filename); FILE* file = fopen(filename, "r"); if (file == NULL) { Msg("Model::LoadObj: Impossible to open the file !"); return; } while (1) { char lineHeader[128]; // read the first word of the line int res = fscanf(file, "%s", lineHeader); if (res == EOF) break; // EOF = End Of File. Quit the loop. if (strcmp(lineHeader, "map_Kd") == 0) { char stupidBuffer[1000]; fgets(stupidBuffer, 1000, file); const char* textureFilename = stupidBuffer + 1; m_AlbedoTexture = g_pTexturesManager->LoadTexture2D(textureFilename, true); } //if (strcmp(lineHeader, "v") == 0) { // glm::vec3 vertex; // fscanf(file, "%f %f %f\n", &vertex.x, &vertex.y, &vertex.z); // temp_vertices.push_back(vertex); //} //else { // // Probably a comment, eat up the rest of the line // char stupidBuffer[1000]; // fgets(stupidBuffer, 1000, file); //} } fclose(file); } void Model::Draw(const glm::mat4& model, bool isTransparent /*= false*/) { if (!g_litShader) { g_litShader = g_pShaderSystem->CreateShader("lit_generic", "data/shaders/lit_generic.vs", "data/shaders/lit_generic.ps", g_staticVertexLayout, sizeof(g_staticVertexLayout) / sizeof(g_staticVertexLayout[0])); } glFrontFace(GL_CCW); glDepthFunc(GL_LESS); g_pRenderDevice->SetCullFace(true); g_pRenderDevice->SetDepthTest(true); g_pRenderDevice->SetDepthWrite(true); if (isTransparent) { // Enable blending g_pRenderDevice->SetBlending(true); g_pRenderDevice->SetBlendingFunction(BF_SRC_ALPHA, BF_ONE_MINUS_SRC_ALPHA); glm::vec4 color = glm::vec4(1.f, 1.f, 1.f, .5f); g_pShaderSystem->SetUniformFloat4(g_litShader, UNIFORM_CUSTOM_COLOR, glm::value_ptr(color)); } else { g_pRenderDevice->SetBlending(false); //glm::vec4 color = glm::vec4(1.f, 1.f, 1.f, 1.f); //g_pShaderSystem->SetUniformFloat4(g_litShader, UNIFORM_CUSTOM_COLOR, glm::value_ptr(color)); } g_pRenderDevice->SetVerticesBuffer(m_data.vb); g_pShaderSystem->SetShader(g_litShader); g_pShaderSystem->SetUniformMatrix(g_litShader, UNIFORM_MODEL_MATRIX, &model[0]); //static float test = 0.0f; //test += g_systemTimer->GetDelta() * 6.0f; //glm::mat4 model = glm::mat4(1.0f); //int32_t x = 0, y = 0; //g_inputSystem->GetMousePosition(&x, &y); // //glm::mat4 model = glm::mat4(1.0f); //model = glm::rotate(model, test, glm::vec3(0.0f, 1.0f, 0.0f)); // //float realY = (float)g_renderView.height - (float)y - 1; // //glm::vec4 viewport = glm::vec4(0.0f, 0.0f, (float)g_renderView.width, (float)g_renderView.height); //glm::vec3 pos = glm::unProject( // glm::vec3((float)x, realY, 0.0f), // model, // g_renderView.proj, // viewport); // //pos *= 50.0f; // //model = glm::translate(model, pos); glm::mat4 mvp = glm::identity(); mvp = g_pRender->GetProjectionMatrix() * g_pRender->GetViewMatrix() * model; g_pShaderSystem->SetUniformMatrix(g_litShader, UNIFORM_MVP_MATRIX, &mvp[0]); g_pTexturesManager->SetTexture(0, m_AlbedoTexture); g_pShaderSystem->SetUniformSampler(g_litShader, SAMPLER_ALBEDO, 0); g_pRenderDevice->DrawArrays(PT_TRIANGLES, 0, m_data.vbcount); #if 0 glm::mat4 mvp = glm::identity(); mvp = g_renderView.proj * g_renderView.view * model; g_shaderSystem->SetUniformMatrix(g_litShader, UNIFORM_MVP_MATRIX, &mvp[0]); g_pTexturesManager->SetTexture(0, m_AlbedoTexture); g_shaderSystem->SetUniformSampler(g_litShader, SAMPLER_ALBEDO, 0); g_renderDevice->DrawArrays(PT_TRIANGLES, 0, m_data.vbcount); BoundingBox bbox = m_boundingBox; TransformBoundingBox(bbox, model); g_pDebugRender->DrawBoundingBox(bbox, glm::vec3(1.0f)); #endif } void ReleaseModelData(ModelData_t& data) { if (data.ib) { delete data.ib; data.ib = nullptr; } if (data.vb) { delete data.vb; data.vb = nullptr; } }