Wymaga OpenGL, GLEW (do shaderow) i GLTools.
/* * BloomPostProcess.h * * Created on: 2011-06-27 * Author: myood */ /* * KNOWN BUGS: * * if new width while resizing is < 16, then GL_ERROR_INVALID_OPERATION occur */ #ifndef BLOOMPOSTPROCESS_H_ #define BLOOMPOSTPROCESS_H_ #include#include #include #include #include /* * Typical usage: * initialize once: * BloomPostProcess::getInstance()->init(); * * in resize screen handling: * BloomPostProcess::getInstance()->resize(); * * render loop: * { * BloomPostProcess::getInstance()->BeginRendering(); * * --do normal rendering-- * BloomPostProcess::getInstance()->BeginGlowParts(); * --do rendering-- * BloomPostProcess::getInstance()->PostProcess(); * BloomPostProcess::getInstance()->display(); * } * * cleanup: * BloomPostProcess::getInstance()->finalize(); * BloomPostProcess::getInstance()->destroy(); */ class BloomPostProcess { public: enum BLOOM_STATE { NONEXISTENT, //Before instatination or after destroy() call INSTANITED, //After getInstance() call INITIALIZED, //After init() or display() call RENDERED, //After BeginRendering() call PREPROCESSED, //After BeginGlowParts() call POSTPROCESSED, //After PostProcess() call FINALIZED, //After cleanup() or finalize() call DESTROYED //After destroy() call, next call will return NONEXISTENT }; bool debug; static BloomPostProcess* getInstance(); virtual ~BloomPostProcess(){}; inline static enum BLOOM_STATE getState(); /* * Initialize Bloom Post Process Effect */ GLenum init(int newScreenWidth, int newScreenHeight, int RENDER_STEPS=3); /* * Do clean up - free memory etc. * Both functions do exactly the same. */ GLenum finalize(); inline GLenum cleanup(); /* * Destroy post processing effect */ GLenum destroy(); /* * Resize handling */ GLenum resize(int new_width, int new_height); /* * Pre and post process glow, display effect on screen */ GLenum BeginRendering(); GLenum BeginGlowParts(); GLenum PostProcess(); GLenum Display(); /* * Resize screen function */ //todo /* * LOTS OF TO DO :) */ protected: BloomPostProcess(bool doWeDebug= true) { mp_state= NONEXISTENT; debug= doWeDebug; } private: static BloomPostProcess* mp_BloomPostProcess; BloomPostProcess( BloomPostProcess const& bps){} BloomPostProcess& operator=(BloomPostProcess const&){ return *this; } /* * CONFIGURATION */ static BLOOM_STATE mp_state; int mp_iScreenWidth; int mp_iScreenHeight; int mp_iPostRenderSteps; GLenum* mp_fboBuffs; GLenum* mp_fboWindowBuff; //todo --- ?resize? /* * SHADERS */ //This shader is used to downsampling textures GLint* mp_shScreenTextMVP; //This shader is used to find glowing parts, //but it is deprecated. // GLint* processGlowShader; //Blur scene horizontally GLint* mp_shBlurHori; //Blur scene verticaly GLint* mp_shBlurVerti; //This shader is used to create bloom effect - //it add all downsampled textures to the //normally rendered scene texture. GLint* mp_shPostProcess; /* * TEXTURES */ GLuint* mp_texRendering; GLuint* mp_texGlowParts; GLuint* mp_texDownsampled; GLuint* mp_texHoriBlur; GLuint* mp_texVertBlur; GLuint* mp_texGlowing; /* * FBOS */ GLuint* mp_fboRendering; GLuint* mp_fboGlowParts; GLuint* mp_fboDownsampled; GLuint* mp_fboHoriBlur; GLuint* mp_fboVertBlur; GLuint* mp_fboGlowing; /* * RBO */ GLuint* mp_rboRendering; /* * PROJECTION MATRICES AND SCREEN QUADS */ M3DMatrix44f* mp_OrthoMatrix; GLBatch* mp_ScreenQuad; /* * ACTIONS */ GLenum createAndBindFBO(int* ScreenWidth, int* ScreenHeight, GLuint* FBO, GLuint* Texture, GLuint* DepthBuffer= NULL); GLenum renderTextureOnWholeScreen(GLuint* textureID, GLint* shader, float v4color[4], int i= 0); }; #endif /* BLOOMPOSTPROCESS_H_ */
/* * BloomPostProcess.cpp * * Created on: 2011-06-27 * Author: myood */ #include "BloomPostProcess.h" // enum BLOOM_STATE { // NONEXISTENT, //Before intatination or after destroy() call // INSTANITED, //After getInstance() call // INITIALIZED, //After init() call // FINALIZED, //After cleanup() or finalize() call // DESTROYED //After destroy() call, next call will return NONEXISTENT // }; BloomPostProcess* BloomPostProcess::mp_BloomPostProcess= 0; BloomPostProcess::BLOOM_STATE BloomPostProcess::mp_state= NONEXISTENT; BloomPostProcess* BloomPostProcess::getInstance() { if ( !mp_BloomPostProcess ) { mp_BloomPostProcess= new BloomPostProcess(); mp_state= INSTANITED; } return mp_BloomPostProcess; } BloomPostProcess::BLOOM_STATE BloomPostProcess::getState() { return mp_state; } //todo changable postrender steps GLenum BloomPostProcess::init(int newScreenWidth, int newScreenHeight, int POSTRENDER_STEPS) { /* * STATE CHECK */ if ( mp_state != INSTANITED ) { if ( debug ) { std::cerr << "BloomPostProcess::init() Invalid operation.\n" << "\tObject is in wrong state - it must be INSTANITED.\n" << "\tYou can get current state by calling getState(). \n" << "\tCall getInstance() first, or finalize() and destroy() in that order." << std::endl; } return GL_INVALID_OPERATION; } /* * AVAILABLE TEXTURE UNITS CHECK */ GLint iMAX_TEXT_UNITS= 0; glGetIntegerv(GL_MAX_TEXTURE_UNITS, &iMAX_TEXT_UNITS); if ( iMAX_TEXT_UNITS < POSTRENDER_STEPS+1 ) { std::cerr << "Error: Not enough available textures in multitexturing, required: " << POSTRENDER_STEPS+1 <<", implementation have: " << iMAX_TEXT_UNITS << std::endl; return GL_OUT_OF_MEMORY; } else std::cout << "OK: Enough available textures in multitexturing, required: 4, " << "implementation have: " << iMAX_TEXT_UNITS << std::endl; if ( POSTRENDER_STEPS != 3 ) { fprintf(stderr, "Error: Sorry, post render steps value must be 3, different render steps are not implemented yet." ); return GL_INVALID_VALUE; } /* * CFG SAVE */ mp_iPostRenderSteps= POSTRENDER_STEPS; mp_iScreenWidth= newScreenWidth; mp_iScreenHeight= newScreenHeight; /* * FLAT SCREEN MVP ALLOCATION */ mp_OrthoMatrix= new M3DMatrix44f[mp_iPostRenderSteps]; mp_ScreenQuad= new GLBatch[mp_iPostRenderSteps]; /* * TEXTURES VARS ALLOCATION */ //TODO //FREE MEMORY IN FINALIZE mp_texRendering= new GLuint; mp_texGlowParts= new GLuint; mp_texGlowing= new GLuint; mp_texDownsampled= new GLuint[mp_iPostRenderSteps]; mp_texHoriBlur= new GLuint[mp_iPostRenderSteps]; mp_texVertBlur= new GLuint[mp_iPostRenderSteps]; /* * FBO & RBO VARS ALLOC */ mp_fboRendering= new GLuint; mp_fboGlowParts= new GLuint; mp_fboDownsampled= new GLuint[mp_iPostRenderSteps]; mp_fboHoriBlur= new GLuint[mp_iPostRenderSteps]; mp_fboVertBlur= new GLuint[mp_iPostRenderSteps]; mp_fboGlowing= new GLuint; mp_rboRendering= new GLuint; /* * ATTACHMENTS ALLOC AND SETUP */ mp_fboBuffs= new GLenum(GL_COLOR_ATTACHMENT0); mp_fboWindowBuff= new GLenum(GL_BACK_LEFT); /* * SHADERS VARS ALLOC */ mp_shScreenTextMVP= new GLint; mp_shBlurHori= new GLint; mp_shBlurVerti= new GLint; mp_shPostProcess= new GLint; GLenum error; if ( (error= createAndBindFBO(&mp_iScreenWidth,&mp_iScreenHeight,mp_fboRendering,mp_texRendering,mp_rboRendering)) != GL_NO_ERROR ) return error; if ( (error= createAndBindFBO(&mp_iScreenWidth,&mp_iScreenHeight,mp_fboGlowParts,mp_texGlowParts)) != GL_NO_ERROR ) return error; int l_screenWidth= mp_iScreenWidth >> 2; int l_screenHeight= mp_iScreenHeight >> 2; for ( int i= 0; i < mp_iPostRenderSteps; i++ ) { gltGenerateOrtho2DMat(l_screenWidth, l_screenHeight, mp_OrthoMatrix[i], mp_ScreenQuad[i]); if ( (error= createAndBindFBO(&l_screenWidth,&l_screenHeight,&mp_fboDownsampled[i],&mp_texDownsampled[i])) != GL_NO_ERROR ) return error; if ( (error= createAndBindFBO(&l_screenWidth,&l_screenHeight,&mp_fboHoriBlur[i],&mp_texHoriBlur[i])) != GL_NO_ERROR ) return error; if ( (error= createAndBindFBO(&l_screenWidth,&l_screenHeight,&mp_fboVertBlur[i],&mp_texVertBlur[i])) != GL_NO_ERROR ) return error; l_screenWidth= l_screenWidth >> 1; l_screenHeight= l_screenHeight >> 1; } //ladowanie shadera rysowania na ekranie *mp_shScreenTextMVP = gltLoadShaderPairWithAttributes( "shadery/textured.vp", "shadery/textured.fp", 2, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_TEXTURE0, "vTexCoords"); //ladowanie shadera rozmycia horyzontalnego *mp_shBlurHori = gltLoadShaderPairWithAttributes( "shadery/blurh.vp", "shadery/blurh.fp", 2, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_TEXTURE0, "vTexCoords"); //ladowanie shadera rozmycie pionowego *mp_shBlurVerti = gltLoadShaderPairWithAttributes( "shadery/blurv.vp", "shadery/blurv.fp", 2, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_TEXTURE0, "vTexCoords"); //ladowanie shadera rozmycie pionowego *mp_shPostProcess = gltLoadShaderPairWithAttributes( "shadery/addition.vp", "shadery/addition.fp", 2, GLT_ATTRIBUTE_VERTEX, "vVertex", GLT_ATTRIBUTE_TEXTURE0, "vTexCoords"); mp_state= INITIALIZED; return GL_NO_ERROR; } GLenum BloomPostProcess::finalize() { if ( mp_state != INITIALIZED ) { if ( debug ) { std::cerr << "BloomPostProcess::finalize() Invalid operation.\n" << "\tObject is in wrong state - it must be INITIALIZED.\n" << "\tYou can get current state by calling getState(). \n" << "\tCall init() first." << std::endl; } return GL_INVALID_OPERATION; } // Cleanup textures for ( int i= 0; i < mp_iPostRenderSteps; i++ ) { //TODO I HOPE ITS CORRECT :) glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, 0); } glDeleteTextures(1, mp_texRendering); glDeleteTextures(1, mp_texGlowParts); glDeleteTextures(1, mp_texGlowing); glDeleteTextures(mp_iPostRenderSteps, mp_texDownsampled); glDeleteTextures(mp_iPostRenderSteps, mp_texHoriBlur); glDeleteTextures(mp_iPostRenderSteps, mp_texVertBlur); // Cleanup FBOs glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glDeleteFramebuffers(mp_iPostRenderSteps, mp_fboDownsampled); glDeleteFramebuffers(mp_iPostRenderSteps, mp_fboHoriBlur); glDeleteFramebuffers(mp_iPostRenderSteps, mp_fboVertBlur); // Cleanup RBOs glDeleteRenderbuffers(1, mp_rboRendering); // Cleanup Progams glUseProgram(0); glDeleteProgram(*mp_shScreenTextMVP); glDeleteProgram(*mp_shBlurHori); glDeleteProgram(*mp_shBlurVerti); glDeleteProgram(*mp_shPostProcess); // Cleanup allocated memory delete [] mp_OrthoMatrix; delete [] mp_ScreenQuad; delete mp_texRendering; delete mp_texGlowParts; delete mp_texGlowing; delete [] mp_texDownsampled; delete [] mp_texHoriBlur; delete [] mp_texVertBlur; delete mp_fboRendering; delete mp_fboGlowParts; delete [] mp_fboDownsampled; delete [] mp_fboHoriBlur; delete [] mp_fboVertBlur; delete mp_fboGlowing; delete mp_fboBuffs; delete mp_fboWindowBuff; delete mp_rboRendering; delete mp_shScreenTextMVP; delete mp_shBlurHori; delete mp_shBlurVerti; delete mp_shPostProcess; mp_state= FINALIZED; return GL_NO_ERROR; } GLenum BloomPostProcess::cleanup() { return finalize(); } GLenum BloomPostProcess::destroy() { if ( mp_state != FINALIZED ) { if ( debug ) { std::cerr << "BloomPostProcess::destroy() Invalid operation.\n" << "\tObject is in wrong state - it must be FINALIZED.\n" << "\tYou can get current state by calling getState(). \n" << "\tCall finalize() first." << std::endl; } return GL_INVALID_OPERATION; } mp_state= DESTROYED; delete mp_BloomPostProcess; return GL_NO_ERROR; } GLenum BloomPostProcess::resize(int new_width, int new_height) { if ( mp_state != INITIALIZED ) { if ( debug ) { std::cerr << "BloomPostProcess::resize() Invalid operation.\n" << "\tObject is in wrong state - it must be INITIALIZED.\n" << "\tYou can get current state by calling getState(). \n" << "\tCall init() first." << std::endl; } return GL_INVALID_OPERATION; } if ( new_height < 16 ) new_height= 16; if ( new_width < 16 ) new_height= 16; //New sizes mp_iScreenWidth= new_width; mp_iScreenHeight= new_height; //DELETE PREVIOUS FBOS TEXTURES // Cleanup textures for ( int i= 0; i < mp_iPostRenderSteps; i++ ) { //TODO I HOPE ITS CORRECT :) glActiveTexture(GL_TEXTURE0 + i); glBindTexture(GL_TEXTURE_2D, 0); } glDeleteTextures(1, mp_texRendering); glDeleteTextures(1, mp_texGlowParts); glDeleteTextures(1, mp_texGlowing); glDeleteTextures(mp_iPostRenderSteps, mp_texDownsampled); glDeleteTextures(mp_iPostRenderSteps, mp_texHoriBlur); glDeleteTextures(mp_iPostRenderSteps, mp_texVertBlur); // Cleanup FBOs glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glBindFramebuffer(GL_READ_FRAMEBUFFER, 0); glDeleteFramebuffers(mp_iPostRenderSteps, mp_fboDownsampled); glDeleteFramebuffers(mp_iPostRenderSteps, mp_fboHoriBlur); glDeleteFramebuffers(mp_iPostRenderSteps, mp_fboVertBlur); // Cleanup RBOs glDeleteRenderbuffers(1, mp_rboRendering); //APPLY NEW SIZES GLenum error; if ( (error= createAndBindFBO(&mp_iScreenWidth,&mp_iScreenHeight,mp_fboRendering,mp_texRendering,mp_rboRendering)) != GL_NO_ERROR ) return error; if ( (error= createAndBindFBO(&mp_iScreenWidth,&mp_iScreenHeight,mp_fboGlowParts,mp_texGlowParts)) != GL_NO_ERROR ) return error; int l_screenWidth= mp_iScreenWidth >> 2; int l_screenHeight= mp_iScreenHeight >> 2; for ( int i= 0; i < mp_iPostRenderSteps; i++ ) { gltGenerateOrtho2DMat(l_screenWidth, l_screenHeight, mp_OrthoMatrix[i], mp_ScreenQuad[i]); if ( (error= createAndBindFBO(&l_screenWidth,&l_screenHeight,&mp_fboDownsampled[i],&mp_texDownsampled[i])) != GL_NO_ERROR ) return error; if ( (error= createAndBindFBO(&l_screenWidth,&l_screenHeight,&mp_fboHoriBlur[i],&mp_texHoriBlur[i])) != GL_NO_ERROR ) return error; if ( (error= createAndBindFBO(&l_screenWidth,&l_screenHeight,&mp_fboVertBlur[i],&mp_texVertBlur[i])) != GL_NO_ERROR ) return error; l_screenWidth= l_screenWidth >> 1; l_screenHeight= l_screenHeight >> 1; } return GL_NO_ERROR; } GLenum BloomPostProcess::BeginRendering() { if ( mp_state != INITIALIZED ) { if ( debug ) { std::cerr << "BloomPostProcess::BeginRendering() Invalid operation.\n" << "\tObject is in wrong state - it must be INITIALIZED.\n" << "\tYou can get current state by calling getState(). \n" << "\tCall init() first." << std::endl; } return GL_INVALID_OPERATION; } /* * After calling this function you shall render your scene as usual */ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *mp_fboRendering); glDrawBuffers(1, mp_fboBuffs); mp_state= RENDERED; return GL_NO_ERROR; } GLenum BloomPostProcess::BeginGlowParts() { if ( mp_state != RENDERED ) { if ( debug ) { std::cerr << "BloomPostProcess::BeginGlowParts() Invalid operation.\n" << "\tObject is in wrong state - it must be RENDERED.\n" << "\tYou can get current state by calling getState(). \n" << "\tCall BeginRender() and render your scene first." << std::endl; } return GL_INVALID_OPERATION; } /* * After calling this function you shall render ONLY glowing parts * in way that you find appropriate */ glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *mp_fboGlowParts); glDrawBuffers(1, mp_fboBuffs); mp_state= PREPROCESSED; return GL_NO_ERROR; } GLenum BloomPostProcess::PostProcess() { if ( mp_state != PREPROCESSED ) { if ( debug ) { std::cerr << "BloomPostProcess::PostProcess() Invalid operation.\n" << "\tObject is in wrong state - it must be PREPROCESSED.\n" << "\tYou can get current state by calling getState(). \n" << "\tCall BeginGlowParts() and render glow parts on your scene first." << std::endl; } return GL_INVALID_OPERATION; } //todo delete v4color GLfloat v4color[]= { 1.0f, 1.0f, 1.0f, 1.0f }; /* * DOWNSAMPLING */ for ( int i= 0; i < mp_iPostRenderSteps; i++ ) { glViewport(0,0, mp_iScreenWidth >> (i+2), mp_iScreenHeight >> (i+2)); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mp_fboDownsampled[i]); glDrawBuffers(1, mp_fboBuffs); { //rozmywanie w poziomie>> glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); { renderTextureOnWholeScreen(mp_texGlowParts,mp_shScreenTextMVP,v4color,i); } } } /* * BLURING HORIZONTALLY */ for ( int i= 0; i < mp_iPostRenderSteps; i++ ) { glViewport(0,0, mp_iScreenWidth >> (i+2), mp_iScreenHeight >> (i+2)); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); //bufor do rozmywania w poziomie glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mp_fboHoriBlur[i]); glDrawBuffers(1, mp_fboBuffs); { //rozmywanie w poziomie >> glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); { renderTextureOnWholeScreen(&mp_texDownsampled[i],mp_shBlurHori,v4color,i); } } } /* * BLUR VERTICALLY */ for ( int i= 0; i < mp_iPostRenderSteps; i++ ) { glViewport(0,0, mp_iScreenWidth >> (i+2), mp_iScreenHeight >> (i+2)); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); //bufor do rozmywania w poziomie glBindFramebuffer(GL_DRAW_FRAMEBUFFER, mp_fboVertBlur[i]); glDrawBuffers(1, mp_fboBuffs); { //rozmywanie w poziomie >> glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); { renderTextureOnWholeScreen(&mp_texHoriBlur[i],mp_shBlurVerti,v4color,i); } } } mp_state= POSTPROCESSED; return GL_NO_ERROR; } GLenum BloomPostProcess::Display() { if ( mp_state != POSTPROCESSED ) { if ( debug ) { std::cerr << "BloomPostProcess::Display() Invalid operation.\n" << "\tObject is in wrong state - it must be POSTPROCESSED.\n" << "\tYou can get current state by calling getState(). \n" << "\tCall BeginGlowParts() and render your scene first." << std::endl; } return GL_INVALID_OPERATION; } GLfloat v4color[]= { 1.0f, 1.0f, 1.0f, 1.0f }; glViewport(0,0,mp_iScreenWidth,mp_iScreenHeight); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); glDrawBuffers(1, mp_fboWindowBuff); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glUseProgram(*mp_shPostProcess); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, *mp_texRendering); glActiveTexture(GL_TEXTURE1); glBindTexture(GL_TEXTURE_2D, mp_texVertBlur[0]); glActiveTexture(GL_TEXTURE2); glBindTexture(GL_TEXTURE_2D, mp_texVertBlur[1]); glActiveTexture(GL_TEXTURE3); glBindTexture(GL_TEXTURE_2D, mp_texVertBlur[2]); //Ustawiam zmienna uniform shadera wierzcholkow - macierz projekcji GLint locMVP = glGetUniformLocation(*mp_shPostProcess, "mvpMatrix"); glUniformMatrix4fv(locMVP, 1, GL_FALSE, mp_OrthoMatrix[0]); GLint locColor = glGetUniformLocation(*mp_shPostProcess, "v4color"); glUniform4fv(locColor,1,v4color); GLint iTextureUniform = glGetUniformLocation(*mp_shPostProcess, "colorMap"); glUniform1i(iTextureUniform, 0); iTextureUniform = glGetUniformLocation(*mp_shPostProcess, "colorMap0"); glUniform1i(iTextureUniform, 1); //todo SHADER IS NOT COMPATIBLE WITH DIFFERENT POST RENDER STEPS // if ( mp_iPostRenderSteps > 1 ) // { iTextureUniform = glGetUniformLocation(*mp_shPostProcess, "colorMap1"); glUniform1i(iTextureUniform, 2); // if ( mp_iPostRenderSteps > 2 ) // { iTextureUniform = glGetUniformLocation(*mp_shPostProcess, "colorMap2"); glUniform1i(iTextureUniform, 3); // } // } mp_ScreenQuad[0].Draw(); mp_state= INITIALIZED; return GL_NO_ERROR; } GLenum BloomPostProcess::createAndBindFBO(int* ScreenWidth, int* ScreenHeight, GLuint* FBO, GLuint* Texture, GLuint* DepthBuffer) { if ( ScreenWidth == NULL || ScreenHeight == NULL || FBO == NULL || Texture == NULL ) { std::cerr << "BloomPostProcess::createAndBindFBO:\n" << "\t One of the needed argument is null pointer." << std::endl; return GL_INVALID_VALUE; } // Create and bind an FBO glGenFramebuffers(1,FBO); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, *FBO); // Create depth renderbuffer if ( DepthBuffer != 0 ) { glGenRenderbuffers(1, DepthBuffer); glBindRenderbuffer(GL_RENDERBUFFER, *DepthBuffer); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH_COMPONENT32, *ScreenWidth, *ScreenHeight); } // Create the reflection texture glGenTextures(1, Texture); glBindTexture(GL_TEXTURE_2D, *Texture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, *ScreenWidth, *ScreenHeight, 0, GL_RGBA, GL_FLOAT, NULL); glFramebufferTexture2D(GL_DRAW_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, *Texture, 0); if ( DepthBuffer != 0 ) glFramebufferRenderbuffer(GL_DRAW_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_RENDERBUFFER, *DepthBuffer); glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0); return gltCheckErrors(); } GLenum BloomPostProcess::renderTextureOnWholeScreen(GLuint* textureID, GLint* shader, float v4color[4], int i) { glUseProgram(*shader); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, *textureID); //Ustawiam zmienna uniform shadera fragmentow - texture GLint iTextureUniform = glGetUniformLocation(*shader, "colorMap"); glUniform1i(iTextureUniform, 0); //Ustawiam zmienna uniform shadera wierzcholkow - macierz projekcji GLint locMVP = glGetUniformLocation(*shader, "mvpMatrix"); glUniformMatrix4fv(locMVP, 1, GL_FALSE, mp_OrthoMatrix[i]); GLint locColor = glGetUniformLocation(*shader, "v4color"); glUniform4fv(locColor,1,v4color); mp_ScreenQuad[i].Draw(); return GL_NO_ERROR; }