From 1678252b7a4e49fca9e892500523d835d463adaa Mon Sep 17 00:00:00 2001 From: Alexander Szpakowski Date: Tue, 1 Jan 2013 21:29:38 -0400 Subject: [PATCH 01/13] =?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/13] 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/13] 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/13] 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/13] 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/13] 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/13] 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/13] 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/13] 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/13] 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/13] 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/13] 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 697f4de80aacc81dfcd3ad5df9ebd658c360fce3 Mon Sep 17 00:00:00 2001 From: rude Date: Sat, 12 Jan 2013 11:28:32 +0100 Subject: [PATCH 13/13] Fix compilation issue in MSVC2012. --- src/modules/graphics/opengl/VertexBuffer.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/modules/graphics/opengl/VertexBuffer.cpp b/src/modules/graphics/opengl/VertexBuffer.cpp index 8837ea5f5..d3ffc6172 100644 --- a/src/modules/graphics/opengl/VertexBuffer.cpp +++ b/src/modules/graphics/opengl/VertexBuffer.cpp @@ -28,6 +28,11 @@ #include #include +// Conflicts with std::numeric_limits::max() (Windows). +#ifdef max +# undef max +#endif + namespace love { namespace graphics