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 "Renderer/BsSkybox.h" |
4 | #include "Private/RTTI/BsSkyboxRTTI.h" |
5 | #include "Scene/BsSceneObject.h" |
6 | #include "Image/BsTexture.h" |
7 | #include "Renderer/BsRenderer.h" |
8 | #include "Utility/BsUUID.h" |
9 | #include "Renderer/BsIBLUtility.h" |
10 | #include "CoreThread/BsCoreObjectSync.h" |
11 | |
12 | namespace bs |
13 | { |
14 | template <bool Core> |
15 | template <class P> |
16 | void TSkybox<Core>::rttiEnumFields(P p) |
17 | { |
18 | p(mBrightness); |
19 | p(mTexture); |
20 | } |
21 | |
22 | Skybox::Skybox() |
23 | { |
24 | // This shouldn't normally happen, as filtered textures are generated when a radiance texture is assigned, but |
25 | // we check for it anyway (something could have gone wrong). |
26 | if(mTexture.isLoaded()) |
27 | { |
28 | if (mFilteredRadiance == nullptr || mIrradiance == nullptr) |
29 | filterTexture(); |
30 | } |
31 | } |
32 | |
33 | Skybox::~Skybox() |
34 | { |
35 | if (mRendererTask != nullptr) |
36 | mRendererTask->cancel(); |
37 | } |
38 | |
39 | void Skybox::filterTexture() |
40 | { |
41 | // If previous rendering task exists, cancel it |
42 | if (mRendererTask != nullptr) |
43 | mRendererTask->cancel(); |
44 | |
45 | { |
46 | TEXTURE_DESC cubemapDesc; |
47 | cubemapDesc.type = TEX_TYPE_CUBE_MAP; |
48 | cubemapDesc.format = PF_RG11B10F; |
49 | cubemapDesc.width = ct::IBLUtility::REFLECTION_CUBEMAP_SIZE; |
50 | cubemapDesc.height = ct::IBLUtility::REFLECTION_CUBEMAP_SIZE; |
51 | cubemapDesc.numMips = PixelUtil::getMaxMipmaps(cubemapDesc.width, cubemapDesc.height, 1, cubemapDesc.format); |
52 | cubemapDesc.usage = TU_STATIC | TU_RENDERTARGET; |
53 | |
54 | mFilteredRadiance = Texture::_createPtr(cubemapDesc); |
55 | } |
56 | |
57 | { |
58 | TEXTURE_DESC irradianceCubemapDesc; |
59 | irradianceCubemapDesc.type = TEX_TYPE_CUBE_MAP; |
60 | irradianceCubemapDesc.format = PF_RG11B10F; |
61 | irradianceCubemapDesc.width = ct::IBLUtility::IRRADIANCE_CUBEMAP_SIZE; |
62 | irradianceCubemapDesc.height = ct::IBLUtility::IRRADIANCE_CUBEMAP_SIZE; |
63 | irradianceCubemapDesc.numMips = 0; |
64 | irradianceCubemapDesc.usage = TU_STATIC | TU_RENDERTARGET; |
65 | |
66 | mIrradiance = Texture::_createPtr(irradianceCubemapDesc); |
67 | } |
68 | |
69 | auto renderComplete = [this]() |
70 | { |
71 | mRendererTask = nullptr; |
72 | }; |
73 | |
74 | SPtr<ct::Skybox> coreSkybox = getCore(); |
75 | SPtr<ct::Texture> coreFilteredRadiance = mFilteredRadiance->getCore(); |
76 | SPtr<ct::Texture> coreIrradiance = mIrradiance->getCore(); |
77 | |
78 | auto filterSkybox = [coreFilteredRadiance, coreIrradiance, coreSkybox]() |
79 | { |
80 | // Filter radiance |
81 | ct::gIBLUtility().scaleCubemap(coreSkybox->getTexture(), 0, coreFilteredRadiance, 0); |
82 | ct::gIBLUtility().filterCubemapForSpecular(coreFilteredRadiance, nullptr); |
83 | |
84 | coreSkybox->mFilteredRadiance = coreFilteredRadiance; |
85 | |
86 | // Generate irradiance |
87 | ct::gIBLUtility().filterCubemapForIrradiance(coreSkybox->getTexture(), coreIrradiance); |
88 | coreSkybox->mIrradiance = coreIrradiance; |
89 | |
90 | return true; |
91 | }; |
92 | |
93 | mRendererTask = ct::RendererTask::create("SkyboxFilter" , filterSkybox); |
94 | |
95 | mRendererTask->onComplete.connect(renderComplete); |
96 | ct::gRenderer()->addTask(mRendererTask); |
97 | } |
98 | |
99 | void Skybox::setTexture(const HTexture& texture) |
100 | { |
101 | mTexture = texture; |
102 | |
103 | mFilteredRadiance = nullptr; |
104 | mIrradiance = nullptr; |
105 | |
106 | if(mTexture.isLoaded()) |
107 | filterTexture(); |
108 | |
109 | _markCoreDirty((ActorDirtyFlag)SkyboxDirtyFlag::Texture); |
110 | } |
111 | |
112 | SPtr<ct::Skybox> Skybox::getCore() const |
113 | { |
114 | return std::static_pointer_cast<ct::Skybox>(mCoreSpecific); |
115 | } |
116 | |
117 | SPtr<Skybox> Skybox::createEmpty() |
118 | { |
119 | Skybox* skybox = new (bs_alloc<Skybox>()) Skybox(); |
120 | SPtr<Skybox> skyboxPtr = bs_core_ptr<Skybox>(skybox); |
121 | skyboxPtr->_setThisPtr(skyboxPtr); |
122 | |
123 | return skyboxPtr; |
124 | } |
125 | |
126 | SPtr<Skybox> Skybox::create() |
127 | { |
128 | SPtr<Skybox> skyboxPtr = createEmpty(); |
129 | skyboxPtr->initialize(); |
130 | |
131 | return skyboxPtr; |
132 | } |
133 | |
134 | SPtr<ct::CoreObject> Skybox::createCore() const |
135 | { |
136 | SPtr<ct::Texture> radiance; |
137 | if (mTexture) |
138 | radiance = mTexture->getCore(); |
139 | |
140 | SPtr<ct::Texture> filteredRadiance; |
141 | if (mFilteredRadiance) |
142 | filteredRadiance = mFilteredRadiance->getCore(); |
143 | |
144 | SPtr<ct::Texture> irradiance; |
145 | if (mIrradiance) |
146 | irradiance = mIrradiance->getCore(); |
147 | |
148 | ct::Skybox* skybox = new (bs_alloc<ct::Skybox>()) ct::Skybox(radiance, filteredRadiance, irradiance); |
149 | SPtr<ct::Skybox> skyboxPtr = bs_shared_ptr<ct::Skybox>(skybox); |
150 | skyboxPtr->_setThisPtr(skyboxPtr); |
151 | |
152 | return skyboxPtr; |
153 | } |
154 | |
155 | CoreSyncData Skybox::syncToCore(FrameAlloc* allocator) |
156 | { |
157 | UINT32 size = 0; |
158 | size += rttiGetElemSize(getCoreDirtyFlags()); |
159 | size += coreSyncGetElemSize((SceneActor&)*this); |
160 | size += coreSyncGetElemSize(*this); |
161 | |
162 | UINT8* buffer = allocator->alloc(size); |
163 | |
164 | char* dataPtr = (char*)buffer; |
165 | dataPtr = rttiWriteElem(getCoreDirtyFlags(), dataPtr); |
166 | dataPtr = coreSyncWriteElem((SceneActor&)*this, dataPtr); |
167 | dataPtr = coreSyncWriteElem(*this, dataPtr); |
168 | |
169 | return CoreSyncData(buffer, size); |
170 | } |
171 | |
172 | void Skybox::_markCoreDirty(ActorDirtyFlag flags) |
173 | { |
174 | markCoreDirty((UINT32)flags); |
175 | } |
176 | |
177 | RTTITypeBase* Skybox::getRTTIStatic() |
178 | { |
179 | return SkyboxRTTI::instance(); |
180 | } |
181 | |
182 | RTTITypeBase* Skybox::getRTTI() const |
183 | { |
184 | return Skybox::getRTTIStatic(); |
185 | } |
186 | |
187 | namespace ct |
188 | { |
189 | Skybox::Skybox(const SPtr<Texture>& radiance, const SPtr<Texture>& filteredRadiance, const SPtr<Texture>& irradiance) |
190 | :mFilteredRadiance(filteredRadiance), mIrradiance(irradiance) |
191 | { |
192 | mTexture = radiance; |
193 | } |
194 | |
195 | Skybox::~Skybox() |
196 | { |
197 | gRenderer()->notifySkyboxRemoved(this); |
198 | } |
199 | |
200 | void Skybox::initialize() |
201 | { |
202 | gRenderer()->notifySkyboxAdded(this); |
203 | |
204 | CoreObject::initialize(); |
205 | } |
206 | |
207 | void Skybox::syncToCore(const CoreSyncData& data) |
208 | { |
209 | char* dataPtr = (char*)data.getBuffer(); |
210 | |
211 | SkyboxDirtyFlag dirtyFlags; |
212 | bool oldIsActive = mActive; |
213 | |
214 | dataPtr = rttiReadElem(dirtyFlags, dataPtr); |
215 | dataPtr = coreSyncReadElem((SceneActor&)*this, dataPtr); |
216 | dataPtr = coreSyncReadElem(*this, dataPtr); |
217 | |
218 | if (oldIsActive != mActive) |
219 | { |
220 | if (mActive) |
221 | gRenderer()->notifySkyboxAdded(this); |
222 | else |
223 | gRenderer()->notifySkyboxRemoved(this); |
224 | } |
225 | else |
226 | { |
227 | if (dirtyFlags != SkyboxDirtyFlag::Texture) |
228 | { |
229 | gRenderer()->notifySkyboxRemoved(this); |
230 | gRenderer()->notifySkyboxAdded(this); |
231 | } |
232 | } |
233 | } |
234 | } |
235 | } |
236 | |