瀏覽代碼

Fixed up the API: setCanvas (singular) now only takes one canvas, setCanvases must be used for multi-canvas rendering

--HG--
branch : MRTs
Alex Szpakowski 12 年之前
父節點
當前提交
6c5daab312

+ 41 - 7
src/modules/graphics/opengl/Canvas.cpp

@@ -60,11 +60,14 @@ struct FramebufferStrategy
 	virtual void deleteFBO(GLuint, GLuint, GLuint) {}
 	virtual void deleteFBO(GLuint, GLuint, GLuint) {}
 	virtual void bindFBO(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
 	 * @param[in] canvases List of canvases to attach
 	 **/
 	 **/
 	virtual void setAttachments(const std::vector<Canvas *> &canvases) {}
 	virtual void setAttachments(const std::vector<Canvas *> &canvases) {}
+
+	/// stop using all additional attached canvases
+	virtual void setAttachments() {}
 };
 };
 
 
 struct FramebufferStrategyGL3 : public FramebufferStrategy
 struct FramebufferStrategyGL3 : public FramebufferStrategy
@@ -134,12 +137,17 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy
 		glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
 		glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
 	}
 	}
 
 
+	virtual void setAttachments()
+	{
+		// set a single render target
+		glDrawBuffer(GL_COLOR_ATTACHMENT0);
+	}
+
 	virtual void setAttachments(const std::vector<Canvas *> &canvases)
 	virtual void setAttachments(const std::vector<Canvas *> &canvases)
 	{
 	{
 		if (canvases.size() == 0)
 		if (canvases.size() == 0)
 		{
 		{
-			// set a single render target
-			glDrawBuffer(GL_COLOR_ATTACHMENT0);
+			setAttachments();
 			return;
 			return;
 		}
 		}
 
 
@@ -232,12 +240,17 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy
 		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer);
 		glBindFramebufferEXT(GL_FRAMEBUFFER_EXT, framebuffer);
 	}
 	}
 
 
+	virtual void setAttachments()
+	{
+		// set a single render target
+		glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+	}
+
 	virtual void setAttachments(const std::vector<Canvas *> &canvases)
 	virtual void setAttachments(const std::vector<Canvas *> &canvases)
 	{
 	{
 		if (canvases.size() == 0)
 		if (canvases.size() == 0)
 		{
 		{
-			// set a single render target
-			glDrawBuffer(GL_COLOR_ATTACHMENT0_EXT);
+			setAttachments();
 			return;
 			return;
 		}
 		}
 
 
@@ -431,7 +444,7 @@ void Canvas::bindDefaultCanvas()
 		current->stopGrab();
 		current->stopGrab();
 }
 }
 
 
-void Canvas::startGrab()
+void Canvas::setupGrab()
 {
 {
 	// already grabbing
 	// already grabbing
 	if (current == this)
 	if (current == this)
@@ -476,14 +489,18 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
 	{
 	{
 		if (canvases[i]->getWidth() != width || canvases[i]->getHeight() != height)
 		if (canvases[i]->getWidth() != width || canvases[i]->getHeight() != height)
 			throw love::Exception("All canvas arguments must have the same dimensions.");
 			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
 	// don't attach anything if there's nothing to attach/detach
 	if (canvases.size() == 0 && attachedCanvases.size() == 0)
 	if (canvases.size() == 0 && attachedCanvases.size() == 0)
 		return;
 		return;
 
 
+	// attach the canvas textures to this FBO and set up multiple render targets
 	strategy->setAttachments(canvases);
 	strategy->setAttachments(canvases);
 
 
 	// retain newly attached canvases
 	// retain newly attached canvases
@@ -497,6 +514,23 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
 	attachedCanvases = 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()
 void Canvas::stopGrab()
 {
 {
 	// i am not grabbing. leave me alone
 	// i am not grabbing. leave me alone

+ 2 - 1
src/modules/graphics/opengl/Canvas.h

@@ -59,6 +59,7 @@ public:
 	 * to allow drawing to multiple canvases at once.
 	 * to allow drawing to multiple canvases at once.
 	 **/
 	 **/
 	void startGrab(const std::vector<Canvas *> &canvases);
 	void startGrab(const std::vector<Canvas *> &canvases);
+	void startGrab();
 	void stopGrab();
 	void stopGrab();
 
 
 	void clear(const Color &c);
 	void clear(const Color &c);
@@ -135,7 +136,7 @@ private:
 
 
 	std::vector<Canvas *> attachedCanvases;
 	std::vector<Canvas *> attachedCanvases;
 
 
-	void startGrab();
+	void setupGrab();
 	void drawv(const Matrix &t, const vertex *v) const;
 	void drawv(const Matrix &t, const vertex *v) const;
 
 
 	static StringMap<TextureType, TYPE_MAX_ENUM>::Entry textureTypeEntries[];
 	static StringMap<TextureType, TYPE_MAX_ENUM>::Entry textureTypeEntries[];

+ 1 - 2
src/modules/graphics/opengl/wrap_Canvas.cpp

@@ -47,10 +47,9 @@ int w_Canvas_renderTo(lua_State *L)
 	if (!lua_isfunction(L, 2))
 	if (!lua_isfunction(L, 2))
 		return luaL_error(L, "Need a function to render to canvas.");
 		return luaL_error(L, "Need a function to render to canvas.");
 
 
-	static std::vector<Canvas *> attachments;
 	try
 	try
 	{
 	{
-		canvas->startGrab(attachments);
+		canvas->startGrab();
 	}
 	}
 	catch (love::Exception &e)
 	catch (love::Exception &e)
 	{
 	{

+ 29 - 1
src/modules/graphics/opengl/wrap_Graphics.cpp

@@ -942,6 +942,34 @@ int w_setCanvas(lua_State *L)
 		return 0;
 		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);
 	bool is_table = lua_istable(L, 1);
 	std::vector<Canvas *> attachments;
 	std::vector<Canvas *> attachments;
 
 
@@ -1474,7 +1502,7 @@ static const luaL_Reg functions[] =
 	{ "getMaxPointSize", w_getMaxPointSize },
 	{ "getMaxPointSize", w_getMaxPointSize },
 	{ "newScreenshot", w_newScreenshot },
 	{ "newScreenshot", w_newScreenshot },
 	{ "setCanvas", w_setCanvas },
 	{ "setCanvas", w_setCanvas },
-	{ "setCanvases", w_setCanvas },
+	{ "setCanvases", w_setCanvases },
 	{ "getCanvas", w_getCanvas },
 	{ "getCanvas", w_getCanvas },
 	{ "getCanvases", w_getCanvas },
 	{ "getCanvases", w_getCanvas },
 
 

+ 1 - 0
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_getMaxPointSize(lua_State *L);
 int w_newScreenshot(lua_State *L);
 int w_newScreenshot(lua_State *L);
 int w_setCanvas(lua_State *L);
 int w_setCanvas(lua_State *L);
+int w_setCanvases(lua_State *L);
 int w_getCanvas(lua_State *L);
 int w_getCanvas(lua_State *L);
 int w_setShader(lua_State *L);
 int w_setShader(lua_State *L);
 int w_getShader(lua_State *L);
 int w_getShader(lua_State *L);