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