From 1678252b7a4e49fca9e892500523d835d463adaa Mon Sep 17 00:00:00 2001 From: Alexander Szpakowski Date: Tue, 1 Jan 2013 21:29:38 -0400 Subject: [PATCH 01/20] =?UTF-8?q?Applied=20patch=20from=20issue=20#542=20(?= =?UTF-8?q?texture=20filtering=20inconsistencies)=20in=20main=20L=C3=96VE?= =?UTF-8?q?=20repository?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/graphics/Image.cpp | 12 ++ src/modules/graphics/Image.h | 7 + src/modules/graphics/opengl/Canvas.cpp | 49 ++---- src/modules/graphics/opengl/Font.cpp | 31 +++- src/modules/graphics/opengl/Font.h | 5 +- src/modules/graphics/opengl/Graphics.cpp | 10 +- src/modules/graphics/opengl/Image.cpp | 139 +----------------- src/modules/graphics/opengl/Image.h | 9 +- src/modules/graphics/opengl/OpenGL.cpp | 127 ++++++++++++++++ src/modules/graphics/opengl/OpenGL.h | 23 +++ src/modules/graphics/opengl/wrap_Canvas.cpp | 47 ++++-- src/modules/graphics/opengl/wrap_Font.cpp | 41 ++++++ src/modules/graphics/opengl/wrap_Font.h | 2 + src/modules/graphics/opengl/wrap_Graphics.cpp | 3 + src/modules/graphics/opengl/wrap_Image.cpp | 14 +- 15 files changed, 315 insertions(+), 204 deletions(-) diff --git a/src/modules/graphics/Image.cpp b/src/modules/graphics/Image.cpp index fa9a105aa..1e2b093be 100644 --- a/src/modules/graphics/Image.cpp +++ b/src/modules/graphics/Image.cpp @@ -25,6 +25,8 @@ namespace love namespace graphics { +Image::Filter Image::defaultFilter; + Image::Filter::Filter() : min(FILTER_LINEAR) , mag(FILTER_LINEAR) @@ -41,6 +43,16 @@ Image::~Image() { } +void Image::setDefaultFilter(const Filter &f) +{ + defaultFilter = f; +} + +const Image::Filter &Image::getDefaultFilter() +{ + return defaultFilter; +} + bool Image::getConstant(const char *in, FilterMode &out) { return filterModes.find(in, out); diff --git a/src/modules/graphics/Image.h b/src/modules/graphics/Image.h index 5e060616c..85ef7f55d 100644 --- a/src/modules/graphics/Image.h +++ b/src/modules/graphics/Image.h @@ -64,6 +64,10 @@ public: }; virtual ~Image(); + + // The default filter. + static void setDefaultFilter(const Filter &f); + static const Filter &getDefaultFilter(); static bool getConstant(const char *in, FilterMode &out); static bool getConstant(FilterMode in, const char *&out); @@ -71,6 +75,9 @@ public: static bool getConstant(WrapMode in, const char *&out); private: + + // The default image filter + static Filter defaultFilter; static StringMap::Entry filterModeEntries[]; static StringMap filterModes; diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index 9119df4a8..b3b9fbe32 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -97,8 +97,9 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy glGenTextures(1, &img); bindTexture(img); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + setTextureFilter(Image::getDefaultFilter()); + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, format, NULL); bindTexture(0); @@ -164,8 +165,8 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy glGenTextures(1, &img); bindTexture(img); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + setTextureFilter(Image::getDefaultFilter()); glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, format, NULL); @@ -231,8 +232,9 @@ struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT glGenTextures(1, &img); bindTexture(img); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + setTextureFilter(Image::getDefaultFilter()); + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, format, NULL); bindTexture(0); @@ -311,6 +313,8 @@ Canvas::Canvas(int width, int height, TextureType texture_type) vertices[2].t = 1; vertices[3].s = 1; vertices[3].t = 0; + + settings.filter = Image::getDefaultFilter(); getStrategy(); @@ -456,51 +460,26 @@ love::image::ImageData *Canvas::getImageData(love::image::Image *image) void Canvas::setFilter(const Image::Filter &f) { - GLint gmin = (f.min == Image::FILTER_NEAREST) ? GL_NEAREST : GL_LINEAR; - GLint gmag = (f.mag == Image::FILTER_NEAREST) ? GL_NEAREST : GL_LINEAR; - bindTexture(img); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gmin); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gmag); + setTextureFilter(f); } Image::Filter Canvas::getFilter() const { - GLint gmin, gmag; - bindTexture(img); - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &gmin); - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &gmag); - - Image::Filter f; - f.min = (gmin == GL_NEAREST) ? Image::FILTER_NEAREST : Image::FILTER_LINEAR; - f.mag = (gmag == GL_NEAREST) ? Image::FILTER_NEAREST : Image::FILTER_LINEAR; - return f; + return getTextureFilter(); } void Canvas::setWrap(const Image::Wrap &w) { - GLint wrap_s = (w.s == Image::WRAP_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT; - GLint wrap_t = (w.t == Image::WRAP_CLAMP) ? GL_CLAMP_TO_EDGE : GL_REPEAT; - bindTexture(img); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t); + setTextureWrap(w); } Image::Wrap Canvas::getWrap() const { - GLint wrap_s, wrap_t; bindTexture(img); - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &wrap_s); - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, &wrap_t); - - Image::Wrap w; - w.s = (wrap_s == GL_CLAMP_TO_EDGE) ? Image::WRAP_CLAMP : Image::WRAP_REPEAT; - w.t = (wrap_t == GL_CLAMP_TO_EDGE) ? Image::WRAP_CLAMP : Image::WRAP_REPEAT; - - return w; + return getTextureWrap(); } bool Canvas::loadVolatile() diff --git a/src/modules/graphics/opengl/Font.cpp b/src/modules/graphics/opengl/Font.cpp index 2473c4661..3fd65f899 100644 --- a/src/modules/graphics/opengl/Font.cpp +++ b/src/modules/graphics/opengl/Font.cpp @@ -116,16 +116,15 @@ void Font::createTexture() GLuint t; glGenTextures(1, &t); textures.push_back(t); + bindTexture(t); + + setTextureFilter(filter); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, - (filter.mag == Image::FILTER_LINEAR) ? GL_LINEAR : GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, - (filter.min == Image::FILTER_LINEAR) ? GL_LINEAR : GL_NEAREST); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - GLint format = (type == FONT_TRUETYPE ? GL_LUMINANCE_ALPHA : GL_RGBA); + GLint format = (type == FONT_TRUETYPE ? GL_LUMINANCE_ALPHA : GL_RGBA); // try to initialize the texture, attempting smaller sizes if initialization fails bool initialized = false; @@ -493,6 +492,28 @@ float Font::getSpacing() const return mSpacing; } +void Font::setFilter(const Image::Filter &f) +{ + std::vector::const_iterator it; + for (it = textures.begin(); it != textures.end(); ++it) + { + bindTexture(*it); + setTextureFilter(f); + } +} + +Image::Filter Font::getFilter() +{ + std::vector::const_iterator it; + for (it = textures.begin(); it != textures.end(); ++it) + { + bindTexture(*it); + return getTextureFilter(); + } + + return Image::getDefaultFilter(); +} + bool Font::loadVolatile() { createTexture(); diff --git a/src/modules/graphics/opengl/Font.h b/src/modules/graphics/opengl/Font.h index c8cd4fb71..6b35b8b51 100644 --- a/src/modules/graphics/opengl/Font.h +++ b/src/modules/graphics/opengl/Font.h @@ -49,7 +49,7 @@ public: * * @param data The font data to construct from. **/ - Font(love::font::Rasterizer *r, const Image::Filter &filter = Image::Filter()); + Font(love::font::Rasterizer *r, const Image::Filter &filter = Image::getDefaultFilter()); virtual ~Font(); @@ -125,6 +125,9 @@ public: * Returns the spacing modifier. **/ float getSpacing() const; + + void setFilter(const Image::Filter &f); + Image::Filter getFilter(); // Implements Volatile. bool loadVolatile(); diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index e500d87ab..e65fe6985 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -567,11 +567,6 @@ void Graphics::setColorMode(Graphics::ColorMode mode) glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE); } -void Graphics::setDefaultImageFilter(const Image::Filter &f) -{ - Image::setDefaultFilter(f); -} - Graphics::BlendMode Graphics::getBlendMode() { GLint dst, src, equation; @@ -606,6 +601,11 @@ Graphics::ColorMode Graphics::getColorMode() return COLOR_REPLACE; } +void Graphics::setDefaultImageFilter(const Image::Filter &f) +{ + Image::setDefaultFilter(f); +} + const Image::Filter &Graphics::getDefaultImageFilter() const { return Image::getDefaultFilter(); diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index 79646b785..e659bf8c5 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -33,8 +33,6 @@ namespace graphics namespace opengl { -Image::Filter Image::defaultFilter; - Image::Image(love::image::ImageData *data) : width((float)(data->getWidth())) , height((float)(data->getHeight())) @@ -63,7 +61,7 @@ Image::Image(love::image::ImageData *data) vertices[3].s = 1; vertices[3].t = 0; - settings.filter = defaultFilter; + settings.filter = getDefaultFilter(); } Image::~Image() @@ -146,141 +144,26 @@ void Image::drawq(love::graphics::Quad *quad, float x, float y, float angle, flo void Image::setFilter(const Image::Filter &f) { - GLint gmin, gmag; - gmin = gmag = 0; // so that they're not used uninitialized - - switch (f.min) - { - case FILTER_LINEAR: - gmin = GL_LINEAR; - break; - case FILTER_NEAREST: - gmin = GL_NEAREST; - break; - default: - break; - } - - switch (f.mag) - { - case FILTER_LINEAR: - gmag = GL_LINEAR; - break; - case FILTER_NEAREST: - gmag = GL_NEAREST; - break; - default: - break; - } - bind(); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gmin); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gmag); + setTextureFilter(f); } Image::Filter Image::getFilter() const { bind(); - - GLint gmin, gmag; - - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &gmin); - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &gmag); - - Image::Filter f; - - switch (gmin) - { - case GL_NEAREST: - f.min = FILTER_NEAREST; - break; - case GL_LINEAR: - default: - f.min = FILTER_LINEAR; - break; - } - - switch (gmin) - { - case GL_NEAREST: - f.mag = FILTER_NEAREST; - break; - case GL_LINEAR: - default: - f.mag = FILTER_LINEAR; - break; - } - - return f; + return getTextureFilter(); } -void Image::setWrap(Image::Wrap w) +void Image::setWrap(Image::Wrap &w) { - GLint gs, gt; - - switch (w.s) - { - case WRAP_CLAMP: - gs = GL_CLAMP_TO_EDGE; - break; - case WRAP_REPEAT: - default: - gs = GL_REPEAT; - break; - } - - switch (w.t) - { - case WRAP_CLAMP: - gt = GL_CLAMP_TO_EDGE; - break; - case WRAP_REPEAT: - default: - gt = GL_REPEAT; - break; - } - bind(); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gs); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gt); + setTextureWrap(w); } Image::Wrap Image::getWrap() const { bind(); - - GLint gs, gt; - - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &gs); - glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, >); - - Wrap w; - - switch (gs) - { - case GL_CLAMP_TO_EDGE: - w.s = WRAP_CLAMP; - break; - case GL_REPEAT: - default: - w.s = WRAP_REPEAT; - break; - } - - switch (gt) - { - case GL_CLAMP_TO_EDGE: - w.t = WRAP_CLAMP; - break; - case GL_REPEAT: - default: - w.t = WRAP_REPEAT; - break; - } - - return w; + return getTextureWrap(); } void Image::bind() const @@ -417,16 +300,6 @@ bool Image::hasNpot() return GLEE_ARB_texture_non_power_of_two != 0; } -void Image::setDefaultFilter(const Image::Filter &f) -{ - defaultFilter = f; -} - -const Image::Filter &Image::getDefaultFilter() -{ - return defaultFilter; -} - } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index 463bef6ea..dd2b59f73 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -103,7 +103,7 @@ public: Image::Filter getFilter() const; - void setWrap(Image::Wrap r); + void setWrap(Image::Wrap &w); Image::Wrap getWrap() const; @@ -118,10 +118,6 @@ public: static bool hasNpot(); - // The default filter. - static void setDefaultFilter(const Image::Filter &f); - static const Image::Filter &getDefaultFilter(); - private: void drawv(const Matrix &t, const vertex *v) const; @@ -153,9 +149,6 @@ private: bool loadVolatilePOT(); bool loadVolatileNPOT(); - // The default image filter - static Image::Filter defaultFilter; - }; // Image } // opengl diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index edcdf59fa..b1292b1d7 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -52,6 +52,133 @@ void deleteTexture(GLuint texture) glDeleteTextures(1, &texture); } +void setTextureFilter(const graphics::Image::Filter &f) +{ + GLint gmin, gmag; + + switch (f.min) + { + case Image::FILTER_NEAREST: + gmin = GL_NEAREST; + break; + case Image::FILTER_LINEAR: + default: + gmin = GL_LINEAR; + break; + } + + switch (f.mag) + { + case Image::FILTER_NEAREST: + gmag = GL_NEAREST; + break; + case Image::FILTER_LINEAR: + default: + gmag = GL_LINEAR; + break; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gmin); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gmag); +} + +graphics::Image::Filter getTextureFilter() +{ + GLint gmin, gmag; + glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &gmin); + glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &gmag); + + Image::Filter f; + + switch (gmin) + { + case GL_NEAREST: + f.min = Image::FILTER_NEAREST; + break; + case GL_LINEAR: + default: + f.min = Image::FILTER_LINEAR; + break; + } + + switch (gmag) + { + case GL_NEAREST: + f.mag = Image::FILTER_NEAREST; + break; + case GL_LINEAR: + default: + f.mag = Image::FILTER_LINEAR; + break; + } + + return f; +} + +void setTextureWrap(const graphics::Image::Wrap &w) +{ + GLint gs, gt; + + switch (w.s) + { + case Image::WRAP_CLAMP: + gs = GL_CLAMP_TO_EDGE; + break; + case Image::WRAP_REPEAT: + default: + gs = GL_REPEAT; + break; + } + + switch (w.t) + { + case Image::WRAP_CLAMP: + gt = GL_CLAMP_TO_EDGE; + break; + case Image::WRAP_REPEAT: + default: + gt = GL_REPEAT; + break; + } + + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gs); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gt); +} + +graphics::Image::Wrap getTextureWrap() +{ + GLint gs, gt; + + glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &gs); + glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, >); + + Image::Wrap w; + + switch (gs) + { + case GL_CLAMP_TO_EDGE: + w.s = Image::WRAP_CLAMP; + break; + case GL_REPEAT: + default: + w.s = Image::WRAP_REPEAT; + break; + } + + switch (gt) + { + case GL_CLAMP_TO_EDGE: + w.t = Image::WRAP_CLAMP; + break; + case GL_REPEAT: + default: + w.t = Image::WRAP_REPEAT; + break; + } + + return w; +} + } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/OpenGL.h b/src/modules/graphics/opengl/OpenGL.h index 93d32d47d..23c0f1be1 100644 --- a/src/modules/graphics/opengl/OpenGL.h +++ b/src/modules/graphics/opengl/OpenGL.h @@ -22,6 +22,7 @@ #define LOVE_COMMON_OPENGL_H #include "GLee.h" +#include "graphics/Image.h" namespace love { @@ -48,6 +49,28 @@ void bindTexture(GLuint texture, bool override = false); **/ void deleteTexture(GLuint texture); +/** + * Sets the image filter mode for the currently bound texture + * @param f The image filter to set + */ +void setTextureFilter(const graphics::Image::Filter &f); + +/** + * Returns the image filter mode for the currently bound texture + */ +graphics::Image::Filter getTextureFilter(); + +/** + * Sets the image wrap mode for the currently bound texture + * @param w The wrap mode to set + */ +void setTextureWrap(const graphics::Image::Wrap &w); + +/** + * Returns the image wrap mode for the currently bound texture + */ +graphics::Image::Wrap getTextureWrap(); + } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/wrap_Canvas.cpp b/src/modules/graphics/opengl/wrap_Canvas.cpp index 3af47051c..1be14facb 100644 --- a/src/modules/graphics/opengl/wrap_Canvas.cpp +++ b/src/modules/graphics/opengl/wrap_Canvas.cpp @@ -67,17 +67,26 @@ int w_Canvas_getImageData(lua_State *L) int w_Canvas_setFilter(lua_State *L) { Canvas *canvas = luax_checkcanvas(L, 1); + + Image::FilterMode min; + Image::FilterMode mag; + const char *minstr = luaL_checkstring(L, 2); - const char *magstr = luaL_checkstring(L, 3); - + const char *magstr = luaL_optstring(L, 3, minstr); + + if (!Image::getConstant(minstr, min)) + return luaL_error(L, "Invalid filter mode: %s", minstr); + if (!Image::getConstant(magstr, mag)) + return luaL_error(L, "Invalid filter mode: %s", magstr); + Image::Filter f; - if (!Image::getConstant(minstr, f.min)) - return luaL_error(L, "Invalid min filter mode: %s", minstr); - if (!Image::getConstant(magstr, f.mag)) - return luaL_error(L, "Invalid max filter mode: %s", magstr); - + f.min = min; + f.mag = mag; + canvas->setFilter(f); + return 0; + } int w_Canvas_getFilter(lua_State *L) @@ -99,16 +108,24 @@ int w_Canvas_getFilter(lua_State *L) int w_Canvas_setWrap(lua_State *L) { Canvas *canvas = luax_checkcanvas(L, 1); - const char *wrap_s = luaL_checkstring(L, 2); - const char *wrap_t = luaL_checkstring(L, 3); - + + Image::WrapMode s; + Image::WrapMode t; + + const char *sstr = luaL_checkstring(L, 2); + const char *tstr = luaL_optstring(L, 3, sstr); + + if (!Image::getConstant(sstr, s)) + return luaL_error(L, "Invalid wrap mode: %s", sstr); + if (!Image::getConstant(tstr, t)) + return luaL_error(L, "Invalid wrap mode, %s", tstr); + Image::Wrap w; - if (!Image::getConstant(wrap_s, w.s)) - return luaL_error(L, "Invalid wrap mode: %s", wrap_s); - if (!Image::getConstant(wrap_t, w.t)) - return luaL_error(L, "Invalid wrap mode: %s", wrap_t); - + w.s = s; + w.t = t; + canvas->setWrap(w); + return 0; } diff --git a/src/modules/graphics/opengl/wrap_Font.cpp b/src/modules/graphics/opengl/wrap_Font.cpp index 21d0a0bb3..2b76a393f 100644 --- a/src/modules/graphics/opengl/wrap_Font.cpp +++ b/src/modules/graphics/opengl/wrap_Font.cpp @@ -90,6 +90,45 @@ int w_Font_getLineHeight(lua_State *L) return 1; } +int w_Font_setFilter(lua_State *L) +{ + Font *t = luax_checkfont(L, 1); + + Image::FilterMode min; + Image::FilterMode mag; + + const char *minstr = luaL_checkstring(L, 2); + const char *magstr = luaL_optstring(L, 3, minstr); + + if (!Image::getConstant(minstr, min)) + return luaL_error(L, "Invalid filter mode: %s", minstr); + if (!Image::getConstant(magstr, mag)) + return luaL_error(L, "Invalid filter mode: %s", magstr); + + Image::Filter f; + f.min = min; + f.mag = mag; + + t->setFilter(f); + + return 0; +} + +int w_Font_getFilter(lua_State *L) +{ + Font *t = luax_checkfont(L, 1); + Image::Filter f = t->getFilter(); + Image::FilterMode min = f.min; + Image::FilterMode mag = f.mag; + const char *minstr; + const char *magstr; + Image::getConstant(min, minstr); + Image::getConstant(mag, magstr); + lua_pushstring(L, minstr); + lua_pushstring(L, magstr); + return 2; +} + static const luaL_Reg functions[] = { { "getHeight", w_Font_getHeight }, @@ -97,6 +136,8 @@ static const luaL_Reg functions[] = { "getWrap", w_Font_getWrap }, { "setLineHeight", w_Font_setLineHeight }, { "getLineHeight", w_Font_getLineHeight }, + { "setFilter", w_Font_setFilter }, + { "getFilter", w_Font_getFilter }, { 0, 0 } }; diff --git a/src/modules/graphics/opengl/wrap_Font.h b/src/modules/graphics/opengl/wrap_Font.h index 452c24696..c145167b2 100644 --- a/src/modules/graphics/opengl/wrap_Font.h +++ b/src/modules/graphics/opengl/wrap_Font.h @@ -38,6 +38,8 @@ int w_Font_getWidth(lua_State *L); int w_Font_getWrap(lua_State *L); int w_Font_setLineHeight(lua_State *L); int w_Font_getLineHeight(lua_State *L); +int w_Font_setFilter(lua_State *L); +int w_Font_getFilter(lua_State *L); extern "C" int luaopen_font(lua_State *L); } // opengl diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 9d434acc8..cce9a0be5 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -601,8 +601,10 @@ int w_setDefaultImageFilter(lua_State *L) { Image::FilterMode min; Image::FilterMode mag; + const char *minstr = luaL_checkstring(L, 1); const char *magstr = luaL_optstring(L, 2, minstr); + if (!Image::getConstant(minstr, min)) return luaL_error(L, "Invalid filter mode: %s", minstr); if (!Image::getConstant(magstr, mag)) @@ -611,6 +613,7 @@ int w_setDefaultImageFilter(lua_State *L) Image::Filter f; f.min = min; f.mag = mag; + instance->setDefaultImageFilter(f); return 0; diff --git a/src/modules/graphics/opengl/wrap_Image.cpp b/src/modules/graphics/opengl/wrap_Image.cpp index af40f3add..f0f08e4e2 100644 --- a/src/modules/graphics/opengl/wrap_Image.cpp +++ b/src/modules/graphics/opengl/wrap_Image.cpp @@ -50,19 +50,24 @@ int w_Image_getHeight(lua_State *L) int w_Image_setFilter(lua_State *L) { Image *t = luax_checkimage(L, 1); - Image::Filter f; + Image::FilterMode min; Image::FilterMode mag; + const char *minstr = luaL_checkstring(L, 2); const char *magstr = luaL_optstring(L, 3, minstr); + if (!Image::getConstant(minstr, min)) return luaL_error(L, "Invalid filter mode: %s", minstr); if (!Image::getConstant(magstr, mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); + Image::Filter f; f.min = min; f.mag = mag; + t->setFilter(f); + return 0; } @@ -84,19 +89,24 @@ int w_Image_getFilter(lua_State *L) int w_Image_setWrap(lua_State *L) { Image *i = luax_checkimage(L, 1); - Image::Wrap w; + Image::WrapMode s; Image::WrapMode t; + const char *sstr = luaL_checkstring(L, 2); const char *tstr = luaL_optstring(L, 3, sstr); + if (!Image::getConstant(sstr, s)) return luaL_error(L, "Invalid wrap mode: %s", sstr); if (!Image::getConstant(tstr, t)) return luaL_error(L, "Invalid wrap mode, %s", tstr); + Image::Wrap w; w.s = s; w.t = t; + i->setWrap(w); + return 0; } From ab98b0de45f7e5e93551117b4f16e54e54c42a9c Mon Sep 17 00:00:00 2001 From: Alexander Szpakowski Date: Tue, 1 Jan 2013 21:44:27 -0400 Subject: [PATCH 02/20] Added mipmap support to Image filter struct and OpenGL texture filter helper functions --- src/modules/graphics/Image.cpp | 1 + src/modules/graphics/Image.h | 2 ++ src/modules/graphics/opengl/OpenGL.cpp | 43 +++++++++++++++++++++----- 3 files changed, 38 insertions(+), 8 deletions(-) diff --git a/src/modules/graphics/Image.cpp b/src/modules/graphics/Image.cpp index 1e2b093be..c985cd482 100644 --- a/src/modules/graphics/Image.cpp +++ b/src/modules/graphics/Image.cpp @@ -30,6 +30,7 @@ Image::Filter Image::defaultFilter; Image::Filter::Filter() : min(FILTER_LINEAR) , mag(FILTER_LINEAR) + , mipmap(FILTER_NONE) { } diff --git a/src/modules/graphics/Image.h b/src/modules/graphics/Image.h index 85ef7f55d..881ae94fc 100644 --- a/src/modules/graphics/Image.h +++ b/src/modules/graphics/Image.h @@ -46,6 +46,7 @@ public: { FILTER_LINEAR = 1, FILTER_NEAREST, + FILTER_NONE, FILTER_MAX_ENUM }; @@ -54,6 +55,7 @@ public: Filter(); FilterMode min; FilterMode mag; + FilterMode mipmap; }; struct Wrap diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index b1292b1d7..4cae16000 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -56,16 +56,27 @@ void setTextureFilter(const graphics::Image::Filter &f) { GLint gmin, gmag; - switch (f.min) + if (f.mipmap == Image::FILTER_NONE) { - case Image::FILTER_NEAREST: - gmin = GL_NEAREST; - break; - case Image::FILTER_LINEAR: - default: - gmin = GL_LINEAR; - break; + if (f.min == Image::FILTER_NEAREST) + gmin = GL_NEAREST; + else // f.min == Image::FILTER_LINEAR + gmin = GL_LINEAR; } + else + { + if (f.min == f.mipmap == Image::FILTER_NEAREST) + gmin = GL_NEAREST_MIPMAP_NEAREST; + else if (f.min == Image::FILTER_NEAREST && f.mipmap == Image::FILTER_LINEAR) + gmin = GL_NEAREST_MIPMAP_LINEAR; + else if (f.min == Image::FILTER_LINEAR && f.mipmap == Image::FILTER_NEAREST) + gmin = GL_LINEAR_MIPMAP_NEAREST; + else if (f.min == f.mipmap == Image::FILTER_LINEAR) + gmin = GL_LINEAR_MIPMAP_LINEAR; + else + gmin = GL_LINEAR; + } + switch (f.mag) { @@ -94,10 +105,26 @@ graphics::Image::Filter getTextureFilter() { case GL_NEAREST: f.min = Image::FILTER_NEAREST; + f.mipmap = Image::FILTER_NONE; + break; + case GL_NEAREST_MIPMAP_NEAREST: + f.min = f.mipmap = Image::FILTER_NEAREST; + break; + case GL_NEAREST_MIPMAP_LINEAR: + f.min = Image::FILTER_NEAREST; + f.mipmap = Image::FILTER_LINEAR; + break; + case GL_LINEAR_MIPMAP_NEAREST: + f.min = Image::FILTER_LINEAR; + f.mipmap = Image::FILTER_NEAREST; + break; + case GL_LINEAR_MIPMAP_LINEAR: + f.min = f.mipmap = Image::FILTER_LINEAR; break; case GL_LINEAR: default: f.min = Image::FILTER_LINEAR; + f.mipmap = Image::FILTER_NONE; break; } From 2739ea561ad5d3b5c0589949324891475e6f27bf Mon Sep 17 00:00:00 2001 From: Alexander Szpakowski Date: Wed, 2 Jan 2013 02:50:13 -0400 Subject: [PATCH 03/20] Initial image mipmapping implementation. Includes Image:set/getMipmapFilter and Image:set/getMipmapSharpness. setMipMapFilter requires a filter mode, or nil to disable mipmapping. Enabling mipmapping on an image that does not have power-of-two dimensions will raise an error, due to inconsistent support in older graphics chipsets --- src/modules/graphics/opengl/Image.cpp | 102 +++++++++++++++++---- src/modules/graphics/opengl/Image.h | 27 ++++-- src/modules/graphics/opengl/wrap_Image.cpp | 97 +++++++++++++++++--- src/modules/graphics/opengl/wrap_Image.h | 7 ++ 4 files changed, 196 insertions(+), 37 deletions(-) diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index e659bf8c5..723876aff 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -22,9 +22,9 @@ // STD #include // For memcpy +#include // for min/max #include -using namespace std; namespace love { @@ -37,6 +37,7 @@ Image::Image(love::image::ImageData *data) : width((float)(data->getWidth())) , height((float)(data->getHeight())) , texture(0) + , mipmapsharpness(0.0f) { data->retain(); this->data = data; @@ -61,7 +62,7 @@ Image::Image(love::image::ImageData *data) vertices[3].s = 1; vertices[3].t = 0; - settings.filter = getDefaultFilter(); + filter = getDefaultFilter(); } Image::~Image() @@ -144,26 +145,72 @@ void Image::drawq(love::graphics::Quad *quad, float x, float y, float angle, flo void Image::setFilter(const Image::Filter &f) { + filter = f; + bind(); + + if (f.mipmap == FILTER_NEAREST || f.mipmap == FILTER_LINEAR) + { + if (!hasMipmapSupport()) + throw love::Exception("Mipmaps are not supported on this system!"); + + if (width != next_p2(width) || height != next_p2(height)) + throw love::Exception("Could not generate mipmaps: image does not have power of two dimensions!"); + + GLboolean aremipmapscreated; + glGetTexParameteriv(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLint *)&aremipmapscreated); + + // generate mipmaps for this image if we haven't already + if (!aremipmapscreated) + { + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); + + if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object) + glGenerateMipmap(GL_TEXTURE_2D); + else if (GLEE_EXT_framebuffer_object) + glGenerateMipmapEXT(GL_TEXTURE_2D); + else + // modify single pixel in texture to trigger mip chain generation + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, (GLsizei)width, (GLsizei)height, GL_RGBA, GL_UNSIGNED_BYTE, getData()); + } + } + setTextureFilter(f); } -Image::Filter Image::getFilter() const +const Image::Filter &Image::getFilter() const { - bind(); - return getTextureFilter(); + return filter; } void Image::setWrap(Image::Wrap &w) { + wrap = w; + bind(); setTextureWrap(w); } -Image::Wrap Image::getWrap() const +const Image::Wrap &Image::getWrap() const { + return wrap; +} + +void Image::setMipmapSharpness(float sharpness) +{ + if (!(GLEE_VERSION_1_4 || GLEE_EXT_texture_lod_bias)) + return; + + // LOD bias has the range (-maxbias, maxbias) + mipmapsharpness = std::min(std::max(sharpness, -maxmipmapsharpness + 0.01f), maxmipmapsharpness - 0.01f); + bind(); - return getTextureWrap(); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapsharpness); +} + +float Image::getMipmapSharpness() const +{ + return mipmapsharpness; } void Image::bind() const @@ -186,6 +233,8 @@ void Image::unload() bool Image::loadVolatile() { + glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxmipmapsharpness); + if (hasNpot()) return loadVolatileNPOT(); else @@ -196,9 +245,10 @@ bool Image::loadVolatilePOT() { glGenTextures(1,(GLuint *)&texture); bindTexture(texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -221,6 +271,13 @@ bool Image::loadVolatilePOT() GL_RGBA, GL_UNSIGNED_BYTE, 0); + + if (hasMipmapSupport()) + { + // auto-generate mipmaps when texture is modified, if mipmapping is enabled + bool genmipmaps = (filter.mipmap == FILTER_LINEAR) || (filter.mipmap == FILTER_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, genmipmaps ? GL_TRUE : GL_FALSE); + } glTexSubImage2D(GL_TEXTURE_2D, 0, @@ -231,9 +288,9 @@ bool Image::loadVolatilePOT() GL_RGBA, GL_UNSIGNED_BYTE, data->getData()); - - setFilter(settings.filter); - setWrap(settings.wrap); + + setFilter(filter); + setWrap(wrap); return true; } @@ -242,11 +299,19 @@ bool Image::loadVolatileNPOT() { glGenTextures(1,(GLuint *)&texture); bindTexture(texture); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + if (hasMipmapSupport()) + { + // auto-generate mipmaps when texture is modified, if mipmapping is enabled + bool genmipmaps = (filter.mipmap == FILTER_LINEAR) || (filter.mipmap == FILTER_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, genmipmaps ? GL_TRUE : GL_FALSE); + } glTexImage2D(GL_TEXTURE_2D, 0, @@ -257,17 +322,15 @@ bool Image::loadVolatileNPOT() GL_RGBA, GL_UNSIGNED_BYTE, data->getData()); - - setFilter(settings.filter); - setWrap(settings.wrap); + + setFilter(filter); + setWrap(wrap); return true; } void Image::unloadVolatile() { - settings.filter = getFilter(); - settings.wrap = getWrap(); // Delete the hardware texture. if (texture != 0) { @@ -300,6 +363,11 @@ bool Image::hasNpot() return GLEE_ARB_texture_non_power_of_two != 0; } +bool Image::hasMipmapSupport() +{ + return (GLEE_VERSION_1_4 || GLEE_SGIS_generate_mipmap) != 0; +} + } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index dd2b59f73..9778a878b 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -101,11 +101,15 @@ public: **/ void setFilter(const Image::Filter &f); - Image::Filter getFilter() const; + const Image::Filter &getFilter() const; void setWrap(Image::Wrap &w); - Image::Wrap getWrap() const; + const Image::Wrap &getWrap() const; + + void setMipmapSharpness(float sharpness); + + float getMipmapSharpness() const; void bind() const; @@ -117,6 +121,7 @@ public: void unloadVolatile(); static bool hasNpot(); + static bool hasMipmapSupport(); private: @@ -138,13 +143,17 @@ private: // The source vertices of the image. vertex vertices[4]; - - // The settings we need to save when reloading. - struct - { - Image::Filter filter; - Image::Wrap wrap; - } settings; + + // Mipmap texture LOD bias value + float mipmapsharpness; + + float maxmipmapsharpness; + + // The image's filter mode + Image::Filter filter; + + // The image's wrap mode + Image::Wrap wrap; bool loadVolatilePOT(); bool loadVolatileNPOT(); diff --git a/src/modules/graphics/opengl/wrap_Image.cpp b/src/modules/graphics/opengl/wrap_Image.cpp index f0f08e4e2..88db24cc4 100644 --- a/src/modules/graphics/opengl/wrap_Image.cpp +++ b/src/modules/graphics/opengl/wrap_Image.cpp @@ -61,12 +61,22 @@ int w_Image_setFilter(lua_State *L) return luaL_error(L, "Invalid filter mode: %s", minstr); if (!Image::getConstant(magstr, mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); + + const Image::Filter curfilter = t->getFilter(); Image::Filter f; f.min = min; f.mag = mag; + f.mipmap = curfilter.mipmap; - t->setFilter(f); + try + { + t->setFilter(f); + } + catch(love::Exception &e) + { + return luaL_error(L, e.what()); + } return 0; } @@ -74,18 +84,61 @@ int w_Image_setFilter(lua_State *L) int w_Image_getFilter(lua_State *L) { Image *t = luax_checkimage(L, 1); - Image::Filter f = t->getFilter(); - Image::FilterMode min = f.min; - Image::FilterMode mag = f.mag; + const Image::Filter f = t->getFilter(); const char *minstr; const char *magstr; - Image::getConstant(min, minstr); - Image::getConstant(mag, magstr); + Image::getConstant(f.min, minstr); + Image::getConstant(f.mag, magstr); lua_pushstring(L, minstr); lua_pushstring(L, magstr); return 2; } +int w_Image_setMipmapFilter(lua_State *L) +{ + Image *i = luax_checkimage(L, 1); + + const Image::Filter curfilter = i->getFilter(); + Image::Filter f; + f.min = curfilter.min; + f.mag = curfilter.mag; + + if (lua_isnoneornil(L, 2)) // disable mipmapping if no arguments are given + f.mipmap = Image::FILTER_NONE; + else + { + const char *filterstr = luaL_checkstring(L, 2); + if (!Image::getConstant(filterstr, f.mipmap)) + return luaL_error(L, "Invalid filter mode: %s", filterstr); + } + + try + { + i->setFilter(f); + } + catch(love::Exception &e) + { + return luaL_error(L, e.what()); + } + + return 0; +} + +int w_Image_getMipmapFilter(lua_State *L) +{ + Image *i = luax_checkimage(L, 1); + + const Image::Filter f = i->getFilter(); + const char *filterstr; + + if (Image::getConstant(f.mipmap, filterstr)) + lua_pushstring(L, filterstr); + else + lua_pushnil(L); // return nil if mipmap filter is FILTER_NONE + + return 1; +} + int w_Image_setWrap(lua_State *L) { Image *i = luax_checkimage(L, 1); @@ -113,18 +166,36 @@ int w_Image_setWrap(lua_State *L) int w_Image_getWrap(lua_State *L) { Image *i = luax_checkimage(L, 1); - Image::Wrap w = i->getWrap(); - Image::WrapMode s = w.s; - Image::WrapMode t = w.t; + const Image::Wrap w = i->getWrap(); const char *sstr; const char *tstr; - Image::getConstant(s, sstr); - Image::getConstant(t, tstr); + Image::getConstant(w.s, sstr); + Image::getConstant(w.t, tstr); lua_pushstring(L, sstr); lua_pushstring(L, tstr); return 2; } +int w_Image_setMipmapSharpness(lua_State *L) +{ + Image *i = luax_checkimage(L, 1); + + float sharpness = (float) luaL_checknumber(L, 2); + i->setMipmapSharpness(sharpness); + + return 0; +} + +int w_Image_getMipmapSharpness(lua_State *L) +{ + Image *i = luax_checkimage(L, 1); + + float sharpness = i->getMipmapSharpness(); + lua_pushnumber(L, sharpness); + + return 1; +} + static const luaL_Reg functions[] = { { "getWidth", w_Image_getWidth }, @@ -133,6 +204,10 @@ static const luaL_Reg functions[] = { "getFilter", w_Image_getFilter }, { "setWrap", w_Image_setWrap }, { "getWrap", w_Image_getWrap }, + { "setMipmapFilter", w_Image_setMipmapFilter }, + { "getMipmapFilter", w_Image_getMipmapFilter }, + { "setMipmapSharpness", w_Image_setMipmapSharpness }, + { "getMipmapSharpness", w_Image_getMipmapSharpness }, { 0, 0 } }; diff --git a/src/modules/graphics/opengl/wrap_Image.h b/src/modules/graphics/opengl/wrap_Image.h index 80e0fe96d..f06b73ba8 100644 --- a/src/modules/graphics/opengl/wrap_Image.h +++ b/src/modules/graphics/opengl/wrap_Image.h @@ -36,6 +36,13 @@ Image *luax_checkimage(lua_State *L, int idx); int w_Image_getWidth(lua_State *L); int w_Image_getHeight(lua_State *L); int w_Image_setFilter(lua_State *L); +int w_image_getFilter(lua_State *L); +int w_Image_setWrap(lua_State *L); +int w_Image_getWrap(lua_State *L); +int w_Image_setMipmapFilter(lua_State *L); +int w_Image_getMipmapFilter(lua_State *L); +int w_Image_setMipmapSharpness(lua_State *L); +int w_Image_getMipmapSharpness(lua_State *L); extern "C" int luaopen_image(lua_State *L); } // opengl From fda16e27cdcac955c7d62041884df9a787a9e50a Mon Sep 17 00:00:00 2001 From: Alexander Szpakowski Date: Wed, 2 Jan 2013 04:21:22 -0400 Subject: [PATCH 04/20] Changed image mipmap api: Image:setFilter now takes an optional third argument (mipmap filter mode), Image:get/setMipmapFilter is removed. --- src/modules/graphics/opengl/Image.cpp | 16 ++--- src/modules/graphics/opengl/Image.h | 3 +- src/modules/graphics/opengl/wrap_Image.cpp | 82 +++++----------------- src/modules/graphics/opengl/wrap_Image.h | 2 - 4 files changed, 29 insertions(+), 74 deletions(-) diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index 723876aff..e80c52040 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -152,16 +152,16 @@ void Image::setFilter(const Image::Filter &f) if (f.mipmap == FILTER_NEAREST || f.mipmap == FILTER_LINEAR) { if (!hasMipmapSupport()) - throw love::Exception("Mipmaps are not supported on this system!"); + throw love::Exception("Mipmap filtering is not supported on this system!"); if (width != next_p2(width) || height != next_p2(height)) throw love::Exception("Could not generate mipmaps: image does not have power of two dimensions!"); - GLboolean aremipmapscreated; - glGetTexParameteriv(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLint *)&aremipmapscreated); + GLboolean mipmapscreated; + glGetTexParameteriv(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLint *)&mipmapscreated); // generate mipmaps for this image if we haven't already - if (!aremipmapscreated) + if (!mipmapscreated) { glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); @@ -170,7 +170,7 @@ void Image::setFilter(const Image::Filter &f) else if (GLEE_EXT_framebuffer_object) glGenerateMipmapEXT(GL_TEXTURE_2D); else - // modify single pixel in texture to trigger mip chain generation + // modify single pixel in texture to trigger mipmap chain generation glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, (GLsizei)width, (GLsizei)height, GL_RGBA, GL_UNSIGNED_BYTE, getData()); } } @@ -205,7 +205,7 @@ void Image::setMipmapSharpness(float sharpness) mipmapsharpness = std::min(std::max(sharpness, -maxmipmapsharpness + 0.01f), maxmipmapsharpness - 0.01f); bind(); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapsharpness); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapsharpness); // negative bias is sharper } float Image::getMipmapSharpness() const @@ -274,7 +274,7 @@ bool Image::loadVolatilePOT() if (hasMipmapSupport()) { - // auto-generate mipmaps when texture is modified, if mipmapping is enabled + // tell GL to auto-generate mipmaps when texture is modified, if mipmapping is enabled bool genmipmaps = (filter.mipmap == FILTER_LINEAR) || (filter.mipmap == FILTER_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, genmipmaps ? GL_TRUE : GL_FALSE); } @@ -308,7 +308,7 @@ bool Image::loadVolatileNPOT() if (hasMipmapSupport()) { - // auto-generate mipmaps when texture is modified, if mipmapping is enabled + // tell GL to auto-generate mipmaps when texture is modified, if mipmapping is enabled bool genmipmaps = (filter.mipmap == FILTER_LINEAR) || (filter.mipmap == FILTER_NEAREST); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, genmipmaps ? GL_TRUE : GL_FALSE); } diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index 9778a878b..d9fc83602 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -97,7 +97,7 @@ public: /** * Sets the filter mode. * - * @param mode The filter mode. + * @param f The filter mode. **/ void setFilter(const Image::Filter &f); @@ -147,6 +147,7 @@ private: // Mipmap texture LOD bias value float mipmapsharpness; + // Implementation-dependent maximum/minimum sharpness values float maxmipmapsharpness; // The image's filter mode diff --git a/src/modules/graphics/opengl/wrap_Image.cpp b/src/modules/graphics/opengl/wrap_Image.cpp index 88db24cc4..6e286fd0c 100644 --- a/src/modules/graphics/opengl/wrap_Image.cpp +++ b/src/modules/graphics/opengl/wrap_Image.cpp @@ -51,23 +51,24 @@ int w_Image_setFilter(lua_State *L) { Image *t = luax_checkimage(L, 1); - Image::FilterMode min; - Image::FilterMode mag; + Image::Filter f; const char *minstr = luaL_checkstring(L, 2); const char *magstr = luaL_optstring(L, 3, minstr); - if (!Image::getConstant(minstr, min)) + if (!Image::getConstant(minstr, f.min)) return luaL_error(L, "Invalid filter mode: %s", minstr); - if (!Image::getConstant(magstr, mag)) + if (!Image::getConstant(magstr, f.mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); - const Image::Filter curfilter = t->getFilter(); - - Image::Filter f; - f.min = min; - f.mag = mag; - f.mipmap = curfilter.mipmap; + if (lua_isnoneornil(L, 4)) + f.mipmap = Image::FILTER_NONE; // mipmapping is disabled unless third argument is given + else + { + const char *mipmapstr = luaL_checkstring(L, 4); + if (!Image::getConstant(mipmapstr, f.mipmap)) + return luaL_error(L, "Invalid filter mode: %s", mipmapstr); + } try { @@ -87,77 +88,34 @@ int w_Image_getFilter(lua_State *L) const Image::Filter f = t->getFilter(); const char *minstr; const char *magstr; + const char *mipmapstr; Image::getConstant(f.min, minstr); Image::getConstant(f.mag, magstr); lua_pushstring(L, minstr); lua_pushstring(L, magstr); - return 2; -} - -int w_Image_setMipmapFilter(lua_State *L) -{ - Image *i = luax_checkimage(L, 1); - const Image::Filter curfilter = i->getFilter(); - Image::Filter f; - f.min = curfilter.min; - f.mag = curfilter.mag; - - if (lua_isnoneornil(L, 2)) // disable mipmapping if no arguments are given - f.mipmap = Image::FILTER_NONE; + if (Image::getConstant(f.mipmap, mipmapstr)) + lua_pushstring(L, mipmapstr); else - { - const char *filterstr = luaL_checkstring(L, 2); - if (!Image::getConstant(filterstr, f.mipmap)) - return luaL_error(L, "Invalid filter mode: %s", filterstr); - } + lua_pushnil(L); // only return a mipmap filter if mipmapping is enabled - try - { - i->setFilter(f); - } - catch(love::Exception &e) - { - return luaL_error(L, e.what()); - } - - return 0; -} - -int w_Image_getMipmapFilter(lua_State *L) -{ - Image *i = luax_checkimage(L, 1); - - const Image::Filter f = i->getFilter(); - const char *filterstr; - - if (Image::getConstant(f.mipmap, filterstr)) - lua_pushstring(L, filterstr); - else - lua_pushnil(L); // return nil if mipmap filter is FILTER_NONE - - return 1; + return 3; } int w_Image_setWrap(lua_State *L) { Image *i = luax_checkimage(L, 1); - Image::WrapMode s; - Image::WrapMode t; + Image::Wrap w; const char *sstr = luaL_checkstring(L, 2); const char *tstr = luaL_optstring(L, 3, sstr); - if (!Image::getConstant(sstr, s)) + if (!Image::getConstant(sstr, w.s)) return luaL_error(L, "Invalid wrap mode: %s", sstr); - if (!Image::getConstant(tstr, t)) + if (!Image::getConstant(tstr, w.t)) return luaL_error(L, "Invalid wrap mode, %s", tstr); - Image::Wrap w; - w.s = s; - w.t = t; - i->setWrap(w); return 0; @@ -204,8 +162,6 @@ static const luaL_Reg functions[] = { "getFilter", w_Image_getFilter }, { "setWrap", w_Image_setWrap }, { "getWrap", w_Image_getWrap }, - { "setMipmapFilter", w_Image_setMipmapFilter }, - { "getMipmapFilter", w_Image_getMipmapFilter }, { "setMipmapSharpness", w_Image_setMipmapSharpness }, { "getMipmapSharpness", w_Image_getMipmapSharpness }, { 0, 0 } diff --git a/src/modules/graphics/opengl/wrap_Image.h b/src/modules/graphics/opengl/wrap_Image.h index f06b73ba8..a6c8d5d6a 100644 --- a/src/modules/graphics/opengl/wrap_Image.h +++ b/src/modules/graphics/opengl/wrap_Image.h @@ -39,8 +39,6 @@ int w_Image_setFilter(lua_State *L); int w_image_getFilter(lua_State *L); int w_Image_setWrap(lua_State *L); int w_Image_getWrap(lua_State *L); -int w_Image_setMipmapFilter(lua_State *L); -int w_Image_getMipmapFilter(lua_State *L); int w_Image_setMipmapSharpness(lua_State *L); int w_Image_getMipmapSharpness(lua_State *L); extern "C" int luaopen_image(lua_State *L); From f067e228b4679a2d0d588d8e3e1ddedaeac16bde Mon Sep 17 00:00:00 2001 From: Alexander Szpakowski Date: Wed, 2 Jan 2013 04:44:24 -0400 Subject: [PATCH 05/20] Fixed mipmap sharpness setting not being correctly reapplied on resolution change --- src/modules/graphics/opengl/Image.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index e80c52040..b42ce5c23 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -289,6 +289,7 @@ bool Image::loadVolatilePOT() GL_UNSIGNED_BYTE, data->getData()); + setMipmapSharpness(mipmapsharpness); setFilter(filter); setWrap(wrap); @@ -323,6 +324,7 @@ bool Image::loadVolatileNPOT() GL_UNSIGNED_BYTE, data->getData()); + setMipmapSharpness(mipmapsharpness); setFilter(filter); setWrap(wrap); From 2d077758d138949e328e87fc342a163a27c0da0c Mon Sep 17 00:00:00 2001 From: Alexander Szpakowski Date: Wed, 2 Jan 2013 05:29:17 -0400 Subject: [PATCH 06/20] Fixed mipmap generation for pre-FBO systems, fixed NPOT check if mipmap filtering is enabled on an image before the texture is created --- src/modules/graphics/opengl/Image.cpp | 26 ++++++++------------------ 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index b42ce5c23..4efc2b9c2 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -154,7 +154,10 @@ void Image::setFilter(const Image::Filter &f) if (!hasMipmapSupport()) throw love::Exception("Mipmap filtering is not supported on this system!"); - if (width != next_p2(width) || height != next_p2(height)) + // some old GPUs/systems claim support for NPOT textures, but fail when generating mipmaps for them + // we can't detect which systems will do this, so it's better to fail gracefully for all NPOT images + int w = int(width), h = int(height); + if (w != next_p2(w) || h != next_p2(h)) throw love::Exception("Could not generate mipmaps: image does not have power of two dimensions!"); GLboolean mipmapscreated; @@ -170,8 +173,8 @@ void Image::setFilter(const Image::Filter &f) else if (GLEE_EXT_framebuffer_object) glGenerateMipmapEXT(GL_TEXTURE_2D); else - // modify single pixel in texture to trigger mipmap chain generation - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, (GLsizei)width, (GLsizei)height, GL_RGBA, GL_UNSIGNED_BYTE, getData()); + // modify single texel in texture to trigger mipmap chain generation + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data->getData()); } } @@ -233,7 +236,8 @@ void Image::unload() bool Image::loadVolatile() { - glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxmipmapsharpness); + if (GLEE_VERSION_1_4 || GLEE_EXT_texture_lod_bias) + glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxmipmapsharpness); if (hasNpot()) return loadVolatileNPOT(); @@ -271,13 +275,6 @@ bool Image::loadVolatilePOT() GL_RGBA, GL_UNSIGNED_BYTE, 0); - - if (hasMipmapSupport()) - { - // tell GL to auto-generate mipmaps when texture is modified, if mipmapping is enabled - bool genmipmaps = (filter.mipmap == FILTER_LINEAR) || (filter.mipmap == FILTER_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, genmipmaps ? GL_TRUE : GL_FALSE); - } glTexSubImage2D(GL_TEXTURE_2D, 0, @@ -306,13 +303,6 @@ bool Image::loadVolatileNPOT() glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - - if (hasMipmapSupport()) - { - // tell GL to auto-generate mipmaps when texture is modified, if mipmapping is enabled - bool genmipmaps = (filter.mipmap == FILTER_LINEAR) || (filter.mipmap == FILTER_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, genmipmaps ? GL_TRUE : GL_FALSE); - } glTexImage2D(GL_TEXTURE_2D, 0, From 1de26ea1fac4399908c96f6f54d9ed5bdd04986e Mon Sep 17 00:00:00 2001 From: Alexander Szpakowski Date: Wed, 2 Jan 2013 05:55:50 -0400 Subject: [PATCH 07/20] Added "mipmap" love.graphics.isSupported string --- src/modules/graphics/Graphics.cpp | 1 + src/modules/graphics/Graphics.h | 1 + src/modules/graphics/opengl/wrap_Graphics.cpp | 7 ++++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index cd8403f0e..58019c017 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -160,6 +160,7 @@ StringMap::Entry Graphics::suppor { "pixeleffect", Graphics::SUPPORT_PIXELEFFECT }, { "npot", Graphics::SUPPORT_NPOT }, { "subtractive", Graphics::SUPPORT_SUBTRACTIVE }, + { "mipmap", Graphics::SUPPORT_MIPMAP }, }; StringMap Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries)); diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index ed0da81a2..4926aa90a 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -89,6 +89,7 @@ public: SUPPORT_PIXELEFFECT, SUPPORT_NPOT, SUPPORT_SUBTRACTIVE, + SUPPORT_MIPMAP, SUPPORT_MAX_ENUM }; diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index cce9a0be5..0fe1a9140 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -853,7 +853,12 @@ int w_isSupported(lua_State *L) supported = false; break; case Graphics::SUPPORT_SUBTRACTIVE: - supported = (GLEE_VERSION_1_4 || GLEE_ARB_imaging) || (GLEE_EXT_blend_minmax && GLEE_EXT_blend_subtract); + if (!((GLEE_VERSION_1_4 || GLEE_ARB_imaging) || (GLEE_EXT_blend_minmax && GLEE_EXT_blend_subtract))) + supported = false; + break; + case Graphics::SUPPORT_MIPMAP: + if (!Image::hasMipmapSupport()) + supported = false; break; default: supported = false; From 8b3fb1d71c86f0a58d382c538112b81b99bdd466 Mon Sep 17 00:00:00 2001 From: Alexander Szpakowski Date: Wed, 2 Jan 2013 17:19:41 -0400 Subject: [PATCH 08/20] Code cleanup --- src/modules/graphics/opengl/Graphics.cpp | 2 +- src/modules/graphics/opengl/Image.cpp | 76 ++++++++++++--------- src/modules/graphics/opengl/Image.h | 8 ++- src/modules/graphics/opengl/wrap_Canvas.cpp | 26 +++---- src/modules/graphics/opengl/wrap_Font.cpp | 19 ++---- src/modules/graphics/opengl/wrap_Image.cpp | 7 +- 6 files changed, 65 insertions(+), 73 deletions(-) diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index e65fe6985..ed27fdd3c 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -342,7 +342,7 @@ Image *Graphics::newImage(love::image::ImageData *data) catch(love::Exception &e) { image->release(); - throw love::Exception(e.what()); + throw; } if (!success) { diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index 4efc2b9c2..470902cd8 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -143,41 +143,46 @@ void Image::drawq(love::graphics::Quad *quad, float x, float y, float angle, flo drawv(t, v); } +void Image::checkMipmapsCreated() const +{ + if (filter.mipmap != FILTER_NEAREST && filter.mipmap != FILTER_LINEAR) + return; + + if (!hasMipmapSupport()) + throw love::Exception("Mipmap filtering is not supported on this system!"); + + // some old GPUs/systems claim support for NPOT textures, but fail when generating mipmaps + // we can't detect which systems will do this, so we fail gracefully for all NPOT images + int w = int(width), h = int(height); + if (w != next_p2(w) || h != next_p2(h)) + throw love::Exception("Could not generate mipmaps: image does not have power of two dimensions!"); + + bind(); + + GLboolean mipmapscreated; + glGetTexParameteriv(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLint *)&mipmapscreated); + + // generate mipmaps for this image if we haven't already + if (!mipmapscreated) + { + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); + + if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object) + glGenerateMipmap(GL_TEXTURE_2D); + else if (GLEE_EXT_framebuffer_object) + glGenerateMipmapEXT(GL_TEXTURE_2D); + else + // modify single texel to trigger mipmap chain generation + glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data->getData()); + } +} + void Image::setFilter(const Image::Filter &f) { filter = f; bind(); - - if (f.mipmap == FILTER_NEAREST || f.mipmap == FILTER_LINEAR) - { - if (!hasMipmapSupport()) - throw love::Exception("Mipmap filtering is not supported on this system!"); - - // some old GPUs/systems claim support for NPOT textures, but fail when generating mipmaps for them - // we can't detect which systems will do this, so it's better to fail gracefully for all NPOT images - int w = int(width), h = int(height); - if (w != next_p2(w) || h != next_p2(h)) - throw love::Exception("Could not generate mipmaps: image does not have power of two dimensions!"); - - GLboolean mipmapscreated; - glGetTexParameteriv(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLint *)&mipmapscreated); - - // generate mipmaps for this image if we haven't already - if (!mipmapscreated) - { - glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); - - if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object) - glGenerateMipmap(GL_TEXTURE_2D); - else if (GLEE_EXT_framebuffer_object) - glGenerateMipmapEXT(GL_TEXTURE_2D); - else - // modify single texel in texture to trigger mipmap chain generation - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, data->getData()); - } - } - + checkMipmapsCreated(); setTextureFilter(f); } @@ -186,7 +191,7 @@ const Image::Filter &Image::getFilter() const return filter; } -void Image::setWrap(Image::Wrap &w) +void Image::setWrap(const Image::Wrap &w) { wrap = w; @@ -201,7 +206,7 @@ const Image::Wrap &Image::getWrap() const void Image::setMipmapSharpness(float sharpness) { - if (!(GLEE_VERSION_1_4 || GLEE_EXT_texture_lod_bias)) + if (!hasMipmapSharpnessSupport()) return; // LOD bias has the range (-maxbias, maxbias) @@ -236,7 +241,7 @@ void Image::unload() bool Image::loadVolatile() { - if (GLEE_VERSION_1_4 || GLEE_EXT_texture_lod_bias) + if (hasMipmapSharpnessSupport()) glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxmipmapsharpness); if (hasNpot()) @@ -360,6 +365,11 @@ bool Image::hasMipmapSupport() return (GLEE_VERSION_1_4 || GLEE_SGIS_generate_mipmap) != 0; } +bool Image::hasMipmapSharpnessSupport() +{ + return (GLEE_VERSION_1_4 || GLEE_EXT_texture_lod_bias) != 0; +} + } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index d9fc83602..cbe2d38b3 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -96,14 +96,13 @@ public: /** * Sets the filter mode. - * * @param f The filter mode. **/ void setFilter(const Image::Filter &f); const Image::Filter &getFilter() const; - void setWrap(Image::Wrap &w); + void setWrap(const Image::Wrap &w); const Image::Wrap &getWrap() const; @@ -122,6 +121,7 @@ public: static bool hasNpot(); static bool hasMipmapSupport(); + static bool hasMipmapSharpnessSupport(); private: @@ -147,7 +147,7 @@ private: // Mipmap texture LOD bias value float mipmapsharpness; - // Implementation-dependent maximum/minimum sharpness values + // Implementation-dependent maximum/minimum mipmap sharpness values float maxmipmapsharpness; // The image's filter mode @@ -158,6 +158,8 @@ private: bool loadVolatilePOT(); bool loadVolatileNPOT(); + + void checkMipmapsCreated() const; }; // Image diff --git a/src/modules/graphics/opengl/wrap_Canvas.cpp b/src/modules/graphics/opengl/wrap_Canvas.cpp index 1be14facb..9a7853802 100644 --- a/src/modules/graphics/opengl/wrap_Canvas.cpp +++ b/src/modules/graphics/opengl/wrap_Canvas.cpp @@ -68,21 +68,16 @@ int w_Canvas_setFilter(lua_State *L) { Canvas *canvas = luax_checkcanvas(L, 1); - Image::FilterMode min; - Image::FilterMode mag; + Image::Filter f; const char *minstr = luaL_checkstring(L, 2); const char *magstr = luaL_optstring(L, 3, minstr); - if (!Image::getConstant(minstr, min)) + if (!Image::getConstant(minstr, f.min)) return luaL_error(L, "Invalid filter mode: %s", minstr); - if (!Image::getConstant(magstr, mag)) + if (!Image::getConstant(magstr, f.mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); - Image::Filter f; - f.min = min; - f.mag = mag; - canvas->setFilter(f); return 0; @@ -92,7 +87,7 @@ int w_Canvas_setFilter(lua_State *L) int w_Canvas_getFilter(lua_State *L) { Canvas *canvas = luax_checkcanvas(L, 1); - Image::Filter f = canvas->getFilter(); + const Image::Filter f = canvas->getFilter(); const char *minstr; const char *magstr; @@ -109,21 +104,16 @@ int w_Canvas_setWrap(lua_State *L) { Canvas *canvas = luax_checkcanvas(L, 1); - Image::WrapMode s; - Image::WrapMode t; + Image::Wrap w; const char *sstr = luaL_checkstring(L, 2); const char *tstr = luaL_optstring(L, 3, sstr); - if (!Image::getConstant(sstr, s)) + if (!Image::getConstant(sstr, w.s)) return luaL_error(L, "Invalid wrap mode: %s", sstr); - if (!Image::getConstant(tstr, t)) + if (!Image::getConstant(tstr, w.t)) return luaL_error(L, "Invalid wrap mode, %s", tstr); - Image::Wrap w; - w.s = s; - w.t = t; - canvas->setWrap(w); return 0; @@ -132,7 +122,7 @@ int w_Canvas_setWrap(lua_State *L) int w_Canvas_getWrap(lua_State *L) { Canvas *canvas = luax_checkcanvas(L, 1); - Image::Wrap w = canvas->getWrap(); + const Image::Wrap w = canvas->getWrap(); const char *wrap_s; const char *wrap_t; diff --git a/src/modules/graphics/opengl/wrap_Font.cpp b/src/modules/graphics/opengl/wrap_Font.cpp index 2b76a393f..5dd7021ad 100644 --- a/src/modules/graphics/opengl/wrap_Font.cpp +++ b/src/modules/graphics/opengl/wrap_Font.cpp @@ -94,21 +94,16 @@ int w_Font_setFilter(lua_State *L) { Font *t = luax_checkfont(L, 1); - Image::FilterMode min; - Image::FilterMode mag; + Image::Filter f; const char *minstr = luaL_checkstring(L, 2); const char *magstr = luaL_optstring(L, 3, minstr); - if (!Image::getConstant(minstr, min)) + if (!Image::getConstant(minstr, f.min)) return luaL_error(L, "Invalid filter mode: %s", minstr); - if (!Image::getConstant(magstr, mag)) + if (!Image::getConstant(magstr, f.mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); - Image::Filter f; - f.min = min; - f.mag = mag; - t->setFilter(f); return 0; @@ -117,13 +112,11 @@ int w_Font_setFilter(lua_State *L) int w_Font_getFilter(lua_State *L) { Font *t = luax_checkfont(L, 1); - Image::Filter f = t->getFilter(); - Image::FilterMode min = f.min; - Image::FilterMode mag = f.mag; + const Image::Filter f = t->getFilter(); const char *minstr; const char *magstr; - Image::getConstant(min, minstr); - Image::getConstant(mag, magstr); + Image::getConstant(f.min, minstr); + Image::getConstant(f.mag, magstr); lua_pushstring(L, minstr); lua_pushstring(L, magstr); return 2; diff --git a/src/modules/graphics/opengl/wrap_Image.cpp b/src/modules/graphics/opengl/wrap_Image.cpp index 6e286fd0c..a843c1f37 100644 --- a/src/modules/graphics/opengl/wrap_Image.cpp +++ b/src/modules/graphics/opengl/wrap_Image.cpp @@ -88,12 +88,12 @@ int w_Image_getFilter(lua_State *L) const Image::Filter f = t->getFilter(); const char *minstr; const char *magstr; - const char *mipmapstr; Image::getConstant(f.min, minstr); Image::getConstant(f.mag, magstr); lua_pushstring(L, minstr); lua_pushstring(L, magstr); + const char *mipmapstr; if (Image::getConstant(f.mipmap, mipmapstr)) lua_pushstring(L, mipmapstr); else @@ -147,10 +147,7 @@ int w_Image_setMipmapSharpness(lua_State *L) int w_Image_getMipmapSharpness(lua_State *L) { Image *i = luax_checkimage(L, 1); - - float sharpness = i->getMipmapSharpness(); - lua_pushnumber(L, sharpness); - + lua_pushnumber(L, i->getMipmapSharpness()); return 1; } From eb98e8cc488776956cbe84e88ac4d631c0d91401 Mon Sep 17 00:00:00 2001 From: Alexander Szpakowski Date: Mon, 7 Jan 2013 06:56:59 -0400 Subject: [PATCH 09/20] Removed unnecessary tabs in empty lines, fixed texture filtering when the minification and mipmap filter are the same --- src/modules/graphics/Image.h | 2 +- src/modules/graphics/opengl/Canvas.cpp | 10 +++--- src/modules/graphics/opengl/Image.cpp | 34 +++++++++---------- src/modules/graphics/opengl/Image.h | 14 ++++---- src/modules/graphics/opengl/OpenGL.cpp | 4 +-- .../graphics/opengl/ParticleSystem.cpp | 33 +++++++++--------- src/modules/graphics/opengl/ParticleSystem.h | 2 +- src/modules/graphics/opengl/wrap_Graphics.cpp | 6 ++-- src/modules/graphics/opengl/wrap_Image.cpp | 28 +++++++-------- 9 files changed, 67 insertions(+), 66 deletions(-) diff --git a/src/modules/graphics/Image.h b/src/modules/graphics/Image.h index 881ae94fc..2c063e5db 100644 --- a/src/modules/graphics/Image.h +++ b/src/modules/graphics/Image.h @@ -77,7 +77,7 @@ public: static bool getConstant(WrapMode in, const char *&out); private: - + // The default image filter static Filter defaultFilter; diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index b3b9fbe32..a802efea6 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -97,9 +97,9 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy glGenTextures(1, &img); bindTexture(img); - + setTextureFilter(Image::getDefaultFilter()); - + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, format, NULL); bindTexture(0); @@ -165,7 +165,7 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy glGenTextures(1, &img); bindTexture(img); - + setTextureFilter(Image::getDefaultFilter()); glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, @@ -232,9 +232,9 @@ struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT glGenTextures(1, &img); bindTexture(img); - + setTextureFilter(Image::getDefaultFilter()); - + glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height, 0, GL_RGBA, format, NULL); bindTexture(0); diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index 470902cd8..c85b1b5ba 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -147,26 +147,26 @@ void Image::checkMipmapsCreated() const { if (filter.mipmap != FILTER_NEAREST && filter.mipmap != FILTER_LINEAR) return; - + if (!hasMipmapSupport()) throw love::Exception("Mipmap filtering is not supported on this system!"); - + // some old GPUs/systems claim support for NPOT textures, but fail when generating mipmaps // we can't detect which systems will do this, so we fail gracefully for all NPOT images int w = int(width), h = int(height); if (w != next_p2(w) || h != next_p2(h)) throw love::Exception("Could not generate mipmaps: image does not have power of two dimensions!"); - + bind(); - + GLboolean mipmapscreated; glGetTexParameteriv(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLint *)&mipmapscreated); - + // generate mipmaps for this image if we haven't already if (!mipmapscreated) { glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); - + if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object) glGenerateMipmap(GL_TEXTURE_2D); else if (GLEE_EXT_framebuffer_object) @@ -180,7 +180,7 @@ void Image::checkMipmapsCreated() const void Image::setFilter(const Image::Filter &f) { filter = f; - + bind(); checkMipmapsCreated(); setTextureFilter(f); @@ -194,7 +194,7 @@ const Image::Filter &Image::getFilter() const void Image::setWrap(const Image::Wrap &w) { wrap = w; - + bind(); setTextureWrap(w); } @@ -208,10 +208,10 @@ void Image::setMipmapSharpness(float sharpness) { if (!hasMipmapSharpnessSupport()) return; - + // LOD bias has the range (-maxbias, maxbias) mipmapsharpness = std::min(std::max(sharpness, -maxmipmapsharpness + 0.01f), maxmipmapsharpness - 0.01f); - + bind(); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapsharpness); // negative bias is sharper } @@ -243,7 +243,7 @@ bool Image::loadVolatile() { if (hasMipmapSharpnessSupport()) glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxmipmapsharpness); - + if (hasNpot()) return loadVolatileNPOT(); else @@ -254,10 +254,10 @@ bool Image::loadVolatilePOT() { glGenTextures(1,(GLuint *)&texture); bindTexture(texture); - + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -290,7 +290,7 @@ bool Image::loadVolatilePOT() GL_RGBA, GL_UNSIGNED_BYTE, data->getData()); - + setMipmapSharpness(mipmapsharpness); setFilter(filter); setWrap(wrap); @@ -302,10 +302,10 @@ bool Image::loadVolatileNPOT() { glGenTextures(1,(GLuint *)&texture); bindTexture(texture); - + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -318,7 +318,7 @@ bool Image::loadVolatileNPOT() GL_RGBA, GL_UNSIGNED_BYTE, data->getData()); - + setMipmapSharpness(mipmapsharpness); setFilter(filter); setWrap(wrap); diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index cbe2d38b3..829ec98c3 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -105,9 +105,9 @@ public: void setWrap(const Image::Wrap &w); const Image::Wrap &getWrap() const; - + void setMipmapSharpness(float sharpness); - + float getMipmapSharpness() const; void bind() const; @@ -143,22 +143,22 @@ private: // The source vertices of the image. vertex vertices[4]; - + // Mipmap texture LOD bias value float mipmapsharpness; - + // Implementation-dependent maximum/minimum mipmap sharpness values float maxmipmapsharpness; - + // The image's filter mode Image::Filter filter; - + // The image's wrap mode Image::Wrap wrap; bool loadVolatilePOT(); bool loadVolatileNPOT(); - + void checkMipmapsCreated() const; }; // Image diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 4cae16000..28b64cbdd 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -65,13 +65,13 @@ void setTextureFilter(const graphics::Image::Filter &f) } else { - if (f.min == f.mipmap == Image::FILTER_NEAREST) + if (f.min == Image::FILTER_NEAREST && f.mipmap == Image::FILTER_NEAREST) gmin = GL_NEAREST_MIPMAP_NEAREST; else if (f.min == Image::FILTER_NEAREST && f.mipmap == Image::FILTER_LINEAR) gmin = GL_NEAREST_MIPMAP_LINEAR; else if (f.min == Image::FILTER_LINEAR && f.mipmap == Image::FILTER_NEAREST) gmin = GL_LINEAR_MIPMAP_NEAREST; - else if (f.min == f.mipmap == Image::FILTER_LINEAR) + else if (f.min == Image::FILTER_LINEAR && f.mipmap == Image::FILTER_LINEAR) gmin = GL_LINEAR_MIPMAP_LINEAR; else gmin = GL_LINEAR; diff --git a/src/modules/graphics/opengl/ParticleSystem.cpp b/src/modules/graphics/opengl/ParticleSystem.cpp index 167958dd7..60714cf6e 100644 --- a/src/modules/graphics/opengl/ParticleSystem.cpp +++ b/src/modules/graphics/opengl/ParticleSystem.cpp @@ -105,7 +105,7 @@ ParticleSystem::~ParticleSystem() if (pStart != 0) delete [] pStart; - + if (particleVerts != 0) delete [] particleVerts; } @@ -207,10 +207,10 @@ void ParticleSystem::setBufferSize(unsigned int size) pLast = pStart = new particle[size]; pEnd = pStart + size; - + if (particleVerts != 0) delete [] particleVerts; - + // each particle has 4 vertices particleVerts = new vertex[size*4]; } @@ -468,7 +468,7 @@ bool ParticleSystem::isFull() const void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky) const { if (sprite == 0) return; // just in case of failure - + int numParticles = count(); if (numParticles == 0) return; // don't bother if there's nothing to do @@ -478,25 +478,26 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo static Matrix t; t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky); glMultMatrixf((const GLfloat *)t.getElements()); - + const vertex * imageVerts = sprite->getVertices(); - + // set the vertex data for each particle (transformation, texcoords, color) for (int i = 0; i < numParticles; i++) { particle * p = pStart + i; - + // particle vertices are sprite vertices transformed by particle information t.setTransformation(p->position[0], p->position[1], p->rotation, p->size, p->size, offsetX, offsetY, 0.0f, 0.0f); t.transform(&particleVerts[i*4], &imageVerts[0], 4); - + // set the texture coordinate and color data for particle vertices - for (int v = 0; v < 4; v++) { + for (int v = 0; v < 4; v++) + { int vi = (i * 4) + v; // current vertex index for particle - + particleVerts[vi].s = imageVerts[v].s; particleVerts[vi].t = imageVerts[v].t; - + // particle colors are stored as floats (0-1) but vertex colors are stored as unsigned bytes (0-255) particleVerts[vi].r = p->color.r*255; particleVerts[vi].g = p->color.g*255; @@ -504,19 +505,19 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo particleVerts[vi].a = p->color.a*255; } } - + sprite->bind(); - + glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - + glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vertex), (GLvoid *)&particleVerts[0].r); glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&particleVerts[0].x); glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&particleVerts[0].s); - + glDrawArrays(GL_QUADS, 0, numParticles*4); - + glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); glDisableClientState(GL_COLOR_ARRAY); diff --git a/src/modules/graphics/opengl/ParticleSystem.h b/src/modules/graphics/opengl/ParticleSystem.h index 5c02f75d7..15651c14a 100644 --- a/src/modules/graphics/opengl/ParticleSystem.h +++ b/src/modules/graphics/opengl/ParticleSystem.h @@ -406,7 +406,7 @@ protected: // Pointer to the end of the memory allocation. particle *pEnd; - + // array of transformed vertex data for all particles, for drawing vertex * particleVerts; diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 0fe1a9140..4ad88f0a9 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -601,10 +601,10 @@ int w_setDefaultImageFilter(lua_State *L) { Image::FilterMode min; Image::FilterMode mag; - + const char *minstr = luaL_checkstring(L, 1); const char *magstr = luaL_optstring(L, 2, minstr); - + if (!Image::getConstant(minstr, min)) return luaL_error(L, "Invalid filter mode: %s", minstr); if (!Image::getConstant(magstr, mag)) @@ -613,7 +613,7 @@ int w_setDefaultImageFilter(lua_State *L) Image::Filter f; f.min = min; f.mag = mag; - + instance->setDefaultImageFilter(f); return 0; diff --git a/src/modules/graphics/opengl/wrap_Image.cpp b/src/modules/graphics/opengl/wrap_Image.cpp index a843c1f37..3abffa7c1 100644 --- a/src/modules/graphics/opengl/wrap_Image.cpp +++ b/src/modules/graphics/opengl/wrap_Image.cpp @@ -50,17 +50,17 @@ int w_Image_getHeight(lua_State *L) int w_Image_setFilter(lua_State *L) { Image *t = luax_checkimage(L, 1); - + Image::Filter f; - + const char *minstr = luaL_checkstring(L, 2); const char *magstr = luaL_optstring(L, 3, minstr); - + if (!Image::getConstant(minstr, f.min)) return luaL_error(L, "Invalid filter mode: %s", minstr); if (!Image::getConstant(magstr, f.mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); - + if (lua_isnoneornil(L, 4)) f.mipmap = Image::FILTER_NONE; // mipmapping is disabled unless third argument is given else @@ -69,16 +69,16 @@ int w_Image_setFilter(lua_State *L) if (!Image::getConstant(mipmapstr, f.mipmap)) return luaL_error(L, "Invalid filter mode: %s", mipmapstr); } - + try { t->setFilter(f); } catch(love::Exception &e) { - return luaL_error(L, e.what()); + return luaL_error(L, "%s", e.what()); } - + return 0; } @@ -92,32 +92,32 @@ int w_Image_getFilter(lua_State *L) Image::getConstant(f.mag, magstr); lua_pushstring(L, minstr); lua_pushstring(L, magstr); - + const char *mipmapstr; if (Image::getConstant(f.mipmap, mipmapstr)) lua_pushstring(L, mipmapstr); else lua_pushnil(L); // only return a mipmap filter if mipmapping is enabled - + return 3; } int w_Image_setWrap(lua_State *L) { Image *i = luax_checkimage(L, 1); - + Image::Wrap w; - + const char *sstr = luaL_checkstring(L, 2); const char *tstr = luaL_optstring(L, 3, sstr); - + if (!Image::getConstant(sstr, w.s)) return luaL_error(L, "Invalid wrap mode: %s", sstr); if (!Image::getConstant(tstr, w.t)) return luaL_error(L, "Invalid wrap mode, %s", tstr); i->setWrap(w); - + return 0; } @@ -140,7 +140,7 @@ int w_Image_setMipmapSharpness(lua_State *L) float sharpness = (float) luaL_checknumber(L, 2); i->setMipmapSharpness(sharpness); - + return 0; } From e5388ff73b15f7a389364fc4c601ccd994087438 Mon Sep 17 00:00:00 2001 From: Alexander Szpakowski Date: Mon, 7 Jan 2013 07:11:40 -0400 Subject: [PATCH 10/20] Removed more unnecessary tabs in blank lines --- src/modules/graphics/opengl/Canvas.cpp | 2 +- src/modules/graphics/opengl/Font.cpp | 108 +++++++++----------- src/modules/graphics/opengl/Font.h | 14 +-- src/modules/graphics/opengl/OpenGL.cpp | 32 +++--- src/modules/graphics/opengl/wrap_Canvas.cpp | 20 ++-- src/modules/graphics/opengl/wrap_Font.cpp | 10 +- src/modules/graphics/opengl/wrap_Image.cpp | 2 +- 7 files changed, 90 insertions(+), 98 deletions(-) diff --git a/src/modules/graphics/opengl/Canvas.cpp b/src/modules/graphics/opengl/Canvas.cpp index a802efea6..b863a4dbb 100644 --- a/src/modules/graphics/opengl/Canvas.cpp +++ b/src/modules/graphics/opengl/Canvas.cpp @@ -313,7 +313,7 @@ Canvas::Canvas(int width, int height, TextureType texture_type) vertices[2].t = 1; vertices[3].s = 1; vertices[3].t = 0; - + settings.filter = Image::getDefaultFilter(); getStrategy(); diff --git a/src/modules/graphics/opengl/Font.cpp b/src/modules/graphics/opengl/Font.cpp index 3fd65f899..e8caac22e 100644 --- a/src/modules/graphics/opengl/Font.cpp +++ b/src/modules/graphics/opengl/Font.cpp @@ -49,12 +49,10 @@ Font::Font(love::font::Rasterizer *r, const Image::Filter &filter) , mSpacing(1) , filter(filter) { - r->retain(); - love::font::GlyphData *gd = r->getGlyphData(32); type = (gd->getFormat() == love::font::GlyphData::FORMAT_LUMINANCE_ALPHA ? FONT_TRUETYPE : FONT_IMAGE); delete gd; - + // try to find the best texture size match for the font size // default to the largest texture size if no rough match is found texture_size_index = NUM_TEXTURE_SIZES - 1; @@ -68,19 +66,13 @@ Font::Font(love::font::Rasterizer *r, const Image::Filter &filter) break; } } - + texture_width = TEXTURE_WIDTHS[texture_size_index]; texture_height = TEXTURE_HEIGHTS[texture_size_index]; - - try - { - createTexture(); - } - catch (love::Exception &e) - { - r->release(); - throw; - } + + createTexture(); + + r->retain(); } Font::~Font() @@ -92,10 +84,10 @@ Font::~Font() bool Font::initializeTexture(GLint format) { GLint internalformat = (format == GL_LUMINANCE_ALPHA) ? GL_LUMINANCE8_ALPHA8 : GL_RGBA8; - + // clear errors before initializing while (glGetError() != GL_NO_ERROR); - + glTexImage2D(GL_TEXTURE_2D, 0, internalformat, @@ -105,49 +97,49 @@ bool Font::initializeTexture(GLint format) format, GL_UNSIGNED_BYTE, NULL); - + return glGetError() == GL_NO_ERROR; } void Font::createTexture() { texture_x = texture_y = rowHeight = TEXTURE_PADDING; - + GLuint t; glGenTextures(1, &t); textures.push_back(t); - + bindTexture(t); - + setTextureFilter(filter); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - + GLint format = (type == FONT_TRUETYPE ? GL_LUMINANCE_ALPHA : GL_RGBA); - + // try to initialize the texture, attempting smaller sizes if initialization fails bool initialized = false; while (texture_size_index >= 0) { texture_width = TEXTURE_WIDTHS[texture_size_index]; texture_height = TEXTURE_HEIGHTS[texture_size_index]; - + initialized = initializeTexture(format); - + if (initialized || texture_size_index <= 0) break; - + --texture_size_index; } - + if (!initialized) { // cleanup before throwing deleteTexture(t); bindTexture(0); textures.pop_back(); - + throw love::Exception("Could not create font texture!"); } @@ -183,17 +175,17 @@ Font::Glyph *Font::addGlyph(const int glyph) } Glyph *g = new Glyph; - + g->texture = 0; g->spacing = gd->getAdvance(); - + memset(&g->quad, 0, sizeof(GlyphQuad)); // don't waste space for empty glyphs. also fixes a division by zero bug with ati drivers if (w > 0 && h > 0) { const GLuint t = textures.back(); - + bindTexture(t); glTexSubImage2D(GL_TEXTURE_2D, 0, @@ -211,10 +203,10 @@ Font::Glyph *Font::addGlyph(const int glyph) v.y = (float) texture_y; v.w = (float) w; v.h = (float) h; - + Quad q = Quad(v, (const float) texture_width, (const float) texture_height); const vertex *verts = q.getVertices(); - + // copy vertex data to the glyph and set proper bearing for (int i = 0; i < 4; i++) { @@ -230,9 +222,9 @@ Font::Glyph *Font::addGlyph(const int glyph) rowHeight = std::max(rowHeight, h + TEXTURE_PADDING); delete gd; - + glyphs[glyph] = g; - + return g; } @@ -241,7 +233,7 @@ Font::Glyph *Font::findGlyph(const int glyph) Glyph *g = glyphs[glyph]; if (!g) g = addGlyph(glyph); - + return g; } @@ -254,15 +246,15 @@ void Font::print(const std::string &text, float x, float y, float letter_spacing { float dx = 0.0f; // spacing counter for newline handling float dy = 0.0f; - + // keeps track of when we need to switch textures in our vertex array std::vector glyphinfolist; - + std::vector glyphquads; glyphquads.reserve(text.size()); // pre-allocate space for the maximum possible number of quads - + int quadindex = 0; - + glPushMatrix(); Matrix t; @@ -273,11 +265,11 @@ void Font::print(const std::string &text, float x, float y, float letter_spacing { utf8::iterator i(text.begin(), text.begin(), text.end()); utf8::iterator end(text.end(), text.begin(), text.end()); - + while (i != end) { int g = *i++; - + if (g == '\n') { // wrap newline, but do not print it @@ -285,27 +277,27 @@ void Font::print(const std::string &text, float x, float y, float letter_spacing dx = 0.0f; continue; } - + Glyph *glyph = findGlyph(g); - + // we only care about the vertices of glyphs which have a texture if (glyph->texture != 0) { // copy glyphquad (4 vertices) from original glyph to our current quad list glyphquads.push_back(glyph->quad); - + // 1.25 is magic line height for true type fonts float lineheight = (type == FONT_TRUETYPE) ? floor(getHeight() / 1.25f + 0.5f) : 0.0f; - + // set proper relative position for (int i = 0; i < 4; i++) { glyphquads[quadindex].vertices[i].x += dx; glyphquads[quadindex].vertices[i].y += dy + lineheight; } - + size_t listsize = glyphinfolist.size(); - + // check if current glyph texture has changed since the previous iteration if (listsize == 0 || glyphinfolist[listsize-1].texture != glyph->texture) { @@ -316,11 +308,11 @@ void Font::print(const std::string &text, float x, float y, float letter_spacing glyphdrawinfo.texture = glyph->texture; glyphinfolist.push_back(glyphdrawinfo); } - + ++quadindex; ++glyphinfolist[glyphinfolist.size()-1].numquads; } - + // advance the x position for the next glyph dx += glyph->spacing + letter_spacing; } @@ -337,32 +329,32 @@ void Font::print(const std::string &text, float x, float y, float letter_spacing } if (quadindex > 0 && glyphinfolist.size() > 0) - { + { // sort glyph draw info list by texture first, and quad position in memory second (using the struct's < operator) std::sort(glyphinfolist.begin(), glyphinfolist.end()); - + glEnableClientState(GL_VERTEX_ARRAY); glEnableClientState(GL_TEXTURE_COORD_ARRAY); - + glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&glyphquads[0].vertices[0].x); glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&glyphquads[0].vertices[0].s); - + // we need to draw a new vertex array for every section of the string that uses a different texture than the previous section std::vector::const_iterator it; for (it = glyphinfolist.begin(); it != glyphinfolist.end(); ++it) { bindTexture(it->texture); - + int startvertex = it->startquad * 4; int numvertices = it->numquads * 4; - + glDrawArrays(GL_QUADS, startvertex, numvertices); } - + glDisableClientState(GL_TEXTURE_COORD_ARRAY); glDisableClientState(GL_VERTEX_ARRAY); } - + glPopMatrix(); } @@ -510,7 +502,7 @@ Image::Filter Font::getFilter() bindTexture(*it); return getTextureFilter(); } - + return Image::getDefaultFilter(); } diff --git a/src/modules/graphics/opengl/Font.h b/src/modules/graphics/opengl/Font.h index 6b35b8b51..299836cdd 100644 --- a/src/modules/graphics/opengl/Font.h +++ b/src/modules/graphics/opengl/Font.h @@ -125,14 +125,14 @@ public: * Returns the spacing modifier. **/ float getSpacing() const; - + void setFilter(const Image::Filter &f); Image::Filter getFilter(); // Implements Volatile. bool loadVolatile(); void unloadVolatile(); - + private: enum FontType @@ -154,13 +154,13 @@ private: int spacing; GlyphQuad quad; }; - + // used to determine when to change textures in the vertex array generated when printing text struct GlyphArrayDrawInfo { GLuint texture; int startquad, numquads; - + // used when sorting with std::sort // sorts by texture first (binding textures is expensive) and relative position in memory second bool operator < (const GlyphArrayDrawInfo &other) const @@ -177,16 +177,16 @@ private: int height; float lineHeight; float mSpacing; // modifies the spacing by multiplying it with this value - + int texture_size_index; int texture_width; int texture_height; - + std::vector textures; // vector of packed textures std::map glyphs; // maps glyphs to quad information FontType type; Image::Filter filter; - + static const int NUM_TEXTURE_SIZES = 7; static const int TEXTURE_WIDTHS[NUM_TEXTURE_SIZES]; static const int TEXTURE_HEIGHTS[NUM_TEXTURE_SIZES]; diff --git a/src/modules/graphics/opengl/OpenGL.cpp b/src/modules/graphics/opengl/OpenGL.cpp index 28b64cbdd..d931b8ead 100644 --- a/src/modules/graphics/opengl/OpenGL.cpp +++ b/src/modules/graphics/opengl/OpenGL.cpp @@ -55,7 +55,7 @@ void deleteTexture(GLuint texture) void setTextureFilter(const graphics::Image::Filter &f) { GLint gmin, gmag; - + if (f.mipmap == Image::FILTER_NONE) { if (f.min == Image::FILTER_NEAREST) @@ -76,8 +76,8 @@ void setTextureFilter(const graphics::Image::Filter &f) else gmin = GL_LINEAR; } - - + + switch (f.mag) { case Image::FILTER_NEAREST: @@ -88,7 +88,7 @@ void setTextureFilter(const graphics::Image::Filter &f) gmag = GL_LINEAR; break; } - + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gmin); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gmag); } @@ -98,9 +98,9 @@ graphics::Image::Filter getTextureFilter() GLint gmin, gmag; glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &gmin); glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, &gmag); - + Image::Filter f; - + switch (gmin) { case GL_NEAREST: @@ -127,7 +127,7 @@ graphics::Image::Filter getTextureFilter() f.mipmap = Image::FILTER_NONE; break; } - + switch (gmag) { case GL_NEAREST: @@ -138,14 +138,14 @@ graphics::Image::Filter getTextureFilter() f.mag = Image::FILTER_LINEAR; break; } - + return f; } void setTextureWrap(const graphics::Image::Wrap &w) { GLint gs, gt; - + switch (w.s) { case Image::WRAP_CLAMP: @@ -156,7 +156,7 @@ void setTextureWrap(const graphics::Image::Wrap &w) gs = GL_REPEAT; break; } - + switch (w.t) { case Image::WRAP_CLAMP: @@ -167,7 +167,7 @@ void setTextureWrap(const graphics::Image::Wrap &w) gt = GL_REPEAT; break; } - + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gs); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gt); } @@ -175,12 +175,12 @@ void setTextureWrap(const graphics::Image::Wrap &w) graphics::Image::Wrap getTextureWrap() { GLint gs, gt; - + glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &gs); glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, >); - + Image::Wrap w; - + switch (gs) { case GL_CLAMP_TO_EDGE: @@ -191,7 +191,7 @@ graphics::Image::Wrap getTextureWrap() w.s = Image::WRAP_REPEAT; break; } - + switch (gt) { case GL_CLAMP_TO_EDGE: @@ -202,7 +202,7 @@ graphics::Image::Wrap getTextureWrap() w.t = Image::WRAP_REPEAT; break; } - + return w; } diff --git a/src/modules/graphics/opengl/wrap_Canvas.cpp b/src/modules/graphics/opengl/wrap_Canvas.cpp index 9a7853802..10ff83f6d 100644 --- a/src/modules/graphics/opengl/wrap_Canvas.cpp +++ b/src/modules/graphics/opengl/wrap_Canvas.cpp @@ -67,19 +67,19 @@ int w_Canvas_getImageData(lua_State *L) int w_Canvas_setFilter(lua_State *L) { Canvas *canvas = luax_checkcanvas(L, 1); - + Image::Filter f; - + const char *minstr = luaL_checkstring(L, 2); const char *magstr = luaL_optstring(L, 3, minstr); - + if (!Image::getConstant(minstr, f.min)) return luaL_error(L, "Invalid filter mode: %s", minstr); if (!Image::getConstant(magstr, f.mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); - + canvas->setFilter(f); - + return 0; } @@ -103,19 +103,19 @@ int w_Canvas_getFilter(lua_State *L) int w_Canvas_setWrap(lua_State *L) { Canvas *canvas = luax_checkcanvas(L, 1); - + Image::Wrap w; - + const char *sstr = luaL_checkstring(L, 2); const char *tstr = luaL_optstring(L, 3, sstr); - + if (!Image::getConstant(sstr, w.s)) return luaL_error(L, "Invalid wrap mode: %s", sstr); if (!Image::getConstant(tstr, w.t)) return luaL_error(L, "Invalid wrap mode, %s", tstr); - + canvas->setWrap(w); - + return 0; } diff --git a/src/modules/graphics/opengl/wrap_Font.cpp b/src/modules/graphics/opengl/wrap_Font.cpp index 5dd7021ad..cc71ec88b 100644 --- a/src/modules/graphics/opengl/wrap_Font.cpp +++ b/src/modules/graphics/opengl/wrap_Font.cpp @@ -93,19 +93,19 @@ int w_Font_getLineHeight(lua_State *L) int w_Font_setFilter(lua_State *L) { Font *t = luax_checkfont(L, 1); - + Image::Filter f; - + const char *minstr = luaL_checkstring(L, 2); const char *magstr = luaL_optstring(L, 3, minstr); - + if (!Image::getConstant(minstr, f.min)) return luaL_error(L, "Invalid filter mode: %s", minstr); if (!Image::getConstant(magstr, f.mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); - + t->setFilter(f); - + return 0; } diff --git a/src/modules/graphics/opengl/wrap_Image.cpp b/src/modules/graphics/opengl/wrap_Image.cpp index 3abffa7c1..e92c22952 100644 --- a/src/modules/graphics/opengl/wrap_Image.cpp +++ b/src/modules/graphics/opengl/wrap_Image.cpp @@ -137,7 +137,7 @@ int w_Image_getWrap(lua_State *L) int w_Image_setMipmapSharpness(lua_State *L) { Image *i = luax_checkimage(L, 1); - + float sharpness = (float) luaL_checknumber(L, 2); i->setMipmapSharpness(sharpness); From a6f4a3ab0fc55ba2cbd73f3b088ca8600675b663 Mon Sep 17 00:00:00 2001 From: Alexander Szpakowski Date: Mon, 7 Jan 2013 07:29:04 -0400 Subject: [PATCH 11/20] Removed names of unused parameters to quiet noisy compilers --- src/modules/graphics/opengl/Font.cpp | 2 +- src/modules/graphics/opengl/Graphics.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/modules/graphics/opengl/Font.cpp b/src/modules/graphics/opengl/Font.cpp index e8caac22e..ba0b7464b 100644 --- a/src/modules/graphics/opengl/Font.cpp +++ b/src/modules/graphics/opengl/Font.cpp @@ -317,7 +317,7 @@ void Font::print(const std::string &text, float x, float y, float letter_spacing dx += glyph->spacing + letter_spacing; } } - catch (love::Exception &e) + catch (love::Exception &) { glPopMatrix(); throw; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index ed27fdd3c..182deccc4 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -339,7 +339,7 @@ Image *Graphics::newImage(love::image::ImageData *data) { success = image->load(); } - catch(love::Exception &e) + catch(love::Exception &) { image->release(); throw; From 36c5259e12d90d8cafe64535fed6b4823cc21990 Mon Sep 17 00:00:00 2001 From: Alexander Szpakowski Date: Mon, 7 Jan 2013 16:31:48 -0400 Subject: [PATCH 12/20] Font objects now have mipmap filter and mipmap sharpness support --- src/modules/graphics/opengl/Font.cpp | 78 ++++++++++++++++++++--- src/modules/graphics/opengl/Font.h | 13 +++- src/modules/graphics/opengl/wrap_Font.cpp | 46 ++++++++++++- src/modules/graphics/opengl/wrap_Font.h | 2 + 4 files changed, 127 insertions(+), 12 deletions(-) diff --git a/src/modules/graphics/opengl/Font.cpp b/src/modules/graphics/opengl/Font.cpp index ba0b7464b..d7f511188 100644 --- a/src/modules/graphics/opengl/Font.cpp +++ b/src/modules/graphics/opengl/Font.cpp @@ -21,15 +21,15 @@ #include "Font.h" #include "font/GlyphData.h" #include "Quad.h" +#include "Image.h" #include "libraries/utf8/utf8.h" #include "common/math.h" #include "common/Matrix.h" + #include - #include - #include // for max namespace love @@ -39,8 +39,8 @@ namespace graphics namespace opengl { -const int Font::TEXTURE_WIDTHS[] = {128, 256, 256, 512, 512, 1024, 1024}; -const int Font::TEXTURE_HEIGHTS[] = {128, 128, 256, 256, 512, 512, 1024}; +const int Font::TEXTURE_WIDTHS[] = {128, 256, 256, 512, 512, 1024, 1024}; +const int Font::TEXTURE_HEIGHTS[] = {128, 128, 256, 256, 512, 512, 1024}; Font::Font(love::font::Rasterizer *r, const Image::Filter &filter) : rasterizer(r) @@ -48,6 +48,7 @@ Font::Font(love::font::Rasterizer *r, const Image::Filter &filter) , lineHeight(1) , mSpacing(1) , filter(filter) + , mipmapsharpness(0.0f) { love::font::GlyphData *gd = r->getGlyphData(32); type = (gd->getFormat() == love::font::GlyphData::FORMAT_LUMINANCE_ALPHA ? FONT_TRUETYPE : FONT_IMAGE); @@ -70,7 +71,7 @@ Font::Font(love::font::Rasterizer *r, const Image::Filter &filter) texture_width = TEXTURE_WIDTHS[texture_size_index]; texture_height = TEXTURE_HEIGHTS[texture_size_index]; - createTexture(); + loadVolatile(); r->retain(); } @@ -111,7 +112,8 @@ void Font::createTexture() bindTexture(t); - setTextureFilter(filter); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); @@ -153,6 +155,9 @@ void Font::createTexture() format, GL_UNSIGNED_BYTE, &emptyData[0]); + + setFilter(filter); + setMipmapSharpness(mipmapsharpness); } Font::Glyph *Font::addGlyph(const int glyph) @@ -484,30 +489,85 @@ float Font::getSpacing() const return mSpacing; } +void Font::checkMipmapsCreated() const +{ + if (filter.mipmap != Image::FILTER_NEAREST && filter.mipmap != Image::FILTER_LINEAR) + return; + + if (!Image::hasMipmapSupport()) + throw love::Exception("Mipmap filtering is not supported on this system!"); + + GLboolean mipmapscreated; + glGetTexParameteriv(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, (GLint *)&mipmapscreated); + + // generate mipmaps for this image if we haven't already + if (!mipmapscreated) + { + glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); + + if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object) + glGenerateMipmap(GL_TEXTURE_2D); + else if (GLEE_EXT_framebuffer_object) + glGenerateMipmapEXT(GL_TEXTURE_2D); + else + { + // modify single texel to trigger mipmap chain generation + std::vector emptydata(type == FONT_TRUETYPE ? 2 : 4); + glTexSubImage2D(GL_TEXTURE_2D, + 0, + 0, 0, + 1, 1, + type == FONT_TRUETYPE ? GL_LUMINANCE_ALPHA : GL_RGBA, + GL_UNSIGNED_BYTE, + &emptydata[0]); + } + } +} + void Font::setFilter(const Image::Filter &f) { + filter = f; + std::vector::const_iterator it; for (it = textures.begin(); it != textures.end(); ++it) { bindTexture(*it); + checkMipmapsCreated(); setTextureFilter(f); } } -Image::Filter Font::getFilter() +const Image::Filter &Font::getFilter() { + return filter; +} + +void Font::setMipmapSharpness(float sharpness) +{ + if (!Image::hasMipmapSharpnessSupport()) + return; + + // LOD bias has the range (-maxbias, maxbias) + mipmapsharpness = std::min(std::max(sharpness, -maxmipmapsharpness + 0.01f), maxmipmapsharpness - 0.01f); + std::vector::const_iterator it; for (it = textures.begin(); it != textures.end(); ++it) { bindTexture(*it); - return getTextureFilter(); + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapsharpness); // negative bias is sharper } +} - return Image::getDefaultFilter(); +float Font::getMipmapSharpness() const +{ + return mipmapsharpness; } bool Font::loadVolatile() { + if (Image::hasMipmapSharpnessSupport()) + glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxmipmapsharpness); + createTexture(); return true; } diff --git a/src/modules/graphics/opengl/Font.h b/src/modules/graphics/opengl/Font.h index 299836cdd..73baccd9b 100644 --- a/src/modules/graphics/opengl/Font.h +++ b/src/modules/graphics/opengl/Font.h @@ -127,7 +127,10 @@ public: float getSpacing() const; void setFilter(const Image::Filter &f); - Image::Filter getFilter(); + const Image::Filter &getFilter(); + + void setMipmapSharpness(float sharpness); + float getMipmapSharpness() const; // Implements Volatile. bool loadVolatile(); @@ -196,6 +199,14 @@ private: int texture_x, texture_y; int rowHeight; + // Mipmap texture LOD bias value + float mipmapsharpness; + + // Implementation-dependent maximum/minimum mipmap sharpness values + float maxmipmapsharpness; + + void checkMipmapsCreated() const; + bool initializeTexture(GLint format); void createTexture(); Glyph *addGlyph(const int glyph); diff --git a/src/modules/graphics/opengl/wrap_Font.cpp b/src/modules/graphics/opengl/wrap_Font.cpp index cc71ec88b..5306a10e3 100644 --- a/src/modules/graphics/opengl/wrap_Font.cpp +++ b/src/modules/graphics/opengl/wrap_Font.cpp @@ -104,7 +104,23 @@ int w_Font_setFilter(lua_State *L) if (!Image::getConstant(magstr, f.mag)) return luaL_error(L, "Invalid filter mode: %s", magstr); - t->setFilter(f); + if (lua_isnoneornil(L, 4)) + f.mipmap = Image::FILTER_NONE; // mipmapping is disabled unless third argument is given + else + { + const char *mipmapstr = luaL_checkstring(L, 4); + if (!Image::getConstant(mipmapstr, f.mipmap)) + return luaL_error(L, "Invalid filter mode: %s", mipmapstr); + } + + try + { + t->setFilter(f); + } + catch(love::Exception &e) + { + return luaL_error(L, "%s", e.what()); + } return 0; } @@ -119,7 +135,31 @@ int w_Font_getFilter(lua_State *L) Image::getConstant(f.mag, magstr); lua_pushstring(L, minstr); lua_pushstring(L, magstr); - return 2; + + const char *mipmapstr; + if (Image::getConstant(f.mipmap, mipmapstr)) + lua_pushstring(L, mipmapstr); + else + lua_pushnil(L); // only return a mipmap filter if mipmapping is enabled + + return 3; +} + +int w_Font_setMipmapSharpness(lua_State *L) +{ + Font *t = luax_checkfont(L, 1); + + float sharpness = (float) luaL_checknumber(L, 2); + t->setMipmapSharpness(sharpness); + + return 0; +} + +int w_Font_getMipmapSharpness(lua_State *L) +{ + Font *t = luax_checkfont(L, 1); + lua_pushnumber(L, t->getMipmapSharpness()); + return 1; } static const luaL_Reg functions[] = @@ -131,6 +171,8 @@ static const luaL_Reg functions[] = { "getLineHeight", w_Font_getLineHeight }, { "setFilter", w_Font_setFilter }, { "getFilter", w_Font_getFilter }, + { "setMipmapSharpness", w_Font_setMipmapSharpness }, + { "getMipmapSharpness", w_Font_getMipmapSharpness }, { 0, 0 } }; diff --git a/src/modules/graphics/opengl/wrap_Font.h b/src/modules/graphics/opengl/wrap_Font.h index c145167b2..a64be5863 100644 --- a/src/modules/graphics/opengl/wrap_Font.h +++ b/src/modules/graphics/opengl/wrap_Font.h @@ -40,6 +40,8 @@ int w_Font_setLineHeight(lua_State *L); int w_Font_getLineHeight(lua_State *L); int w_Font_setFilter(lua_State *L); int w_Font_getFilter(lua_State *L); +int w_Font_setMipmapSharpness(lua_State *L); +int w_Font_getMipmapSharpness(lua_State *L); extern "C" int luaopen_font(lua_State *L); } // opengl From 2db9bfad111ad9a08986ea9bf7268ab198432e08 Mon Sep 17 00:00:00 2001 From: vrld Date: Sun, 13 Jan 2013 16:19:27 +0100 Subject: [PATCH 13/20] Fix PixelEffect texture unit pool. Fixes two problems: (1) Overwriting externs with the same name and (2) not using unused texture units properly. 1) Sending two different images to two different effects using the same extern name would use the same image for both effects, e.g.: effect_1:send('img', img_1) effect_2:send('img', img_2) -- also changes img to point to img_2 in effect_1! Fixed by localizing the name -> texture unit mapping for each pixel effect. 2) When a pixel effect was destroyed, the allocated texture units were not marked as being available again. Fixed by having a vector marking the free units instead of just a counter how many units are in use. Still problematic: Sending more than GL_MAX_TEXTURE_IMAGE_UNITS (>= 16, depending on the implementation) images/canvases *in total* to pixel effects. Effects could hold references to used *texture-ids* and bind/unbind them dynamically on a effect switch. Con: Introduces additional complexity when switching effects. However, benchmarks by Alexander Szpakowski have shown the performance loss is negligible. --- src/modules/graphics/opengl/PixelEffect.cpp | 29 ++++++++++++++++----- src/modules/graphics/opengl/PixelEffect.h | 8 +++--- 2 files changed, 26 insertions(+), 11 deletions(-) diff --git a/src/modules/graphics/opengl/PixelEffect.cpp b/src/modules/graphics/opengl/PixelEffect.cpp index 8e570fb27..9accd90ed 100644 --- a/src/modules/graphics/opengl/PixelEffect.cpp +++ b/src/modules/graphics/opengl/PixelEffect.cpp @@ -51,9 +51,7 @@ namespace opengl PixelEffect *PixelEffect::current = NULL; -std::map PixelEffect::_texture_unit_pool; -GLint PixelEffect::_current_texture_unit = 0; -GLint PixelEffect::_max_texture_units = 0; +std::vector PixelEffect::_unit_available; GLint PixelEffect::getTextureUnit(const std::string &name) { @@ -62,18 +60,35 @@ GLint PixelEffect::getTextureUnit(const std::string &name) if (it != _texture_unit_pool.end()) return it->second; - if (++_current_texture_unit >= _max_texture_units) + GLint unit = -1; + for (int i = 1; i < _unit_available.size(); ++i) + { + if (_unit_available[i]) + { + unit = i; + break; + } + } + + if (unit == -1) throw love::Exception("No more texture units available"); - _texture_unit_pool[name] = _current_texture_unit; - return _current_texture_unit; + _unit_available[unit] = false; + _texture_unit_pool[name] = unit; + return unit; } PixelEffect::PixelEffect(const std::string &code) : _program(0) , _code(code) { - glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &_max_texture_units); + if (_unit_available.empty()) + { + GLint max_units; + glGetIntegerv(GL_MAX_TEXTURE_IMAGE_UNITS, &max_units); + _unit_available.resize(max_units, true); + _unit_available[0] = false; + } loadVolatile(); } diff --git a/src/modules/graphics/opengl/PixelEffect.h b/src/modules/graphics/opengl/PixelEffect.h index e1818e735..b0d7fc704 100644 --- a/src/modules/graphics/opengl/PixelEffect.h +++ b/src/modules/graphics/opengl/PixelEffect.h @@ -24,6 +24,7 @@ #include "common/Object.h" #include #include +#include #include "OpenGL.h" #include "Image.h" #include "Canvas.h" @@ -67,10 +68,9 @@ private: std::map _uniforms; // texture unit pool for setting images - static std::map _texture_unit_pool; - static GLint _current_texture_unit; - static GLint _max_texture_units; - static GLint getTextureUnit(const std::string &name); + std::map _texture_unit_pool; + GLint getTextureUnit(const std::string &name); + static std::vector _unit_available; }; } // opengl From b97765b16935f9c7339686e372f245ec16ba97ec Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Fri, 18 Jan 2013 00:29:01 +0100 Subject: [PATCH 14/20] Check for OpenGL 2.0 in NPOT check (issue #538) --- src/modules/graphics/opengl/Image.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index c85b1b5ba..81f17d376 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -357,7 +357,7 @@ void Image::drawv(const Matrix &t, const vertex *v) const bool Image::hasNpot() { - return GLEE_ARB_texture_non_power_of_two != 0; + return GLEE_VERSION_2_0 || GLEE_ARB_texture_non_power_of_two; } bool Image::hasMipmapSupport() From 49961d66c737a2c9b50e319e869f21f2c7fb2a77 Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Fri, 18 Jan 2013 00:32:25 +0100 Subject: [PATCH 15/20] Fix setVolumeLimits (issue #537) --- src/modules/audio/wrap_Source.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/modules/audio/wrap_Source.cpp b/src/modules/audio/wrap_Source.cpp index 291d28b14..34a5afd3b 100644 --- a/src/modules/audio/wrap_Source.cpp +++ b/src/modules/audio/wrap_Source.cpp @@ -232,7 +232,7 @@ int w_Source_setVolumeLimits(lua_State *L) if (vmin < .0f || vmin > 1.f || vmax < .0f || vmax > 1.f) return luaL_error(L, "Invalid volume limits: [%f:%f]. Must be in [0:1]", vmin, vmax); t->setMinVolume(vmin); - t->setMaxVolume(vmin); + t->setMaxVolume(vmax); return 0; } From 501beb7d023caffc425b39aeb20f30c7c370a4ec Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Fri, 18 Jan 2013 00:48:36 +0100 Subject: [PATCH 16/20] Add blend mode 'none' (issue #536) --- src/modules/graphics/Graphics.cpp | 1 + src/modules/graphics/Graphics.h | 1 + src/modules/graphics/opengl/Graphics.cpp | 4 ++++ 3 files changed, 6 insertions(+) diff --git a/src/modules/graphics/Graphics.cpp b/src/modules/graphics/Graphics.cpp index 58019c017..c29896bad 100644 --- a/src/modules/graphics/Graphics.cpp +++ b/src/modules/graphics/Graphics.cpp @@ -124,6 +124,7 @@ StringMap::Entry Graphics::blendM { "subtractive", Graphics::BLEND_SUBTRACTIVE }, { "multiplicative", Graphics::BLEND_MULTIPLICATIVE }, { "premultiplied", Graphics::BLEND_PREMULTIPLIED }, + { "none", Graphics::BLEND_NONE }, }; StringMap Graphics::blendModes(Graphics::blendModeEntries, sizeof(Graphics::blendModeEntries)); diff --git a/src/modules/graphics/Graphics.h b/src/modules/graphics/Graphics.h index 4926aa90a..2480184f9 100644 --- a/src/modules/graphics/Graphics.h +++ b/src/modules/graphics/Graphics.h @@ -57,6 +57,7 @@ public: BLEND_SUBTRACTIVE, BLEND_MULTIPLICATIVE, BLEND_PREMULTIPLIED, + BLEND_NONE, BLEND_MAX_ENUM }; diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index 182deccc4..f33cb3eb0 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -549,6 +549,8 @@ void Graphics::setBlendMode(Graphics::BlendMode mode) glBlendFunc(GL_DST_COLOR, GL_ZERO); else if (mode == BLEND_PREMULTIPLIED) glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA); + else if (mode == BLEND_NONE) + glBlendFunc(GL_ONE, GL_ZERO); else // mode == BLEND_ADDITIVE || mode == BLEND_SUBTRACTIVE glBlendFunc(GL_SRC_ALPHA, GL_ONE); } @@ -584,6 +586,8 @@ Graphics::BlendMode Graphics::getBlendMode() return BLEND_MULTIPLICATIVE; else if (src == GL_ONE && dst == GL_ONE_MINUS_SRC_ALPHA) // && equation == GL_FUNC_ADD return BLEND_PREMULTIPLIED; + else if (src == GL_ONE && dst == GL_ZERO) + return BLEND_NONE; return BLEND_MAX_ENUM; // Should never be reached. } From a72c981c3215dc8419508f74daee1c37eaa303eb Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Fri, 18 Jan 2013 00:55:28 +0100 Subject: [PATCH 17/20] Make sure love.errhand gets a local reference to print as well, and find the error handler at errortime (partial #390) --- src/scripts/boot.lua | 11 ++++++++--- src/scripts/boot.lua.h | 26 ++++++++++++++++---------- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/scripts/boot.lua b/src/scripts/boot.lua index 5fed6e914..9603ca741 100644 --- a/src/scripts/boot.lua +++ b/src/scripts/boot.lua @@ -682,7 +682,7 @@ end -- Error screen. ----------------------------------------------------------- -local debug = debug +local debug, print = debug, print local function error_printer(msg, layer) print((debug.traceback("Error: " .. tostring(msg), 1+(layer or 1)):gsub("\n[^\n]+$", ""))) @@ -801,6 +801,11 @@ function love.releaseerrhand(msg) end end +local function deferErrhand(...) + local handler = ((love._release and love.releaseerrhand) or love.errhand or error_printer) + return handler(...) +end + ----------------------------------------------------------- -- The root of all calls. @@ -809,9 +814,9 @@ end return function() local result = xpcall(love.boot, error_printer) if not result then return 1 end - local result = xpcall(love.init, love._release and love.releaseerrhand or love.errhand) + local result = xpcall(love.init, deferErrhand) if not result then return 1 end - local result, retval = xpcall(love.run, love._release and love.releaseerrhand or love.errhand) + local result, retval = xpcall(love.run, deferErrhand) if not result then return 1 end return tonumber(retval) or 0 diff --git a/src/scripts/boot.lua.h b/src/scripts/boot.lua.h index 9156b20f3..f1b0244be 100644 --- a/src/scripts/boot.lua.h +++ b/src/scripts/boot.lua.h @@ -1667,8 +1667,8 @@ const unsigned char boot_lua[] = 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x0a, - 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x65, 0x62, 0x75, 0x67, 0x20, 0x3d, 0x20, 0x64, 0x65, 0x62, 0x75, - 0x67, 0x0a, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2c, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, + 0x20, 0x3d, 0x20, 0x64, 0x65, 0x62, 0x75, 0x67, 0x2c, 0x20, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x0a, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, 0x28, 0x6d, 0x73, 0x67, 0x2c, 0x20, 0x6c, 0x61, 0x79, 0x65, 0x72, 0x29, 0x0a, @@ -1845,6 +1845,17 @@ const unsigned char boot_lua[] = 0x09, 0x09, 0x64, 0x72, 0x61, 0x77, 0x28, 0x29, 0x0a, 0x09, 0x65, 0x6e, 0x64, 0x0a, 0x65, 0x6e, 0x64, 0x0a, + 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x66, 0x75, 0x6e, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x64, 0x65, 0x66, + 0x65, 0x72, 0x45, 0x72, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x28, 0x2e, 0x2e, 0x2e, 0x29, 0x0a, + 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x20, 0x3d, 0x20, 0x28, + 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x61, 0x6e, 0x64, + 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x65, 0x72, 0x72, 0x68, 0x61, + 0x6e, 0x64, 0x29, 0x20, 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x72, 0x72, 0x68, 0x61, 0x6e, + 0x64, 0x20, 0x6f, 0x72, 0x20, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x5f, 0x70, 0x72, 0x69, 0x6e, 0x74, 0x65, 0x72, + 0x29, 0x0a, + 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x68, 0x61, 0x6e, 0x64, 0x6c, 0x65, 0x72, 0x28, 0x2e, 0x2e, + 0x2e, 0x29, 0x0a, + 0x65, 0x6e, 0x64, 0x0a, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, 0x2d, @@ -1862,18 +1873,13 @@ const unsigned char boot_lua[] = 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x3d, 0x20, 0x78, 0x70, - 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x2c, 0x20, 0x6c, 0x6f, - 0x76, 0x65, 0x2e, 0x5f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, - 0x76, 0x65, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x65, 0x72, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x20, - 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x72, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x29, 0x0a, + 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x69, 0x6e, 0x69, 0x74, 0x2c, 0x20, 0x64, 0x65, + 0x66, 0x65, 0x72, 0x45, 0x72, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x29, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x2c, 0x20, 0x72, 0x65, 0x74, 0x76, 0x61, 0x6c, 0x20, 0x3d, 0x20, 0x78, 0x70, 0x63, 0x61, 0x6c, 0x6c, 0x28, 0x6c, 0x6f, 0x76, 0x65, 0x2e, - 0x72, 0x75, 0x6e, 0x2c, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x5f, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, - 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x72, 0x65, 0x6c, 0x65, 0x61, 0x73, 0x65, 0x65, - 0x72, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x72, 0x20, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x65, 0x72, 0x72, - 0x68, 0x61, 0x6e, 0x64, 0x29, 0x0a, + 0x72, 0x75, 0x6e, 0x2c, 0x20, 0x64, 0x65, 0x66, 0x65, 0x72, 0x45, 0x72, 0x72, 0x68, 0x61, 0x6e, 0x64, 0x29, 0x0a, 0x09, 0x69, 0x66, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x72, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x20, 0x74, 0x68, 0x65, 0x6e, 0x20, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x31, 0x20, 0x65, 0x6e, 0x64, 0x0a, 0x09, 0x72, 0x65, 0x74, 0x75, 0x72, 0x6e, 0x20, 0x74, 0x6f, 0x6e, 0x75, 0x6d, 0x62, 0x65, 0x72, 0x28, 0x72, From 84b6eedf1fa853ca6ed60d2307b2006fafd642bf Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Fri, 18 Jan 2013 12:43:43 +0100 Subject: [PATCH 18/20] Make the default point style to setPoint 'smooth' (issue #543), and fix setPointStyle ignoring normal operation --- src/modules/graphics/opengl/wrap_Graphics.cpp | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 4ad88f0a9..4ff95ca86 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -712,14 +712,11 @@ int w_setPointSize(lua_State *L) int w_setPointStyle(lua_State *L) { - Graphics::PointStyle style = Graphics::POINT_SMOOTH; + Graphics::PointStyle style; - if (lua_gettop(L) >= 2) - { - const char *str = luaL_checkstring(L, 1); - if (!Graphics::getConstant(str, style)) - return luaL_error(L, "Invalid point style: %s", str); - } + const char *str = luaL_checkstring(L, 1); + if (!Graphics::getConstant(str, style)) + return luaL_error(L, "Invalid point style: %s", str); instance->setPointStyle(style); return 0; @@ -729,10 +726,14 @@ int w_setPoint(lua_State *L) { float size = (float)luaL_checknumber(L, 1); - Graphics::PointStyle style; - const char *str = luaL_checkstring(L, 2); - if (!Graphics::getConstant(str, style)) - return luaL_error(L, "Invalid point style: %s", str); + Graphics::PointStyle style = Graphics::POINT_SMOOTH; + + if (lua_gettop(L) >= 2) + { + const char *str = luaL_checkstring(L, 2); + if (!Graphics::getConstant(str, style)) + return luaL_error(L, "Invalid point style: %s", str); + } instance->setPoint(size, style); return 0; From 32684b674ef09449367a6d19165ddea509d1b524 Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Fri, 18 Jan 2013 13:20:40 +0100 Subject: [PATCH 19/20] Add Font:getAscent/getDescent/getBaseline (issue #445) --- src/modules/graphics/opengl/Font.cpp | 19 ++++++++++++++++-- src/modules/graphics/opengl/Font.h | 5 +++++ src/modules/graphics/opengl/wrap_Font.cpp | 24 +++++++++++++++++++++++ src/modules/graphics/opengl/wrap_Font.h | 3 +++ 4 files changed, 49 insertions(+), 2 deletions(-) diff --git a/src/modules/graphics/opengl/Font.cpp b/src/modules/graphics/opengl/Font.cpp index d7f511188..7d4195ef8 100644 --- a/src/modules/graphics/opengl/Font.cpp +++ b/src/modules/graphics/opengl/Font.cpp @@ -291,8 +291,7 @@ void Font::print(const std::string &text, float x, float y, float letter_spacing // copy glyphquad (4 vertices) from original glyph to our current quad list glyphquads.push_back(glyph->quad); - // 1.25 is magic line height for true type fonts - float lineheight = (type == FONT_TRUETYPE) ? floor(getHeight() / 1.25f + 0.5f) : 0.0f; + float lineheight = getBaseline(); // set proper relative position for (int i = 0; i < 4; i++) @@ -592,6 +591,22 @@ void Font::unloadVolatile() textures.clear(); } +int Font::getAscent() const +{ + return rasterizer->getAscent(); +} + +int Font::getDescent() const +{ + return rasterizer->getDescent(); +} + +float Font::getBaseline() const +{ + // 1.25 is magic line height for true type fonts + return (type == FONT_TRUETYPE) ? floor(getHeight() / 1.25f + 0.5f) : 0.0f; +} + } // opengl } // graphics } // love diff --git a/src/modules/graphics/opengl/Font.h b/src/modules/graphics/opengl/Font.h index 73baccd9b..c29372346 100644 --- a/src/modules/graphics/opengl/Font.h +++ b/src/modules/graphics/opengl/Font.h @@ -136,6 +136,11 @@ public: bool loadVolatile(); void unloadVolatile(); + // Extra font metrics + int getAscent() const; + int getDescent() const; + float getBaseline() const; + private: enum FontType diff --git a/src/modules/graphics/opengl/wrap_Font.cpp b/src/modules/graphics/opengl/wrap_Font.cpp index 5306a10e3..ce1566a40 100644 --- a/src/modules/graphics/opengl/wrap_Font.cpp +++ b/src/modules/graphics/opengl/wrap_Font.cpp @@ -162,6 +162,27 @@ int w_Font_getMipmapSharpness(lua_State *L) return 1; } +int w_Font_getAscent(lua_State *L) +{ + Font *t = luax_checkfont(L, 1); + lua_pushnumber(L, t->getAscent()); + return 1; +} + +int w_Font_getDescent(lua_State *L) +{ + Font *t = luax_checkfont(L, 1); + lua_pushnumber(L, t->getDescent()); + return 1; +} + +int w_Font_getBaseline(lua_State *L) +{ + Font *t = luax_checkfont(L, 1); + lua_pushnumber(L, t->getBaseline()); + return 1; +} + static const luaL_Reg functions[] = { { "getHeight", w_Font_getHeight }, @@ -173,6 +194,9 @@ static const luaL_Reg functions[] = { "getFilter", w_Font_getFilter }, { "setMipmapSharpness", w_Font_setMipmapSharpness }, { "getMipmapSharpness", w_Font_getMipmapSharpness }, + { "getAscent", w_Font_getAscent }, + { "getDescent", w_Font_getDescent }, + { "getBaseline", w_Font_getBaseline }, { 0, 0 } }; diff --git a/src/modules/graphics/opengl/wrap_Font.h b/src/modules/graphics/opengl/wrap_Font.h index a64be5863..28dca46de 100644 --- a/src/modules/graphics/opengl/wrap_Font.h +++ b/src/modules/graphics/opengl/wrap_Font.h @@ -42,6 +42,9 @@ int w_Font_setFilter(lua_State *L); int w_Font_getFilter(lua_State *L); int w_Font_setMipmapSharpness(lua_State *L); int w_Font_getMipmapSharpness(lua_State *L); +int w_Font_getAscent(lua_State *L); +int w_Font_getDescent(lua_State *L); +int w_Font_getBaseline(lua_State *L); extern "C" int luaopen_font(lua_State *L); } // opengl From 4221d554684907589d885d4eba930a7556fb9a7d Mon Sep 17 00:00:00 2001 From: Bart van Strien Date: Fri, 18 Jan 2013 21:03:07 +0100 Subject: [PATCH 20/20] Enfore limits on ParticleSystem:setSizeVariation (issue #545) --- src/modules/graphics/opengl/wrap_ParticleSystem.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp index 69df1c67f..0843cc470 100644 --- a/src/modules/graphics/opengl/wrap_ParticleSystem.cpp +++ b/src/modules/graphics/opengl/wrap_ParticleSystem.cpp @@ -192,6 +192,9 @@ int w_ParticleSystem_setSizeVariation(lua_State *L) { ParticleSystem *t = luax_checkparticlesystem(L, 1); float arg1 = (float)luaL_checknumber(L, 2); + if (arg1 < 0.0f || arg1 > 1.0f) + return luaL_error(L, "Size variation has to be between 0 and 1, inclusive."); + t->setSizeVariation(arg1); return 0; }