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 "Reflection/BsRTTIType.h"
7#include "Material/BsMaterialParams.h"
8#include "RenderAPI/BsSamplerState.h"
9#include "FileSystem/BsDataStream.h"
10#include "Animation/BsAnimationCurve.h"
11#include "Image/BsColorGradient.h"
12#include "Private/RTTI/BsAnimationCurveRTTI.h"
13#include "Private/RTTI/BsColorGradientRTTI.h"
14
15namespace bs
16{
17 /** @cond RTTI */
18 /** @addtogroup RTTI-Impl-Core
19 * @{
20 */
21
22 class BS_CORE_EXPORT MaterialParamTextureDataRTTI : public RTTIType<MaterialParamTextureData, IReflectable, MaterialParamTextureDataRTTI>
23 {
24 public:
25 BS_BEGIN_RTTI_MEMBERS
26 BS_RTTI_MEMBER_REFL(texture, 0)
27 BS_RTTI_MEMBER_PLAIN(isLoadStore, 1)
28 BS_RTTI_MEMBER_PLAIN(surface, 2)
29 BS_RTTI_MEMBER_REFL(spriteTexture, 3)
30 BS_END_RTTI_MEMBERS
31
32 const String& getRTTIName() override
33 {
34 static String name = "TextureParamData";
35 return name;
36 }
37
38 UINT32 getRTTIId() override
39 {
40 return TID_TextureParamData;
41 }
42
43 SPtr<IReflectable> newRTTIObject() override
44 {
45 return bs_shared_ptr_new<MaterialParamTextureData>();
46 }
47 };
48
49 class BS_CORE_EXPORT MaterialParamStructDataRTTI : public RTTIType<MaterialParamStructData, IReflectable, MaterialParamStructDataRTTI>
50 {
51 public:
52 SPtr<DataStream> getDataBuffer(MaterialParamStructData* obj, UINT32& size)
53 {
54 size = obj->dataSize;
55
56 return bs_shared_ptr_new<MemoryDataStream>(obj->data, obj->dataSize, false);
57 }
58
59 void setDataBuffer(MaterialParamStructData* obj, const SPtr<DataStream>& value, UINT32 size)
60 {
61 obj->data = (UINT8*)bs_alloc(size);
62 value->read(obj->data, size);
63
64 obj->dataSize = size;
65 }
66
67 MaterialParamStructDataRTTI()
68 {
69 addDataBlockField("dataBuffer", 0, &MaterialParamStructDataRTTI::getDataBuffer, &MaterialParamStructDataRTTI::setDataBuffer);
70 }
71
72 const String& getRTTIName() override
73 {
74 static String name = "StructParamData";
75 return name;
76 }
77
78 UINT32 getRTTIId() override
79 {
80 return TID_StructParamData;
81 }
82
83 SPtr<IReflectable> newRTTIObject() override
84 {
85 return bs_shared_ptr_new<MaterialParamStructData>();
86 }
87 };
88
89 class BS_CORE_EXPORT MaterialParamsRTTI : public RTTIType<MaterialParams, IReflectable, MaterialParamsRTTI>
90 {
91 public:
92 struct MaterialParam
93 {
94 String name;
95 UINT32 index;
96 MaterialParams::ParamData data;
97 };
98
99 MaterialParam& getParamData(MaterialParams* obj, UINT32 idx)
100 {
101 return mMatParams[idx];
102 }
103
104 void setParamData(MaterialParams* obj, UINT32 idx, MaterialParam& param)
105 {
106 UINT32 paramIdx = param.index;
107
108 // Older saved files might not have indices preserved
109 if(paramIdx == (UINT32)-1)
110 paramIdx = mNextParamIdx++;
111
112 obj->mParams[paramIdx] = param.data;
113 obj->mParamLookup[param.name] = paramIdx;
114 }
115
116 UINT32 getParamDataArraySize(MaterialParams* obj)
117 {
118 return (UINT32)mMatParams.size();
119 }
120
121 void setParamDataArraySize(MaterialParams* obj, UINT32 size)
122 {
123 obj->mParams.resize(size);
124 }
125
126 SPtr<DataStream> getDataBuffer(MaterialParams* obj, UINT32& size)
127 {
128 size = obj->mDataSize;
129
130 return bs_shared_ptr_new<MemoryDataStream>(obj->mDataParamsBuffer, obj->mDataSize, false);
131 }
132
133 void setDataBuffer(MaterialParams* obj, const SPtr<DataStream>& value, UINT32 size)
134 {
135 obj->mDataParamsBuffer = obj->mAlloc.alloc(size);
136 value->read(obj->mDataParamsBuffer, size);
137
138 obj->mDataSize = size;
139 }
140
141 MaterialParamStructData& getStructParam(MaterialParams* obj, UINT32 idx) { return obj->mStructParams[idx]; }
142 void setStructParam(MaterialParams* obj, UINT32 idx, MaterialParamStructData& param)
143 {
144 MaterialParamStructData& newStructParam = obj->mStructParams[idx];
145 newStructParam.data = (UINT8*)obj->mAlloc.alloc(param.dataSize);
146 memcpy(newStructParam.data, param.data, param.dataSize);
147 newStructParam.dataSize = param.dataSize;
148
149 bs_free(param.data);
150 param.data = nullptr;
151 }
152 UINT32 getStructArraySize(MaterialParams* obj) { return (UINT32)obj->mNumStructParams; }
153 void setStructArraySize(MaterialParams* obj, UINT32 size)
154 {
155 obj->mNumStructParams = size;
156 obj->mStructParams = obj->mAlloc.construct<MaterialParamStructData>(size);
157 }
158
159 MaterialParamTextureData& getTextureParam(MaterialParams* obj, UINT32 idx) { return obj->mTextureParams[idx]; }
160 void setTextureParam(MaterialParams* obj, UINT32 idx, MaterialParamTextureData& param) { obj->mTextureParams[idx] = param; }
161 UINT32 getTextureArraySize(MaterialParams* obj) { return (UINT32)obj->mNumTextureParams; }
162 void setTextureArraySize(MaterialParams* obj, UINT32 size)
163 {
164 obj->mNumTextureParams = size;
165 obj->mTextureParams = obj->mAlloc.construct<MaterialParamTextureData>(size);
166 }
167
168 SPtr<SamplerState> getSamplerStateParam(MaterialParams* obj, UINT32 idx) { return obj->mSamplerStateParams[idx].value; }
169 void setSamplerStateParam(MaterialParams* obj, UINT32 idx, SPtr<SamplerState> param) { obj->mSamplerStateParams[idx].value = param; }
170 UINT32 getSamplerStateArraySize(MaterialParams* obj) { return (UINT32)obj->mNumSamplerParams; }
171 void setSamplerStateArraySize(MaterialParams* obj, UINT32 size)
172 {
173 obj->mNumSamplerParams = size;
174 obj->mSamplerStateParams = obj->mAlloc.construct<MaterialParamSamplerStateData>(size);
175 }
176
177 UINT32& getNumBufferParams(MaterialParams* obj)
178 {
179 return obj->mNumBufferParams;
180 }
181
182 void setNumBufferParams(MaterialParams* obj, UINT32& value)
183 {
184 obj->mNumBufferParams = value;
185 obj->mBufferParams = obj->mAlloc.construct<MaterialParamBufferData>(value);
186 }
187
188 MaterialParamsBase::DataParamInfo& getDataParam(MaterialParams* obj, UINT32 idx) { return obj->mDataParams[idx]; }
189 void setDataParam(MaterialParams* obj, UINT32 idx, MaterialParamsBase::DataParamInfo& param) { obj->mDataParams[idx] = param; }
190 UINT32 getDataParamArraySize(MaterialParams* obj) { return (UINT32)obj->mNumDataParams; }
191 void setDataParamArraySize(MaterialParams* obj, UINT32 size)
192 {
193 obj->mNumDataParams = size;
194 obj->mDataParams = obj->mAlloc.construct<MaterialParamsBase::DataParamInfo>(size);
195 }
196
197 MaterialParamsRTTI()
198 {
199 addPlainArrayField("paramData", 0, &MaterialParamsRTTI::getParamData, &MaterialParamsRTTI::getParamDataArraySize,
200 &MaterialParamsRTTI::setParamData, &MaterialParamsRTTI::setParamDataArraySize);
201
202 addDataBlockField("dataBuffer", 1, &MaterialParamsRTTI::getDataBuffer, &MaterialParamsRTTI::setDataBuffer);
203
204 addReflectableArrayField("structParams", 2, &MaterialParamsRTTI::getStructParam,
205 &MaterialParamsRTTI::getStructArraySize, &MaterialParamsRTTI::setStructParam, &MaterialParamsRTTI::setStructArraySize);
206
207 addReflectableArrayField("textureParams", 3, &MaterialParamsRTTI::getTextureParam,
208 &MaterialParamsRTTI::getTextureArraySize, &MaterialParamsRTTI::setTextureParam, &MaterialParamsRTTI::setTextureArraySize);
209
210 addReflectablePtrArrayField("samplerStateParams", 4, &MaterialParamsRTTI::getSamplerStateParam,
211 &MaterialParamsRTTI::getSamplerStateArraySize, &MaterialParamsRTTI::setSamplerStateParam, &MaterialParamsRTTI::setSamplerStateArraySize);
212
213 addPlainField("numBufferParams", 5, &MaterialParamsRTTI::getNumBufferParams, &MaterialParamsRTTI::setNumBufferParams);
214
215 addPlainArrayField("dataParams", 6, &MaterialParamsRTTI::getDataParam,
216 &MaterialParamsRTTI::getDataParamArraySize, &MaterialParamsRTTI::setDataParam, &MaterialParamsRTTI::setDataParamArraySize);
217 }
218
219 void onSerializationStarted(IReflectable* obj, SerializationContext* context) override
220 {
221 MaterialParams* paramsObj = static_cast<MaterialParams*>(obj);
222
223 for (auto& entry : paramsObj->mParamLookup)
224 {
225 UINT32 paramIdx = entry.second;
226 mMatParams.push_back({ entry.first, paramIdx, paramsObj->mParams[paramIdx] });
227 }
228 }
229
230 void onDeserializationEnded(IReflectable* obj, SerializationContext* context) override
231 {
232 MaterialParams* paramsObj = static_cast<MaterialParams*>(obj);
233
234 // This field was added in later versions of the file format, so generate valid data for it if loading from
235 // an older serialized version
236 if(!paramsObj->mDataParams)
237 {
238 paramsObj->mNumDataParams = 0;
239 for(auto& entry : paramsObj->mParams)
240 {
241 if(entry.type != MaterialParams::ParamType::Data)
242 continue;
243
244 paramsObj->mNumDataParams++;
245 }
246
247 paramsObj->mDataParams = (MaterialParams::DataParamInfo*)paramsObj->mAlloc.alloc(
248 paramsObj->mNumDataParams * sizeof(MaterialParams::DataParamInfo));
249 memset(paramsObj->mDataParams, 0, paramsObj->mNumDataParams * sizeof(MaterialParams::DataParamInfo));
250
251 UINT32 paramIdx = 0;
252 UINT32 dataBufferIdx = 0;
253 for(auto& entry : paramsObj->mParams)
254 {
255 if(entry.type != MaterialParams::ParamType::Data)
256 continue;
257
258 const GpuParamDataTypeInfo& typeInfo = GpuParams::PARAM_SIZES.lookup[(int)entry.dataType];
259 const UINT32 paramSize = typeInfo.numColumns * typeInfo.numRows * typeInfo.baseTypeSize;
260 for (UINT32 i = 0; i < entry.arraySize; i++)
261 {
262 paramsObj->mDataParams[paramIdx + i].offset = dataBufferIdx;
263
264 dataBufferIdx += paramSize;
265 }
266
267 entry.index = paramIdx;
268 paramIdx += entry.arraySize;
269 }
270 }
271 }
272
273 const String& getRTTIName() override
274 {
275 static String name = "MaterialParams";
276 return name;
277 }
278
279 UINT32 getRTTIId() override
280 {
281 return TID_MaterialParams;
282 }
283
284 SPtr<IReflectable> newRTTIObject() override
285 {
286 return bs_shared_ptr_new<MaterialParams>();
287 }
288
289 private:
290 Vector<MaterialParam> mMatParams;
291 UINT32 mNextParamIdx = 0;
292 };
293
294 template<> struct RTTIPlainType<MaterialParamsBase::ParamData>
295 {
296 enum { id = TID_MaterialParamData }; enum { hasDynamicSize = 0 };
297
298 static void toMemory(const MaterialParamsBase::ParamData& data, char* memory)
299 {
300 memory = rttiWriteElem(data.type, memory);
301 memory = rttiWriteElem(data.dataType, memory);
302 memory = rttiWriteElem(data.index, memory);
303 memory = rttiWriteElem(data.arraySize, memory);
304 }
305
306 static UINT32 fromMemory(MaterialParamsBase::ParamData& data, char* memory)
307 {
308 UINT32 size = 0;
309 memory = rttiReadElem(data.type, memory, size);
310 memory = rttiReadElem(data.dataType, memory, size);
311 memory = rttiReadElem(data.index, memory, size);
312 memory = rttiReadElem(data.arraySize, memory, size);
313
314 data.version = 1;
315 size += sizeof(data.version);
316
317 return size;
318 }
319
320 static UINT32 getDynamicSize(const MaterialParamsBase::ParamData& data)
321 {
322 assert(false);
323 return 0;
324 }
325 };
326
327 template<> struct RTTIPlainType<MaterialParamsBase::DataParamInfo>
328 {
329 enum { id = TID_DataParamInfo }; enum { hasDynamicSize = 1 };
330
331 static void toMemory(const MaterialParamsBase::DataParamInfo& data, char* memory)
332 {
333 static constexpr UINT32 VERSION = 0;
334
335 const UINT32 size = getDynamicSize(data);
336 memory = rttiWriteElem(size, memory);
337 memory = rttiWriteElem(VERSION, memory);
338
339 memory = rttiWriteElem(data.offset, memory);
340
341 UINT32 curveType = 0; // No curve
342
343 if(data.floatCurve)
344 curveType = 1;
345 else if(data.colorGradient)
346 curveType = 2;
347 else if(data.spriteTextureIdx != (UINT32)-1)
348 curveType = 3;
349
350 memory = rttiWriteElem(curveType, memory);
351 if(data.floatCurve)
352 memory = rttiWriteElem(*data.floatCurve, memory);
353 else if(data.colorGradient)
354 memory = rttiWriteElem(*data.colorGradient, memory);
355 else if(data.spriteTextureIdx != (UINT32)-1)
356 memory = rttiWriteElem(data.spriteTextureIdx, memory);
357 }
358
359 static UINT32 fromMemory(MaterialParamsBase::DataParamInfo& data, char* memory)
360 {
361 UINT32 size = 0;
362 memory = rttiReadElem(size, memory);
363
364 UINT32 version = 0;
365 memory = rttiReadElem(version, memory);
366
367 switch(version)
368 {
369 case 0:
370 {
371 memory = rttiReadElem(data.offset, memory);
372
373 UINT32 curveType = 0;
374 memory = rttiReadElem(curveType, memory);
375
376 data.floatCurve = nullptr;
377 data.colorGradient = nullptr;
378 data.spriteTextureIdx = (UINT32)-1;
379
380 switch(curveType)
381 {
382 case 1:
383 data.floatCurve = bs_pool_new<TAnimationCurve<float>>();
384 memory = rttiReadElem(*data.floatCurve, memory);
385 break;
386 case 2:
387 data.colorGradient = bs_pool_new<ColorGradient>();
388 memory = rttiReadElem(*data.colorGradient, memory);
389 break;
390 case 3:
391 memory = rttiReadElem(data.spriteTextureIdx, memory);
392 break;
393 default:
394 break;
395 }
396 }
397 break;
398 default:
399 LOGERR("Unknown version. Unable to deserialize.");
400 break;
401 }
402
403 return size;
404 }
405
406 static UINT32 getDynamicSize(const MaterialParamsBase::DataParamInfo& data)
407 {
408 UINT32 size = sizeof(UINT32) * 3 + rttiGetElemSize(data.offset);
409
410 if(data.floatCurve)
411 size += rttiGetElemSize(*data.floatCurve);
412 else if(data.colorGradient)
413 size += rttiGetElemSize(*data.colorGradient);
414 else if(data.spriteTextureIdx != (UINT32)-1)
415 size += rttiGetElemSize(data.spriteTextureIdx);
416
417 return size;
418 }
419 };
420
421 template<> struct RTTIPlainType<MaterialParamsRTTI::MaterialParam>
422 {
423 enum { id = TID_MaterialRTTIParam }; enum { hasDynamicSize = 1 };
424
425 static void toMemory(const MaterialParamsRTTI::MaterialParam& data, char* memory)
426 {
427 static constexpr UINT32 VERSION = 1;
428
429 const UINT32 size = getDynamicSize(data);
430
431 memory = rttiWriteElem(size, memory);
432 memory = rttiWriteElem(data.name, memory);
433 memory = rttiWriteElem(data.data, memory);
434
435 // Version 1 data
436 memory = rttiWriteElem(VERSION, memory);
437 memory = rttiWriteElem(data.index, memory);
438 }
439
440 static UINT32 fromMemory(MaterialParamsRTTI::MaterialParam& data, char* memory)
441 {
442 UINT32 size = 0;
443 UINT32 sizeRead = 0;
444
445 memory = rttiReadElem(size, memory, sizeRead);
446 memory = rttiReadElem(data.name, memory, sizeRead);
447 memory = rttiReadElem(data.data, memory, sizeRead);
448
449 // More fields means a newer version of the data format
450 if(size > sizeRead)
451 {
452 UINT32 version = 0;
453 memory = rttiReadElem(version, memory);
454
455 switch (version)
456 {
457 case 1:
458 memory = rttiReadElem(data.index, memory);
459 break;
460 default:
461 LOGERR("Unknown version. Unable to deserialize.");
462 break;
463 }
464 }
465 else
466 data.index = (UINT32)-1; // Lets the other code know that index needs to be generated
467
468 return size;
469 }
470
471 static UINT32 getDynamicSize(const MaterialParamsRTTI::MaterialParam& data)
472 {
473 const UINT64 dataSize = rttiGetElemSize(data.name) + rttiGetElemSize(data.data) + rttiGetElemSize(data.index) +
474 sizeof(UINT32) * 2;
475
476#if BS_DEBUG_MODE
477 if(dataSize > std::numeric_limits<UINT32>::max())
478 {
479 __string_throwDataOverflowException();
480 }
481#endif
482
483 return (UINT32)dataSize;
484 }
485 };
486
487 /** @} */
488 /** @endcond */
489}
490