aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/linden/indra/newview/llpostprocess.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--linden/indra/newview/llpostprocess.cpp594
1 files changed, 0 insertions, 594 deletions
diff --git a/linden/indra/newview/llpostprocess.cpp b/linden/indra/newview/llpostprocess.cpp
deleted file mode 100644
index c7d5dad..0000000
--- a/linden/indra/newview/llpostprocess.cpp
+++ /dev/null
@@ -1,594 +0,0 @@
1/**
2 * @file llpostprocess.cpp
3 * @brief LLPostProcess class implementation
4 *
5 * $LicenseInfo:firstyear=2007&license=viewergpl$
6 *
7 * Copyright (c) 2007-2009, Linden Research, Inc.
8 *
9 * Second Life Viewer Source Code
10 * The source code in this file ("Source Code") is provided by Linden Lab
11 * to you under the terms of the GNU General Public License, version 2.0
12 * ("GPL"), unless you have obtained a separate licensing agreement
13 * ("Other License"), formally executed by you and Linden Lab. Terms of
14 * the GPL can be found in doc/GPL-license.txt in this distribution, or
15 * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
16 *
17 * There are special exceptions to the terms and conditions of the GPL as
18 * it is applied to this Source Code. View the full text of the exception
19 * in the file doc/FLOSS-exception.txt in this software distribution, or
20 * online at
21 * http://secondlifegrid.net/programs/open_source/licensing/flossexception
22 *
23 * By copying, modifying or distributing this software, you acknowledge
24 * that you have read and understood your obligations described above,
25 * and agree to abide by those obligations.
26 *
27 * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
28 * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
29 * COMPLETENESS OR PERFORMANCE.
30 * $/LicenseInfo$
31 */
32
33#include "llviewerprecompiledheaders.h"
34
35#include "linden_common.h"
36
37#include "llpostprocess.h"
38#include "llglslshader.h"
39#include "llsdserialize.h"
40#include "llrender.h"
41
42#include "llviewershadermgr.h" // KL throwing some includes at postprocess see if we can get the bastard working!
43#include "pipeline.h"
44#include "llimagegl.h"
45
46
47
48LLPostProcess * gPostProcess = NULL;
49
50
51static const unsigned int NOISE_SIZE = 512;
52
53/// CALCULATING LUMINANCE (Using NTSC lum weights)
54/// http://en.wikipedia.org/wiki/Luma_%28video%29
55static const float LUMINANCE_R = 0.299f;
56static const float LUMINANCE_G = 0.587f;
57static const float LUMINANCE_B = 0.114f;
58
59static const char * const XML_FILENAME = "postprocesseffects.xml";
60
61LLPostProcess::LLPostProcess(void) :
62 initialized(false),
63 mAllEffects(LLSD::emptyMap()),
64 screenW(1), screenH(1)
65{
66 mSceneRenderTexture = NULL ;
67 mNoiseTexture = NULL ;
68 mTempBloomTexture = NULL ;
69
70 // Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender.
71 std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME));
72 LL_DEBUGS2("AppInit", "Shaders") << "Loading PostProcess Effects settings from " << pathName << LL_ENDL;
73
74 llifstream effectsXML(pathName);
75
76 if (effectsXML)
77 {
78 LLPointer<LLSDParser> parser = new LLSDXMLParser();
79
80 parser->parse(effectsXML, mAllEffects, LLSDSerialize::SIZE_UNLIMITED);
81 }
82
83 if (!mAllEffects.has("default"))
84 {
85 LLSD & defaultEffect = (mAllEffects["default"] = LLSD::emptyMap());
86
87 defaultEffect["enable_night_vision"] = LLSD::Boolean(false);
88 defaultEffect["enable_bloom"] = LLSD::Boolean(false);
89 defaultEffect["enable_color_filter"] = LLSD::Boolean(false);
90
91 /// NVG Defaults
92 defaultEffect["brightness_multiplier"] = 3.0;
93 defaultEffect["noise_size"] = 25.0;
94 defaultEffect["noise_strength"] = 0.4;
95
96 // TODO BTest potentially add this to tweaks?
97 noiseTextureScale = 1.0f;
98
99 /// Bloom Defaults
100 defaultEffect["extract_low"] = 0.95;
101 defaultEffect["extract_high"] = 1.0;
102 defaultEffect["bloom_width"] = 2.25;
103 defaultEffect["bloom_strength"] = 1.5;
104
105 /// Color Filter Defaults
106 defaultEffect["brightness"] = 1.0;
107 defaultEffect["contrast"] = 1.0;
108 defaultEffect["saturation"] = 1.0;
109
110 LLSD& contrastBase = (defaultEffect["contrast_base"] = LLSD::emptyArray());
111 contrastBase.append(1.0);
112 contrastBase.append(1.0);
113 contrastBase.append(1.0);
114 contrastBase.append(0.5);
115 }
116
117 setSelectedEffect("default");
118
119}
120
121LLPostProcess::~LLPostProcess(void)
122{
123 invalidate() ;
124}
125
126// static
127void LLPostProcess::initClass(void)
128{
129 //this will cause system to crash at second time login
130 //if first time login fails due to network connection --- bao
131 //***llassert_always(gPostProcess == NULL);
132 //replaced by the following line:
133 if(gPostProcess)
134 return ;
135
136
137 gPostProcess = new LLPostProcess();
138}
139
140// static
141void LLPostProcess::cleanupClass()
142{
143 delete gPostProcess;
144 gPostProcess = NULL;
145}
146
147void LLPostProcess::setSelectedEffect(std::string const & effectName)
148{
149 mSelectedEffectName = effectName;
150 static_cast<LLSD &>(tweaks) = mAllEffects[effectName];
151}
152
153void LLPostProcess::saveEffect(std::string const & effectName)
154{
155 // Do nothing. Needs to be updated to use our current shader system, and to work with the move into llrender.
156 mAllEffects[effectName] = tweaks;
157
158 std::string pathName(gDirUtilp->getExpandedFilename(LL_PATH_APP_SETTINGS, "windlight", XML_FILENAME));
159 //llinfos << "Saving PostProcess Effects settings to " << pathName << llendl;
160
161 llofstream effectsXML(pathName);
162
163 LLPointer<LLSDFormatter> formatter = new LLSDXMLFormatter();
164
165 formatter->format(mAllEffects, effectsXML);
166
167}
168void LLPostProcess::invalidate()
169{
170 mSceneRenderTexture = NULL ;
171 mNoiseTexture = NULL ;
172 mTempBloomTexture = NULL ;
173 initialized = FALSE ;
174}
175
176void LLPostProcess::apply(unsigned int width, unsigned int height)
177{
178 if (!initialized || width != screenW || height != screenH){
179 initialize(width, height);
180 }
181 if (shadersEnabled()){
182 doEffects();
183 }
184}
185
186void LLPostProcess::initialize(unsigned int width, unsigned int height)
187{
188 screenW = width;
189 screenH = height;
190 createTexture(mSceneRenderTexture, screenW, screenH);
191 initialized = true;
192
193 checkError();
194 createNightVisionShader();
195 createBloomShader();
196 createColorFilterShader();
197 checkError();
198}
199
200inline bool LLPostProcess::shadersEnabled(void)
201{
202 return (tweaks.useColorFilter().asBoolean() ||
203 tweaks.useNightVisionShader().asBoolean() ||
204 tweaks.useBloomShader().asBoolean() );
205
206}
207
208void LLPostProcess::applyShaders(void)
209{
210 if (tweaks.useColorFilter()){
211 applyColorFilterShader();
212 checkError();
213 }
214 if (tweaks.useNightVisionShader()){
215 /// If any of the above shaders have been called update the frame buffer;
216 if (tweaks.useColorFilter())
217 {
218 U32 tex = mSceneRenderTexture->getTexName() ;
219 copyFrameBuffer(tex, screenW, screenH);
220 }
221 applyNightVisionShader();
222 checkError();
223 }
224 if (tweaks.useBloomShader()){
225 /// If any of the above shaders have been called update the frame buffer;
226 if (tweaks.useColorFilter().asBoolean() || tweaks.useNightVisionShader().asBoolean())
227 {
228 U32 tex = mSceneRenderTexture->getTexName() ;
229 copyFrameBuffer(tex, screenW, screenH);
230 }
231 applyBloomShader();
232 checkError();
233 }
234}
235
236void LLPostProcess::applyColorFilterShader(void)
237{
238 // Do nothing. moved back to newview work in progress KL
239 gPostColorFilterProgram.bind();
240
241 gGL.getTexUnit(0)->activate();
242 gGL.getTexUnit(0)->enable(LLTexUnit::TT_RECT_TEXTURE);
243
244 U32 tex = mSceneRenderTexture->getTexName() ; // KL
245
246 gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, tex);
247
248 getShaderUniforms(colorFilterUniforms, gPostColorFilterProgram.mProgramObject);
249 glUniform1iARB(colorFilterUniforms["RenderTexture"], 0);
250 glUniform1fARB(colorFilterUniforms["brightness"], tweaks.getBrightness());
251 glUniform1fARB(colorFilterUniforms["contrast"], tweaks.getContrast());
252 float baseI = (tweaks.getContrastBaseR() + tweaks.getContrastBaseG() + tweaks.getContrastBaseB()) / 3.0f;
253 baseI = tweaks.getContrastBaseIntensity() / ((baseI < 0.001f) ? 0.001f : baseI);
254 float baseR = tweaks.getContrastBaseR() * baseI;
255 float baseG = tweaks.getContrastBaseG() * baseI;
256 float baseB = tweaks.getContrastBaseB() * baseI;
257 glUniform3fARB(colorFilterUniforms["contrastBase"], baseR, baseG, baseB);
258 glUniform1fARB(colorFilterUniforms["saturation"], tweaks.getSaturation());
259 glUniform3fARB(colorFilterUniforms["lumWeights"], LUMINANCE_R, LUMINANCE_G, LUMINANCE_B);
260
261 LLGLEnable blend(GL_BLEND);
262 gGL.setSceneBlendType(LLRender::BT_REPLACE);
263 LLGLDepthTest depth(GL_FALSE);
264
265 /// Draw a screen space quad
266 drawOrthoQuad(screenW, screenH, QUAD_NORMAL);
267 gPostColorFilterProgram.unbind();
268
269}
270
271void LLPostProcess::createColorFilterShader(void)
272{
273 /// Define uniform names
274 colorFilterUniforms["RenderTexture"] = 0;
275 colorFilterUniforms["brightness"] = 0;
276 colorFilterUniforms["contrast"] = 0;
277 colorFilterUniforms["contrastBase"] = 0;
278 colorFilterUniforms["saturation"] = 0;
279 colorFilterUniforms["lumWeights"] = 0;
280}
281
282void LLPostProcess::applyNightVisionShader(void)
283{
284 // KL re-enabled and moved back to newview
285 gPostNightVisionProgram.bind();
286
287 gGL.getTexUnit(0)->activate();
288 gGL.getTexUnit(0)->enable(LLTexUnit::TT_RECT_TEXTURE);
289
290 getShaderUniforms(nightVisionUniforms, gPostNightVisionProgram.mProgramObject);
291 U32 sceneRenderTexture = mSceneRenderTexture->getTexName() ; // KL
292 gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, sceneRenderTexture);
293 glUniform1iARB(nightVisionUniforms["RenderTexture"], 0);
294
295 gGL.getTexUnit(1)->activate();
296 gGL.getTexUnit(1)->enable(LLTexUnit::TT_TEXTURE);
297 U32 noiseTexture = mNoiseTexture->getTexName(); //KL
298 gGL.getTexUnit(1)->bindManual(LLTexUnit::TT_TEXTURE, noiseTexture);
299 glUniform1iARB(nightVisionUniforms["NoiseTexture"], 1);
300
301
302 glUniform1fARB(nightVisionUniforms["brightMult"], tweaks.getBrightMult());
303 glUniform1fARB(nightVisionUniforms["noiseStrength"], tweaks.getNoiseStrength());
304 noiseTextureScale = 0.01f + ((101.f - tweaks.getNoiseSize()) / 100.f);
305 noiseTextureScale *= (screenH / NOISE_SIZE);
306
307
308 glUniform3fARB(nightVisionUniforms["lumWeights"], LUMINANCE_R, LUMINANCE_G, LUMINANCE_B);
309
310 LLGLEnable blend(GL_BLEND);
311 gGL.setSceneBlendType(LLRender::BT_REPLACE);
312 LLGLDepthTest depth(GL_FALSE);
313
314 /// Draw a screen space quad
315 drawOrthoQuad(screenW, screenH, QUAD_NOISE);
316 gPostNightVisionProgram.unbind();
317 gGL.getTexUnit(0)->activate();
318
319}
320
321void LLPostProcess::createNightVisionShader(void)
322{
323 /// Define uniform names
324 nightVisionUniforms["RenderTexture"] = 0;
325 nightVisionUniforms["NoiseTexture"] = 0;
326 nightVisionUniforms["brightMult"] = 0;
327 nightVisionUniforms["noiseStrength"] = 0;
328 nightVisionUniforms["lumWeights"] = 0;
329
330 createNoiseTexture(mNoiseTexture);
331}
332
333void LLPostProcess::applyBloomShader(void)
334{
335
336}
337
338void LLPostProcess::createBloomShader(void)
339{
340 createTexture(mTempBloomTexture, unsigned(screenW * 0.5), unsigned(screenH * 0.5));
341
342 /// Create Bloom Extract Shader
343 bloomExtractUniforms["RenderTexture"] = 0;
344 bloomExtractUniforms["extractLow"] = 0;
345 bloomExtractUniforms["extractHigh"] = 0;
346 bloomExtractUniforms["lumWeights"] = 0;
347
348 /// Create Bloom Blur Shader
349 bloomBlurUniforms["RenderTexture"] = 0;
350 bloomBlurUniforms["bloomStrength"] = 0;
351 bloomBlurUniforms["texelSize"] = 0;
352 bloomBlurUniforms["blurDirection"] = 0;
353 bloomBlurUniforms["blurWidth"] = 0;
354}
355
356void LLPostProcess::getShaderUniforms(glslUniforms & uniforms, GLhandleARB & prog)
357{
358 /// Find uniform locations and insert into map
359 std::map<const char *, GLuint>::iterator i;
360 for (i = uniforms.begin(); i != uniforms.end(); ++i){
361 i->second = glGetUniformLocationARB(prog, i->first);
362 }
363}
364
365void LLPostProcess::doEffects(void)
366{
367 /// Save GL State
368 glPushAttrib(GL_ALL_ATTRIB_BITS);
369 glPushClientAttrib(GL_ALL_ATTRIB_BITS);
370
371 /// Copy the screen buffer to the render texture
372 {
373 U32 tex = mSceneRenderTexture->getTexName() ;
374 copyFrameBuffer(tex, screenW, screenH);
375 }
376
377 /// Clear the frame buffer.
378 glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
379 glClear(GL_COLOR_BUFFER_BIT);
380
381 /// Change to an orthogonal view
382 viewOrthogonal(screenW, screenH);
383
384 checkError();
385 applyShaders();
386
387 LLGLSLShader::bindNoShader();
388 checkError();
389
390 /// Change to a perspective view
391 viewPerspective();
392
393 /// Reset GL State
394 glPopClientAttrib();
395 glPopAttrib();
396 checkError();
397}
398
399void LLPostProcess::copyFrameBuffer(U32 & texture, unsigned int width, unsigned int height)
400{
401 gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, texture);
402 glCopyTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, GL_RGBA, 0, 0, width, height, 0);
403}
404
405void LLPostProcess::drawOrthoQuad(unsigned int width, unsigned int height, QuadType type)
406{
407
408 float noiseX = 0.f;
409 float noiseY = 0.f;
410 float screenRatio = 1.0f;
411
412 if (type == QUAD_NOISE){
413 noiseX = ((float) rand() / (float) RAND_MAX);
414 noiseY = ((float) rand() / (float) RAND_MAX);
415 screenRatio = (float) width / (float) height;
416 }
417
418
419 glBegin(GL_QUADS);
420 if (type != QUAD_BLOOM_EXTRACT){
421 glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.f, (GLfloat) height);
422 } else {
423 glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.f, (GLfloat) height * 2.0f);
424 }
425 if (type == QUAD_NOISE){
426 glMultiTexCoord2fARB(GL_TEXTURE1_ARB,
427 noiseX,
428 noiseTextureScale + noiseY);
429 } else if (type == QUAD_BLOOM_COMBINE){
430 glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.f, (GLfloat) height * 0.5f);
431 }
432 glVertex2f(0.f, (GLfloat) screenH - height);
433
434 if (type != QUAD_BLOOM_EXTRACT){
435 glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.f, 0.f);
436 } else {
437 glMultiTexCoord2fARB(GL_TEXTURE0_ARB, 0.f, 0.f);
438 }
439 if (type == QUAD_NOISE){
440 glMultiTexCoord2fARB(GL_TEXTURE1_ARB,
441 noiseX,
442 noiseY);
443 } else if (type == QUAD_BLOOM_COMBINE){
444 glMultiTexCoord2fARB(GL_TEXTURE1_ARB, 0.f, 0.f);
445 }
446 glVertex2f(0.f, (GLfloat) height + (screenH - height));
447
448
449 if (type != QUAD_BLOOM_EXTRACT){
450 glMultiTexCoord2fARB(GL_TEXTURE0_ARB, (GLfloat) width, 0.f);
451 } else {
452 glMultiTexCoord2fARB(GL_TEXTURE0_ARB, (GLfloat) width * 2.0f, 0.f);
453 }
454 if (type == QUAD_NOISE){
455 glMultiTexCoord2fARB(GL_TEXTURE1_ARB,
456 screenRatio * noiseTextureScale + noiseX,
457 noiseY);
458 } else if (type == QUAD_BLOOM_COMBINE){
459 glMultiTexCoord2fARB(GL_TEXTURE1_ARB, (GLfloat) width * 0.5f, 0.f);
460 }
461 glVertex2f((GLfloat) width, (GLfloat) height + (screenH - height));
462
463
464 if (type != QUAD_BLOOM_EXTRACT){
465 glMultiTexCoord2fARB(GL_TEXTURE0_ARB, (GLfloat) width, (GLfloat) height);
466 } else {
467 glMultiTexCoord2fARB(GL_TEXTURE0_ARB, (GLfloat) width * 2.0f, (GLfloat) height * 2.0f);
468 }
469 if (type == QUAD_NOISE){
470 glMultiTexCoord2fARB(GL_TEXTURE1_ARB,
471 screenRatio * noiseTextureScale + noiseX,
472 noiseTextureScale + noiseY);
473 } else if (type == QUAD_BLOOM_COMBINE){
474 glMultiTexCoord2fARB(GL_TEXTURE1_ARB, (GLfloat) width * 0.5f, (GLfloat) height * 0.5f);
475 }
476 glVertex2f((GLfloat) width, (GLfloat) screenH - height);
477 glEnd();
478
479}
480
481void LLPostProcess::viewOrthogonal(unsigned int width, unsigned int height)
482{
483 glMatrixMode(GL_PROJECTION);
484 glPushMatrix();
485 glLoadIdentity();
486 glOrtho( 0.f, (GLdouble) width , (GLdouble) height , 0.f, -1.f, 1.f );
487 glMatrixMode(GL_MODELVIEW);
488 glPushMatrix();
489 glLoadIdentity();
490}
491
492void LLPostProcess::viewPerspective(void)
493{
494 glMatrixMode( GL_PROJECTION );
495 glPopMatrix();
496 glMatrixMode( GL_MODELVIEW );
497 glPopMatrix();
498}
499
500void LLPostProcess::changeOrthogonal(unsigned int width, unsigned int height)
501{
502 viewPerspective();
503 viewOrthogonal(width, height);
504}
505
506void LLPostProcess::createTexture(LLPointer<LLImageGL>& texture, unsigned int width, unsigned int height)
507{
508 std::vector<GLubyte> data(width * height * 4, 0) ;
509
510 texture = new LLImageGL(FALSE) ;
511 if(texture->createGLTexture())
512 {
513 gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_RECT_TEXTURE, texture->getTexName());
514 glTexImage2D(GL_TEXTURE_RECTANGLE_ARB, 0, 4, width, height, 0,
515 GL_RGBA, GL_UNSIGNED_BYTE, &data[0]);
516 gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
517 gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_CLAMP);
518 }
519}
520
521void LLPostProcess::createNoiseTexture(LLPointer<LLImageGL>& texture)
522{
523 std::vector<GLubyte> buffer(NOISE_SIZE * NOISE_SIZE);
524 for (unsigned int i = 0; i < NOISE_SIZE; i++){
525 for (unsigned int k = 0; k < NOISE_SIZE; k++){
526 buffer[(i * NOISE_SIZE) + k] = (GLubyte)((double) rand() / ((double) RAND_MAX + 1.f) * 255.f);
527 }
528 }
529
530 texture = new LLImageGL(FALSE) ;
531 if(texture->createGLTexture())
532 {
533 gGL.getTexUnit(0)->bindManual(LLTexUnit::TT_TEXTURE, texture->getTexName());
534 LLImageGL::setManualImage(GL_TEXTURE_2D, 0, GL_LUMINANCE, NOISE_SIZE, NOISE_SIZE, GL_LUMINANCE, GL_UNSIGNED_BYTE, &buffer[0]);
535 gGL.getTexUnit(0)->setTextureFilteringOption(LLTexUnit::TFO_BILINEAR);
536 gGL.getTexUnit(0)->setTextureAddressMode(LLTexUnit::TAM_WRAP);
537 }
538}
539
540bool LLPostProcess::checkError(void)
541{
542 GLenum glErr;
543 bool retCode = false;
544
545 glErr = glGetError();
546 while (glErr != GL_NO_ERROR)
547 {
548 // shaderErrorLog << (const char *) gluErrorString(glErr) << std::endl;
549 char const * err_str_raw = (const char *) gluErrorString(glErr);
550
551 if(err_str_raw == NULL)
552 {
553 std::ostringstream err_builder;
554 err_builder << "unknown error number " << glErr;
555 mShaderErrorString = err_builder.str();
556 }
557 else
558 {
559 mShaderErrorString = err_str_raw;
560 }
561
562 retCode = true;
563 glErr = glGetError();
564 }
565 return retCode;
566}
567
568void LLPostProcess::checkShaderError(GLhandleARB shader)
569{
570 GLint infologLength = 0;
571 GLint charsWritten = 0;
572 GLchar *infoLog;
573
574 checkError(); // Check for OpenGL errors
575
576 glGetObjectParameterivARB(shader, GL_OBJECT_INFO_LOG_LENGTH_ARB, &infologLength);
577
578 checkError(); // Check for OpenGL errors
579
580 if (infologLength > 0)
581 {
582 infoLog = (GLchar *)malloc(infologLength);
583 if (infoLog == NULL)
584 {
585 /// Could not allocate infolog buffer
586 return;
587 }
588 glGetInfoLogARB(shader, infologLength, &charsWritten, infoLog);
589 // shaderErrorLog << (char *) infoLog << std::endl;
590 mShaderErrorString = (char *) infoLog;
591 free(infoLog);
592 }
593 checkError(); // Check for OpenGL errors
594} \ No newline at end of file