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