Code cleanup

--HG--
branch : image-CompressedData
This commit is contained in:
Alex Szpakowski
2013-04-05 18:55:44 -03:00
parent 5301026f3c
commit 8a8adcce39
11 changed files with 129 additions and 90 deletions
+6 -8
View File
@@ -81,7 +81,6 @@ bool Parser::isDDS(const void *data, size_t dataSize)
// Data must be big enough for both headers plus the magic value. // Data must be big enough for both headers plus the magic value.
if (dataSize < (sizeof(uint32_t) + sizeof(DDSHeader) + sizeof(DDSHeader10))) if (dataSize < (sizeof(uint32_t) + sizeof(DDSHeader) + sizeof(DDSHeader10)))
return false; return false;
} }
return true; return true;
@@ -106,7 +105,6 @@ Parser::Parser(const Parser &other)
if ((options & OPTIONS_COPY_DATA) && img.dataSize > 0) if ((options & OPTIONS_COPY_DATA) && img.dataSize > 0)
{ {
uint8_t *data = 0; uint8_t *data = 0;
try try
{ {
data = new uint8_t[img.dataSize]; data = new uint8_t[img.dataSize];
@@ -116,7 +114,7 @@ Parser::Parser(const Parser &other)
clearData(); clearData();
throw; throw;
} }
memcpy(data, it->data, img.dataSize);
img.data = data; img.data = data;
} }
@@ -164,7 +162,9 @@ Format Parser::parseDDSFormat(const DDSPixelFormat &fmt) const
else if (fmt.fourCC == FourCC('D','X','T','5')) else if (fmt.fourCC == FourCC('D','X','T','5'))
return FORMAT_DXT5; return FORMAT_DXT5;
else if (fmt.fourCC == FourCC('A','T','I','2')) else if (fmt.fourCC == FourCC('A','T','I','2'))
return FORMAT_BC5u; return FORMAT_BC5;
else if (fmt.fourCC == FourCC('B','C','5','S'))
return FORMAT_BC5s;
} }
return FORMAT_UNKNOWN; return FORMAT_UNKNOWN;
@@ -196,7 +196,7 @@ Format Parser::parseDX10Format(DXGIFormat fmt) const
break; break;
case DXGI_FORMAT_BC5_TYPELESS: case DXGI_FORMAT_BC5_TYPELESS:
case DXGI_FORMAT_BC5_UNORM: case DXGI_FORMAT_BC5_UNORM:
f = FORMAT_BC5u; f = FORMAT_BC5;
break; break;
case DXGI_FORMAT_BC7_TYPELESS: case DXGI_FORMAT_BC7_TYPELESS:
case DXGI_FORMAT_BC7_UNORM: case DXGI_FORMAT_BC7_UNORM:
@@ -221,7 +221,7 @@ size_t Parser::parseImageSize(Format fmt, int width, int height) const
case FORMAT_DXT3: case FORMAT_DXT3:
case FORMAT_DXT5: case FORMAT_DXT5:
case FORMAT_BC5s: case FORMAT_BC5s:
case FORMAT_BC5u: case FORMAT_BC5:
case FORMAT_BC7: case FORMAT_BC7:
case FORMAT_BC7srgb: case FORMAT_BC7srgb:
{ {
@@ -269,7 +269,6 @@ bool Parser::parseTexData(const uint8_t *data, size_t dataSize, Format fmt, int
if (options & OPTIONS_COPY_DATA) if (options & OPTIONS_COPY_DATA)
{ {
uint8_t *newData = 0; uint8_t *newData = 0;
try try
{ {
newData = new uint8_t[img.dataSize]; newData = new uint8_t[img.dataSize];
@@ -280,7 +279,6 @@ bool Parser::parseTexData(const uint8_t *data, size_t dataSize, Format fmt, int
clearData(); clearData();
throw; throw;
} }
memcpy(newData, &data[offset], img.dataSize); memcpy(newData, &data[offset], img.dataSize);
img.data = newData; img.data = newData;
} }
+1 -1
View File
@@ -43,7 +43,7 @@ enum Format
FORMAT_DXT3, FORMAT_DXT3,
FORMAT_DXT5, FORMAT_DXT5,
FORMAT_BC5s, // Signed. FORMAT_BC5s, // Signed.
FORMAT_BC5u, // Unsigned. FORMAT_BC5, // Unsigned.
FORMAT_BC7, FORMAT_BC7,
FORMAT_BC7srgb, // sRGB color space. FORMAT_BC7srgb, // sRGB color space.
FORMAT_UNKNOWN FORMAT_UNKNOWN
+5 -1
View File
@@ -224,7 +224,11 @@ void Graphics::present()
void Graphics::setIcon(Image *image) void Graphics::setIcon(Image *image)
{ {
currentWindow->setIcon(image->getData()); love::image::ImageData *data = image->getData();
if (data)
currentWindow->setIcon(data);
else
throw love::Exception("Cannot use compressed image data to set an icon.");
} }
void Graphics::setCaption(const char *caption) void Graphics::setCaption(const char *caption)
+86 -67
View File
@@ -24,8 +24,6 @@
#include <cstring> // For memcpy #include <cstring> // For memcpy
#include <algorithm> // for min/max #include <algorithm> // for min/max
#include <iostream>
namespace love namespace love
{ {
namespace graphics namespace graphics
@@ -146,81 +144,102 @@ void Image::drawq(love::graphics::Quad *quad, float x, float y, float angle, flo
drawv(t, v); drawv(t, v);
} }
void Image::checkMipmapsCreated() void Image::uploadCompressedMipmaps()
{ {
if (mipmapsCreated || (filter.mipmap != FILTER_NEAREST && filter.mipmap != FILTER_LINEAR)) if (!isCompressed || !cdata || !hasCompressedTextureSupport(cdata->getType()))
return; return;
if (!(isCompressed && cdata) && !hasMipmapSupport())
throw love::Exception("Mipmap filtering is not supported on this system.");
// 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 (!isCompressed && (w != next_p2(w) || h != next_p2(h)))
throw love::Exception("Cannot create mipmaps: image does not have power of two dimensions.");
bind(); bind();
if (isCompressed && cdata && hasCompressedTextureSupport(cdata->getType())) int numMipmaps = cdata->getNumMipmaps();
// We have to inform OpenGL if the image doesn't have all mipmap levels.
if (GLEE_VERSION_1_2 || GLEE_SGIS_texture_lod)
{ {
int numMipmaps = cdata->getNumMipmaps(); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, numMipmaps - 1);
// We have to inform OpenGL if the image doesn't have all mipmap levels.
if (GLEE_VERSION_1_2 || GLEE_SGIS_texture_lod)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, numMipmaps - 1);
else if (cdata->getWidth(numMipmaps-1) > 1 || cdata->getHeight(numMipmaps-1) > 1)
{
// Telling OpenGL to ignore certain levels isn't always supported.
throw love::Exception("Cannot load mipmaps: "
"compressed image does not have all required levels.");
}
GLenum format = getCompressedFormat(cdata->getType());
for (int i = 1; i < numMipmaps; i++)
{
glCompressedTexImage2DARB(GL_TEXTURE_2D,
i,
format,
cdata->getWidth(i),
cdata->getHeight(i),
0,
GLsizei(cdata->getSize(i)),
cdata->getData(i));
}
} }
else if (data && hasNpot() && (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object)) else if (cdata->getWidth(numMipmaps-1) > 1 || cdata->getHeight(numMipmaps-1) > 1)
{
// Telling OpenGL to ignore certain levels isn't always supported.
throw love::Exception("Cannot load mipmaps: "
"compressed image does not have all required levels.");
}
for (int i = 1; i < numMipmaps; i++)
{
glCompressedTexImage2DARB(GL_TEXTURE_2D,
i,
getCompressedFormat(cdata->getType()),
cdata->getWidth(i),
cdata->getHeight(i),
0,
GLsizei(cdata->getSize(i)),
cdata->getData(i));
}
}
void Image::createMipmaps()
{
if (!data)
return;
if (!hasMipmapSupport())
throw love::Exception("Mipmap filtering is not supported on this system.");
// 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("Cannot create mipmaps: "
"image does not have power of two dimensions.");
}
bind();
if (hasNpot() && (GLEE_VERSION_3_0 || GLEE_ARB_framebuffer_object))
{ {
// AMD/ATI drivers have several bugs when generating mipmaps, // AMD/ATI drivers have several bugs when generating mipmaps,
// re-uploading the entire base image seems to be required. // re-uploading the entire base image seems to be required.
glTexImage2D(GL_TEXTURE_2D, glTexImage2D(GL_TEXTURE_2D,
0, 0,
GL_RGBA8, GL_RGBA8,
(GLsizei)width, (GLsizei)width,
(GLsizei)height, (GLsizei)height,
0, 0,
GL_RGBA, GL_RGBA,
GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE,
data->getData()); data->getData());
// More bugs: http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation // More bugs: http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation
glEnable(GL_TEXTURE_2D); glEnable(GL_TEXTURE_2D);
glGenerateMipmap(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D);
} }
else if (data) else
{ {
glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE);
glTexSubImage2D(GL_TEXTURE_2D, glTexSubImage2D(GL_TEXTURE_2D,
0, 0,
0, 0,
0, 0,
(GLsizei)width, (GLsizei)width,
(GLsizei)height, (GLsizei)height,
GL_RGBA, GL_RGBA,
GL_UNSIGNED_BYTE, GL_UNSIGNED_BYTE,
data->getData()); data->getData());
} }
}
void Image::checkMipmapsCreated()
{
if (mipmapsCreated || filter.mipmap == FILTER_NONE)
return;
if (isCompressed && cdata && hasCompressedTextureSupport(cdata->getType()))
uploadCompressedMipmaps();
else if (data)
createMipmaps();
else else
return; return;
@@ -262,7 +281,9 @@ void Image::setMipmapSharpness(float sharpness)
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(); bind();
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapSharpness); // negative bias is sharper
// negative bias is sharper
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapSharpness);
} }
else else
mipmapSharpness = 0.0f; mipmapSharpness = 0.0f;
@@ -325,7 +346,7 @@ bool Image::loadVolatile()
if (image::CompressedData::getConstant(cdata->getType(), str)) if (image::CompressedData::getConstant(cdata->getType(), str))
{ {
throw love::Exception("Cannot create image: " throw love::Exception("Cannot create image: "
"%s compressed images are not supported on this system.", str); "%s compressed images are not supported on this system.", str);
} }
else else
throw love::Exception("cannot create image: format is not supported on this system."); throw love::Exception("cannot create image: format is not supported on this system.");
@@ -362,17 +383,15 @@ bool Image::loadVolatilePOT()
if (isCompressed && cdata) if (isCompressed && cdata)
{ {
if (s != 1.0f || t != 1.0f) if (s < 1.0f || t < 1.0f)
{ {
throw love::Exception("Cannot create image: " throw love::Exception("Cannot create image: "
"NPOT compressed images are not supported on this system."); "compressed NPOT images are not supported on this system.");
} }
GLenum format = getCompressedFormat(cdata->getType());
glCompressedTexImage2DARB(GL_TEXTURE_2D, glCompressedTexImage2DARB(GL_TEXTURE_2D,
0, 0,
format, getCompressedFormat(cdata->getType()),
cdata->getWidth(0), cdata->getWidth(0),
cdata->getHeight(0), cdata->getHeight(0),
0, 0,
@@ -520,7 +539,7 @@ GLenum Image::getCompressedFormat(image::CompressedData::TextureType type) const
return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
case image::CompressedData::TYPE_BC5s: case image::CompressedData::TYPE_BC5s:
return GL_COMPRESSED_SIGNED_RG_RGTC2; return GL_COMPRESSED_SIGNED_RG_RGTC2;
case image::CompressedData::TYPE_BC5u: case image::CompressedData::TYPE_BC5:
return GL_COMPRESSED_RG_RGTC2; return GL_COMPRESSED_RG_RGTC2;
case image::CompressedData::TYPE_BC7: case image::CompressedData::TYPE_BC7:
return GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; return GL_COMPRESSED_RGBA_BPTC_UNORM_ARB;
@@ -569,8 +588,8 @@ bool Image::hasCompressedTextureSupport(image::CompressedData::TextureType type)
return GLEE_EXT_texture_compression_s3tc; return GLEE_EXT_texture_compression_s3tc;
case image::CompressedData::TYPE_BC5s: case image::CompressedData::TYPE_BC5s:
case image::CompressedData::TYPE_BC5u: case image::CompressedData::TYPE_BC5:
return (GLEE_VERSION_3_0 || GLEE_ARB_texture_compression_rgtc); return (GLEE_VERSION_3_0 || GLEE_ARB_texture_compression_rgtc || GLEE_EXT_texture_compression_rgtc);
case image::CompressedData::TYPE_BC7: case image::CompressedData::TYPE_BC7:
case image::CompressedData::TYPE_BC7srgb: case image::CompressedData::TYPE_BC7srgb:
+2
View File
@@ -180,6 +180,8 @@ private:
bool loadVolatilePOT(); bool loadVolatilePOT();
bool loadVolatileNPOT(); bool loadVolatileNPOT();
void uploadCompressedMipmaps();
void createMipmaps();
void checkMipmapsCreated(); void checkMipmapsCreated();
static float maxMipmapSharpness; static float maxMipmapSharpness;
@@ -158,7 +158,14 @@ int w_present(lua_State *)
int w_setIcon(lua_State *L) int w_setIcon(lua_State *L)
{ {
Image *image = luax_checktype<Image>(L, 1, "Image", GRAPHICS_IMAGE_T); Image *image = luax_checktype<Image>(L, 1, "Image", GRAPHICS_IMAGE_T);
instance->setIcon(image); try
{
instance->setIcon(image);
}
catch (love::Exception &e)
{
return luaL_error(L, "%s", e.what());
}
return 0; return 0;
} }
@@ -1139,7 +1146,7 @@ int w_isSupported(lua_State *L)
supported = false; supported = false;
break; break;
case Graphics::SUPPORT_BC5: case Graphics::SUPPORT_BC5:
if (!Image::hasCompressedTextureSupport(image::CompressedData::TYPE_BC5u)) if (!Image::hasCompressedTextureSupport(image::CompressedData::TYPE_BC5))
supported = false; supported = false;
break; break;
case Graphics::SUPPORT_BC7: case Graphics::SUPPORT_BC7:
+1 -1
View File
@@ -112,7 +112,7 @@ StringMap<CompressedData::TextureType, CompressedData::TYPE_MAX_ENUM>::Entry Com
{"dxt3", CompressedData::TYPE_DXT3}, {"dxt3", CompressedData::TYPE_DXT3},
{"dxt5", CompressedData::TYPE_DXT5}, {"dxt5", CompressedData::TYPE_DXT5},
{"bc5s", CompressedData::TYPE_BC5s}, {"bc5s", CompressedData::TYPE_BC5s},
{"bc5u", CompressedData::TYPE_BC5u}, {"bc5", CompressedData::TYPE_BC5},
{"bc7", CompressedData::TYPE_BC7}, {"bc7", CompressedData::TYPE_BC7},
{"bc7srgb", CompressedData::TYPE_BC7srgb}, {"bc7srgb", CompressedData::TYPE_BC7srgb},
}; };
+6 -3
View File
@@ -36,19 +36,22 @@ namespace love
namespace image namespace image
{ {
// // CompressedData represents image data which is designed to be uploaded to the
// GPU and rendered in its compressed form, without being un-compressed.
// http://renderingpipeline.com/2012/07/texture-compression/
class CompressedData : public Data class CompressedData : public Data
{ {
public: public:
// // Types of compressed image data.
enum TextureType enum TextureType
{ {
TYPE_DXT1, TYPE_DXT1,
TYPE_DXT3, TYPE_DXT3,
TYPE_DXT5, TYPE_DXT5,
TYPE_BC5s, TYPE_BC5s,
TYPE_BC5u, TYPE_BC5,
TYPE_BC7, TYPE_BC7,
TYPE_BC7srgb, TYPE_BC7srgb,
TYPE_MAX_ENUM TYPE_MAX_ENUM
+10 -4
View File
@@ -79,22 +79,28 @@ public:
virtual ImageData *newImageData(int width, int height, void *data) = 0; virtual ImageData *newImageData(int width, int height, void *data) = 0;
/** /**
* * Creates new CompressedData from a file.
* @param file The file containing the compressed image data.
* @return The new CompressedData.
**/ **/
virtual CompressedData *newCompressedData(love::filesystem::File *file) = 0; virtual CompressedData *newCompressedData(love::filesystem::File *file) = 0;
/** /**
* * Creates new CompressedData from a raw Data.
* @param data The object containing the compressed image data.
* @return The new CompressedData.
**/ **/
virtual CompressedData *newCompressedData(Data *data) = 0; virtual CompressedData *newCompressedData(Data *data) = 0;
/** /**
* * Determines whether a File is Compressed image data or not.
* @param file The file to test.
**/ **/
virtual bool isCompressed(love::filesystem::File *file) = 0; virtual bool isCompressed(love::filesystem::File *file) = 0;
/** /**
* * Determines whether a raw Data is Compressed image data or not.
* @param data The data to test.
**/ **/
virtual bool isCompressed(Data *data) = 0; virtual bool isCompressed(Data *data) = 0;
+2 -2
View File
@@ -67,8 +67,8 @@ bool CompressedData::convertFormat(dds::Format ddsformat)
case dds::FORMAT_BC5s: case dds::FORMAT_BC5s:
type = TYPE_BC5s; type = TYPE_BC5s;
break; break;
case dds::FORMAT_BC5u: case dds::FORMAT_BC5:
type = TYPE_BC5u; type = TYPE_BC5;
break; break;
case dds::FORMAT_BC7: case dds::FORMAT_BC7:
type = TYPE_BC7; type = TYPE_BC7;
+1 -1
View File
@@ -105,7 +105,7 @@ bool Image::isCompressed(love::filesystem::File *file)
// Check whether the actual data is compressed. // Check whether the actual data is compressed.
Data *data = file->read(); Data *data = file->read();
bool compressed = CompressedData::isCompressed(data); bool compressed = isCompressed(data);
data->release(); data->release();
return compressed; return compressed;