1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2024-11-29 12:03:51 +00:00
Aquaria/BBGE/AfterEffect.cpp

573 lines
13 KiB
C++
Raw Normal View History

/*
Copyright (C) 2007, 2010 - Bit-Blot
This file is part of Aquaria.
Aquaria is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
See the GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
#include "AfterEffect.h"
#include "RenderBase.h"
#include "Shader.h"
2016-05-05 17:40:28 +00:00
#include <assert.h>
Effect::Effect()
{
done = false;
rate = 1;
}
AfterEffectManager::AfterEffectManager(int xDivs, int yDivs)
{
active = false;
numEffects = 0;
bRenderGridPoints = true;
shaderPipeline.resize(10, 0);
drawGrid = 0;
this->xDivs = xDivs;
this->yDivs = yDivs;
if (xDivs != 0 && yDivs != 0)
{
drawGrid = new Vector * [xDivs];
for (int i = 0; i < xDivs; i++)
{
drawGrid[i] = new Vector [yDivs];
}
}
updateDevice();
loadShaders();
}
void AfterEffectManager::loadShaders()
{
deleteShaders();
// ...Load shaders here...
}
AfterEffectManager::~AfterEffectManager()
{
if (drawGrid)
{
int i;
for (i = 0; i < xDivs; i++)
{
delete[] drawGrid[i];
2016-05-05 17:40:28 +00:00
}
delete[] drawGrid;
}
deleteEffects();
deleteShaders();
}
void AfterEffectManager::deleteEffects()
{
for (size_t i = 0; i < effects.size(); i++)
{
if (effects[i])
{
delete effects[i];
}
}
effects.clear();
numEffects=0;
openSpots.clear();
}
void AfterEffectManager::deleteShaders()
{
for(size_t i = 0; i < shaderPipeline.size(); ++i)
shaderPipeline[i] = 0;
for(size_t i = 0; i < loadedShaders.size(); ++i)
{
if(loadedShaders[i])
{
delete loadedShaders[i];
loadedShaders[i] = 0;
}
}
}
2013-10-24 23:44:34 +00:00
void AfterEffectManager::unloadShaders()
{
for(size_t i = 0; i < loadedShaders.size(); ++i)
if(loadedShaders[i])
loadedShaders[i]->unload();
}
void AfterEffectManager::clear()
{
deleteEffects();
resetGrid();
}
void AfterEffectManager::update(float dt)
{
2016-05-05 17:40:28 +00:00
if (core->particlesPaused) return;
resetGrid();
if (core->frameBuffer.isInited())
active = true;
else
active = false;
for (size_t i = 0; i < effects.size(); i++)
2016-05-05 17:40:28 +00:00
{
Effect *e = effects[i];
if (e)
{
active = true;
e->update(dt, drawGrid, xDivs, yDivs);
if (e->done)
{
numEffects--;
destroyEffect(i);
}
}
}
}
void AfterEffectManager::resetGrid()
{
for (int i = 0; i < xDivs; i++)
{
for (int j = 0; j < yDivs; j++)
{
drawGrid[i][j].x = i/(float)(xDivs-1);
drawGrid[i][j].y = j/(float)(yDivs-1);
}
}
}
void AfterEffectManager::destroyEffect(int id)
{
delete effects[id];
effects[id] = 0;
openSpots.push_back(id);
}
void AfterEffectManager::render() const
{
assert(core->frameBuffer.isInited());
glPushMatrix();
glDisable (GL_ALPHA_TEST);
glDisable(GL_BLEND);
2013-06-14 22:58:32 +00:00
core->frameBuffer.endCapture();
glTranslatef(core->cameraPos.x, core->cameraPos.y, 0);
glScalef(core->invGlobalScale, core->invGlobalScale,0);
glColor4f(1,1,1,1);
renderGrid();
2016-05-05 17:40:28 +00:00
glPopMatrix();
}
void AfterEffectManager::renderGrid() const
{
2013-06-14 22:58:32 +00:00
int firstShader = -1;
int lastShader = -1;
Shader *activeShader = 0;
for (size_t i = 0; i < shaderPipeline.size(); ++i)
2013-06-14 22:58:32 +00:00
{
2013-10-24 23:44:34 +00:00
if(shaderPipeline[i] && shaderPipeline[i]->isLoaded())
2013-06-14 22:58:32 +00:00
{
if(firstShader < 0)
{
2013-06-14 22:58:32 +00:00
firstShader = i;
activeShader = shaderPipeline[i];
}
2013-06-14 22:58:32 +00:00
lastShader = i;
}
}
float percentX, percentY;
percentX = (float)screenWidth/(float)textureWidth;
percentY = (float)screenHeight/(float)textureHeight;
int vw = core->getVirtualWidth();
int vh = core->getVirtualHeight();
int offx = -core->getVirtualOffX();
int offy = -core->getVirtualOffY();
core->frameBuffer.bindTexture();
if(activeShader)
{
activeShader->bind();
activeShader->setInt("tex", 0);
if(firstShader != lastShader)
backupBuffer.startCapture();
}
2016-05-05 17:40:28 +00:00
for (int i = 0; i < (xDivs-1); i++)
{
for (int j = 0; j < (yDivs-1); j++)
2016-05-05 17:40:28 +00:00
{
glBegin(GL_QUADS);
glTexCoord2f(i/(float)(xDivs-1)*percentX, 1*percentY-(j)/(float)(yDivs-1)*percentY);
2016-05-05 17:40:28 +00:00
glVertex2f(offx + vw*drawGrid[i][j].x, offy + vh*drawGrid[i][j].y);
glTexCoord2f(i/(float)(xDivs-1)*percentX, 1*percentY-(j+1)/(float)(yDivs-1)*percentY);
2016-05-05 17:40:28 +00:00
glVertex2f(offx + vw*drawGrid[i][j+1].x, offy + vh*drawGrid[i][j+1].y);
2016-05-05 17:40:28 +00:00
glTexCoord2f((i+1)/(float)(xDivs-1)*percentX, 1*percentY-(j+1)/(float)(yDivs-1)*percentY);
glVertex2f(offx + vw*drawGrid[i+1][j+1].x, offy + vh*drawGrid[i+1][j+1].y);
2016-05-05 17:40:28 +00:00
glTexCoord2f((i+1)/(float)(xDivs-1)*percentX, 1*percentY-(j)/(float)(yDivs-1)*percentY);
glVertex2f(offx + vw*drawGrid[i+1][j].x, offy + vh*drawGrid[i+1][j].y);
glEnd();
}
}
2013-06-14 22:58:32 +00:00
if (activeShader)
activeShader->unbind();
if(firstShader != lastShader)
2013-06-14 22:58:32 +00:00
{
// From here on: secondary shader passes.
// We just outputted to the backup buffer...
const FrameBuffer *fbIn = &core->frameBuffer;
const FrameBuffer *fbOut = &backupBuffer;
for(int i = firstShader + 1; i <= lastShader; ++i)
2013-06-14 22:58:32 +00:00
{
activeShader = shaderPipeline[i];
2013-10-24 23:44:34 +00:00
if(!(activeShader && activeShader->isLoaded()))
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);
2016-05-05 17:40:28 +00:00
// note that offx, offy are negative here!
2013-06-14 22:58:32 +00:00
glBegin(GL_QUADS);
glTexCoord2f(0.0f, 0.0f);
glVertex3f(offx, vh+offy, 0.0f);
glTexCoord2f(percentX, 0.0f);
glVertex3f( vw+offx, vh+offy, 0.0f);
glTexCoord2f(percentX, percentY);
glVertex3f( vw+offx, offy, 0.0f);
glTexCoord2f(0.0f, percentY);
glVertex3f(offx, offy, 0.0f);
2013-06-14 22:58:32 +00:00
glEnd();
2016-05-05 17:40:28 +00:00
activeShader->unbind();
2013-06-14 22:58:32 +00:00
}
}
// uncomment to render grid points
/*
glBindTexture(GL_TEXTURE_2D, 0);
glPointSize(2);
glColor4f(1, 0, 0, 0.5);
for (int i = 0; i < (xDivs-1); i++)
{
for (int j = 0; j < (yDivs-1); j++)
2016-05-05 17:40:28 +00:00
{
glBegin(GL_POINTS);
//glColor3f(i/div, i/div, i/div);
glTexCoord2f(i/(float)(xDivs-1)*percentX, 1*percentY-(j)/(float)(yDivs-1)*percentY);
//glMultiTexCoord2fARB(GL_TEXTURE0_ARB,i/(float)(xDivs-1)*percentX, 1*percentY-(j)/(float)(yDivs-1)*percentY);
//glMultiTexCoord2fARB(GL_TEXTURE1_ARB,0,0);
glVertex2f(800*drawGrid[i][j].x, 600*drawGrid[i][j].y);
glTexCoord2f(i/(float)(xDivs-1)*percentX, 1*percentY-(j+1)/(float)(yDivs-1)*percentY);
//glMultiTexCoord2fARB(GL_TEXTURE0_ARB,i/(float)(xDivs-1)*percentX, 1*percentY-(j+1)/(float)(yDivs-1)*percentY);
//glMultiTexCoord2fARB(GL_TEXTURE1_ARB,0,(float)(screenHeight/(yDivs-1))/16);
glVertex2f(800*drawGrid[i][j+1].x, 600*drawGrid[i][j+1].y);
2016-05-05 17:40:28 +00:00
glTexCoord2f((i+1)/(float)(xDivs-1)*percentX, 1*percentY-(j+1)/(float)(yDivs-1)*percentY);
//glMultiTexCoord2fARB(GL_TEXTURE0_ARB,(i+1)/(float)(xDivs-1)*percentX, 1*percentY-(j+1)/(float)(yDivs-1)*percentY);
//glMultiTexCoord2fARB(GL_TEXTURE1_ARB,(float)(screenWidth/(xDivs-1))/16,(float)(screenHeight/(yDivs-1))/16);
glVertex2f(800*drawGrid[i+1][j+1].x, 600*drawGrid[i+1][j+1].y);
2016-05-05 17:40:28 +00:00
glTexCoord2f((i+1)/(float)(xDivs-1)*percentX, 1*percentY-(j)/(float)(yDivs-1)*percentY);
//glMultiTexCoord2fARB(GL_TEXTURE0_ARB,(i+1)/(float)(xDivs-1)*percentX, 1*percentY-(j)/(float)(yDivs-1)*percentY);
//glMultiTexCoord2fARB(GL_TEXTURE1_ARB,(float)(screenWidth/(xDivs-1))/16,0);
glVertex2f(800*drawGrid[i+1][j].x, 600*drawGrid[i+1][j].y);
glEnd();
}
2016-05-05 17:40:28 +00:00
}
*/
//glDisable(GL_TEXTURE_2D);
RenderObject::lastTextureApplied = 0;
glBindTexture(GL_TEXTURE_2D, 0);
//bwShader.unbind();
//glActiveTextureARB(GL_TEXTURE0_ARB);
2016-05-05 17:40:28 +00:00
//glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
//if (bRenderGridPoints)
// renderGridPoints();
}
void AfterEffectManager::renderGridPoints() const
{
glColor4f(0.0f,0.0f,0.0f,1.0f);
for (int i = 0; i < (xDivs); i++)
{
for (int j = 0; j < (yDivs); j++)
{
glBegin(GL_QUADS);
glVertex2f(screenWidth*drawGrid[i][j].x-3, screenHeight*drawGrid[i][j].y-3);
glVertex2f(screenWidth*drawGrid[i][j].x-3, screenHeight*drawGrid[i][j].y+3);
glVertex2f(screenWidth*drawGrid[i][j].x+3, screenHeight*drawGrid[i][j].y+3);
glVertex2f(screenWidth*drawGrid[i][j].x+3, screenHeight*drawGrid[i][j].y-3);
glEnd();
}
}
}
void AfterEffectManager::unloadDevice()
{
2013-06-14 22:58:32 +00:00
backupBuffer.unloadDevice();
2013-10-24 23:44:34 +00:00
unloadShaders();
}
void AfterEffectManager::_updateScreenSize()
{
screenWidth = core->getWindowWidth();
screenHeight = core->getWindowHeight();
if (core->frameBuffer.isInited())
{
textureWidth = core->frameBuffer.getWidth();
textureHeight = core->frameBuffer.getHeight();
}
else
{
2013-06-14 22:58:32 +00:00
textureWidth = screenWidth;
sizePowerOf2Texture(textureWidth);
textureHeight = screenHeight;
sizePowerOf2Texture(textureHeight);
}
}
void AfterEffectManager::updateDevice()
{
_updateScreenSize();
backupBuffer.init(-1, -1, true);
}
void AfterEffectManager::reloadDevice()
{
_updateScreenSize();
backupBuffer.reloadDevice();
2013-10-24 23:44:34 +00:00
for (size_t i = 0; i < loadedShaders.size(); ++i)
{
if (Shader *sh = loadedShaders[i])
{
sh->reload();
if (!sh->isLoaded())
{
debugLog("AfterEffect::reloadDevice(): Failed to reload shader");
loadedShaders[i] = 0;
for(size_t j = 0; j < shaderPipeline.size(); ++j)
if(sh == shaderPipeline[j])
shaderPipeline[j] = 0;
delete sh;
2013-10-24 23:44:34 +00:00
}
}
}
}
void AfterEffectManager::addEffect(Effect *e)
{
if (!openSpots.empty())
{
int i = openSpots.back();
openSpots.pop_back();
effects[i] = e;
}
else
{
effects.push_back(e);
}
numEffects++;
2016-05-05 17:40:28 +00:00
Vector base(0,0,0);
2016-05-05 17:40:28 +00:00
e->position.x /= screenWidth;
e->position.y /= screenHeight;
}
void ShockEffect::update(float dt, Vector ** drawGrid, int xDivs, int yDivs)
{
dt *= timeMultiplier;
Effect::update(dt, drawGrid, xDivs, yDivs);
centerPoint = position;
centerPoint -= ((core->screenCenter-originalCenter)*core->globalScale.x)/core->width;
amplitude-=dt*rate;
currentDistance+=dt*frequency;
float distFromCamp = 4;
float adjWaveLength = waveLength/distFromCamp;
float adjAmplitude = amplitude/distFromCamp;
if (amplitude < 0)
done=true;
for (int i = 1; i < (xDivs-1); i++)
{
for (int j = 1; j < (yDivs-1); j++)
{
float xDist = (centerPoint.x - drawGrid[i][j].x)/.75;
float yDist = centerPoint.y - drawGrid[i][j].y;
2016-05-05 17:40:28 +00:00
float tDist = sqrtf(xDist*xDist+yDist*yDist);
if (tDist < currentDistance*adjWaveLength)
{
drawGrid[i][j].x += adjAmplitude*sinf(-tDist/adjWaveLength+currentDistance)*.75f;
drawGrid[i][j].y += adjAmplitude*cosf(-tDist/adjWaveLength+currentDistance);
}
}
}
}
RippleEffect::RippleEffect() : Effect()
{
time = 0;
}
void RippleEffect::update(float dt, Vector ** drawGrid, int xDivs, int yDivs)
{
2016-05-05 17:40:28 +00:00
time += dt*0.5f;
float amp = 0.002f;
for (int i = 0; i < (xDivs-1); i++)
{
for (int j = 0; j < (yDivs-1); j++)
{
float offset = i/float(xDivs) + (core->screenCenter.x/float(core->width)/2) +j/float(xDivs) + (core->screenCenter.y/float(core->height)/2);
2016-05-05 17:40:28 +00:00
drawGrid[i][j].x += sinf((time+offset)*7.5f)*(amp*0.5f);
drawGrid[i][j].y += cosf((time+offset)*7.5f)*amp;
}
}
}
int AfterEffectManager::loadShaderFile(const char *vert, const char *frag)
{
Shader *sh = new Shader();
sh->load(vert, frag);
if(!sh->isLoaded())
{
delete sh;
return 0;
}
return _insertShader(sh);
}
int AfterEffectManager::loadShaderSrc(const char *vert, const char *frag)
{
Shader *sh = new Shader();
sh->loadSrc(vert, frag);
if(!sh->isLoaded())
{
delete sh;
return 0;
}
return _insertShader(sh);
}
Shader *AfterEffectManager::getShaderPtr(int handle)
{
size_t idx = handle - 1;
return idx < loadedShaders.size() ? loadedShaders[idx] : 0;
}
void AfterEffectManager::setShaderPipelineSize(size_t size)
{
shaderPipeline.resize(size, 0);
}
bool AfterEffectManager::setShaderPipelinePos(int handle, size_t pos)
{
if(pos < shaderPipeline.size())
{
shaderPipeline[pos] = getShaderPtr(handle);
return true;
}
return false;
}
// returns handle (= index + 1)
int AfterEffectManager::_insertShader(Shader *sh)
{
for(size_t i = 0; i < loadedShaders.size(); ++i)
{
if(!loadedShaders[i])
{
loadedShaders[i] = sh;
return i+1;
}
}
loadedShaders.push_back(sh);
return loadedShaders.size();
}
2013-10-24 23:44:34 +00:00
void AfterEffectManager::deleteShader(int handle)
{
Shader *sh = getShaderPtr(handle);
if(!sh)
return;
for(size_t i = 0; i < shaderPipeline.size(); ++i)
if(shaderPipeline[i] == sh)
shaderPipeline[i] = 0;
size_t idx = handle - 1;
loadedShaders[idx] = 0;
delete sh;
}