Implement Array, Cubemap, and Volume texture types (issue #1111).

- Add love.graphics.newArrayImage, newCubeImage, and newVolumeImage.
- Add love.graphics.newCanvas(w, h, layers) and newCanvas(w, h, layers, settings). Add ‘type’ field to the settings table of newCanvas.

- Add new love.graphics.setCanvas variants: setCanvas(canvas, slice), and setCanvas(canvastable) where canvastable is in the format: {{canvas1, layer=2}, {canvas2, face=5}}

- Add Texture:getTextureType, getDepth, getLayerCount, getMipmapCount, and getFormat.

- Remove Image:getData and Image:refresh.
- Add Image:replacePixels(imagedata [, slice] [, mipmap]).

- Update Canvas:newImageData to accept a slice argument.

- Add love.image.newCubeFaces(imagedata).

--HG--
branch : minor
This commit is contained in:
Alex Szpakowski
2017-02-20 14:58:13 -04:00
parent d70fe5cb89
commit 73fd45558b
91 changed files with 3160 additions and 2003 deletions
+5 -23
View File
@@ -104,7 +104,7 @@ bool ASTCHandler::canParse(const filesystem::FileData *data)
return true;
}
uint8 *ASTCHandler::parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB)
StrongRef<CompressedImageData::Memory> ASTCHandler::parse(filesystem::FileData *filedata, std::vector<StrongRef<CompressedImageData::Slice>> &images, PixelFormat &format, bool &sRGB)
{
if (!canParse(filedata))
throw love::Exception("Could not decode compressed data (not an .astc file?)");
@@ -129,35 +129,17 @@ uint8 *ASTCHandler::parse(filesystem::FileData *filedata, std::vector<Compressed
if (totalsize + sizeof(header) > filedata->getSize())
throw love::Exception("Could not parse .astc file: file is too small.");
uint8 *data = nullptr;
try
{
data = new uint8[totalsize];
}
catch (std::bad_alloc &)
{
throw love::Exception("Out of memory.");
}
StrongRef<CompressedImageData::Memory> memory(new CompressedImageData::Memory(totalsize), Acquire::NORETAIN);
// .astc files only store a single mipmap level.
memcpy(data, (uint8 *) filedata->getData() + sizeof(ASTCHeader), totalsize);
memcpy(memory->data, (uint8 *) filedata->getData() + sizeof(ASTCHeader), totalsize);
CompressedImageData::SubImage mip;
images.emplace_back(new CompressedImageData::Slice(cformat, sizeX, sizeY, memory, 0, totalsize), Acquire::NORETAIN);
mip.width = sizeX;
mip.height = sizeY;
mip.size = totalsize;
mip.data = data;
images.push_back(mip);
dataSize = totalsize;
format = cformat;
sRGB = false;
return data;
return memory;
}
} // magpie
+5 -2
View File
@@ -42,8 +42,11 @@ public:
virtual ~ASTCHandler() {}
// Implements CompressedFormatHandler.
virtual bool canParse(const filesystem::FileData *data);
virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB);
bool canParse(const filesystem::FileData *data) override;
StrongRef<CompressedImageData::Memory> parse(filesystem::FileData *filedata,
std::vector<StrongRef<CompressedImageData::Slice>> &images,
PixelFormat &format, bool &sRGB) override;
}; // ASTCHandler
@@ -58,14 +58,14 @@ public:
* @param[in] filedata The data to parse.
* @param[out] images 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.
* @param[out] sRGB Whether the texture is sRGB-encoded.
*
* @return The single block of memory containing the parsed images.
**/
virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images,
size_t &dataSize, PixelFormat &format, bool &sRGB) = 0;
virtual StrongRef<CompressedImageData::Memory> parse(filesystem::FileData *filedata,
std::vector<StrongRef<CompressedImageData::Slice>> &images,
PixelFormat &format, bool &sRGB) = 0;
}; // CompressedFormatHandler
@@ -43,42 +43,31 @@ CompressedImageData::CompressedImageData(std::list<CompressedFormatHandler *> fo
if (parser == nullptr)
throw love::Exception("Could not parse compressed data: Unknown format.");
data = parser->parse(filedata, dataImages, dataSize, format, sRGB);
memory = parser->parse(filedata, dataImages, format, sRGB);
if (data == nullptr)
if (memory == nullptr)
throw love::Exception("Could not parse compressed data.");
if (format == PIXELFORMAT_UNKNOWN)
{
delete[] data;
throw love::Exception("Could not parse compressed data: Unknown format.");
}
if (dataImages.size() == 0 || dataSize == 0)
{
delete[] data;
if (dataImages.size() == 0 || memory->size == 0)
throw love::Exception("Could not parse compressed data: No valid data?");
}
}
CompressedImageData::CompressedImageData(const CompressedImageData &c)
{
format = c.format;
sRGB = c.sRGB;
dataSize = c.dataSize;
data = new uint8[dataSize];
memcpy(data, c.data, dataSize);
memory.set(new Memory(c.memory->size), Acquire::NORETAIN);
memcpy(memory->data, c.memory->data, memory->size);
for (auto i : c.dataImages )
for (const auto &i : c.dataImages)
{
struct SubImage s;
s.width = i.width;
s.height = i.height;
s.size = i.size;
s.data = (uint8*)((intptr_t)data + (intptr_t)i.data - (intptr_t)c.data);
dataImages.push_back(s);
Slice *slice = new Slice(i->getFormat(), i->getWidth(), i->getHeight(), memory, i->getOffset(), i->getSize());
dataImages.push_back(slice);
slice->release();
}
}
@@ -89,7 +78,6 @@ CompressedImageData *CompressedImageData::clone() const
CompressedImageData::~CompressedImageData()
{
delete[] data;
}
} // magpie
+1 -1
View File
@@ -103,7 +103,7 @@ ImageData::~ImageData()
handler->release();
}
ImageData *ImageData::clone() const
love::image::ImageData *ImageData::clone() const
{
return new ImageData(*this);
}
+1 -1
View File
@@ -45,8 +45,8 @@ public:
ImageData(const ImageData &c);
virtual ~ImageData();
virtual ImageData *clone() const;
// Implements image::ImageData.
virtual love::image::ImageData *clone() const;
virtual love::filesystem::FileData *encode(EncodedFormat encodedFormat, const char *filename);
private:
+11 -20
View File
@@ -297,7 +297,7 @@ bool KTXHandler::canParse(const filesystem::FileData *data)
return true;
}
uint8 *KTXHandler::parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB)
StrongRef<CompressedImageData::Memory> KTXHandler::parse(filesystem::FileData *filedata, std::vector<StrongRef<CompressedImageData::Slice>> &images, PixelFormat &format, bool &sRGB)
{
if (!canParse(filedata))
throw love::Exception("Could not decode compressed data (not a KTX file?)");
@@ -353,15 +353,8 @@ uint8 *KTXHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
fileoffset += mipsizepadded;
}
uint8 *data = nullptr;
try
{
data = new uint8[totalsize];
}
catch (std::bad_alloc &)
{
throw love::Exception("Out of memory.");
}
StrongRef<CompressedImageData::Memory> memory;
memory.set(new CompressedImageData::Memory(totalsize), Acquire::NORETAIN);
// Reset the file offset to the start of the file's image data.
fileoffset = sizeof(KTXHeader) + header.bytesOfKeyValueData;
@@ -379,25 +372,23 @@ uint8 *KTXHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
uint32 mipsizepadded = (mipsize + 3) & ~uint32(3);
CompressedImageData::SubImage mip;
mip.width = (int) std::max(header.pixelWidth >> i, 1u);
mip.height = (int) std::max(header.pixelHeight >> i, 1u);
mip.size = mipsize;
int width = (int) std::max(header.pixelWidth >> i, 1u);
int height = (int) std::max(header.pixelHeight >> i, 1u);
memcpy(data + dataoffset, filebytes + fileoffset, mipsize);
mip.data = data + dataoffset;
memcpy(memory->data + dataoffset, filebytes + fileoffset, mipsize);
auto slice = new CompressedImageData::Slice(cformat, width, height, memory, dataoffset, mipsize);
images.push_back(slice);
slice->release();
fileoffset += mipsizepadded;
dataoffset += mipsizepadded;
images.push_back(mip);
}
dataSize = totalsize;
format = cformat;
sRGB = isSRGB;
return data;
return memory;
}
} // magpie
+5 -2
View File
@@ -41,8 +41,11 @@ public:
virtual ~KTXHandler() {}
// Implements CompressedFormatHandler.
virtual bool canParse(const filesystem::FileData *data);
virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB);
bool canParse(const filesystem::FileData *data) override;
StrongRef<CompressedImageData::Memory> parse(filesystem::FileData *filedata,
std::vector<StrongRef<CompressedImageData::Slice>> &images,
PixelFormat &format, bool &sRGB) override;
}; // KTXHandler
+8 -21
View File
@@ -113,7 +113,7 @@ bool PKMHandler::canParse(const filesystem::FileData *data)
return true;
}
uint8 *PKMHandler::parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB)
StrongRef<CompressedImageData::Memory> PKMHandler::parse(filesystem::FileData *filedata, std::vector<StrongRef<CompressedImageData::Slice>> &images, PixelFormat &format, bool &sRGB)
{
if (!canParse(filedata))
throw love::Exception("Could not decode compressed data (not a PKM file?)");
@@ -133,37 +133,24 @@ uint8 *PKMHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
// The rest of the file after the header is all texture data.
size_t totalsize = filedata->getSize() - sizeof(PKMHeader);
uint8 *data = nullptr;
try
{
data = new uint8[totalsize];
}
catch (std::bad_alloc &)
{
throw love::Exception("Out of memory.");
}
StrongRef<CompressedImageData::Memory> memory;
memory.set(new CompressedImageData::Memory(totalsize), Acquire::NORETAIN);
// PKM files only store a single mipmap level.
memcpy(data, (uint8 *) filedata->getData() + sizeof(PKMHeader), totalsize);
CompressedImageData::SubImage mip;
memcpy(memory->data, (uint8 *) filedata->getData() + sizeof(PKMHeader), totalsize);
// TODO: verify whether glCompressedTexImage works properly with the unpadded
// width and height values (extended == padded.)
mip.width = header.widthBig;
mip.height = header.heightBig;
int width = header.widthBig;
int height = header.heightBig;
mip.size = totalsize;
mip.data = data;
images.emplace_back(new CompressedImageData::Slice(cformat, width, height, memory, 0, totalsize), Acquire::NORETAIN);
images.push_back(mip);
dataSize = totalsize;
format = cformat;
sRGB = false;
return data;
return memory;
}
} // magpie
+5 -2
View File
@@ -41,8 +41,11 @@ public:
virtual ~PKMHandler() {}
// Implements CompressedFormatHandler.
virtual bool canParse(const filesystem::FileData *data);
virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB);
bool canParse(const filesystem::FileData *data) override;
StrongRef<CompressedImageData::Memory> parse(filesystem::FileData *filedata,
std::vector<StrongRef<CompressedImageData::Slice>> &images,
PixelFormat &format, bool &sRGB) override;
}; // PKMHandler
+10 -18
View File
@@ -474,7 +474,7 @@ bool PVRHandler::canParse(const filesystem::FileData *data)
return false;
}
uint8 *PVRHandler::parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB)
StrongRef<CompressedImageData::Memory> PVRHandler::parse(filesystem::FileData *filedata, std::vector<StrongRef<CompressedImageData::Slice>> &images, PixelFormat &format, bool &sRGB)
{
if (!canParse(filedata))
throw love::Exception("Could not decode compressed data (not a PVR file?)");
@@ -525,14 +525,8 @@ uint8 *PVRHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
if (filedata->getSize() < fileoffset + totalsize)
throw love::Exception("Could not parse PVR file: invalid size calculation.");
try
{
data = new uint8[totalsize];
}
catch (std::bad_alloc &)
{
throw love::Exception("Out of memory.");
}
StrongRef<CompressedImageData::Memory> memory;
memory.set(new CompressedImageData::Memory(totalsize), Acquire::NORETAIN);
size_t curoffset = 0;
const uint8 *filebytes = (uint8 *) filedata->getData() + fileoffset;
@@ -544,24 +538,22 @@ uint8 *PVRHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
if (curoffset + mipsize > totalsize)
break; // Just in case.
CompressedImageData::SubImage mip;
mip.width = std::max((int) header3.width >> i, 1);
mip.height = std::max((int) header3.height >> i, 1);
mip.size = mipsize;
int width = std::max((int) header3.width >> i, 1);
int height = std::max((int) header3.height >> i, 1);
memcpy(data + curoffset, filebytes + curoffset, mipsize);
mip.data = data + curoffset;
auto slice = new CompressedImageData::Slice(cformat, width, height, memory, curoffset, mipsize);
images.push_back(slice);
slice->release();
curoffset += mipsize;
images.push_back(mip);
}
dataSize = totalsize;
format = cformat;
sRGB = (header3.colorSpace == 1);
return data;
return memory;
}
} // magpie
+5 -2
View File
@@ -39,8 +39,11 @@ public:
virtual ~PVRHandler() {}
// Implements CompressedFormatHandler.
virtual bool canParse(const filesystem::FileData *data);
virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB);
bool canParse(const filesystem::FileData *data) override;
StrongRef<CompressedImageData::Memory> parse(filesystem::FileData *filedata,
std::vector<StrongRef<CompressedImageData::Slice>> &images,
PixelFormat &format, bool &sRGB) override;
}; // PVRHandler
+37 -51
View File
@@ -32,7 +32,7 @@ bool DDSHandler::canParse(const filesystem::FileData *data)
return dds::isCompressedDDS(data->getData(), data->getSize());
}
uint8 *DDSHandler::parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB)
StrongRef<CompressedImageData::Memory> DDSHandler::parse(filesystem::FileData *filedata, std::vector<StrongRef<CompressedImageData::Slice>> &images, PixelFormat &format, bool &sRGB)
{
if (!dds::isDDS(filedata->getData(), filedata->getSize()))
throw love::Exception("Could not decode compressed data (not a DDS file?)");
@@ -40,65 +40,51 @@ uint8 *DDSHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
PixelFormat texformat = PIXELFORMAT_UNKNOWN;
bool isSRGB = false;
uint8 *data = nullptr;
dataSize = 0;
StrongRef<CompressedImageData::Memory> memory;
size_t dataSize = 0;
images.clear();
try
// Attempt to parse the dds file.
dds::Parser parser(filedata->getData(), filedata->getSize());
texformat = convertFormat(parser.getFormat(), isSRGB);
if (texformat == PIXELFORMAT_UNKNOWN)
throw love::Exception("Could not parse compressed data: Unsupported format.");
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++)
{
// Attempt to parse the dds file.
dds::Parser parser(filedata->getData(), filedata->getSize());
texformat = convertFormat(parser.getFormat(), isSRGB);
if (texformat == PIXELFORMAT_UNKNOWN)
throw love::Exception("Could not parse compressed data: Unsupported format.");
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 CompressedImageData.
for (size_t i = 0; i < parser.getMipmapCount(); i++)
{
// Fetch the data for this mipmap level.
const dds::Image *img = parser.getImageData(i);
CompressedImageData::SubImage mip;
mip.width = img->width;
mip.height = img->height;
mip.size = img->dataSize;
// 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);
}
const dds::Image *img = parser.getImageData(i);
dataSize += img->dataSize;
}
catch (std::exception &e)
memory.set(new CompressedImageData::Memory(dataSize), Acquire::NORETAIN);
size_t dataOffset = 0;
// Copy the parsed mipmap levels from the FileData to our CompressedImageData.
for (size_t i = 0; i < parser.getMipmapCount(); i++)
{
delete[] data;
images.clear();
throw love::Exception("%s", e.what());
// Fetch the data for this mipmap level.
const dds::Image *img = parser.getImageData(i);
// Copy the mipmap image from the FileData to our block of memory.
memcpy(memory->data + dataOffset, img->data, img->dataSize);
auto slice = new CompressedImageData::Slice(texformat, img->width, img->height, memory, dataOffset, img->dataSize);
images.emplace_back(slice, Acquire::NORETAIN);
dataOffset += img->dataSize;
}
format = texformat;
sRGB = isSRGB;
return data;
return memory;
}
PixelFormat DDSHandler::convertFormat(dds::Format ddsformat, bool &sRGB)
+5 -2
View File
@@ -47,8 +47,11 @@ public:
virtual ~DDSHandler() {}
// Implements CompressedFormatHandler.
virtual bool canParse(const filesystem::FileData *data);
virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB);
bool canParse(const filesystem::FileData *data) override;
StrongRef<CompressedImageData::Memory> parse(filesystem::FileData *filedata,
std::vector<StrongRef<CompressedImageData::Slice>> &images,
PixelFormat &format, bool &sRGB) override;
private: