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