Browse Source

Added a new texture wrap mode "clampzero", which outputs transparent black (or opaque black for textures without an alpha channel) rather than the texture's edge colors, when it's drawn or sampled from outside of its regular texture coordinate range.

Alex Szpakowski 9 years ago
parent
commit
4c82c96369

+ 1 - 0
src/modules/graphics/Graphics.cpp

@@ -182,6 +182,7 @@ StringMap<Graphics::LineJoin, Graphics::LINE_JOIN_MAX_ENUM> Graphics::lineJoins(
 StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM>::Entry Graphics::supportEntries[] =
 {
 	{ "multicanvasformats", SUPPORT_MULTI_CANVAS_FORMATS },
+	{ "clampzero", SUPPORT_CLAMP_ZERO },
 };
 
 StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM> Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries));

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

@@ -99,6 +99,7 @@ public:
 	enum Support
 	{
 		SUPPORT_MULTI_CANVAS_FORMATS,
+		SUPPORT_CLAMP_ZERO,
 		SUPPORT_MAX_ENUM
 	};
 

+ 7 - 6
src/modules/graphics/Texture.cpp

@@ -114,18 +114,19 @@ bool Texture::getConstant(WrapMode in, const char  *&out)
 
 StringMap<Texture::FilterMode, Texture::FILTER_MAX_ENUM>::Entry Texture::filterModeEntries[] =
 {
-	{ "linear", Texture::FILTER_LINEAR },
-	{ "nearest", Texture::FILTER_NEAREST },
-	{ "none", Texture::FILTER_NONE },
+	{ "linear", FILTER_LINEAR },
+	{ "nearest", FILTER_NEAREST },
+	{ "none", FILTER_NONE },
 };
 
 StringMap<Texture::FilterMode, Texture::FILTER_MAX_ENUM> Texture::filterModes(Texture::filterModeEntries, sizeof(Texture::filterModeEntries));
 
 StringMap<Texture::WrapMode, Texture::WRAP_MAX_ENUM>::Entry Texture::wrapModeEntries[] =
 {
-	{ "clamp", Texture::WRAP_CLAMP },
-	{ "repeat", Texture::WRAP_REPEAT },
-	{ "mirroredrepeat", Texture::WRAP_MIRRORED_REPEAT },
+	{ "clamp", WRAP_CLAMP },
+	{ "clampzero", WRAP_CLAMP_ZERO },
+	{ "repeat", WRAP_REPEAT },
+	{ "mirroredrepeat", WRAP_MIRRORED_REPEAT },
 };
 
 StringMap<Texture::WrapMode, Texture::WRAP_MAX_ENUM> Texture::wrapModes(Texture::wrapModeEntries, sizeof(Texture::wrapModeEntries));

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

@@ -43,6 +43,7 @@ public:
 	enum WrapMode
 	{
 		WRAP_CLAMP,
+		WRAP_CLAMP_ZERO,
 		WRAP_REPEAT,
 		WRAP_MIRRORED_REPEAT,
 		WRAP_MAX_ENUM

+ 1 - 10
src/modules/graphics/opengl/Canvas.cpp

@@ -407,9 +407,6 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
 
 	if (canvases.size() > 0)
 	{
-		if (!isMultiCanvasSupported())
-			throw love::Exception("Multi-canvas rendering is not supported on this system.");
-
 		if ((int) canvases.size() + 1 > gl.getMaxRenderTargets())
 			throw love::Exception("This system can't simultaneously render to %d canvases.", canvases.size()+1);
 
@@ -804,15 +801,9 @@ bool Canvas::isSupported()
 	return GLAD_ES_VERSION_2_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object || GLAD_EXT_framebuffer_object;
 }
 
-bool Canvas::isMultiCanvasSupported()
-{
-	// system must support at least 4 simultaneous active canvases.
-	return gl.getMaxRenderTargets() >= 4;
-}
-
 bool Canvas::isMultiFormatMultiCanvasSupported()
 {
-	return isMultiCanvasSupported() && (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object);
+	return gl.getMaxRenderTargets() > 1 && (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object);
 }
 
 bool Canvas::supportedFormats[] = {false};

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

@@ -118,7 +118,6 @@ public:
 	}
 
 	static bool isSupported();
-	static bool isMultiCanvasSupported();
 	static bool isMultiFormatMultiCanvasSupported();
 	static bool isFormatSupported(Format format);
 

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

@@ -1491,6 +1491,8 @@ bool Graphics::isSupported(Support feature) const
 	{
 	case SUPPORT_MULTI_CANVAS_FORMATS:
 		return Canvas::isMultiFormatMultiCanvasSupported();
+	case SUPPORT_CLAMP_ZERO:
+		return gl.isClampZeroTextureWrapSupported();
 	default:
 		return false;
 	}

+ 26 - 15
src/modules/graphics/opengl/OpenGL.cpp

@@ -602,24 +602,35 @@ void OpenGL::setTextureFilter(graphics::Texture::Filter &f)
 		f.anisotropy = 1.0f;
 }
 
-void OpenGL::setTextureWrap(const graphics::Texture::Wrap &w)
+GLint OpenGL::getGLWrapMode(Texture::WrapMode wmode)
 {
-	auto glWrapMode = [](Texture::WrapMode wmode) -> GLint
+	if (wmode == Texture::WRAP_CLAMP_ZERO && !isClampZeroTextureWrapSupported())
+		wmode = Texture::WRAP_CLAMP;
+
+	switch (wmode)
 	{
-		switch (wmode)
-		{
-		case Texture::WRAP_CLAMP:
-		default:
-			return GL_CLAMP_TO_EDGE;
-		case Texture::WRAP_REPEAT:
-			return GL_REPEAT;
-		case Texture::WRAP_MIRRORED_REPEAT:
-			return GL_MIRRORED_REPEAT;
-		}
-	};
+	case Texture::WRAP_CLAMP:
+	default:
+		return GL_CLAMP_TO_EDGE;
+	case Texture::WRAP_CLAMP_ZERO:
+		return GL_CLAMP_TO_BORDER;
+	case Texture::WRAP_REPEAT:
+		return GL_REPEAT;
+	case Texture::WRAP_MIRRORED_REPEAT:
+		return GL_MIRRORED_REPEAT;
+	}
 
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapMode(w.s));
-	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapMode(w.t));
+}
+
+void OpenGL::setTextureWrap(const graphics::Texture::Wrap &w)
+{
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, getGLWrapMode(w.s));
+	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, getGLWrapMode(w.t));
+}
+
+bool OpenGL::isClampZeroTextureWrapSupported() const
+{
+	return GLAD_VERSION_1_3 || GLAD_EXT_texture_border_clamp || GLAD_NV_texture_border_clamp;
 }
 
 int OpenGL::getMaxTextureSize() const

+ 4 - 0
src/modules/graphics/opengl/OpenGL.h

@@ -312,6 +312,8 @@ public:
 	 **/
 	void setTextureWrap(const graphics::Texture::Wrap &w);
 
+	bool isClampZeroTextureWrapSupported() const;
+
 	/**
 	 * Returns the maximum supported width or height of a texture.
 	 **/
@@ -354,6 +356,8 @@ private:
 	void initMatrices();
 	void createDefaultTexture();
 
+	GLint getGLWrapMode(Texture::WrapMode wmode);
+
 	bool contextInitialized;
 
 	float maxAnisotropy;