1
0
Fork 0
mirror of https://github.com/AquariaOSE/Aquaria.git synced 2025-02-16 17:45:52 +00:00

Changes to rendering logic, incl water surface flicker fix, plus other fixes.

This commit changes a bunch of internal rendering logic to
use FBOs in a way that doesn't violate the GL spec.
The water surface FBO's output texture was bound for reading
while at the same time rendering the water surface back into the
same FBO! Depending on the card/driver/load/zoom factor/moon phase,
this could lead to water surface flickering, chessboard effects,
and other visual glitches.
In order to fix this an extra FBO is needed.
In theory this is a simple fix but in practice this is the Aquaria
codebase and everything is more complicated than it has any right to be.

Couple other things:

- FBOs no longer have a depth renderbuffer. Aquaria never uses the depth
buffer for anything, so this can go to save some memory.
Also remove renderbuffer GL function pointers.

- Make FBOs multi-"paged". This is supposedly more efficient on desktop GL,
if glDrawBuffer() supports GL_COLOR_ATTACHMENTn. This is currently checked
via the presence of glDrawBuffersARB().

- Main core FBO now has 2 pages becaus it's needed for the water surface.
The same 2 pages are later used by the after effect manager to ping-pong
postprocessing shaders. Remove private after effect FBO.

TODO:
- There's still a bug in the one-fbo-multiple-binding-points code path.
-> for now glDrawBuffersARB must be NULL to work properly.
This commit is contained in:
fgenesis 2024-04-25 03:33:02 +02:00
parent dd7ab0448f
commit 09edbf49fd
19 changed files with 608 additions and 390 deletions

View file

@ -201,7 +201,6 @@ DSQ::DSQ(const std::string& fileSystem, const std::string& extraDataDir)
console = 0;
cmDebug = 0;
saveSlotMode = SSM_NONE;
afterEffectManagerLayer = LR_AFTER_EFFECTS; // LR_AFTER_EFFECTS
renderObjectLayers.resize(LR_MAX);
entities.resize(64, 0);
@ -585,7 +584,7 @@ static void loadBit(int index, float perc = 1)
loading->setWidthHeight(loadingProgress*600, 23);
dsq->render();
dsq->renderExternal();
dsq->showBuffer();
}
@ -688,6 +687,45 @@ static bool sdlVideoModeOK(int disp, const int w, const int h, const int bpp)
#endif
}
static bool preRenderDarkLayer(const RenderState& rs)
{
if(core->darkLayer.isUsed())
core->darkLayer.beginCapture();
return true;
}
static void postRenderDarkLayer(const RenderState& rs)
{
if(core->darkLayer.isUsed())
{
core->darkLayer.endCapture();
}
}
static bool beginAfterEffectCapture(const RenderState& rs)
{
if (core->afterEffectManager)
core->afterEffectManager->beginCapture();
return true;
}
static bool preRenderAfterEffectLayer(const RenderState& rs)
{
if(core->darkLayer.isUsed())
core->darkLayer.render(rs);
if(core->afterEffectManager)
{
unsigned page = core->frameBuffer.popCapture();
core->afterEffectManager->render(rs, page);
}
return true;
}
void DSQ::init()
{
#define PSIZEOF(x) { std::ostringstream os_; os_ << ("sizeof(" #x ") = ") << sizeof(x); debugLog(os_.str()); }
@ -911,12 +949,6 @@ void DSQ::init()
precacher.clear();
render();
showBuffer();
loadBit(LOAD_INITIAL);
debugLog("Loading Particle Bank...");
@ -968,7 +1000,6 @@ void DSQ::init()
user.video.darkbuffersize = MAX(user.video.darkbuffersize,128);
darkLayer.setLayers(LR_ELEMENTS13, LR_AFTER_EFFECTS);
debugLog("dark layer init");
darkLayer.init(user.video.darkbuffersize, user.video.darkfbuffer);
debugLog("dark layer togle...");
@ -1270,6 +1301,14 @@ void DSQ::init()
renderObjectLayerOrder[LR_ENTITIES_MINUS3] = -1;
renderObjectLayerOrder[LR_ENTITIES_MINUS2] = -1;
renderObjectLayers[LR_ZERO].preRender = beginAfterEffectCapture;
renderObjectLayers[LR_AFTER_EFFECTS].preRender = preRenderAfterEffectLayer;
renderObjectLayers[LR_ELEMENTS13].preRender = preRenderDarkLayer;
renderObjectLayers[LR_ELEMENTS13].postRender = postRenderDarkLayer;
darkLayer.beginLayer = LR_ELEMENTS13;
darkLayer.lastLayer = LR_ELEMENTS13;
setMousePosition(center);
@ -2717,8 +2756,8 @@ void DSQ::doSaveSlotMenu(SaveSlotMode ssm, const Vector &position)
glPushAttrib(GL_VIEWPORT_BIT);
glViewport(0, 0, renderWidth, renderHeight);
clearBuffers();
render();
glClear(GL_COLOR_BUFFER_BIT);
renderExternal();
scrShotData = grabScreenshot(x, y, scrShotWidth, scrShotHeight);
glPopAttrib();
showBuffer();
@ -3315,6 +3354,11 @@ void DSQ::prepScreen(bool screenshot)
}
}
void DSQ::onPrepareRender()
{
game->onPrepareRender();
}
void DSQ::onRender()
{
if (cursor)
@ -3661,7 +3705,7 @@ void DSQ::onUpdate(float dt)
pollEvents(sec);
ActionMapper::onUpdate(sec);
SDL_Delay(int(sec*1000));
render();
renderExternal();
showBuffer();
resetTimer();
@ -4162,17 +4206,18 @@ void AquariaScreenTransition::capture()
InterpolatedVector oldAlpha = dsq->cursor->alpha;
dsq->cursor->alpha.x = 0;
int width=0, height=0;
dsq->render();
dsq->renderExternal();
width = dsq->getWindowWidth();
height = dsq->getWindowHeight();
glBindTexture(GL_TEXTURE_2D,screen_texture);
glReadBuffer(GL_BACK);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, width, height);
dsq->cursor->alpha = oldAlpha;
dsq->render();
dsq->renderExternal();
dsq->showBuffer();
this->alpha = 1;

View file

@ -444,8 +444,9 @@ protected:
float shakeCameraTimer;
float shakeCameraMag;
void onUpdate(float dt);
void onRender();
void onUpdate(float dt) OVERRIDE;
void onRender() OVERRIDE;
void onPrepareRender() OVERRIDE;
void modifyDt(float &dt);

View file

@ -232,6 +232,7 @@ Game::Game() : StateObject()
noSceneTransitionFadeout = false;
fullTilesetReload = false;
highestLoadedEntityID = 0;
waterSurfaceRender = NULL;
}
Game::~Game()
@ -2032,7 +2033,7 @@ bool Game::saveScene(std::string scene)
saveFile.InsertEndChild(pathXml);
}
for(size_t lr = 0; lr < MAX_TILE_LAYERS; ++lr)
for(unsigned lr = 0; lr < MAX_TILE_LAYERS; ++lr)
{
const TileStorage& ts = dsq->tilemgr.tilestore[lr];
std::ostringstream simpleElements;
@ -2084,7 +2085,7 @@ bool Game::saveScene(std::string scene)
{
XMLElement *simpleElementsXML = saveFile.NewElement("SE");
simpleElementsXML->SetAttribute("k", s.c_str());
simpleElementsXML->SetAttribute("l", (unsigned)lr);
simpleElementsXML->SetAttribute("l", lr);
std::string str = simpleElements_repeatScale.str();
if(!str.empty())
simpleElementsXML->SetAttribute("repeatScale", str.c_str());
@ -2436,6 +2437,7 @@ void Game::applyState()
inHelpScreen = false;
helpBG = 0;
helpBG2 = 0;
waterSurfaceRender = NULL;
dsq->returnToScene = "";
@ -4788,6 +4790,7 @@ void Game::removeState()
gridRenderUser1 = 0;
gridRenderUser2 = 0;
worldMapRender = 0;
waterSurfaceRender = 0;
clearObsRows();
@ -4987,3 +4990,9 @@ void Game::onContinuityReset()
{
themenu->onContinuityReset();
}
void Game::onPrepareRender()
{
if(waterSurfaceRender)
waterSurfaceRender->prepareRender();
}

View file

@ -398,6 +398,7 @@ public:
bool isIgnoreAction(AquariaActions ac) const;
void onContinuityReset();
void onPrepareRender();
protected:
unsigned highestLoadedEntityID;

View file

@ -6,30 +6,26 @@
#include "RenderBase.h"
WaterSurfaceRender::WaterSurfaceRender() : Quad()
{
cull = false;
this->texcoordOverride = true;
if (dsq->useFrameBuffer && dsq->frameBuffer.isInited())
if (dsq->useFrameBuffer)
{
setSegs(4, 32, 0.5f, 0.5f, -0.005f, 0, 5, 1);
}
this->renderBorder = false;
this->renderCenter = false;
this->borderAlpha = 1;
qLine = new Quad("water/water-line", Vector(0,0));
qLine->repeatTextureToFill(1);
qLine->cull = false;
game->addRenderObject(qLine, LR_WATERSURFACE2);
qLine2 = 0;
qSurface = new Quad("missingimage", Vector(0,0));
qSurface->cull = false;
qSurface->repeatTextureToFill(1);
game->addRenderObject(qSurface, LR_WATERSURFACE2);
@ -38,16 +34,28 @@ WaterSurfaceRender::WaterSurfaceRender() : Quad()
shareAlphaWithChildren = 0;
}
void WaterSurfaceRender::onUpdate(float dt)
WaterSurfaceRender::~WaterSurfaceRender()
{
}
void WaterSurfaceRender::onEndOfLife()
{
if(qLine)
qLine->safeKill();
if(qSurface)
qSurface->safeKill();
qLine = NULL;
qSurface = NULL;
}
void WaterSurfaceRender::prepareRender()
{
bool fbEffectVisible = false;
if (game->waterLevel.x > 0)
{
Quad::onUpdate(dt);
qLine->alpha = qSurface->alpha = 1;
position.x = core->screenCenter.x;
position.y = game->waterLevel.x;
@ -88,28 +96,24 @@ void WaterSurfaceRender::onUpdate(float dt)
if (dsq->useFrameBuffer && dsq->frameBuffer.isInited())
{
qSurface->alphaMod = 0.5;
qSurface->alphaMod = 0.5f;
fbEffectVisible = this->isOnScreen();
}
}
else
{
qLine->alpha = qSurface->alpha = 0;
if (qLine2)
{
qLine2->alpha = 0;
}
}
if (dsq->useFrameBuffer && dsq->frameBuffer.isInited())
if (fbEffectVisible)
{
const float reflectSize = 97;
const float reflectPos = (game->waterLevel.x - core->cameraPos.y)
+ (game->waterLevel.x - core->screenCenter.y) / 3;
const float reflectOffset = -0.03f;
const float coordDiv = 768;
const float v0 = 1 + reflectOffset - (reflectPos * core->globalScale.x) / coordDiv;
const float v1 = v0 + (reflectSize * core->globalScale.x) / coordDiv;
const float coordMul = 1.0f / 768;
const float v0 = 1 + reflectOffset - (reflectPos * core->globalScale.x) * coordMul;
const float v1 = v0 + (reflectSize * core->globalScale.x) * coordMul;
texcoords.u1 = 0;
texcoords.u2 = core->frameBuffer.getWidthP();
@ -127,27 +131,73 @@ void WaterSurfaceRender::onUpdate(float dt)
color = Vector(0.4f, 0.7f, 0.8f);
alpha = 0.2f;
}
//debugLog(fbEffectVisible ? "ws on screen" : "ws not vis");
this->fbEffectVisible = fbEffectVisible;
this->renderBorder = RenderObject::renderCollisionShape;
if(this->renderBorder)
{
this->renderBorderColor = fbEffectVisible ? Vector(1,0,1) : Vector(0,0.5f,1);
}
grid->setTexCoords(texcoords);
}
static void quadBlit(const RenderState& rs, unsigned tex)
{
rs.gpu.setBlend(BLEND_DISABLED);
glBindTexture(GL_TEXTURE_2D, tex);
glColor4f(1,1,1,1);
glPushMatrix();
glLoadIdentity();
glScalef(core->globalResolutionScale.x, core->globalResolutionScale.y, core->globalResolutionScale.z);
int vw = core->getVirtualWidth();
int vh = core->getVirtualHeight();
int offx = -core->getVirtualOffX();
int offy = -core->getVirtualOffY();
// verts are in 0..1, transform so that we cover the entire screen
glTranslatef(offx, offy, 0);
glScalef(vw, vh, 1);
core->blitQuad.render(rs);
glPopMatrix();
}
void WaterSurfaceRender::render(const RenderState& rs) const
{
if (game->waterLevel.x > 0)
{
if (fbEffectVisible)
{
// Everything up until now was rendered to the first page; flip it
const unsigned curpage = core->frameBuffer.getCurrentPage();
const unsigned oldtex = core->frameBuffer.getTextureID(curpage);
const unsigned newtex = core->frameBuffer.getTextureID(curpage + 1);
core->frameBuffer.replaceCapture(curpage + 1);
if(glCopyImageSubDataEXT)
glCopyImageSubDataEXT(
oldtex, GL_TEXTURE_2D, 0, 0, 0, 0,
newtex, GL_TEXTURE_2D, 0, 0, 0, 0,
core->width, core->height, 1
);
else
quadBlit(rs, oldtex);
}
Quad::render(rs);
}
}
void WaterSurfaceRender::onRender(const RenderState& rs) const
{
if (game->waterLevel == 0) return;
if (dsq->useFrameBuffer && dsq->frameBuffer.isInited())
{
dsq->frameBuffer.bindTexture();
}
else
{
glBindTexture(GL_TEXTURE_2D, 0);
}
if (!fbEffectVisible || game->waterLevel == 0) return;
core->frameBuffer.bindTexture(core->frameBuffer.getCurrentPage() - 1);
Quad::onRender(rs);

View file

@ -27,11 +27,14 @@ class WaterSurfaceRender : public Quad
{
public:
WaterSurfaceRender();
virtual ~WaterSurfaceRender();
void render(const RenderState& rs) const OVERRIDE;
void prepareRender();
protected:
Quad *qSurface, *qLine, *qLine2;
virtual void onEndOfLife() OVERRIDE;
Quad *qSurface, *qLine;
void onRender(const RenderState& rs) const OVERRIDE;
void onUpdate(float dt) OVERRIDE;
bool fbEffectVisible;
};
#endif

View file

@ -72,6 +72,19 @@ void AfterEffectManager::deleteEffects()
openSpots.clear();
}
void AfterEffectManager::beginCapture()
{
assert(core->frameBuffer.isInited());
core->frameBuffer.pushCapture(0);
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
}
void AfterEffectManager::endCapture()
{
core->frameBuffer.popCapture();
}
void AfterEffectManager::deleteShaders()
{
for(size_t i = 0; i < shaderPipeline.size(); ++i)
@ -146,7 +159,7 @@ void AfterEffectManager::destroyEffect(int id)
openSpots.push_back(id);
}
void AfterEffectManager::render(const RenderState& rs) const
void AfterEffectManager::render(const RenderState& rs, unsigned fboPageWithImage) const
{
assert(core->frameBuffer.isInited());
@ -154,48 +167,53 @@ void AfterEffectManager::render(const RenderState& rs) const
rs.gpu.setBlend(BLEND_DISABLED);
core->frameBuffer.endCapture();
glTranslatef(core->cameraPos.x, core->cameraPos.y, 0);
glScalef(core->invGlobalScale, core->invGlobalScale,0);
glColor4f(1,1,1,1);
renderGrid(rs);
renderGrid(rs, fboPageWithImage);
glPopMatrix();
}
void AfterEffectManager::renderGrid(const RenderState& rs) const
void AfterEffectManager::renderGrid(const RenderState& rs, unsigned fbPage) const
{
int firstShader = -1;
int lastShader = -1;
Shader *activeShader = 0;
size_t firstShader, lastShader;
Shader *activeShader = NULL;
for (size_t i = 0; i < shaderPipeline.size(); ++i)
{
if(shaderPipeline[i] && shaderPipeline[i]->isLoaded())
{
if(firstShader < 0)
if(!activeShader)
{
firstShader = int(i);
firstShader = i;
activeShader = shaderPipeline[i];
}
lastShader = int(i);
lastShader = i;
}
}
// Disable blending so we don't need to clear the framebuffers
rs.gpu.setBlend(BLEND_DISABLED);
int vw = core->getVirtualWidth();
int vh = core->getVirtualHeight();
int offx = -core->getVirtualOffX();
int offy = -core->getVirtualOffY();
core->frameBuffer.bindTexture();
const FrameBuffer * const fb = &core->frameBuffer;
// STARTING POINT: game image was just rendered into fb(0), use that as starting point
fb->bindTexture(fbPage);
if(activeShader)
{
activeShader->bind();
activeShader->setInt("tex", 0);
activeShader->bind();
// Unless this is the last pass, render to fb(1)
if(firstShader != lastShader)
backupBuffer.startCapture();
fb->pushCapture(1 - fbPage);
}
// verts are in 0..1, transform so that we cover the entire screen
@ -208,39 +226,44 @@ void AfterEffectManager::renderGrid(const RenderState& rs) const
//renderGridPoints(rs);
}
else
blitQuad.render(rs);
core->blitQuad.render(rs);
if (activeShader)
{
activeShader->unbind();
if(firstShader != lastShader)
{
// 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)
if(firstShader != lastShader)
{
activeShader = shaderPipeline[i];
if(!(activeShader && activeShader->isLoaded()))
continue;
// From here on: secondary shader passes.
// We just outputted to the backup buffer...
// Swap and exchange framebuffers. The old output buffer serves as texture input for the other one
fbOut->endCapture();
std::swap(fbIn, fbOut);
fbIn->bindTexture();
unsigned pageOut = 1 - fbPage;
// If this is the last pass, do not render to a frame buffer again
if(i != lastShader)
fbOut->startCapture();
for(size_t i = firstShader + 1; i <= lastShader; ++i)
{
unsigned pageIn = 1 - pageOut;
activeShader = shaderPipeline[i];
if(!(activeShader && activeShader->isLoaded()))
continue;
activeShader->bind();
activeShader->setInt("tex", 0);
// Swap and exchange framebuffers. The old output buffer serves as texture input for the other one
pageOut = pageIn;
blitQuad.render(rs);
// If this is the last pass, do not render to a frame buffer again
if(i == lastShader)
fb->popCapture();
else
fb->replaceCapture(pageOut);
activeShader->unbind();
fb->bindTexture(pageIn);
activeShader->bind();
activeShader->setInt("tex", 0);
core->blitQuad.render(rs);
activeShader->unbind();
}
}
}
@ -255,9 +278,7 @@ void AfterEffectManager::renderGridPoints(const RenderState& rs) const
void AfterEffectManager::unloadDevice()
{
backupBuffer.unloadDevice();
grid.dropBuffers();
blitQuad.dropBuffers();
unloadShaders();
}
@ -266,30 +287,12 @@ void AfterEffectManager::_updateScreenSize()
screenWidth = core->getWindowWidth();
screenHeight = core->getWindowHeight();
if (core->frameBuffer.isInited())
{
textureWidth = core->frameBuffer.getTexWidth();
textureHeight = core->frameBuffer.getTexHeight();
}
else
{
textureWidth = screenWidth;
sizePowerOf2Texture(textureWidth);
textureHeight = screenHeight;
sizePowerOf2Texture(textureHeight);
}
const float percentX = (float)screenWidth/(float)textureWidth;
const float percentY = (float)screenHeight/(float)textureHeight;
TexCoordBox tc = { 0, percentY, percentX, 0 }; // Y is upside down
grid.setTexCoords(tc);
blitQuad.setTexCoords(tc);
grid.setTexCoords(core->blitQuad.getTexCoords());
}
void AfterEffectManager::updateDevice()
{
_updateScreenSize();
backupBuffer.init(-1, -1, true);
_initGrid();
}
@ -297,7 +300,6 @@ void AfterEffectManager::reloadDevice()
{
_updateScreenSize();
backupBuffer.reloadDevice();
_initGrid();
for (size_t i = 0; i < loadedShaders.size(); ++i)
@ -442,10 +444,6 @@ void AfterEffectManager::_initGrid()
grid.init(xDivs, yDivs);
else
grid.dropBuffers();
blitQuad.init(2, 2);
blitQuad.reset01();
blitQuad.updateVBO(); // never changed afterwards
}
void AfterEffectManager::deleteShader(int handle)

View file

@ -78,10 +78,13 @@ public:
void clear();
void deleteEffects();
void beginCapture();
void endCapture();
void resetGrid();
void render(const RenderState& rs) const;
void renderGrid(const RenderState& rs) const;
void render(const RenderState& rs, unsigned fboPageWithImage) const;
void renderGrid(const RenderState& rs, unsigned fbPage) const;
void renderGridPoints(const RenderState& rs) const;
void loadShaders();
@ -105,17 +108,15 @@ protected:
int _insertShader(Shader *sh);
void _initGrid();
RenderGrid grid, blitQuad;
RenderGrid grid;
bool active;
int numEffects;
int xDivs, yDivs;
int screenWidth, screenHeight;
int textureWidth, textureHeight;
std::vector<Effect*> effects;
std::vector<int> openSpots;
std::vector<Shader*> shaderPipeline; // Shaders are applied in this order. Can contain the same pointer more than once.
std::vector<Shader*> loadedShaders;
FrameBuffer backupBuffer;
};

View file

@ -151,7 +151,7 @@ void Core::setup_opengl()
setClearColor(clearColor);
frameBuffer.init(-1, -1, true);
frameBuffer.init(-1, -1, 2);
if(afterEffectManager)
afterEffectManager->updateDevice();
@ -160,6 +160,32 @@ void Core::setup_opengl()
defaultQuadGrid.init(2, 2, defaultTC);
defautQuadBorder.initQuadVertices(defaultTC, GPUACCESS_DEFAULT);
int screenWidth = getWindowWidth();
int screenHeight = core->getWindowHeight();
int textureWidth, textureHeight;
if (core->frameBuffer.isInited())
{
textureWidth = core->frameBuffer.getTexWidth();
textureHeight = core->frameBuffer.getTexHeight();
}
else
{
textureWidth = screenWidth;
sizePowerOf2Texture(textureWidth);
textureHeight = screenHeight;
sizePowerOf2Texture(textureHeight);
}
const float percentX = (float)screenWidth/(float)textureWidth;
const float percentY = (float)screenHeight/(float)textureHeight;
TexCoordBox tc = { 0, percentY, percentX, 0 }; // Y is upside down
blitQuad.setTexCoords(tc);
blitQuad.init(2, 2);
blitQuad.reset01();
blitQuad.updateVBO(); // never changed afterwards
}
void Core::resizeWindow(int w, int h, int full, int bpp, int vsync, int display, int hz)
@ -378,7 +404,6 @@ Core::Core(const std::string &filesystem, const std::string& extraDataDir, int n
baseCullRadius = 1;
width = height = 0;
_lastEnumeratedDisplayIndex = -1;
afterEffectManagerLayer = 0;
renderObjectLayers.resize(1);
invGlobalScale = 1.0;
invGlobalScaleSqr = 1.0;
@ -740,7 +765,9 @@ void Core::initGraphicsLibrary(int width, int height, bool fullscreen, bool vsyn
enumerateScreenModes(window->getDisplayIndex());
window->updateSize();
cacheRender(); // Clears the window bg to black early; prevents flickering
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
showBuffer();
lib_graphics = true;
}
@ -1182,15 +1209,14 @@ void Core::run(float runTime)
if (settings.renderOn)
{
if (darkLayer.isUsed())
if(!minimized)
{
darkLayer.preRender();
prepareRender();
renderInternal(-1, -1, true);
showBuffer();
}
render();
showBuffer();
if (nestedMains == 1)
clearGarbage();
@ -1221,11 +1247,6 @@ void Core::run(float runTime)
nestedMains--;
}
void Core::clearBuffers()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); // Clear The Screen And The Depth Buffer
}
void Core::setupRenderPositionAndScale()
{
glScalef(globalScale.x*globalResolutionScale.x, globalScale.y*globalResolutionScale.y, globalScale.z*globalResolutionScale.z);
@ -1766,7 +1787,7 @@ void Core::print(int x, int y, const char *str, float sz)
void Core::cacheRender()
{
render();
renderExternal();
// what if the screen was full white? then you wouldn't want to clear buffers
//clearBuffers();
showBuffer();
@ -1780,7 +1801,13 @@ void Core::updateCullData()
screenCenter = cullCenter = cameraPos + Vector(400.0f*invGlobalScale,300.0f*invGlobalScale);
}
void Core::render(int startLayer, int endLayer, bool useFrameBufferIfAvail)
void Core::renderExternal()
{
prepareRender();
renderInternal(-1, -1, true);
}
void Core::prepareRender()
{
renderObjectCount = 0;
processedRenderObjectCount = 0;
@ -1788,13 +1815,10 @@ void Core::render(int startLayer, int endLayer, bool useFrameBufferIfAvail)
globalScaleChanged();
if (minimized) return;
onRender();
RenderObject::lastTextureApplied = 0;
updateCullData();
onPrepareRender();
// TODO: this could be done in parallel
for (size_t i = 0; i < renderObjectLayers.size(); ++i)
{
@ -1802,50 +1826,54 @@ void Core::render(int startLayer, int endLayer, bool useFrameBufferIfAvail)
renderObjectLayers[i].prepareRender();
}
if (darkLayer.isUsed())
{
darkLayer.preRender();
}
glClearColor(0,0,0,0);
glClear(GL_COLOR_BUFFER_BIT);
glViewport(0, 0, core->width, core->height);
}
// Make sure to call prepareRender() before calling this!
void Core::renderInternal(int startLayer, int endLayer, bool allowSkip)
{
onRender();
RenderObject::lastTextureApplied = 0;
glBindTexture(GL_TEXTURE_2D, 0);
glLoadIdentity(); // Reset The View
clearBuffers();
if (afterEffectManager && frameBuffer.isInited() && useFrameBufferIfAvail)
{
frameBuffer.startCapture();
}
setupRenderPositionAndScale();
CombinedRenderAndGPUState rs;
for (size_t c = 0; c < renderObjectLayerOrder.size(); c++)
{
int i = renderObjectLayerOrder[c];
if (i == -1) continue;
if ((startLayer != -1 && endLayer != -1) && (i < startLayer || i > endLayer)) continue;
if (darkLayer.isUsed() )
{
if (i == darkLayer.getRenderLayer())
{
darkLayer.render(rs);
}
if (i == darkLayer.getLayer() && startLayer != i)
{
continue;
}
}
if (afterEffectManager /*&& afterEffectManager->active*/ && i == afterEffectManagerLayer)
{
afterEffectManager->render(rs);
}
// don't render the layers that the dark layer takes as input
if(allowSkip && !darkLayer.shouldRenderLayer(i))
continue;
RenderObjectLayer *r = &renderObjectLayers[i];
if(!r->visible)
continue;
if(r->preRender)
if(!r->preRender(rs))
continue;
r->render(rs);
if(r->postRender)
r->postRender(rs);
}
}
@ -1949,6 +1977,7 @@ void Core::shutdown()
defaultQuadGrid.dropBuffers();
defautQuadBorder.dropBuffer();
blitQuad.dropBuffers();
debugLog("Shutdown Graphics Library...");
shutdownGraphicsLibrary();

View file

@ -113,6 +113,9 @@ enum FollowCameraLock
typedef std::vector <RenderObject*> RenderObjects;
typedef bool (*PreRenderFunc)(const RenderState& rs);
typedef void (*PostRenderFunc)(const RenderState& rs);
class RenderObjectLayer
{
public:
@ -170,6 +173,9 @@ public:
bool update;
PreRenderFunc preRender;
PostRenderFunc postRender;
protected:
RenderObjects renderObjects;
std::vector<const RenderObject*> toRender;
@ -206,8 +212,9 @@ public:
void applyState(const std::string &state);
void clearBuffers();
void render(int startLayer=-1, int endLayer=-1, bool useFrameBufferIfAvail=true);
void renderExternal();
void prepareRender();
void renderInternal(int startLayer, int endLayer, bool allowSkip);
void showBuffer();
void quit();
bool isShuttingDown();
@ -465,7 +472,6 @@ protected:
virtual void onJoystickAdded(int deviceID);
virtual void onJoystickRemoved(int instanceID);
int afterEffectManagerLayer;
Vector cameraOffset;
std::vector<float> avgFPS;
virtual void modifyDt(float &dt){}
@ -486,6 +492,7 @@ protected:
virtual void onUpdate(float dt);
virtual void onRender(){}
virtual void onPrepareRender(){}
void setupFileAccess();
std::string _extraDataDir;
@ -498,6 +505,8 @@ protected:
DynamicGPUBuffer defautQuadBorder;
public:
RenderGrid blitQuad;
// inclusive!
inline int getMaxActionStatusIndex() const { return int(actionStatus.size()) - 2; }
// pass -1 for is a sentinel that captures all input

View file

@ -26,12 +26,11 @@ DarkLayer::DarkLayer()
{
quality = 0;
active = false;
layer = -1;
renderLayer = -1;
texture = 0;
format = GL_RGB; //FIXED?: used to be GL_LUMINANCE, that might have been causing problems
useFrameBuffer = true; //BUG?: will do this even if frame buffer is off in usersettings...
useFrameBuffer = false;
layer = -1;
beginLayer = -1;
lastLayer = -1;
}
void DarkLayer::unloadDevice()
@ -53,23 +52,16 @@ void DarkLayer::reloadDevice()
texture = generateEmptyTexture(quality);
}
int DarkLayer::getRenderLayer()
bool DarkLayer::isUsed() const
{
return renderLayer;
return active;
}
bool DarkLayer::isUsed()
bool DarkLayer::shouldRenderLayer(int lr) const
{
//HACK: disabling dark layer for temporary testing build
// MAKE SURE TO RESTORE THIS CODE TO THE WAY IT WAS
return layer > -1 && active;
}
void DarkLayer::setLayers(int layer, int rl)
{
this->layer = layer;
this->renderLayer = rl;
if(!active)
return true;
return useFrameBuffer || (lr < beginLayer || lr > lastLayer);
}
void DarkLayer::init(int quality, bool useFrameBufferParam)
@ -80,7 +72,7 @@ void DarkLayer::init(int quality, bool useFrameBufferParam)
if (useFrameBuffer)
{
if (!frameBuffer.init(quality, quality))
if (!frameBuffer.init(quality, quality, 1))
useFrameBuffer = false;
else
debugLog("Dark Layer: using framebuffer");
@ -92,11 +84,6 @@ void DarkLayer::init(int quality, bool useFrameBufferParam)
}
}
int DarkLayer::getLayer()
{
return layer;
}
void DarkLayer::toggle(bool on)
{
this->active = on;
@ -104,77 +91,77 @@ void DarkLayer::toggle(bool on)
void DarkLayer::preRender()
{
if (layer != -1)
if(!useFrameBuffer)
{
glViewport(0,0,quality,quality);
if (useFrameBuffer)
frameBuffer.startCapture();
glViewport(0, 0, quality, quality);
glClearColor(1,1,1,0);
glClear(GL_COLOR_BUFFER_BIT);
core->renderInternal(beginLayer, lastLayer, false);
glBindTexture(GL_TEXTURE_2D, texture);
glReadBuffer(GL_BACK);
glCopyTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, 0, 0, quality, quality, 0);
glBindTexture(GL_TEXTURE_2D, 0);
}
}
core->render(layer, layer, false);
void DarkLayer::beginCapture()
{
if(useFrameBuffer)
{
frameBuffer.pushCapture(0);
glClearColor(1,1,1,0);
glClear(GL_COLOR_BUFFER_BIT);
}
}
if (useFrameBuffer)
frameBuffer.endCapture();
else
{
glBindTexture(GL_TEXTURE_2D,texture); // Bind To The Blur Texture
// Copy Our ViewPort To The Blur Texture (From 0,0 To q,q... No Border)
glCopyTexImage2D(GL_TEXTURE_2D, 0, format, 0, 0, quality, quality, 0);
}
glViewport(0, 0, core->width, core->height);
glClearColor(0,0,0,0);
void DarkLayer::endCapture()
{
if(useFrameBuffer)
{
frameBuffer.popCapture();
}
}
void DarkLayer::render(const RenderState& rs) const
{
if (renderLayer != -1)
{
glPushMatrix();
glLoadIdentity();
glPushMatrix();
glLoadIdentity();
glEnable(GL_TEXTURE_2D);
if (useFrameBuffer)
frameBuffer.bindTexture(0);
else
glBindTexture(GL_TEXTURE_2D,texture);
glEnable(GL_TEXTURE_2D);
if (useFrameBuffer)
frameBuffer.bindTexture();
else
glBindTexture(GL_TEXTURE_2D,texture);
rs.gpu.setBlend(BLEND_MULT);
rs.gpu.setBlend(BLEND_MULT);
glColor4f(1,1,1,1);
glColor4f(1,1,1,1);
const float width = core->getWindowWidth();
const float height = core->getWindowHeight();
const float offX = -(core->getVirtualOffX() * width / core->getVirtualWidth());
const float offY = -(core->getVirtualOffY() * height / core->getVirtualHeight());
const float stretch = 4;
const float width = core->getWindowWidth();
const float height = core->getWindowHeight();
const float offX = -(core->getVirtualOffX() * width / core->getVirtualWidth());
const float offY = -(core->getVirtualOffY() * height / core->getVirtualHeight());
const float stretch = 4;
glBegin(GL_QUADS);
glBegin(GL_QUADS);
glTexCoord2f(0,1);
glVertex2f(offX-stretch, offY-stretch);
glTexCoord2f(0,1);
glVertex2f(offX-stretch, offY-stretch);
glTexCoord2f(0,0);
glVertex2f(offX-stretch, height+offY+stretch);
glTexCoord2f(0,0);
glVertex2f(offX-stretch, height+offY+stretch);
glTexCoord2f(1,0);
glVertex2f(width+offX+stretch, height+offY+stretch);
glTexCoord2f(1,0);
glVertex2f(width+offX+stretch, height+offY+stretch);
glTexCoord2f(1,1);
glVertex2f(width+offX+stretch, offY-stretch);
glTexCoord2f(1,1);
glVertex2f(width+offX+stretch, offY-stretch);
glEnd();
glEnd();
glPopMatrix();
glPopMatrix();
RenderObject::lastTextureApplied = 0;
glBindTexture(GL_TEXTURE_2D, 0);
}
RenderObject::lastTextureApplied = 0;
glBindTexture(GL_TEXTURE_2D, 0);
}

View file

@ -32,24 +32,28 @@ public:
DarkLayer();
void init(int quality, bool useFrameBuffer=true);
void toggle(bool on);
void setLayers(int layer, int renderLayer);
void preRender();
void setSrcLayer(int layer);
void preRender(); // call before rendering anything else. this is for render-to-texture mode
void beginCapture(); // call this + endCapture() when rendering the layer where dark layer objects are located
void endCapture();
void render(const RenderState& rs) const;
int getLayer();
int getRenderLayer();
bool isUsed();
bool isUsed() const;
bool shouldRenderLayer(int lr) const;
void unloadDevice();
void reloadDevice();
int beginLayer;
int lastLayer; // inclusive
protected:
bool useFrameBuffer;
FrameBuffer frameBuffer;
protected:
int quality;
int layer;
bool active;
int layer, renderLayer;
unsigned texture;
unsigned format;
};
#endif

View file

@ -24,15 +24,47 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
//WARNING: FrameBuffer objects have to have reloadDevice/unloadDevice called manually!
struct FBOStack
{
const FrameBuffer *fbo;
unsigned page;
};
static FBOStack s_fbostack[4]; // first entry is always unused
static size_t s_stackpos = 0;
static bool isOnTop(const FrameBuffer *fbo)
{
return s_fbostack[s_stackpos].fbo == fbo;
}
static bool isInStack(const FrameBuffer *fbo, unsigned page)
{
for(size_t i = 1; i <= s_stackpos; ++i) // first entry is always NULL
if(s_fbostack[i].fbo == fbo && s_fbostack[i].page == page)
return true;
return false;
}
FrameBuffer::FrameBuffer()
{
inited = false;
texw = 0;
texh = 0;
g_frameBuffer = 0;
g_depthRenderBuffer = 0;
g_dynamicTextureID = 0;
viewportW = 0;
viewportH = 0;
_curpage = 0;
_w = _h = 0;
_numpages = 0;
_numfbos = 0;
for(size_t i = 0; i < Countof(_texs); ++i)
{
_fbos[i] = 0;
_texs[i] = 0;
}
}
FrameBuffer::~FrameBuffer()
@ -50,10 +82,18 @@ float FrameBuffer::getHeightP() const
return (float)core->getWindowHeight()/(float)texh;
}
bool FrameBuffer::init(int width, int height, bool fitToScreen)
bool FrameBuffer::getCurrentPage() const
{
assert(_curpage);
return _curpage - 1;
}
bool FrameBuffer::init(int width, int height, unsigned pages)
{
assert(pages && pages < Countof(_texs));
_w = width;
_h = height;
_numpages = pages;
if (width == -1)
width = core->width;
@ -61,13 +101,12 @@ bool FrameBuffer::init(int width, int height, bool fitToScreen)
if (height == -1)
height = core->height;
if (fitToScreen)
{
sizePowerOf2Texture(width);
sizePowerOf2Texture(height);
}
viewportW = width;
viewportH = height;
sizePowerOf2Texture(width);
sizePowerOf2Texture(height);
_fitToScreen = fitToScreen;
if (width == 0 || height == 0)
return false;
@ -78,12 +117,8 @@ bool FrameBuffer::init(int width, int height, bool fitToScreen)
os << "Loading EXT_framebuffer_object (" << texw << ", " << texh << ")";
debugLog(os.str());
if( !glIsRenderbufferEXT || !glBindRenderbufferEXT || !glDeleteRenderbuffersEXT ||
!glGenRenderbuffersEXT || !glRenderbufferStorageEXT || !glGetRenderbufferParameterivEXT ||
!glIsFramebufferEXT || !glBindFramebufferEXT || !glDeleteFramebuffersEXT ||
!glGenFramebuffersEXT || !glCheckFramebufferStatusEXT || !glFramebufferTexture1DEXT ||
!glFramebufferTexture2DEXT || !glFramebufferTexture3DEXT || !glFramebufferRenderbufferEXT||
!glGetFramebufferAttachmentParameterivEXT)
if( !glIsFramebufferEXT || !glBindFramebufferEXT || !glDeleteFramebuffersEXT ||
!glGenFramebuffersEXT || !glCheckFramebufferStatusEXT || !glFramebufferTexture2DEXT)
{
debugLog("One or more EXT_framebuffer_object functions were not found");
return false;
@ -91,58 +126,58 @@ bool FrameBuffer::init(int width, int height, bool fitToScreen)
unloadDevice();
//
// Create a frame-buffer object and a render-buffer object...
//
// If glDrawBuffersARB() is present, we can attach multiple textures per FBO
// and switch between them as render targets. More efficient than switching FBOs.
_numfbos = glDrawBuffersARB ? 1 : pages;
glGenFramebuffersEXT( 1, &g_frameBuffer );
glGenRenderbuffersEXT( 1, &g_depthRenderBuffer );
glGenFramebuffersEXT(_numfbos, &_fbos[0]);
for(unsigned i = 0; i < _numfbos; ++i)
if(!_fbos[i])
return false;
// Initialize the render-buffer for usage as a depth buffer.
// We don't really need this to render things into the frame-buffer object,
// but without it the geometry will not be sorted properly.
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, g_depthRenderBuffer );
glRenderbufferStorageEXT( GL_RENDERBUFFER_EXT, GL_DEPTH_COMPONENT24, width, height );
if(_numfbos == 1)
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, _fbos[0] );
glGenTextures( pages, &_texs[0] );
glGenTextures( 1, &g_dynamicTextureID );
for(unsigned i = 0; i < pages; ++i)
{
unsigned attach = GL_COLOR_ATTACHMENT0_EXT;
if(_numfbos > 1)
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, _fbos[i] );
else
attach += i;
glBindTexture( GL_TEXTURE_2D, g_dynamicTextureID );
// GL_LINEAR
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glBindTexture(GL_TEXTURE_2D, _texs[i]);
// GL_LINEAR
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA,
width, height,
0, GL_RGBA, GL_UNSIGNED_BYTE, 0 );
glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA,
width, height,
0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
// Put together
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, g_frameBuffer );
glFramebufferTexture2DEXT( GL_FRAMEBUFFER_EXT, GL_COLOR_ATTACHMENT0_EXT, GL_TEXTURE_2D, g_dynamicTextureID, 0 );
glFramebufferRenderbufferEXT( GL_FRAMEBUFFER_EXT, GL_DEPTH_ATTACHMENT_EXT, GL_RENDERBUFFER_EXT, g_depthRenderBuffer );
//
// Check for errors...
//
GLenum status = glCheckFramebufferStatusEXT( GL_FRAMEBUFFER_EXT );
glFramebufferTexture2DEXT(GL_FRAMEBUFFER_EXT, attach, GL_TEXTURE_2D, _texs[i], 0);
}
glBindTexture(GL_TEXTURE_2D, 0);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
glBindRenderbufferEXT(GL_RENDERBUFFER_EXT, 0);
switch( status )
for(unsigned i = 0; i < _numfbos; ++i)
{
case GL_FRAMEBUFFER_COMPLETE_EXT:
break;
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, _fbos[i] );
GLenum status = glCheckFramebufferStatusEXT(GL_FRAMEBUFFER_EXT);
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
debugLog("GL_FRAMEBUFFER_UNSUPPORTED_EXT!");
default:
unloadDevice();
return false;
switch( status )
{
case GL_FRAMEBUFFER_COMPLETE_EXT:
break;
case GL_FRAMEBUFFER_UNSUPPORTED_EXT:
debugLog("GL_FRAMEBUFFER_UNSUPPORTED_EXT!");
default:
unloadDevice();
return false;
}
}
debugLog("Done");
@ -161,58 +196,107 @@ void FrameBuffer::unloadDevice()
return;
}
if (g_frameBuffer)
{
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
for(size_t i = 0; i < Countof(_texs); ++i)
if (_fbos[i])
{
debugLog("frameBuffer handle present, deleting");
glDeleteFramebuffersEXT(1, &_fbos[i]);
_fbos[i] = 0;
}
debugLog("frameBuffer handle present, deleting");
glDeleteFramebuffersEXT(1, &g_frameBuffer);
g_frameBuffer = 0;
}
for(size_t i = 0; i < Countof(_texs); ++i)
if (_texs[i])
{
debugLog("delete framebuffer texture");
glDeleteTextures(1, &_texs[i]);
_texs[i] = 0;
}
if (g_dynamicTextureID)
{
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
debugLog("dynamic texture ID handle present, deleting");
glDeleteTextures(1, &g_dynamicTextureID);
g_dynamicTextureID = 0;
}
if (g_depthRenderBuffer)
{
glBindRenderbufferEXT( GL_RENDERBUFFER_EXT, 0 );
debugLog("depth render buffer handle present, deleting");
glDeleteRenderbuffersEXT(1, &g_depthRenderBuffer);
g_depthRenderBuffer = 0;
}
debugLog("done");
}
void FrameBuffer::reloadDevice()
{
if(!_numpages)
return;
debugLog("frameBuffer::reloadDevice");
init(_w, _h, _fitToScreen);
init(_w, _h, _numpages);
}
void FrameBuffer::startCapture() const
void FrameBuffer::_bind(unsigned page) const
{
assert(page < _numpages);
_curpage = page + 1;
if(glDrawBuffersARB)
{
assert(_numfbos == 1);
if(!isOnTop(this))
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fbos[0]);
GLenum buf = GL_COLOR_ATTACHMENT0_EXT + page;
glDrawBuffersARB(1, &buf);
}
else
{
assert(_fbos[page]);
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, _fbos[page]);
}
glViewport(0,0,viewportW,viewportH);
}
void FrameBuffer::pushCapture(unsigned page) const
{
assert(inited);
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, g_frameBuffer );
glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
_bind(page);
size_t idx = ++s_stackpos;
assert(idx < Countof(s_fbostack));
s_fbostack[idx].fbo = this;
s_fbostack[idx].page = page;
}
void FrameBuffer::endCapture() const
unsigned FrameBuffer::popCapture() const
{
assert(inited);
glBindFramebufferEXT( GL_FRAMEBUFFER_EXT, 0 );
assert(inited && s_stackpos && isOnTop(this));
const unsigned page = s_fbostack[s_stackpos].page;
FBOStack prev = s_fbostack[--s_stackpos];
if(prev.fbo)
prev.fbo->_bind(prev.page);
else
{
glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, 0);
if(glDrawBuffersARB)
glDrawBuffer(GL_BACK);
glViewport(0, 0, core->width, core->height);
}
return page;
}
void FrameBuffer::bindTexture() const
void FrameBuffer::replaceCapture(unsigned page) const
{
assert(inited);
glBindTexture( GL_TEXTURE_2D, g_dynamicTextureID );
assert(inited && s_stackpos);
_bind(page);
s_fbostack[s_stackpos].fbo = this;
s_fbostack[s_stackpos].page = page;
}
unsigned FrameBuffer::getTextureID(unsigned page) const
{
assert(inited && page < _numpages);
return _texs[page];
}
void FrameBuffer::bindTexture(unsigned page) const
{
// Technically it's enough that this texture isn't the one currently rendered to,
// but because we don't know when the topmost FBO is popped (and subsequently
// writing to the texture we're now about to read from) let's be extra safe
// and generalize this to: Textures part of the FBO stack are forbidden to bind.
assert(!isInStack(this, page));
unsigned tex = getTextureID(page);
glBindTexture(GL_TEXTURE_2D, tex);
}

View file

@ -23,32 +23,47 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "Base.h"
class FrameBufferCapture;
struct RenderState;
class FrameBuffer
{
friend class FrameBufferCapture;
public:
FrameBuffer();
~FrameBuffer();
bool init(int width, int height, bool fitToScreen=false);
bool init(int width, int height, unsigned pages);
bool isInited() const { return inited; }
void startCapture() const;
void endCapture() const;
void bindTexture() const;
unsigned getTextureID(unsigned page) const;
void bindTexture(unsigned page) const;
int getTexWidth() const { return texw; }
int getTexHeight() const { return texh; }
float getWidthP() const;
float getHeightP() const;
bool getCurrentPage() const;
void unloadDevice();
void reloadDevice();
// push/pop capture stack
void pushCapture(unsigned page) const;
unsigned popCapture() const; // returns page
// replace top of capture stack with this
void replaceCapture(unsigned page) const;
protected:
void _bind(unsigned page) const;
unsigned _fbos[8];
unsigned _texs[8];
int _w, _h;
bool _fitToScreen;
unsigned g_frameBuffer;
unsigned g_depthRenderBuffer;
unsigned g_dynamicTextureID;
mutable unsigned _curpage; // 0 if not currently bound
unsigned _numpages, _numfbos;
int texw, texh;
int viewportW, viewportH;
bool inited;
};

View file

@ -98,22 +98,13 @@ PFNGLUNIFORM3IVARBPROC glUniform3ivARB = NULL;
PFNGLUNIFORM4IVARBPROC glUniform4ivARB = NULL;
// GL_ARB_shader_objects and related
PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT = NULL;
PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT = NULL;
PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT = NULL;
PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT = NULL;
PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT = NULL;
PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT = NULL;
PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT = NULL;
PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT = NULL;
PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT = NULL;
PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT = NULL;
PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT = NULL;
PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT = NULL;
PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT = NULL;
PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT = NULL;
PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT = NULL;
PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT = NULL;
PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB = NULL;
// ARB_vertex_buffer_object
PFNGLGENBUFFERSARBPROC glGenBuffersARB = NULL;
@ -124,6 +115,8 @@ PFNGLBINDBUFFERARBPROC glBindBufferARB = NULL;
PFNGLMAPBUFFERARBPROC glMapBufferARB = NULL;
PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB = NULL;
PFNGLCOPYIMAGESUBDATAEXTPROC glCopyImageSubDataEXT = NULL;
// extern
unsigned g_dbg_numRenderCalls = 0;
bool g_has_GL_GENERATE_MIPMAP = false;
@ -182,22 +175,16 @@ bool lookup_all_glsyms()
debugLog(os.str());
}
// framebuffer
glIsRenderbufferEXT = (PFNGLISRENDERBUFFEREXTPROC)SDL_GL_GetProcAddress("glIsRenderbufferEXT");
glBindRenderbufferEXT = (PFNGLBINDRENDERBUFFEREXTPROC)SDL_GL_GetProcAddress("glBindRenderbufferEXT");
glDeleteRenderbuffersEXT = (PFNGLDELETERENDERBUFFERSEXTPROC)SDL_GL_GetProcAddress("glDeleteRenderbuffersEXT");
glGenRenderbuffersEXT = (PFNGLGENRENDERBUFFERSEXTPROC)SDL_GL_GetProcAddress("glGenRenderbuffersEXT");
glRenderbufferStorageEXT = (PFNGLRENDERBUFFERSTORAGEEXTPROC)SDL_GL_GetProcAddress("glRenderbufferStorageEXT");
glGetRenderbufferParameterivEXT = (PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC)SDL_GL_GetProcAddress("glGetRenderbufferParameterivEXT");
glIsFramebufferEXT = (PFNGLISFRAMEBUFFEREXTPROC)SDL_GL_GetProcAddress("glIsFramebufferEXT");
glBindFramebufferEXT = (PFNGLBINDFRAMEBUFFEREXTPROC)SDL_GL_GetProcAddress("glBindFramebufferEXT");
glDeleteFramebuffersEXT = (PFNGLDELETEFRAMEBUFFERSEXTPROC)SDL_GL_GetProcAddress("glDeleteFramebuffersEXT");
glGenFramebuffersEXT = (PFNGLGENFRAMEBUFFERSEXTPROC)SDL_GL_GetProcAddress("glGenFramebuffersEXT");
glCheckFramebufferStatusEXT = (PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC)SDL_GL_GetProcAddress("glCheckFramebufferStatusEXT");
glFramebufferTexture1DEXT = (PFNGLFRAMEBUFFERTEXTURE1DEXTPROC)SDL_GL_GetProcAddress("glFramebufferTexture1DEXT");
glFramebufferTexture2DEXT = (PFNGLFRAMEBUFFERTEXTURE2DEXTPROC)SDL_GL_GetProcAddress("glFramebufferTexture2DEXT");
glFramebufferTexture3DEXT = (PFNGLFRAMEBUFFERTEXTURE3DEXTPROC)SDL_GL_GetProcAddress("glFramebufferTexture3DEXT");
glFramebufferRenderbufferEXT = (PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC)SDL_GL_GetProcAddress("glFramebufferRenderbufferEXT");
glGetFramebufferAttachmentParameterivEXT = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC)SDL_GL_GetProcAddress("glGetFramebufferAttachmentParameterivEXT");
glDrawBuffersARB = NULL;//(PFNGLDRAWBUFFERSARBPROC)SDL_GL_GetProcAddress("glDrawBuffersARB");
// GL 4.3+, but maybe available as an extension
glCopyImageSubDataEXT = (PFNGLCOPYIMAGESUBDATAEXTPROC)SDL_GL_GetProcAddress("glCopyImageSubDataEXT");
// shaders
glCreateProgramObjectARB = (PFNGLCREATEPROGRAMOBJECTARBPROC)SDL_GL_GetProcAddress("glCreateProgramObjectARB");
@ -265,22 +252,13 @@ void unload_all_glsyms()
// set these back to NULL and reload them upon reinit, otherwise they
// might point to a bogus address when the shared library is reloaded.
glIsRenderbufferEXT = NULL;
glBindRenderbufferEXT = NULL;
glDeleteRenderbuffersEXT = NULL;
glGenRenderbuffersEXT = NULL;
glRenderbufferStorageEXT = NULL;
glGetRenderbufferParameterivEXT = NULL;
glIsFramebufferEXT = NULL;
glBindFramebufferEXT = NULL;
glDeleteFramebuffersEXT = NULL;
glGenFramebuffersEXT = NULL;
glCheckFramebufferStatusEXT = NULL;
glFramebufferTexture1DEXT = NULL;
glFramebufferTexture2DEXT = NULL;
glFramebufferTexture3DEXT = NULL;
glFramebufferRenderbufferEXT = NULL;
glGetFramebufferAttachmentParameterivEXT = NULL;
glDrawBuffersARB = NULL;
glCreateProgramObjectARB = NULL;
glDeleteObjectARB = NULL;

View file

@ -87,6 +87,8 @@ GL_FUNC(void,glTexCoord2f,(GLfloat s, GLfloat t),(s,t),)
//GL_FUNC(void,glTexCoord2d,(GLdouble s, GLdouble t),(s,t),)
GL_FUNC(void,glVertex2f,(GLfloat x, GLfloat y),(x,y),)
GL_FUNC(void,glVertex3f,(GLfloat x, GLfloat y, GLfloat z),(x,y,z),)
GL_FUNC(void,glReadBuffer,(GLenum mode),(mode),)
GL_FUNC(void,glDrawBuffer,(GLenum mode),(mode),)
// stuff GLU needs...
GL_FUNC(void,glGetIntegerv,(GLenum pname, GLint *params),(pname,params),)

View file

@ -50,6 +50,10 @@ GLAPI GLuint APIENTRY glGetDebugMessageLogARB (GLuint count, GLsizei bufSize, GL
#endif
#endif /* GL_ARB_debug_output */
#if !defined(GL_ARB_copy_image) && !defined(GL_VERSION_4_3)
typedef void (APIENTRYP PFNGLCOPYIMAGESUBDATAEXTPROC) (GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
#endif
#ifdef _WINDOWS_
#error windows.h was included! euuugh!
#endif
@ -86,22 +90,13 @@ extern PFNGLUNIFORM2IVARBPROC glUniform2ivARB;
extern PFNGLUNIFORM3IVARBPROC glUniform3ivARB;
extern PFNGLUNIFORM4IVARBPROC glUniform4ivARB;
extern PFNGLISRENDERBUFFEREXTPROC glIsRenderbufferEXT;
extern PFNGLBINDRENDERBUFFEREXTPROC glBindRenderbufferEXT;
extern PFNGLDELETERENDERBUFFERSEXTPROC glDeleteRenderbuffersEXT;
extern PFNGLGENRENDERBUFFERSEXTPROC glGenRenderbuffersEXT;
extern PFNGLRENDERBUFFERSTORAGEEXTPROC glRenderbufferStorageEXT;
extern PFNGLGETRENDERBUFFERPARAMETERIVEXTPROC glGetRenderbufferParameterivEXT;
extern PFNGLISFRAMEBUFFEREXTPROC glIsFramebufferEXT;
extern PFNGLBINDFRAMEBUFFEREXTPROC glBindFramebufferEXT;
extern PFNGLDELETEFRAMEBUFFERSEXTPROC glDeleteFramebuffersEXT;
extern PFNGLGENFRAMEBUFFERSEXTPROC glGenFramebuffersEXT;
extern PFNGLCHECKFRAMEBUFFERSTATUSEXTPROC glCheckFramebufferStatusEXT;
extern PFNGLFRAMEBUFFERTEXTURE1DEXTPROC glFramebufferTexture1DEXT;
extern PFNGLFRAMEBUFFERTEXTURE2DEXTPROC glFramebufferTexture2DEXT;
extern PFNGLFRAMEBUFFERTEXTURE3DEXTPROC glFramebufferTexture3DEXT;
extern PFNGLFRAMEBUFFERRENDERBUFFEREXTPROC glFramebufferRenderbufferEXT;
extern PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVEXTPROC glGetFramebufferAttachmentParameterivEXT;
extern PFNGLDRAWBUFFERSARBPROC glDrawBuffersARB;
extern PFNGLGENBUFFERSARBPROC glGenBuffersARB;
extern PFNGLDELETEBUFFERSARBPROC glDeleteBuffersARB;
@ -111,4 +106,6 @@ extern PFNGLBINDBUFFERARBPROC glBindBufferARB;
extern PFNGLMAPBUFFERARBPROC glMapBufferARB;
extern PFNGLUNMAPBUFFERARBPROC glUnmapBufferARB;
extern PFNGLCOPYIMAGESUBDATAEXTPROC glCopyImageSubDataEXT;
#endif

View file

@ -37,6 +37,8 @@ RenderObjectLayer::RenderObjectLayer()
renderObjects[i] = 0;
objectCount = 0;
firstFreeIdx = 0;
preRender = NULL;
postRender = NULL;
}
RenderObjectLayer::~RenderObjectLayer()
@ -251,8 +253,10 @@ void RenderObjectLayer::render(const RenderState& rs) const
{
assert(rs.pass == RenderObject::RENDER_ALL);
const RenderObject * const * rlist = &toRender[0]; // known to have at least one element
while(const RenderObject *ro = *rlist++)
const RenderObject *ro = *rlist++;
do
ro->render(rs);
while( (ro = *rlist++) );
proc += toRender.size() - 1;
}
else

View file

@ -81,11 +81,12 @@ void ScreenTransition::reloadDevice()
void ScreenTransition::capture()
{
assert(screen_texture);
core->render();
core->renderExternal();
if (screen_texture)
{
glBindTexture(GL_TEXTURE_2D,screen_texture);
glReadBuffer(GL_BACK);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, windowWidth, windowHeight);
glBindTexture(GL_TEXTURE_2D, 0);
}