Browse Source

Updated CompressedData to store its data in a single block of memory, like other Data objects

Alex Szpakowski 12 years ago
parent
commit
4c4a385ce6

+ 5 - 14
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

+ 6 - 4
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<SubImage> dataImages;
 

+ 25 - 16
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<SubImage> 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;

+ 3 - 3
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
 

+ 28 - 12
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<CompressedData::SubImage> &images)
+uint8 *ddsHandler::parse(filesystem::FileData *filedata, std::vector<CompressedData::SubImage> &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)

+ 11 - 6
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<CompressedData::SubImage> &images);
+	static uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedData::SubImage> &images, size_t &dataSize, CompressedData::Format &format);
 
 private:
 

+ 2 - 59
src/modules/image/wrap_CompressedData.cpp

@@ -31,62 +31,6 @@ CompressedData *luax_checkcompresseddata(lua_State *L, int idx)
 	return luax_checktype<CompressedData>(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 },

+ 0 - 2
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);