1#include "EntityDefinition.h"
5#include "EntityStore.h"
7#include "Resources/MaterialManager.h"
8#include "Resources/ModelManager.h"
9#include "Resources/MeshManager.h"
10#include "Resources/TextureManager.h"
11#include "Resources/AssetManager.h"
13#include "Services/DeferredNameResolution.h"
15#include "Serialization/ResourceReader.h"
17#include "Foundation/Logging/Logger.h"
18#include "Foundation/Reflection/TypeDatabase.h"
30 void applyFieldValue(
void *
object,
const Reflection::Field * field, T & value)
33 auto fieldPointer = field->getPtr<
typename std::remove_reference<typename std::remove_const<T>::type>::type>(object);
35 *fieldPointer = value;
40 if (!materialInstance) {
41 LOG_ERROR(logger,
"Cannot update invalid material instance.");
45 auto material = materialInstance->
material;
47 if (materialInstanceValue.permutation.size()) {
48 materialInstance->setPermutation(materialInstanceValue.permutation);
51 for (
auto & v : materialInstanceValue.variants) {
52 materialInstance->setVariant(v.first, v.second);
55 for (
auto & o : materialInstanceValue.options) {
56 materialInstance->
setOption(o.first, o.second);
59 auto logError = [](
const char * name,
const char * type) {
60 LOG_ERROR(logger,
"Material property %s of type %s not found.", name, type);
63 for (
auto & p : materialInstanceValue.properties) {
64 auto & value = p.second;
67 case DefaultValueType::Float:
69 auto key = material->getFloatKey(p.first);
70 if (key != NoProperty) {
73 logError(p.first.c_str(),
"float");
78 case DefaultValueType::Int:
80 auto key = material->getIntKey(p.first);
81 if (key != NoProperty) {
82 materialInstance->setIntProperty(key, value.intValue);
84 logError(p.first.c_str(),
"int");
89 case DefaultValueType::Bool:
91 auto key = material->getBoolKey(p.first);
92 if (key != NoProperty) {
95 logError(p.first.c_str(),
"bool");
100 case DefaultValueType::Vec2:
102 auto key = material->getVec2Key(p.first);
103 if (key != NoProperty) {
106 logError(p.first.c_str(),
"float2");
111 case DefaultValueType::Vec3:
113 auto key = material->getVec3Key(p.first);
114 if (key != NoProperty) {
117 logError(p.first.c_str(),
"float3");
122 case DefaultValueType::Vec4:
124 auto key = material->getVec4Key(p.first);
125 if (key != NoProperty) {
128 logError(p.first.c_str(),
"float4");
133 case DefaultValueType::Texture:
135 auto key = material->getTextureKey(p.first);
137 if (key != NoProperty) {
138 materialInstance->
setTextureProperty(key, context->textureManager->getTexture(p.second.value));
143 LOG_ERROR(logger,
"Unknown type for material property \"%s\".", p.first.c_str());
149 void applyMaterialInstanceValue(Context * context,
void * component,
const Reflection::Field * field,
const FieldValue & value)
151 auto materialInstanceDefinition = value.asMaterialInstance();
153 auto materialInstance = context->assetManager->instantiateMaterialInstance(
AssetHandle::NoHandle, *materialInstanceDefinition);
155 auto fieldPointer = field->
getPtr<MaterialInstanceHandle>(component);
157 *fieldPointer = materialInstance;
159 *fieldPointer = materialInstance;
167 for (
auto & value : values) {
168 if (value.componentId == Reflection::NoType) {
169 LOG_ERROR(logger,
"Could not apply field values for invalid type.");
178 auto & type = Reflection::TypeDatabase::getType(value.componentId);
180 if (value.fieldId == Reflection::NoField)
continue;
182 auto field = type.getField(value.fieldId);
185 LOG_ERROR(logger,
"Field %s not found on type %s.", field->
getName().
c_str(), type.getName().c_str());
193 LOG_ERROR(logger,
"Component of type %s not found on entity.", type.getName().c_str());
198 switch (value.type) {
199 case DefaultValueType::String:
200 applyFieldValue(component, field, value.value);
202 case DefaultValueType::MultiString:
203 applyFieldValue(component, field, value.values);
205 case DefaultValueType::IntArray:
206 applyFieldValue(component, field, value.intValues);
208 case DefaultValueType::FloatArray:
209 applyFieldValue(component, field, value.floatValues);
211 case DefaultValueType::Vec2Array:
212 applyFieldValue(component, field, value.vec2Values);
214 case DefaultValueType::Vec3Array:
215 applyFieldValue(component, field, value.vec3Values);
217 case DefaultValueType::Vec4Array:
218 applyFieldValue(component, field, value.vec4Values);
220 case DefaultValueType::Bool:
221 applyFieldValue(component, field, value.boolValue);
223 case DefaultValueType::Int:
224 applyFieldValue(component, field, value.intValue);
226 case DefaultValueType::Enum:
227 applyFieldValue(component, field, value.intValue);
229 case DefaultValueType::Float:
230 applyFieldValue(component, field, value.floatValue);
232 case DefaultValueType::Vec2:
233 applyFieldValue(component, field, value.float2);
235 case DefaultValueType::Vec3:
236 applyFieldValue(component, field, value.float3);
238 case DefaultValueType::Vec4:
239 applyFieldValue(component, field, value.float4);
241 case DefaultValueType::Mat4:
242 applyFieldValue(component, field, value.mat4);
244 case DefaultValueType::DVec2:
245 applyFieldValue(component, field, value.double2);
247 case DefaultValueType::DVec3:
248 applyFieldValue(component, field, value.double3);
250 case DefaultValueType::DVec4:
251 applyFieldValue(component, field, value.double4);
253 case DefaultValueType::Quaternion:
254 applyFieldValue(component, field, value.quat);
256 case DefaultValueType::MaterialInstance:
257 applyMaterialInstanceValue(context, component, field, value);
259 case DefaultValueType::Model:
261 if (value.value.front() ==
'$') {
262 auto name = value.value.substr(1);
263 auto model = context->modelManager->getByName(name);
265 applyFieldValue(component, field, model);
267 LOG_ERROR(logger,
"Could not find handle for model \"%s\".", name.c_str());
270 auto model = context->modelManager->loadModel(value.value, NoResourceId, ModelLoadFlags::None);
271 applyFieldValue(component, field, model);
276 case DefaultValueType::Asset:
278 if (value.value.front() ==
'$') {
279 auto asset = context->assetManager->getByName(value.value.substr(1));
280 applyFieldValue(component, field, asset);
282 auto asset = context->assetManager->loadAsset(value.value, NoResourceId, AssetLoadFlags::None);
283 applyFieldValue(component, field, asset);
287 case DefaultValueType::Gui:
289 auto * mgr = context->
engine->getResourceManagerByValueType((
int)DefaultValueType::Gui);
291 mgr->applyFieldValue(component, field, value);
294 LOG_ERROR(logger,
"No manager for DefaultValueType::Gui");
298 case DefaultValueType::Mesh:
300 auto mesh = context->meshManager->getMesh(value.value);
301 applyFieldValue(component, field, mesh);
304 case DefaultValueType::Texture:
306 auto texture = context->textureManager->getTexture(value.value);
307 applyFieldValue(component, field, texture);
310 case DefaultValueType::Entity:
311 if (value.value.empty()) {
313 applyFieldValue(component, field, ptr);
315 else if (1 < value.value.size() && value.value[0] !=
'$') {
316 LOG_WARNING(logger,
"Missing '$' in entity field \"%s\".", value.value.c_str());
321 if (field->
getTypeId() == Reflection::TypeDatabase::getType<EntityPtr>().getTypeId()) {
322 applyFieldValue(component, field, entity_);
324 else if (field->
getTypeId() == Reflection::TypeDatabase::getType<WeakEntityPtr>().getTypeId()) {
326 applyFieldValue(component, field, weakEntity);
330 auto handle = component->getComponentHandle(component->getTypeId());
333 value.value.substr(1));
337 case DefaultValueType::EntityArray:
339 std::vector<EntityPtr> entities(value.values.size());
340 for (
size_t i = 0; i < value.values.size(); i++) {
341 if (value.values[i].size() < 2 || value.values[i][0] !=
'$') {
342 LOG_WARNING(logger,
"Missing '$' name in entity field \"%s\".", value.values[i].c_str());
348 auto handle = component->getComponentHandle(component->getTypeId());
352 value.values[i].substr(1));
355 if (field->
getTypeId() == Reflection::TypeDatabase::getType<std::vector<EntityPtr>>().getTypeId()) {
356 applyFieldValue(component, field, entities);
358 else if (field->
getTypeId() == Reflection::TypeDatabase::getType<std::vector<WeakEntityPtr>>().getTypeId()) {
359 std::vector<WeakEntityPtr> weakEntities;
360 for (
auto & e : entities) weakEntities.push_back(e);
361 applyFieldValue(component, field, weakEntities);
365 case DefaultValueType::Extension:
367 auto ext = getExtensionReader(field->
getTypeId());
370 ext->setCallback(component, field, value);
375 LOG_WARNING(logger,
"Unhandled value type for field %s.", field->
getName().
c_str());
379 component->setFieldChanged(value.fieldId);
Base class for Component instances.
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.
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.
std::unique_ptr< class Engine > engine
Engine instance.
ComponentModel::Component * addComponent(ComponentModel::Entity *entity, Reflection::TypeId typeId)
Add a component of the given type to the entity.
EntityPtr findEntity(const StringView &name, const ComponentModel::Entity *root=nullptr, EntityFind findOptions=EntityFind::Default) const
Finds an entity with the given name.
Log implementation class.
Field definition describing a single data member of a data structure.
const Name & getName() const
Get the name of the field.
size_t getDimensions() const
Get the array dimensions of the field. Returns zero if the field is not an array.
TypeId getTypeId() const
Get the type id of the field.
FieldValueType * getPtr(void *container) const
Get a pointer to this field on the given container.
Provides a weakly referenced view over the contents of a string.
constexpr StringView substr(size_t offset, size_t count=NoPosition) const noexcept
Get the given sub string.
void updateMaterialInstance(Context *context, MaterialInstance *materialInstance, const MaterialInstanceDefinition &materialInstanceValue)
Apply material instance values.
void applyFieldValues(class Context *context, std::span< FieldValue > entityDefinition, ComponentModel::Entity *entity)
Apply defaults from the given entityDefinition to the given entity.
std::weak_ptr< ComponentModel::Entity > WeakEntityPtr
Weak Smart pointer for Entity access.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Contains all Cogs related functionality.
Material instances represent a specialized Material combined with state for all its buffers and prope...
void setFloatProperty(const VariableKey key, float value)
Set the float property with the given key to value.
void setVec3Property(const VariableKey key, glm::vec3 value)
Set the vec3 property with the given key to value.
void setOption(const StringView &key, const StringView &value)
Sets the option with the given key to a value parsed from the value string.
void setTextureProperty(const StringView &key, TextureHandle value)
Set the texture property with the given key to the texture resource held by value.
void setVec2Property(const VariableKey key, glm::vec2 value)
Set the vec2 property with the given key to value.
void setVec4Property(const VariableKey key, glm::vec4 value)
Set the vec4 property with the given key to value.
void setBoolProperty(const VariableKey key, bool value)
Set the bool property with the given key to value.
Material * material
Material resource this MaterialInstance is created from.
static const ResourceHandle_t NoHandle
Handle representing a default (or none if default not present) resource.
const char * c_str() const
Gets the name as a null-terminated string.