mirror of
https://github.com/love2d/love.git
synced 2026-08-16 16:20:42 +02:00
ImageData (and Images loaded from them) now support different data formats. Resolves issue #1048.
Currently exposed formats are rgba8 and rgba16 (normalized), and rgba16f and rgba32f (floating-point). Some systems, especially mobile ones, won't support every format when creating a love.graphics Image. Use love.graphics.getRawImageFormats to check for support. love.image.newImageData now takes an optional format parameter as its third argument when creating an empty sized ImageData. It defaults to rgba8. 16-bit PNGs, .hdr images, and floating-point OpenEXR images can now be loaded via love.image.newImageData and love.graphics.newImage. --HG-- branch : minor
This commit is contained in:
@@ -633,7 +633,7 @@ love::image::ImageData *Canvas::newImageData(love::image::Image *image, int x, i
|
||||
gl.bindFramebuffer(GL_FRAMEBUFFER, prevfbo);
|
||||
|
||||
// The new ImageData now owns the pixel data, so we don't delete it here.
|
||||
return image->newImageData(w, h, pixels, true);
|
||||
return image->newImageData(w, h, image::ImageData::FORMAT_RGBA8, pixels, true);
|
||||
}
|
||||
|
||||
bool Canvas::resolveMSAA(bool restoreprev)
|
||||
|
||||
@@ -1600,7 +1600,7 @@ love::image::ImageData *Graphics::newScreenshot(love::image::Image *image, bool
|
||||
{
|
||||
// Tell the new ImageData that it owns the screenshot data, so we don't
|
||||
// need to delete it here.
|
||||
img = image->newImageData(w, h, (void *) screenshot, true);
|
||||
img = image->newImageData(w, h, image::ImageData::FORMAT_RGBA8, screenshot, true);
|
||||
}
|
||||
catch (love::Exception &)
|
||||
{
|
||||
|
||||
@@ -66,6 +66,8 @@ static bool verifyMipmapLevels(const std::vector<T> &miplevels)
|
||||
int width = miplevels[0]->getWidth();
|
||||
int height = miplevels[0]->getHeight();
|
||||
|
||||
auto format = miplevels[0]->getFormat();
|
||||
|
||||
int expectedlevels = getMipmapCount(width, height);
|
||||
|
||||
// All mip levels must be present when not using auto-generated mipmaps.
|
||||
@@ -82,6 +84,9 @@ static bool verifyMipmapLevels(const std::vector<T> &miplevels)
|
||||
throw love::Exception("Width of image mipmap level %d is incorrect (expected %d, got %d)", i+1, width, miplevels[i]->getWidth());
|
||||
if (miplevels[i]->getHeight() != height)
|
||||
throw love::Exception("Height of image mipmap level %d is incorrect (expected %d, got %d)", i+1, height, miplevels[i]->getHeight());
|
||||
|
||||
if (miplevels[i]->getFormat() != format)
|
||||
throw love::Exception("All image mipmap levels must have the same format.");
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -140,12 +145,8 @@ Image::Image(const std::vector<love::image::CompressedImageData *> &compressedda
|
||||
}
|
||||
}
|
||||
|
||||
for (const auto &cd : compresseddata)
|
||||
{
|
||||
for (image::CompressedImageData *cd : compresseddata)
|
||||
cdata.push_back(cd);
|
||||
if (cd->getFormat() != cdata[0]->getFormat())
|
||||
throw love::Exception("All image mipmap levels must have the same format.");
|
||||
}
|
||||
|
||||
preload();
|
||||
loadVolatile();
|
||||
@@ -256,15 +257,12 @@ void Image::loadFromCompressedData()
|
||||
|
||||
void Image::loadFromImageData()
|
||||
{
|
||||
GLenum iformat = sRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8;
|
||||
GLenum format = GL_RGBA;
|
||||
GLenum glformat = GL_RGBA;
|
||||
GLenum gltype = GL_UNSIGNED_BYTE;
|
||||
GLenum iformat = getFormat(data[0]->getFormat(), glformat, gltype, sRGB);
|
||||
|
||||
// in GLES2, the internalformat and format params of TexImage have to match.
|
||||
if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
|
||||
{
|
||||
format = sRGB ? GL_SRGB_ALPHA : GL_RGBA;
|
||||
iformat = format;
|
||||
}
|
||||
if (isGammaCorrect() && !sRGB)
|
||||
flags.linear = true;
|
||||
|
||||
int mipcount = flags.mipmaps ? (int) data.size() : 1;
|
||||
|
||||
@@ -274,7 +272,7 @@ void Image::loadFromImageData()
|
||||
love::thread::Lock lock(id->getMutex());
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, i, iformat, id->getWidth(), id->getHeight(),
|
||||
0, format, GL_UNSIGNED_BYTE, id->getData());
|
||||
0, glformat, gltype, id->getData());
|
||||
}
|
||||
|
||||
if (data.size() <= 1)
|
||||
@@ -416,12 +414,9 @@ bool Image::refresh(int xoffset, int yoffset, int w, int h)
|
||||
return true;
|
||||
}
|
||||
|
||||
GLenum format = GL_RGBA;
|
||||
|
||||
// In ES2, the format parameter of TexSubImage must match the internal
|
||||
// format of the texture.
|
||||
if (sRGB && (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0))
|
||||
format = GL_SRGB_ALPHA;
|
||||
GLenum glformat = GL_RGBA;
|
||||
GLenum gltype = GL_UNSIGNED_BYTE;
|
||||
getFormat(data[0]->getFormat(), glformat, gltype, sRGB);
|
||||
|
||||
int mipcount = flags.mipmaps ? (int) data.size() : 1;
|
||||
|
||||
@@ -432,8 +427,8 @@ bool Image::refresh(int xoffset, int yoffset, int w, int h)
|
||||
pdata += yoffset * data[i]->getWidth() + xoffset;
|
||||
|
||||
thread::Lock lock(data[i]->getMutex());
|
||||
glTexSubImage2D(GL_TEXTURE_2D, i, xoffset, yoffset, w, h, format,
|
||||
GL_UNSIGNED_BYTE, pdata);
|
||||
glTexSubImage2D(GL_TEXTURE_2D, i, xoffset, yoffset, w, h, glformat,
|
||||
gltype, pdata);
|
||||
|
||||
xoffset /= 2;
|
||||
yoffset /= 2;
|
||||
@@ -596,6 +591,53 @@ bool Image::isCompressed() const
|
||||
return compressed;
|
||||
}
|
||||
|
||||
GLenum Image::getFormat(image::ImageData::Format format, GLenum &glformat, GLenum &gltype, bool &isSRGB) const
|
||||
{
|
||||
using image::ImageData;
|
||||
|
||||
GLenum internalformat = GL_RGBA8;
|
||||
glformat = GL_RGBA;
|
||||
gltype = GL_UNSIGNED_BYTE;
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case ImageData::FORMAT_RGBA8:
|
||||
if (isSRGB)
|
||||
{
|
||||
internalformat = GL_SRGB8_ALPHA8;
|
||||
if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
|
||||
glformat = GL_SRGB_ALPHA;
|
||||
}
|
||||
break;
|
||||
case ImageData::FORMAT_RGBA16:
|
||||
internalformat = GL_RGBA16;
|
||||
gltype = GL_UNSIGNED_SHORT;
|
||||
isSRGB = false;
|
||||
break;
|
||||
case ImageData::FORMAT_RGBA16F:
|
||||
internalformat = GL_RGBA16F;
|
||||
// HALF_FLOAT_OES has a different value than HALF_FLOAT... of course
|
||||
if (GLAD_OES_texture_half_float && !GLAD_ES_VERSION_3_0)
|
||||
gltype = GL_HALF_FLOAT_OES;
|
||||
else
|
||||
gltype = GL_HALF_FLOAT;
|
||||
isSRGB = false;
|
||||
break;
|
||||
case ImageData::FORMAT_RGBA32F:
|
||||
internalformat = GL_RGBA32F;
|
||||
gltype = GL_FLOAT;
|
||||
isSRGB = false;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
|
||||
internalformat = glformat;
|
||||
|
||||
return internalformat;
|
||||
}
|
||||
|
||||
GLenum Image::getCompressedFormat(image::CompressedImageData::Format cformat, bool &isSRGB) const
|
||||
{
|
||||
using image::CompressedImageData;
|
||||
@@ -701,6 +743,38 @@ bool Image::hasAnisotropicFilteringSupport()
|
||||
return GLAD_EXT_texture_filter_anisotropic != GL_FALSE;
|
||||
}
|
||||
|
||||
bool Image::hasTextureSupport(image::ImageData::Format format)
|
||||
{
|
||||
using image::ImageData;
|
||||
|
||||
switch (format)
|
||||
{
|
||||
case ImageData::FORMAT_RGBA8:
|
||||
return true;
|
||||
case ImageData::FORMAT_RGBA16:
|
||||
return GLAD_VERSION_1_1 || GLAD_EXT_texture_norm16;
|
||||
case ImageData::FORMAT_RGBA16F:
|
||||
return GLAD_VERSION_3_0 || (GLAD_ARB_texture_float && GLAD_ARB_half_float_pixel) || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float;
|
||||
case ImageData::FORMAT_RGBA32F:
|
||||
return GLAD_VERSION_3_0 || GLAD_ARB_texture_float || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_float;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool Image::hasTextureFilteringSupport(image::ImageData::Format format)
|
||||
{
|
||||
switch (format)
|
||||
{
|
||||
case image::ImageData::FORMAT_RGBA16F:
|
||||
return GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float_linear;
|
||||
case image::ImageData::FORMAT_RGBA32F:
|
||||
return GLAD_VERSION_1_1;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool Image::hasCompressedTextureSupport(image::CompressedImageData::Format format, bool sRGB)
|
||||
{
|
||||
using image::CompressedImageData;
|
||||
|
||||
@@ -128,6 +128,8 @@ public:
|
||||
static FilterMode getDefaultMipmapFilter();
|
||||
|
||||
static bool hasAnisotropicFilteringSupport();
|
||||
static bool hasTextureSupport(image::ImageData::Format format);
|
||||
static bool hasTextureFilteringSupport(image::ImageData::Format format);
|
||||
static bool hasCompressedTextureSupport(image::CompressedImageData::Format format, bool sRGB);
|
||||
static bool hasSRGBSupport();
|
||||
|
||||
@@ -147,6 +149,7 @@ private:
|
||||
void loadFromCompressedData();
|
||||
void loadFromImageData();
|
||||
|
||||
GLenum getFormat(image::ImageData::Format format, GLenum &glformat, GLenum &gltype, bool &isSRGB) const;
|
||||
GLenum getCompressedFormat(image::CompressedImageData::Format cformat, bool &isSRGB) const;
|
||||
|
||||
// The ImageData from which the texture is created. May be empty if
|
||||
|
||||
@@ -1416,13 +1416,32 @@ int w_getCanvasFormats(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_getRawImageFormats(lua_State *L)
|
||||
{
|
||||
lua_createtable(L, 0, (int) image::ImageData::FORMAT_MAX_ENUM);
|
||||
|
||||
for (int i = 0; i < (int) image::ImageData::FORMAT_MAX_ENUM; i++)
|
||||
{
|
||||
auto format = (image::ImageData::Format) i;
|
||||
const char *name = nullptr;
|
||||
|
||||
if (!image::ImageData::getConstant(format, name))
|
||||
continue;
|
||||
|
||||
luax_pushboolean(L, Image::hasTextureSupport(format));
|
||||
lua_setfield(L, -2, name);
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int w_getCompressedImageFormats(lua_State *L)
|
||||
{
|
||||
lua_createtable(L, 0, (int) image::CompressedImageData::FORMAT_MAX_ENUM);
|
||||
|
||||
for (int i = 0; i < (int) image::CompressedImageData::FORMAT_MAX_ENUM; i++)
|
||||
{
|
||||
image::CompressedImageData::Format format = (image::CompressedImageData::Format) i;
|
||||
auto format = (image::CompressedImageData::Format) i;
|
||||
const char *name = nullptr;
|
||||
|
||||
if (format == image::CompressedImageData::FORMAT_UNKNOWN)
|
||||
@@ -1996,6 +2015,7 @@ static const luaL_Reg functions[] =
|
||||
|
||||
{ "getSupported", w_getSupported },
|
||||
{ "getCanvasFormats", w_getCanvasFormats },
|
||||
{ "getRawImageFormats", w_getRawImageFormats },
|
||||
{ "getCompressedImageFormats", w_getCompressedImageFormats },
|
||||
{ "getRendererInfo", w_getRendererInfo },
|
||||
{ "getSystemLimits", w_getSystemLimits },
|
||||
|
||||
Reference in New Issue
Block a user