diff --git a/changes.txt b/changes.txt
index dc7752933..db7de7b74 100644
--- a/changes.txt
+++ b/changes.txt
@@ -10,6 +10,14 @@ LOVE 0.8.1 [Rubber Piggy]
* Added love.mouse.setX/setY.
* Added love.filesystem.getIdentity.
* Added HDR canvas support.
+ * Added Source:isPlaying.
+ * Added mipmapping support (has isSupported test).
+ * Added Font:getAscent/getDescent/getBaseline.
+ * Added Canvas:getPixel.
+ * Added vertex shader support.
+ * Added boolean support to Shader:send.
+ * Added support for UTF-8 ImageFonts.
+ * Added SoundData:getDuration.
* OPTIONAL: Added support for GME.
* Fixed crashes with font drawing on some ATI cards.
@@ -26,18 +34,26 @@ LOVE 0.8.1 [Rubber Piggy]
* Fixed multiplicative blend mode.
* Fixed Box2D exception in World:update.
* Fixed spacing for the last character in an ImageFont.
+ * Fixed crash when locking SpriteBatches multiple times.
+ * Fixed File:read reading past end of file.
+ * Fixed keyrepeat settings being lost after (indirect) setMode.
* Moved love's startup to modules/love.
* Renamed love's boot script to 'love.boot', which can be required.
+ * Renamed PixelEffect to Shader (but now with vertex shaders).
* Removed love.joystick.open and friends.
+ * Removed love.graphics.drawTest.
* Updated allocation for SoundData, it's more efficient and less wasteful.
* Updated Source:set* functions to default z to 0.
* Updated the windows console, it now tries to re-use an active one first.
* Updated love.image memory handling, improves errors and thread-safety.
* Updated order of sleep/present in love.run (now draws, *then* sleeps).
+ * Updated the setFilter and setWrap methods, the second argument is now optional.
+ * Updated font rendering code, now more performant.
+ * Updated error handling, error handlers now get resolved when the error occurs.
LOVE 0.8.0 [Rubber Piggy]
-------------------------
diff --git a/platform/msvc2010/liblove.vcxproj b/platform/msvc2010/liblove.vcxproj
index 490cb667f..c72f9cdc1 100644
--- a/platform/msvc2010/liblove.vcxproj
+++ b/platform/msvc2010/liblove.vcxproj
@@ -112,11 +112,13 @@
$(SolutionDir)\bin\$(PlatformShortName)\Debug\MD\
$(ProjectName)\$(PlatformShortName)\Debug\
false
+ love
$(SolutionDir)\bin\$(PlatformShortName)\Debug\MD\
$(ProjectName)\$(PlatformShortName)\Debug\
false
+ love
$(SolutionDir)\bin\$(PlatformShortName)\Release\MT\
@@ -130,11 +132,13 @@
$(SolutionDir)\bin\$(PlatformShortName)\Release\MD\
$(ProjectName)\$(PlatformShortName)\Release\
false
+ love
$(SolutionDir)\bin\$(PlatformShortName)\Release\MD\
$(ProjectName)\$(PlatformShortName)\Release\
false
+ love
@@ -733,4 +737,4 @@
-
+
\ No newline at end of file
diff --git a/platform/msvc2010/love.rc b/platform/msvc2010/love.rc
index 665d87058..1e91ecf7d 100644
Binary files a/platform/msvc2010/love.rc and b/platform/msvc2010/love.rc differ
diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp
index 776082642..29c4deaf3 100644
--- a/src/modules/graphics/opengl/Image.cpp
+++ b/src/modules/graphics/opengl/Image.cpp
@@ -37,7 +37,8 @@ Image::Image(love::image::ImageData *data)
: width((float)(data->getWidth()))
, height((float)(data->getHeight()))
, texture(0)
- , mipmapsharpness(0.0f)
+ , mipmapSharpness(0.0f)
+ , mipmapsCreated(false)
{
data->retain();
this->data = data;
@@ -143,36 +144,55 @@ void Image::drawq(love::graphics::Quad *quad, float x, float y, float angle, flo
drawv(t, v);
}
-void Image::checkMipmapsCreated() const
+void Image::checkMipmapsCreated()
{
- if (filter.mipmap != FILTER_NEAREST && filter.mipmap != FILTER_LINEAR)
+ if (mipmapsCreated || (filter.mipmap != FILTER_NEAREST && filter.mipmap != FILTER_LINEAR))
return;
if (!hasMipmapSupport())
- throw love::Exception("Mipmap filtering is not supported on this system!");
+ 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
+ // Some old drivers claim support for NPOT textures, but fail when creating 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!");
+ throw love::Exception("Cannot create mipmaps: image does not have power of two dimensions.");
bind();
- GLint mipmapscreated;
- glGetTexParameteriv(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, &mipmapscreated);
+ if (hasNpot() && (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object))
+ {
+ // AMD/ATI drivers have several bugs when generating mipmaps,
+ // re-uploading the entire base image seems to be required.
+ glTexImage2D(GL_TEXTURE_2D,
+ 0,
+ GL_RGBA8,
+ (GLsizei)width,
+ (GLsizei)height,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ data->getData());
- // generate mipmaps for this image if we haven't already
- if (!mipmapscreated)
+ // More bugs: http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation
+ glEnable(GL_TEXTURE_2D);
+ glGenerateMipmap(GL_TEXTURE_2D);
+ }
+ else
{
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
-
- if (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object)
- glGenerateMipmap(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());
+ glTexSubImage2D(GL_TEXTURE_2D,
+ 0,
+ 0,
+ 0,
+ (GLsizei)width,
+ (GLsizei)height,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ data->getData());
}
+
+ mipmapsCreated = true;
}
void Image::setFilter(const Image::Filter &f)
@@ -180,8 +200,8 @@ void Image::setFilter(const Image::Filter &f)
filter = f;
bind();
- checkMipmapsCreated();
setTextureFilter(f);
+ checkMipmapsCreated();
}
const Image::Filter &Image::getFilter() const
@@ -208,15 +228,15 @@ void Image::setMipmapSharpness(float sharpness)
return;
// LOD bias has the range (-maxbias, maxbias)
- mipmapsharpness = std::min(std::max(sharpness, -maxmipmapsharpness + 0.01f), maxmipmapsharpness - 0.01f);
+ 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
+ glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapSharpness); // negative bias is sharper
}
float Image::getMipmapSharpness() const
{
- return mipmapsharpness;
+ return mipmapSharpness;
}
void Image::bind() const
@@ -240,7 +260,7 @@ void Image::unload()
bool Image::loadVolatile()
{
if (hasMipmapSharpnessSupport())
- glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxmipmapsharpness);
+ glGetFloatv(GL_MAX_TEXTURE_LOD_BIAS, &maxMipmapSharpness);
if (hasNpot())
return loadVolatileNPOT();
@@ -253,11 +273,8 @@ bool Image::loadVolatilePOT()
glGenTextures(1,(GLuint *)&texture);
bindTexture(texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
-
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ setTextureFilter(filter);
+ setTextureWrap(wrap);
float p2width = next_p2(width);
float p2height = next_p2(height);
@@ -269,29 +286,34 @@ bool Image::loadVolatilePOT()
vertices[2].s = s;
vertices[3].s = s;
+ while (glGetError() != GL_NO_ERROR); // clear errors
+
glTexImage2D(GL_TEXTURE_2D,
- 0,
- GL_RGBA8,
- (GLsizei)p2width,
- (GLsizei)p2height,
- 0,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- 0);
+ 0,
+ GL_RGBA8,
+ (GLsizei)p2width,
+ (GLsizei)p2height,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ 0);
glTexSubImage2D(GL_TEXTURE_2D,
- 0,
- 0,
- 0,
- (GLsizei)width,
- (GLsizei)height,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- data->getData());
+ 0,
+ 0,
+ 0,
+ (GLsizei)width,
+ (GLsizei)height,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ data->getData());
- setMipmapSharpness(mipmapsharpness);
- setFilter(filter);
- setWrap(wrap);
+ if (glGetError() != GL_NO_ERROR)
+ throw love::Exception("Cannot create image: size may be too large for this system.");
+
+ mipmapsCreated = false;
+ checkMipmapsCreated();
+ setMipmapSharpness(mipmapSharpness);
return true;
}
@@ -301,25 +323,27 @@ 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);
+ setTextureFilter(filter);
+ setTextureWrap(wrap);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
- glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
+ while (glGetError() != GL_NO_ERROR); // clear errors
glTexImage2D(GL_TEXTURE_2D,
- 0,
- GL_RGBA8,
- (GLsizei)width,
- (GLsizei)height,
- 0,
- GL_RGBA,
- GL_UNSIGNED_BYTE,
- data->getData());
+ 0,
+ GL_RGBA8,
+ (GLsizei)width,
+ (GLsizei)height,
+ 0,
+ GL_RGBA,
+ GL_UNSIGNED_BYTE,
+ data->getData());
- setMipmapSharpness(mipmapsharpness);
- setFilter(filter);
- setWrap(wrap);
+ if (glGetError() != GL_NO_ERROR)
+ throw love::Exception("Cannot create image: size may be too large for this system.");
+
+ mipmapsCreated = false;
+ checkMipmapsCreated();
+ setMipmapSharpness(mipmapSharpness);
return true;
}
@@ -360,12 +384,12 @@ bool Image::hasNpot()
bool Image::hasMipmapSupport()
{
- return (GLEE_VERSION_1_4 || GLEE_SGIS_generate_mipmap) != 0;
+ return GLEE_VERSION_1_4 || GLEE_SGIS_generate_mipmap;
}
bool Image::hasMipmapSharpnessSupport()
{
- return (GLEE_VERSION_1_4 || GLEE_EXT_texture_lod_bias) != 0;
+ return GLEE_VERSION_1_4 || GLEE_EXT_texture_lod_bias;
}
} // opengl
diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h
index d09eb8954..ea4f05bfb 100644
--- a/src/modules/graphics/opengl/Image.h
+++ b/src/modules/graphics/opengl/Image.h
@@ -142,11 +142,14 @@ private:
// The source vertices of the image.
vertex vertices[4];
- // Mipmap texture LOD bias value
- float mipmapsharpness;
+ // Mipmap texture LOD bias (sharpness) value.
+ float mipmapSharpness;
- // Implementation-dependent maximum/minimum mipmap sharpness values
- float maxmipmapsharpness;
+ // Implementation-dependent min/max mipmap sharpness values.
+ float maxMipmapSharpness;
+
+ // True if mipmaps have been created for this Image.
+ bool mipmapsCreated;
// The image's filter mode
Image::Filter filter;
@@ -157,7 +160,7 @@ private:
bool loadVolatilePOT();
bool loadVolatileNPOT();
- void checkMipmapsCreated() const;
+ void checkMipmapsCreated();
}; // Image
diff --git a/src/modules/graphics/opengl/SpriteBatch.cpp b/src/modules/graphics/opengl/SpriteBatch.cpp
index fc2bfc6ad..e80c4b491 100644
--- a/src/modules/graphics/opengl/SpriteBatch.cpp
+++ b/src/modules/graphics/opengl/SpriteBatch.cpp
@@ -20,9 +20,6 @@
#include "SpriteBatch.h"
-// STD
-#include // std::find
-
// OpenGL
#include "OpenGL.h"
@@ -97,25 +94,9 @@ SpriteBatch::~SpriteBatch()
int SpriteBatch::add(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky, int index /*= -1*/)
{
// Only do this if there's a free slot.
- if ((index == -1 && next >= size && gaps.size() == 0) || index < -1 || index >= size)
+ if ((index == -1 && next >= size) || index < -1 || index >= size)
return -1;
- // Determine where in the vertex buffer to insert into, using the gap list
- // if possible.
- int realindex;
- if (index == -1 && gaps.size() > 0)
- {
- realindex = gaps.front();
- gaps.pop_front();
- }
- else
- {
- realindex = (index == -1) ? next : index;
- std::deque::iterator it = std::find(gaps.begin(), gaps.end(), realindex);
- if (it != gaps.end())
- gaps.erase(it); // This index is no longer a gap.
- }
-
// Needed for colors.
memcpy(sprite, image->getVertices(), sizeof(vertex)*4);
@@ -128,37 +109,21 @@ int SpriteBatch::add(float x, float y, float a, float sx, float sy, float ox, fl
setColorv(sprite, *color);
- addv(sprite, realindex);
+ addv(sprite, (index == -1) ? next : index);
// Increment counter.
- if (index == -1 && realindex == next)
+ if (index == -1)
return next++;
- return realindex;
+ return index;
}
int SpriteBatch::addq(Quad *quad, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky, int index /*= -1*/)
{
// Only do this if there's a free slot.
- if ((index == -1 && next >= size && gaps.size() == 0) || index < -1 || index >= next)
+ if ((index == -1 && next >= size) || index < -1 || index >= next)
return -1;
- // Determine where in the vertex buffer to insert into, using the gap list
- // if possible.
- int realindex;
- if (index == -1 && gaps.size() > 0)
- {
- realindex = gaps.front();
- gaps.pop_front();
- }
- else
- {
- realindex = (index == -1) ? next : index;
- std::deque::iterator it = std::find(gaps.begin(), gaps.end(), realindex);
- if (it != gaps.end())
- gaps.erase(it); // This index is no longer a gap.
- }
-
// Needed for colors.
memcpy(sprite, quad->getVertices(), sizeof(vertex)*4);
@@ -170,53 +135,19 @@ int SpriteBatch::addq(Quad *quad, float x, float y, float a, float sx, float sy,
if (color)
setColorv(sprite, *color);
- addv(sprite, realindex);
+ addv(sprite, (index == -1) ? next : index);
// Increment counter.
- if (index == -1 && realindex == next)
+ if (index == -1)
return next++;
- return realindex;
-}
-
-void SpriteBatch::remove(int index)
-{
- if (index < 0 || index >= next || next <= 0)
- return;
-
- // If this is the last index in the sprite list, decrease the total sprite
- // count instead of adding a dummy sprite.
- if (index == next - 1)
- {
- int spritecount = index;
-
- // Remove all consecutive gaps at the end of the sprite list.
- std::deque::iterator it;
- while ((it = std::find(gaps.begin(), gaps.end(), --spritecount)) != gaps.end())
- gaps.erase(it);
-
- next = spritecount + 1;
- return;
- }
- else if (std::find(gaps.begin(), gaps.end(), index) != gaps.end())
- return; // Don't add the same index to the gap list twice.
-
-
- // OpenGL won't render any primitive whose vertices are all identical.
- for (int i = 0; i < 4; i++)
- sprite[i].x = sprite[i].y = 0;
-
- // Replace the existing sprite at this index with the dummy sprite.
- addv(sprite, index);
-
- gaps.push_back(index);
+ return index;
}
void SpriteBatch::clear()
{
// Reset the position of the next index.
next = 0;
- gaps.clear();
}
void *SpriteBatch::lock()
diff --git a/src/modules/graphics/opengl/SpriteBatch.h b/src/modules/graphics/opengl/SpriteBatch.h
index 43055dab1..5cf71b928 100644
--- a/src/modules/graphics/opengl/SpriteBatch.h
+++ b/src/modules/graphics/opengl/SpriteBatch.h
@@ -23,7 +23,6 @@
// C
#include
-#include
// LOVE
#include "common/math.h"
@@ -64,7 +63,6 @@ public:
int add(float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky, int index = -1);
int addq(Quad *quad, float x, float y, float a, float sx, float sy, float ox, float oy, float kx, float ky, int index = -1);
- void remove(int index);
void clear();
void *lock();
@@ -127,10 +125,6 @@ private:
VertexBuffer *array_buf;
VertexIndex *element_buf;
- // List of gaps in the SpriteBatch. Checked when adding sprites, and added
- // to when removing them.
- std::deque gaps;
-
}; // SpriteBatch
} // opengl
diff --git a/src/modules/graphics/opengl/wrap_SpriteBatch.cpp b/src/modules/graphics/opengl/wrap_SpriteBatch.cpp
index f29619991..6d9f501c1 100644
--- a/src/modules/graphics/opengl/wrap_SpriteBatch.cpp
+++ b/src/modules/graphics/opengl/wrap_SpriteBatch.cpp
@@ -101,14 +101,6 @@ int w_SpriteBatch_setq(lua_State *L)
return 0;
}
-int w_SpriteBatch_remove(lua_State *L)
-{
- SpriteBatch *t = luax_checkspritebatch(L, 1);
- int id = luaL_checkinteger(L, 2);
- t->remove(id);
- return 0;
-}
-
int w_SpriteBatch_clear(lua_State *L)
{
SpriteBatch *t = luax_checkspritebatch(L, 1);
@@ -198,7 +190,6 @@ static const luaL_Reg functions[] =
{ "addq", w_SpriteBatch_addq },
{ "set", w_SpriteBatch_set },
{ "setq", w_SpriteBatch_setq },
- { "remove", w_SpriteBatch_remove },
{ "clear", w_SpriteBatch_clear },
{ "bind", w_SpriteBatch_bind },
{ "unbind", w_SpriteBatch_unbind },
diff --git a/src/modules/graphics/opengl/wrap_SpriteBatch.h b/src/modules/graphics/opengl/wrap_SpriteBatch.h
index ca397d715..aa737dcc9 100644
--- a/src/modules/graphics/opengl/wrap_SpriteBatch.h
+++ b/src/modules/graphics/opengl/wrap_SpriteBatch.h
@@ -36,7 +36,6 @@ int w_SpriteBatch_add(lua_State *L);
int w_SpriteBatch_addq(lua_State *L);
int w_SpriteBatch_set(lua_State *L);
int w_SpriteBatch_setq(lua_State *L);
-int w_SpriteBatch_remove(lua_State *L);
int w_SpriteBatch_clear(lua_State *L);
int w_SpriteBatch_lock(lua_State *L);
int w_SpriteBatch_unlock(lua_State *L);