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:
parent
3485199bec
commit
836de14093
3 changed files with 96 additions and 73 deletions
|
@ -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)
|
||||||
|
|
|
@ -91,6 +91,7 @@ public:
|
||||||
void renderGridPoints();
|
void renderGridPoints();
|
||||||
|
|
||||||
void loadShaders();
|
void loadShaders();
|
||||||
|
void deleteShaders();
|
||||||
|
|
||||||
void unloadDevice();
|
void unloadDevice();
|
||||||
void reloadDevice();
|
void reloadDevice();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
Loading…
Reference in a new issue