mirror of
https://github.com/love2d/love.git
synced 2026-08-17 19:23:38 +02:00
Added optional xoffset/yoffset/width/height arguments to Image:refresh, to specify a sub-rectangle. Specifying a small sub-rectangle can improve the performance of Image:refresh.
--HG-- branch : minor
This commit is contained in:
@@ -20,6 +20,8 @@
|
|||||||
|
|
||||||
#include "Image.h"
|
#include "Image.h"
|
||||||
|
|
||||||
|
#include "common/int.h"
|
||||||
|
|
||||||
// STD
|
// STD
|
||||||
#include <cstring> // For memcpy
|
#include <cstring> // For memcpy
|
||||||
#include <algorithm> // for min/max
|
#include <algorithm> // for min/max
|
||||||
@@ -218,50 +220,12 @@ void Image::unload()
|
|||||||
return unloadVolatile();
|
return unloadVolatile();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::uploadCompressedData()
|
void Image::generateMipmaps()
|
||||||
{
|
{
|
||||||
GLenum iformat = getCompressedFormat(cdata->getFormat());
|
// The GL_GENERATE_MIPMAP texparameter is set in loadVolatile if we don't
|
||||||
int count = flags.mipmaps ? cdata->getMipmapCount() : 1;
|
// have support for glGenerateMipmap.
|
||||||
|
if (flags.mipmaps && !isCompressed() &&
|
||||||
// We have to inform OpenGL if the image doesn't have all mipmap levels.
|
(GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object))
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, count - 1);
|
|
||||||
|
|
||||||
for (int i = 0; i < count; i++)
|
|
||||||
{
|
|
||||||
glCompressedTexImage2D(GL_TEXTURE_2D,
|
|
||||||
i,
|
|
||||||
iformat,
|
|
||||||
cdata->getWidth(i),
|
|
||||||
cdata->getHeight(i),
|
|
||||||
0,
|
|
||||||
(GLsizei) cdata->getSize(i),
|
|
||||||
cdata->getData(i));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Image::uploadImageData()
|
|
||||||
{
|
|
||||||
GLenum iformat = flags.sRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8;
|
|
||||||
|
|
||||||
if (flags.mipmaps && !(GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object))
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
|
|
||||||
|
|
||||||
{
|
|
||||||
love::thread::Lock lock(data->getMutex());
|
|
||||||
glTexImage2D(GL_TEXTURE_2D,
|
|
||||||
0,
|
|
||||||
iformat,
|
|
||||||
width,
|
|
||||||
height,
|
|
||||||
0,
|
|
||||||
GL_RGBA,
|
|
||||||
GL_UNSIGNED_BYTE,
|
|
||||||
data->getData());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flags.mipmaps)
|
|
||||||
{
|
|
||||||
if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object)
|
|
||||||
{
|
{
|
||||||
// Driver bug: http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation
|
// Driver bug: http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation
|
||||||
#if defined(LOVE_WINDOWS) || defined(LOVE_LINUX)
|
#if defined(LOVE_WINDOWS) || defined(LOVE_LINUX)
|
||||||
@@ -271,19 +235,35 @@ void Image::uploadImageData()
|
|||||||
|
|
||||||
glGenerateMipmap(GL_TEXTURE_2D);
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
}
|
}
|
||||||
else
|
}
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_FALSE);
|
|
||||||
|
void Image::loadTextureFromCompressedData()
|
||||||
|
{
|
||||||
|
GLenum iformat = getCompressedFormat(cdata->getFormat());
|
||||||
|
int count = flags.mipmaps ? cdata->getMipmapCount() : 1;
|
||||||
|
|
||||||
|
// We have to inform OpenGL if the image doesn't have all mipmap levels.
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, count - 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++)
|
||||||
|
{
|
||||||
|
glCompressedTexImage2D(GL_TEXTURE_2D, i, iformat,
|
||||||
|
cdata->getWidth(i), cdata->getHeight(i), 0,
|
||||||
|
(GLsizei) cdata->getSize(i), cdata->getData(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::uploadTexture()
|
void Image::loadTextureFromImageData()
|
||||||
{
|
{
|
||||||
bind();
|
GLenum iformat = flags.sRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8;
|
||||||
|
|
||||||
if (isCompressed() && cdata.get())
|
{
|
||||||
uploadCompressedData();
|
love::thread::Lock lock(data->getMutex());
|
||||||
else if (data.get())
|
glTexImage2D(GL_TEXTURE_2D, 0, iformat, width, height, 0, GL_RGBA,
|
||||||
uploadImageData();
|
GL_UNSIGNED_BYTE, data->getData());
|
||||||
|
}
|
||||||
|
|
||||||
|
generateMipmaps();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Image::loadVolatile()
|
bool Image::loadVolatile()
|
||||||
@@ -313,21 +293,32 @@ bool Image::loadVolatile()
|
|||||||
gl.setTextureWrap(wrap);
|
gl.setTextureWrap(wrap);
|
||||||
setMipmapSharpness(mipmapSharpness);
|
setMipmapSharpness(mipmapSharpness);
|
||||||
|
|
||||||
if (!flags.mipmaps)
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
|
||||||
|
|
||||||
// Use a default texture if the size is too big for the system.
|
// Use a default texture if the size is too big for the system.
|
||||||
if (width > gl.getMaxTextureSize() || height > gl.getMaxTextureSize())
|
if (width > gl.getMaxTextureSize() || height > gl.getMaxTextureSize())
|
||||||
{
|
{
|
||||||
uploadDefaultTexture();
|
loadDefaultTexture();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!flags.mipmaps)
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, 0);
|
||||||
|
|
||||||
|
if (flags.mipmaps && !isCompressed() &&
|
||||||
|
!(GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object))
|
||||||
|
{
|
||||||
|
// Auto-generate mipmaps every time the texture is modified, if
|
||||||
|
// glGenerateMipmap isn't supported.
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
|
||||||
|
}
|
||||||
|
|
||||||
while (glGetError() != GL_NO_ERROR); // Clear errors.
|
while (glGetError() != GL_NO_ERROR); // Clear errors.
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
uploadTexture();
|
if (isCompressed())
|
||||||
|
loadTextureFromCompressedData();
|
||||||
|
else
|
||||||
|
loadTextureFromImageData();
|
||||||
|
|
||||||
GLenum glerr = glGetError();
|
GLenum glerr = glGetError();
|
||||||
if (glerr != GL_NO_ERROR)
|
if (glerr != GL_NO_ERROR)
|
||||||
@@ -374,13 +365,39 @@ void Image::unloadVolatile()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Image::refresh()
|
void Image::uploadImageData(int xoffset, int yoffset, int w, int h)
|
||||||
|
{
|
||||||
|
const image::pixel *pdata = (const image::pixel *) data->getData();
|
||||||
|
pdata += yoffset * data->getWidth() + xoffset;
|
||||||
|
|
||||||
|
{
|
||||||
|
thread::Lock lock(data->getMutex());
|
||||||
|
glTexSubImage2D(GL_TEXTURE_2D, 0, xoffset, yoffset, w, h, GL_RGBA,
|
||||||
|
GL_UNSIGNED_BYTE, pdata);
|
||||||
|
}
|
||||||
|
|
||||||
|
generateMipmaps();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Image::refresh(int xoffset, int yoffset, int w, int h)
|
||||||
{
|
{
|
||||||
// No effect if the texture hasn't been created yet.
|
// No effect if the texture hasn't been created yet.
|
||||||
if (texture == 0 || usingDefaultTexture)
|
if (texture == 0 || usingDefaultTexture)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
uploadTexture();
|
if (xoffset < 0 || yoffset < 0 || w <= 0 || h <= 0 ||
|
||||||
|
(xoffset + w) > width || (yoffset + h) > height)
|
||||||
|
{
|
||||||
|
throw love::Exception("Invalid rectangle dimensions.");
|
||||||
|
}
|
||||||
|
|
||||||
|
bind();
|
||||||
|
|
||||||
|
if (isCompressed())
|
||||||
|
loadTextureFromCompressedData();
|
||||||
|
else
|
||||||
|
uploadImageData(xoffset, yoffset, w, h);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -389,7 +406,7 @@ const Image::Flags &Image::getFlags() const
|
|||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Image::uploadDefaultTexture()
|
void Image::loadDefaultTexture()
|
||||||
{
|
{
|
||||||
usingDefaultTexture = true;
|
usingDefaultTexture = true;
|
||||||
|
|
||||||
|
|||||||
@@ -133,7 +133,7 @@ public:
|
|||||||
* Re-uploads the ImageData or CompressedData associated with this Image to
|
* Re-uploads the ImageData or CompressedData associated with this Image to
|
||||||
* the GPU.
|
* the GPU.
|
||||||
**/
|
**/
|
||||||
bool refresh();
|
bool refresh(int xoffset, int yoffset, int w, int h);
|
||||||
|
|
||||||
const Flags &getFlags() const;
|
const Flags &getFlags() const;
|
||||||
|
|
||||||
@@ -153,10 +153,18 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
||||||
void uploadDefaultTexture();
|
|
||||||
|
|
||||||
void drawv(const Matrix &t, const Vertex *v);
|
void drawv(const Matrix &t, const Vertex *v);
|
||||||
|
|
||||||
|
void preload();
|
||||||
|
|
||||||
|
void generateMipmaps();
|
||||||
|
void loadDefaultTexture();
|
||||||
|
void loadTextureFromCompressedData();
|
||||||
|
void loadTextureFromImageData();
|
||||||
|
void uploadImageData(int xoffset, int yoffset, int w, int h);
|
||||||
|
|
||||||
|
GLenum getCompressedFormat(image::CompressedData::Format cformat) const;
|
||||||
|
|
||||||
// The ImageData from which the texture is created. May be null if
|
// The ImageData from which the texture is created. May be null if
|
||||||
// Compressed image data was used to create the texture.
|
// Compressed image data was used to create the texture.
|
||||||
Object::StrongRef<love::image::ImageData> data;
|
Object::StrongRef<love::image::ImageData> data;
|
||||||
@@ -183,19 +191,11 @@ private:
|
|||||||
|
|
||||||
size_t textureMemorySize;
|
size_t textureMemorySize;
|
||||||
|
|
||||||
void preload();
|
|
||||||
|
|
||||||
void uploadCompressedData();
|
|
||||||
void uploadImageData();
|
|
||||||
void uploadTexture();
|
|
||||||
|
|
||||||
static float maxMipmapSharpness;
|
static float maxMipmapSharpness;
|
||||||
|
|
||||||
static FilterMode defaultMipmapFilter;
|
static FilterMode defaultMipmapFilter;
|
||||||
static float defaultMipmapSharpness;
|
static float defaultMipmapSharpness;
|
||||||
|
|
||||||
GLenum getCompressedFormat(image::CompressedData::Format cformat) const;
|
|
||||||
|
|
||||||
static StringMap<FlagType, FLAG_TYPE_MAX_ENUM>::Entry flagNameEntries[];
|
static StringMap<FlagType, FLAG_TYPE_MAX_ENUM>::Entry flagNameEntries[];
|
||||||
static StringMap<FlagType, FLAG_TYPE_MAX_ENUM> flagNames;
|
static StringMap<FlagType, FLAG_TYPE_MAX_ENUM> flagNames;
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,13 @@ int w_Image_isCompressed(lua_State *L)
|
|||||||
int w_Image_refresh(lua_State *L)
|
int w_Image_refresh(lua_State *L)
|
||||||
{
|
{
|
||||||
Image *i = luax_checkimage(L, 1);
|
Image *i = luax_checkimage(L, 1);
|
||||||
luax_catchexcept(L, [&](){ i->refresh(); });
|
|
||||||
|
int xoffset = luaL_optint(L, 2, 0);
|
||||||
|
int yoffset = luaL_optint(L, 3, 0);
|
||||||
|
int w = luaL_optint(L, 4, i->getWidth());
|
||||||
|
int h = luaL_optint(L, 5, i->getHeight());
|
||||||
|
|
||||||
|
luax_catchexcept(L, [&](){ i->refresh(xoffset, yoffset, w, h); });
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user