1#include "ModelSystem.h"
3#include "EntityStore.h"
5#include "Components/Core/MeshComponent.h"
6#include "Components/Core/TransformComponent.h"
7#include "Components/Core/MeshRenderComponent.h"
8#include "Components/Appearance/MaterialComponent.h"
9#include "Components/Core/SceneComponent.h"
10#include "Components/Core/AnimationComponent.h"
11#include "Components/Core/PropertiesComponent.h"
13#include "Systems/Core/TransformSystem.h"
14#include "Systems/Core/SceneSystem.h"
15#include "Systems/Core/MeshSystem.h"
16#include "Systems/Core/RenderSystem.h"
17#include "Systems/Appearance/MaterialSystem.h"
19#include "Services/DeferredNameResolution.h"
21#include "Resources/ModelManager.h"
22#include "Resources/MaterialManager.h"
23#include "Resources/DefaultMaterial.h"
24#include "Resources/Texture.h"
26#include "Foundation/Logging/Logger.h"
27#include "Foundation/Platform/Timer.h"
38 void forwardRenderProperties(SceneComponent * sceneComp,
const RenderComponent * masterRenderComp)
40 for (
auto & child : sceneComp->children) {
41 auto * childRenderComp = child->getComponent<RenderComponent>();
43 if (childRenderComp) {
44 childRenderComp->layer = masterRenderComp->layer;
45 childRenderComp->objectId = masterRenderComp->objectId;
46 childRenderComp->drawOrder = masterRenderComp->drawOrder;
48 childRenderComp->setChanged();
50 forwardRenderProperties(child->getComponent<SceneComponent>(), masterRenderComp);
54 MaterialInstanceHandle getMaterialInstance(Context * context)
56 return context->materialInstanceManager->createMaterialInstance(context->materialManager->getDefaultMaterial());
59 void updateMasterMaterial(Context * , ModelData & modelData, MaterialInstanceHandle masterMaterial)
61 modelData.masterMaterial = masterMaterial;
63 for (
auto & materialInstance : modelData.materials) {
64 if (!materialInstance->isDefaultMaterial())
continue;
66 materialInstance->masterInstance = masterMaterial;
68 if (masterMaterial->isDefaultMaterial()) {
72 if (overrideColor || overrideAlpha) {
73 auto masterColor = masterMaterial->getVec4Property(DefaultMaterial::DiffuseColor);
75 materialInstance->setVec4Property(DefaultMaterial::MasterColor, masterColor);
76 materialInstance->setBoolProperty(DefaultMaterial::OverrideColor, overrideColor);
77 materialInstance->setBoolProperty(DefaultMaterial::OverrideAlpha, overrideAlpha);
79 if (overrideAlpha && masterColor.a != 1) {
85 materialInstance->setBoolProperty(DefaultMaterial::OverrideColor,
false);
86 materialInstance->setBoolProperty(DefaultMaterial::OverrideAlpha,
false);
98 hierarchyUpdatedMessage =
context->dynamicComponentSystem->registerMessage(
"hierarchyUpdated");
105 for (
auto & component : pool) {
106 auto & modelData = getData<ModelData>(&component);
108 auto model =
HandleIsValid(component.model) ? context->modelManager->get(component.model) :
nullptr;
110 if (component.hasChanged() || !modelData.isLoaded() ||
111 (model && (!modelData.isGeneration((uint8_t)model->getGeneration()) || modelData.getResourceId() != model->getId()))) {
113 modelData.clearResourcesLoaded();
115 if (model->isLoaded()) {
117 if (component.waitForSubresources) {
119 for (
auto& mesh : model->meshes) {
120 ready &= mesh->isResident();
124 ready &= material->isResident();
131 if (!ready)
continue;
132 modelData.setResourcesLoaded();
135 loadModel(context, component, modelData, model);
137 auto id = component.getContainer()->getId();
138 for (
auto c : callbacks) {
139 c.second(context,
id);
142 context->dynamicComponentSystem->sendMessage(component.getContainer(), hierarchyUpdatedMessage);
146 forwardRenderProperties(component.getComponent<
SceneComponent>(), renderComp);
150 }
else if (modelData.isLoaded()) {
151 clearModel(context, component);
156 if (renderComp && renderComp->hasChanged()) {
157 forwardRenderProperties(component.getComponent<
SceneComponent>(), renderComp);
166 ModelData& modelData = getData<ModelData>(modelComponent);
167 if (modelData.isResourcesLoaded())
return 1.f;
169 Model* model = context->modelManager->get(modelComponent->
model);
170 if (!model->isLoaded())
return 0.f;
173 size_t total = model->meshes.size() + model->materials.size();
174 for (
const MeshHandle& mesh : model->meshes) {
175 if (mesh->isActive()) progress++;
179 ready &= material->isResident();
184 if (ready) progress++;
187 return static_cast<float>(progress) /
static_cast<float>(total);
192 for (
auto & component : pool) {
193 auto & modelData = getData<ModelData>(&component);
196 if (!materialComponent)
continue;
198 auto& materialData = context->materialSystem->getData(materialComponent);
200 if (!materialData.instance)
continue;
202 if (materialData.instance != modelData.masterMaterial || materialData.instance->hasChanged()) {
203 updateMasterMaterial(context, modelData, materialData.instance);
212 if (modelData.isLoaded()) {
213 clearModel(context, component);
222 uint32_t maxProp = model->parts.empty() ? model->properties.size() : model->parts[0].firstProperty;
223 if (uint32_t ix = model->properties.findProperty(0, maxProp, Strings::add(
"modelOrigin")); ix !=
PropertyStore::NoProperty) {
226 if (std::span<const double> view = model->properties.getDoubleArray(ix); view.size() == 3) {
229 Entity* root = modelEntity;
235 if (TransformComponent* trComp = root->
getComponent<TransformComponent>(); trComp) {
236 for (glm::dvec3::length_type i = 0; i < 3; i++) {
237 trComp->coordinates[i] = view[i];
239 trComp->setChanged();
246 const MaterialComponent* materialComponent = modelEntity->
getComponent<MaterialComponent>();
248 MaterialInstanceHandle modelMaterialInstance;
253 if (materialComponent) {
254 auto& materialData = context->materialSystem->getData(materialComponent);
255 modelMaterialInstance = materialData.instance;
260 if (model->animation) {
261 auto animationComponent = modelEntity->
getComponent<AnimationComponent>();
263 if (!animationComponent) {
264 animationComponent = context->
store->
addComponent<AnimationComponent>(modelEntity);
267 animationComponent->animation = model->animation;
272 Timer t = Timer::startNew();
275 std::vector<EntityPtr> entities(model->parts.size());
276 std::vector<ComponentHandle> transformComponents(model->parts.size());
277 std::vector<ComponentHandle> sceneComponents(model->parts.size());
279 const auto groupId =
hash(
"Group");
280 const auto meshPartId =
hash(
"MeshPart");
282 auto store = context->
store;
289 for (
size_t i = 0; i < model->parts.size(); ++i) {
290 const auto & part = model->parts[i];
291 auto & entity = entities[i];
293 auto partName = model->getPartName(part);
294 if (!partName.empty()) {
295 entity->setName(partName);
300 transformComponents[i] = transformComponent;
302 entity->addComponent(transformComponent);
305 entity->addComponent(sceneComponents[i]);
307 if (part.parentIndex != NoParentPart) {
308 sceneComponents[part.parentIndex].
resolveComponent<SceneComponent>()->children.emplace_back(entity);
309 transformComponent.resolveComponent<TransformComponent>()->parent = transformComponents[part.parentIndex];
314 EntityData* entityData =
static_cast<EntityData *
>(entity->getUserData());
315 entityData->templateId = (part.meshIndex !=
static_cast<uint32_t
>(-1) ? meshPartId : groupId);
317 if (part.meshIndex !=
static_cast<uint32_t
>(-1)) {
318 auto & mesh = model->meshes[part.meshIndex];
321 entity->addComponent(mcHandle);
324 meshComponent->meshHandle = mesh;
325 meshComponent->setChanged();
328 entity->addComponent(mrcHandle);
331 if (part.boundsIndex !=
static_cast<uint32_t
>(-1) && model->bounds.size() > part.boundsIndex) {
332 context->renderSystem->setLocalBounds(renderComponent, model->bounds[part.boundsIndex]);
337 renderComponent->startIndex = part.startIndex;
338 renderComponent->vertexCount = part.vertexCount;
341 MaterialInstanceHandle partMaterial = part.materialIndex < model->materials.size()
342 ? model->materials[part.materialIndex]
350 renderComponent->material = modelMaterialInstance;
352 else if (partMaterial) {
353 renderComponent->material = partMaterial;
356 MaterialInstanceHandle master = context->materialManager->getDefaultMaterial();
357 renderComponent->material = context->materialInstanceManager->createMaterialInstance(master);
363 auto master = context->materialManager->generateHandle(modelMaterialInstance->material);
364 renderComponent->material = context->materialInstanceManager->createMaterialInstance(master);
365 renderComponent->material->clone(modelMaterialInstance.resolve());
368 MaterialHandle master;
370 master = context->materialManager->generateHandle(partMaterial->material);
373 master = context->materialManager->getDefaultMaterial();
375 renderComponent->material = context->materialInstanceManager->createMaterialInstance(master);
376 modelData.materials.push_back(renderComponent->material);
380 renderComponent->material->setPermutation(partMaterial->getPermutation());
381 renderComponent->material->instanceFlags = partMaterial->instanceFlags;
382 renderComponent->material->options = partMaterial->options;
383 renderComponent->material->cloneMatchingProperties(partMaterial.resolve());
384 renderComponent->material->cloneMatchingVariants(partMaterial.resolve());
388 if (animationHandle) {
389 auto animationComponent = context->
store->
addComponent<AnimationComponent>(entity.get());
390 animationComponent->animation = model->animation;
391 animationComponent->master = animationHandle;
392 animationComponent->setChanged();
396 if (part.numProperties) {
397 auto propertiesComponent = entity->getComponent<PropertiesComponent>();
399 if (!propertiesComponent) {
400 propertiesComponent = context->
store->
addComponent<PropertiesComponent>(entity.get());
403 propertiesComponent->properties.copyProperties(model->properties, part.firstProperty, part.numProperties);
407 for (
size_t i = 0; i < model->parts.size(); ++i) {
408 const auto & part = model->parts[i];
410 context->transformSystem->setLocalTransform(transformComponents[i].resolveComponent<TransformComponent>(), model->getPartTransform(part));
414 LOG_TRACE(logger,
"Model spawn elapsed: %f.", t.elapsedSeconds());
416 if (modelMaterialInstance) {
417 updateMasterMaterial(context, modelData, modelMaterialInstance);
420 modelData.setLoaded();
422 modelData.setResourceId(model->
getId());
425void Cogs::Core::ModelSystem::clearModel(Context * ,
const ModelComponent & component)
428 auto sceneComponent = component.getComponent<SceneComponent>();
430 sceneComponent->children.clear();
433int Cogs::Core::ModelSystem::addHierarchyCallback(HierarchyChangedCallback callback)
436 callbacks[id] = callback;
440void Cogs::Core::ModelSystem::removeHierarchyCallback(
int id)
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.
ComponentHandle getComponentHandle() const
Get a component handle to the first component implementing the given type.
Context * context
Pointer to the Context instance the system lives in.
void postUpdate()
Perform post update logic in the system.
virtual void initialize(Context *context)
Initialize the system.
void update()
Updates the system state to that of the current frame.
ComponentHandle createComponent() override
ComponentHandle createComponent() override
Create a new component instance.
A Context instance contains all the services, systems and runtime components needed to use Cogs.
class EntityStore * store
Entity store.
std::unique_ptr< class DeferredNameResolution > deferredResolution
Deferred name resolution service instance.
ComponentModel::Component * addComponent(ComponentModel::Entity *entity, Reflection::TypeId typeId)
Add a component of the given type to the entity.
void addChild(ComponentModel::Entity *parent, const EntityPtr &entity)
Add a child to the given parent.
Cogs::ComponentModel::Entity * getEntityParent(const ComponentModel::Entity *entity) const
Gets the parent of the given entity.
void createEntities(size_t count, std::vector< EntityPtr > &entities)
Allocates and initializes a collection of empty entities.
float getLoadProgress(ModelComponent *modelComponent)
void initialize(Context *context) override
Initialize the system.
Base component for all rendering content.
ComponentHandle createComponent() override
Create a new component instance.
Contains information on how the entity behaves in the scene.
Log implementation class.
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
@ CastShadows
Casts shadows.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Contains all Cogs related functionality.
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
Handle to a Component instance.
ComponentType * resolveComponent() const
Exposes material properties for legacy entities and code.
@ OverrideAlpha
Override alpha of any inheriting materials.
@ OverrideColor
Override color of any inheriting materials.
@ MasterTransparency
Material contains transparency.
std::vector< TextureValue > textureVariables
Texture property values for this instance.
Contains a model reference to instance as children to the entity the ModelComponent belongs to.
bool inheritMaterial
If the model should inherit the material from the base entity.
MaterialInstanceHandle materialInstance
Explicit material handle.
ModelHandle model
Handle to a model resource that will be instanced onto the entity this ModelComponent belongs to.
bool shareMaterial
If the model should use shared model materials and not create it's own instances.
bool setCoordinate
If model resource has a localOrigin property, forward this value to the TransformComponent's coordina...
Model resources define a template for a set of connected entities, with resources such as meshes,...
static constexpr uint32_t NoProperty
Return from findProperty if key not found.
uint32_t getGeneration() const
Get the generation count.
ResourceId getId() const
Get the resource id of this instance.
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
TextureWithSampler texture
Value of the property for the material instance this belongs to.
TextureHandle handle
Handle to a texture resource, or TextureHandle::NoHandle if texture should be disabled.
EPrimitiveType
Primitive type enumeration.