Cogs.Core
MaterialInstance.cpp
1#include "MaterialInstance.h"
2
3#include "Foundation/Logging/Logger.h"
4
5#include "Texture.h"
6
7#include "Utilities/Parsing.h"
8
9#include <cstring>
10
11namespace
12{
13 using namespace Cogs::Core;
14
15 Cogs::Logging::Log logger = Cogs::Logging::getLogger("MaterialInstance");
16
17 void initializeInstanceTextureVariables(std::vector<TextureValue>& variables, const std::span<const TextureProperty>& properties)
18 {
19 for (const TextureProperty& p : properties) {
20 TextureValue& v = variables.emplace_back();
21 v.property = &p;
22 v.key = p.key;
23 v.texture = p.texture;
24 }
25 }
26
27 void reversePropertyFlags(const MaterialProperty& prop, MaterialPropertyFlags flags, void* data, size_t /*size*/)
28 {
29 float* values = nullptr;
30 int length = 0;
31 switch (prop.type) {
32 case MaterialDataType::Float:
33 values = (float*)data;
34 length = 1;
35 break;
36 case MaterialDataType::Float2:
37 values = (float*)data;
38 length = 2;
39 break;
40 case MaterialDataType::Float3:
41 values = (float*)data;
42 length = 3;
43 break;
44 case MaterialDataType::Float4:
45 values = (float*)data;
46 length = 4;
47 break;
48 default:
49 break;
50 }
51
52 if (!values || !length) return;
53
54 if ((int)(flags) & (int)MaterialPropertyFlags::sRGB) {
55 for (int i = 0; i < std::min(3, length); i++) {
56 values[i] = std::pow(std::abs(values[i]), 1.0f / 2.2f);
57 }
58 }
59 }
60
61 static constexpr const char* shaderVariantTypeName[] = {
62 "None",
63 "Bool",
64 "Int",
65 "Enum",
66 "Format",
67 "String",
68 };
69
70 bool setVariantImpl(MaterialInstance* that, const ShaderVariantDefinition& definition, ShaderVariantType type, size_t value)
71 {
72 if (definition.type != type) {
73 LOG_ERROR(logger, "Variant type is not %s", shaderVariantTypeName[size_t(type)]);
74 return false;
75 }
76 if (definition.isShared) {
77 LOG_ERROR(logger, "Cannot set shared variant through material instance");
78 return false;
79 }
80 assert(definition.index < that->variantSelectors.size());
81 ShaderVariantSelector& selector = that->variantSelectors[definition.index];
82
83 assert(selector.index == definition.index);
84 if (selector.value != value) {
85 selector.value = value;
86 that->variantGeneration++;
87 that->setChanged();
88 }
89 return true;
90 }
91
92 bool setVariantImpl(MaterialInstance* that, size_t index, ShaderVariantType type, size_t value)
93 {
94 if (that->material->definition.variants.size() <= index) {
95 LOG_ERROR(logger, "Variant index %zu out of range.", index);
96 return false;
97 }
98 const ShaderVariantDefinition& definition = that->material->definition.variants[index];
99 assert(definition.index == index);
100 return setVariantImpl(that, definition, type, value);
101 }
102
103 size_t lookupVariantValue(const MaterialInstance* that, const ShaderVariantDefinition& definition)
104 {
105 if (definition.isShared) return definition.defaultValue;
106
107 assert(definition.index < that->variantSelectors.size());
108 const ShaderVariantSelector& selector = that->variantSelectors[definition.index];
109
110 assert(selector.index == definition.index);
111 return selector.value;
112 }
113
114 bool lookupVariantIndex(const MaterialInstance* that, size_t& index, const Cogs::StringView& key)
115 {
116 index = that->material->getVariantIndex(key);
117 if (index != Material::NoVariantIndex) {
118 return true;
119 }
120 LOG_ERROR(logger, "Unrecognized variant name '%.*s'", StringViewFormat(key));
121 return false;
122 }
123
124}
125
127{
128 this->material = material;
129
130 for (auto & buffer : material->constantBuffers.buffers) {
131 buffers.emplace_back();
132
133 auto & instanceBuffer = buffers[buffers.size() - 1];
134
135 if (buffer.isPerInstance) {
136 instanceBuffer.content = buffer.content;
137 }
138 instanceBuffer.name = buffer.name;
139 instanceBuffer.isPerInstance = buffer.isPerInstance;
140 instanceBuffer.index = buffer.index;
141 instanceBuffer.size = buffer.size;
142 }
143
145
146 variantSelectors.resize(material->definition.variants.size());
147
148 for (auto & v : material->definition.variants) {
149 variantSelectors[v.index].index = v.index;
150 variantSelectors[v.index].value = v.defaultValue;
151 }
152
153 initializeInstanceTextureVariables(textureVariables, material->textureProperties);
154}
155
157{
158 if (material != instance->material) {
159 buffersGeneration++;
160 material = instance->material;
161 }
162
163 masterInstance = instance->masterInstance;
164 buffers = instance->buffers;
165 for (MaterialPropertyBufferInstance& b : buffers) b.generation++;
166
167 textureVariables = instance->textureVariables;
168 instanceFlags = instance->instanceFlags;
169 options = instance->options;
170 variantSelectors = instance->variantSelectors;
171 variantStrings = instance->variantStrings;
172 variantGeneration++;
173 permutationIndex = instance->permutationIndex;
174
175 setChanged();
176}
177
179{
180 if (!instance) {
181 LOG_ERROR(logger, "Material instance not valid.");
182 return 0;
183 }
184
185 if (!material || !instance->material) {
186 LOG_ERROR(logger, "Invalid or missing materials.");
187 return 0;
188 }
189
190 int cloned = 0;
191
192 for (auto & dp : material->constantBuffers.variables) {
193 for (auto & sp : instance->material->constantBuffers.variables) {
194 if (dp.name == sp.name && dp.type == sp.type && dp.flags == sp.flags) {
195 auto numBytes = DataTypeSizes[(unsigned)dp.type];
196
197 union alignas(float) {
198 char buffer[64];
199 };
200
201 if (dp.type == MaterialDataType::Bool) {
202 auto value = instance->getBoolProperty(sp.key);
203 setBoolProperty(dp.key, value);
204 } else if (instance->getProperty(sp.key, buffer, numBytes)) {
205 setProperty(dp.key, buffer, numBytes);
206 ++cloned;
207 } else {
208 LOG_ERROR(logger, "Could not clone property %s.", dp.name.c_str());
209 }
210 }
211 }
212 }
213
214 for (auto & tp : material->textureProperties) {
215 for (auto & dp : instance->material->textureProperties) {
216 if (dp.name == tp.name) {
217 setTextureProperty(tp.key, instance->getTextureProperty(dp.key).texture.handle);
218 }
219 }
220 }
221
222 return cloned;
223}
224
226{
227 if (!srcInstance) {
228 LOG_ERROR(logger, "Material instance not valid.");
229 return;
230 }
231
232 if (!material || !srcInstance->material) {
233 LOG_ERROR(logger, "Invalid or missing materials.");
234 return;
235 }
236
237 for (const ShaderVariantDefinition& srcDefinition : srcInstance->material->definition.variants) {
238 if (srcDefinition.isShared) continue; // We do not clone from shared variants
239
240
241 if (size_t dstIndex = material->getVariantIndex(srcDefinition.name); dstIndex != Material::NoVariantIndex) {
242
243 const ShaderVariantDefinition& dstDefinition = material->definition.variants[dstIndex];
244 if (srcDefinition.type != dstDefinition.type) continue; // Silently ignore mis-matched types.
245 if (dstDefinition.isShared) continue; // We do not clone into shared variants
246
247 size_t srcValue = lookupVariantValue(srcInstance, srcDefinition);
248 if (dstDefinition.type == ShaderVariantType::String) {
249 assert(srcValue < srcInstance->variantStrings.size());
250 setVariant(dstIndex, srcInstance->variantStrings[srcValue]);
251 }
252 else {
253 setVariantImpl(this, dstDefinition, srcDefinition.type, srcValue);
254 }
255 }
256 }
257}
258
260{
261 assert(material);
262
263 for (size_t i = 0; i < material->constantBuffers.buffers.size(); ++i) {
264 auto & buffer = material->constantBuffers.buffers[i];
265 auto & instanceBuffer = buffers[i];
266
267 if (buffer.isPerInstance) {
268 instanceBuffer.content = buffer.content;
269 }
270 }
271
272 options = material->options;
273
274 textureVariables.clear();
275 initializeInstanceTextureVariables(textureVariables, material->textureProperties);
276}
277
279{
280 if ((instanceFlags & MaterialFlags::MasterTransparency) != 0) return true;
281
282 switch (options.transparencyMode)
283 {
284 case TransparencyMode::Off:
285 return false;
286 case TransparencyMode::On:
287 return true;
288 case TransparencyMode::Auto:
289 {
290 VariableKey diffuseKey = material->getVec4Key("diffuseColor");
291 if (diffuseKey != NoProperty && getVec4Property(diffuseKey).a < 1.0f) {
292 return true;
293 }
294 for (const TextureValue& t : textureVariables) {
295 if (HandleIsValid(t.texture.handle) && t.texture.handle->hasAlpha) {
296 return true;
297 }
298 }
299 return false;
300 }
301 default:
302 break;
303 }
304
305 return false;
306}
307
309{
310 options.transparencyMode = TransparencyMode::On;
311 setVariant("ShadowCast", "Transparent");
312}
313
315{
316 options.transparencyMode = TransparencyMode::Off;
317 setVariant("ShadowCast", "Opaque");
318}
319
321{
322 applyMaterialOption(options, key, value);
323}
324
325void Cogs::Core::MaterialInstance::setProperty(const StringView & name, const void * data, const size_t sizeInBytes)
326{
327 auto key = material->constantBuffers.getPropertyKey(name);
328
329 if (key == NoProperty) {
330 LOG_ERROR(logger, "Could not get key for property %.*s.", StringViewFormat(name));
331 return;
332 }
333
334 setProperty(key, data, sizeInBytes);
335}
336
337void Cogs::Core::MaterialInstance::setProperty(VariableKey key, const void * data, const size_t sizeInBytes)
338{
339 auto & materialProperty = material->constantBuffers.variables[key];
340
341 // For smaller elements, take a copy so we may modify the value if necessary.
342 // FIXME: Handle arrays
343 uint8_t valueBuffer[sizeof(glm::mat4)];
344 if (sizeInBytes <= sizeof(glm::mat4)) {
345 std::memcpy(valueBuffer, data, sizeInBytes);
346 if (materialProperty.flags != MaterialPropertyFlags::None) {
347 enforcePropertyFlags(materialProperty, materialProperty.flags, valueBuffer);
348 }
349 data = &valueBuffer;
350 }
351
352 bool okSize = true;
353 if (materialProperty.descriptor.size == 4) {
354 // Possibly Boolean - accept 1(bool) or 4(int)
355 if (sizeInBytes != 1 && sizeInBytes != 4) {
356 okSize = false;
357 }
358 }
359 else if (sizeInBytes != materialProperty.descriptor.size) {
360 // Size mismatch also for types with Size=0.
361 okSize = false;
362 }
363
364 if (!okSize) {
365 LOG_ERROR(logger, "setProperty: Invalid size given Property=%s, Expected=%zu, Given=%zu",
366 materialProperty.name.data(), materialProperty.descriptor.size, sizeInBytes);
367 return;
368 }
369
370 buffers[materialProperty.buffer].setValue(materialProperty.descriptor, static_cast<const uint8_t *>(data));
371
372 setChanged();
373}
374
375bool Cogs::Core::MaterialInstance::getProperty(const StringView & name, void * value, const size_t sizeInBytes) const
376{
377 auto key = material->constantBuffers.getPropertyKey(name);
378
379 if (key == NoProperty) {
380 LOG_ERROR(logger, "Could not get key for property %.*s.", StringViewFormat(name));
381 return false;
382 }
383
384 return getProperty(key, value, sizeInBytes);
385}
386
387bool Cogs::Core::MaterialInstance::getProperty(VariableKey key, void * value, const size_t sizeInBytes) const
388{
389 if (key > material->constantBuffers.variables.size()) {
390 LOG_ERROR(logger, "Key %d out of range.", key);
391 return false;
392 }
393
394 auto & materialProperty = material->constantBuffers.variables[key];
395
396 if (materialProperty.isPerInstance) {
397 std::memcpy(value, buffers[materialProperty.buffer].content.data() + materialProperty.descriptor.offset, sizeInBytes);
398 }
399 else {
400 std::memcpy(value, material->constantBuffers.buffers[materialProperty.buffer].content.data() + materialProperty.descriptor.offset, sizeInBytes);
401 }
402
403
404 if (materialProperty.flags != MaterialPropertyFlags::None) {
405 reversePropertyFlags(materialProperty, materialProperty.flags, value, sizeInBytes);
406 }
407
408 return true;
409}
410
412{
413 if (VariableKey key = material->getTextureKey(name); key != NoProperty) {
414
415 switch (addressMode.hashLowercase()) {
416 case Cogs::hash("clamp"):
417 case Cogs::hash("clamptoedge"): // GL name
418 setTextureAddressMode(key, SamplerState::Clamp);
419 break;
420
421 case Cogs::hash("wrap"):
422 case Cogs::hash("repeat"): // GL name
423 setTextureAddressMode(key, SamplerState::Wrap);
424 break;
425
426 case Cogs::hash("mirror"):
427 case Cogs::hash("mirrorrepeat"): // GL name
428 setTextureAddressMode(key, SamplerState::Mirror);
429 break;
430
431 case Cogs::hash("border"):
432 case Cogs::hash("clamptoborder"): // GL name
433 setTextureAddressMode(key, SamplerState::Border);
434 break;
435
436 default:
437 LOG_WARNING_ONCE(logger, "Unrecognized address mode '%.*s'", StringViewFormat(addressMode));
438 break;
439 }
440 }
441}
442
444{
445 if (VariableKey key = material->getTextureKey(name); key != NoProperty) {
446 switch (filterMode.hashLowercase()) {
447
448 case Cogs::hash("point"):
449 case Cogs::hash("minmagmippoint"):
450 setTextureFilterMode(key, SamplerState::FilterMode::MinMagMipPoint);
451 break;
452
453 case Cogs::hash("linear"):
454 case Cogs::hash("minmagmiplinear"):
455 setTextureFilterMode(key, SamplerState::FilterMode::MinMagMipLinear);
456 break;
457
458 case Cogs::hash("comparisonpoint"):
459 case Cogs::hash("comparisonminmagmiploint"):
461 break;
462
463 case Cogs::hash("comparisonlinear"):
464 case Cogs::hash("comparisonminmagmiplinear"):
466 break;
467
468 default:
469 LOG_WARNING_ONCE(logger, "Unrecognized filter mode '%.*s'", StringViewFormat(filterMode));
470 break;
471 }
472 }
473}
474
476{
477 setTextureProperty(material->getTextureKey(key), value);
478}
479
481{
482 if (key == NoProperty) {
483 LOG_ERROR(logger, "Cannot set texture property with invalid key.");
484 return;
485 }
486
487 auto & textureVariable = textureVariables[key];
488
489 if (value != textureVariable.texture.handle) {
490 textureVariable.texture.handle = value;
491 textureVariable.dirty = true;
492
493 setChanged();
494 }
495}
496
498{
499 setTextureAddressMode(key, mode, mode, mode);
500}
501
503{
504 if (key == NoProperty) {
505 LOG_ERROR(logger, "Cannot set texture property with invalid key.");
506 return;
507 }
508
509 auto & textureVariable = textureVariables[key];
510
511 if (sMode != textureVariable.texture.sMode || tMode != textureVariable.texture.tMode || uMode != textureVariable.texture.uMode) {
512 textureVariable.texture.sMode = sMode;
513 textureVariable.texture.tMode = tMode;
514 textureVariable.texture.uMode = uMode;
515 textureVariable.dirty = true;
516
517 setChanged();
518 }
519}
520
522{
523 if (key == NoProperty) {
524 LOG_ERROR(logger, "Cannot set texture property with invalid key.");
525 return;
526 }
527
528 TextureValue& textureVariable = textureVariables[key];
529 if (textureVariable.texture.filterMode != filterMode) {
530 textureVariable.texture.filterMode = filterMode;
531 setChanged();
532 }
533}
534
535
536size_t Cogs::Core::MaterialInstance::getPermutationIndex(const StringView & key) const
537{
538 for (size_t i = 0; i < material->permutationKeys.size(); ++i) {
539 if (key == material->permutationKeys[i]) {
540 return i;
541 }
542 }
543
544 return 0;
545}
546
547void Cogs::Core::MaterialInstance::setPermutation(const StringView & key)
548{
549 size_t ix = getPermutationIndex(key);
550 if (permutationIndex == ix) return; // No change
551
552 // Update permutation index
553 permutationIndex = ix;
554
555 // Initialize variant selectors to be used with new permutation
556 const MaterialDefinition& definition = material->definition.permutations[permutationIndex];
557 const ShaderVariants& variants = definition.variants;
558
559 variantSelectors.resize(variants.size());
560 for (auto& v : variants) {
561 variantSelectors[v.index].index = v.index;
562 variantSelectors[v.index].value = v.defaultValue;
563 }
564 variantGeneration++;
565 setChanged();
566}
567
568Cogs::StringView Cogs::Core::MaterialInstance::getPermutation() const
569{
570 return material->permutationKeys[permutationIndex];
571}
572
573void Cogs::Core::MaterialInstance::setVariant(size_t index, bool value)
574{
575 setVariantImpl(this, index, ShaderVariantType::Bool, value ? 1 : 0);
576}
577
578void Cogs::Core::MaterialInstance::setVariant(size_t index, int value)
579{
580 setVariantImpl(this, index, ShaderVariantType::Int, size_t(value));
581}
582
583void Cogs::Core::MaterialInstance::setVariant(size_t index, const StringView & value)
584{
585 assert(index < material->definition.variants.size());
586 const ShaderVariantDefinition& variantDefinition = material->definition.variants[index];
587 switch (variantDefinition.type) {
588 case ShaderVariantType::None:
589 if (!value.empty()) {
590 LOG_ERROR(logger, "Trying to set variant %s with no type to '%.*s'.", variantDefinition.name.c_str(), StringViewFormat(value));
591 }
592 break;
593
594 case ShaderVariantType::Bool:
595 if (bool val = false; parseBool_(val, value)) {
596 setVariantImpl(this, variantDefinition, ShaderVariantType::Bool, val ? 1 : 0);
597 }
598 break;
599
600 case ShaderVariantType::Int:
601 if (int val = 0; parseInt_(val, value)) {
602 setVariantImpl(this, variantDefinition, ShaderVariantType::Int, val);
603 }
604 break;
605
606 case ShaderVariantType::Format:
607 if (Cogs::DataFormat format = Cogs::parseDataFormat(value); format != Cogs::DataFormat::Unknown) {
608 setVariantImpl(this, variantDefinition, ShaderVariantType::Format, size_t(format));
609 }
610 else {
611 LOG_ERROR(logger, "Failed to parse data format \"%.*s\"", StringViewFormat(value));
612 }
613 break;
614
615 case ShaderVariantType::Enum:
616 for (const ShaderVariantEnum& e : variantDefinition.values) {
617 if (value == e.key) {
618 setVariantImpl(this, variantDefinition, Cogs::Core::ShaderVariantType::Enum, e.index);
619 return;
620 }
621 }
622 LOG_ERROR(logger, "Unrecognized enum value '%.*s'", StringViewFormat(value));
623 break;
624
625 case ShaderVariantType::String:
626 for (size_t strIx = 0, strCnt = variantStrings.size(); strIx < strCnt; strIx++) {
627 if (variantStrings[strIx] == value) {
628 setVariantImpl(this, variantDefinition, Cogs::Core::ShaderVariantType::String, strIx);
629 return;
630 }
631 }
632 setVariantImpl(this, variantDefinition, Cogs::Core::ShaderVariantType::String, variantStrings.size());
633 variantStrings.emplace_back(value.begin(), value.end());
634 break;
635
636 default:
637 assert(false && "Invalid ShaderVariantType enum value");
638 break;
639 }
640}
641
642void Cogs::Core::MaterialInstance::setVariant(const StringView& key, bool value)
643{
644 if (size_t index; lookupVariantIndex(this, index, key)) {
645 setVariant(index, value);
646 }
647}
648
649void Cogs::Core::MaterialInstance::setVariant(const StringView& key, int value)
650{
651 if (size_t index; lookupVariantIndex(this, index, key)) {
652 setVariant(index, value);
653 }
654}
655
656void Cogs::Core::MaterialInstance::setVariant(const StringView& key, const StringView& value)
657{
658 if (size_t index; lookupVariantIndex(this, index, key)) {
659 setVariant(index, value);
660 }
661}
662
663std::string Cogs::Core::MaterialInstance::getVariant(const StringView& key) const
664{
665 size_t index;
666 if (!lookupVariantIndex(this, index, key)) {
667 return std::string();
668 }
669 assert(index < material->definition.variants.size());
670 const ShaderVariantDefinition& definition = material->definition.variants[index];
671
672 size_t value = lookupVariantValue(this, definition);
673
674 switch (definition.type) {
675 case ShaderVariantType::None:
676 return std::string();
677
678 case ShaderVariantType::Bool:
679 return value ? "true" : "false";
680
681 case ShaderVariantType::Int:
682 return std::to_string(int(value));
683
684 case ShaderVariantType::Format:
685 if (const Cogs::FormatInfo* info = Cogs::getFormatInfo(Cogs::Format(value)); info) {
686 return info->vName;
687 }
688 LOG_ERROR(logger, "Variant '%.*s' has invalid format enum %zd", StringViewFormat(key), value);
689 break;
690
691 case ShaderVariantType::Enum:
692 for (const ShaderVariantEnum& e : definition.values) {
693 if (value == e.index) {
694 return e.key;
695 }
696 }
697 LOG_ERROR(logger, "Variant '%.*s' contains illegal enum index %zd", StringViewFormat(key), value);
698 break;
699
700 case ShaderVariantType::String:
701 if (value < variantStrings.size()) {
702 return variantStrings[value];
703 }
704 LOG_ERROR(logger, "Variant '%.*s' contains illegal string index %zd", StringViewFormat(key), value);
705 break;
706
707 default:
708 assert(false && "Invalid ShaderVariantType enum value");
709 break;
710 }
711
712 return std::string();
713}
Log implementation class.
Definition: LogManager.h:139
Provides a weakly referenced view over the contents of a string.
Definition: StringView.h:24
constexpr iterator begin() noexcept
Iterator to the beginning of the string.
Definition: StringView.h:100
constexpr iterator end() noexcept
Iterator to the end of the string.
Definition: StringView.h:103
constexpr bool empty() const noexcept
Check if the string is empty.
Definition: StringView.h:122
size_t hashLowercase(size_t hashValue=Cogs::hash()) const noexcept
Get the hash code of the string converted to lowercase.
Definition: StringView.cpp:13
Contains the Engine, Renderer, resource managers and other systems needed to run Cogs....
bool HandleIsValid(const ResourceHandle_t< T > &handle)
Check if the given resource is valid, that is not equal to NoHandle or InvalidHandle.
bool parseBool_(bool &rv, const StringView &token)
Parse a bool putting return value in rv and returning whether or not parsing was successful.
Definition: Parsing.cpp:538
bool parseInt_(int32_t &rv, const StringView &token)
Parse an int putting return value in rv and returning whether or not parsing was successful.
Definition: Parsing.cpp:559
uint16_t VariableKey
Used to lookup material properties.
Definition: Resources.h:46
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 setChanged(Cogs::Core::Context *context, Cogs::ComponentModel::Component *component, Reflection::FieldId fieldId)
Must be Called after changing a Component field. Mark field changed. Request engine update.
Definition: FieldSetter.h:25
std::vector< MaterialPropertyBuffer > buffers
Constant buffer instances.
std::vector< MaterialProperty > variables
Individual variables from all buffer instances.
@ MasterTransparency
Material contains transparency.
Definition: Material.h:47
Material instances represent a specialized Material combined with state for all its buffers and prope...
std::vector< TextureValue > textureVariables
Texture property values for this instance.
bool hasTransparency() const
Get if this instance has any transparency and should be rendered with blending enabled.
int cloneMatchingProperties(MaterialInstance *instance)
Clones matching property values from the given instance.
void setTransparent()
Set the material instance to transparent, indicating to the renderer that blending should be enabled ...
void cloneMatchingVariants(MaterialInstance *instance)
Clones matching varient values from the given instance.
bool getBoolProperty(const VariableKey key) const
Get the value of the property with the given key.
void setupInstance(Material *material)
Setup the material instance from the given material.
TextureValue getTextureProperty(const VariableKey key) const
Get the value of the property with the given key.
std::vector< MaterialPropertyBufferInstance > buffers
Buffer instances matching the buffers and layout of the parent material.
void reset()
Reset the material instance properties.
std::vector< std::string > variantStrings
String storage for string variants.
void setOption(const StringView &key, const StringView &value)
Sets the option with the given key to a value parsed from the value string.
size_t variantGeneration
If the variant or definitions need updates.
void setTextureAddressMode(const StringView &key, const StringView &addressMode)
Set texture address mode with textual name.
void clone(MaterialInstance *instance)
Clone the the given material instance.
MaterialInstanceHandle masterInstance
Master material instance overriding properties in this instance if override is enabled.
void setTextureProperty(const StringView &key, TextureHandle value)
Set the texture property with the given key to the texture resource held by value.
void setTextureFilterMode(const StringView &key, const StringView &filterMode)
Set texture filter mode with textual name.
MaterialOptions options
Material rendering options used by this instance.
size_t permutationIndex
Index of material permutation to use.
Material * material
Material resource this MaterialInstance is created from.
ShaderVariantSelectors variantSelectors
Variant selectors.
uint16_t instanceFlags
Material instance flags.
void setOpaque()
Set the material instance to opaque, indicating to the renderer that blending should be disabled for ...
Material property buffer instances are created from MaterialPropertyBuffers, and have the same set of...
Defines a single material property.
MaterialDataType type
Type of data held by property.
Material resources define the how of geometry rendering (the what is defined by Mesh and Texture reso...
Definition: Material.h:82
MaterialOptions options
Material rendering options.
Definition: Material.h:383
Property value for texture samplers.
TextureWithSampler texture
Value of the property for the material instance this belongs to.
SamplerState::FilterMode filterMode
Filter mode to use when rendering with this texture.
TextureHandle handle
Handle to a texture resource, or TextureHandle::NoHandle if texture should be disabled.
AddressMode
Addressing modes to use when sampling textures.
Definition: SamplerState.h:15
@ Clamp
Texture coordinates are clamped to the [0, 1] range.
Definition: SamplerState.h:17
@ Border
Texture color is set to the border color when outside [0, 1] range.
Definition: SamplerState.h:23
@ Wrap
Texture coordinates automatically wrap around to [0, 1] range.
Definition: SamplerState.h:19
@ Mirror
Texture coordinates are mirrored when outside [0, 1] range.
Definition: SamplerState.h:21
FilterMode
Filter modes to specify how texture data is treated when sampled.
Definition: SamplerState.h:31
@ ComparisonMinMagMipPoint
Comparison filter for depth sample comparisons using point sampling.
Definition: SamplerState.h:38
@ ComparisonMinMagMipLinear
Comparison filter for depth sample comparisons using linear interpolation sampling.
Definition: SamplerState.h:40
@ MinMagMipPoint
Point sampling for both minification and magnification.
Definition: SamplerState.h:33
@ MinMagMipLinear
Linear sampling for both minification and magnification.
Definition: SamplerState.h:35