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 "Image/BsTexture.h"
8#include "Math/BsMath.h"
9#include "CoreThread/BsCoreThread.h"
10#include "RenderAPI/BsRenderAPI.h"
11#include "Managers/BsTextureManager.h"
12#include "Image/BsPixelData.h"
13
14namespace bs
15{
16 /** @cond RTTI */
17 /** @addtogroup RTTI-Impl-Core
18 * @{
19 */
20
21 class BS_CORE_EXPORT TextureRTTI : public RTTIType<Texture, Resource, TextureRTTI>
22 {
23 private:
24 BS_BEGIN_RTTI_MEMBERS
25 BS_RTTI_MEMBER_PLAIN(mSize, 0)
26 BS_RTTI_MEMBER_PLAIN_NAMED(height, mProperties.mDesc.height, 2)
27 BS_RTTI_MEMBER_PLAIN_NAMED(width, mProperties.mDesc.width, 3)
28 BS_RTTI_MEMBER_PLAIN_NAMED(depth, mProperties.mDesc.depth, 4)
29 BS_RTTI_MEMBER_PLAIN_NAMED(numMips, mProperties.mDesc.numMips, 5)
30 BS_RTTI_MEMBER_PLAIN_NAMED(hwGamma, mProperties.mDesc.hwGamma, 6)
31 BS_RTTI_MEMBER_PLAIN_NAMED(numSamples, mProperties.mDesc.numSamples, 7)
32 BS_RTTI_MEMBER_PLAIN_NAMED(type, mProperties.mDesc.type, 9)
33 BS_RTTI_MEMBER_PLAIN_NAMED(format, mProperties.mDesc.format, 10)
34 BS_END_RTTI_MEMBERS
35
36 INT32& getUsage(Texture* obj) { return obj->mProperties.mDesc.usage; }
37 void setUsage(Texture* obj, INT32& val)
38 {
39 // Render target and depth stencil texture formats are for in-memory use only
40 // and don't make sense when serialized
41 if ((val & (TU_DEPTHSTENCIL | TU_RENDERTARGET)) != 0)
42 {
43 obj->mProperties.mDesc.usage &= ~(TU_DEPTHSTENCIL | TU_RENDERTARGET);
44 obj->mProperties.mDesc.usage |= TU_STATIC;
45 }
46 else
47 obj->mProperties.mDesc.usage = val;
48 }
49
50 SPtr<PixelData> getPixelData(Texture* obj, UINT32 idx)
51 {
52 UINT32 face = (size_t)Math::floor(idx / (float)(obj->mProperties.getNumMipmaps() + 1));
53 UINT32 mipmap = idx % (obj->mProperties.getNumMipmaps() + 1);
54
55 SPtr<PixelData> pixelData = obj->mProperties.allocBuffer(face, mipmap);
56
57 obj->readData(pixelData, face, mipmap);
58 gCoreThread().submitAll(true);
59
60 return pixelData;
61 }
62
63 void setPixelData(Texture* obj, UINT32 idx, SPtr<PixelData> data)
64 {
65 mPixelData[idx] = data;
66 }
67
68 UINT32 getPixelDataArraySize(Texture* obj)
69 {
70 return obj->mProperties.getNumFaces() * (obj->mProperties.getNumMipmaps() + 1);
71 }
72
73 void setPixelDataArraySize(Texture* obj, UINT32 size)
74 {
75 mPixelData.resize(size);
76 }
77
78 public:
79 TextureRTTI()
80 {
81 addPlainField("mUsage", 11, &TextureRTTI::getUsage, &TextureRTTI::setUsage);
82
83 addReflectablePtrArrayField("mPixelData", 12, &TextureRTTI::getPixelData, &TextureRTTI::getPixelDataArraySize,
84 &TextureRTTI::setPixelData, &TextureRTTI::setPixelDataArraySize, RTTIFieldInfo(RTTIFieldFlag::SkipInReferenceSearch));
85 }
86
87 void onDeserializationEnded(IReflectable* obj, SerializationContext* context) override
88 {
89 Texture* texture = static_cast<Texture*>(obj);
90 TextureProperties& texProps = texture->mProperties;
91
92 // Update pixel format if needed as it's possible the original texture was saved using some other render API
93 // that has an unsupported format.
94 PixelFormat originalFormat = texProps.getFormat();
95 PixelFormat validFormat = TextureManager::instance().getNativeFormat(
96 texProps.getTextureType(), texProps.getFormat(), texProps.getUsage(), texProps.isHardwareGammaEnabled());
97
98 if (originalFormat != validFormat)
99 {
100 texProps.mDesc.format = validFormat;
101
102 for (size_t i = 0; i < mPixelData.size(); i++)
103 {
104 SPtr<PixelData> origData = mPixelData[i];
105 SPtr<PixelData> newData = PixelData::create(origData->getWidth(), origData->getHeight(), origData->getDepth(), validFormat);
106
107 PixelUtil::bulkPixelConversion(*origData, *newData);
108 mPixelData[i] = newData;
109 }
110 }
111
112 // A bit clumsy initializing with already set values, but I feel its better than complicating things and storing the values
113 // in mRTTIData.
114 texture->initialize();
115
116 for(size_t i = 0; i < mPixelData.size(); i++)
117 {
118 UINT32 face = (size_t)Math::floor(i / (float)(texProps.getNumMipmaps() + 1));
119 UINT32 mipmap = i % (texProps.getNumMipmaps() + 1);
120
121 texture->writeData(mPixelData[i], face, mipmap, false);
122 }
123 }
124
125 const String& getRTTIName() override
126 {
127 static String name = "Texture";
128 return name;
129 }
130
131 UINT32 getRTTIId() override
132 {
133 return TID_Texture;
134 }
135
136 SPtr<IReflectable> newRTTIObject() override
137 {
138 return TextureManager::instance()._createEmpty();
139 }
140
141 private:
142 Vector<SPtr<PixelData>> mPixelData;
143 };
144
145 /** @} */
146 /** @endcond */
147}
148