niedziela, 12 czerwca 2011

OpenGL Blooom :)

W koncu udalo mi sie zrobic efekt bloom, korzystajac z GLSL. xD Screen gdzies na dole, moze jak uprzatne kod (straszny, okropny balagan) to wrzuce. Zamieszczam tez kod, ale dwie adnotacje: kod wrzucony jak leci, kod nie jest w 100% dokonczony, ale dziala na tyle na ile mi potrzeba. :) W przyszlosci poprawie (i post, i kod).

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;
}