Browse Source

Improve the error message when an invalid layer or face index is given in love.graphics.setMode.

Alex Szpakowski 7 years ago
parent
commit
39201af79f

+ 30 - 5
src/modules/graphics/Graphics.cpp

@@ -578,7 +578,10 @@ void Graphics::setCanvas(const RenderTargets &rts)
 	DisplayState &state = states.back();
 	DisplayState &state = states.back();
 	int ncanvases = (int) rts.colors.size();
 	int ncanvases = (int) rts.colors.size();
 
 
-	if (ncanvases == 0 && rts.depthStencil.canvas == nullptr)
+	RenderTarget firsttarget = rts.getFirstTarget();
+	love::graphics::Canvas *firstcanvas = firsttarget.canvas;
+
+	if (firstcanvas == nullptr)
 		return setCanvas();
 		return setCanvas();
 
 
 	const auto &prevRTs = state.renderTargets;
 	const auto &prevRTs = state.renderTargets;
@@ -609,9 +612,6 @@ void Graphics::setCanvas(const RenderTargets &rts)
 	if (ncanvases > capabilities.limits[LIMIT_MULTI_CANVAS])
 	if (ncanvases > capabilities.limits[LIMIT_MULTI_CANVAS])
 		throw love::Exception("This system can't simultaneously render to %d canvases.", ncanvases);
 		throw love::Exception("This system can't simultaneously render to %d canvases.", ncanvases);
 
 
-	RenderTarget firsttarget = rts.getFirstTarget();
-	love::graphics::Canvas *firstcanvas = firsttarget.canvas;
-
 	bool multiformatsupported = capabilities.features[FEATURE_MULTI_CANVAS_FORMATS];
 	bool multiformatsupported = capabilities.features[FEATURE_MULTI_CANVAS_FORMATS];
 
 
 	PixelFormat firstcolorformat = PIXELFORMAT_UNKNOWN;
 	PixelFormat firstcolorformat = PIXELFORMAT_UNKNOWN;
@@ -624,6 +624,9 @@ void Graphics::setCanvas(const RenderTargets &rts)
 	if (firsttarget.mipmap < 0 || firsttarget.mipmap >= firstcanvas->getMipmapCount())
 	if (firsttarget.mipmap < 0 || firsttarget.mipmap >= firstcanvas->getMipmapCount())
 		throw love::Exception("Invalid mipmap level %d.", firsttarget.mipmap + 1);
 		throw love::Exception("Invalid mipmap level %d.", firsttarget.mipmap + 1);
 
 
+	if (!firstcanvas->isValidSlice(firsttarget.slice))
+		throw love::Exception("Invalid slice index: %d.", firsttarget.slice + 1);
+
 	bool hasSRGBcanvas = firstcolorformat == PIXELFORMAT_sRGBA8;
 	bool hasSRGBcanvas = firstcolorformat == PIXELFORMAT_sRGBA8;
 	int pixelw = firstcanvas->getPixelWidth(firsttarget.mipmap);
 	int pixelw = firstcanvas->getPixelWidth(firsttarget.mipmap);
 	int pixelh = firstcanvas->getPixelHeight(firsttarget.mipmap);
 	int pixelh = firstcanvas->getPixelHeight(firsttarget.mipmap);
@@ -633,10 +636,14 @@ void Graphics::setCanvas(const RenderTargets &rts)
 		love::graphics::Canvas *c = rts.colors[i].canvas;
 		love::graphics::Canvas *c = rts.colors[i].canvas;
 		PixelFormat format = c->getPixelFormat();
 		PixelFormat format = c->getPixelFormat();
 		int mip = rts.colors[i].mipmap;
 		int mip = rts.colors[i].mipmap;
+		int slice = rts.colors[i].slice;
 
 
 		if (mip < 0 || mip >= c->getMipmapCount())
 		if (mip < 0 || mip >= c->getMipmapCount())
 			throw love::Exception("Invalid mipmap level %d.", mip + 1);
 			throw love::Exception("Invalid mipmap level %d.", mip + 1);
 
 
+		if (!c->isValidSlice(slice))
+			throw love::Exception("Invalid slice index: %d.", slice + 1);
+
 		if (c->getPixelWidth(mip) != pixelw || c->getPixelHeight(mip) != pixelh)
 		if (c->getPixelWidth(mip) != pixelw || c->getPixelHeight(mip) != pixelh)
 			throw love::Exception("All canvases must have the same pixel dimensions.");
 			throw love::Exception("All canvases must have the same pixel dimensions.");
 
 
@@ -657,6 +664,7 @@ void Graphics::setCanvas(const RenderTargets &rts)
 	{
 	{
 		love::graphics::Canvas *c = rts.depthStencil.canvas;
 		love::graphics::Canvas *c = rts.depthStencil.canvas;
 		int mip = rts.depthStencil.mipmap;
 		int mip = rts.depthStencil.mipmap;
+		int slice = rts.depthStencil.slice;
 
 
 		if (!isPixelFormatDepthStencil(c->getPixelFormat()))
 		if (!isPixelFormatDepthStencil(c->getPixelFormat()))
 			throw love::Exception("Only depth/stencil format Canvases can be used with the 'depthstencil' field of the table passed into setCanvas.");
 			throw love::Exception("Only depth/stencil format Canvases can be used with the 'depthstencil' field of the table passed into setCanvas.");
@@ -669,6 +677,9 @@ void Graphics::setCanvas(const RenderTargets &rts)
 
 
 		if (mip < 0 || mip >= c->getMipmapCount())
 		if (mip < 0 || mip >= c->getMipmapCount())
 			throw love::Exception("Invalid mipmap level %d.", mip + 1);
 			throw love::Exception("Invalid mipmap level %d.", mip + 1);
+
+		if (!c->isValidSlice(slice))
+			throw love::Exception("Invalid slice index: %d.", slice + 1);
 	}
 	}
 
 
 	int w = firstcanvas->getWidth(firsttarget.mipmap);
 	int w = firstcanvas->getWidth(firsttarget.mipmap);
@@ -681,7 +692,7 @@ void Graphics::setCanvas(const RenderTargets &rts)
 	refs.colors.reserve(rts.colors.size());
 	refs.colors.reserve(rts.colors.size());
 
 
 	for (auto c : rts.colors)
 	for (auto c : rts.colors)
-		refs.colors.emplace_back(c.canvas, c.slice);
+		refs.colors.emplace_back(c.canvas, c.slice, c.mipmap);
 
 
 	refs.depthStencil = RenderTargetStrongRef(rts.depthStencil.canvas, rts.depthStencil.slice);
 	refs.depthStencil = RenderTargetStrongRef(rts.depthStencil.canvas, rts.depthStencil.slice);
 	refs.temporaryRTFlags = rts.temporaryRTFlags;
 	refs.temporaryRTFlags = rts.temporaryRTFlags;
@@ -691,6 +702,20 @@ void Graphics::setCanvas(const RenderTargets &rts)
 	canvasSwitchCount++;
 	canvasSwitchCount++;
 }
 }
 
 
+void Graphics::setCanvas()
+{
+	DisplayState &state = states.back();
+
+	if (state.renderTargets.colors.empty() && state.renderTargets.depthStencil.canvas == nullptr)
+		return;
+
+	flushStreamDraws();
+	setCanvasInternal(RenderTargets(), width, height, pixelWidth, pixelHeight, isGammaCorrect());
+
+	state.renderTargets = RenderTargetsStrongRef();
+	canvasSwitchCount++;
+}
+
 Graphics::RenderTargets Graphics::getCanvas() const
 Graphics::RenderTargets Graphics::getCanvas() const
 {
 {
 	const auto &curRTs = states.back().renderTargets;
 	const auto &curRTs = states.back().renderTargets;

+ 1 - 1
src/modules/graphics/Graphics.h

@@ -570,7 +570,7 @@ public:
 	void setCanvas(RenderTarget rt, uint32 temporaryRTFlags);
 	void setCanvas(RenderTarget rt, uint32 temporaryRTFlags);
 	void setCanvas(const RenderTargets &rts);
 	void setCanvas(const RenderTargets &rts);
 	void setCanvas(const RenderTargetsStrongRef &rts);
 	void setCanvas(const RenderTargetsStrongRef &rts);
-	virtual void setCanvas() = 0;
+	void setCanvas();
 
 
 	RenderTargets getCanvas() const;
 	RenderTargets getCanvas() const;
 	bool isCanvasActive() const;
 	bool isCanvasActive() const;

+ 17 - 0
src/modules/graphics/Texture.cpp

@@ -102,6 +102,23 @@ bool Texture::isReadable() const
 	return readable;
 	return readable;
 }
 }
 
 
+bool Texture::isValidSlice(int slice) const
+{
+	if (slice < 0)
+		return false;
+
+	if (texType == TEXTURE_CUBE)
+		return slice < 6;
+	else if (texType == TEXTURE_VOLUME)
+		return slice < depth;
+	else if (texType == TEXTURE_2D_ARRAY)
+		return slice < layers;
+	else if (slice > 0)
+		return false;
+
+	return true;
+}
+
 void Texture::draw(Graphics *gfx, const Matrix4 &m)
 void Texture::draw(Graphics *gfx, const Matrix4 &m)
 {
 {
 	draw(gfx, quad, m);
 	draw(gfx, quad, m);

+ 2 - 0
src/modules/graphics/Texture.h

@@ -120,6 +120,8 @@ public:
 
 
 	bool isReadable() const;
 	bool isReadable() const;
 
 
+	bool isValidSlice(int slice) const;
+
 	int getWidth(int mip = 0) const;
 	int getWidth(int mip = 0) const;
 	int getHeight(int mip = 0) const;
 	int getHeight(int mip = 0) const;
 	int getDepth(int mip = 0) const;
 	int getDepth(int mip = 0) const;

+ 22 - 46
src/modules/graphics/opengl/Graphics.cpp

@@ -475,72 +475,48 @@ void Graphics::setCanvasInternal(const RenderTargets &rts, int w, int h, int pix
 {
 {
 	const DisplayState &state = states.back();
 	const DisplayState &state = states.back();
 
 
-	OpenGL::TempDebugGroup debuggroup("setCanvas(...)");
+	OpenGL::TempDebugGroup debuggroup("setCanvas");
 
 
 	flushStreamDraws();
 	flushStreamDraws();
 	endPass();
 	endPass();
 
 
-	bindCachedFBO(rts);
+	bool iswindow = rts.getFirstTarget().canvas == nullptr;
+	vertex::Winding vertexwinding = state.winding;
 
 
-	gl.setViewport({0, 0, pixelw, pixelh});
-
-	// Flip front face winding when rendering to a canvas, since our projection
-	// matrix is flipped.
-	glFrontFace(state.winding == vertex::WINDING_CW ? GL_CCW : GL_CW);
-
-	// Re-apply the scissor if it was active, since the rectangle passed to
-	// glScissor is affected by the viewport dimensions.
-	if (state.scissor)
-		setScissor(state.scissorRect);
-
-	projectionMatrix = Matrix4::ortho(0.0, (float) w, 0.0, (float) h, -10.0f, 10.0f);
-
-	// Make sure the correct sRGB setting is used when drawing to the canvases.
-	if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
+	if (iswindow)
 	{
 	{
-		if (hasSRGBcanvas != gl.isStateEnabled(OpenGL::ENABLE_FRAMEBUFFER_SRGB))
-			gl.setEnableState(OpenGL::ENABLE_FRAMEBUFFER_SRGB, hasSRGBcanvas);
-	}
-}
-
-void Graphics::setCanvas()
-{
-	DisplayState &state = states.back();
+		gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, gl.getDefaultFBO());
 
 
-	if (state.renderTargets.colors.empty() && state.renderTargets.depthStencil.canvas == nullptr)
-		return;
+		// The projection matrix is flipped compared to rendering to a canvas, due
+		// to OpenGL considering (0,0) bottom-left instead of top-left.
+		projectionMatrix = Matrix4::ortho(0.0, (float) w, (float) h, 0.0, -10.0f, 10.0f);
+	}
+	else
+	{
+		bindCachedFBO(rts);
 
 
-	OpenGL::TempDebugGroup debuggroup("setCanvas()");
+		projectionMatrix = Matrix4::ortho(0.0, (float) w, 0.0, (float) h, -10.0f, 10.0f);
 
 
-	flushStreamDraws();
-	endPass();
-
-	// Re-apply the correct front face winding, since it may have been flipped
-	// if we were previously rendering to a canvas.
-	glFrontFace(state.winding == vertex::WINDING_CW ? GL_CW : GL_CCW);
+		// Flip front face winding when rendering to a canvas, since our
+		// projection matrix is flipped.
+		vertexwinding = vertexwinding == vertex::WINDING_CW ? vertex::WINDING_CCW : vertex::WINDING_CW;
+	}
 
 
-	state.renderTargets = RenderTargetsStrongRef();
+	glFrontFace(vertexwinding == vertex::WINDING_CW ? GL_CW : GL_CCW);
 
 
-	gl.bindFramebuffer(OpenGL::FRAMEBUFFER_ALL, gl.getDefaultFBO());
-
-	gl.setViewport({0, 0, pixelWidth, pixelHeight});
+	gl.setViewport({0, 0, pixelw, pixelh});
 
 
 	// Re-apply the scissor if it was active, since the rectangle passed to
 	// Re-apply the scissor if it was active, since the rectangle passed to
 	// glScissor is affected by the viewport dimensions.
 	// glScissor is affected by the viewport dimensions.
 	if (state.scissor)
 	if (state.scissor)
 		setScissor(state.scissorRect);
 		setScissor(state.scissorRect);
 
 
-	// The projection matrix is flipped compared to rendering to a canvas, due
-	// to OpenGL considering (0,0) bottom-left instead of top-left.
-	projectionMatrix = Matrix4::ortho(0.0, (float) width, (float) height, 0.0, -10.0f, 10.0f);
-
+	// Make sure the correct sRGB setting is used when drawing to the canvases.
 	if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
 	if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
 	{
 	{
-		if (isGammaCorrect() != gl.isStateEnabled(OpenGL::ENABLE_FRAMEBUFFER_SRGB))
-			gl.setEnableState(OpenGL::ENABLE_FRAMEBUFFER_SRGB, isGammaCorrect());
+		if (hasSRGBcanvas != gl.isStateEnabled(OpenGL::ENABLE_FRAMEBUFFER_SRGB))
+			gl.setEnableState(OpenGL::ENABLE_FRAMEBUFFER_SRGB, hasSRGBcanvas);
 	}
 	}
-
-	canvasSwitchCount++;
 }
 }
 
 
 void Graphics::endPass()
 void Graphics::endPass()

+ 0 - 2
src/modules/graphics/opengl/Graphics.h

@@ -82,8 +82,6 @@ public:
 
 
 	void setColor(Colorf c) override;
 	void setColor(Colorf c) override;
 
 
-	void setCanvas() override;
-
 	void setScissor(const Rect &rect) override;
 	void setScissor(const Rect &rect) override;
 	void setScissor() override;
 	void setScissor() override;
 
 

+ 1 - 1
src/modules/image/CompressedImageData.cpp

@@ -91,7 +91,7 @@ void *CompressedImageData::getData() const
 	return memory->data;
 	return memory->data;
 }
 }
 
 
-int CompressedImageData::getMipmapCount(int /*slice*/) const
+int CompressedImageData::getMipmapCount() const
 {
 {
 	return (int) dataImages.size();
 	return (int) dataImages.size();
 }
 }

+ 1 - 1
src/modules/image/CompressedImageData.h

@@ -61,7 +61,7 @@ public:
 	 * Gets the number of mipmaps in this Compressed Image Data.
 	 * Gets the number of mipmaps in this Compressed Image Data.
 	 * Includes the base image level.
 	 * Includes the base image level.
 	 **/
 	 **/
-	int getMipmapCount(int slice = 0) const;
+	int getMipmapCount() const;
 
 
 	/**
 	/**
 	 * Gets the number of slices (array layers, cube faces, 3D layers, etc.)
 	 * Gets the number of slices (array layers, cube faces, 3D layers, etc.)