1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2024-12-26 14:45:48 +00:00

Implement multi-pass postprocessing shader.

This allows attaching multiple shader programs, processing the entire
screen as texture. Chaining shaders works, each shader will use
the output of the previous shader as input.
This commit is contained in:
fgenesis 2013-06-15 02:38:49 +02:00
parent 3485199bec
commit 836de14093
3 changed files with 96 additions and 73 deletions

View file

@ -63,6 +63,28 @@ AfterEffectManager::AfterEffectManager(int xDivs, int yDivs)
void AfterEffectManager::loadShaders() void AfterEffectManager::loadShaders()
{ {
deleteShaders();
Shader *sh = new Shader();
sh->load("data/shaders/test.vert", "data/shaders/test.frag");
if(sh->isLoaded())
scriptShader[0] = sh;
else
delete sh;
sh = new Shader();
sh->load("data/shaders/test2.vert", "data/shaders/test2.frag");
if(sh->isLoaded())
scriptShader[1] = sh;
else
delete sh;
sh = new Shader();
sh->load("data/shaders/test3.vert", "data/shaders/test3.frag");
if(sh->isLoaded())
scriptShader[2] = sh;
else
delete sh;
} }
AfterEffectManager::~AfterEffectManager() AfterEffectManager::~AfterEffectManager()
@ -77,6 +99,7 @@ AfterEffectManager::~AfterEffectManager()
delete[] drawGrid; delete[] drawGrid;
} }
deleteEffects(); deleteEffects();
deleteShaders();
} }
void AfterEffectManager::deleteEffects() void AfterEffectManager::deleteEffects()
@ -94,6 +117,18 @@ void AfterEffectManager::deleteEffects()
openSpots.pop(); openSpots.pop();
} }
void AfterEffectManager::deleteShaders()
{
for(size_t i = 0; i < scriptShader.size(); ++i)
{
if(scriptShader[i])
{
delete scriptShader[i];
scriptShader[i] = 0;
}
}
}
void AfterEffectManager::clear() void AfterEffectManager::clear()
{ {
deleteEffects(); deleteEffects();
@ -149,24 +184,18 @@ void AfterEffectManager::destroyEffect(int id)
void AfterEffectManager::render() void AfterEffectManager::render()
{ {
assert(core->frameBuffer.isInited());
#ifdef BBGE_BUILD_OPENGL #ifdef BBGE_BUILD_OPENGL
glPushMatrix(); glPushMatrix();
//glDisable(GL_BLEND);
//glEnable(GL_BLEND);
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//glBlendFunc(GL_SRC_ALPHA, GL_ONE);
glDisable (GL_ALPHA_TEST); glDisable (GL_ALPHA_TEST);
glDisable(GL_BLEND); glDisable(GL_BLEND);
core->frameBuffer.endCapture(); core->frameBuffer.endCapture();
glTranslatef(core->cameraPos.x, core->cameraPos.y, 0); glTranslatef(core->cameraPos.x, core->cameraPos.y, 0);
glScalef(core->invGlobalScale, core->invGlobalScale,0); glScalef(core->invGlobalScale, core->invGlobalScale,0);
/*
static float angle;
angle += 0.03f;
*/
//glRotatef(angle, 0, 0, 1);
//glColor4f(1,1,1,0.75);
glColor4f(1,1,1,1); glColor4f(1,1,1,1);
renderGrid(); renderGrid();
//renderGridPoints(); //renderGridPoints();
@ -178,78 +207,45 @@ void AfterEffectManager::renderGrid()
{ {
#ifdef BBGE_BUILD_OPENGL #ifdef BBGE_BUILD_OPENGL
int shadersOn = 0;
int firstShader = -1; int firstShader = -1;
int lastShader = -1; int lastShader = -1;
Shader *activeShader = 0;
for (size_t i = 0; i < scriptShader.size(); ++i) for (size_t i = 0; i < scriptShader.size(); ++i)
{ {
if(scriptShader[i]) if(scriptShader[i])
{ {
++shadersOn;
if(firstShader < 0) if(firstShader < 0)
{
firstShader = i; firstShader = i;
activeShader = scriptShader[i];
}
lastShader = i; lastShader = i;
} }
} }
if (core->frameBuffer.isInited())
core->frameBuffer.bindTexture();
Shader *activeShader=0;
if (core->frameBuffer.isInited())
{
if(scriptShader.size() && scriptShader[0])
activeShader = scriptShader[0];
}
if (activeShader)
{
//while(glGetError() != GL_NO_ERROR) {}
activeShader->bind();
activeShader->setInt("tex", 0);
}
screenWidth = core->getWindowWidth(); screenWidth = core->getWindowWidth();
screenHeight = core->getWindowHeight(); screenHeight = core->getWindowHeight();
/*
float percentX, percentY;
percentX = 1;
percentY = 0.5;
*/
/*
percentX = (float)textureWidth/(float)screenWidth;
percentY = (float)textureHeight/(float)screenHeight;
*/
float percentX, percentY; float percentX, percentY;
percentX = (float)screenWidth/(float)textureWidth; percentX = (float)screenWidth/(float)textureWidth;
percentY = (float)screenHeight/(float)textureHeight; percentY = (float)screenHeight/(float)textureHeight;
/*
if (screenWidth <= textureWidth)
{
percentX = (float)screenWidth/(float)textureWidth;
percentY = (float)screenHeight/(float)textureHeight;
}
else
{
percentY = 10;
}
*/
int vw = core->getVirtualWidth(); int vw = core->getVirtualWidth();
int vh = core->getVirtualHeight(); int vh = core->getVirtualHeight();
int offx = -core->getVirtualOffX(); int offx = -core->getVirtualOffX();
int offy = -core->getVirtualOffY(); int offy = -core->getVirtualOffY();
core->frameBuffer.bindTexture();
if(activeShader)
{
activeShader->bind();
activeShader->setInt("tex", 0);
if(firstShader != lastShader)
backupBuffer.startCapture();
}
//float div = xDivs; //float div = xDivs;
for (int i = 0; i < (xDivs-1); i++) for (int i = 0; i < (xDivs-1); i++)
{ {
@ -283,32 +279,48 @@ void AfterEffectManager::renderGrid()
float width2 = float(vw)/2; float width2 = float(vw)/2;
float height2 = float(vh)/2; float height2 = float(vh)/2;
/*
for(size_t i = 1; i < scriptShader.size(); ++i)
{
if(scriptShader[i])
{
if (core->frameBuffer.isInited())
core->frameBuffer.startCapture();
scriptShader[i]->bind(); if(firstShader != lastShader)
scriptShader[i]->setInt("tex", 0); {
// From here on: secondary shader passes.
// We just outputted to the backup buffer...
FrameBuffer *fbIn = &core->frameBuffer;
FrameBuffer *fbOut = &backupBuffer;
for(int i = firstShader + 1; i <= lastShader; ++i)
{
activeShader = scriptShader[i];
if(!activeShader)
continue;
// Swap and exchange framebuffers. The old output buffer serves as texture input for the other one
fbOut->endCapture();
std::swap(fbIn, fbOut);
fbIn->bindTexture();
// If this is the last pass, do not render to a frame buffer again
if(i != lastShader)
fbOut->startCapture();
activeShader->bind();
activeShader->setInt("tex", 0);
// note that offx, offy are negative here!
glBegin(GL_QUADS); glBegin(GL_QUADS);
glTexCoord2d(0.0f, 0.0f); glTexCoord2d(0.0f, 0.0f);
glVertex3f(-width2, height2, 0.0f); glVertex3f(offx, vh+offy, 0.0f);
glTexCoord2d(percentX, 0.0f); glTexCoord2d(percentX, 0.0f);
glVertex3f( width2, height2, 0.0f); glVertex3f( vw+offx, vh+offy, 0.0f);
glTexCoord2d(percentX, percentY); glTexCoord2d(percentX, percentY);
glVertex3f( width2, -height2, 0.0f); glVertex3f( vw+offx, offy, 0.0f);
glTexCoord2d(0.0f, percentY); glTexCoord2d(0.0f, percentY);
glVertex3f(-width2, -height2, 0.0f); glVertex3f(offx, offy, 0.0f);
glEnd(); glEnd();
scriptShader[i]->unbind();
capture(); activeShader->unbind();
} }
} }
*/
// uncomment to render grid points // uncomment to render grid points
@ -377,6 +389,7 @@ void AfterEffectManager::renderGridPoints()
void AfterEffectManager::unloadDevice() void AfterEffectManager::unloadDevice()
{ {
backupBuffer.unloadDevice(); backupBuffer.unloadDevice();
deleteShaders();
} }
void AfterEffectManager::reloadDevice() void AfterEffectManager::reloadDevice()
@ -401,6 +414,8 @@ void AfterEffectManager::reloadDevice()
backupBuffer.reloadDevice(); backupBuffer.reloadDevice();
else else
backupBuffer.init(-1, -1, true); backupBuffer.init(-1, -1, true);
loadShaders();
} }
void AfterEffectManager::addEffect(Effect *e) void AfterEffectManager::addEffect(Effect *e)

View file

@ -91,6 +91,7 @@ public:
void renderGridPoints(); void renderGridPoints();
void loadShaders(); void loadShaders();
void deleteShaders();
void unloadDevice(); void unloadDevice();
void reloadDevice(); void reloadDevice();

View file

@ -192,6 +192,13 @@ unsigned int Shader::_compileShader(int type, const char *src, char *errbuf, siz
#ifdef BBGE_BUILD_SHADERS #ifdef BBGE_BUILD_SHADERS
GLint compiled = 0; GLint compiled = 0;
GLhandleARB handle = glCreateShaderObjectARB(type); GLhandleARB handle = glCreateShaderObjectARB(type);
if(!handle)
{
std::ostringstream os;
os << "Failed to create shader object of type " << type;
debugLog(os.str());
return 0;
}
glShaderSourceARB( handle, 1, &src, NULL ); glShaderSourceARB( handle, 1, &src, NULL );
glCompileShaderARB( handle); glCompileShaderARB( handle);