#include "engine/core.h" #include "engine/log.h" #include "engine/ifilesystem.h" #include "engine/camera.h" #include "render/texturesmanager.h" #include "render/modelsystem.h" #include "render/scenemanager.h" #include "render/renderdevice.h" #include "render/gl_shared.h" #include "render/texture2d.h" #include "render/shader.h" #include "render/shadersystem.h" #include "render/render.h" #include "render/debugrender.h" #include "render/gpu_buffer.h" #include "engine/camera.h" #include "engine/physics/physicsworld.h" #include extern int g_NumModels; static bool g_debugRenderScene = false; glm::vec3 g_ambientColor = glm::vec3(0.0f); static std::string getFileExtension(const std::string& filename) { size_t whereIsDot = filename.find_last_of('.'); if (whereIsDot != std::string::npos) { return filename.substr(whereIsDot); } return ""; } static 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; } static std::string getFilenameWithoutPathAndExtension(const std::string& filename) { size_t whereIsDot = filename.find_last_of('.'); size_t whereIsSlash = filename.find_last_of('/'); if (whereIsSlash == std::string::npos) { whereIsSlash = filename.find_last_of('\\'); } if (whereIsDot == std::string::npos && whereIsSlash == std::string::npos) { return filename; } std::string string = filename.substr(whereIsSlash + 1); whereIsDot = string.find_last_of('.'); string = string.substr(0, whereIsDot); return string; } template void TReadFile(FileHandle_t handle, T* value) { GetFileSystem()->ReadFile(handle, (void*)value, sizeof(T)); } template void TWriteFile(FileHandle_t handle, const T* value) { GetFileSystem()->WriteFile(handle, (void*)value, sizeof(T)); } static void WriteString(FileHandle_t handle, const std::string& string) { uint16_t size = string.length(); TWriteFile(handle, &size); GetFileSystem()->WriteFile(handle, (void*)string.c_str(), size); } static void ReadString(FileHandle_t handle, std::string& string) { uint16_t size; TReadFile(handle, &size); //string.resize(size + 1); string.resize(size); GetFileSystem()->ReadFile(handle, (void*)string.c_str(), size); //string[size] = '\0'; } //#ifdef NDEBUG //#pragma comment(lib, "assimp-vc141-mt.lib") //#else //#pragma comment(lib, "assimp-vc141-mtd.lib") //#endif // NDEBUG // //inline static glm::mat4 Assimp2Glm(const aiMatrix4x4& from) //{ // return glm::mat4( // (double)from.a1, (double)from.b1, (double)from.c1, (double)from.d1, // (double)from.a2, (double)from.b2, (double)from.c2, (double)from.d2, // (double)from.a3, (double)from.b3, (double)from.c3, (double)from.d3, // (double)from.a4, (double)from.b4, (double)from.c4, (double)from.d4 // ); //} // //SceneStaticMesh* createSceneStaticMesh(const aiScene* scene, aiMesh* mesh) //{ // assert(scene); // assert(mesh); // //assert(mesh->mPrimitiveTypes == aiPrimitiveType_TRIANGLE); // // std::vector vertices; // std::vector indices; // // // reserve 1024 vertices and indices // vertices.reserve(1024); // indices.reserve(1024); // // for (uint32_t i = 0; i < mesh->mNumVertices; i++) { // SceneStaticMeshVertex vertex; // // // position // aiVector3D position = mesh->mVertices[i]; // vertex.m_position.x = position.x; // vertex.m_position.y = position.y; // vertex.m_position.z = position.z; // // // normal // aiVector3D normal = mesh->mNormals[i]; // vertex.m_normal.x = normal.x; // vertex.m_normal.y = normal.y; // vertex.m_normal.z = normal.z; // // static bool inverseTexCoords = true; // // if (inverseTexCoords) { // // texture coord 0 ( DIFFUSE ) // if (mesh->mTextureCoords[0]) { // vertex.m_texcoord1.x = mesh->mTextureCoords[0][i].x; // vertex.m_texcoord1.y = mesh->mTextureCoords[0][i].y; // } // else { // vertex.m_texcoord1 = glm::vec2(0.0f, 0.0f); // } // // // texture coord 1 ( LIGHTMAP ) // if (mesh->mTextureCoords[1]) { // vertex.m_texcoord0.x = mesh->mTextureCoords[1][i].x; // vertex.m_texcoord0.y = mesh->mTextureCoords[1][i].y; // } // else { // vertex.m_texcoord0 = glm::vec2(0.0f, 0.0f); // } // } // else { // // texture coord 0 ( DIFFUSE ) // if (mesh->mTextureCoords[0]) { // vertex.m_texcoord0.x = mesh->mTextureCoords[0][i].x; // vertex.m_texcoord0.y = mesh->mTextureCoords[0][i].y; // } // else { // vertex.m_texcoord0 = glm::vec2(0.0f, 0.0f); // } // // // texture coord 0 ( LIGHTMAP ) // if (mesh->mTextureCoords[1]) { // vertex.m_texcoord1.x = mesh->mTextureCoords[1][i].x; // vertex.m_texcoord1.y = mesh->mTextureCoords[1][i].y; // } // else { // vertex.m_texcoord1 = glm::vec2(0.0f, 0.0f); // } // } // // vertices.push_back(vertex); // } // // 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]); // } // // aiMaterial* assImpMaterial = scene->mMaterials[mesh->mMaterialIndex]; // aiString diffusePath; // assImpMaterial->GetTexture(aiTextureType_DIFFUSE, 0, &diffusePath); // // if (strlen(diffusePath.C_Str()) == 0) { // Logger::msg("Scene mesh '%s' has assImpMaterial, but diffuse texture is not specified.", mesh->mName.C_Str()); // } // // Material* material = g_materialsManager->createMaterial("default_lightmap", diffusePath.C_Str()); // // glm::mat4 transform = glm::identity(); // // return new SceneStaticMesh(vertices, indices, material, transform); //} SceneManager* g_sceneManager; SceneManager::SceneManager() { m_sceneLoaded = false; DLightManager::GetInstance()->Clear(); } SceneManager::~SceneManager() { m_sceneLoaded = false; } void SceneManager::loadScene(const char* filename) { unloadIfScenePresent(); // Reset ambient color setAmbientColor(glm::vec3(0.0f)); char filenameBuffer[kMaxPathLength]; snprintf(filenameBuffer, kMaxPathLength, "data/levels/%s/%s.xml", filename, filename); FileHandle_t file = GetFileSystem()->OpenFile(filenameBuffer, "rb"); SDL_assert_always(file != kInvalidFileHandleValue); size_t length = GetFileSystem()->GetFileLength(file); char* filedata = new char[length + 1]; GetFileSystem()->ReadFile(file, filedata, length); filedata[length] = '\0'; GetFileSystem()->CloseFile(file); pugi::xml_document doc; pugi::xml_parse_result result = doc.load_buffer(filedata, length); delete[] filedata; if (!result) { Core::Error("SceneManager::LoadScene: Error while reading level description file '%s'\nError: %s:%i", filenameBuffer, result.description(), result.offset); } pugi::xml_node root = doc.document_element(); const char* scenefilename = root.child("LevelDescription").child("SceneFile").attribute("filename").value(); pugi::xml_node ambientnode = root.child("LevelDescription").child("AmbientColor"); if (ambientnode) { glm::vec3 color = glm::vec3(0.0f); color.r = ambientnode.attribute("r").as_float(); color.g = ambientnode.attribute("g").as_float(); color.b = ambientnode.attribute("b").as_float(); setAmbientColor(color); } m_sceneName = getFileNameWithoutExtension(scenefilename); sprintf(filenameBuffer, "data/levels/%s/%s", filename, scenefilename); if (!GetFileSystem()->IsExist(filenameBuffer)) { Core::Error("SceneManager::LoadScene: scene file '%s' doesnt exist", scenefilename); } m_sceneFilename = filenameBuffer; if (getFileExtension(m_sceneFilename) == ".scene") { LoadSceneXML(m_sceneFilename.c_str()); } Logger::Msg("loaded %u meshes", m_sceneMeshes.size()); m_sceneLoaded = true; } void SceneManager::LoadSceneXML(const char* filename) { FileHandle_t file = GetFileSystem()->OpenFile(filename, "rb"); SDL_assert_always(file != kInvalidFileHandleValue); size_t length = GetFileSystem()->GetFileLength(file); char* filedata = new char[length + 1]; GetFileSystem()->ReadFile(file, filedata, length); filedata[length] = '\0'; GetFileSystem()->CloseFile(file); pugi::xml_document doc; pugi::xml_parse_result result = doc.load_buffer(filedata, length); delete[] filedata; if (!result) { Core::Error("SceneManager::LoadSceneXML: Error while reading level description file '%s'\nError: %s:%i", filename, result.description(), result.offset); } for (pugi::xml_node staticMesh : doc.child("Scene").children("StaticMesh")) { const char* meshfilename = staticMesh.attribute("filename").as_string(); if (meshfilename) loadStaticMesh(meshfilename); } } //void SceneManager::loadScene(const char* sceneName) //{ // if (sceneName) // m_sceneName = getFileNameWithoutExtension(sceneName); // // if (!m_sceneName.size()) // Core::Error("Scene::loadScene: Scene file is empty, check the 'SceneFile' attribute in level description."); // // m_sceneFilename = "data/levels/" + std::string(sceneName) + "/" + std::string(sceneName) + ".scene.xml"; // // if (!GetFileSystem()->IsExist(m_sceneFilename.c_str())) // Core::Error("Scene::loadScene: scene file '%s' doesnt exist", m_sceneFilename.c_str()); // // Logger::Msg("loading scene %s", m_sceneFilename.c_str()); // // loadStaticMeshes(); // // // Load lightmap //// m_lightmap = g_texturesManager->createTexture2D("**"); // // //if (!scene->HasTextures()) { // // Core::error("Scene::loadScene: scene '%s' doesnt have textures. Please check assImpMaterial parameters!", scenefilename); // //} // // m_sceneLoaded = true; //} void SceneManager::loadSkybox(const char* skybox) { if (skybox && *skybox && strcmp(skybox, "none")) m_pSkybox = g_modelSystem->LoadModel(skybox); } void SceneManager::loadStaticMeshes() { //File* file = g_fileManager->openFile(m_sceneFilename.c_str(), FileAccess::Read); //file->seek(SeekDir::End, 0); //size_t length = file->tell(); //file->seek(SeekDir::Begin, 0); //char* filedata = new char[length + 1]; //file->read(filedata, length); //filedata[length] = '\0'; //g_fileManager->closeFile(file); //Assimp::Importer importer; //const aiScene* scene = importer.ReadFileFromMemory(filedata, length, // aiProcessPreset_TargetRealtime_Quality | // some optimizations and safety checks // aiProcess_OptimizeMeshes | // minimize number of meshes // aiProcess_PreTransformVertices | // apply node matrices // // aiProcess_Triangulate | // aiProcess_SplitLargeMeshes | // aiProcess_TransformUVCoords /*|*/ // apply UV transformations ///*aiProcess_FlipUVs*/); //delete[] filedata; //if (!scene || scene->mFlags & AI_SCENE_FLAGS_INCOMPLETE || !scene->mRootNode) { // Core::error("Scene::loadScene: failed to load scene '%s'.\n%s", m_sceneName, importer.GetErrorString()); //} //if (scene && !scene->HasMaterials()) { // Core::error("Scene::loadScene: scene '%s' doesnt have materials. Please check export parameters!", m_sceneName); //} //Logger::msg("loaded %u meshes", scene->mNumMeshes); //for (unsigned int i = 0; i < scene->mNumMeshes; i++) { // m_sceneMeshes.push_back(createSceneStaticMesh(scene, scene->mMeshes[i])); //} } void SceneManager::loadStaticMesh(const char* filename) { char filenamebuf[kMaxPathLength]; snprintf(filenamebuf, kMaxPathLength, "data/levels/%s/%s", m_sceneName.c_str(), filename); if (GetFileSystem()->IsExist(filenamebuf)) { SceneStaticMesh* staticMesh = new SceneStaticMesh(); const char* ext = strrchr(filenamebuf, '.'); if (ext && strcmp(ext, ".obj") == 0) staticMesh->LoadObj(filenamebuf); else if (ext && strcmp(ext, ".wmb") == 0) staticMesh->LoadBin(filenamebuf); m_sceneMeshes.push_back(staticMesh); } } bool SceneManager::isSceneLoaded() { return m_sceneLoaded; } void SceneManager::renderScene(const glm::mat4& cameraTranslation) { if (!isSceneLoaded()) return; Camera* camera = g_cameraManager.GetActiveCamera(); if (!camera) return; Frustum& frustum = camera->GetFrustum(); for (std::list::iterator it = m_sceneMeshes.begin(); it != m_sceneMeshes.end(); ++it) { if (*it) { // cull mesh if (frustum.CullBoundingBox((*it)->GetBoundingBox())) continue; (*it)->RenderObjects(); if (g_debugRenderScene) g_debugRender->DrawBoundingBox((*it)->GetBoundingBox(), glm::vec3(1.0f)); } } // draw skybox //if (m_pSkybox) // m_pSkybox->renderObjects(cameraTranslation); //glActiveTexture(GL_TEXTURE1); //m_lightmap->bind(); //if (g_lmTexFilter.getValueB()) { // //m_lightmap->setMin //} //m_lightmap->setWrapS(TextureWrap::ClampToEdge); //m_lightmap->setWrapT(TextureWrap::ClampToEdge); //for (std::list::iterator it = m_sceneMeshes.begin(); it != m_sceneMeshes.end(); ++it) { // if (*it) { // (*it)->renderObjects(); // } //} //glActiveTexture(GL_TEXTURE1); //glBindTexture(GL_TEXTURE_2D, 0); } void SceneManager::unloadIfScenePresent() { if (!isSceneLoaded()) return; unloadScene(); } void SceneManager::replaceMaterial(const char* oldMaterialname, const char* newMaterialName) { } void SceneManager::replaceAllMaterialsWithBruteForce(const char* materialname) { /*for (std::list::iterator it = m_sceneMeshes.begin(); it != m_sceneMeshes.end(); ++it) { SceneStaticMesh* mesh = (*it); assert(mesh); assert(mesh->m_material && "scene mesh has nullptr assImpMaterial"); mesh->m_material = g_materialsManager->createMaterial(materialname, mesh->m_material->getTemplateMaterial()->m_diffuseTextures[0].c_str()); }*/ } void SceneManager::unloadScene() { Logger::Msg("deleting scene ..."); if (m_sceneMeshes.empty()) return; for (std::list::iterator it = m_sceneMeshes.begin(); it != m_sceneMeshes.end(); ++it) { if (*it) { delete* it; *it = nullptr; } } m_sceneMeshes.clear(); DLightManager::GetInstance()->Clear(); m_sceneLoaded = false; } const char* SceneManager::getSceneName() { return m_sceneName.c_str(); } void SceneManager::toggleDebugRender() { g_debugRenderScene = !g_debugRenderScene; } void SceneManager::setAmbientColor(const glm::vec3& color) { g_ambientColor = color; } const glm::vec3& SceneManager::getAmbientColor() { return g_ambientColor; } // SceneStaticMesh SceneStaticMesh::SceneStaticMesh() : m_vb(nullptr), m_ib(nullptr), m_albedoTexture(nullptr), m_vbcount(0), m_ibcount(0) { } SceneStaticMesh::~SceneStaticMesh() { if (m_ib) { delete m_ib; m_ib = nullptr; } if (m_vb) { delete m_vb; m_vb = nullptr; } } void SceneStaticMesh::LoadObj(const char* 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("SceneStaticMesh::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("SceneStaticMesh::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); if (i == 0) { m_boundingBox.m_min = vertex; m_boundingBox.m_max = vertex; } else { m_boundingBox.m_min = glm::min(m_boundingBox.m_min, vertex); m_boundingBox.m_max = glm::max(m_boundingBox.m_max, vertex); } } // Fill face indices std::vector indices; for (uint32_t i = 0; i < vertices.size(); i++) { indices.push_back(i); } std::string binaryCache = getFileNameWithoutExtension(filename); binaryCache += ".wmb"; if (!GetFileSystem()->IsExist(binaryCache.c_str())) { FileHandle_t handle = GetFileSystem()->OpenFile(binaryCache.c_str(), "wb"); // write header WriteString(handle, "StaticSceneMeshFile"); WriteString(handle, "0.1"); // write material file std::string mtlfilename = getFileNameWithoutExtension(filename); mtlfilename += ".mtl"; WriteString(handle, mtlfilename); // write vertices uint32_t vbcount = vertices.size(); TWriteFile(handle, &vbcount); GetFileSystem()->WriteFile(handle, vertices.data(), vertices.size() * sizeof(StaticMeshVertex)); // write indices uint32_t ibcount = indices.size(); TWriteFile(handle, &ibcount); GetFileSystem()->WriteFile(handle, indices.data(), indices.size() * sizeof(uint32_t)); GetFileSystem()->CloseFile(handle); } // m_Vertices = vertices; m_vb = g_renderDevice->CreateVertexBuffer(vertices.data(), (int)sizeof(StaticMeshVertex) * (int)vertices.size()); m_vbcount = vertices.size(); std::string mtlfilename = getFileNameWithoutExtension(filename); mtlfilename += ".mtl"; LoadMtl(mtlfilename.c_str()); if (g_PhysicsWorld) { g_PhysicsWorld->AddCollisionModel(vertices.data(), vertices.size(), indices.data(), indices.size()); } } void SceneStaticMesh::LoadBin(const char* filename) { FileHandle_t handle = GetFileSystem()->OpenFile(filename, "rb"); std::string header; ReadString(handle, header); if (header != "StaticSceneMeshFile") Core::Error(" SceneStaticMesh::LoadBin: Error during scene loading!\n%s is not a proper scene mesh.\n%s (should be %s)", filename, header.c_str(), "StaticSceneMeshFile"); std::string version; ReadString(handle, version); if (version != "0.1") Core::Error(" SceneStaticMesh::LoadBin: Error during scene loading!\n%s is outdated.\nversion %s (current is %s)", filename, version.c_str(), "0.1"); std::string mtlfilename; ReadString(handle, mtlfilename); LoadMtl(mtlfilename.c_str()); // read vertices uint32_t vbcount; TReadFile(handle, &vbcount); std::vector vertices; vertices.resize(vbcount); GetFileSystem()->ReadFile(handle, vertices.data(), vertices.size() * sizeof(StaticMeshVertex)); // read indices uint32_t ibcount; TReadFile(handle, &ibcount); std::vector vertexIndices; vertexIndices.resize(ibcount); GetFileSystem()->ReadFile(handle, vertexIndices.data(), vertexIndices.size() * sizeof(unsigned int)); // bbox calculation for (unsigned int i = 0; i < vertices.size(); i++) { if (i == 0) { m_boundingBox.m_min = vertices[i].position; m_boundingBox.m_max = vertices[i].position; } else { m_boundingBox.m_min = glm::min(m_boundingBox.m_min, vertices[i].position); m_boundingBox.m_max = glm::max(m_boundingBox.m_max, vertices[i].position); } } // create vb m_vb = g_renderDevice->CreateVertexBuffer(vertices.data(), (int)sizeof(StaticMeshVertex) * (int)vertices.size()); m_vbcount = vertices.size(); // create ib ?? if (g_PhysicsWorld) { g_PhysicsWorld->AddCollisionModel(vertices.data(), vertices.size(), vertexIndices.data(), vertexIndices.size()); } GetFileSystem()->CloseFile(handle); } void SceneStaticMesh::LoadMtl(const char* filename) { FILE* file = fopen(filename, "r"); if (file == NULL) { Msg("SceneStaticMesh::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); char* textureFilename = stupidBuffer + 1; int str_len = strlen(textureFilename); if (textureFilename[str_len - 1] == '\n') textureFilename[str_len - 1] = '\0'; m_albedoTexture = g_texturesManager->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); } static glm::mat4 s_identity = glm::mat4(1.0f); void R_SceneStaticMesh_BindShader(const glm::mat4& worldMatrix, Texture2D* albedoTexture, DLight* light) { extern Shader* g_unlitShader; extern Shader* g_litShader; SDL_assert(g_unlitShader); SDL_assert(g_litShader); Shader* shader = light ? g_litShader : g_unlitShader; g_shaderSystem->SetShader(shader); g_shaderSystem->SetUniformMatrix(shader, UNIFORM_MODEL_MATRIX, &worldMatrix[0]); glm::mat4 mvp = g_render->GetProjectionMatrix() * g_render->GetViewMatrix() * worldMatrix; g_shaderSystem->SetUniformMatrix(shader, UNIFORM_MVP_MATRIX, &mvp[0]); Camera* camera = g_cameraManager.GetActiveCamera(); if (camera && shader->HasUniform(UNIFORM_CAMERA_POS)) { glm::vec4 campos = glm::vec4(camera->GetPosition(), 1.0f); g_shaderSystem->SetUniformFloat4(shader, UNIFORM_CAMERA_POS, &campos); } if (shader->HasUniform(UNIFORM_SUN_DIRECTION)) { glm::vec4 lightPos = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f); if (light) lightPos = glm::vec4(light->position, light->radius); g_shaderSystem->SetUniformFloat4(shader, UNIFORM_SUN_DIRECTION, &lightPos); } if (shader->HasUniform(UNIFORM_SUN_COLOR)) { glm::vec4 lightColor = glm::vec4(0.0f, 0.0f, 0.0f, 0.0f); if (light) lightColor = glm::vec4(light->color, 1.0f); g_shaderSystem->SetUniformFloat4(shader, UNIFORM_SUN_COLOR, &lightColor); } if (shader->HasUniform(UNIFORM_SUN_AMBIENT)) { glm::vec4 lightColor = glm::vec4(g_sceneManager->getAmbientColor(), 1.0f); g_shaderSystem->SetUniformFloat4(shader, UNIFORM_SUN_AMBIENT, &lightColor); } g_texturesManager->SetTexture(0, albedoTexture); g_shaderSystem->SetUniformSampler(shader, SAMPLER_ALBEDO, 0); } void SceneStaticMesh::RenderObjects() { glFrontFace(GL_CCW); glDepthFunc(GL_LESS); g_renderDevice->SetCullFace(true); g_renderDevice->SetDepthTest(true); g_renderDevice->SetDepthWrite(true); g_renderDevice->SetBlending(false); int numlights = DLightManager::GetInstance()->GetNumLights(); if (!numlights) { g_renderDevice->SetVerticesBuffer(m_vb); R_SceneStaticMesh_BindShader(s_identity, m_albedoTexture, nullptr); g_renderDevice->DrawArrays(PT_TRIANGLES, 0, m_vbcount); g_NumModels++; } else { // first pass g_renderDevice->SetVerticesBuffer(m_vb); R_SceneStaticMesh_BindShader(s_identity, m_albedoTexture, DLightManager::GetInstance()->GetDLight(0)); g_renderDevice->DrawArrays(PT_TRIANGLES, 0, m_vbcount); g_NumModels++; // overdraw YAAAY if (numlights > 1) { // fragment passed, can turn off depth write g_renderDevice->SetDepthWrite(false); // testing only written fragments glDepthFunc(GL_EQUAL); // additive blending g_renderDevice->SetBlending(true); g_renderDevice->SetBlendingFunction(BF_ONE, BF_ONE); glBlendFunc(GL_ONE, GL_ONE); for (int i = 1; i < numlights; i++) { g_renderDevice->SetVerticesBuffer(m_vb); R_SceneStaticMesh_BindShader(s_identity, m_albedoTexture, DLightManager::GetInstance()->GetDLight(i)); g_renderDevice->DrawArrays(PT_TRIANGLES, 0, m_vbcount); g_NumModels++; // overdraw YAAAY } g_renderDevice->SetBlending(false); glDepthFunc(GL_LESS); } } } DLightManager* DLightManager::GetInstance() { static DLightManager instance; return &instance; } DLight* DLightManager::AllocLight() { return &m_dlights[m_numdlights++]; } void DLightManager::Clear() { memset(m_dlights, 0, sizeof(m_dlights)); m_numdlights = 0; } DLight* DLightManager::GetDLight(int index) { if (index >= m_numdlights) Core::Error("DLightManager::GetDLight: index is out of range"); return &m_dlights[index]; } int DLightManager::GetNumLights() { return m_numdlights; } //void R_SceneStaticMesh_BindShader(const glm::mat4& worldMatrix, Texture2D* albedoTexture) //{ // extern Shader* g_unlitShader; // extern Shader* g_litShader; // // SDL_assert(g_unlitShader); // SDL_assert(g_litShader); // // Shader* shader = g_litShader; // // g_shaderSystem->SetShader(shader); // // g_shaderSystem->SetUniformMatrix(shader, UNIFORM_MODEL_MATRIX, &worldMatrix[0]); // // glm::mat4 mvp = g_render->GetProjectionMatrix() * g_render->GetViewMatrix() * worldMatrix; // g_shaderSystem->SetUniformMatrix(shader, UNIFORM_MVP_MATRIX, &mvp[0]); // // Camera* camera = g_cameraManager.GetActiveCamera(); // if (camera && shader->HasUniform(UNIFORM_CAMERA_POS)) // { // glm::vec4 campos = glm::vec4(camera->GetPosition(), 1.0f); // g_shaderSystem->SetUniformFloat4(shader, UNIFORM_CAMERA_POS, &campos); // } // // if (shader->HasUniform(UNIFORM_SUN_DIRECTION)) // { // glm::vec4 lightPos = glm::vec4(1.0f, 1.0f, 1.0f, 0.0f); // // // g_debugRender->DrawAxis(glm::vec3(lightPos)); // // Camera* camera = g_cameraManager.GetActiveCamera(); // if (camera) // lightPos = glm::vec4(camera->GetPosition(), 1.0f); // // g_shaderSystem->SetUniformFloat4(shader, UNIFORM_SUN_DIRECTION, &lightPos); // } // // if (shader->HasUniform(UNIFORM_SUN_AMBIENT)) // { // glm::vec4 lightColor = glm::vec4(0.1f); // g_shaderSystem->SetUniformFloat4(shader, UNIFORM_SUN_AMBIENT, &lightColor); // } // // g_texturesManager->SetTexture(0, albedoTexture); // g_shaderSystem->SetUniformSampler(shader, SAMPLER_ALBEDO, 0); //} // //void SceneStaticMesh::RenderObjects() //{ // glFrontFace(GL_CCW); // glDepthFunc(GL_LESS); // // g_renderDevice->SetCullFace(true); // g_renderDevice->SetDepthTest(true); // g_renderDevice->SetDepthWrite(true); // // g_renderDevice->SetBlending(false); // // g_renderDevice->SetVerticesBuffer(m_vb); // // R_SceneStaticMesh_BindShader(s_identity, m_albedoTexture); // // g_renderDevice->DrawArrays(PT_TRIANGLES, 0, m_vbcount); // // g_NumModels++; //}