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.

This commit is contained in:
Alex Szpakowski
2015-11-30 02:22:20 -04:00
parent 2c4e713114
commit 4c82c96369
9 changed files with 43 additions and 32 deletions
+1
View File
@@ -182,6 +182,7 @@ StringMap<Graphics::LineJoin, Graphics::LINE_JOIN_MAX_ENUM> Graphics::lineJoins(
StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM>::Entry Graphics::supportEntries[] = StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM>::Entry Graphics::supportEntries[] =
{ {
{ "multicanvasformats", SUPPORT_MULTI_CANVAS_FORMATS }, { "multicanvasformats", SUPPORT_MULTI_CANVAS_FORMATS },
{ "clampzero", SUPPORT_CLAMP_ZERO },
}; };
StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM> Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries)); StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM> Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries));
+1
View File
@@ -99,6 +99,7 @@ public:
enum Support enum Support
{ {
SUPPORT_MULTI_CANVAS_FORMATS, SUPPORT_MULTI_CANVAS_FORMATS,
SUPPORT_CLAMP_ZERO,
SUPPORT_MAX_ENUM SUPPORT_MAX_ENUM
}; };
+7 -6
View File
@@ -114,18 +114,19 @@ bool Texture::getConstant(WrapMode in, const char *&out)
StringMap<Texture::FilterMode, Texture::FILTER_MAX_ENUM>::Entry Texture::filterModeEntries[] = StringMap<Texture::FilterMode, Texture::FILTER_MAX_ENUM>::Entry Texture::filterModeEntries[] =
{ {
{ "linear", Texture::FILTER_LINEAR }, { "linear", FILTER_LINEAR },
{ "nearest", Texture::FILTER_NEAREST }, { "nearest", FILTER_NEAREST },
{ "none", Texture::FILTER_NONE }, { "none", FILTER_NONE },
}; };
StringMap<Texture::FilterMode, Texture::FILTER_MAX_ENUM> Texture::filterModes(Texture::filterModeEntries, sizeof(Texture::filterModeEntries)); StringMap<Texture::FilterMode, Texture::FILTER_MAX_ENUM> Texture::filterModes(Texture::filterModeEntries, sizeof(Texture::filterModeEntries));
StringMap<Texture::WrapMode, Texture::WRAP_MAX_ENUM>::Entry Texture::wrapModeEntries[] = StringMap<Texture::WrapMode, Texture::WRAP_MAX_ENUM>::Entry Texture::wrapModeEntries[] =
{ {
{ "clamp", Texture::WRAP_CLAMP }, { "clamp", WRAP_CLAMP },
{ "repeat", Texture::WRAP_REPEAT }, { "clampzero", WRAP_CLAMP_ZERO },
{ "mirroredrepeat", Texture::WRAP_MIRRORED_REPEAT }, { "repeat", WRAP_REPEAT },
{ "mirroredrepeat", WRAP_MIRRORED_REPEAT },
}; };
StringMap<Texture::WrapMode, Texture::WRAP_MAX_ENUM> Texture::wrapModes(Texture::wrapModeEntries, sizeof(Texture::wrapModeEntries)); StringMap<Texture::WrapMode, Texture::WRAP_MAX_ENUM> Texture::wrapModes(Texture::wrapModeEntries, sizeof(Texture::wrapModeEntries));
+1
View File
@@ -43,6 +43,7 @@ public:
enum WrapMode enum WrapMode
{ {
WRAP_CLAMP, WRAP_CLAMP,
WRAP_CLAMP_ZERO,
WRAP_REPEAT, WRAP_REPEAT,
WRAP_MIRRORED_REPEAT, WRAP_MIRRORED_REPEAT,
WRAP_MAX_ENUM WRAP_MAX_ENUM
+1 -10
View File
@@ -407,9 +407,6 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
if (canvases.size() > 0) 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()) if ((int) canvases.size() + 1 > gl.getMaxRenderTargets())
throw love::Exception("This system can't simultaneously render to %d canvases.", canvases.size()+1); 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; 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() 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}; bool Canvas::supportedFormats[] = {false};
-1
View File
@@ -118,7 +118,6 @@ public:
} }
static bool isSupported(); static bool isSupported();
static bool isMultiCanvasSupported();
static bool isMultiFormatMultiCanvasSupported(); static bool isMultiFormatMultiCanvasSupported();
static bool isFormatSupported(Format format); static bool isFormatSupported(Format format);
+2
View File
@@ -1491,6 +1491,8 @@ bool Graphics::isSupported(Support feature) const
{ {
case SUPPORT_MULTI_CANVAS_FORMATS: case SUPPORT_MULTI_CANVAS_FORMATS:
return Canvas::isMultiFormatMultiCanvasSupported(); return Canvas::isMultiFormatMultiCanvasSupported();
case SUPPORT_CLAMP_ZERO:
return gl.isClampZeroTextureWrapSupported();
default: default:
return false; return false;
} }
+26 -15
View File
@@ -602,24 +602,35 @@ void OpenGL::setTextureFilter(graphics::Texture::Filter &f)
f.anisotropy = 1.0f; f.anisotropy = 1.0f;
} }
GLint OpenGL::getGLWrapMode(Texture::WrapMode wmode)
{
if (wmode == Texture::WRAP_CLAMP_ZERO && !isClampZeroTextureWrapSupported())
wmode = Texture::WRAP_CLAMP;
switch (wmode)
{
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;
}
}
void OpenGL::setTextureWrap(const graphics::Texture::Wrap &w) void OpenGL::setTextureWrap(const graphics::Texture::Wrap &w)
{ {
auto glWrapMode = [](Texture::WrapMode wmode) -> GLint glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, getGLWrapMode(w.s));
{ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, getGLWrapMode(w.t));
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;
}
};
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, glWrapMode(w.s)); bool OpenGL::isClampZeroTextureWrapSupported() const
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, glWrapMode(w.t)); {
return GLAD_VERSION_1_3 || GLAD_EXT_texture_border_clamp || GLAD_NV_texture_border_clamp;
} }
int OpenGL::getMaxTextureSize() const int OpenGL::getMaxTextureSize() const
+4
View File
@@ -312,6 +312,8 @@ public:
**/ **/
void setTextureWrap(const graphics::Texture::Wrap &w); void setTextureWrap(const graphics::Texture::Wrap &w);
bool isClampZeroTextureWrapSupported() const;
/** /**
* Returns the maximum supported width or height of a texture. * Returns the maximum supported width or height of a texture.
**/ **/
@@ -354,6 +356,8 @@ private:
void initMatrices(); void initMatrices();
void createDefaultTexture(); void createDefaultTexture();
GLint getGLWrapMode(Texture::WrapMode wmode);
bool contextInitialized; bool contextInitialized;
float maxAnisotropy; float maxAnisotropy;