Cogs.Core
ResourceCommands.cpp
1#include "ResourceCommands.h"
2
3#include "Resources/MaterialInstance.h"
4
5#include "Components/Core/SceneComponent.h"
6#include "Components/Core/MeshComponent.h"
7#include "Components/Core/MeshRenderComponent.h"
8
9#include "Resources/MaterialManager.h"
10#include "Resources/MeshManager.h"
11#include "Resources/DefaultMaterial.h"
12#include "Resources/Texture.h"
13#include "Resources/TextureManager.h"
14
15#include "Resources/MaterialInstance.h"
16
17#include "Foundation/HashSequence.h"
18#include "Foundation/Logging/Logger.h"
19#include "Foundation/Platform/IO.h"
20
21#include <iostream>
22#include <set>
23
24namespace {
25 const Cogs::Logging::Log logger = Cogs::Logging::getLogger("ResourceCommand");
26}
27
29{
30 auto textureKey = material->material->getTextureKey(key);
31 auto textureProperty = material->getTextureProperty(textureKey);
32
33 previousTexture = textureProperty.texture.handle;
34
35 material->setTextureProperty(textureKey, texture);
36}
37
38void Cogs::Core::SetTexturePropertyCommand::undo()
39{
40 auto textureKey = material->material->getTextureKey(key);
41 material->setTextureProperty(textureKey, previousTexture);
42}
43
44namespace Cogs::Core
45{
46 void gatherMaterials(ComponentModel::Entity * entity, std::unordered_map<EntityId, MaterialInstanceHandle> & materials)
47 {
48 auto component = entity->getComponent<MeshRenderComponent>();
49
50 if (component) {
51 if (component->material) {
52 materials[entity->getId()] = component->material;
53 }
54 }
55
56 auto sceneComponent = entity->getComponent<SceneComponent>();
57
58 if (sceneComponent) {
59 for (auto & child : sceneComponent->children) {
60 gatherMaterials(child.get(), materials);
61 }
62 }
63 }
64}
65
67{
68 gatherMaterials(context->store->getEntityPtr(entityId), materials);
69
70 // Keep a mapping of already-remapped materials to avoid creating more instances than
71 // necessary.
72 std::unordered_map<MaterialInstance *, MaterialInstance *> mapping;
73
74 auto material = context->materialManager->getMaterial("StandardMaterial");
75
76 for (auto & m : materials) {
77 auto entity = context->store->getEntityPtr(m.first);
78 auto component = entity->getComponent<MeshRenderComponent>();
79
80 auto found = mapping.find(m.second.resolve());
81
82 if (found != mapping.end()) {
83 component->material = context->materialInstanceManager->generateHandle(found->second);
84 continue;
85 }
86
87 auto newMaterial = context->materialInstanceManager->createMaterialInstance(material);
88 newMaterial->setVariant("Textured", false);
89
90 auto color = m.second->getVec4Property(DefaultMaterial::DiffuseColor);
91 color = glm::pow(color, glm::vec4(glm::vec3(1.0f / 2.2f), 1.0f));
92
93 auto diffuseMap = m.second->getTextureProperty(DefaultMaterial::DiffuseMap);
94
95 TextureHandle diffuseHandle = m.second->getTextureProperty(DefaultMaterial::DiffuseMap).texture.handle;
96 if(diffuseHandle){
97 if(!diffuseHandle->getSource().empty()){
98 newMaterial->setTextureProperty(material->getTextureKey("albedoMap"), diffuseHandle);
99 newMaterial->setVariant("Textured", true);
100 newMaterial->setVariant("AlbedoMap", true);
101 }
102
103 auto name = diffuseHandle->getName();
104
105 const char *patterns[] = {
106 "ALBEDO",
107 "DIFFUSE",
108 "GLOSS",
109 "NORMAL",
110 "SPEC"
111 };
112
113 std::string albedo, diffuse, gloss, normal, spec;
114 for(const char *pattern : patterns){
115 std::string::size_type pos;
116 if((pos = name.find(pattern)) != StringView::NoPosition){
117 std::string first = name.substr(0, pos).to_string();
118 std::string last = name.substr(pos+strlen(pattern)).to_string();
119 albedo = first+"ALBEDO"+last;
120 if(!Cogs::IO::exists(albedo)) albedo = "";
121 diffuse = first+"DIFFUSE"+last;
122 if(!Cogs::IO::exists(diffuse)) diffuse = "";
123 gloss = first+"GLOSS"+last;
124 if(!Cogs::IO::exists(gloss)) gloss = "";
125 normal = first+"NORMAL"+last;
126 if(!Cogs::IO::exists(normal)) normal = "";
127 spec = first+"SPEC"+last;
128 if(!Cogs::IO::exists(spec)) spec = "";
129 break;
130 }
131 }
132 newMaterial->setPermutation("Specular");
133 newMaterial->setVariant("Textured", false);
134 newMaterial->setVec4Property(material->getVec4Key("albedo"), color);
135 newMaterial->setFloatProperty(material->getFloatKey("gloss"), 1.0);
136 newMaterial->setVec3Property(material->getVec3Key("specular"), glm::vec3(0.0));
137 newMaterial->setFloatProperty(material->getFloatKey("normalMapFactor"), 1.0);
138 if(albedo != ""){
139 newMaterial->setVariant("Textured", true);
140 newMaterial->setVariant("AlbedoMap", true);
141 Cogs::Core::TextureHandle mh = context->textureManager->loadTexture(albedo, NoResourceId, TextureLoadFlags::None);
142 newMaterial->setTextureProperty(material->getTextureKey("albedoMap"), mh);
143 }
144 else if(diffuse != ""){
145 newMaterial->setVariant("Textured", true);
146 newMaterial->setVariant("AlbedoMap", true);
147 Cogs::Core::TextureHandle mh = context->textureManager->loadTexture(diffuse, NoResourceId, TextureLoadFlags::None);
148 newMaterial->setTextureProperty(material->getTextureKey("albedoMap"), mh);
149 }
150 if(gloss != ""){
151 newMaterial->setVariant("Textured", true);
152 newMaterial->setVariant("GlossMap", true);
153 Cogs::Core::TextureHandle mh = context->textureManager->loadTexture(gloss, NoResourceId, TextureLoadFlags::LinearColorSpace);
154 newMaterial->setTextureProperty(material->getTextureKey("glossMap"), mh);
155 }
156 if(normal != ""){
157 newMaterial->setVariant("Textured", true);
158 newMaterial->setVariant("NormalMap", true);
159 Cogs::Core::TextureHandle mh = context->textureManager->loadTexture(normal, NoResourceId, TextureLoadFlags::LinearColorSpace);
160 newMaterial->setTextureProperty(material->getTextureKey("normalMap"), mh);
161 }
162 if(spec != ""){
163 newMaterial->setVariant("Textured", true);
164 newMaterial->setVariant("SpecularMap", true);
165 newMaterial->setVec3Property(material->getVec3Key("specular"), glm::vec3(1.0));
166 Cogs::Core::TextureHandle mh = context->textureManager->loadTexture(spec, NoResourceId, TextureLoadFlags::None);
167 newMaterial->setTextureProperty(material->getTextureKey("specularMap"), mh);
168 }
169 }
170
171 mapping[m.second.resolve()] = newMaterial.resolve();
172 component->material = newMaterial;
173 }
174}
175
176void Cogs::Core::RemapMaterialCommand::undo()
177{
178 for (auto & m : materials) {
179 auto entity = context->store->getEntityPtr(m.first);
180 auto component = entity->getComponent<MeshRenderComponent>();
181 component->material = m.second;
182 }
183}
184namespace Cogs::Core{
185static size_t getMaterialHash(MaterialInstance * material)
186{
187 size_t hashValue = material->getName().hash();
188
189 if (material->material->getName() == "DefaultMaterial") {
190 hashValue = Cogs::hash(material->getVec4Property(DefaultMaterial::DiffuseColor), hashValue);
191 hashValue = Cogs::hash(material->getVec3Property(DefaultMaterial::SpecularColor), hashValue);
192 hashValue = Cogs::hash(material->getVec3Property(DefaultMaterial::EmissiveColor), hashValue);
193 hashValue = Cogs::hash(material->getFloatProperty(DefaultMaterial::SpecularPower), hashValue);
194
195 TextureHandle diffuseHandle = material->getTextureProperty(DefaultMaterial::DiffuseMap).texture.handle;
196 if(diffuseHandle) {
197 hashValue = Cogs::hash(diffuseHandle->getName(), hashValue);
198 }
199
200 TextureHandle normalHandle = material->getTextureProperty(DefaultMaterial::NormalMap).texture.handle;
201 if(normalHandle) {
202 hashValue = Cogs::hash(normalHandle->getName(), hashValue);
203 }
204
205 TextureHandle specularHandle = material->getTextureProperty(DefaultMaterial::SpecularMap).texture.handle;
206 if(specularHandle) {
207 hashValue = Cogs::hash(specularHandle->getName(), hashValue);
208 }
209 }
210 else {
211 hashValue = Cogs::hash(reinterpret_cast<intptr_t>(material), hashValue);
212 }
213 return hashValue;
214}
215}// namespace ...
217{
218 gatherMaterials(context->store->getEntityPtr(entityId), materials);
219
220 std::set<MaterialInstance*> count;
221 for (auto & m : materials)
222 count.insert(m.second.resolve());
223
224 std::unordered_map<size_t, MaterialInstance*> mapping;
225
226 for (auto & m : materials) {
227 auto entity = context->store->getEntityPtr(m.first);
228 auto component = entity->getComponent<MeshRenderComponent>();
229
230 size_t hash = getMaterialHash(m.second.resolve());
231 if(!mapping.count(hash))
232 mapping[hash] = m.second.resolve();
233 component->material = MaterialInstanceHandle(mapping[hash]);
234 }
235 LOG_INFO(logger, "%zu materials merget to %zu materials", count.size(), mapping.size());
236}
237void Cogs::Core::MergeMaterialCommand::undo()
238{
239 for (auto & m : materials) {
240 auto entity = context->store->getEntityPtr(m.first);
241 auto component = entity->getComponent<MeshRenderComponent>();
242 component->material = m.second;
243 }
244}
245namespace Cogs::Core{
246static void gatherMeshes(ComponentModel::Entity * entity, std::unordered_map<EntityId, MeshHandle> &meshes)
247{
248 auto component = entity->getComponent<MeshComponent>();
249
250 if (component) {
251 if (component->meshHandle) {
252 meshes[entity->getId()] = component->meshHandle;
253 }
254 }
255
256 auto sceneComponent = entity->getComponent<SceneComponent>();
257
258 if (sceneComponent) {
259 for (auto & child : sceneComponent->children) {
260 gatherMeshes(child.get(), meshes);
261 }
262 }
263}
264}// namespace ...
266{
267 gatherMeshes(context->store->getEntityPtr(entityId), meshes);
268 for(auto &m : meshes){
269 // auto entity = context->store->getEntityPtr(m.first);
270 // auto component = entity->getComponent<MeshComponent>();
271 // MeshManager::ResourceProxy mesh = context->meshManager->createLocked();
272 // mesh->copy(*m.second.resolve());
273 // component->meshHandle = mesh.getHandle();
274 auto mesh = m.second.resolve();
276 }
277}
278void Cogs::Core::GenNormalsCommand::undo()
279{
280 LOG_ERROR(logger, "TODO: Undo normal generation.");
281 for (auto & m : meshes) {
282 auto entity = context->store->getEntityPtr(m.first);
283 auto component = entity->getComponent<MeshComponent>();
284 component->meshHandle = m.second;
285 }
286}
288{
289 gatherMeshes(context->store->getEntityPtr(entityId), meshes);
290 for(auto &m : meshes){
291 // auto entity = context->store->getEntityPtr(m.first);
292 // auto component = entity->getComponent<MeshComponent>();
293 // MeshManager::ResourceProxy mesh = context->meshManager->createLocked();
294 // mesh->copy(*m.second.resolve());
295 // component->meshHandle = mesh.getHandle();
296 auto mesh = m.second.resolve();
298 }
299}
300void Cogs::Core::GenerateTangentsCommand::undo()
301{
302 LOG_ERROR(logger, "TODO: Undo tangent generation.");
303 for (auto & m : meshes) {
304 auto entity = context->store->getEntityPtr(m.first);
305 auto component = entity->getComponent<MeshComponent>();
306 component->meshHandle = m.second;
307 }
308}
Container for components, providing composition of dynamic entities.
Definition: Entity.h:18
T * getComponent() const
Get a pointer to the first component implementing the given type in the entity.
Definition: Entity.h:35
constexpr size_t getId() const noexcept
Get the unique identifier of this entity.
Definition: Entity.h:113
Contains a handle to a Mesh resource to use when rendering using the MeshRenderComponent.
Definition: MeshComponent.h:15
MeshHandle meshHandle
Handle to a Mesh resource to use when rendering.
Definition: MeshComponent.h:29
Renders the contents of a MeshComponent using the given materials.
MaterialInstanceHandle material
Material used to render the mesh.
Log implementation class.
Definition: LogManager.h:139
constexpr bool empty() const noexcept
Check if the string is empty.
Definition: StringView.h:122
constexpr StringView substr(size_t offset, size_t count=NoPosition) const noexcept
Get the given sub string.
Definition: StringView.h:258
static constexpr size_t NoPosition
No position.
Definition: StringView.h:43
std::string to_string() const
String conversion method.
Definition: StringView.cpp:9
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
void COGSCORE_DLL_API generateMeshNormals(Mesh *mesh)
Generate normals.
Definition: MeshHelper.cpp:112
void COGSCORE_DLL_API generateMeshTangents(Mesh *mesh)
Generate tangents.
Definition: MeshHelper.cpp:171
@ LinearColorSpace
For textures with RGBA format without color space information, mark the data as being in linear color...
size_t getMaterialHash(const MaterialComponent &component)
Creates a hash value from the material properties in the given component.
constexpr Log getLogger(const char(&name)[LEN]) noexcept
Definition: LogManager.h:180
constexpr size_t hash() noexcept
Simple getter function that returns the initial value for fnv1a hashing.
Definition: HashFunctions.h:62
void apply() override
Run the command.
void apply() override
Run the command.
TextureValue getTextureProperty(const VariableKey key) const
Get the value of the property with the given key.
void setTextureProperty(const StringView &key, TextureHandle value)
Set the texture property with the given key to the texture resource held by value.
Material * material
Material resource this MaterialInstance is created from.
void apply() override
Run the command.
void apply() override
Run the command.
StringView getName() const
Get the name of the resource.
Definition: ResourceBase.h:307
void apply() override
Run the command.