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 | |
15 | namespace 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 | |