diff --git a/ECS/Systems/RenderSystem.h b/ECS/Systems/RenderSystem.h index 24581d1..7bc4988 100644 --- a/ECS/Systems/RenderSystem.h +++ b/ECS/Systems/RenderSystem.h @@ -20,106 +20,6 @@ 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(); - - // Lighting - // TODO: Currently only the last light is used! - pWorld->each([&](Entity *ent, ComponentHandle light) { - shader.setVec3("lightDirection", light->direction); - }); - - glm::vec3 cameraPos = cameraTransform->get_origin(); - - glm::mat4 view = cameraTransform->matrix; - view[3] = glm::vec4(cameraPos, 1.0); - - shader.setMat4("projection", camera->projection); - shader.setMat4("view", glm::inverse(view)); - shader.setVec3("cameraPosition", cameraTransform->get_origin()); - - std::vector renderObjects; - std::vector transparentRenderObjects; - - /*pWorld->each([&](Entity *ent, ComponentHandle mesh, ComponentHandle transform) { - renderObjects.emplace_back(RenderObject(transform->matrix, 0, mesh.get(), 0)); - });*/ - - /*// 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->get_origin()); - - if (distance > mesh->minDistance && distance < mesh->maxDistance) { - // Get optional components - ComponentHandle textureComponent = ent->get(); - ComponentHandle materialComponent = ent->get(); - - Material material = materialComponent.isValid() ? materialComponent.get() : Material(); - unsigned int textureID = textureComponent.isValid() ? textureComponent->id : 0; - - // Put it into the list of transparent render objects if the texture wants to be rendered transparently - if (textureComponent.isValid() && textureComponent->render_transparent) { - transparentRenderObjects.emplace_back(RenderObject(transform->matrix, transform->get_origin(), textureID, mesh.get(), distance, material)); - } else { - renderObjects.emplace_back(RenderObject(transform->matrix, transform->get_origin(), textureID, mesh.get(), distance, material)); - } - } - }); - - // LODObjMesh with Texture - pWorld->each([&](Entity *ent, ComponentHandle lodMesh, ComponentHandle transform) { - float distance = glm::distance(cameraPos, transform->get_origin()); - - for (const auto &mesh : lodMesh->meshes) { - if (distance > mesh.minDistance && distance < mesh.maxDistance) { - // Get optional components - ComponentHandle textureComponent = ent->get(); - ComponentHandle materialComponent = ent->get(); - - Material material = materialComponent.isValid() ? materialComponent.get() : Material(); - unsigned int textureID = textureComponent.isValid() ? textureComponent->id : 0; - - // Put it into the list of transparent render objects if the texture wants to be rendered transparently - if (textureComponent.isValid() && textureComponent->render_transparent) { - transparentRenderObjects.emplace_back(RenderObject(transform->matrix, transform->get_origin(), textureID, mesh, distance, material)); - } else { - renderObjects.emplace_back(RenderObject(transform->matrix, transform->get_origin(), textureID, mesh, distance, material)); - } - } - } - }); - - 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, const glm::vec3 &origin, unsigned int textureId, const Mesh &mesh, float distance, const Material &material) : matrix(matrix), @@ -152,6 +52,113 @@ public: float distance; Material material; }; + + // Fill the passed vector with render objects of the given world + std::vector> getRenderObjects(World *world, glm::vec3 cameraPos) { + std::vector> renderObjects(2); // First normal, then transparent + + /*pWorld->each([&](Entity *ent, ComponentHandle mesh, ComponentHandle transform) { + renderObjects.emplace_back(RenderObject(transform->matrix, 0, mesh.get(), 0)); + });*/ + + /*// 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 + world->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->get_origin()); + + if (distance > mesh->minDistance && distance < mesh->maxDistance) { + // Get optional components + ComponentHandle textureComponent = ent->get(); + ComponentHandle materialComponent = ent->get(); + + Material material = materialComponent.isValid() ? materialComponent.get() : Material(); + unsigned int textureID = textureComponent.isValid() ? textureComponent->id : 0; + + // Put it into the list of transparent render objects if the texture wants to be rendered transparently + if (textureComponent.isValid() && textureComponent->render_transparent) { + renderObjects[1].emplace_back(RenderObject(transform->matrix, transform->get_origin(), textureID, mesh.get(), distance, material)); + } else { + renderObjects[0].emplace_back(RenderObject(transform->matrix, transform->get_origin(), textureID, mesh.get(), distance, material)); + } + } + }); + + // LODObjMesh with Texture + world->each([&](Entity *ent, ComponentHandle lodMesh, ComponentHandle transform) { + float distance = glm::distance(cameraPos, transform->get_origin()); + + for (const auto &mesh : lodMesh->meshes) { + if (distance > mesh.minDistance && distance < mesh.maxDistance) { + // Get optional components + ComponentHandle textureComponent = ent->get(); + ComponentHandle materialComponent = ent->get(); + + Material material = materialComponent.isValid() ? materialComponent.get() : Material(); + unsigned int textureID = textureComponent.isValid() ? textureComponent->id : 0; + + // Put it into the list of transparent render objects if the texture wants to be rendered transparently + if (textureComponent.isValid() && textureComponent->render_transparent) { + renderObjects[1].emplace_back(RenderObject(transform->matrix, transform->get_origin(), textureID, mesh, distance, material)); + } else { + renderObjects[0].emplace_back(RenderObject(transform->matrix, transform->get_origin(), textureID, mesh, distance, material)); + } + } + } + }); + + // Sort transparent objects + std::sort(renderObjects[1].begin(), renderObjects[1].end(), [](const RenderObject &first, const RenderObject &second) -> bool { + return first.distance > second.distance; + }); + + return renderObjects; + } + + 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(); + + // Lighting + // TODO: Currently only the last light is used! + pWorld->each([&](Entity *ent, ComponentHandle light) { + shader.setVec3("lightDirection", light->direction); + }); + + glm::vec3 cameraPos = cameraTransform->get_origin(); + + glm::mat4 view = cameraTransform->matrix; + view[3] = glm::vec4(cameraPos, 1.0); + + shader.setMat4("projection", camera->projection); + shader.setMat4("view", glm::inverse(view)); + shader.setVec3("cameraPosition", cameraTransform->get_origin()); + + std::vector> allRenderObjects = getRenderObjects(pWorld, cameraPos); + std::vector renderObjects = allRenderObjects[0]; + std::vector transparentRenderObjects = allRenderObjects[1]; + + for (const RenderObject &obj : renderObjects) { + obj.render(shader); + } + for (const RenderObject &obj : transparentRenderObjects) { + obj.render(shader); + } + }); + } }; #endif //ECSGAME_RENDERSYSTEM_H