1#include "ScreenSizeSystem.h"
5#include "Components/Core/SceneComponent.h"
7#include "Services/Variables.h"
9#include "Systems/Core/CameraSystem.h"
10#include "Systems/Core/TransformSystem.h"
11#include "Systems/Core/RenderSystem.h"
13#include "Scene/GetBounds.h"
15#include "Utilities/Parallel.h"
17#include "Foundation/Logging/Logger.h"
25 template<
typename FunT>
31 if (sceneComponent !=
nullptr && sceneComponent->children.size() > 0)
33 for (
auto & child : sceneComponent->children)
35 ForEachEntityPreOrder(child.get(), f);
43 auto rootLocalToWorldInverse = glm::inverse(context->transformSystem->getLocalToWorld(rootTransform));
44 auto parentLocalToWorld = rootTransform->parent
45 ? context->transformSystem->getLocalToWorld(rootTransform->parent.resolveComponent<
TransformComponent>())
46 : glm::translate(glm::vec3(rootTransform->coordinates - context->transformSystem->
getOrigin()));
47 auto totalParentTransform = parentLocalToWorld * rootLocalToWorldInverse;
49 data.childWorldBoundingBoxes.resize(data.children.size(), Cogs::Geometry::makeEmptyBoundingBox<Cogs::Geometry::BoundingBox>());
51 auto entityBBoxCalculationFun = [context, &data, &totalParentTransform](
size_t index)
53 auto entity = data.children[index];
57 assert(meshRenderComponent !=
nullptr &&
"MeshRenderComponent should not be null");
60 auto & localBounds = context->renderSystem->getLocalBounds(meshRenderComponent);
61 auto parentLocalTransform = totalParentTransform * context->transformSystem->getLocalToWorld(transformComponent);
62 data.childWorldBoundingBoxes[index] = Bounds::getTransformedBounds(localBounds, parentLocalTransform);
66 Parallel::forEach(context, data.children.size(), entityBBoxCalculationFun,
"PredictWorldBoundingBoxes");
69 for (
size_t entityIndex = 0; entityIndex < data.children.size(); ++entityIndex) {
70 entityBBoxCalculationFun(entityIndex);
75 Cogs::Geometry::BoundingBox AccumulateBoudingBoxes(
ScreenSizeData& data)
77 auto result = Cogs::Geometry::makeEmptyBoundingBox<Cogs::Geometry::BoundingBox>();
79 for (
auto const & bb : data.childWorldBoundingBoxes) {
86 float CalculateProjectedSize(
Context* context,
ScreenSizeComponent const & component, Cogs::Geometry::BoundingBox& worldBounds)
90 if (component.camera !=
nullptr)
97 cameraComponent = context->cameraSystem->getMainCamera();
98 cameraTransform = context->cameraSystem->getMainCamera()->getContainer()->getComponent<
TransformComponent>();
101 if (cameraComponent ==
nullptr || cameraTransform ==
nullptr)
103 LOG_WARNING(logger,
"Unable to get camera data for entity id %zu.", component.
getContainer()->
getId());
104 return std::numeric_limits<float>::max();
107 auto & cameraData = context->cameraSystem->getData(cameraComponent);
108 auto cameraPosition = glm::vec3(context->transformSystem->getLocalToWorld(cameraTransform) * glm::vec4(0, 0, 0, 1));
109 auto cameraDir = glm::normalize(glm::vec3(cameraData.inverseViewMatrix * glm::vec4(0, 0, -1, 0)));
111 auto worldCenter = (worldBounds.max + worldBounds.min) / 2.0f;
112 auto worldRadius = glm::length(worldBounds.max - worldCenter);
114 auto cameraDistanceAlongViewDir = glm::abs(glm::dot(worldCenter - cameraPosition, cameraDir));
115 auto projectedRadius = worldRadius / (cameraDistanceAlongViewDir * glm::tan(cameraData.fieldOfView / 2.0f));
116 return 2 * projectedRadius;
122 auto worldCenter = (worldBounds.min + worldBounds.max) / 2.0f;
123 auto coreTransform = glm::translate(glm::scale(glm::translate(worldCenter), glm::vec3(desiredScale, desiredScale, desiredScale)), -worldCenter);
124 auto localTransfrom = transformComponent->parent ? glm::mat4() : glm::translate(glm::vec3(transformComponent->coordinates - context->transformSystem->getOrigin()));
125 return glm::inverse(localTransfrom) * coreTransform * localTransfrom;
138 CpuInstrumentationScope(SCOPE_SYSTEMS,
"ScreenSizeSystem::update");
140 const bool workParallel = context->
engine->workParallel();
142 calcluateNewScales(context, workParallel);
143 updateTransforms(context, workParallel);
148 if (taskGroup.isValid()) {
153void Cogs::Core::ScreenSizeSystem::calcluateNewScales(
Context* context,
bool workParallel)
155 constexpr static const float Epsilon = 1e-5f;
157 CpuInstrumentationScope(SCOPE_SYSTEMS,
"ScreenSizeSystem::calcluateNewScales");
159 auto calcluateNewScalesParallel = [
this, context, workParallel](
ScreenSizeComponent const & screenSizeComponent, size_t)
161 auto & data = this->getData<ScreenSizeData>(&screenSizeComponent);
163 data.children.clear();
164 data.transformUpdateRequired =
false;
167 auto meshRenderComponent = entity->getComponent<MeshRenderComponent>();
168 if (meshRenderComponent != nullptr && meshRenderComponent->isVisible())
170 data.children.push_back(entity);
174 PredictWorldBoundingBoxes(context, workParallel, screenSizeComponent, data);
175 auto worldBounds = AccumulateBoudingBoxes(data);
176 auto newSize = CalculateProjectedSize(context, screenSizeComponent, worldBounds);
178 auto currentScale = std::isfinite(data.currentSize) ? screenSizeComponent.minSize / data.currentSize : 1.0f;
179 auto newScale = std::isfinite(newSize) ? screenSizeComponent.minSize / newSize : 1.0f;
181 if (newScale + Epsilon <= 1.0f)
183 if(currentScale + Epsilon > 1.0f)
187 transformComponent->transformFlags = 1;
188 transformComponent->setChanged();
190 data.transformUpdateRequired =
true;
193 else if(newSize != data.currentSize)
196 transformComponent->
transform = CalculateNewTransform(context, screenSizeComponent, data, worldBounds, newScale);
197 transformComponent->transformFlags = 1;
198 transformComponent->setChanged();
200 data.transformUpdateRequired =
true;
203 data.currentSize = newSize;
207 Parallel::processComponents(context, pool,
"ScreenSizeSystem::calcluateNewScalesParallel", calcluateNewScalesParallel, taskGroup);
211 Serial::processComponents(pool, calcluateNewScalesParallel);
215void Cogs::Core::ScreenSizeSystem::updateTransforms(
Context* context,
bool workParallel)
217 CpuInstrumentationScope(SCOPE_SYSTEMS,
"ScreenSizeSystem::updateTransforms");
219 auto updateTransformsParallel = [
this, context](
ScreenSizeComponent const & screenSizeComponent, size_t)
221 auto & data = this->getData<ScreenSizeData>(&screenSizeComponent);
223 if (!data.transformUpdateRequired)
229 context->transformSystem->updateLocalTransform(*transformComponent);
232 context->transformSystem->getData<Core::TransformState>(transformComponent).cached = false;
233 context->transformSystem->getData<Core::TransformState>(transformComponent).changed = true;
234 context->transformSystem->updateLocalToWorldTransform(*transformComponent);
239 Parallel::processComponents(context, pool,
"ScreenSizeSystem::updateTransformsParallel", updateTransformsParallel, taskGroup);
243 Serial::processComponents(pool, updateTransformsParallel);
ComponentType * getComponent() const
class Entity * getContainer() const
Get the container currently owning this component instance.
Container for components, providing composition of dynamic entities.
T * getComponent() const
Get a pointer to the first component implementing the given type in the entity.
constexpr size_t getId() const noexcept
Get the unique identifier of this entity.
Context * context
Pointer to the Context instance the system lives in.
virtual void initialize(Context *context)
Initialize the system.
void update()
Updates the system state to that of the current frame.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
std::unique_ptr< class TaskManager > taskManager
TaskManager service instance.
std::unique_ptr< class Engine > engine
Engine instance.
Renders the contents of a MeshComponent using the given materials.
Contains information on how the entity behaves in the scene.
Allows to control the screen size of the entity.
void initialize(Context *context) override
Initialize the system.
void cleanup(Context *context) override
Provided for custom cleanup logic in derived systems.
Log implementation class.
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
constexpr Log getLogger(const char(&name)[LEN]) noexcept