Merged in slime73/love-mipmap (pull request #18: Add mipmapping support to images)

This commit is contained in:
vrld
2013-01-12 23:54:15 +01:00
20 changed files with 672 additions and 318 deletions
+1
View File
@@ -160,6 +160,7 @@ StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM>::Entry Graphics::suppor
{ "pixeleffect", Graphics::SUPPORT_PIXELEFFECT },
{ "npot", Graphics::SUPPORT_NPOT },
{ "subtractive", Graphics::SUPPORT_SUBTRACTIVE },
{ "mipmap", Graphics::SUPPORT_MIPMAP },
};
StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM> Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries));
+1
View File
@@ -89,6 +89,7 @@ public:
SUPPORT_PIXELEFFECT,
SUPPORT_NPOT,
SUPPORT_SUBTRACTIVE,
SUPPORT_MIPMAP,
SUPPORT_MAX_ENUM
};
+13
View File
@@ -25,9 +25,12 @@ namespace love
namespace graphics
{
Image::Filter Image::defaultFilter;
Image::Filter::Filter()
: min(FILTER_LINEAR)
, mag(FILTER_LINEAR)
, mipmap(FILTER_NONE)
{
}
@@ -41,6 +44,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);
+9
View File
@@ -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
@@ -65,6 +67,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);
static bool getConstant(const char *in, WrapMode &out);
@@ -72,6 +78,9 @@ public:
private:
// The default image filter
static Filter defaultFilter;
static StringMap<FilterMode, FILTER_MAX_ENUM>::Entry filterModeEntries[];
static StringMap<FilterMode, FILTER_MAX_ENUM> filterModes;
static StringMap<WrapMode, WRAP_MAX_ENUM>::Entry wrapModeEntries[];
+14 -35
View File
@@ -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);
@@ -312,6 +314,8 @@ Canvas::Canvas(int width, int height, TextureType texture_type)
vertices[3].s = 1;
vertices[3].t = 0;
settings.filter = Image::getDefaultFilter();
getStrategy();
loadVolatile();
@@ -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()
+92 -19
View File
@@ -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 <math.h>
#include <sstream>
#include <algorithm> // for max
namespace love
@@ -48,9 +48,8 @@ Font::Font(love::font::Rasterizer *r, const Image::Filter &filter)
, lineHeight(1)
, mSpacing(1)
, filter(filter)
, mipmapsharpness(0.0f)
{
r->retain();
love::font::GlyphData *gd = r->getGlyphData(32);
type = (gd->getFormat() == love::font::GlyphData::FORMAT_LUMINANCE_ALPHA ? FONT_TRUETYPE : FONT_IMAGE);
delete gd;
@@ -72,15 +71,9 @@ Font::Font(love::font::Rasterizer *r, const Image::Filter &filter)
texture_width = TEXTURE_WIDTHS[texture_size_index];
texture_height = TEXTURE_HEIGHTS[texture_size_index];
try
{
createTexture();
}
catch (love::Exception &e)
{
r->release();
throw;
}
loadVolatile();
r->retain();
}
Font::~Font()
@@ -116,16 +109,16 @@ void Font::createTexture()
GLuint t;
glGenTextures(1, &t);
textures.push_back(t);
bindTexture(t);
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);
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);
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;
@@ -162,6 +155,9 @@ void Font::createTexture()
format,
GL_UNSIGNED_BYTE,
&emptyData[0]);
setFilter(filter);
setMipmapSharpness(mipmapsharpness);
}
Font::Glyph *Font::addGlyph(const int glyph)
@@ -326,7 +322,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;
@@ -493,8 +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<GLubyte> 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<GLuint>::const_iterator it;
for (it = textures.begin(); it != textures.end(); ++it)
{
bindTexture(*it);
checkMipmapsCreated();
setTextureFilter(f);
}
}
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<GLuint>::const_iterator it;
for (it = textures.begin(); it != textures.end(); ++it)
{
bindTexture(*it);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapsharpness); // negative bias is sharper
}
}
float Font::getMipmapSharpness() const
{
return mipmapsharpness;
}
bool Font::loadVolatile()
{
if (Image::hasMipmapSharpnessSupport())
glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxmipmapsharpness);
createTexture();
return true;
}
+15 -1
View File
@@ -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();
@@ -126,6 +126,12 @@ public:
**/
float getSpacing() const;
void setFilter(const Image::Filter &f);
const Image::Filter &getFilter();
void setMipmapSharpness(float sharpness);
float getMipmapSharpness() const;
// Implements Volatile.
bool loadVolatile();
void unloadVolatile();
@@ -193,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);
+7 -7
View File
@@ -339,10 +339,10 @@ Image *Graphics::newImage(love::image::ImageData *data)
{
success = image->load();
}
catch(love::Exception &e)
catch(love::Exception &)
{
image->release();
throw love::Exception(e.what());
throw;
}
if (!success)
{
@@ -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();
+77 -134
View File
@@ -22,9 +22,9 @@
// STD
#include <cstring> // For memcpy
#include <algorithm> // for min/max
#include <iostream>
using namespace std;
namespace love
{
@@ -33,12 +33,11 @@ namespace graphics
namespace opengl
{
Image::Filter Image::defaultFilter;
Image::Image(love::image::ImageData *data)
: width((float)(data->getWidth()))
, height((float)(data->getHeight()))
, texture(0)
, mipmapsharpness(0.0f)
{
data->retain();
this->data = data;
@@ -63,7 +62,7 @@ Image::Image(love::image::ImageData *data)
vertices[3].s = 1;
vertices[3].t = 0;
settings.filter = defaultFilter;
filter = getDefaultFilter();
}
Image::~Image()
@@ -144,143 +143,82 @@ 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)
{
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;
}
filter = f;
bind();
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gmin);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gmag);
checkMipmapsCreated();
setTextureFilter(f);
}
Image::Filter Image::getFilter() const
const 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 filter;
}
void Image::setWrap(Image::Wrap w)
void Image::setWrap(const 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;
}
wrap = w;
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
const Image::Wrap &Image::getWrap() const
{
return wrap;
}
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
}
GLint gs, gt;
glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &gs);
glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, &gt);
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;
float Image::getMipmapSharpness() const
{
return mipmapsharpness;
}
void Image::bind() const
@@ -303,6 +241,9 @@ void Image::unload()
bool Image::loadVolatile()
{
if (hasMipmapSharpnessSupport())
glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxmipmapsharpness);
if (hasNpot())
return loadVolatileNPOT();
else
@@ -313,6 +254,7 @@ 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);
@@ -349,8 +291,9 @@ bool Image::loadVolatilePOT()
GL_UNSIGNED_BYTE,
data->getData());
setFilter(settings.filter);
setWrap(settings.wrap);
setMipmapSharpness(mipmapsharpness);
setFilter(filter);
setWrap(wrap);
return true;
}
@@ -359,6 +302,7 @@ 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);
@@ -375,16 +319,15 @@ bool Image::loadVolatileNPOT()
GL_UNSIGNED_BYTE,
data->getData());
setFilter(settings.filter);
setWrap(settings.wrap);
setMipmapSharpness(mipmapsharpness);
setFilter(filter);
setWrap(wrap);
return true;
}
void Image::unloadVolatile()
{
settings.filter = getFilter();
settings.wrap = getWrap();
// Delete the hardware texture.
if (texture != 0)
{
@@ -417,14 +360,14 @@ bool Image::hasNpot()
return GLEE_ARB_texture_non_power_of_two != 0;
}
void Image::setDefaultFilter(const Image::Filter &f)
bool Image::hasMipmapSupport()
{
defaultFilter = f;
return (GLEE_VERSION_1_4 || GLEE_SGIS_generate_mipmap) != 0;
}
const Image::Filter &Image::getDefaultFilter()
bool Image::hasMipmapSharpnessSupport()
{
return defaultFilter;
return (GLEE_VERSION_1_4 || GLEE_EXT_texture_lod_bias) != 0;
}
} // opengl
+20 -15
View File
@@ -96,16 +96,19 @@ public:
/**
* Sets the filter mode.
*
* @param mode The filter mode.
* @param f The filter mode.
**/
void setFilter(const Image::Filter &f);
Image::Filter getFilter() const;
const Image::Filter &getFilter() const;
void setWrap(Image::Wrap r);
void setWrap(const Image::Wrap &w);
Image::Wrap getWrap() const;
const Image::Wrap &getWrap() const;
void setMipmapSharpness(float sharpness);
float getMipmapSharpness() const;
void bind() const;
@@ -117,10 +120,8 @@ public:
void unloadVolatile();
static bool hasNpot();
// The default filter.
static void setDefaultFilter(const Image::Filter &f);
static const Image::Filter &getDefaultFilter();
static bool hasMipmapSupport();
static bool hasMipmapSharpnessSupport();
private:
@@ -143,18 +144,22 @@ private:
// The source vertices of the image.
vertex vertices[4];
// The settings we need to save when reloading.
struct
{
// 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;
} settings;
bool loadVolatilePOT();
bool loadVolatileNPOT();
// The default image filter
static Image::Filter defaultFilter;
void checkMipmapsCreated() const;
}; // Image
+154
View File
@@ -52,6 +52,160 @@ void deleteTexture(GLuint texture)
glDeleteTextures(1, &texture);
}
void setTextureFilter(const graphics::Image::Filter &f)
{
GLint gmin, gmag;
if (f.mipmap == Image::FILTER_NONE)
{
if (f.min == Image::FILTER_NEAREST)
gmin = GL_NEAREST;
else // f.min == Image::FILTER_LINEAR
gmin = GL_LINEAR;
}
else
{
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 == Image::FILTER_LINEAR && f.mipmap == Image::FILTER_LINEAR)
gmin = GL_LINEAR_MIPMAP_LINEAR;
else
gmin = GL_LINEAR;
}
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;
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;
}
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, &gt);
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
+23
View File
@@ -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
@@ -491,7 +491,8 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo
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;
+19 -12
View File
@@ -67,23 +67,27 @@ int w_Canvas_getImageData(lua_State *L)
int w_Canvas_setFilter(lua_State *L)
{
Canvas *canvas = luax_checkcanvas(L, 1);
const char *minstr = luaL_checkstring(L, 2);
const char *magstr = luaL_checkstring(L, 3);
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 min filter mode: %s", minstr);
return luaL_error(L, "Invalid filter mode: %s", minstr);
if (!Image::getConstant(magstr, f.mag))
return luaL_error(L, "Invalid max filter mode: %s", magstr);
return luaL_error(L, "Invalid filter mode: %s", magstr);
canvas->setFilter(f);
return 0;
}
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;
@@ -99,23 +103,26 @@ 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::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);
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;
}
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;
+76
View File
@@ -90,6 +90,78 @@ int w_Font_getLineHeight(lua_State *L)
return 1;
}
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);
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;
}
int w_Font_getFilter(lua_State *L)
{
Font *t = luax_checkfont(L, 1);
const Image::Filter f = t->getFilter();
const char *minstr;
const char *magstr;
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
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[] =
{
{ "getHeight", w_Font_getHeight },
@@ -97,6 +169,10 @@ 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 },
{ "setMipmapSharpness", w_Font_setMipmapSharpness },
{ "getMipmapSharpness", w_Font_getMipmapSharpness },
{ 0, 0 }
};
+4
View File
@@ -38,6 +38,10 @@ 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);
int w_Font_setMipmapSharpness(lua_State *L);
int w_Font_getMipmapSharpness(lua_State *L);
extern "C" int luaopen_font(lua_State *L);
} // opengl
@@ -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;
@@ -850,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;
+61 -23
View File
@@ -50,71 +50,107 @@ 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))
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);
f.min = min;
f.mag = mag;
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;
}
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;
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;
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))
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);
w.s = s;
w.t = t;
i->setWrap(w);
return 0;
}
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);
lua_pushnumber(L, i->getMipmapSharpness());
return 1;
}
static const luaL_Reg functions[] =
{
{ "getWidth", w_Image_getWidth },
@@ -123,6 +159,8 @@ static const luaL_Reg functions[] =
{ "getFilter", w_Image_getFilter },
{ "setWrap", w_Image_setWrap },
{ "getWrap", w_Image_getWrap },
{ "setMipmapSharpness", w_Image_setMipmapSharpness },
{ "getMipmapSharpness", w_Image_getMipmapSharpness },
{ 0, 0 }
};
+5
View File
@@ -36,6 +36,11 @@ 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_setMipmapSharpness(lua_State *L);
int w_Image_getMipmapSharpness(lua_State *L);
extern "C" int luaopen_image(lua_State *L);
} // opengl