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#include "Material/BsMaterialParams.h"
4#include "Private/RTTI/BsMaterialParamsRTTI.h"
5#include "Material/BsShader.h"
6#include "Image/BsTexture.h"
7#include "Image/BsSpriteTexture.h"
8#include "RenderAPI/BsGpuBuffer.h"
9#include "RenderAPI/BsSamplerState.h"
10#include "Image/BsColorGradient.h"
11#include "Animation/BsAnimationCurve.h"
12#include "Allocators/BsPoolAlloc.h"
13
14namespace bs
15{
16 namespace impl
17 {
18 SPtr<ct::Texture> getSpriteTextureAtlas(const SPtr<ct::SpriteTexture>& spriteTexture)
19 {
20 if(spriteTexture)
21 return spriteTexture->getTexture();
22
23 return nullptr;
24 }
25
26 HTexture getSpriteTextureAtlas(const HSpriteTexture& spriteTexture)
27 {
28 if(spriteTexture.isLoaded())
29 return spriteTexture->getTexture();
30
31 return HTexture();
32 }
33 }
34
35 MaterialParamsBase::MaterialParamsBase(
36 const Map<String, SHADER_DATA_PARAM_DESC>& dataParams,
37 const Map<String, SHADER_OBJECT_PARAM_DESC>& textureParams,
38 const Map<String, SHADER_OBJECT_PARAM_DESC>& bufferParams,
39 const Map<String, SHADER_OBJECT_PARAM_DESC>& samplerParams,
40 UINT64 initialParamVersion
41 )
42 : mParamVersion(initialParamVersion)
43 {
44 mDataSize = 0;
45
46 for (auto& param : dataParams)
47 {
48 if(param.second.type == GPDT_UNKNOWN)
49 continue;
50
51 UINT32 arraySize = param.second.arraySize > 1 ? param.second.arraySize : 1;
52 if(param.second.type == GPDT_STRUCT)
53 mNumStructParams += arraySize;
54 else
55 {
56 const GpuParamDataTypeInfo& typeInfo = GpuParams::PARAM_SIZES.lookup[(int)param.second.type];
57 UINT32 paramSize = typeInfo.numColumns * typeInfo.numRows * typeInfo.baseTypeSize;
58
59 mDataSize += arraySize * paramSize;
60 mNumDataParams += arraySize;
61 }
62 }
63
64 mNumTextureParams = (UINT32)textureParams.size();
65 mNumBufferParams = (UINT32)bufferParams.size();
66 mNumSamplerParams = (UINT32)samplerParams.size();
67
68 mDataParamsBuffer = mAlloc.alloc(mDataSize);
69 memset(mDataParamsBuffer, 0, mDataSize);
70
71 mDataParams = (DataParamInfo*)mAlloc.alloc(mNumDataParams * sizeof(DataParamInfo));
72 memset(mDataParams, 0, mNumDataParams * sizeof(DataParamInfo));
73
74 UINT32 dataParamIdx = 0;
75 UINT32 dataBufferIdx = 0;
76 UINT32 structParamIdx = 0;
77
78 for (auto& entry : dataParams)
79 {
80 if(entry.second.type == GPDT_UNKNOWN)
81 continue;
82
83 const auto paramIdx = (UINT32)mParams.size();
84 mParams.push_back(ParamData());
85 mParamLookup[entry.first] = paramIdx;
86
87 ParamData& dataParam = mParams.back();
88
89 const UINT32 arraySize = entry.second.arraySize > 1 ? entry.second.arraySize : 1;
90 dataParam.arraySize = arraySize;
91 dataParam.type = ParamType::Data;
92 dataParam.dataType = entry.second.type;
93 dataParam.version = 1;
94
95 if(entry.second.type == GPDT_STRUCT)
96 {
97 dataParam.index = structParamIdx;
98 structParamIdx += arraySize;
99 }
100 else
101 {
102 dataParam.index = dataParamIdx;
103
104 const GpuParamDataTypeInfo& typeInfo = GpuParams::PARAM_SIZES.lookup[(int)dataParam.dataType];
105 const UINT32 paramSize = typeInfo.numColumns * typeInfo.numRows * typeInfo.baseTypeSize;
106 for (UINT32 i = 0; i < arraySize; i++)
107 {
108 mDataParams[dataParamIdx].offset = dataBufferIdx;
109 mDataParams[dataParamIdx].spriteTextureIdx = (UINT32)-1;
110
111 dataBufferIdx += paramSize;
112 dataParamIdx++;
113 }
114 }
115 }
116
117 UINT32 textureIdx = 0;
118 for (auto& entry : textureParams)
119 {
120 UINT32 paramIdx = (UINT32)mParams.size();
121 mParams.push_back(ParamData());
122 mParamLookup[entry.first] = paramIdx;
123
124 ParamData& dataParam = mParams.back();
125
126 dataParam.arraySize = 1;
127 dataParam.type = ParamType::Texture;
128 dataParam.dataType = GPDT_UNKNOWN;
129 dataParam.index = textureIdx;
130 dataParam.version = 1;
131
132 textureIdx++;
133 }
134
135 UINT32 bufferIdx = 0;
136 for (auto& entry : bufferParams)
137 {
138 UINT32 paramIdx = (UINT32)mParams.size();
139 mParams.push_back(ParamData());
140 mParamLookup[entry.first] = paramIdx;
141
142 ParamData& dataParam = mParams.back();
143
144 dataParam.arraySize = 1;
145 dataParam.type = ParamType::Buffer;
146 dataParam.dataType = GPDT_UNKNOWN;
147 dataParam.index = bufferIdx;
148 dataParam.version = 1;
149
150 bufferIdx++;
151 }
152
153 UINT32 samplerIdx = 0;
154 for (auto& entry : samplerParams)
155 {
156 UINT32 paramIdx = (UINT32)mParams.size();
157 mParams.push_back(ParamData());
158 mParamLookup[entry.first] = paramIdx;
159
160 ParamData& dataParam = mParams.back();
161
162 dataParam.arraySize = 1;
163 dataParam.type = ParamType::Sampler;
164 dataParam.dataType = GPDT_UNKNOWN;
165 dataParam.index = samplerIdx;
166 dataParam.version = 1;
167
168 samplerIdx++;
169 }
170 }
171
172 MaterialParamsBase::~MaterialParamsBase()
173 {
174 for(UINT32 i = 0; i < mNumDataParams; i++)
175 {
176 DataParamInfo& paramInfo = mDataParams[i];
177
178 if (paramInfo.floatCurve)
179 {
180 bs_pool_free(paramInfo.floatCurve);
181 paramInfo.floatCurve = nullptr;
182 }
183
184 if (paramInfo.colorGradient)
185 {
186 bs_pool_free(paramInfo.colorGradient);
187 paramInfo.colorGradient = nullptr;
188 }
189 }
190
191 mAlloc.free(mDataParamsBuffer);
192 mAlloc.free(mDataParams);
193
194 mAlloc.clear();
195 }
196
197 const ColorGradient& MaterialParamsBase::getColorGradientParam(const String& name, UINT32 arrayIdx) const
198 {
199 static ColorGradient EMPTY_GRADIENT;
200
201 const ParamData* param = nullptr;
202 auto result = getParamData(name, ParamType::Data, GPDT_COLOR, arrayIdx, &param);
203 if (result != GetParamResult::Success)
204 return EMPTY_GRADIENT;
205
206 return getColorGradientParam(*param, arrayIdx);
207 }
208
209 void MaterialParamsBase::setColorGradientParam(const String& name, UINT32 arrayIdx, const ColorGradient& input) const
210 {
211 const ParamData* param = nullptr;
212 auto result = getParamData(name, ParamType::Data, GPDT_COLOR, arrayIdx, &param);
213 if (result != GetParamResult::Success)
214 return;
215
216 setColorGradientParam(*param, arrayIdx, input);
217 }
218
219 const ColorGradient& MaterialParamsBase::getColorGradientParam(const ParamData& param, UINT32 arrayIdx) const
220 {
221 const DataParamInfo& paramInfo = mDataParams[param.index + arrayIdx];
222 if (paramInfo.colorGradient)
223 return *paramInfo.colorGradient;
224
225 static ColorGradient EMPTY_GRADIENT;
226 return EMPTY_GRADIENT;
227 }
228
229 void MaterialParamsBase::setColorGradientParam(const ParamData& param, UINT32 arrayIdx, const ColorGradient& input) const
230 {
231 DataParamInfo& paramInfo = mDataParams[param.index + arrayIdx];
232 if (paramInfo.colorGradient)
233 bs_pool_free(paramInfo.colorGradient);
234
235 paramInfo.colorGradient = bs_pool_new<ColorGradient>(input);
236
237 param.version = ++mParamVersion;
238 }
239
240 UINT32 MaterialParamsBase::getParamIndex(const String& name) const
241 {
242 auto iterFind = mParamLookup.find(name);
243 if (iterFind == mParamLookup.end())
244 return (UINT32)-1;
245
246 return iterFind->second;
247 }
248
249 MaterialParamsBase::GetParamResult MaterialParamsBase::getParamIndex(const String& name, ParamType type,
250 GpuParamDataType dataType, UINT32 arrayIdx, UINT32& output) const
251 {
252 auto iterFind = mParamLookup.find(name);
253 if (iterFind == mParamLookup.end())
254 return GetParamResult::NotFound;
255
256 UINT32 index = iterFind->second;
257 const ParamData& param = mParams[index];
258
259 if (param.type != type || (type == ParamType::Data && param.dataType != dataType))
260 return GetParamResult::InvalidType;
261
262 if (arrayIdx >= param.arraySize)
263 return GetParamResult::IndexOutOfBounds;
264
265 output = index;
266 return GetParamResult::Success;
267 }
268
269 MaterialParamsBase::GetParamResult MaterialParamsBase::getParamData(const String& name, ParamType type,
270 GpuParamDataType dataType, UINT32 arrayIdx, const ParamData** output) const
271 {
272 auto iterFind = mParamLookup.find(name);
273 if (iterFind == mParamLookup.end())
274 return GetParamResult::NotFound;
275
276 UINT32 index = iterFind->second;
277 const ParamData& param = mParams[index];
278 *output = &param;
279
280 if (param.type != type || (type == ParamType::Data && param.dataType != dataType))
281 return GetParamResult::InvalidType;
282
283 if (arrayIdx >= param.arraySize)
284 return GetParamResult::IndexOutOfBounds;
285
286 return GetParamResult::Success;
287 }
288
289 void MaterialParamsBase::reportGetParamError(GetParamResult errorCode, const String& name, UINT32 arrayIdx) const
290 {
291 switch (errorCode)
292 {
293 case GetParamResult::NotFound:
294 LOGWRN("Material doesn't have a parameter named " + name + ".");
295 break;
296 case GetParamResult::InvalidType:
297 LOGWRN("Parameter \"" + name + "\" is not of the requested type.");
298 break;
299 case GetParamResult::IndexOutOfBounds:
300 LOGWRN("Parameter \"" + name + "\" array index " + toString(arrayIdx) + " out of range.");
301 break;
302 default:
303 break;
304 }
305 }
306
307 RTTITypeBase* MaterialParamStructData::getRTTIStatic()
308 {
309 return MaterialParamStructDataRTTI::instance();
310 }
311
312 RTTITypeBase* MaterialParamStructData::getRTTI() const
313 {
314 return getRTTIStatic();
315 }
316
317 RTTITypeBase* MaterialParamTextureData::getRTTIStatic()
318 {
319 return MaterialParamTextureDataRTTI::instance();
320 }
321
322 RTTITypeBase* MaterialParamTextureData::getRTTI() const
323 {
324 return getRTTIStatic();
325 }
326
327 template<bool Core>
328 TMaterialParams<Core>::TMaterialParams(const ShaderType& shader, UINT64 initialParamVersion)
329 :MaterialParamsBase(
330 shader->getDataParams(),
331 shader->getTextureParams(),
332 shader->getBufferParams(),
333 shader->getSamplerParams(),
334 initialParamVersion
335 )
336 {
337 mStructParams = mAlloc.construct<ParamStructDataType>(mNumStructParams);
338 mTextureParams = mAlloc.construct<ParamTextureDataType>(mNumTextureParams);
339 mBufferParams = mAlloc.construct<ParamBufferDataType>(mNumBufferParams);
340 mSamplerStateParams = mAlloc.construct<ParamSamplerStateDataType>(mNumSamplerParams);
341 mDefaultTextureParams = mAlloc.construct<TextureType>(mNumTextureParams);
342 mDefaultSamplerStateParams = mAlloc.construct<SamplerType>(mNumSamplerParams);
343
344 auto& textureParams = shader->getTextureParams();
345 UINT32 textureIdx = 0;
346 for (auto& entry : textureParams)
347 {
348 ParamTextureDataType& param = mTextureParams[textureIdx];
349 param.isLoadStore = false;
350
351 if (entry.second.defaultValueIdx != (UINT32)-1)
352 mDefaultTextureParams[textureIdx] = shader->getDefaultTexture(entry.second.defaultValueIdx);
353
354 textureIdx++;
355 }
356
357 auto& samplerParams = shader->getSamplerParams();
358 UINT32 samplerIdx = 0;
359 for (auto& entry : samplerParams)
360 {
361 if (entry.second.defaultValueIdx != (UINT32)-1)
362 mDefaultSamplerStateParams[samplerIdx] = shader->getDefaultSampler(entry.second.defaultValueIdx);
363
364 samplerIdx++;
365 }
366
367 // Note: Make sure to process data parameters after textures, in order to handle SpriteUV data parameters
368 auto& dataParams = shader->getDataParams();
369 auto& paramAttributes = shader->getParamAttributes();
370 UINT32 structIdx = 0;
371 for (auto& entry : dataParams)
372 {
373 if(entry.second.type == GPDT_STRUCT)
374 {
375 UINT32 arraySize = entry.second.arraySize > 1 ? entry.second.arraySize : 1;
376 for (UINT32 i = 0; i < arraySize; i++)
377 {
378 ParamStructDataType& param = mStructParams[structIdx];
379 param.dataSize = entry.second.elementSize;
380 param.data = mAlloc.alloc(param.dataSize);
381
382 structIdx++;
383 }
384 }
385 else
386 {
387 // Check for SpriteUV attribute
388 UINT32 attribIdx = entry.second.attribIdx;
389 while (attribIdx != (UINT32)-1)
390 {
391 const SHADER_PARAM_ATTRIBUTE& attrib = paramAttributes[attribIdx];
392 if (attrib.type == ShaderParamAttributeType::SpriteUV)
393 {
394 // Find referenced texture
395 const auto findIterTex = mParamLookup.find(attrib.value);
396 const auto findIterParam = mParamLookup.find(entry.first);
397 if (findIterTex != mParamLookup.end() && findIterParam != mParamLookup.end())
398 {
399 ParamData& paramData = mParams[findIterParam->second];
400
401 DataParamInfo& dataParamInfo = mDataParams[paramData.index];
402 dataParamInfo.spriteTextureIdx = findIterTex->second;
403 }
404 }
405
406 attribIdx = attrib.nextParamIdx;
407 }
408 }
409 }
410 }
411
412 template<bool Core>
413 TMaterialParams<Core>::~TMaterialParams()
414 {
415 if (mStructParams != nullptr)
416 {
417 for (UINT32 i = 0; i < mNumStructParams; i++)
418 mAlloc.free(mStructParams[i].data);
419 }
420
421 mAlloc.destruct(mStructParams, mNumStructParams);
422 mAlloc.destruct(mTextureParams, mNumTextureParams);
423 mAlloc.destruct(mBufferParams, mNumBufferParams);
424 mAlloc.destruct(mSamplerStateParams, mNumSamplerParams);
425
426 if(mDefaultTextureParams != nullptr)
427 mAlloc.destruct(mDefaultTextureParams, mNumTextureParams);
428
429 if (mDefaultSamplerStateParams != nullptr)
430 mAlloc.destruct(mDefaultSamplerStateParams, mNumSamplerParams);
431 }
432
433 template<bool Core>
434 void TMaterialParams<Core>::getStructData(const String& name, void* value, UINT32 size, UINT32 arrayIdx) const
435 {
436 const ParamData* param = nullptr;
437 GetParamResult result = getParamData(name, ParamType::Data, GPDT_STRUCT, arrayIdx, &param);
438 if (result != GetParamResult::Success)
439 {
440 reportGetParamError(result, name, arrayIdx);
441 return;
442 }
443
444 getStructData(*param, value, size, arrayIdx);
445 }
446
447 template<bool Core>
448 void TMaterialParams<Core>::setStructData(const String& name, const void* value, UINT32 size, UINT32 arrayIdx)
449 {
450 const ParamData* param = nullptr;
451 GetParamResult result = getParamData(name, ParamType::Data, GPDT_STRUCT, arrayIdx, &param);
452 if (result != GetParamResult::Success)
453 {
454 reportGetParamError(result, name, arrayIdx);
455 return;
456 }
457
458 setStructData(*param, value, size, arrayIdx);
459 }
460
461 template<bool Core>
462 void TMaterialParams<Core>::getTexture(const String& name, TextureType& value, TextureSurface& surface) const
463 {
464 const ParamData* param = nullptr;
465 GetParamResult result = getParamData(name, ParamType::Texture, GPDT_UNKNOWN, 0, &param);
466 if (result != GetParamResult::Success)
467 {
468 reportGetParamError(result, name, 0);
469 return;
470 }
471
472 getTexture(*param, value, surface);
473 }
474
475 template<bool Core>
476 void TMaterialParams<Core>::setTexture(const String& name, const TextureType& value, const TextureSurface& surface)
477 {
478 const ParamData* param = nullptr;
479 GetParamResult result = getParamData(name, ParamType::Texture, GPDT_UNKNOWN, 0, &param);
480 if (result != GetParamResult::Success)
481 {
482 reportGetParamError(result, name, 0);
483 return;
484 }
485
486 setTexture(*param, value, surface);
487 }
488
489 template<bool Core>
490 void TMaterialParams<Core>::getSpriteTexture(const String& name, SpriteTextureType& value) const
491 {
492 const ParamData* param = nullptr;
493 GetParamResult result = getParamData(name, ParamType::Texture, GPDT_UNKNOWN, 0, &param);
494 if (result != GetParamResult::Success)
495 {
496 reportGetParamError(result, name, 0);
497 return;
498 }
499
500 getSpriteTexture(*param, value);
501 }
502
503 template<bool Core>
504 void TMaterialParams<Core>::setSpriteTexture(const String& name, const SpriteTextureType& value)
505 {
506 const ParamData* param = nullptr;
507 GetParamResult result = getParamData(name, ParamType::Texture, GPDT_UNKNOWN, 0, &param);
508 if (result != GetParamResult::Success)
509 {
510 reportGetParamError(result, name, 0);
511 return;
512 }
513
514 setSpriteTexture(*param, value);
515 }
516
517 template<bool Core>
518 void TMaterialParams<Core>::getLoadStoreTexture(const String& name, TextureType& value, TextureSurface& surface) const
519 {
520 const ParamData* param = nullptr;
521 GetParamResult result = getParamData(name, ParamType::Texture, GPDT_UNKNOWN, 0, &param);
522 if (result != GetParamResult::Success)
523 {
524 reportGetParamError(result, name, 0);
525 return;
526 }
527
528 getLoadStoreTexture(*param, value, surface);
529 }
530
531 template<bool Core>
532 void TMaterialParams<Core>::setLoadStoreTexture(const String& name, const TextureType& value, const TextureSurface& surface)
533 {
534 const ParamData* param = nullptr;
535 GetParamResult result = getParamData(name, ParamType::Texture, GPDT_UNKNOWN, 0, &param);
536 if (result != GetParamResult::Success)
537 {
538 reportGetParamError(result, name, 0);
539 return;
540 }
541
542 setLoadStoreTexture(*param, value, surface);
543 }
544
545 template<bool Core>
546 void TMaterialParams<Core>::getBuffer(const String& name, BufferType& value) const
547 {
548 const ParamData* param = nullptr;
549 GetParamResult result = getParamData(name, ParamType::Buffer, GPDT_UNKNOWN, 0, &param);
550 if (result != GetParamResult::Success)
551 {
552 reportGetParamError(result, name, 0);
553 return;
554 }
555
556 getBuffer(*param, value);
557 }
558
559 template<bool Core>
560 void TMaterialParams<Core>::setBuffer(const String& name, const BufferType& value)
561 {
562 const ParamData* param = nullptr;
563 GetParamResult result = getParamData(name, ParamType::Buffer, GPDT_UNKNOWN, 0, &param);
564 if (result != GetParamResult::Success)
565 {
566 reportGetParamError(result, name, 0);
567 return;
568 }
569
570 setBuffer(*param, value);
571 }
572
573 template<bool Core>
574 void TMaterialParams<Core>::getSamplerState(const String& name, SamplerType& value) const
575 {
576 const ParamData* param = nullptr;
577 GetParamResult result = getParamData(name, ParamType::Sampler, GPDT_UNKNOWN, 0, &param);
578 if (result != GetParamResult::Success)
579 {
580 reportGetParamError(result, name, 0);
581 return;
582 }
583
584 getSamplerState(*param, value);
585 }
586
587 template<bool Core>
588 void TMaterialParams<Core>::setSamplerState(const String& name, const SamplerType& value)
589 {
590 const ParamData* param = nullptr;
591 GetParamResult result = getParamData(name, ParamType::Sampler, GPDT_UNKNOWN, 0, &param);
592 if(result != GetParamResult::Success)
593 {
594 reportGetParamError(result, name, 0);
595 return;
596 }
597
598 setSamplerState(*param, value);
599 }
600
601 template<bool Core>
602 bool TMaterialParams<Core>::isAnimated(const String& name, UINT32 arrayIdx)
603 {
604 auto iterFind = mParamLookup.find(name);
605 if (iterFind == mParamLookup.end())
606 return false;
607
608 UINT32 index = iterFind->second;
609 const ParamData& param = mParams[index];
610
611 if (param.type != ParamType::Data)
612 return false;
613
614 if (arrayIdx >= param.arraySize)
615 return false;
616
617 return isAnimated(param, arrayIdx);
618 }
619
620 template<bool Core>
621 void TMaterialParams<Core>::getStructData(const ParamData& param, void* value, UINT32 size, UINT32 arrayIdx) const
622 {
623 const ParamStructDataType& structParam = mStructParams[param.index + arrayIdx];
624 if (structParam.dataSize != size)
625 {
626 LOGWRN("Size mismatch when writing to a struct. Provided size was " + toString(size) + " bytes but the "
627 "struct size is" + toString(structParam.dataSize) + " bytes");
628 return;
629 }
630
631 memcpy(value, structParam.data, structParam.dataSize);
632 }
633
634 template<bool Core>
635 void TMaterialParams<Core>::setStructData(const ParamData& param, const void* value, UINT32 size, UINT32 arrayIdx)
636 {
637 const ParamStructDataType& structParam = mStructParams[param.index + arrayIdx];
638 if (structParam.dataSize != size)
639 {
640 LOGWRN("Size mismatch when writing to a struct. Provided size was " + toString(size) + " bytes but the "
641 "struct size is" + toString(structParam.dataSize) + " bytes");
642 return;
643 }
644
645 memcpy(structParam.data, value, structParam.dataSize);
646 param.version = ++mParamVersion;
647 }
648
649 template<bool Core>
650 UINT32 TMaterialParams<Core>::getStructSize(const ParamData& param) const
651 {
652 const ParamStructDataType& structParam = mStructParams[param.index];
653 return structParam.dataSize;
654 }
655
656 template<bool Core>
657 void TMaterialParams<Core>::getTexture(const ParamData& param, TextureType& value, TextureSurface& surface) const
658 {
659 ParamTextureDataType& textureParam = mTextureParams[param.index];
660
661 if(textureParam.texture)
662 value = textureParam.texture;
663 else if(textureParam.spriteTexture)
664 value = impl::getSpriteTextureAtlas(textureParam.spriteTexture);
665
666 surface = textureParam.surface;
667 }
668
669 template<bool Core>
670 void TMaterialParams<Core>::setTexture(const ParamData& param, const TextureType& value, const TextureSurface& surface)
671 {
672 ParamTextureDataType& textureParam = mTextureParams[param.index];
673 textureParam.texture = value;
674 textureParam.spriteTexture = nullptr;
675 textureParam.isLoadStore = false;
676 textureParam.surface = surface;
677
678 param.version = ++mParamVersion;
679 }
680
681 template<bool Core>
682 void TMaterialParams<Core>::getSpriteTexture(const ParamData& param, SpriteTextureType& value) const
683 {
684 ParamTextureDataType& textureParam = mTextureParams[param.index];
685 value = textureParam.spriteTexture;
686 }
687
688 template<bool Core>
689 void TMaterialParams<Core>::setSpriteTexture(const ParamData& param, const SpriteTextureType& value)
690 {
691 ParamTextureDataType& textureParam = mTextureParams[param.index];
692 textureParam.texture = nullptr;
693 textureParam.spriteTexture = value;
694 textureParam.isLoadStore = false;
695 textureParam.surface = TextureSurface::COMPLETE;
696
697 param.version = ++mParamVersion;
698 }
699
700 template<bool Core>
701 void TMaterialParams<Core>::getBuffer(const ParamData& param, BufferType& value) const
702 {
703 value = mBufferParams[param.index].value;
704 }
705
706 template<bool Core>
707 void TMaterialParams<Core>::setBuffer(const ParamData& param, const BufferType& value)
708 {
709 mBufferParams[param.index].value = value;
710
711 param.version = ++mParamVersion;
712 }
713
714 template<bool Core>
715 void TMaterialParams<Core>::getLoadStoreTexture(const ParamData& param, TextureType& value, TextureSurface& surface) const
716 {
717 ParamTextureDataType& textureParam = mTextureParams[param.index];
718 value = textureParam.texture;
719 surface = textureParam.surface;
720 }
721
722 template<bool Core>
723 void TMaterialParams<Core>::setLoadStoreTexture(const ParamData& param, const TextureType& value, const TextureSurface& surface)
724 {
725 ParamTextureDataType& textureParam = mTextureParams[param.index];
726 textureParam.texture = value;
727 textureParam.spriteTexture = nullptr;
728 textureParam.isLoadStore = true;
729 textureParam.surface = surface;
730
731 param.version = ++mParamVersion;
732 }
733
734 template<bool Core>
735 void TMaterialParams<Core>::getSamplerState(const ParamData& param, SamplerType& value) const
736 {
737 value = mSamplerStateParams[param.index].value;
738 }
739
740 template<bool Core>
741 void TMaterialParams<Core>::setSamplerState(const ParamData& param, const SamplerType& value)
742 {
743 mSamplerStateParams[param.index].value = value;
744
745 param.version = ++mParamVersion;
746 }
747
748 template<bool Core>
749 MateralParamTextureType TMaterialParams<Core>::getTextureType(const ParamData& param) const
750 {
751 if(mTextureParams[param.index].isLoadStore)
752 return MateralParamTextureType::LoadStore;
753
754 if(mTextureParams[param.index].spriteTexture)
755 return MateralParamTextureType::Sprite;
756
757 return MateralParamTextureType::Normal;
758 }
759
760 template<bool Core>
761 bool TMaterialParams<Core>::isAnimated(const ParamData& param, UINT32 arrayIdx) const
762 {
763 const DataParamInfo& paramInfo = mDataParams[param.index + arrayIdx];
764
765 return paramInfo.floatCurve || paramInfo.colorGradient || paramInfo.spriteTextureIdx != (UINT32)-1;
766 }
767
768 template<bool Core>
769 typename TMaterialParams<Core>::SpriteTextureType TMaterialParams<Core>::getOwningSpriteTexture(const ParamData& param) const
770 {
771 SpriteTextureType output;
772
773 const DataParamInfo& paramInfo = mDataParams[param.index];
774 if (paramInfo.spriteTextureIdx == (UINT32)-1)
775 return output;
776
777 const ParamData* spriteTexParamData = getParamData(paramInfo.spriteTextureIdx);
778 if(spriteTexParamData)
779 getSpriteTexture(*spriteTexParamData, output);
780
781 return output;
782 }
783
784 template<bool Core>
785 void TMaterialParams<Core>::getDefaultTexture(const ParamData& param, TextureType& value) const
786 {
787 value = mDefaultTextureParams[param.index];
788 }
789
790 template<bool Core>
791 void TMaterialParams<Core>::getDefaultSamplerState(const ParamData& param, SamplerType& value) const
792 {
793 value = mDefaultSamplerStateParams[param.index];
794 }
795
796 template class TMaterialParams<true>;
797 template class TMaterialParams<false>;
798
799 MaterialParams::MaterialParams(const HShader& shader, UINT64 initialParamVersion)
800 :TMaterialParams(shader, initialParamVersion), mLastSyncVersion(1)
801 { }
802
803 void MaterialParams::getSyncData(UINT8* buffer, UINT32& size, bool forceAll)
804 {
805 // Note: Not syncing struct data
806
807 UINT32 numDirtyDataParams = 0;
808 UINT32 numDirtyStructParams = 0;
809 UINT32 numDirtyTextureParams = 0;
810 UINT32 numDirtyBufferParams = 0;
811 UINT32 numDirtySamplerParams = 0;
812
813 UINT32 dataParamSize = 0;
814 UINT32 structParamSize = 0;
815 for(auto& param : mParams)
816 {
817 if (param.version <= mLastSyncVersion && !forceAll)
818 continue;
819
820 switch(param.type)
821 {
822 case ParamType::Data:
823 {
824 const UINT32 arraySize = param.arraySize > 1 ? param.arraySize : 1;
825
826 if(param.dataType == GPDT_STRUCT)
827 {
828 // Param index
829 structParamSize += sizeof(UINT32);
830
831 // Param data
832 structParamSize += arraySize * mStructParams[param.index].dataSize;
833
834 numDirtyStructParams++;
835 }
836 else
837 {
838 const GpuParamDataTypeInfo& typeInfo = GpuParams::PARAM_SIZES.lookup[(int)param.dataType];
839 const UINT32 paramSize = typeInfo.numColumns * typeInfo.numRows * typeInfo.baseTypeSize;
840
841 // Param index
842 dataParamSize += sizeof(UINT32);
843
844 // Param data
845 dataParamSize += arraySize * paramSize;
846
847 // Param curves
848 dataParamSize += sizeof(UINT32);
849 for (UINT32 i = 0; i < arraySize; i++)
850 {
851 const DataParamInfo& paramInfo = mDataParams[param.index + i];
852 if (paramInfo.floatCurve && param.dataType == GPDT_FLOAT1)
853 {
854 // Array index
855 dataParamSize += sizeof(UINT32);
856
857 // Curve data
858 dataParamSize += rttiGetElemSize(*paramInfo.floatCurve);
859 }
860 else if (paramInfo.colorGradient && param.dataType == GPDT_COLOR)
861 {
862 // Array index
863 dataParamSize += sizeof(UINT32);
864
865 // Curve data
866 dataParamSize += rttiGetElemSize(*paramInfo.colorGradient);
867 }
868 }
869
870 numDirtyDataParams++;
871 }
872 }
873 break;
874 case ParamType::Texture:
875 numDirtyTextureParams++;
876 break;
877 case ParamType::Buffer:
878 numDirtyBufferParams++;
879 break;
880 case ParamType::Sampler:
881 numDirtySamplerParams++;
882 break;
883 }
884 }
885
886 const UINT32 textureEntrySize = sizeof(MaterialParamTextureDataCore) + sizeof(UINT32);
887 const UINT32 bufferEntrySize = sizeof(MaterialParamBufferDataCore) + sizeof(UINT32);
888 const UINT32 samplerStateEntrySize = sizeof(MaterialParamSamplerStateDataCore) + sizeof(UINT32);
889
890 const UINT32 dataParamsOffset = sizeof(UINT32) * 5;
891 const UINT32 textureParamsOffset = dataParamsOffset + dataParamSize;
892 const UINT32 bufferParamsOffset = textureParamsOffset + textureEntrySize * numDirtyTextureParams;
893 const UINT32 samplerStateParamsOffset = bufferParamsOffset + bufferEntrySize * numDirtyBufferParams;
894 const UINT32 structParamsOffset = samplerStateParamsOffset + samplerStateEntrySize * numDirtySamplerParams;
895
896 const UINT32 totalSize = structParamsOffset + structParamSize;
897
898 if (buffer == nullptr)
899 {
900 size = totalSize;
901 return;
902 }
903
904 if(size != totalSize)
905 {
906 LOGERR("Invalid buffer size provided, ignoring.");
907 return;
908 }
909
910 char* writeDest = (char*)buffer;
911
912 // Dirty counts for each parameter type
913 writeDest = rttiWriteElem(numDirtyDataParams, writeDest);
914 writeDest = rttiWriteElem(numDirtyTextureParams, writeDest);
915 writeDest = rttiWriteElem(numDirtyBufferParams, writeDest);
916 writeDest = rttiWriteElem(numDirtySamplerParams, writeDest);
917 writeDest = rttiWriteElem(numDirtyStructParams, writeDest);
918
919 UINT32 dirtyDataParamOffset = 0;
920 UINT32 dirtyTextureParamIdx = 0;
921 UINT32 dirtyBufferParamIdx = 0;
922 UINT32 dirtySamplerParamIdx = 0;
923 UINT32 dirtyStructParamOffset = 0;
924
925 for(UINT32 i = 0; i < (UINT32)mParams.size(); i++)
926 {
927 ParamData& param = mParams[i];
928 if (param.version <= mLastSyncVersion && !forceAll)
929 continue;
930
931 switch (param.type)
932 {
933 case ParamType::Data:
934 {
935 const UINT32 arraySize = param.arraySize > 1 ? param.arraySize : 1;
936
937 if (param.dataType == GPDT_STRUCT)
938 {
939 const ParamStructDataType& paramData = mStructParams[param.index];
940
941 writeDest = (char*)buffer + structParamsOffset + dirtyStructParamOffset;
942
943 // Param index
944 writeDest = rttiWriteElem(i, writeDest, dirtyStructParamOffset);
945
946 // Param data
947 for (UINT32 j = 0; j < arraySize; j++)
948 {
949 memcpy(writeDest, mStructParams[param.index + j].data, paramData.dataSize);
950 writeDest += paramData.dataSize;
951 dirtyStructParamOffset += paramData.dataSize;
952 }
953 }
954 else
955 {
956 const GpuParamDataTypeInfo& typeInfo = GpuParams::PARAM_SIZES.lookup[(int)param.dataType];
957 const UINT32 paramSize = typeInfo.numColumns * typeInfo.numRows * typeInfo.baseTypeSize;
958
959 const UINT32 dataSize = arraySize * paramSize;
960 const DataParamInfo& paramInfo = mDataParams[param.index];
961
962 writeDest = (char*)buffer + dataParamsOffset + dirtyDataParamOffset;
963
964 // Param index
965 writeDest = rttiWriteElem(i, writeDest, dirtyDataParamOffset);
966
967 // Param data
968 // Note: This relies on the fact that all data params in the array are sequential
969 memcpy(writeDest, &mDataParamsBuffer[paramInfo.offset], dataSize);
970 writeDest += dataSize;
971 dirtyDataParamOffset += dataSize;
972
973 // Param curves
974 UINT32* numDirtyCurvesWriteDst = (UINT32*)writeDest;
975 writeDest += sizeof(UINT32);
976 dirtyDataParamOffset += sizeof(UINT32);
977
978 UINT32 numDirtyCurves = 0;
979 for (UINT32 j = 0; j < arraySize; j++)
980 {
981 const DataParamInfo& arrParamInfo = mDataParams[param.index + j];
982 if (arrParamInfo.floatCurve && param.dataType == GPDT_FLOAT1)
983 {
984 // Array index
985 writeDest = rttiWriteElem(j, writeDest, dirtyDataParamOffset);
986
987 // Curve data
988 writeDest = rttiWriteElem(*arrParamInfo.floatCurve, writeDest, dirtyDataParamOffset);
989
990 numDirtyCurves++;
991 }
992 else if (arrParamInfo.colorGradient && param.dataType == GPDT_COLOR)
993 {
994 // Array index
995 writeDest = rttiWriteElem(j, writeDest, dirtyDataParamOffset);
996
997 // Curve data
998 writeDest = rttiWriteElem(*arrParamInfo.colorGradient, writeDest, dirtyDataParamOffset);
999
1000 numDirtyCurves++;
1001 }
1002 }
1003
1004 *numDirtyCurvesWriteDst = numDirtyCurves;
1005 }
1006 }
1007 break;
1008 case ParamType::Texture:
1009 {
1010 writeDest = (char*)buffer + textureParamsOffset + dirtyTextureParamIdx * textureEntrySize;
1011 writeDest = rttiWriteElem(i, writeDest);
1012
1013 const MaterialParamTextureData& textureData = mTextureParams[param.index];
1014 MaterialParamTextureDataCore* coreTexData = (MaterialParamTextureDataCore*)writeDest;
1015 new (coreTexData) MaterialParamTextureDataCore();
1016
1017 coreTexData->isLoadStore = textureData.isLoadStore;
1018 coreTexData->surface = textureData.surface;
1019
1020 if (textureData.texture.isLoaded())
1021 coreTexData->texture = textureData.texture->getCore();
1022
1023 if (textureData.spriteTexture.isLoaded())
1024 coreTexData->spriteTexture = textureData.spriteTexture->getCore();
1025
1026 dirtyTextureParamIdx++;
1027 }
1028 break;
1029 case ParamType::Buffer:
1030 {
1031 writeDest = (char*)buffer + bufferParamsOffset + dirtyBufferParamIdx * bufferEntrySize;
1032 writeDest = rttiWriteElem(i, writeDest);
1033
1034 const MaterialParamBufferData& bufferData = mBufferParams[param.index];
1035 MaterialParamBufferDataCore* coreBufferData = (MaterialParamBufferDataCore*)writeDest;
1036 new (coreBufferData) MaterialParamBufferDataCore();
1037
1038 if(bufferData.value != nullptr)
1039 coreBufferData->value = bufferData.value->getCore();
1040
1041 dirtyBufferParamIdx++;
1042 }
1043 break;
1044 case ParamType::Sampler:
1045 {
1046 writeDest = (char*)buffer + samplerStateParamsOffset + dirtySamplerParamIdx * samplerStateEntrySize;
1047 writeDest = rttiWriteElem(i, writeDest);
1048
1049 const MaterialParamSamplerStateData& samplerData = mSamplerStateParams[param.index];
1050 MaterialParamSamplerStateDataCore* coreSamplerData = (MaterialParamSamplerStateDataCore*)writeDest;
1051 new (coreSamplerData) MaterialParamSamplerStateDataCore();
1052
1053 if (samplerData.value != nullptr)
1054 coreSamplerData->value = samplerData.value->getCore();
1055
1056 dirtySamplerParamIdx++;
1057 }
1058 break;
1059 }
1060 }
1061
1062 mLastSyncVersion = mParamVersion;
1063 }
1064
1065 void MaterialParams::getResourceDependencies(Vector<HResource>& resources)
1066 {
1067 for (UINT32 i = 0; i < (UINT32)mParams.size(); i++)
1068 {
1069 ParamData& param = mParams[i];
1070 if (param.type != ParamType::Texture)
1071 continue;
1072
1073 const MaterialParamTextureData& textureData = mTextureParams[param.index];
1074 if (textureData.texture != nullptr)
1075 resources.push_back(textureData.texture);
1076
1077 if (textureData.spriteTexture != nullptr)
1078 resources.push_back(textureData.spriteTexture);
1079 }
1080 }
1081
1082 void MaterialParams::getCoreObjectDependencies(Vector<CoreObject*>& coreObjects)
1083 {
1084 for (UINT32 i = 0; i < (UINT32)mParams.size(); i++)
1085 {
1086 ParamData& param = mParams[i];
1087
1088 switch (param.type)
1089 {
1090 case ParamType::Texture:
1091 {
1092 const MaterialParamTextureData& textureData = mTextureParams[param.index];
1093
1094 if (textureData.texture.isLoaded())
1095 coreObjects.push_back(textureData.texture.get());
1096
1097 if (textureData.spriteTexture.isLoaded())
1098 coreObjects.push_back(textureData.spriteTexture.get());
1099 }
1100 break;
1101 case ParamType::Buffer:
1102 {
1103 const MaterialParamBufferData& bufferData = mBufferParams[param.index];
1104
1105 if (bufferData.value != nullptr)
1106 coreObjects.push_back(bufferData.value.get());
1107 }
1108 break;
1109 case ParamType::Sampler:
1110 {
1111
1112 const MaterialParamSamplerStateData& samplerData = mSamplerStateParams[param.index];
1113
1114 if (samplerData.value != nullptr)
1115 coreObjects.push_back(samplerData.value.get());
1116 }
1117 break;
1118 default:
1119 break;
1120 }
1121 }
1122 }
1123
1124 RTTITypeBase* MaterialParams::getRTTIStatic()
1125 {
1126 return MaterialParamsRTTI::instance();
1127 }
1128
1129 RTTITypeBase* MaterialParams::getRTTI() const
1130 {
1131 return MaterialParams::getRTTIStatic();
1132 }
1133
1134 namespace ct
1135 {
1136 MaterialParams::MaterialParams(const SPtr<Shader>& shader, UINT64 initialParamVersion)
1137 :TMaterialParams(shader, initialParamVersion)
1138 { }
1139
1140 MaterialParams::MaterialParams(const SPtr<Shader>& shader, const SPtr<bs::MaterialParams>& params)
1141 : TMaterialParams(shader, 1)
1142 {
1143 memcpy(mDataParamsBuffer, params->mDataParamsBuffer, mDataSize);
1144
1145 for (auto& param : mParams)
1146 {
1147 switch (param.type)
1148 {
1149 case ParamType::Data:
1150 {
1151 const UINT32 arraySize = param.arraySize > 1 ? param.arraySize : 1;
1152
1153 if(param.dataType == GPDT_STRUCT)
1154 {
1155 for (UINT32 i = 0; i < arraySize; i++)
1156 {
1157 const MaterialParamStructData& srcParamInfo = params->mStructParams[param.index + i];
1158 MaterialParamStructDataCore& dstParamInfo = mStructParams[param.index + i];
1159
1160 memcpy(dstParamInfo.data, srcParamInfo.data, srcParamInfo.dataSize);
1161 }
1162 }
1163 else
1164 {
1165 for (UINT32 i = 0; i < arraySize; i++)
1166 {
1167 DataParamInfo& srcParamInfo = params->mDataParams[param.index + i];
1168 DataParamInfo& dstParamInfo = mDataParams[param.index + i];
1169
1170 if (srcParamInfo.floatCurve)
1171 dstParamInfo.floatCurve = bs_pool_new<TAnimationCurve<float>>(*srcParamInfo.floatCurve);
1172
1173 if (srcParamInfo.colorGradient)
1174 dstParamInfo.colorGradient = bs_pool_new<ColorGradient>(*srcParamInfo.colorGradient);
1175 }
1176 }
1177 }
1178 break;
1179 case ParamType::Texture:
1180 {
1181 HTexture texture = params->mTextureParams[param.index].texture;
1182 SPtr<Texture> textureCore;
1183 if (texture.isLoaded())
1184 textureCore = texture->getCore();
1185
1186 mTextureParams[param.index].texture = textureCore;
1187
1188 HSpriteTexture spriteTexture = params->mTextureParams[param.index].spriteTexture;
1189 SPtr<SpriteTexture> spriteTextureCore;
1190 if (spriteTexture.isLoaded())
1191 spriteTextureCore = spriteTexture->getCore();
1192
1193 mTextureParams[param.index].spriteTexture = spriteTextureCore;
1194
1195 mTextureParams[param.index].isLoadStore = params->mTextureParams[param.index].isLoadStore;
1196 mTextureParams[param.index].surface = params->mTextureParams[param.index].surface;
1197 }
1198 break;
1199 case ParamType::Buffer:
1200 {
1201 SPtr<bs::GpuBuffer> buffer = params->mBufferParams[param.index].value;
1202 SPtr<GpuBuffer> bufferCore;
1203 if (buffer != nullptr)
1204 bufferCore = buffer->getCore();
1205
1206 mBufferParams[param.index].value = bufferCore;
1207 }
1208 break;
1209 case ParamType::Sampler:
1210 {
1211 SPtr<bs::SamplerState> sampState = params->mSamplerStateParams[param.index].value;
1212 SPtr<SamplerState> sampStateCore;
1213 if (sampState != nullptr)
1214 sampStateCore = sampState->getCore();
1215
1216 mSamplerStateParams[param.index].value = sampStateCore;
1217 }
1218 break;
1219 default:
1220 break;
1221 }
1222 }
1223 }
1224
1225 void MaterialParams::setSyncData(UINT8* buffer, UINT32 size)
1226 {
1227 char* sourceData = (char*)buffer;
1228
1229 UINT32 numDirtyDataParams = 0;
1230 UINT32 numDirtyTextureParams = 0;
1231 UINT32 numDirtyBufferParams = 0;
1232 UINT32 numDirtySamplerParams = 0;
1233 UINT32 numDirtyStructParams = 0;
1234
1235 sourceData = rttiReadElem(numDirtyDataParams, sourceData);
1236 sourceData = rttiReadElem(numDirtyTextureParams, sourceData);
1237 sourceData = rttiReadElem(numDirtyBufferParams, sourceData);
1238 sourceData = rttiReadElem(numDirtySamplerParams, sourceData);
1239 sourceData = rttiReadElem(numDirtyStructParams, sourceData);
1240
1241 mParamVersion++;
1242
1243 for(UINT32 i = 0; i < numDirtyDataParams; i++)
1244 {
1245 // Param index
1246 UINT32 paramIdx = 0;
1247 sourceData = rttiReadElem(paramIdx, sourceData);
1248
1249 ParamData& param = mParams[paramIdx];
1250 param.version = mParamVersion;
1251
1252 const UINT32 arraySize = param.arraySize > 1 ? param.arraySize : 1;
1253 const GpuParamDataTypeInfo& typeInfo = bs::GpuParams::PARAM_SIZES.lookup[(int)param.dataType];
1254 const UINT32 paramSize = typeInfo.numColumns * typeInfo.numRows * typeInfo.baseTypeSize;
1255
1256 const DataParamInfo& paramInfo = mDataParams[param.index];
1257
1258 const UINT32 dataParamSize = arraySize * paramSize;
1259
1260 // Param data
1261 // Note: This relies on the fact that all data params in the array are sequential
1262 memcpy(&mDataParamsBuffer[paramInfo.offset], sourceData, dataParamSize);
1263 sourceData += dataParamSize;
1264
1265 // Param curves
1266 UINT32 numDirtyCurves = 0;
1267 sourceData = rttiReadElem(numDirtyCurves, sourceData);
1268 for(UINT32 j = 0; j < numDirtyCurves; j++)
1269 {
1270 UINT32 localIdx = 0;
1271 sourceData = rttiReadElem(localIdx, sourceData);
1272
1273 DataParamInfo& arrParamInfo = mDataParams[param.index + localIdx];
1274 if (param.dataType == GPDT_FLOAT1)
1275 {
1276 if(arrParamInfo.floatCurve)
1277 bs_pool_free(arrParamInfo.floatCurve);
1278
1279 arrParamInfo.floatCurve = bs_pool_new<TAnimationCurve<float>>();
1280 sourceData = rttiReadElem(*arrParamInfo.floatCurve, sourceData);
1281 }
1282 else if (param.dataType == GPDT_COLOR)
1283 {
1284 if(arrParamInfo.colorGradient)
1285 bs_pool_free(arrParamInfo.colorGradient);
1286
1287 arrParamInfo.colorGradient = bs_pool_new<ColorGradient>();
1288 sourceData = rttiReadElem(*arrParamInfo.colorGradient, sourceData);
1289 }
1290 }
1291 }
1292
1293 for(UINT32 i = 0; i < numDirtyTextureParams; i++)
1294 {
1295 UINT32 paramIdx = 0;
1296 sourceData = rttiReadElem(paramIdx, sourceData);
1297
1298 ParamData& param = mParams[paramIdx];
1299 param.version = mParamVersion;
1300
1301 MaterialParamTextureDataCore* sourceTexData = (MaterialParamTextureDataCore*)sourceData;
1302 sourceData += sizeof(MaterialParamTextureDataCore);
1303
1304 mTextureParams[param.index] = *sourceTexData;
1305 sourceTexData->~MaterialParamTextureDataCore();
1306 }
1307
1308 for (UINT32 i = 0; i < numDirtyBufferParams; i++)
1309 {
1310 UINT32 paramIdx = 0;
1311 sourceData = rttiReadElem(paramIdx, sourceData);
1312
1313 ParamData& param = mParams[paramIdx];
1314 param.version = mParamVersion;
1315
1316 MaterialParamBufferDataCore* sourceBufferData = (MaterialParamBufferDataCore*)sourceData;
1317 sourceData += sizeof(MaterialParamBufferDataCore);
1318
1319 mBufferParams[param.index] = *sourceBufferData;
1320 sourceBufferData->~MaterialParamBufferDataCore();
1321 }
1322
1323 for (UINT32 i = 0; i < numDirtySamplerParams; i++)
1324 {
1325 UINT32 paramIdx = 0;
1326 sourceData = rttiReadElem(paramIdx, sourceData);
1327
1328 ParamData& param = mParams[paramIdx];
1329 param.version = mParamVersion;
1330
1331 MaterialParamSamplerStateDataCore* sourceSamplerStateData = (MaterialParamSamplerStateDataCore*)sourceData;
1332 sourceData += sizeof(MaterialParamSamplerStateDataCore);
1333
1334 mSamplerStateParams[param.index] = *sourceSamplerStateData;
1335 sourceSamplerStateData->~MaterialParamSamplerStateDataCore();
1336 }
1337
1338 for(UINT32 i = 0; i < numDirtyStructParams; i++)
1339 {
1340 // Param index
1341 UINT32 paramIdx = 0;
1342 sourceData = rttiReadElem(paramIdx, sourceData);
1343
1344 ParamData& param = mParams[paramIdx];
1345 param.version = mParamVersion;
1346
1347 const UINT32 arraySize = param.arraySize > 1 ? param.arraySize : 1;
1348 const ParamStructDataType& paramData = mStructParams[param.index];
1349
1350 // Param data
1351 for (UINT32 j = 0; j < arraySize; j++)
1352 {
1353 memcpy(mStructParams[param.index + j].data, sourceData, paramData.dataSize);
1354 sourceData += paramData.dataSize;
1355 }
1356 }
1357 }
1358 }
1359}
1360