diff --git a/src/modules/image/CompressedData.cpp b/src/modules/image/CompressedData.cpp index 1f42eb83e..7e0a698c5 100644 --- a/src/modules/image/CompressedData.cpp +++ b/src/modules/image/CompressedData.cpp @@ -27,6 +27,8 @@ namespace image CompressedData::CompressedData() : format(FORMAT_UNKNOWN) + , data(0) + , dataSize(0) { } @@ -36,23 +38,12 @@ CompressedData::~CompressedData() int CompressedData::getSize() const { - // Adding up the total size for all mipmap levels would make more sense, but - // it's probably better for getSize() to match getData() so no bad memory - // accesses happen... - if (dataImages.size() > 0) - return dataImages[0].size; - else - return 0; + return int(dataSize); } void *CompressedData::getData() const { - // Data for different mipmap levels is not stored contiguously in memory, so - // getData() won't work properly for CompressedData. - if (dataImages.size() > 0 && dataImages[0].size > 0) - return (void *) dataImages[0].data; - else - return 0; + return data; } int CompressedData::getMipmapCount() const @@ -64,7 +55,7 @@ int CompressedData::getSize(int miplevel) const { checkMipmapLevelExists(miplevel); - return dataImages[miplevel].size; + return int(dataImages[miplevel].size); } void *CompressedData::getData(int miplevel) const diff --git a/src/modules/image/CompressedData.h b/src/modules/image/CompressedData.h index 2862e0435..303bcf6a6 100644 --- a/src/modules/image/CompressedData.h +++ b/src/modules/image/CompressedData.h @@ -63,15 +63,13 @@ public: { int width, height; size_t size; - uint8 *data; + uint8 *data; // Should not have ownership of the data. }; CompressedData(); virtual ~CompressedData(); - // Implements Data. Note that data for different mipmap levels is not always - // stored contiguously in memory, so getData() and getSize() don't make - // much sense. Use getData(miplevel) and getSize(mipleveL) instead. + // Implements Data. virtual void *getData() const; virtual int getSize() const; @@ -113,6 +111,10 @@ protected: Format format; + // Single block of memory containing all of the sub-images. + uint8 *data; + size_t dataSize; + // Texture info for each mipmap level. std::vector dataImages; diff --git a/src/modules/image/magpie/CompressedData.cpp b/src/modules/image/magpie/CompressedData.cpp index 0cafd4085..418f6d1c2 100644 --- a/src/modules/image/magpie/CompressedData.cpp +++ b/src/modules/image/magpie/CompressedData.cpp @@ -29,47 +29,56 @@ namespace image namespace magpie { -CompressedData::CompressedData(love::filesystem::FileData *data) +CompressedData::CompressedData(love::filesystem::FileData *filedata) { - load(data); + load(filedata); } CompressedData::~CompressedData() { - // We have ownership of the heap memory in dataImages, so we have to free it. - for (size_t i = 0; i < dataImages.size(); i++) - delete[] dataImages[i].data; + delete[] data; } -void CompressedData::load(love::filesystem::FileData *data) +void CompressedData::load(love::filesystem::FileData *filedata) { // SubImage vector will be populated by a parser. std::vector parsedimages; Format texformat = FORMAT_UNKNOWN; - if (ddsHandler::canParse(data)) - texformat = ddsHandler::parse(data, parsedimages); + uint8 *newdata = 0; + size_t newdata_size = 0; + + if (ddsHandler::canParse(filedata)) + newdata = ddsHandler::parse(filedata, parsedimages, newdata_size, texformat); + + if (newdata == 0) + throw love::Exception("Could not parse compressed data."); if (texformat == FORMAT_UNKNOWN) + { + delete[] newdata; throw love::Exception("Could not parse compressed data: Unknown format."); + } - if (parsedimages.size() == 0) + if (parsedimages.size() == 0 || newdata_size == 0) + { + delete[] newdata; throw love::Exception("Could not parse compressed data: No valid data?"); + } // Make sure to clean up any previously loaded data. - for (size_t i = 0; i < dataImages.size(); i++) - { - delete[] dataImages[i].data; - dataImages[i].data = 0; - } + delete[] data; + + data = newdata; + dataSize = newdata_size; dataImages = parsedimages; format = texformat; } -bool CompressedData::isCompressed(love::filesystem::FileData *data) +bool CompressedData::isCompressed(love::filesystem::FileData *filedata) { - if (ddsHandler::canParse(data)) + if (ddsHandler::canParse(filedata)) return true; return false; diff --git a/src/modules/image/magpie/CompressedData.h b/src/modules/image/magpie/CompressedData.h index 56caffb86..147cdf331 100644 --- a/src/modules/image/magpie/CompressedData.h +++ b/src/modules/image/magpie/CompressedData.h @@ -36,14 +36,14 @@ class CompressedData : public love::image::CompressedData { public: - CompressedData(love::filesystem::FileData *data); + CompressedData(love::filesystem::FileData *filedata); virtual ~CompressedData(); - static bool isCompressed(love::filesystem::FileData *data); + static bool isCompressed(love::filesystem::FileData *filedata); private: - void load(love::filesystem::FileData *data); + void load(love::filesystem::FileData *filedata); }; // CompressedData diff --git a/src/modules/image/magpie/ddsHandler.cpp b/src/modules/image/magpie/ddsHandler.cpp index 50eb3b1be..099e3d84e 100644 --- a/src/modules/image/magpie/ddsHandler.cpp +++ b/src/modules/image/magpie/ddsHandler.cpp @@ -40,17 +40,21 @@ bool ddsHandler::canParse(const filesystem::FileData *data) return dds::isCompressedDDS(data->getData(), data->getSize()); } -CompressedData::Format ddsHandler::parse(filesystem::FileData *data, std::vector &images) +uint8 *ddsHandler::parse(filesystem::FileData *filedata, std::vector &images, size_t &dataSize, CompressedData::Format &format) { - if (!dds::isDDS(data->getData(), data->getSize())) + if (!dds::isDDS(filedata->getData(), filedata->getSize())) throw love::Exception("Could not decode compressed data (not a DDS file?)"); CompressedData::Format texformat = CompressedData::FORMAT_UNKNOWN; + uint8 *data = 0; + dataSize = 0; + images.clear(); + try { // Attempt to parse the dds file. - dds::Parser parser(data->getData(), data->getSize()); + dds::Parser parser(filedata->getData(), filedata->getSize()); texformat = convertFormat(parser.getFormat()); @@ -60,6 +64,17 @@ CompressedData::Format ddsHandler::parse(filesystem::FileData *data, std::vector if (parser.getMipmapCount() == 0) throw love::Exception("Could not parse compressed data: No readable texture data."); + // Calculate the size of the block of memory we're returning. + for (size_t i = 0; i < parser.getMipmapCount(); i++) + { + const dds::Image *img = parser.getImageData(i); + dataSize += img->dataSize; + } + + data = new uint8[dataSize]; + + size_t dataOffset = 0; + // Copy the parsed mipmap levels from the FileData to our CompressedData. for (size_t i = 0; i < parser.getMipmapCount(); i++) { @@ -72,23 +87,24 @@ CompressedData::Format ddsHandler::parse(filesystem::FileData *data, std::vector mip.height = img->height; mip.size = img->dataSize; - // Copy the mipmap image from the FileData. - mip.data = new uint8[mip.size]; - memcpy(mip.data, img->data, mip.size); + // Copy the mipmap image from the FileData to our block of memory. + memcpy(data + dataOffset, img->data, mip.size); + mip.data = data + dataOffset; + + dataOffset += mip.size; images.push_back(mip); } } catch (std::exception &e) { - // Clean up any newly allocated heap memory before throwing. - for (size_t i = 0; i < images.size(); i++) - delete[] images[i].data; - - throw love::Exception(e.what()); + delete[] data; + images.clear(); + throw love::Exception("%s", e.what()); } - return texformat; + format = texformat; + return data; } CompressedData::Format ddsHandler::convertFormat(dds::Format ddsformat) diff --git a/src/modules/image/magpie/ddsHandler.h b/src/modules/image/magpie/ddsHandler.h index d8de7db94..3bb152ccc 100644 --- a/src/modules/image/magpie/ddsHandler.h +++ b/src/modules/image/magpie/ddsHandler.h @@ -54,13 +54,18 @@ public: static bool canParse(const filesystem::FileData *data); /** - * Parses Compressed image data into a list of sub-images. - * @param[in] data The data to parse. - * @param[out] images The list of sub-images (including byte data for each) - * parsed from the file data. - * @return The format of the CompressedData. + * Parses compressed image filedata into a list of sub-images and returns + * a single block of memory containing all the images. + * + * @param[in] filedata The data to parse. + * @param[out] image The list of sub-images generated. Byte data is a pointer + * to the returned data. + * @param[out] dataSize The total size in bytes of the returned data. + * @param[out] format The format of the Compressed Data. + * + * @return The single block of memory containing the parsed images. **/ - static CompressedData::Format parse(filesystem::FileData *data, std::vector &images); + static uint8 *parse(filesystem::FileData *filedata, std::vector &images, size_t &dataSize, CompressedData::Format &format); private: diff --git a/src/modules/image/wrap_CompressedData.cpp b/src/modules/image/wrap_CompressedData.cpp index c84afb911..8a37e1049 100644 --- a/src/modules/image/wrap_CompressedData.cpp +++ b/src/modules/image/wrap_CompressedData.cpp @@ -31,62 +31,6 @@ CompressedData *luax_checkcompresseddata(lua_State *L, int idx) return luax_checktype(L, idx, "CompressedData", IMAGE_COMPRESSED_DATA_T); } -int w_CompressedData_getString(lua_State *L) -{ - CompressedData *t = luax_checkcompresseddata(L, 1); - - // CompressedData's data isn't contiguous in memory, so we need to copy it - // all to a single block before sending the string. - - size_t totalsize = 0; - - for (int i = 0; i < t->getMipmapCount(); i++) - totalsize += t->getSize(i); - - if (totalsize == 0) - { - lua_pushstring(L, ""); - return 1; - } - - char *datastr = 0; - try - { - datastr = new char[totalsize]; - } - catch (std::exception &) - { - return luaL_error(L, "Out of memory."); - } - - size_t curpos = 0; - for (int i = 0; i < t->getMipmapCount(); i++) - { - memcpy(&datastr[curpos], t->getData(i), t->getSize(i)); - curpos += t->getSize(i); - } - - lua_pushlstring(L, datastr, totalsize); - - delete[] datastr; - - return 1; -} - -int w_CompressedData_getSize(lua_State *L) -{ - CompressedData *t = luax_checkcompresseddata(L, 1); - - size_t totalsize = 0; - - for (int i = 0; i < t->getMipmapCount(); i++) - totalsize += t->getSize(i); - - lua_pushnumber(L, (lua_Number) totalsize); - - return 1; -} - int w_CompressedData_getWidth(lua_State *L) { CompressedData *t = luax_checkcompresseddata(L, 1); @@ -165,9 +109,8 @@ int w_CompressedData_getFormat(lua_State *L) static const luaL_Reg functions[] = { // Data - // CompressedData's data is not in contiguous memory, so it needs custom functions. - { "getString", w_CompressedData_getString }, - { "getSize", w_CompressedData_getSize }, + { "getString", w_Data_getString }, + { "getSize", w_Data_getSize }, { "getWidth", w_CompressedData_getWidth }, { "getHeight", w_CompressedData_getHeight }, diff --git a/src/modules/image/wrap_CompressedData.h b/src/modules/image/wrap_CompressedData.h index 3fbe3eec4..a28a28f93 100644 --- a/src/modules/image/wrap_CompressedData.h +++ b/src/modules/image/wrap_CompressedData.h @@ -31,8 +31,6 @@ namespace image { CompressedData *luax_checkcompresseddata(lua_State *L, int idx); -int w_CompressedData_getString(lua_State *L); -int w_CompressedData_getSize(lua_State *L); int w_CompressedData_getWidth(lua_State *L); int w_CompressedData_getHeight(lua_State *L); int w_CompressedData_getDimensions(lua_State *L);