From 6c5daab312d7724e3584cf1b8c1776edc2394a93 Mon Sep 17 00:00:00 2001 From: Alex Szpakowski Date: Mon, 25 Mar 2013 21:23:09 -0300 Subject: [PATCH] Fixed up the API: setCanvas (singular) now only takes one canvas, setCanvases must be used for multi-canvas rendering --HG-- branch : MRTs --- src/modules/graphics/opengl/Canvas.cpp | 48 ++++++++++++++++--- src/modules/graphics/opengl/Canvas.h | 3 +- src/modules/graphics/opengl/wrap_Canvas.cpp | 3 +- src/modules/graphics/opengl/wrap_Graphics.cpp | 30 +++++++++++- src/modules/graphics/opengl/wrap_Graphics.h | 1 + 5 files changed, 74 insertions(+), 11 deletions(-) diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index b19947b4b..a8e283635 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -60,11 +60,14 @@ struct FramebufferStrategy virtual void deleteFBO(GLuint, GLuint, GLuint) {} virtual void bindFBO(GLuint) {} - /// attach additional canvases to this framebuffer for rendering + /// attach additional canvases to the active framebuffer for rendering /** * @param[in] canvases List of canvases to attach **/ virtual void setAttachments(const std::vector &canvases) {} + + /// stop using all additional attached canvases + virtual void setAttachments() {} }; struct FramebufferStrategyGL3 : public FramebufferStrategy @@ -134,12 +137,17 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy glBindFramebuffer(GL_FRAMEBUFFER, framebuffer); } + virtual void setAttachments() + { + // set a single render target + glDrawBuffer(GL_COLOR_ATTACHMENT0); + } + virtual void setAttachments(const std::vector &canvases) { if (canvases.size() == 0) { - // set a single render target - glDrawBuffer(GL_COLOR_ATTACHMENT0); + setAttachments(); return; } @@ -232,12 +240,17 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer); } + virtual void setAttachments() + { + // set a single render target + glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + } + virtual void setAttachments(const std::vector &canvases) { if (canvases.size() == 0) { - // set a single render target - glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT); + setAttachments(); return; } @@ -431,7 +444,7 @@ void Canvas::bindDefaultCanvas() current->stopGrab(); } -void Canvas::startGrab() +void Canvas::setupGrab() { // already grabbing if (current == this) @@ -476,14 +489,18 @@ void Canvas::startGrab(const std::vector &canvases) { if (canvases[i]->getWidth() != width || canvases[i]->getHeight() != height) throw love::Exception("All canvas arguments must have the same dimensions."); + + if (canvases[i]->getTextureType() != texture_type) + throw love::Exception("All canvas arguments must have the same texture type."); } - startGrab(); + setupGrab(); // don't attach anything if there's nothing to attach/detach if (canvases.size() == 0 && attachedCanvases.size() == 0) return; + // attach the canvas textures to this FBO and set up multiple render targets strategy->setAttachments(canvases); // retain newly attached canvases @@ -497,6 +514,23 @@ void Canvas::startGrab(const std::vector &canvases) attachedCanvases = canvases; } +void Canvas::startGrab() +{ + setupGrab(); + + if (attachedCanvases.size() == 0) + return; + + // make sure the FBO is only using a single render target + strategy->setAttachments(); + + // release any previously attached canvases + for (size_t i = 0; i < attachedCanvases.size(); i++) + attachedCanvases[i]->release(); + + attachedCanvases.clear(); +} + void Canvas::stopGrab() { // i am not grabbing. leave me alone diff --git a/src/modules/graphics/opengl/Canvas.h b/src/modules/graphics/opengl/Canvas.h index 832df4185..44a63a962 100644 --- a/src/modules/graphics/opengl/Canvas.h +++ b/src/modules/graphics/opengl/Canvas.h @@ -59,6 +59,7 @@ public: * to allow drawing to multiple canvases at once. **/ void startGrab(const std::vector &canvases); + void startGrab(); void stopGrab(); void clear(const Color &c); @@ -135,7 +136,7 @@ private: std::vector attachedCanvases; - void startGrab(); + void setupGrab(); void drawv(const Matrix &t, const vertex *v) const; static StringMap::Entry textureTypeEntries[]; diff --git a/src/modules/graphics/opengl/wrap_Canvas.cpp b/src/modules/graphics/opengl/wrap_Canvas.cpp index aef511e52..991dc8b66 100644 --- a/src/modules/graphics/opengl/wrap_Canvas.cpp +++ b/src/modules/graphics/opengl/wrap_Canvas.cpp @@ -47,10 +47,9 @@ int w_Canvas_renderTo(lua_State *L) if (!lua_isfunction(L, 2)) return luaL_error(L, "Need a function to render to canvas."); - static std::vector attachments; try { - canvas->startGrab(attachments); + canvas->startGrab(); } catch (love::Exception &e) { diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index e8edcee47..a69407354 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -942,6 +942,34 @@ int w_setCanvas(lua_State *L) return 0; } + Canvas *canvas = luax_checkcanvas(L, 1); + + try + { + // this unbinds the previous fbo + canvas->startGrab(); + } + catch (love::Exception &e) + { + return luaL_error(L, "%s", e.what()); + } + + return 0; +} + +int w_setCanvases(lua_State *L) +{ + // discard stencil testing + instance->discardStencil(); + + // called with none -> reset to default buffer + // nil is an error, to help people with typoes + if (lua_isnone(L,1)) + { + Canvas::bindDefaultCanvas(); + return 0; + } + bool is_table = lua_istable(L, 1); std::vector attachments; @@ -1474,7 +1502,7 @@ static const luaL_Reg functions[] = { "getMaxPointSize", w_getMaxPointSize }, { "newScreenshot", w_newScreenshot }, { "setCanvas", w_setCanvas }, - { "setCanvases", w_setCanvas }, + { "setCanvases", w_setCanvases }, { "getCanvas", w_getCanvas }, { "getCanvases", w_getCanvas }, diff --git a/src/modules/graphics/opengl/wrap_Graphics.h b/src/modules/graphics/opengl/wrap_Graphics.h index 1d4dea8a3..89f7c68bb 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.h +++ b/src/modules/graphics/opengl/wrap_Graphics.h @@ -90,6 +90,7 @@ int w_getPointStyle(lua_State *L); int w_getMaxPointSize(lua_State *L); int w_newScreenshot(lua_State *L); int w_setCanvas(lua_State *L); +int w_setCanvases(lua_State *L); int w_getCanvas(lua_State *L); int w_setShader(lua_State *L); int w_getShader(lua_State *L);