1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
4 // This source file has been modified by the following contributors:
5 // Copyright (C) 2013-2014 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
7 // This program is free software: you can redistribute it and/or modify
8 // it under the terms of the GNU Affero General Public License as
9 // published by the Free Software Foundation, either version 3 of the
10 // License, or (at your option) any later version.
12 // This program is distributed in the hope that it will be useful,
13 // but WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 // GNU Affero General Public License for more details.
17 // You should have received a copy of the GNU Affero General Public License
18 // along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include "nel/3d/u_driver.h"
24 #include "nel/3d/u_scene.h"
25 #include "nel/3d/u_camera.h"
28 #include "nel/3d/driver_user.h"
29 #include "nel/3d/texture_bloom.h"
30 #include "nel/3d/texture_user.h"
32 #include "nel/3d/bloom_effect.h"
35 using namespace NLMISC
;
47 // vertex program used to blur texture
48 static const char *TextureOffset
=
50 MOV o[COL0].x, c[8].x; \n\
51 MOV o[COL0].y, c[8].y; \n\
52 MOV o[COL0].z, c[8].z; \n\
53 MOV o[COL0].w, c[8].w; \n\
54 MOV o[HPOS].x, v[OPOS].x; \n\
55 MOV o[HPOS].y, v[OPOS].y; \n\
56 MOV o[HPOS].z, v[OPOS].z; \n\
57 MOV o[HPOS].w, c[9].w; \n\
58 ADD o[TEX0], v[TEX0], c[10]; \n\
59 ADD o[TEX1], v[TEX0], c[11]; \n\
60 ADD o[TEX2], v[TEX0], c[12]; \n\
61 ADD o[TEX3], v[TEX0], c[13]; \n\
65 static NLMISC::CSmartPtr
<CVertexProgram
> TextureOffsetVertexProgram
;
68 //-----------------------------------------------------------------------------------------------------------
70 CBloomEffect::CBloomEffect()
72 if (!TextureOffsetVertexProgram
)
74 TextureOffsetVertexProgram
= new CVertexProgram(TextureOffset
);
84 _BlurHorizontalTex
= NULL
;
87 //-----------------------------------------------------------------------------------------------------------
89 CBloomEffect::~CBloomEffect()
93 if (!_DisplayBlurMat
.empty())
95 if (_Driver
) _Driver
->deleteMaterial(_DisplayBlurMat
);
98 if (!_DisplaySquareBlurMat
.empty())
100 if (_Driver
) _Driver
->deleteMaterial(_DisplaySquareBlurMat
);
103 if (!_BlurMat
.empty())
105 if (_Driver
) _Driver
->deleteMaterial(_BlurMat
);
110 //-----------------------------------------------------------------------------------------------------------
112 void CBloomEffect::init()
114 if (!((CDriverUser
*)_Driver
)->getDriver()->supportBloomEffect())
117 CDriverUser
*dru
= static_cast<CDriverUser
*>(_Driver
);
118 IDriver
*drv
= dru
->getDriver();
123 // initialize blur material
124 _BlurMat
= _Driver
->createMaterial();
125 CMaterial
* matObject
= _BlurMat
.getObjectPtr();
126 _BlurMat
.initUnlit();
127 _BlurMat
.setColor(CRGBA::White
);
128 _BlurMat
.setBlend (false);
129 _BlurMat
.setAlphaTest (false);
130 matObject
->setBlendFunc (CMaterial::one
, CMaterial::zero
);
131 matObject
->setZWrite(false);
132 matObject
->setZFunc(CMaterial::always
);
133 matObject
->setDoubleSided(true);
135 // initialize stages of fixed pipeline
136 CRGBA
constantCol1(85, 85, 85, 85);
137 CRGBA
constantCol2(43, 43, 43, 43);
139 matObject
->texConstantColor(0, constantCol1
);
140 matObject
->texEnvOpRGB(0, CMaterial::Modulate
);
141 matObject
->texEnvArg0RGB(0, CMaterial::Texture
, CMaterial::SrcColor
);
142 matObject
->texEnvArg1RGB(0, CMaterial::Constant
, CMaterial::SrcColor
);
145 matObject
->texConstantColor(1, constantCol2
);
146 matObject
->texEnvOpRGB(1, CMaterial::Mad
);
147 matObject
->texEnvArg0RGB(1, CMaterial::Texture
, CMaterial::SrcColor
);
148 matObject
->texEnvArg1RGB(1, CMaterial::Constant
, CMaterial::SrcColor
);
149 matObject
->texEnvArg2RGB(1, CMaterial::Previous
, CMaterial::SrcColor
);
152 matObject
->texConstantColor(2, constantCol1
);
153 matObject
->texEnvOpRGB(2, CMaterial::Mad
);
154 matObject
->texEnvArg0RGB(2, CMaterial::Texture
, CMaterial::SrcColor
);
155 matObject
->texEnvArg1RGB(2, CMaterial::Constant
, CMaterial::SrcColor
);
156 matObject
->texEnvArg2RGB(2, CMaterial::Previous
, CMaterial::SrcColor
);
159 matObject
->texConstantColor(3, constantCol2
);
160 matObject
->texEnvOpRGB(3, CMaterial::Mad
);
161 matObject
->texEnvArg0RGB(3, CMaterial::Texture
, CMaterial::SrcColor
);
162 matObject
->texEnvArg1RGB(3, CMaterial::Constant
, CMaterial::SrcColor
);
163 matObject
->texEnvArg2RGB(3, CMaterial::Previous
, CMaterial::SrcColor
);
165 // initialize linear blur material
166 _DisplayBlurMat
= _Driver
->createMaterial();
167 CMaterial
* matObjectFinal
= _DisplayBlurMat
.getObjectPtr();
168 _DisplayBlurMat
.initUnlit();
169 _DisplayBlurMat
.setColor(CRGBA::White
);
170 matObjectFinal
->setBlend(true);
171 matObjectFinal
->setBlendFunc(CMaterial::one
, CMaterial::invsrccolor
);
172 matObjectFinal
->setZWrite(false);
173 matObjectFinal
->setZFunc(CMaterial::always
);
174 matObjectFinal
->setDoubleSided(true);
176 // matObjectFinal->setTexture(0, _BlurFinalTex);
177 matObjectFinal
->texEnvOpRGB(0, CMaterial::Modulate
);
178 matObjectFinal
->texEnvArg0RGB(0, CMaterial::Texture
, CMaterial::SrcColor
);
179 matObjectFinal
->texEnvArg1RGB(0, CMaterial::Constant
, CMaterial::SrcColor
);
181 // initialize square blur material
182 _DisplaySquareBlurMat
= _Driver
->createMaterial();
183 matObjectFinal
= _DisplaySquareBlurMat
.getObjectPtr();
184 _DisplaySquareBlurMat
.initUnlit();
185 _DisplaySquareBlurMat
.setColor(CRGBA::White
);
186 matObjectFinal
->setBlend(true);
187 matObjectFinal
->setBlendFunc(CMaterial::one
, CMaterial::invsrccolor
);
188 matObjectFinal
->setZWrite(false);
189 matObjectFinal
->setZFunc(CMaterial::always
);
190 matObjectFinal
->setDoubleSided(true);
192 matObjectFinal
->texEnvOpRGB(0, CMaterial::Modulate
);
193 matObjectFinal
->texEnvArg0RGB(0, CMaterial::Texture
, CMaterial::SrcColor
);
194 matObjectFinal
->texEnvArg1RGB(0, CMaterial::Constant
, CMaterial::SrcColor
);
196 matObjectFinal
->texEnvOpRGB(1, CMaterial::Modulate
);
197 matObjectFinal
->texEnvArg0RGB(1, CMaterial::Texture
, CMaterial::SrcColor
);
198 matObjectFinal
->texEnvArg1RGB(1, CMaterial::Previous
, CMaterial::SrcColor
);
201 _BlurQuad
.V0
= CVector(-1.f
, -1.f
, 0.5f
);
202 _BlurQuad
.V1
= CVector(1.f
, -1.f
, 0.5f
);
203 _BlurQuad
.V2
= CVector(1.f
, 1.f
, 0.5f
);
204 _BlurQuad
.V3
= CVector(-1.f
, 1.f
, 0.5f
);
205 if (drv
->textureCoordinateAlternativeMode())
207 _BlurQuad
.Uv0
= CUV(0.f
, 1.f
);
208 _BlurQuad
.Uv1
= CUV(1.f
, 1.f
);
209 _BlurQuad
.Uv2
= CUV(1.f
, 0.f
);
210 _BlurQuad
.Uv3
= CUV(0.f
, 0.f
);
214 _BlurQuad
.Uv0
= CUV(0.f
, 0.f
);
215 _BlurQuad
.Uv1
= CUV(1.f
, 0.f
);
216 _BlurQuad
.Uv2
= CUV(1.f
, 1.f
);
217 _BlurQuad
.Uv3
= CUV(0.f
, 1.f
);
223 //-----------------------------------------------------------------------------------------------------------
225 void CBloomEffect::applyBloom()
227 if (!((CDriverUser
*)_Driver
)->getDriver()->supportBloomEffect())
230 // don't activate bloom when PolygonMode is different from Filled
231 if (_Driver
->getPolygonMode() != UDriver::Filled
) return;
233 if (_Driver
->getWindowWidth()==0 || _Driver
->getWindowHeight()==0)
239 CDriverUser
*dru
= static_cast<CDriverUser
*>(_Driver
);
240 IDriver
*drv
= dru
->getDriver();
243 bool fogEnabled
= _Driver
->fogEnabled();
244 _Driver
->enableFog(false);
246 NL3D::ITexture
*renderTarget
= drv
->getRenderTarget();
247 nlassert(renderTarget
);
248 nlassert(renderTarget
->isBloomTexture());
250 uint width
= renderTarget
->getWidth();
251 uint height
= renderTarget
->getHeight();
252 bool mode2D
= static_cast<CTextureBloom
*>(renderTarget
)->isMode2D();
253 nlassert(renderTarget
->getUploadFormat() == ITexture::Auto
);
255 if (width
>= 256) _BlurWidth
= 256;
256 else _BlurWidth
= raiseToNextPowerOf2(width
) / 2;
257 if (height
>= 256) _BlurHeight
= 256;
258 else _BlurHeight
= raiseToNextPowerOf2(height
) / 2;
260 nlassert(!_BlurFinalTex
);
261 _BlurFinalTex
= _Driver
->getRenderTargetManager().getRenderTarget(_BlurWidth
, _BlurHeight
, true);
262 nlassert(!_BlurHorizontalTex
);
263 _BlurHorizontalTex
= _Driver
->getRenderTargetManager().getRenderTarget(_BlurWidth
, _BlurHeight
, true);
265 _DisplayBlurMat
.getObjectPtr()->setTexture(0, _BlurFinalTex
->getITexture());
266 _DisplaySquareBlurMat
.getObjectPtr()->setTexture(0, _BlurFinalTex
->getITexture());
267 _DisplaySquareBlurMat
.getObjectPtr()->setTexture(1, _BlurFinalTex
->getITexture());
269 CTextureUser texNull
;
270 dru
->setRenderTarget(texNull
);
272 // Stretch original render target into blur texture
273 CTextureUser
txt1(renderTarget
);
274 CTextureUser
txt2(_BlurFinalTex
->getITexture());
275 CRect
rect1(0, 0, width
, height
);
276 CRect
rect2(0, 0, _BlurWidth
, _BlurHeight
);
277 dru
->stretchRect(_Scene
, txt1
, rect1
, txt2
, rect2
);
278 _Driver
->setMatrixMode2D11();
280 // horizontal blur pass
283 // vertical blur pass
286 // apply blur with a blend operation
287 drv
->setRenderTarget(renderTarget
);
288 _Driver
->setMatrixMode2D11();
291 // cleanup material texture references
292 _DisplayBlurMat
.getObjectPtr()->setTexture(0, NULL
);
293 _DisplaySquareBlurMat
.getObjectPtr()->setTexture(0, NULL
);
294 _DisplaySquareBlurMat
.getObjectPtr()->setTexture(1, NULL
);
295 _BlurMat
.getObjectPtr()->setTexture(0, NULL
);
296 _BlurMat
.getObjectPtr()->setTexture(1, NULL
);
297 _BlurMat
.getObjectPtr()->setTexture(2, NULL
);
298 _BlurMat
.getObjectPtr()->setTexture(3, NULL
);
301 _Driver
->enableFog(fogEnabled
);
303 // recycle render targets
304 _Driver
->getRenderTargetManager().recycleRenderTarget(_BlurFinalTex
);
305 _BlurFinalTex
= NULL
;
306 _Driver
->getRenderTargetManager().recycleRenderTarget(_BlurHorizontalTex
);
307 _BlurHorizontalTex
= NULL
;
310 //-----------------------------------------------------------------------------------------------------------
312 void CBloomEffect::applyBlur()
314 NL3D::IDriver
*drvInternal
= ((CDriverUser
*) _Driver
)->getDriver();
316 // initialize vertex program
317 drvInternal
->activeVertexProgram(TextureOffsetVertexProgram
);
318 drvInternal
->setUniform4f(IDriver::VertexProgram
, 8, 255.f
, 255.f
, 255.f
, 255.f
);
319 drvInternal
->setUniform4f(IDriver::VertexProgram
, 9, 0.0f
, 0.f
, 0.f
, 1.f
);
321 // initialize blur material
322 UMaterial displayBlurMat
;
325 displayBlurMat
= _DisplaySquareBlurMat
;
329 displayBlurMat
= _DisplayBlurMat
;
331 CMaterial
* matObjectFinal
= displayBlurMat
.getObjectPtr();
333 uint8 d
= _DensityBloom
;
334 CRGBA
constCoeff(d
, d
, d
, d
);
335 matObjectFinal
->texConstantColor(0, constCoeff
);
338 _Driver
->drawQuad(_BlurQuad
, displayBlurMat
);
340 // disable vertex program
341 drvInternal
->activeVertexProgram(NULL
);
344 //-----------------------------------------------------------------------------------------------------------
346 void CBloomEffect::doBlur(bool horizontalBlur
)
349 ITexture
* startTexture
;
350 ITexture
* endTexture
;
352 // set displayed texture and render target texture of the pass
355 blurVec
= CVector2f(1.f
, 0.f
);
356 startTexture
= _BlurFinalTex
->getITexture();
357 endTexture
= _BlurHorizontalTex
->getITexture();
361 blurVec
= CVector2f(0.f
, 1.f
);
362 startTexture
= _BlurHorizontalTex
->getITexture();
363 endTexture
= _BlurFinalTex
->getITexture();
366 NL3D::IDriver
*drvInternal
= ((CDriverUser
*) _Driver
)->getDriver();
367 CTextureUser
txt(endTexture
);
368 // initialize render target
369 if(!((CDriverUser
*) _Driver
)->setRenderTarget(txt
, 0, 0, _BlurWidth
, _BlurHeight
))
371 nlwarning("setRenderTarget return false with blur texture for bloom effect\n");
374 _Driver
->setMatrixMode2D11();
376 // initialize vertex program
377 drvInternal
->activeVertexProgram(TextureOffsetVertexProgram
);
378 drvInternal
->setUniform4f(IDriver::VertexProgram
, 8, 255.f
, 255.f
, 255.f
, 255.f
);
379 drvInternal
->setUniform4f(IDriver::VertexProgram
, 9, 0.0f
, 0.f
, 0.f
, 1.f
);
381 // set several decal constants in order to obtain in the render target texture a mix of color
382 // of a texel and its neighbored texels on the axe of the pass.
383 float decalL
, decal2L
, decalR
, decal2R
;
384 if (drvInternal
->textureCoordinateAlternativeMode())
408 drvInternal
->setUniform2f(IDriver::VertexProgram
, 10, (decalR
/(float)_BlurWidth
)*blurVec
.x
, (decalR
/(float)_BlurHeight
)*blurVec
.y
);
409 drvInternal
->setUniform2f(IDriver::VertexProgram
, 11, (decal2R
/(float)_BlurWidth
)*blurVec
.x
, (decal2R
/(float)_BlurHeight
)*blurVec
.y
);
410 drvInternal
->setUniform2f(IDriver::VertexProgram
, 12, (decalL
/(float)_BlurWidth
)*blurVec
.x
, (decalL
/(float)_BlurHeight
)*blurVec
.y
);
411 drvInternal
->setUniform2f(IDriver::VertexProgram
, 13, (decal2L
/(float)_BlurWidth
)*blurVec
.x
, (decal2L
/(float)_BlurHeight
)*blurVec
.y
);
413 // initialize material textures
414 CMaterial
* matObject
= _BlurMat
.getObjectPtr();
415 matObject
->setTexture(0, startTexture
);
416 matObject
->setTexture(1, startTexture
);
417 matObject
->setTexture(2, startTexture
);
418 matObject
->setTexture(3, startTexture
);
421 _Driver
->drawQuad(_BlurQuad
, _BlurMat
);
423 // disable render target and vertex program
424 drvInternal
->activeVertexProgram(NULL
);
426 ((CDriverUser
*)_Driver
)->setRenderTarget(cu
, 0, 0, 0, 0);