1//************************************ bs::framework - Copyright 2018 Marko Pintera **************************************//
2//*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********//
3#pragma once
4
5#include "BsCorePrerequisites.h"
6#include "Resources/BsResource.h"
7#include "Resources/BsIResourceListener.h"
8#include "Material/BsMaterialParam.h"
9#include "Material/BsMaterialParams.h"
10#include "Material/BsTechnique.h"
11#include "Animation/BsAnimationCurve.h"
12#include "Math/BsVector2.h"
13#include "Math/BsVector3.h"
14#include "Math/BsVector4.h"
15#include "Math/BsMatrix3.h"
16#include "Math/BsMatrix4.h"
17
18namespace bs
19{
20 template<class T>
21 class TAnimationCurve;
22 class ColorGradient;
23
24 /** @addtogroup Implementation
25 * @{
26 */
27
28 /** Flags that signal in what way did the Material change. */
29 enum class MaterialDirtyFlags
30 {
31 /** Material parameter changed. */
32 Param = 1 << 0,
33 /** Dependant resource has been loaded and/or changed. (e.g. a texture assigned to a parameter. */
34 ParamResource = 1 << 1,
35 /** Material shader has changed. */
36 Shader = 2 << 2
37 };
38
39 /** Structure used when searching for a specific technique in a Material. */
40 struct FIND_TECHNIQUE_DESC
41 {
42 static constexpr UINT32 MAX_NUM_TAGS = 10;
43
44 /** A set of tags that the technique must have. */
45 StringID tags[MAX_NUM_TAGS];
46
47 /** Number of valid tags in the @p tags array. */
48 UINT32 numTags = 0;
49
50 /** Specified variation of the technique. Parameters not specified in the variation are assumed to be irrelevant. */
51 const ShaderVariation* variation = nullptr;
52
53 /**
54 * Determines should the parameters in @p variation override any parameters that might have been defined on the
55 * Material itself. If false then you are guaranteed to search only over the subset of techniques that match the
56 * Material's internal variaton parameters. If true then you can search outside that range by setting a variation
57 * parameter to some different value. Overriding can be useful for renderers which might need to override the user's
58 * choice of variation.
59 */
60 bool override = false;
61
62 /** Registers a new tag to look for when searching for the technique. */
63 void addTag(const StringID& tag)
64 {
65 BS_ASSERT(numTags < MAX_NUM_TAGS);
66
67 tags[numTags] = tag;
68 numTags++;
69 }
70 };
71
72 /**
73 * Material that controls how objects are rendered. It is represented by a shader and parameters used to set up that
74 * shader. It provides a simple interface for manipulating the parameters.
75 */
76 class BS_CORE_EXPORT MaterialBase
77 {
78 public:
79 /** Data used to describe a structure defined within a shader. */
80 struct StructData
81 {
82 StructData()
83 :data(nullptr), size(0)
84 { }
85
86 StructData(UINT32 _size)
87 :size(_size)
88 {
89 data = std::shared_ptr<void>(bs_alloc(_size), (void(*)(void*))&bs_free);
90 }
91
92 /**
93 * Writes the specified data to the internal buffer. Caller must ensure size of the provided buffer is correct.
94 */
95 void write(void* _data)
96 {
97 memcpy(data.get(), _data, size);
98 }
99
100 SPtr<void> data;
101 UINT32 size;
102 };
103
104 MaterialBase() = default;
105 virtual ~MaterialBase() = default;
106
107 /** @name Internal
108 * @{
109 */
110
111 /** Marks the contents of the sim thread object as dirty, causing it to sync with its core thread counterpart. */
112 virtual void _markCoreDirty(MaterialDirtyFlags flags = MaterialDirtyFlags::Param) { }
113
114 /** @copydoc CoreObject::markDependenciesDirty */
115 virtual void _markDependenciesDirty() { }
116
117 /** @copydoc IResourceListener::markListenerResourcesDirty */
118 virtual void _markResourcesDirty() { }
119
120 /** @} */
121 };
122
123 /** @copydoc MaterialBase */
124 template<bool Core>
125 class BS_CORE_EXPORT TMaterial : public MaterialBase
126 {
127 public:
128 using TextureType = CoreVariantHandleType<Texture, Core>;
129 using SpriteTextureType = CoreVariantHandleType<SpriteTexture, Core>;
130 using BufferType = SPtr<CoreVariantType<GpuBuffer, Core>>;
131 using SamplerStateType = SPtr<CoreVariantType<SamplerState, Core>>;
132 using GpuProgramPtrType = SPtr<CoreVariantType<GpuProgram, Core>>;
133 using PassType = CoreVariantType<Pass, Core>;
134 using TechniqueType = CoreVariantType<Technique, Core>;
135 using ShaderType = CoreVariantHandleType<Shader, Core>;
136 using GpuParamsSetType = CoreVariantType<GpuParamsSet, Core>;
137 using MaterialParamsType = CoreVariantType<MaterialParams, Core>;
138
139 TMaterial() = default;
140 virtual ~TMaterial() = default;
141
142 /** Returns the currently active shader. */
143 BS_SCRIPT_EXPORT(n:Shader,pr:getter)
144 ShaderType getShader() const { return mShader; }
145
146 /**
147 * Set of parameters that determine which subset of techniques in the assigned shader should be used. Only the
148 * techniques that have the provided parameters with the provided values will match. This will control which
149 * technique is considered the default technique and which subset of techniques are searched during a call to
150 * findTechnique().
151 */
152 BS_SCRIPT_EXPORT(n:Variation,pr:getter)
153 const ShaderVariation& getVariation() const { return mVariation; }
154
155 /** Returns the total number of techniques supported by this material. */
156 UINT32 getNumTechniques() const { return (UINT32)mTechniques.size(); }
157
158 /** Returns the technique at the specified index. */
159 const SPtr<TechniqueType>& getTechnique(UINT32 idx) const { return mTechniques[idx]; }
160
161 /**
162 * Attempts to find a technique matching the specified variation and tags among the supported techniques.
163 *
164 * @param[in] desc Object containing an optional set of tags and a set of variation parameters to
165 * look for.
166 * @return First technique that matches the tags & variation parameters specified in
167 * @p desc.
168 */
169 UINT32 findTechnique(const FIND_TECHNIQUE_DESC& desc) const;
170
171 /**
172 * Finds the index of the default (primary) technique to use. This will be the first technique that matches the
173 * currently set variation parameters (if any).
174 */
175 UINT32 getDefaultTechnique() const;
176
177 /**
178 * Returns the number of passes that are used by the technique at the specified index.
179 *
180 * @param[in] techniqueIdx Index of the technique to retrieve the number of passes for. 0 is always guaranteed
181 * to be the default technique.
182 * @return Number of passes used by the technique.
183 */
184 UINT32 getNumPasses(UINT32 techniqueIdx = 0) const;
185
186 /**
187 * Retrieves a specific shader pass from the provided technique.
188 *
189 * @param[in] passIdx Sequential index of the pass to retrieve.
190 * @param[in] techniqueIdx Index of the technique to retrieve the pass for. 0 is always guaranteed to be
191 * the default technique.
192 * @return Pass if found, null otherwise.
193 */
194 SPtr<PassType> getPass(UINT32 passIdx = 0, UINT32 techniqueIdx = 0) const;
195
196 /**
197 * Creates a set of GpuParams that may be used for binding material parameters to the GPU. The expected behaviour
198 * is to create a set of GpuParams per-technique once, and then before binding them to the GPU call
199 * updateParamsSet() to ensure any dirty parameters are transfered from the material to GpuParams. You may also
200 * use the parameter set to manually modify parameters on a per-program basis, in which case no further updates from
201 * the material are necessary.
202 */
203 SPtr<GpuParamsSetType> createParamsSet(UINT32 techniqueIdx = 0);
204
205 /**
206 * Copies internal material parameter data to the provided params set.
207 *
208 * @param[in] paramsSet Parameter set to update.
209 * @param[in] t Time to evaluate animated parameters at (if any are present).
210 * @param[in] updateAll Normally the system will track dirty parameters since the last call to this method
211 * (on a per-set basis), and only update the dirty ones. Set this to true if you want
212 * to force all parameters to update, regardless of their dirty state.
213 */
214 void updateParamsSet(const SPtr<GpuParamsSetType>& paramsSet, float t = 0.0f, bool updateAll = false);
215
216 /**
217 * Assigns a float value to the shader parameter with the specified name.
218 *
219 * Optionally if the parameter is an array you may provide an array index to assign the value to.
220 */
221 BS_SCRIPT_EXPORT()
222 void setFloat(const String& name, float value, UINT32 arrayIdx = 0) { return getParamFloat(name).set(value, arrayIdx); }
223
224 /*
225 * Assigns a curve to the the float shader parameter with the specified name. The system will automatically
226 * evaluate the curve with the passage of time and apply the evaluated value to the parameter.
227 *
228 * Optionally if the parameter is an array you may provide an array index to assign the value to.
229 */
230 BS_SCRIPT_EXPORT()
231 void setFloatCurve(const String& name, TAnimationCurve<float> value, UINT32 arrayIdx = 0)
232 { return getParamFloatCurve(name).set(std::move(value), arrayIdx); }
233
234 /**
235 * Assigns a color to the shader parameter with the specified name.
236 *
237 * Optionally if the parameter is an array you may provide an array index to assign the value to.
238 */
239 BS_SCRIPT_EXPORT()
240 void setColor(const String& name, const Color& value, UINT32 arrayIdx = 0) { return getParamColor(name).set(value, arrayIdx); }
241
242 /**
243 * Assigns a color gradient to the shader parameter with the specified name. The system will automatically
244 * evaluate the gradient with the passage of time and apply the evaluated value to the parameter.
245 *
246 * Optionally if the parameter is an array you may provide an array index to assign the value to.
247 */
248 BS_SCRIPT_EXPORT()
249 void setColorGradient(const String& name, const ColorGradient& value, UINT32 arrayIdx = 0)
250 { return getParamColorGradient(name).set(value, arrayIdx); }
251
252 /**
253 * Assigns a 2D vector to the shader parameter with the specified name.
254 *
255 * Optionally if the parameter is an array you may provide an array index to assign the value to.
256 */
257 BS_SCRIPT_EXPORT(n:SetVector2)
258 void setVec2(const String& name, const Vector2& value, UINT32 arrayIdx = 0) { return getParamVec2(name).set(value, arrayIdx); }
259
260 /**
261 * Assigns a 3D vector to the shader parameter with the specified name.
262 *
263 * Optionally if the parameter is an array you may provide an array index to assign the value to.
264 */
265 BS_SCRIPT_EXPORT(n:SetVector3)
266 void setVec3(const String& name, const Vector3& value, UINT32 arrayIdx = 0) { return getParamVec3(name).set(value, arrayIdx); }
267
268 /**
269 * Assigns a 4D vector to the shader parameter with the specified name.
270 *
271 * Optionally if the parameter is an array you may provide an array index to assign the value to.
272 */
273 BS_SCRIPT_EXPORT(n:SetVector4)
274 void setVec4(const String& name, const Vector4& value, UINT32 arrayIdx = 0) { return getParamVec4(name).set(value, arrayIdx); }
275
276 /**
277 * Assigns a 3x3 matrix to the shader parameter with the specified name.
278 *
279 * Optionally if the parameter is an array you may provide an array index to assign the value to.
280 */
281 BS_SCRIPT_EXPORT(n:SetMatrix3)
282 void setMat3(const String& name, const Matrix3& value, UINT32 arrayIdx = 0) { return getParamMat3(name).set(value, arrayIdx); }
283
284 /**
285 * Assigns a 4x4 matrix to the shader parameter with the specified name.
286 *
287 * Optionally if the parameter is an array you may provide an array index to assign the value to.
288 */
289 BS_SCRIPT_EXPORT(n:SetMatrix4)
290 void setMat4(const String& name, const Matrix4& value, UINT32 arrayIdx = 0) { return getParamMat4(name).set(value, arrayIdx); }
291
292 /**
293 * Assigns a structure to the shader parameter with the specified name.
294 *
295 * Structure is provided as a raw buffer and caller must ensure structure in buffer matches what the shader expects.
296 *
297 * Optionally if the parameter is an array you may provide an array index to assign the value to.
298 */
299 void setStructData(const String& name, void* value, UINT32 size, UINT32 arrayIdx = 0) { return getParamStruct(name).set(value, size, arrayIdx); }
300
301 /** Assigns a texture to the shader parameter with the specified name. */
302 void setTexture(const String& name, const TextureType& value, const TextureSurface& surface = TextureSurface::COMPLETE)
303 {
304 return getParamTexture(name).set(value, surface);
305 }
306
307 /**
308 * Assigns a sprite texture to the shader parameter with the specified name. If the sprite texture contains
309 * animation it will be automatically evaluated every frame.
310 *
311 * @note
312 * In order for the sprite sub-image to be properly applied the shader needs to have a 4D vector parameter marked
313 * with the SpriteUV attribute referencing this parameter. This vector will then receive the necessary UV offset
314 * and size which should be utilized by the shader code to render a subset of the texture as defined in the sprite
315 * texture.
316 */
317 void setSpriteTexture(const String& name, const SpriteTextureType& value)
318 {
319 return getParamSpriteTexture(name).set(value);
320 }
321
322 /** Assigns a texture to be used for random load/store operations to the shader parameter with the specified name. */
323 void setLoadStoreTexture(const String& name, const TextureType& value, const TextureSurface& surface)
324 {
325 return getParamLoadStoreTexture(name).set(value, surface);
326 }
327
328 /** Assigns a buffer to the shader parameter with the specified name. */
329 void setBuffer(const String& name, const BufferType& value) { return getParamBuffer(name).set(value); }
330
331 /** Assigns a sampler state to the shader parameter with the specified name. */
332 void setSamplerState(const String& name, const SamplerStateType& value) { return getParamSamplerState(name).set(value); }
333
334 /**
335 * Returns a float value assigned with the parameter with the specified name. If a curve is assigned to this
336 * parameter, returns the curve value evaluated at time 0. Use getBoundParamType() to determine
337 * the type of the parameter.
338 *
339 * Optionally if the parameter is an array you may provide an array index you which to retrieve.
340 */
341 BS_SCRIPT_EXPORT()
342 float getFloat(const String& name, UINT32 arrayIdx = 0) const { return getParamFloat(name).get(arrayIdx); }
343
344 /**
345 * Returns a curve value assigned to the parameter with the specified name. If the parameter has a constant
346 * value bound instead of a curve then this method returns an empty curve. Use getBoundParamType() to determine
347 * the type of the parameter.
348 *
349 * Optionally if the parameter is an array you may provide an array index you which to retrieve.
350 */
351 BS_SCRIPT_EXPORT()
352 const TAnimationCurve<float>& getFloatCurve(const String& name, UINT32 arrayIdx = 0) const
353 { return getParamFloatCurve(name).get(arrayIdx); }
354
355 /**
356 * Returns a color assigned with the parameter with the specified name. If a color gradient is assigned to this
357 * parameter, returns the gradient color evaluated at time 0. Use getBoundParamType() to determine
358 * the type of the parameter.
359 *
360 * Optionally if the parameter is an array you may provide an array index you which to retrieve.
361 */
362 BS_SCRIPT_EXPORT()
363 Color getColor(const String& name, UINT32 arrayIdx = 0) const { return getParamColor(name).get(arrayIdx); }
364
365 /**
366 * Returns a color gradient assigned with the parameter with the specified name. If the parameter has a constant
367 * value bound instead of a gradient then this method returns an empty gradient. Use getBoundParamType() to
368 * determine the type of the parameter.
369 *
370 * Optionally if the parameter is an array you may provide an array index you which to retrieve.
371 */
372 BS_SCRIPT_EXPORT()
373 const ColorGradient& getColorGradient(const String& name, UINT32 arrayIdx = 0) const
374 { return getParamColorGradient(name).get(arrayIdx); }
375
376 /**
377 * Returns a 2D vector assigned with the parameter with the specified name.
378 *
379 * Optionally if the parameter is an array you may provide an array index you which to retrieve.
380 */
381 BS_SCRIPT_EXPORT(n:GetVector2)
382 Vector2 getVec2(const String& name, UINT32 arrayIdx = 0) const { return getParamVec2(name).get(arrayIdx); }
383
384 /**
385 * Returns a 3D vector assigned with the parameter with the specified name.
386 *
387 * Optionally if the parameter is an array you may provide an array index you which to retrieve.
388 */
389 BS_SCRIPT_EXPORT(n:GetVector3)
390 Vector3 getVec3(const String& name, UINT32 arrayIdx = 0) const { return getParamVec3(name).get(arrayIdx); }
391
392 /**
393 * Returns a 4D vector assigned with the parameter with the specified name.
394 *
395 * Optionally if the parameter is an array you may provide an array index you which to retrieve.
396 */
397 BS_SCRIPT_EXPORT(n:GetVector4)
398 Vector4 getVec4(const String& name, UINT32 arrayIdx = 0) const { return getParamVec4(name).get(arrayIdx); }
399
400 /**
401 * Returns a 3x3 matrix assigned with the parameter with the specified name.
402 *
403 * Optionally if the parameter is an array you may provide an array index you which to retrieve.
404 */
405 BS_SCRIPT_EXPORT(n:GetMatrix3)
406 Matrix3 getMat3(const String& name, UINT32 arrayIdx = 0) const { return getParamMat3(name).get(arrayIdx); }
407
408 /**
409 * Returns a 4x4 matrix assigned with the parameter with the specified name.
410 *
411 * Optionally if the parameter is an array you may provide an array index you which to retrieve.
412 */
413 BS_SCRIPT_EXPORT(n:GetMatrix4)
414 Matrix4 getMat4(const String& name, UINT32 arrayIdx = 0) const { return getParamMat4(name).get(arrayIdx); }
415
416 /**
417 * Checks does the data parameter with the specified name currently contains animated data. This could be
418 * an animation curve or a color gradient.
419 */
420 BS_SCRIPT_EXPORT()
421 bool isAnimated(const String& name, UINT32 arrayIdx = 0);
422
423 /** Returns a texture assigned with the parameter with the specified name. */
424 TextureType getTexture(const String& name) const { return getParamTexture(name).get(); }
425
426 /**
427 * Returns a sprite texture assigned to the parameter with the specified name. If the parameter has a regular
428 * texture attached instead of a sprite texture, null will be returned. Use getBoundParamType() to determine
429 * the type of the parameter.
430 */
431 SpriteTextureType getSpriteTexture(const String& name) const { return getParamSpriteTexture(name).get(); }
432
433 /** Returns a sampler state assigned with the parameter with the specified name. */
434 SamplerStateType getSamplerState(const String& name) const { return getParamSamplerState(name).get(); }
435
436 /**
437 * Returns a buffer representing a structure assigned to the parameter with the specified name.
438 *
439 * Optionally if the parameter is an array you may provide an array index you which to retrieve.
440 */
441 MaterialBase::StructData getStructData(const String& name, UINT32 arrayIdx = 0) const
442 {
443 TMaterialParamStruct<Core> structParam = getParamStruct(name);
444
445 MaterialBase::StructData data(structParam.getElementSize());
446 structParam.get(data.data.get(), structParam.getElementSize(), arrayIdx);
447
448 return data;
449 }
450
451 /**
452 * Returns a handle that allows you to assign a constant value to a floating point parameter. This handle
453 * may be used for more efficiently getting/setting GPU parameter values than calling
454 * Material::get* / Material::set* methods.
455 *
456 * @note
457 * Expected behavior is that you would retrieve this handle when initially constructing the material, and then
458 * use it throughout material lifetime to assign and retrieve parameter values.
459 * @note
460 * If material shader changes this handle will be invalidated.
461 */
462 TMaterialDataParam<float, Core> getParamFloat(const String& name) const
463 {
464 TMaterialDataParam<float, Core> gpuParam;
465 getParam(name, gpuParam);
466
467 return gpuParam;
468 }
469
470 /**
471 * Returns a handle that allows you to assign a time-varying curve to a floating point parameter. This
472 * handle may be used for more efficiently getting/setting GPU parameter values than calling
473 * Material::get* / Material::set* methods.
474 *
475 * @note
476 * Expected behavior is that you would retrieve this handle when initially constructing the material, and then
477 * use it throughout material lifetime to assign and retrieve parameter values.
478 * @note
479 * If material shader changes this handle will be invalidated.
480 */
481 TMaterialCurveParam<float, Core> getParamFloatCurve(const String& name) const;
482
483 /**
484 * Returns a handle that allows you to assign a constant value to a color parameter. This handle may be
485 * used for more efficiently getting/setting GPU parameter values than calling Material::get* / Material::set*
486 * methods.
487 *
488 * @note
489 * Expected behavior is that you would retrieve this handle when initially constructing the material,
490 * and then use it throughout material lifetime to assign and retrieve parameter values.
491 * @note
492 * If material shader changes this handle will be invalidated.
493 */
494 TMaterialDataParam<Color, Core> getParamColor(const String& name) const
495 {
496 TMaterialDataParam<Color, Core> gpuParam;
497 getParam(name, gpuParam);
498
499 return gpuParam;
500 }
501
502 /**
503 * Returns a handle that allows you to assign a time-varying gradient to a color parameter. This handle
504 * may be used for more efficiently getting/setting GPU parameter values than calling
505 * Material::get* / Material::set* methods.
506 *
507 * @note
508 * Expected behavior is that you would retrieve this handle when initially constructing the material,
509 * and then use it throughout material lifetime to assign and retrieve parameter values.
510 * @note
511 * If material shader changes this handle will be invalidated.
512 */
513 TMaterialColorGradientParam<Core> getParamColorGradient(const String& name) const;
514
515 /**
516 * Returns a handle that allows you to assign a constant value to a 2D vector parameter. This handle may be
517 * used for more efficiently getting/setting GPU parameter values than calling Material::get* / Material::set*
518 * methods.
519 *
520 * @note
521 * Expected behavior is that you would retrieve this handle when initially constructing the material, and then
522 * use it throughout material lifetime to assign and retrieve parameter values.
523 * @note
524 * If material shader changes this handle will be invalidated.
525 */
526 TMaterialDataParam<Vector2, Core> getParamVec2(const String& name) const
527 {
528 TMaterialDataParam<Vector2, Core> gpuParam;
529 getParam(name, gpuParam);
530
531 return gpuParam;
532 }
533
534 /**
535 * Returns a handle that allows you to assign a constant value to a 3D vector parameter. This handle may be
536 * used for more efficiently getting/setting GPU parameter values than calling Material::get* / Material::set*
537 * methods.
538 *
539 * @note
540 * Expected behavior is that you would retrieve this handle when initially constructing the material, and then
541 * use it throughout material lifetime to assign and retrieve parameter values.
542 * @note
543 * If material shader changes this handle will be invalidated.
544 */
545 TMaterialDataParam<Vector3, Core> getParamVec3(const String& name) const
546 {
547 TMaterialDataParam<Vector3, Core> gpuParam;
548 getParam(name, gpuParam);
549
550 return gpuParam;
551 }
552
553 /**
554 * Returns a handle that allows you to assign a constant value to a 4D vector parameter. This handle may be
555 * used for more efficiently getting/setting GPU parameter values than calling Material::get* / Material::set*
556 * methods.
557 *
558 * @note
559 * Expected behavior is that you would retrieve this handle when initially constructing the material, and then
560 * use it throughout material lifetime to assign and retrieve parameter values.
561 * @note
562 * If material shader changes this handle will be invalidated.
563 */
564 TMaterialDataParam<Vector4, Core> getParamVec4(const String& name) const
565 {
566 TMaterialDataParam<Vector4, Core> gpuParam;
567 getParam(name, gpuParam);
568
569 return gpuParam;
570 }
571
572 /**
573 * Returns a handle that allows you to assign a constant value to a 3x3 matrix parameter. This handle may be
574 * used for more efficiently getting/setting GPU parameter values than calling Material::get* / Material::set*
575 * methods.
576 *
577 * @note
578 * Expected behavior is that you would retrieve this handle when initially constructing the material, and then
579 * use it throughout material lifetime to assign and retrieve parameter values.
580 * @note
581 * If material shader changes this handle will be invalidated.
582 */
583 TMaterialDataParam<Matrix3, Core> getParamMat3(const String& name) const
584 {
585 TMaterialDataParam<Matrix3, Core> gpuParam;
586 getParam(name, gpuParam);
587
588 return gpuParam;
589 }
590
591 /**
592 * Returns a handle that allows you to assign a constant value to a 4x4 matrix parameter. This handle may be
593 * used for more efficiently getting/setting GPU parameter values than calling Material::get* / Material::set*
594 * methods.
595 *
596 * @note
597 * Expected behavior is that you would retrieve this handle when initially constructing the material, and then
598 * use it throughout material lifetime to assign and retrieve parameter values.
599 * @note
600 * If material shader changes this handle will be invalidated.
601 */
602 TMaterialDataParam<Matrix4, Core> getParamMat4(const String& name) const
603 {
604 TMaterialDataParam<Matrix4, Core> gpuParam;
605 getParam(name, gpuParam);
606
607 return gpuParam;
608 }
609
610 /**
611 * Returns a handle that allows you to assign a structure GPU parameter. This handle may be used for more
612 * efficiently getting/setting GPU parameter values than calling Material::get* / Material::set* methods.
613 *
614 * @note
615 * Expected behavior is that you would retrieve this handle when initially constructing the material, and then
616 * use it throughout material lifetime to assign and retrieve parameter values.
617 * @note
618 * If material shader changes this handle will be invalidated.
619 */
620 TMaterialParamStruct<Core> getParamStruct(const String& name) const;
621
622 /**
623 * Returns a handle that allows you to assign a texture GPU parameter. This handle may be used for more
624 * efficiently getting/setting GPU parameter values than calling Material::get* / Material::set* methods.
625 *
626 * @note
627 * Expected behavior is that you would retrieve this handle when initially constructing the material, and then
628 * use it throughout material lifetime to assign and retrieve parameter values.
629 * @note
630 * If material shader changes this handle will be invalidated.
631 */
632 TMaterialParamTexture<Core> getParamTexture(const String& name) const;
633
634 /**
635 * Returns a handle that allows you to assign a sprite texture GPU parameter. This handle may be used for more
636 * efficiently getting/setting GPU parameter values than calling Material::get* / Material::set* methods.
637 *
638 * @note
639 * Expected behavior is that you would retrieve this handle when initially constructing the material, and then
640 * use it throughout material lifetime to assign and retrieve parameter values.
641 * @note
642 * If material shader changes this handle will be invalidated.
643 */
644 TMaterialParamSpriteTexture<Core> getParamSpriteTexture(const String& name) const;
645
646 /**
647 * Returns a handle that allows you to assign a load-store texture GPU parameter. This handle may be used for more
648 * efficiently getting/setting GPU parameter values than calling Material::get* / Material::set* methods.
649 *
650 * @note
651 * Expected behavior is that you would retrieve this handle when initially constructing the material, and then
652 * use it throughout material lifetime to assign and retrieve parameter values.
653 * @note
654 * If material shader changes this handle will be invalidated.
655 */
656 TMaterialParamLoadStoreTexture<Core> getParamLoadStoreTexture(const String& name) const;
657
658 /**
659 * Returns a handle that allows you to assign a buffer GPU parameter. This handle may be used for more
660 * efficiently getting/setting GPU parameter values than calling Material::get* / Material::set* methods.
661 *
662 * @note
663 * Expected behavior is that you would retrieve this handle when initially constructing the material, and then
664 * use it throughout material lifetime to assign and retrieve parameter values.
665 * @note
666 * If material shader changes this handle will be invalidated.
667 */
668 TMaterialParamBuffer<Core> getParamBuffer(const String& name) const;
669
670 /**
671 * Returns a handle that allows you to assign a sampler state GPU parameter. This handle may be used for more
672 * efficiently getting/setting GPU parameter values than calling Material::get* / Material::set* methods.
673 *
674 * @note
675 * Expected behavior is that you would retrieve this handle when initially constructing the material, and then
676 * use it throughout material lifetime to assign and retrieve parameter values.
677 * @note
678 * If material shader changes this handle will be invalidated.
679 */
680 TMaterialParamSampState<Core> getParamSamplerState(const String& name) const;
681
682 /**
683 * Allows you to retrieve a handle to a parameter that you can then use for quickly setting and retrieving parameter
684 * data. This allows you to set/get parameter data without all the cost of extra lookups otherwise required.
685 *
686 * @note
687 * All of these handles will be invalidated if material shader ever changes. It is up to the caller to keep track
688 * of that.
689 */
690 template <typename T>
691 void getParam(const String& name, TMaterialDataParam<T, Core>& output) const;
692
693 /**
694 * @name Internal
695 * @{
696 */
697
698 /**
699 * Returns an object containg all of material's parameters. Allows the caller to manipulate the parameters more
700 * directly.
701 */
702 SPtr<MaterialParamsType> _getInternalParams() const { return mParams; }
703
704 /** @} */
705 protected:
706 /**
707 * Assigns a value from a raw buffer to the parameter with the specified name. Buffer must be of sizeof(T) *
708 * numElements size and initialized.
709 *
710 * @note Provided parameter must exist, no checking is done.
711 */
712 template <typename T>
713 void setParamValue(const String& name, UINT8* buffer, UINT32 numElements);
714
715 /**
716 * Initializes the material by using the compatible techniques from the currently set shader. Shader must contain
717 * the techniques that matches the current renderer and render system.
718 */
719 void initializeTechniques();
720
721 /** Assigns all the default parameters specified in the shader to the material. */
722 void initDefaultParameters();
723
724 /** Throw an exception if no shader is set, or no acceptable technique was found. */
725 void throwIfNotInitialized() const;
726
727 ShaderType mShader;
728 SPtr<MaterialParamsType> mParams;
729 Vector<SPtr<TechniqueType>> mTechniques;
730 ShaderVariation mVariation;
731 };
732
733 /** @} */
734
735 /** @addtogroup Material
736 * @{
737 */
738
739 /** @copydoc MaterialBase */
740 class BS_CORE_EXPORT BS_SCRIPT_EXPORT(m:Rendering) Material: public Resource, public TMaterial<false>, public IResourceListener
741 {
742 public:
743 ~Material() = default;
744
745 /**
746 * Sets a shader that will be used by the material. Material will be initialized using all compatible techniques
747 * from the shader. Shader must be set before doing any other operations with the material.
748 */
749 BS_SCRIPT_EXPORT(n:Shader,pr:setter)
750 void setShader(const HShader& shader);
751
752 /** @copydoc TMaterial<Core>::getVariation() const */
753 BS_SCRIPT_EXPORT(n:Variation,pr:setter,hide)
754 void setVariation(const ShaderVariation& variation);
755
756 /** Retrieves an implementation of a material usable only from the core thread. */
757 SPtr<ct::Material> getCore() const;
758
759 /** @copydoc CoreObject::initialize */
760 void initialize() override;
761
762 /** Creates a deep copy of the material and returns the new object. */
763 BS_SCRIPT_EXPORT(n:Clone)
764 HMaterial clone();
765
766 /**
767 * Creates a new empty material.
768 *
769 * @note Make sure you call Material::setShader before using it.
770 */
771 BS_SCRIPT_EXPORT(ec:Material)
772 static HMaterial create();
773
774 /** Creates a new material with the specified shader. */
775 BS_SCRIPT_EXPORT(ec:Material)
776 static HMaterial create(const HShader& shader);
777
778 /**
779 * Creates a new material with the specified shader, and a set of parameters that determine which subset of
780 * techniques in the shader should the material use.
781 */
782 static HMaterial create(const HShader& shader, const ShaderVariation& variation);
783
784 /** @name Internal
785 * @{
786 */
787
788 /**
789 * Marks the core data as dirty. This causes the syncToCore() method to trigger the next time objects are synced
790 * between core and sim threads.
791 */
792 void _markCoreDirty(MaterialDirtyFlags flags = MaterialDirtyFlags::Param) override;
793
794 /** @copydoc CoreObject::markDependenciesDirty */
795 void _markDependenciesDirty() override;
796
797 /** @copydoc IResourceListener::markListenerResourcesDirty */
798 void _markResourcesDirty() override;
799
800 /** @} */
801 private:
802 Material();
803 Material(const HShader& shader, const ShaderVariation& variation);
804
805 /** @copydoc CoreObject::createCore */
806 SPtr<ct::CoreObject> createCore() const override;
807
808 /** @copydoc CoreObject::syncToCore */
809 CoreSyncData syncToCore(FrameAlloc* allocator) override;
810
811 /** @copydoc CoreObject::getCoreDependencies */
812 void getCoreDependencies(Vector<CoreObject*>& dependencies) override;
813
814 /** @copydoc IResourceListener::getListenerResources */
815 void getListenerResources(Vector<HResource>& resources) override;
816
817 /** @copydoc IResourceListener::notifyResourceLoaded */
818 void notifyResourceLoaded(const HResource& resource) override;
819
820 /** @copydoc IResourceListener::notifyResourceChanged */
821 void notifyResourceChanged(const HResource& resource) override;
822
823 /** Performs material initialization when all resources are ready. */
824 void initializeIfLoaded();
825
826 /**
827 * Uses the provided list of parameters to try to set every parameter in this material. Parameter whose name, type
828 * or size don't match are ignored and will not be set.
829 */
830 void setParams(const SPtr<MaterialParams>& params);
831
832 /** Creates a new empty material but doesn't initialize it. */
833 static SPtr<Material> createEmpty();
834
835 UINT32 mLoadFlags;
836
837 /************************************************************************/
838 /* RTTI */
839 /************************************************************************/
840
841 public:
842 friend class MaterialRTTI;
843 static RTTITypeBase* getRTTIStatic();
844 RTTITypeBase* getRTTI() const override;
845 };
846
847 /** @} */
848
849 namespace ct
850 {
851 /** @addtogroup Material-Internal
852 * @{
853 */
854
855 /** @copydoc MaterialBase */
856 class BS_CORE_EXPORT Material : public CoreObject, public TMaterial<true>
857 {
858 public:
859 ~Material() = default;
860
861 /** @copydoc bs::Material::setShader */
862 void setShader(const SPtr<Shader>& shader);
863
864 /**
865 * Set of parameters that determine which subset of techniques in the assigned shader should be used. Only the
866 * techniques that have the provided parameters with the provided values will match. This will control which
867 * technique is considered the default technique and which subset of techniques are searched during a call to
868 * findTechnique().
869 */
870 void setVariation(const ShaderVariation& variation);
871
872 /** Creates a new material with the specified shader. */
873 static SPtr<Material> create(const SPtr<Shader>& shader);
874 private:
875 friend class bs::Material;
876
877 Material() = default;
878 Material(const SPtr<Shader>& shader, const ShaderVariation& variation);
879 Material(const SPtr<Shader>& shader, const Vector<SPtr<Technique>>& techniques,
880 const SPtr<MaterialParams>& materialParams, const ShaderVariation& variation);
881
882 /** @copydoc CoreObject::syncToCore */
883 void syncToCore(const CoreSyncData& data) override;
884 };
885
886 /** @} */
887 }
888}
889