// // Created by karl on 07.01.20. // #ifndef ECSGAME_RENDERSYSTEM_H #define ECSGAME_RENDERSYSTEM_H #include "../ECS.h" #include "../Components/Transform.h" #include "../Components/Mesh.h" #include "../Components/Camera.h" #include "../../Rendering/Shader.h" #include "../Components/ObjMesh.h" #include "../Components/Texture.h" #include "../Components/LODObjMesh.h" using namespace ECS; class RenderSystem : public EntitySystem { public: void render(World *pWorld, Shader shader) { pWorld->each([&](Entity *ent, ComponentHandle camera, ComponentHandle cameraTransform) { glClearColor(0.6f, 0.9f, 0.9f, 1.0f); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); shader.use(); shader.setMat4("projection", camera->projection); shader.setMat4("view", glm::inverse(cameraTransform->matrix)); std::vector renderObjects; std::vector transparentRenderObjects; pWorld->each([&](Entity *ent, ComponentHandle mesh, ComponentHandle transform) { renderObjects.emplace_back(RenderObject(transform->matrix, 0, mesh.get(), 0)); }); glm::vec3 cameraPos = cameraTransform->getPosition(); /*// TODO: Is it possible to do get ObjMeshes in the Mesh loop above implicitly via polymorphism? * // TODO: Commented out because of double rendering - we only want to get objects that explicitly DON'T have a texture here! pWorld->each([&](Entity *ent, ComponentHandle mesh, ComponentHandle transform) { // Add the object to the renderObjects to draw if the distance is within the min and max distance of the mesh float distance = glm::distance(cameraPos, transform->getPosition()); if (distance > mesh->minDistance && distance < mesh->maxDistance) { renderObjects.emplace_back(RenderObject(transform->matrix, 0, mesh.get(), distance)); } });*/ // ObjMesh with textures pWorld->each([&](Entity *ent, ComponentHandle mesh, ComponentHandle transform, ComponentHandle texture) { // Add the object to the renderObjects to draw if the distance is within the min and max distance of the mesh float distance = glm::distance(cameraPos, transform->getPosition()); if (distance > mesh->minDistance && distance < mesh->maxDistance) { // Put it into the list of transparent render objects if the texture wants to be rendered transparently if (texture->render_transparent) { transparentRenderObjects.emplace_back(RenderObject(transform->matrix, texture->id, mesh.get(), distance)); } else { renderObjects.emplace_back(RenderObject(transform->matrix, texture->id, mesh.get(), distance)); } } }); // LODObjMesh with Texture pWorld->each([&](Entity *ent, ComponentHandle lodMesh, ComponentHandle transform, ComponentHandle texture) { float distance = glm::distance(cameraPos, transform->getPosition()); for (const auto &mesh : lodMesh->meshes) { if (distance > mesh.minDistance && distance < mesh.maxDistance) { // Put it into the list of transparent render objects if the texture wants to be rendered transparently if (texture->render_transparent) { transparentRenderObjects.emplace_back(RenderObject(transform->matrix, texture->id, mesh, distance)); } else { renderObjects.emplace_back(RenderObject(transform->matrix, texture->id, mesh, distance)); } } } }); for (const RenderObject &obj : renderObjects) { obj.render(shader); } // Sort transparent objects and render them std::sort(transparentRenderObjects.begin(), transparentRenderObjects.end(), [](const RenderObject &first, const RenderObject &second) -> bool { return first.distance > second.distance; }); for (const RenderObject &obj : transparentRenderObjects) { obj.render(shader); } }); } struct RenderObject { RenderObject(const glm::mat4 &matrix, unsigned int textureId, const Mesh &mesh, float distance) : matrix(matrix), texture_id(textureId), mesh(mesh), distance(distance) {} void render(Shader shader) const { shader.setMat4("model", matrix); // 0 can't be a valid texture name, so we use it for meshes without textures here if (texture_id != 0) { glBindTexture(GL_TEXTURE_2D, texture_id); } mesh.render(); } glm::mat4 matrix; unsigned int texture_id; Mesh mesh; float distance; }; }; #endif //ECSGAME_RENDERSYSTEM_H