diff --git a/src/libraries/ddsparse/ddsparse.cpp b/src/libraries/ddsparse/ddsparse.cpp index 0046a24f3..cf248b359 100644 --- a/src/libraries/ddsparse/ddsparse.cpp +++ b/src/libraries/ddsparse/ddsparse.cpp @@ -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. if (dataSize < (sizeof(uint32_t) + sizeof(DDSHeader) + sizeof(DDSHeader10))) return false; - } return true; @@ -106,7 +105,6 @@ Parser::Parser(const Parser &other) if ((options & OPTIONS_COPY_DATA) && img.dataSize > 0) { uint8_t *data = 0; - try { data = new uint8_t[img.dataSize]; @@ -116,7 +114,7 @@ Parser::Parser(const Parser &other) clearData(); throw; } - + memcpy(data, it->data, img.dataSize); img.data = data; } @@ -164,7 +162,9 @@ Format Parser::parseDDSFormat(const DDSPixelFormat &fmt) const else if (fmt.fourCC == FourCC('D','X','T','5')) return FORMAT_DXT5; 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; @@ -196,7 +196,7 @@ Format Parser::parseDX10Format(DXGIFormat fmt) const break; case DXGI_FORMAT_BC5_TYPELESS: case DXGI_FORMAT_BC5_UNORM: - f = FORMAT_BC5u; + f = FORMAT_BC5; break; case DXGI_FORMAT_BC7_TYPELESS: 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_DXT5: case FORMAT_BC5s: - case FORMAT_BC5u: + case FORMAT_BC5: case FORMAT_BC7: 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) { uint8_t *newData = 0; - try { newData = new uint8_t[img.dataSize]; @@ -280,7 +279,6 @@ bool Parser::parseTexData(const uint8_t *data, size_t dataSize, Format fmt, int clearData(); throw; } - memcpy(newData, &data[offset], img.dataSize); img.data = newData; } diff --git a/src/libraries/ddsparse/ddsparse.h b/src/libraries/ddsparse/ddsparse.h index d0c3f89d9..0e84b001b 100644 --- a/src/libraries/ddsparse/ddsparse.h +++ b/src/libraries/ddsparse/ddsparse.h @@ -43,7 +43,7 @@ enum Format FORMAT_DXT3, FORMAT_DXT5, FORMAT_BC5s, // Signed. - FORMAT_BC5u, // Unsigned. + FORMAT_BC5, // Unsigned. FORMAT_BC7, FORMAT_BC7srgb, // sRGB color space. FORMAT_UNKNOWN diff --git a/src/modules/graphics/opengl/Graphics.cpp b/src/modules/graphics/opengl/Graphics.cpp index c90af58a2..1cdf061ab 100644 --- a/src/modules/graphics/opengl/Graphics.cpp +++ b/src/modules/graphics/opengl/Graphics.cpp @@ -224,7 +224,11 @@ void Graphics::present() 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) diff --git a/src/modules/graphics/opengl/Image.cpp b/src/modules/graphics/opengl/Image.cpp index a14b5f46e..beee76181 100644 --- a/src/modules/graphics/opengl/Image.cpp +++ b/src/modules/graphics/opengl/Image.cpp @@ -24,8 +24,6 @@ #include // For memcpy #include // for min/max -#include - namespace love { namespace graphics @@ -146,81 +144,102 @@ void Image::drawq(love::graphics::Quad *quad, float x, float y, float angle, flo 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; - 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(); - 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(); - - // 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)); - } + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAX_LEVEL, numMipmaps - 1); } - 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, // 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()); + 0, + GL_RGBA8, + (GLsizei)width, + (GLsizei)height, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + data->getData()); // More bugs: http://www.opengl.org/wiki/Common_Mistakes#Automatic_mipmap_generation glEnable(GL_TEXTURE_2D); glGenerateMipmap(GL_TEXTURE_2D); } - else if (data) + else { glTexParameteri(GL_TEXTURE_2D, GL_GENERATE_MIPMAP, GL_TRUE); 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()); } +} + +void Image::checkMipmapsCreated() +{ + if (mipmapsCreated || filter.mipmap == FILTER_NONE) + return; + + if (isCompressed && cdata && hasCompressedTextureSupport(cdata->getType())) + uploadCompressedMipmaps(); + else if (data) + createMipmaps(); else return; @@ -262,7 +281,9 @@ void Image::setMipmapSharpness(float sharpness) 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 + + // negative bias is sharper + glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_LOD_BIAS, -mipmapSharpness); } else mipmapSharpness = 0.0f; @@ -325,7 +346,7 @@ bool Image::loadVolatile() if (image::CompressedData::getConstant(cdata->getType(), str)) { 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 throw love::Exception("cannot create image: format is not supported on this system."); @@ -362,17 +383,15 @@ bool Image::loadVolatilePOT() if (isCompressed && cdata) { - if (s != 1.0f || t != 1.0f) + if (s < 1.0f || t < 1.0f) { 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, 0, - format, + getCompressedFormat(cdata->getType()), cdata->getWidth(0), cdata->getHeight(0), 0, @@ -520,7 +539,7 @@ GLenum Image::getCompressedFormat(image::CompressedData::TextureType type) const return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT; case image::CompressedData::TYPE_BC5s: return GL_COMPRESSED_SIGNED_RG_RGTC2; - case image::CompressedData::TYPE_BC5u: + case image::CompressedData::TYPE_BC5: return GL_COMPRESSED_RG_RGTC2; case image::CompressedData::TYPE_BC7: return GL_COMPRESSED_RGBA_BPTC_UNORM_ARB; @@ -569,8 +588,8 @@ bool Image::hasCompressedTextureSupport(image::CompressedData::TextureType type) return GLEE_EXT_texture_compression_s3tc; case image::CompressedData::TYPE_BC5s: - case image::CompressedData::TYPE_BC5u: - return (GLEE_VERSION_3_0 || GLEE_ARB_texture_compression_rgtc); + case image::CompressedData::TYPE_BC5: + return (GLEE_VERSION_3_0 || GLEE_ARB_texture_compression_rgtc || GLEE_EXT_texture_compression_rgtc); case image::CompressedData::TYPE_BC7: case image::CompressedData::TYPE_BC7srgb: diff --git a/src/modules/graphics/opengl/Image.h b/src/modules/graphics/opengl/Image.h index ba3d2d885..2c12bf125 100644 --- a/src/modules/graphics/opengl/Image.h +++ b/src/modules/graphics/opengl/Image.h @@ -180,6 +180,8 @@ private: bool loadVolatilePOT(); bool loadVolatileNPOT(); + void uploadCompressedMipmaps(); + void createMipmaps(); void checkMipmapsCreated(); static float maxMipmapSharpness; diff --git a/src/modules/graphics/opengl/wrap_Graphics.cpp b/src/modules/graphics/opengl/wrap_Graphics.cpp index 9813ecb22..6ab99669b 100644 --- a/src/modules/graphics/opengl/wrap_Graphics.cpp +++ b/src/modules/graphics/opengl/wrap_Graphics.cpp @@ -158,7 +158,14 @@ int w_present(lua_State *) int w_setIcon(lua_State *L) { Image *image = luax_checktype(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; } @@ -1139,7 +1146,7 @@ int w_isSupported(lua_State *L) supported = false; break; case Graphics::SUPPORT_BC5: - if (!Image::hasCompressedTextureSupport(image::CompressedData::TYPE_BC5u)) + if (!Image::hasCompressedTextureSupport(image::CompressedData::TYPE_BC5)) supported = false; break; case Graphics::SUPPORT_BC7: diff --git a/src/modules/image/CompressedData.cpp b/src/modules/image/CompressedData.cpp index 236863e85..8a34c1529 100644 --- a/src/modules/image/CompressedData.cpp +++ b/src/modules/image/CompressedData.cpp @@ -112,7 +112,7 @@ StringMap::Entry Com {"dxt3", CompressedData::TYPE_DXT3}, {"dxt5", CompressedData::TYPE_DXT5}, {"bc5s", CompressedData::TYPE_BC5s}, - {"bc5u", CompressedData::TYPE_BC5u}, + {"bc5", CompressedData::TYPE_BC5}, {"bc7", CompressedData::TYPE_BC7}, {"bc7srgb", CompressedData::TYPE_BC7srgb}, }; diff --git a/src/modules/image/CompressedData.h b/src/modules/image/CompressedData.h index 2ac3b9021..e4710f96b 100644 --- a/src/modules/image/CompressedData.h +++ b/src/modules/image/CompressedData.h @@ -36,19 +36,22 @@ namespace love 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 { public: - // + // Types of compressed image data. enum TextureType { TYPE_DXT1, TYPE_DXT3, TYPE_DXT5, TYPE_BC5s, - TYPE_BC5u, + TYPE_BC5, TYPE_BC7, TYPE_BC7srgb, TYPE_MAX_ENUM diff --git a/src/modules/image/Image.h b/src/modules/image/Image.h index c9aefadf3..469c44c51 100644 --- a/src/modules/image/Image.h +++ b/src/modules/image/Image.h @@ -79,22 +79,28 @@ public: 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; /** - * + * 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; /** - * + * Determines whether a File is Compressed image data or not. + * @param file The file to test. **/ 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; diff --git a/src/modules/image/devil/CompressedData.cpp b/src/modules/image/devil/CompressedData.cpp index 831dbb8e2..8bcff4434 100644 --- a/src/modules/image/devil/CompressedData.cpp +++ b/src/modules/image/devil/CompressedData.cpp @@ -67,8 +67,8 @@ bool CompressedData::convertFormat(dds::Format ddsformat) case dds::FORMAT_BC5s: type = TYPE_BC5s; break; - case dds::FORMAT_BC5u: - type = TYPE_BC5u; + case dds::FORMAT_BC5: + type = TYPE_BC5; break; case dds::FORMAT_BC7: type = TYPE_BC7; diff --git a/src/modules/image/devil/Image.cpp b/src/modules/image/devil/Image.cpp index eba49f71e..06240d22d 100644 --- a/src/modules/image/devil/Image.cpp +++ b/src/modules/image/devil/Image.cpp @@ -105,7 +105,7 @@ bool Image::isCompressed(love::filesystem::File *file) // Check whether the actual data is compressed. Data *data = file->read(); - bool compressed = CompressedData::isCompressed(data); + bool compressed = isCompressed(data); data->release(); return compressed;