mirror of
https://github.com/love2d/love.git
synced 2026-08-19 12:14:20 +02:00
Merged in slime73/love-mipmap (pull request #18: Add mipmapping support to images)
This commit is contained in:
@@ -160,6 +160,7 @@ StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM>::Entry Graphics::suppor
|
|||||||
{ "pixeleffect", Graphics::SUPPORT_PIXELEFFECT },
|
{ "pixeleffect", Graphics::SUPPORT_PIXELEFFECT },
|
||||||
{ "npot", Graphics::SUPPORT_NPOT },
|
{ "npot", Graphics::SUPPORT_NPOT },
|
||||||
{ "subtractive", Graphics::SUPPORT_SUBTRACTIVE },
|
{ "subtractive", Graphics::SUPPORT_SUBTRACTIVE },
|
||||||
|
{ "mipmap", Graphics::SUPPORT_MIPMAP },
|
||||||
};
|
};
|
||||||
|
|
||||||
StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM> Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries));
|
StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM> Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries));
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ public:
|
|||||||
SUPPORT_PIXELEFFECT,
|
SUPPORT_PIXELEFFECT,
|
||||||
SUPPORT_NPOT,
|
SUPPORT_NPOT,
|
||||||
SUPPORT_SUBTRACTIVE,
|
SUPPORT_SUBTRACTIVE,
|
||||||
|
SUPPORT_MIPMAP,
|
||||||
SUPPORT_MAX_ENUM
|
SUPPORT_MAX_ENUM
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -25,9 +25,12 @@ namespace love
|
|||||||
namespace graphics
|
namespace graphics
|
||||||
{
|
{
|
||||||
|
|
||||||
|
Image::Filter Image::defaultFilter;
|
||||||
|
|
||||||
Image::Filter::Filter()
|
Image::Filter::Filter()
|
||||||
: min(FILTER_LINEAR)
|
: min(FILTER_LINEAR)
|
||||||
, mag(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)
|
bool Image::getConstant(const char *in, FilterMode &out)
|
||||||
{
|
{
|
||||||
return filterModes.find(in, out);
|
return filterModes.find(in, out);
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ public:
|
|||||||
{
|
{
|
||||||
FILTER_LINEAR = 1,
|
FILTER_LINEAR = 1,
|
||||||
FILTER_NEAREST,
|
FILTER_NEAREST,
|
||||||
|
FILTER_NONE,
|
||||||
FILTER_MAX_ENUM
|
FILTER_MAX_ENUM
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -54,6 +55,7 @@ public:
|
|||||||
Filter();
|
Filter();
|
||||||
FilterMode min;
|
FilterMode min;
|
||||||
FilterMode mag;
|
FilterMode mag;
|
||||||
|
FilterMode mipmap;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Wrap
|
struct Wrap
|
||||||
@@ -64,6 +66,10 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
virtual ~Image();
|
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(const char *in, FilterMode &out);
|
||||||
static bool getConstant(FilterMode in, const char *&out);
|
static bool getConstant(FilterMode in, const char *&out);
|
||||||
@@ -72,6 +78,9 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
|
// The default image filter
|
||||||
|
static Filter defaultFilter;
|
||||||
|
|
||||||
static StringMap<FilterMode, FILTER_MAX_ENUM>::Entry filterModeEntries[];
|
static StringMap<FilterMode, FILTER_MAX_ENUM>::Entry filterModeEntries[];
|
||||||
static StringMap<FilterMode, FILTER_MAX_ENUM> filterModes;
|
static StringMap<FilterMode, FILTER_MAX_ENUM> filterModes;
|
||||||
static StringMap<WrapMode, WRAP_MAX_ENUM>::Entry wrapModeEntries[];
|
static StringMap<WrapMode, WRAP_MAX_ENUM>::Entry wrapModeEntries[];
|
||||||
|
|||||||
@@ -97,8 +97,9 @@ struct FramebufferStrategyGL3 : public FramebufferStrategy
|
|||||||
|
|
||||||
glGenTextures(1, &img);
|
glGenTextures(1, &img);
|
||||||
bindTexture(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,
|
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height,
|
||||||
0, GL_RGBA, format, NULL);
|
0, GL_RGBA, format, NULL);
|
||||||
bindTexture(0);
|
bindTexture(0);
|
||||||
@@ -164,8 +165,8 @@ struct FramebufferStrategyPackedEXT : public FramebufferStrategy
|
|||||||
|
|
||||||
glGenTextures(1, &img);
|
glGenTextures(1, &img);
|
||||||
bindTexture(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,
|
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height,
|
||||||
0, GL_RGBA, format, NULL);
|
0, GL_RGBA, format, NULL);
|
||||||
@@ -231,8 +232,9 @@ struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT
|
|||||||
|
|
||||||
glGenTextures(1, &img);
|
glGenTextures(1, &img);
|
||||||
bindTexture(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,
|
glTexImage2D(GL_TEXTURE_2D, 0, internalFormat, width, height,
|
||||||
0, GL_RGBA, format, NULL);
|
0, GL_RGBA, format, NULL);
|
||||||
bindTexture(0);
|
bindTexture(0);
|
||||||
@@ -312,6 +314,8 @@ Canvas::Canvas(int width, int height, TextureType texture_type)
|
|||||||
vertices[3].s = 1;
|
vertices[3].s = 1;
|
||||||
vertices[3].t = 0;
|
vertices[3].t = 0;
|
||||||
|
|
||||||
|
settings.filter = Image::getDefaultFilter();
|
||||||
|
|
||||||
getStrategy();
|
getStrategy();
|
||||||
|
|
||||||
loadVolatile();
|
loadVolatile();
|
||||||
@@ -456,51 +460,26 @@ love::image::ImageData *Canvas::getImageData(love::image::Image *image)
|
|||||||
|
|
||||||
void Canvas::setFilter(const Image::Filter &f)
|
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);
|
bindTexture(img);
|
||||||
|
setTextureFilter(f);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gmin);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gmag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Image::Filter Canvas::getFilter() const
|
Image::Filter Canvas::getFilter() const
|
||||||
{
|
{
|
||||||
GLint gmin, gmag;
|
|
||||||
|
|
||||||
bindTexture(img);
|
bindTexture(img);
|
||||||
glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, &gmin);
|
return getTextureFilter();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Canvas::setWrap(const Image::Wrap &w)
|
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);
|
bindTexture(img);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, wrap_s);
|
setTextureWrap(w);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, wrap_t);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Image::Wrap Canvas::getWrap() const
|
Image::Wrap Canvas::getWrap() const
|
||||||
{
|
{
|
||||||
GLint wrap_s, wrap_t;
|
|
||||||
bindTexture(img);
|
bindTexture(img);
|
||||||
glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &wrap_s);
|
return getTextureWrap();
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Canvas::loadVolatile()
|
bool Canvas::loadVolatile()
|
||||||
|
|||||||
@@ -21,15 +21,15 @@
|
|||||||
#include "Font.h"
|
#include "Font.h"
|
||||||
#include "font/GlyphData.h"
|
#include "font/GlyphData.h"
|
||||||
#include "Quad.h"
|
#include "Quad.h"
|
||||||
|
#include "Image.h"
|
||||||
|
|
||||||
#include "libraries/utf8/utf8.h"
|
#include "libraries/utf8/utf8.h"
|
||||||
|
|
||||||
#include "common/math.h"
|
#include "common/math.h"
|
||||||
#include "common/Matrix.h"
|
#include "common/Matrix.h"
|
||||||
|
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
#include <algorithm> // for max
|
#include <algorithm> // for max
|
||||||
|
|
||||||
namespace love
|
namespace love
|
||||||
@@ -39,8 +39,8 @@ namespace graphics
|
|||||||
namespace opengl
|
namespace opengl
|
||||||
{
|
{
|
||||||
|
|
||||||
const int Font::TEXTURE_WIDTHS[] = {128, 256, 256, 512, 512, 1024, 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};
|
const int Font::TEXTURE_HEIGHTS[] = {128, 128, 256, 256, 512, 512, 1024};
|
||||||
|
|
||||||
Font::Font(love::font::Rasterizer *r, const Image::Filter &filter)
|
Font::Font(love::font::Rasterizer *r, const Image::Filter &filter)
|
||||||
: rasterizer(r)
|
: rasterizer(r)
|
||||||
@@ -48,13 +48,12 @@ Font::Font(love::font::Rasterizer *r, const Image::Filter &filter)
|
|||||||
, lineHeight(1)
|
, lineHeight(1)
|
||||||
, mSpacing(1)
|
, mSpacing(1)
|
||||||
, filter(filter)
|
, filter(filter)
|
||||||
|
, mipmapsharpness(0.0f)
|
||||||
{
|
{
|
||||||
r->retain();
|
|
||||||
|
|
||||||
love::font::GlyphData *gd = r->getGlyphData(32);
|
love::font::GlyphData *gd = r->getGlyphData(32);
|
||||||
type = (gd->getFormat() == love::font::GlyphData::FORMAT_LUMINANCE_ALPHA ? FONT_TRUETYPE : FONT_IMAGE);
|
type = (gd->getFormat() == love::font::GlyphData::FORMAT_LUMINANCE_ALPHA ? FONT_TRUETYPE : FONT_IMAGE);
|
||||||
delete gd;
|
delete gd;
|
||||||
|
|
||||||
// try to find the best texture size match for the font size
|
// try to find the best texture size match for the font size
|
||||||
// default to the largest texture size if no rough match is found
|
// default to the largest texture size if no rough match is found
|
||||||
texture_size_index = NUM_TEXTURE_SIZES - 1;
|
texture_size_index = NUM_TEXTURE_SIZES - 1;
|
||||||
@@ -68,19 +67,13 @@ Font::Font(love::font::Rasterizer *r, const Image::Filter &filter)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
texture_width = TEXTURE_WIDTHS[texture_size_index];
|
texture_width = TEXTURE_WIDTHS[texture_size_index];
|
||||||
texture_height = TEXTURE_HEIGHTS[texture_size_index];
|
texture_height = TEXTURE_HEIGHTS[texture_size_index];
|
||||||
|
|
||||||
try
|
loadVolatile();
|
||||||
{
|
|
||||||
createTexture();
|
r->retain();
|
||||||
}
|
|
||||||
catch (love::Exception &e)
|
|
||||||
{
|
|
||||||
r->release();
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Font::~Font()
|
Font::~Font()
|
||||||
@@ -92,10 +85,10 @@ Font::~Font()
|
|||||||
bool Font::initializeTexture(GLint format)
|
bool Font::initializeTexture(GLint format)
|
||||||
{
|
{
|
||||||
GLint internalformat = (format == GL_LUMINANCE_ALPHA) ? GL_LUMINANCE8_ALPHA8 : GL_RGBA8;
|
GLint internalformat = (format == GL_LUMINANCE_ALPHA) ? GL_LUMINANCE8_ALPHA8 : GL_RGBA8;
|
||||||
|
|
||||||
// clear errors before initializing
|
// clear errors before initializing
|
||||||
while (glGetError() != GL_NO_ERROR);
|
while (glGetError() != GL_NO_ERROR);
|
||||||
|
|
||||||
glTexImage2D(GL_TEXTURE_2D,
|
glTexImage2D(GL_TEXTURE_2D,
|
||||||
0,
|
0,
|
||||||
internalformat,
|
internalformat,
|
||||||
@@ -105,50 +98,50 @@ bool Font::initializeTexture(GLint format)
|
|||||||
format,
|
format,
|
||||||
GL_UNSIGNED_BYTE,
|
GL_UNSIGNED_BYTE,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
return glGetError() == GL_NO_ERROR;
|
return glGetError() == GL_NO_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Font::createTexture()
|
void Font::createTexture()
|
||||||
{
|
{
|
||||||
texture_x = texture_y = rowHeight = TEXTURE_PADDING;
|
texture_x = texture_y = rowHeight = TEXTURE_PADDING;
|
||||||
|
|
||||||
GLuint t;
|
GLuint t;
|
||||||
glGenTextures(1, &t);
|
glGenTextures(1, &t);
|
||||||
textures.push_back(t);
|
textures.push_back(t);
|
||||||
|
|
||||||
bindTexture(t);
|
bindTexture(t);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER,
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
(filter.mag == Image::FILTER_LINEAR) ? GL_LINEAR : GL_NEAREST);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
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_S, GL_CLAMP_TO_EDGE);
|
||||||
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, 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
|
// try to initialize the texture, attempting smaller sizes if initialization fails
|
||||||
bool initialized = false;
|
bool initialized = false;
|
||||||
while (texture_size_index >= 0)
|
while (texture_size_index >= 0)
|
||||||
{
|
{
|
||||||
texture_width = TEXTURE_WIDTHS[texture_size_index];
|
texture_width = TEXTURE_WIDTHS[texture_size_index];
|
||||||
texture_height = TEXTURE_HEIGHTS[texture_size_index];
|
texture_height = TEXTURE_HEIGHTS[texture_size_index];
|
||||||
|
|
||||||
initialized = initializeTexture(format);
|
initialized = initializeTexture(format);
|
||||||
|
|
||||||
if (initialized || texture_size_index <= 0)
|
if (initialized || texture_size_index <= 0)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
--texture_size_index;
|
--texture_size_index;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!initialized)
|
if (!initialized)
|
||||||
{
|
{
|
||||||
// cleanup before throwing
|
// cleanup before throwing
|
||||||
deleteTexture(t);
|
deleteTexture(t);
|
||||||
bindTexture(0);
|
bindTexture(0);
|
||||||
textures.pop_back();
|
textures.pop_back();
|
||||||
|
|
||||||
throw love::Exception("Could not create font texture!");
|
throw love::Exception("Could not create font texture!");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -162,6 +155,9 @@ void Font::createTexture()
|
|||||||
format,
|
format,
|
||||||
GL_UNSIGNED_BYTE,
|
GL_UNSIGNED_BYTE,
|
||||||
&emptyData[0]);
|
&emptyData[0]);
|
||||||
|
|
||||||
|
setFilter(filter);
|
||||||
|
setMipmapSharpness(mipmapsharpness);
|
||||||
}
|
}
|
||||||
|
|
||||||
Font::Glyph *Font::addGlyph(const int glyph)
|
Font::Glyph *Font::addGlyph(const int glyph)
|
||||||
@@ -184,17 +180,17 @@ Font::Glyph *Font::addGlyph(const int glyph)
|
|||||||
}
|
}
|
||||||
|
|
||||||
Glyph *g = new Glyph;
|
Glyph *g = new Glyph;
|
||||||
|
|
||||||
g->texture = 0;
|
g->texture = 0;
|
||||||
g->spacing = gd->getAdvance();
|
g->spacing = gd->getAdvance();
|
||||||
|
|
||||||
memset(&g->quad, 0, sizeof(GlyphQuad));
|
memset(&g->quad, 0, sizeof(GlyphQuad));
|
||||||
|
|
||||||
// don't waste space for empty glyphs. also fixes a division by zero bug with ati drivers
|
// don't waste space for empty glyphs. also fixes a division by zero bug with ati drivers
|
||||||
if (w > 0 && h > 0)
|
if (w > 0 && h > 0)
|
||||||
{
|
{
|
||||||
const GLuint t = textures.back();
|
const GLuint t = textures.back();
|
||||||
|
|
||||||
bindTexture(t);
|
bindTexture(t);
|
||||||
glTexSubImage2D(GL_TEXTURE_2D,
|
glTexSubImage2D(GL_TEXTURE_2D,
|
||||||
0,
|
0,
|
||||||
@@ -212,10 +208,10 @@ Font::Glyph *Font::addGlyph(const int glyph)
|
|||||||
v.y = (float) texture_y;
|
v.y = (float) texture_y;
|
||||||
v.w = (float) w;
|
v.w = (float) w;
|
||||||
v.h = (float) h;
|
v.h = (float) h;
|
||||||
|
|
||||||
Quad q = Quad(v, (const float) texture_width, (const float) texture_height);
|
Quad q = Quad(v, (const float) texture_width, (const float) texture_height);
|
||||||
const vertex *verts = q.getVertices();
|
const vertex *verts = q.getVertices();
|
||||||
|
|
||||||
// copy vertex data to the glyph and set proper bearing
|
// copy vertex data to the glyph and set proper bearing
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
@@ -231,9 +227,9 @@ Font::Glyph *Font::addGlyph(const int glyph)
|
|||||||
rowHeight = std::max(rowHeight, h + TEXTURE_PADDING);
|
rowHeight = std::max(rowHeight, h + TEXTURE_PADDING);
|
||||||
|
|
||||||
delete gd;
|
delete gd;
|
||||||
|
|
||||||
glyphs[glyph] = g;
|
glyphs[glyph] = g;
|
||||||
|
|
||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -242,7 +238,7 @@ Font::Glyph *Font::findGlyph(const int glyph)
|
|||||||
Glyph *g = glyphs[glyph];
|
Glyph *g = glyphs[glyph];
|
||||||
if (!g)
|
if (!g)
|
||||||
g = addGlyph(glyph);
|
g = addGlyph(glyph);
|
||||||
|
|
||||||
return g;
|
return g;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -255,15 +251,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 dx = 0.0f; // spacing counter for newline handling
|
||||||
float dy = 0.0f;
|
float dy = 0.0f;
|
||||||
|
|
||||||
// keeps track of when we need to switch textures in our vertex array
|
// keeps track of when we need to switch textures in our vertex array
|
||||||
std::vector<GlyphArrayDrawInfo> glyphinfolist;
|
std::vector<GlyphArrayDrawInfo> glyphinfolist;
|
||||||
|
|
||||||
std::vector<GlyphQuad> glyphquads;
|
std::vector<GlyphQuad> glyphquads;
|
||||||
glyphquads.reserve(text.size()); // pre-allocate space for the maximum possible number of quads
|
glyphquads.reserve(text.size()); // pre-allocate space for the maximum possible number of quads
|
||||||
|
|
||||||
int quadindex = 0;
|
int quadindex = 0;
|
||||||
|
|
||||||
glPushMatrix();
|
glPushMatrix();
|
||||||
|
|
||||||
Matrix t;
|
Matrix t;
|
||||||
@@ -274,11 +270,11 @@ void Font::print(const std::string &text, float x, float y, float letter_spacing
|
|||||||
{
|
{
|
||||||
utf8::iterator<std::string::const_iterator> i(text.begin(), text.begin(), text.end());
|
utf8::iterator<std::string::const_iterator> i(text.begin(), text.begin(), text.end());
|
||||||
utf8::iterator<std::string::const_iterator> end(text.end(), text.begin(), text.end());
|
utf8::iterator<std::string::const_iterator> end(text.end(), text.begin(), text.end());
|
||||||
|
|
||||||
while (i != end)
|
while (i != end)
|
||||||
{
|
{
|
||||||
int g = *i++;
|
int g = *i++;
|
||||||
|
|
||||||
if (g == '\n')
|
if (g == '\n')
|
||||||
{
|
{
|
||||||
// wrap newline, but do not print it
|
// wrap newline, but do not print it
|
||||||
@@ -286,27 +282,27 @@ void Font::print(const std::string &text, float x, float y, float letter_spacing
|
|||||||
dx = 0.0f;
|
dx = 0.0f;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
Glyph *glyph = findGlyph(g);
|
Glyph *glyph = findGlyph(g);
|
||||||
|
|
||||||
// we only care about the vertices of glyphs which have a texture
|
// we only care about the vertices of glyphs which have a texture
|
||||||
if (glyph->texture != 0)
|
if (glyph->texture != 0)
|
||||||
{
|
{
|
||||||
// copy glyphquad (4 vertices) from original glyph to our current quad list
|
// copy glyphquad (4 vertices) from original glyph to our current quad list
|
||||||
glyphquads.push_back(glyph->quad);
|
glyphquads.push_back(glyph->quad);
|
||||||
|
|
||||||
// 1.25 is magic line height for true type fonts
|
// 1.25 is magic line height for true type fonts
|
||||||
float lineheight = (type == FONT_TRUETYPE) ? floor(getHeight() / 1.25f + 0.5f) : 0.0f;
|
float lineheight = (type == FONT_TRUETYPE) ? floor(getHeight() / 1.25f + 0.5f) : 0.0f;
|
||||||
|
|
||||||
// set proper relative position
|
// set proper relative position
|
||||||
for (int i = 0; i < 4; i++)
|
for (int i = 0; i < 4; i++)
|
||||||
{
|
{
|
||||||
glyphquads[quadindex].vertices[i].x += dx;
|
glyphquads[quadindex].vertices[i].x += dx;
|
||||||
glyphquads[quadindex].vertices[i].y += dy + lineheight;
|
glyphquads[quadindex].vertices[i].y += dy + lineheight;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t listsize = glyphinfolist.size();
|
size_t listsize = glyphinfolist.size();
|
||||||
|
|
||||||
// check if current glyph texture has changed since the previous iteration
|
// check if current glyph texture has changed since the previous iteration
|
||||||
if (listsize == 0 || glyphinfolist[listsize-1].texture != glyph->texture)
|
if (listsize == 0 || glyphinfolist[listsize-1].texture != glyph->texture)
|
||||||
{
|
{
|
||||||
@@ -317,16 +313,16 @@ void Font::print(const std::string &text, float x, float y, float letter_spacing
|
|||||||
glyphdrawinfo.texture = glyph->texture;
|
glyphdrawinfo.texture = glyph->texture;
|
||||||
glyphinfolist.push_back(glyphdrawinfo);
|
glyphinfolist.push_back(glyphdrawinfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
++quadindex;
|
++quadindex;
|
||||||
++glyphinfolist[glyphinfolist.size()-1].numquads;
|
++glyphinfolist[glyphinfolist.size()-1].numquads;
|
||||||
}
|
}
|
||||||
|
|
||||||
// advance the x position for the next glyph
|
// advance the x position for the next glyph
|
||||||
dx += glyph->spacing + letter_spacing;
|
dx += glyph->spacing + letter_spacing;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (love::Exception &e)
|
catch (love::Exception &)
|
||||||
{
|
{
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
throw;
|
throw;
|
||||||
@@ -338,32 +334,32 @@ void Font::print(const std::string &text, float x, float y, float letter_spacing
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (quadindex > 0 && glyphinfolist.size() > 0)
|
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)
|
// 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());
|
std::sort(glyphinfolist.begin(), glyphinfolist.end());
|
||||||
|
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
|
||||||
glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&glyphquads[0].vertices[0].x);
|
glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&glyphquads[0].vertices[0].x);
|
||||||
glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&glyphquads[0].vertices[0].s);
|
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
|
// 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<GlyphArrayDrawInfo>::const_iterator it;
|
std::vector<GlyphArrayDrawInfo>::const_iterator it;
|
||||||
for (it = glyphinfolist.begin(); it != glyphinfolist.end(); ++it)
|
for (it = glyphinfolist.begin(); it != glyphinfolist.end(); ++it)
|
||||||
{
|
{
|
||||||
bindTexture(it->texture);
|
bindTexture(it->texture);
|
||||||
|
|
||||||
int startvertex = it->startquad * 4;
|
int startvertex = it->startquad * 4;
|
||||||
int numvertices = it->numquads * 4;
|
int numvertices = it->numquads * 4;
|
||||||
|
|
||||||
glDrawArrays(GL_QUADS, startvertex, numvertices);
|
glDrawArrays(GL_QUADS, startvertex, numvertices);
|
||||||
}
|
}
|
||||||
|
|
||||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
}
|
}
|
||||||
|
|
||||||
glPopMatrix();
|
glPopMatrix();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -493,8 +489,85 @@ float Font::getSpacing() const
|
|||||||
return mSpacing;
|
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()
|
bool Font::loadVolatile()
|
||||||
{
|
{
|
||||||
|
if (Image::hasMipmapSharpnessSupport())
|
||||||
|
glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxmipmapsharpness);
|
||||||
|
|
||||||
createTexture();
|
createTexture();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,7 +49,7 @@ public:
|
|||||||
*
|
*
|
||||||
* @param data The font data to construct from.
|
* @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();
|
virtual ~Font();
|
||||||
|
|
||||||
@@ -126,10 +126,16 @@ public:
|
|||||||
**/
|
**/
|
||||||
float getSpacing() const;
|
float getSpacing() const;
|
||||||
|
|
||||||
|
void setFilter(const Image::Filter &f);
|
||||||
|
const Image::Filter &getFilter();
|
||||||
|
|
||||||
|
void setMipmapSharpness(float sharpness);
|
||||||
|
float getMipmapSharpness() const;
|
||||||
|
|
||||||
// Implements Volatile.
|
// Implements Volatile.
|
||||||
bool loadVolatile();
|
bool loadVolatile();
|
||||||
void unloadVolatile();
|
void unloadVolatile();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
enum FontType
|
enum FontType
|
||||||
@@ -151,13 +157,13 @@ private:
|
|||||||
int spacing;
|
int spacing;
|
||||||
GlyphQuad quad;
|
GlyphQuad quad;
|
||||||
};
|
};
|
||||||
|
|
||||||
// used to determine when to change textures in the vertex array generated when printing text
|
// used to determine when to change textures in the vertex array generated when printing text
|
||||||
struct GlyphArrayDrawInfo
|
struct GlyphArrayDrawInfo
|
||||||
{
|
{
|
||||||
GLuint texture;
|
GLuint texture;
|
||||||
int startquad, numquads;
|
int startquad, numquads;
|
||||||
|
|
||||||
// used when sorting with std::sort
|
// used when sorting with std::sort
|
||||||
// sorts by texture first (binding textures is expensive) and relative position in memory second
|
// sorts by texture first (binding textures is expensive) and relative position in memory second
|
||||||
bool operator < (const GlyphArrayDrawInfo &other) const
|
bool operator < (const GlyphArrayDrawInfo &other) const
|
||||||
@@ -174,16 +180,16 @@ private:
|
|||||||
int height;
|
int height;
|
||||||
float lineHeight;
|
float lineHeight;
|
||||||
float mSpacing; // modifies the spacing by multiplying it with this value
|
float mSpacing; // modifies the spacing by multiplying it with this value
|
||||||
|
|
||||||
int texture_size_index;
|
int texture_size_index;
|
||||||
int texture_width;
|
int texture_width;
|
||||||
int texture_height;
|
int texture_height;
|
||||||
|
|
||||||
std::vector<GLuint> textures; // vector of packed textures
|
std::vector<GLuint> textures; // vector of packed textures
|
||||||
std::map<int, Glyph *> glyphs; // maps glyphs to quad information
|
std::map<int, Glyph *> glyphs; // maps glyphs to quad information
|
||||||
FontType type;
|
FontType type;
|
||||||
Image::Filter filter;
|
Image::Filter filter;
|
||||||
|
|
||||||
static const int NUM_TEXTURE_SIZES = 7;
|
static const int NUM_TEXTURE_SIZES = 7;
|
||||||
static const int TEXTURE_WIDTHS[NUM_TEXTURE_SIZES];
|
static const int TEXTURE_WIDTHS[NUM_TEXTURE_SIZES];
|
||||||
static const int TEXTURE_HEIGHTS[NUM_TEXTURE_SIZES];
|
static const int TEXTURE_HEIGHTS[NUM_TEXTURE_SIZES];
|
||||||
@@ -193,6 +199,14 @@ private:
|
|||||||
int texture_x, texture_y;
|
int texture_x, texture_y;
|
||||||
int rowHeight;
|
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);
|
bool initializeTexture(GLint format);
|
||||||
void createTexture();
|
void createTexture();
|
||||||
Glyph *addGlyph(const int glyph);
|
Glyph *addGlyph(const int glyph);
|
||||||
|
|||||||
@@ -339,10 +339,10 @@ Image *Graphics::newImage(love::image::ImageData *data)
|
|||||||
{
|
{
|
||||||
success = image->load();
|
success = image->load();
|
||||||
}
|
}
|
||||||
catch(love::Exception &e)
|
catch(love::Exception &)
|
||||||
{
|
{
|
||||||
image->release();
|
image->release();
|
||||||
throw love::Exception(e.what());
|
throw;
|
||||||
}
|
}
|
||||||
if (!success)
|
if (!success)
|
||||||
{
|
{
|
||||||
@@ -567,11 +567,6 @@ void Graphics::setColorMode(Graphics::ColorMode mode)
|
|||||||
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_REPLACE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Graphics::setDefaultImageFilter(const Image::Filter &f)
|
|
||||||
{
|
|
||||||
Image::setDefaultFilter(f);
|
|
||||||
}
|
|
||||||
|
|
||||||
Graphics::BlendMode Graphics::getBlendMode()
|
Graphics::BlendMode Graphics::getBlendMode()
|
||||||
{
|
{
|
||||||
GLint dst, src, equation;
|
GLint dst, src, equation;
|
||||||
@@ -606,6 +601,11 @@ Graphics::ColorMode Graphics::getColorMode()
|
|||||||
return COLOR_REPLACE;
|
return COLOR_REPLACE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Graphics::setDefaultImageFilter(const Image::Filter &f)
|
||||||
|
{
|
||||||
|
Image::setDefaultFilter(f);
|
||||||
|
}
|
||||||
|
|
||||||
const Image::Filter &Graphics::getDefaultImageFilter() const
|
const Image::Filter &Graphics::getDefaultImageFilter() const
|
||||||
{
|
{
|
||||||
return Image::getDefaultFilter();
|
return Image::getDefaultFilter();
|
||||||
|
|||||||
@@ -22,9 +22,9 @@
|
|||||||
|
|
||||||
// STD
|
// STD
|
||||||
#include <cstring> // For memcpy
|
#include <cstring> // For memcpy
|
||||||
|
#include <algorithm> // for min/max
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
namespace love
|
namespace love
|
||||||
{
|
{
|
||||||
@@ -33,12 +33,11 @@ namespace graphics
|
|||||||
namespace opengl
|
namespace opengl
|
||||||
{
|
{
|
||||||
|
|
||||||
Image::Filter Image::defaultFilter;
|
|
||||||
|
|
||||||
Image::Image(love::image::ImageData *data)
|
Image::Image(love::image::ImageData *data)
|
||||||
: width((float)(data->getWidth()))
|
: width((float)(data->getWidth()))
|
||||||
, height((float)(data->getHeight()))
|
, height((float)(data->getHeight()))
|
||||||
, texture(0)
|
, texture(0)
|
||||||
|
, mipmapsharpness(0.0f)
|
||||||
{
|
{
|
||||||
data->retain();
|
data->retain();
|
||||||
this->data = data;
|
this->data = data;
|
||||||
@@ -63,7 +62,7 @@ Image::Image(love::image::ImageData *data)
|
|||||||
vertices[3].s = 1;
|
vertices[3].s = 1;
|
||||||
vertices[3].t = 0;
|
vertices[3].t = 0;
|
||||||
|
|
||||||
settings.filter = defaultFilter;
|
filter = getDefaultFilter();
|
||||||
}
|
}
|
||||||
|
|
||||||
Image::~Image()
|
Image::~Image()
|
||||||
@@ -144,143 +143,82 @@ void Image::drawq(love::graphics::Quad *quad, float x, float y, float angle, flo
|
|||||||
drawv(t, v);
|
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)
|
void Image::setFilter(const Image::Filter &f)
|
||||||
{
|
{
|
||||||
GLint gmin, gmag;
|
filter = f;
|
||||||
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();
|
bind();
|
||||||
|
checkMipmapsCreated();
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, gmin);
|
setTextureFilter(f);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, gmag);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Image::Filter Image::getFilter() const
|
const Image::Filter &Image::getFilter() const
|
||||||
{
|
{
|
||||||
bind();
|
return filter;
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::setWrap(Image::Wrap w)
|
void Image::setWrap(const Image::Wrap &w)
|
||||||
{
|
{
|
||||||
GLint gs, gt;
|
wrap = w;
|
||||||
|
|
||||||
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();
|
bind();
|
||||||
|
setTextureWrap(w);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, gs);
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, gt);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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();
|
bind();
|
||||||
|
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapsharpness); // negative bias is sharper
|
||||||
|
}
|
||||||
|
|
||||||
GLint gs, gt;
|
float Image::getMipmapSharpness() const
|
||||||
|
{
|
||||||
glGetTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, &gs);
|
return mipmapsharpness;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::bind() const
|
void Image::bind() const
|
||||||
@@ -303,6 +241,9 @@ void Image::unload()
|
|||||||
|
|
||||||
bool Image::loadVolatile()
|
bool Image::loadVolatile()
|
||||||
{
|
{
|
||||||
|
if (hasMipmapSharpnessSupport())
|
||||||
|
glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxmipmapsharpness);
|
||||||
|
|
||||||
if (hasNpot())
|
if (hasNpot())
|
||||||
return loadVolatileNPOT();
|
return loadVolatileNPOT();
|
||||||
else
|
else
|
||||||
@@ -313,6 +254,7 @@ bool Image::loadVolatilePOT()
|
|||||||
{
|
{
|
||||||
glGenTextures(1,(GLuint *)&texture);
|
glGenTextures(1,(GLuint *)&texture);
|
||||||
bindTexture(texture);
|
bindTexture(texture);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
@@ -349,8 +291,9 @@ bool Image::loadVolatilePOT()
|
|||||||
GL_UNSIGNED_BYTE,
|
GL_UNSIGNED_BYTE,
|
||||||
data->getData());
|
data->getData());
|
||||||
|
|
||||||
setFilter(settings.filter);
|
setMipmapSharpness(mipmapsharpness);
|
||||||
setWrap(settings.wrap);
|
setFilter(filter);
|
||||||
|
setWrap(wrap);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -359,6 +302,7 @@ bool Image::loadVolatileNPOT()
|
|||||||
{
|
{
|
||||||
glGenTextures(1,(GLuint *)&texture);
|
glGenTextures(1,(GLuint *)&texture);
|
||||||
bindTexture(texture);
|
bindTexture(texture);
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
@@ -375,16 +319,15 @@ bool Image::loadVolatileNPOT()
|
|||||||
GL_UNSIGNED_BYTE,
|
GL_UNSIGNED_BYTE,
|
||||||
data->getData());
|
data->getData());
|
||||||
|
|
||||||
setFilter(settings.filter);
|
setMipmapSharpness(mipmapsharpness);
|
||||||
setWrap(settings.wrap);
|
setFilter(filter);
|
||||||
|
setWrap(wrap);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::unloadVolatile()
|
void Image::unloadVolatile()
|
||||||
{
|
{
|
||||||
settings.filter = getFilter();
|
|
||||||
settings.wrap = getWrap();
|
|
||||||
// Delete the hardware texture.
|
// Delete the hardware texture.
|
||||||
if (texture != 0)
|
if (texture != 0)
|
||||||
{
|
{
|
||||||
@@ -417,14 +360,14 @@ bool Image::hasNpot()
|
|||||||
return GLEE_ARB_texture_non_power_of_two != 0;
|
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
|
} // opengl
|
||||||
|
|||||||
@@ -96,16 +96,19 @@ public:
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets the filter mode.
|
* Sets the filter mode.
|
||||||
*
|
* @param f The filter mode.
|
||||||
* @param mode The filter mode.
|
|
||||||
**/
|
**/
|
||||||
void setFilter(const Image::Filter &f);
|
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;
|
void bind() const;
|
||||||
|
|
||||||
@@ -117,10 +120,8 @@ public:
|
|||||||
void unloadVolatile();
|
void unloadVolatile();
|
||||||
|
|
||||||
static bool hasNpot();
|
static bool hasNpot();
|
||||||
|
static bool hasMipmapSupport();
|
||||||
// The default filter.
|
static bool hasMipmapSharpnessSupport();
|
||||||
static void setDefaultFilter(const Image::Filter &f);
|
|
||||||
static const Image::Filter &getDefaultFilter();
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
@@ -143,18 +144,22 @@ private:
|
|||||||
// The source vertices of the image.
|
// The source vertices of the image.
|
||||||
vertex vertices[4];
|
vertex vertices[4];
|
||||||
|
|
||||||
// The settings we need to save when reloading.
|
// Mipmap texture LOD bias value
|
||||||
struct
|
float mipmapsharpness;
|
||||||
{
|
|
||||||
Image::Filter filter;
|
// Implementation-dependent maximum/minimum mipmap sharpness values
|
||||||
Image::Wrap wrap;
|
float maxmipmapsharpness;
|
||||||
} settings;
|
|
||||||
|
// The image's filter mode
|
||||||
|
Image::Filter filter;
|
||||||
|
|
||||||
|
// The image's wrap mode
|
||||||
|
Image::Wrap wrap;
|
||||||
|
|
||||||
bool loadVolatilePOT();
|
bool loadVolatilePOT();
|
||||||
bool loadVolatileNPOT();
|
bool loadVolatileNPOT();
|
||||||
|
|
||||||
// The default image filter
|
void checkMipmapsCreated() const;
|
||||||
static Image::Filter defaultFilter;
|
|
||||||
|
|
||||||
}; // Image
|
}; // Image
|
||||||
|
|
||||||
|
|||||||
@@ -52,6 +52,160 @@ void deleteTexture(GLuint texture)
|
|||||||
glDeleteTextures(1, &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, >);
|
||||||
|
|
||||||
|
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
|
} // opengl
|
||||||
} // graphics
|
} // graphics
|
||||||
} // love
|
} // love
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#define LOVE_COMMON_OPENGL_H
|
#define LOVE_COMMON_OPENGL_H
|
||||||
|
|
||||||
#include "GLee.h"
|
#include "GLee.h"
|
||||||
|
#include "graphics/Image.h"
|
||||||
|
|
||||||
namespace love
|
namespace love
|
||||||
{
|
{
|
||||||
@@ -48,6 +49,28 @@ void bindTexture(GLuint texture, bool override = false);
|
|||||||
**/
|
**/
|
||||||
void deleteTexture(GLuint texture);
|
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
|
} // opengl
|
||||||
} // graphics
|
} // graphics
|
||||||
} // love
|
} // love
|
||||||
|
|||||||
@@ -105,7 +105,7 @@ ParticleSystem::~ParticleSystem()
|
|||||||
|
|
||||||
if (pStart != 0)
|
if (pStart != 0)
|
||||||
delete [] pStart;
|
delete [] pStart;
|
||||||
|
|
||||||
if (particleVerts != 0)
|
if (particleVerts != 0)
|
||||||
delete [] particleVerts;
|
delete [] particleVerts;
|
||||||
}
|
}
|
||||||
@@ -207,10 +207,10 @@ void ParticleSystem::setBufferSize(unsigned int size)
|
|||||||
pLast = pStart = new particle[size];
|
pLast = pStart = new particle[size];
|
||||||
|
|
||||||
pEnd = pStart + size;
|
pEnd = pStart + size;
|
||||||
|
|
||||||
if (particleVerts != 0)
|
if (particleVerts != 0)
|
||||||
delete [] particleVerts;
|
delete [] particleVerts;
|
||||||
|
|
||||||
// each particle has 4 vertices
|
// each particle has 4 vertices
|
||||||
particleVerts = new vertex[size*4];
|
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
|
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
|
if (sprite == 0) return; // just in case of failure
|
||||||
|
|
||||||
int numParticles = count();
|
int numParticles = count();
|
||||||
if (numParticles == 0) return; // don't bother if there's nothing to do
|
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;
|
static Matrix t;
|
||||||
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
|
t.setTransformation(x, y, angle, sx, sy, ox, oy, kx, ky);
|
||||||
glMultMatrixf((const GLfloat *)t.getElements());
|
glMultMatrixf((const GLfloat *)t.getElements());
|
||||||
|
|
||||||
const vertex * imageVerts = sprite->getVertices();
|
const vertex * imageVerts = sprite->getVertices();
|
||||||
|
|
||||||
// set the vertex data for each particle (transformation, texcoords, color)
|
// set the vertex data for each particle (transformation, texcoords, color)
|
||||||
for (int i = 0; i < numParticles; i++)
|
for (int i = 0; i < numParticles; i++)
|
||||||
{
|
{
|
||||||
particle * p = pStart + i;
|
particle * p = pStart + i;
|
||||||
|
|
||||||
// particle vertices are sprite vertices transformed by particle information
|
// 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.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);
|
t.transform(&particleVerts[i*4], &imageVerts[0], 4);
|
||||||
|
|
||||||
// set the texture coordinate and color data for particle vertices
|
// 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
|
int vi = (i * 4) + v; // current vertex index for particle
|
||||||
|
|
||||||
particleVerts[vi].s = imageVerts[v].s;
|
particleVerts[vi].s = imageVerts[v].s;
|
||||||
particleVerts[vi].t = imageVerts[v].t;
|
particleVerts[vi].t = imageVerts[v].t;
|
||||||
|
|
||||||
// particle colors are stored as floats (0-1) but vertex colors are stored as unsigned bytes (0-255)
|
// 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].r = p->color.r*255;
|
||||||
particleVerts[vi].g = p->color.g*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;
|
particleVerts[vi].a = p->color.a*255;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
sprite->bind();
|
sprite->bind();
|
||||||
|
|
||||||
glEnableClientState(GL_COLOR_ARRAY);
|
glEnableClientState(GL_COLOR_ARRAY);
|
||||||
glEnableClientState(GL_VERTEX_ARRAY);
|
glEnableClientState(GL_VERTEX_ARRAY);
|
||||||
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
|
|
||||||
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vertex), (GLvoid *)&particleVerts[0].r);
|
glColorPointer(4, GL_UNSIGNED_BYTE, sizeof(vertex), (GLvoid *)&particleVerts[0].r);
|
||||||
glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&particleVerts[0].x);
|
glVertexPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&particleVerts[0].x);
|
||||||
glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&particleVerts[0].s);
|
glTexCoordPointer(2, GL_FLOAT, sizeof(vertex), (GLvoid *)&particleVerts[0].s);
|
||||||
|
|
||||||
glDrawArrays(GL_QUADS, 0, numParticles*4);
|
glDrawArrays(GL_QUADS, 0, numParticles*4);
|
||||||
|
|
||||||
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
|
||||||
glDisableClientState(GL_VERTEX_ARRAY);
|
glDisableClientState(GL_VERTEX_ARRAY);
|
||||||
glDisableClientState(GL_COLOR_ARRAY);
|
glDisableClientState(GL_COLOR_ARRAY);
|
||||||
|
|||||||
@@ -406,7 +406,7 @@ protected:
|
|||||||
|
|
||||||
// Pointer to the end of the memory allocation.
|
// Pointer to the end of the memory allocation.
|
||||||
particle *pEnd;
|
particle *pEnd;
|
||||||
|
|
||||||
// array of transformed vertex data for all particles, for drawing
|
// array of transformed vertex data for all particles, for drawing
|
||||||
vertex * particleVerts;
|
vertex * particleVerts;
|
||||||
|
|
||||||
|
|||||||
@@ -67,23 +67,27 @@ int w_Canvas_getImageData(lua_State *L)
|
|||||||
int w_Canvas_setFilter(lua_State *L)
|
int w_Canvas_setFilter(lua_State *L)
|
||||||
{
|
{
|
||||||
Canvas *canvas = luax_checkcanvas(L, 1);
|
Canvas *canvas = luax_checkcanvas(L, 1);
|
||||||
const char *minstr = luaL_checkstring(L, 2);
|
|
||||||
const char *magstr = luaL_checkstring(L, 3);
|
|
||||||
|
|
||||||
Image::Filter f;
|
Image::Filter f;
|
||||||
|
|
||||||
|
const char *minstr = luaL_checkstring(L, 2);
|
||||||
|
const char *magstr = luaL_optstring(L, 3, minstr);
|
||||||
|
|
||||||
if (!Image::getConstant(minstr, f.min))
|
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))
|
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);
|
canvas->setFilter(f);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int w_Canvas_getFilter(lua_State *L)
|
int w_Canvas_getFilter(lua_State *L)
|
||||||
{
|
{
|
||||||
Canvas *canvas = luax_checkcanvas(L, 1);
|
Canvas *canvas = luax_checkcanvas(L, 1);
|
||||||
Image::Filter f = canvas->getFilter();
|
const Image::Filter f = canvas->getFilter();
|
||||||
|
|
||||||
const char *minstr;
|
const char *minstr;
|
||||||
const char *magstr;
|
const char *magstr;
|
||||||
@@ -99,23 +103,26 @@ int w_Canvas_getFilter(lua_State *L)
|
|||||||
int w_Canvas_setWrap(lua_State *L)
|
int w_Canvas_setWrap(lua_State *L)
|
||||||
{
|
{
|
||||||
Canvas *canvas = luax_checkcanvas(L, 1);
|
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;
|
Image::Wrap w;
|
||||||
if (!Image::getConstant(wrap_s, w.s))
|
|
||||||
return luaL_error(L, "Invalid wrap mode: %s", wrap_s);
|
const char *sstr = luaL_checkstring(L, 2);
|
||||||
if (!Image::getConstant(wrap_t, w.t))
|
const char *tstr = luaL_optstring(L, 3, sstr);
|
||||||
return luaL_error(L, "Invalid wrap mode: %s", wrap_t);
|
|
||||||
|
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);
|
canvas->setWrap(w);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int w_Canvas_getWrap(lua_State *L)
|
int w_Canvas_getWrap(lua_State *L)
|
||||||
{
|
{
|
||||||
Canvas *canvas = luax_checkcanvas(L, 1);
|
Canvas *canvas = luax_checkcanvas(L, 1);
|
||||||
Image::Wrap w = canvas->getWrap();
|
const Image::Wrap w = canvas->getWrap();
|
||||||
|
|
||||||
const char *wrap_s;
|
const char *wrap_s;
|
||||||
const char *wrap_t;
|
const char *wrap_t;
|
||||||
|
|||||||
@@ -90,6 +90,78 @@ int w_Font_getLineHeight(lua_State *L)
|
|||||||
return 1;
|
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[] =
|
static const luaL_Reg functions[] =
|
||||||
{
|
{
|
||||||
{ "getHeight", w_Font_getHeight },
|
{ "getHeight", w_Font_getHeight },
|
||||||
@@ -97,6 +169,10 @@ static const luaL_Reg functions[] =
|
|||||||
{ "getWrap", w_Font_getWrap },
|
{ "getWrap", w_Font_getWrap },
|
||||||
{ "setLineHeight", w_Font_setLineHeight },
|
{ "setLineHeight", w_Font_setLineHeight },
|
||||||
{ "getLineHeight", w_Font_getLineHeight },
|
{ "getLineHeight", w_Font_getLineHeight },
|
||||||
|
{ "setFilter", w_Font_setFilter },
|
||||||
|
{ "getFilter", w_Font_getFilter },
|
||||||
|
{ "setMipmapSharpness", w_Font_setMipmapSharpness },
|
||||||
|
{ "getMipmapSharpness", w_Font_getMipmapSharpness },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ int w_Font_getWidth(lua_State *L);
|
|||||||
int w_Font_getWrap(lua_State *L);
|
int w_Font_getWrap(lua_State *L);
|
||||||
int w_Font_setLineHeight(lua_State *L);
|
int w_Font_setLineHeight(lua_State *L);
|
||||||
int w_Font_getLineHeight(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);
|
extern "C" int luaopen_font(lua_State *L);
|
||||||
|
|
||||||
} // opengl
|
} // opengl
|
||||||
|
|||||||
@@ -601,8 +601,10 @@ int w_setDefaultImageFilter(lua_State *L)
|
|||||||
{
|
{
|
||||||
Image::FilterMode min;
|
Image::FilterMode min;
|
||||||
Image::FilterMode mag;
|
Image::FilterMode mag;
|
||||||
|
|
||||||
const char *minstr = luaL_checkstring(L, 1);
|
const char *minstr = luaL_checkstring(L, 1);
|
||||||
const char *magstr = luaL_optstring(L, 2, minstr);
|
const char *magstr = luaL_optstring(L, 2, minstr);
|
||||||
|
|
||||||
if (!Image::getConstant(minstr, min))
|
if (!Image::getConstant(minstr, min))
|
||||||
return luaL_error(L, "Invalid filter mode: %s", minstr);
|
return luaL_error(L, "Invalid filter mode: %s", minstr);
|
||||||
if (!Image::getConstant(magstr, mag))
|
if (!Image::getConstant(magstr, mag))
|
||||||
@@ -611,6 +613,7 @@ int w_setDefaultImageFilter(lua_State *L)
|
|||||||
Image::Filter f;
|
Image::Filter f;
|
||||||
f.min = min;
|
f.min = min;
|
||||||
f.mag = mag;
|
f.mag = mag;
|
||||||
|
|
||||||
instance->setDefaultImageFilter(f);
|
instance->setDefaultImageFilter(f);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
@@ -850,7 +853,12 @@ int w_isSupported(lua_State *L)
|
|||||||
supported = false;
|
supported = false;
|
||||||
break;
|
break;
|
||||||
case Graphics::SUPPORT_SUBTRACTIVE:
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
supported = false;
|
supported = false;
|
||||||
|
|||||||
@@ -50,71 +50,107 @@ int w_Image_getHeight(lua_State *L)
|
|||||||
int w_Image_setFilter(lua_State *L)
|
int w_Image_setFilter(lua_State *L)
|
||||||
{
|
{
|
||||||
Image *t = luax_checkimage(L, 1);
|
Image *t = luax_checkimage(L, 1);
|
||||||
|
|
||||||
Image::Filter f;
|
Image::Filter f;
|
||||||
Image::FilterMode min;
|
|
||||||
Image::FilterMode mag;
|
|
||||||
const char *minstr = luaL_checkstring(L, 2);
|
const char *minstr = luaL_checkstring(L, 2);
|
||||||
const char *magstr = luaL_optstring(L, 3, minstr);
|
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);
|
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);
|
return luaL_error(L, "Invalid filter mode: %s", magstr);
|
||||||
|
|
||||||
f.min = min;
|
if (lua_isnoneornil(L, 4))
|
||||||
f.mag = mag;
|
f.mipmap = Image::FILTER_NONE; // mipmapping is disabled unless third argument is given
|
||||||
t->setFilter(f);
|
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;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int w_Image_getFilter(lua_State *L)
|
int w_Image_getFilter(lua_State *L)
|
||||||
{
|
{
|
||||||
Image *t = luax_checkimage(L, 1);
|
Image *t = luax_checkimage(L, 1);
|
||||||
Image::Filter f = t->getFilter();
|
const Image::Filter f = t->getFilter();
|
||||||
Image::FilterMode min = f.min;
|
|
||||||
Image::FilterMode mag = f.mag;
|
|
||||||
const char *minstr;
|
const char *minstr;
|
||||||
const char *magstr;
|
const char *magstr;
|
||||||
Image::getConstant(min, minstr);
|
Image::getConstant(f.min, minstr);
|
||||||
Image::getConstant(mag, magstr);
|
Image::getConstant(f.mag, magstr);
|
||||||
lua_pushstring(L, minstr);
|
lua_pushstring(L, minstr);
|
||||||
lua_pushstring(L, magstr);
|
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)
|
int w_Image_setWrap(lua_State *L)
|
||||||
{
|
{
|
||||||
Image *i = luax_checkimage(L, 1);
|
Image *i = luax_checkimage(L, 1);
|
||||||
|
|
||||||
Image::Wrap w;
|
Image::Wrap w;
|
||||||
Image::WrapMode s;
|
|
||||||
Image::WrapMode t;
|
|
||||||
const char *sstr = luaL_checkstring(L, 2);
|
const char *sstr = luaL_checkstring(L, 2);
|
||||||
const char *tstr = luaL_optstring(L, 3, sstr);
|
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);
|
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);
|
return luaL_error(L, "Invalid wrap mode, %s", tstr);
|
||||||
|
|
||||||
w.s = s;
|
|
||||||
w.t = t;
|
|
||||||
i->setWrap(w);
|
i->setWrap(w);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int w_Image_getWrap(lua_State *L)
|
int w_Image_getWrap(lua_State *L)
|
||||||
{
|
{
|
||||||
Image *i = luax_checkimage(L, 1);
|
Image *i = luax_checkimage(L, 1);
|
||||||
Image::Wrap w = i->getWrap();
|
const Image::Wrap w = i->getWrap();
|
||||||
Image::WrapMode s = w.s;
|
|
||||||
Image::WrapMode t = w.t;
|
|
||||||
const char *sstr;
|
const char *sstr;
|
||||||
const char *tstr;
|
const char *tstr;
|
||||||
Image::getConstant(s, sstr);
|
Image::getConstant(w.s, sstr);
|
||||||
Image::getConstant(t, tstr);
|
Image::getConstant(w.t, tstr);
|
||||||
lua_pushstring(L, sstr);
|
lua_pushstring(L, sstr);
|
||||||
lua_pushstring(L, tstr);
|
lua_pushstring(L, tstr);
|
||||||
return 2;
|
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[] =
|
static const luaL_Reg functions[] =
|
||||||
{
|
{
|
||||||
{ "getWidth", w_Image_getWidth },
|
{ "getWidth", w_Image_getWidth },
|
||||||
@@ -123,6 +159,8 @@ static const luaL_Reg functions[] =
|
|||||||
{ "getFilter", w_Image_getFilter },
|
{ "getFilter", w_Image_getFilter },
|
||||||
{ "setWrap", w_Image_setWrap },
|
{ "setWrap", w_Image_setWrap },
|
||||||
{ "getWrap", w_Image_getWrap },
|
{ "getWrap", w_Image_getWrap },
|
||||||
|
{ "setMipmapSharpness", w_Image_setMipmapSharpness },
|
||||||
|
{ "getMipmapSharpness", w_Image_getMipmapSharpness },
|
||||||
{ 0, 0 }
|
{ 0, 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -36,6 +36,11 @@ Image *luax_checkimage(lua_State *L, int idx);
|
|||||||
int w_Image_getWidth(lua_State *L);
|
int w_Image_getWidth(lua_State *L);
|
||||||
int w_Image_getHeight(lua_State *L);
|
int w_Image_getHeight(lua_State *L);
|
||||||
int w_Image_setFilter(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);
|
extern "C" int luaopen_image(lua_State *L);
|
||||||
|
|
||||||
} // opengl
|
} // opengl
|
||||||
|
|||||||
Reference in New Issue
Block a user