mirror of
https://github.com/love2d/love.git
synced 2026-08-20 04:30:09 +02:00
Merge remote-tracking branch 'origin/12.0-development' into vulkan
This commit is contained in:
@@ -45,7 +45,8 @@ static void enqueue_prepend(std::vector<char> &buffer, char *data, size_t size)
|
|||||||
{
|
{
|
||||||
size_t oldSize = buffer.size();
|
size_t oldSize = buffer.size();
|
||||||
buffer.resize(oldSize + size);
|
buffer.resize(oldSize + size);
|
||||||
memmove(&buffer[size], &buffer[0], oldSize);
|
if (oldSize > 0)
|
||||||
|
memmove(&buffer[size], &buffer[0], oldSize);
|
||||||
memcpy(&buffer[0], data, size);
|
memcpy(&buffer[0], data, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -61,6 +62,10 @@ static size_t dequeue(std::vector<char> &buffer, char *data, size_t size)
|
|||||||
memmove(&buffer[0], &buffer[size], remaining);
|
memmove(&buffer[0], &buffer[size], remaining);
|
||||||
buffer.resize(remaining);
|
buffer.resize(remaining);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer.resize(0);
|
||||||
|
}
|
||||||
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -123,7 +123,7 @@ void *Buffer::map(MapType map, size_t offset, size_t size)
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (map == MAP_READ_ONLY && dataUsage != BUFFERDATAUSAGE_READBACK)
|
if (map == MAP_READ_ONLY && dataUsage != BUFFERDATAUSAGE_READBACK)
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
Range r(offset, size);
|
Range r(offset, size);
|
||||||
|
|
||||||
|
|||||||
@@ -1520,14 +1520,17 @@ void Graphics::present(void *screenshotCallbackData)
|
|||||||
|
|
||||||
deprecations.draw(this);
|
deprecations.draw(this);
|
||||||
|
|
||||||
|
// endPass calls useRenderEncoder, which makes sure activeDrawable is set
|
||||||
|
// when possible.
|
||||||
endPass();
|
endPass();
|
||||||
|
|
||||||
id<MTLBuffer> screenshotbuffer = nil;
|
id<MTLBuffer> screenshotbuffer = nil;
|
||||||
|
|
||||||
|
int w = activeDrawable.texture.width;
|
||||||
|
int h = activeDrawable.texture.height;
|
||||||
|
|
||||||
if (!pendingScreenshotCallbacks.empty())
|
if (!pendingScreenshotCallbacks.empty())
|
||||||
{
|
{
|
||||||
int w = activeDrawable.texture.width;
|
|
||||||
int h = activeDrawable.texture.height;
|
|
||||||
size_t size = w * h * 4;
|
size_t size = w * h * 4;
|
||||||
|
|
||||||
screenshotbuffer = [device newBufferWithLength:size options:MTLResourceStorageModeShared];
|
screenshotbuffer = [device newBufferWithLength:size options:MTLResourceStorageModeShared];
|
||||||
@@ -1540,7 +1543,7 @@ void Graphics::present(void *screenshotCallbackData)
|
|||||||
sourceSlice:0
|
sourceSlice:0
|
||||||
sourceLevel:0
|
sourceLevel:0
|
||||||
sourceOrigin:MTLOriginMake(0, 0, 0)
|
sourceOrigin:MTLOriginMake(0, 0, 0)
|
||||||
sourceSize:MTLSizeMake(w, h, 0)
|
sourceSize:MTLSizeMake(w, h, 1)
|
||||||
toBuffer:screenshotbuffer
|
toBuffer:screenshotbuffer
|
||||||
destinationOffset:0
|
destinationOffset:0
|
||||||
destinationBytesPerRow:w * 4
|
destinationBytesPerRow:w * 4
|
||||||
@@ -1564,12 +1567,12 @@ void Graphics::present(void *screenshotCallbackData)
|
|||||||
|
|
||||||
submitCommandBuffer(SUBMIT_DONE);
|
submitCommandBuffer(SUBMIT_DONE);
|
||||||
|
|
||||||
|
activeDrawable = nil;
|
||||||
|
|
||||||
if (!pendingScreenshotCallbacks.empty())
|
if (!pendingScreenshotCallbacks.empty())
|
||||||
{
|
{
|
||||||
[cmd waitUntilCompleted];
|
[cmd waitUntilCompleted];
|
||||||
|
|
||||||
int w = activeDrawable.texture.width;
|
|
||||||
int h = activeDrawable.texture.height;
|
|
||||||
size_t size = w * h * 4;
|
size_t size = w * h * 4;
|
||||||
|
|
||||||
auto imagemodule = Module::getInstance<love::image::Image>(M_IMAGE);
|
auto imagemodule = Module::getInstance<love::image::Image>(M_IMAGE);
|
||||||
@@ -1620,8 +1623,6 @@ void Graphics::present(void *screenshotCallbackData)
|
|||||||
// This is set to NO when there are pending screen captures.
|
// This is set to NO when there are pending screen captures.
|
||||||
metalLayer.framebufferOnly = YES;
|
metalLayer.framebufferOnly = YES;
|
||||||
|
|
||||||
activeDrawable = nil;
|
|
||||||
|
|
||||||
// Reset the per-frame stat counts.
|
// Reset the per-frame stat counts.
|
||||||
drawCalls = 0;
|
drawCalls = 0;
|
||||||
shaderSwitches = 0;
|
shaderSwitches = 0;
|
||||||
|
|||||||
@@ -70,5 +70,10 @@ void FormatHandler::freeRawPixels(unsigned char *mem)
|
|||||||
delete[] mem;
|
delete[] mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FormatHandler::freeEncodedImage(unsigned char *mem)
|
||||||
|
{
|
||||||
|
delete[] mem;
|
||||||
|
}
|
||||||
|
|
||||||
} // image
|
} // image
|
||||||
} // love
|
} // love
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ public:
|
|||||||
{
|
{
|
||||||
ENCODED_TGA,
|
ENCODED_TGA,
|
||||||
ENCODED_PNG,
|
ENCODED_PNG,
|
||||||
|
ENCODED_EXR,
|
||||||
ENCODED_MAX_ENUM
|
ENCODED_MAX_ENUM
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -116,6 +117,11 @@ public:
|
|||||||
**/
|
**/
|
||||||
virtual void freeRawPixels(unsigned char *mem);
|
virtual void freeRawPixels(unsigned char *mem);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Frees encoded image memory allocated by the format handler.
|
||||||
|
**/
|
||||||
|
virtual void freeEncodedImage(unsigned char *mem);
|
||||||
|
|
||||||
}; // FormatHandler
|
}; // FormatHandler
|
||||||
|
|
||||||
} // image
|
} // image
|
||||||
|
|||||||
@@ -206,12 +206,12 @@ love::filesystem::FileData *ImageData::encode(FormatHandler::EncodedFormat encod
|
|||||||
}
|
}
|
||||||
catch (love::Exception &)
|
catch (love::Exception &)
|
||||||
{
|
{
|
||||||
encoder->freeRawPixels(encodedimage.data);
|
encoder->freeEncodedImage(encodedimage.data);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
|
||||||
memcpy(filedata->getData(), encodedimage.data, encodedimage.size);
|
memcpy(filedata->getData(), encodedimage.data, encodedimage.size);
|
||||||
encoder->freeRawPixels(encodedimage.data);
|
encoder->freeEncodedImage(encodedimage.data);
|
||||||
|
|
||||||
if (writefile)
|
if (writefile)
|
||||||
{
|
{
|
||||||
@@ -859,6 +859,7 @@ StringMap<FormatHandler::EncodedFormat, FormatHandler::ENCODED_MAX_ENUM>::Entry
|
|||||||
{
|
{
|
||||||
{"tga", FormatHandler::ENCODED_TGA},
|
{"tga", FormatHandler::ENCODED_TGA},
|
||||||
{"png", FormatHandler::ENCODED_PNG},
|
{"png", FormatHandler::ENCODED_PNG},
|
||||||
|
{"exr", FormatHandler::ENCODED_EXR},
|
||||||
};
|
};
|
||||||
|
|
||||||
StringMap<FormatHandler::EncodedFormat, FormatHandler::ENCODED_MAX_ENUM> ImageData::encodedFormats(ImageData::encodedFormatEntries, sizeof(ImageData::encodedFormatEntries));
|
StringMap<FormatHandler::EncodedFormat, FormatHandler::ENCODED_MAX_ENUM> ImageData::encodedFormats(ImageData::encodedFormatEntries, sizeof(ImageData::encodedFormatEntries));
|
||||||
|
|||||||
@@ -47,8 +47,27 @@ bool EXRHandler::canDecode(Data *data)
|
|||||||
return ParseEXRVersionFromMemory(&version, (const unsigned char *) data->getData(), data->getSize()) == TINYEXR_SUCCESS;
|
return ParseEXRVersionFromMemory(&version, (const unsigned char *) data->getData(), data->getSize()) == TINYEXR_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool EXRHandler::canEncode(PixelFormat /*rawFormat*/, EncodedFormat /*encodedFormat*/)
|
bool EXRHandler::canEncode(PixelFormat rawFormat, EncodedFormat encodedFormat)
|
||||||
{
|
{
|
||||||
|
if (encodedFormat != ENCODED_EXR)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
switch (rawFormat)
|
||||||
|
{
|
||||||
|
case PIXELFORMAT_R16_FLOAT:
|
||||||
|
case PIXELFORMAT_R32_FLOAT:
|
||||||
|
case PIXELFORMAT_R32_UINT:
|
||||||
|
case PIXELFORMAT_RG16_FLOAT:
|
||||||
|
case PIXELFORMAT_RG32_FLOAT:
|
||||||
|
case PIXELFORMAT_RG32_UINT:
|
||||||
|
case PIXELFORMAT_RGBA16_FLOAT:
|
||||||
|
case PIXELFORMAT_RGBA32_FLOAT:
|
||||||
|
case PIXELFORMAT_RGBA32_UINT:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,7 +95,7 @@ static void getEXRChannels(const EXRHeader &header, const EXRImage &image, T *rg
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static T *loadEXRChannels(int width, int height, T *rgba[4], T one)
|
static T *readEXRChannels(int width, int height, T *rgba[4], T one)
|
||||||
{
|
{
|
||||||
T *data = nullptr;
|
T *data = nullptr;
|
||||||
|
|
||||||
@@ -105,6 +124,20 @@ static T *loadEXRChannels(int width, int height, T *rgba[4], T one)
|
|||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
static void writeEXRChannels(int width, int height, int components, const T *pixels, T *rgba[4])
|
||||||
|
{
|
||||||
|
for (int y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
size_t offset = y * width + x;
|
||||||
|
for (int c = 0; c < components; c++)
|
||||||
|
rgba[c][offset] = pixels[offset * components + c];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
FormatHandler::DecodedImage EXRHandler::decode(Data *data)
|
FormatHandler::DecodedImage EXRHandler::decode(Data *data)
|
||||||
{
|
{
|
||||||
const char *err = "unknown error";
|
const char *err = "unknown error";
|
||||||
@@ -131,7 +164,10 @@ FormatHandler::DecodedImage EXRHandler::decode(Data *data)
|
|||||||
throw love::Exception("Could not parse EXR image header: %s", err);
|
throw love::Exception("Could not parse EXR image header: %s", err);
|
||||||
|
|
||||||
if (LoadEXRImageFromMemory(&exrImage, &exrHeader, mem, memsize, &err) != TINYEXR_SUCCESS)
|
if (LoadEXRImageFromMemory(&exrImage, &exrHeader, mem, memsize, &err) != TINYEXR_SUCCESS)
|
||||||
|
{
|
||||||
|
FreeEXRHeader(&exrHeader);
|
||||||
throw love::Exception("Could not decode EXR image: %s", err);
|
throw love::Exception("Could not decode EXR image: %s", err);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (love::Exception &)
|
catch (love::Exception &)
|
||||||
{
|
{
|
||||||
@@ -145,6 +181,7 @@ FormatHandler::DecodedImage EXRHandler::decode(Data *data)
|
|||||||
{
|
{
|
||||||
if (pixelType != exrHeader.pixel_types[i])
|
if (pixelType != exrHeader.pixel_types[i])
|
||||||
{
|
{
|
||||||
|
FreeEXRHeader(&exrHeader);
|
||||||
FreeEXRImage(&exrImage);
|
FreeEXRImage(&exrImage);
|
||||||
throw love::Exception("Could not decode EXR image: all channels must have the same data type.");
|
throw love::Exception("Could not decode EXR image: all channels must have the same data type.");
|
||||||
}
|
}
|
||||||
@@ -153,7 +190,25 @@ FormatHandler::DecodedImage EXRHandler::decode(Data *data)
|
|||||||
img.width = exrImage.width;
|
img.width = exrImage.width;
|
||||||
img.height = exrImage.height;
|
img.height = exrImage.height;
|
||||||
|
|
||||||
if (pixelType == TINYEXR_PIXELTYPE_HALF)
|
if (pixelType == TINYEXR_PIXELTYPE_UINT)
|
||||||
|
{
|
||||||
|
img.format = PIXELFORMAT_RGBA32_UINT;
|
||||||
|
|
||||||
|
uint32 *rgba[4] = {nullptr};
|
||||||
|
getEXRChannels(exrHeader, exrImage, rgba);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
img.data = (unsigned char *) readEXRChannels(img.width, img.height, rgba, 1u);
|
||||||
|
}
|
||||||
|
catch (love::Exception &)
|
||||||
|
{
|
||||||
|
FreeEXRHeader(&exrHeader);
|
||||||
|
FreeEXRImage(&exrImage);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (pixelType == TINYEXR_PIXELTYPE_HALF)
|
||||||
{
|
{
|
||||||
img.format = PIXELFORMAT_RGBA16_FLOAT;
|
img.format = PIXELFORMAT_RGBA16_FLOAT;
|
||||||
|
|
||||||
@@ -162,10 +217,11 @@ FormatHandler::DecodedImage EXRHandler::decode(Data *data)
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
img.data = (unsigned char *) loadEXRChannels(img.width, img.height, rgba, float32to16(1.0f));
|
img.data = (unsigned char *) readEXRChannels(img.width, img.height, rgba, float32to16(1.0f));
|
||||||
}
|
}
|
||||||
catch (love::Exception &)
|
catch (love::Exception &)
|
||||||
{
|
{
|
||||||
|
FreeEXRHeader(&exrHeader);
|
||||||
FreeEXRImage(&exrImage);
|
FreeEXRImage(&exrImage);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
@@ -179,30 +235,145 @@ FormatHandler::DecodedImage EXRHandler::decode(Data *data)
|
|||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
img.data = (unsigned char *) loadEXRChannels(img.width, img.height, rgba, 1.0f);
|
img.data = (unsigned char *) readEXRChannels(img.width, img.height, rgba, 1.0f);
|
||||||
}
|
}
|
||||||
catch (love::Exception &)
|
catch (love::Exception &)
|
||||||
{
|
{
|
||||||
|
FreeEXRHeader(&exrHeader);
|
||||||
FreeEXRImage(&exrImage);
|
FreeEXRImage(&exrImage);
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
FreeEXRHeader(&exrHeader);
|
||||||
FreeEXRImage(&exrImage);
|
FreeEXRImage(&exrImage);
|
||||||
throw love::Exception("Could not decode EXR image: unknown pixel format.");
|
throw love::Exception("Could not decode EXR image: unknown pixel format.");
|
||||||
}
|
}
|
||||||
|
|
||||||
img.size = getPixelFormatSliceSize(img.format, img.width, img.height);
|
img.size = getPixelFormatSliceSize(img.format, img.width, img.height);
|
||||||
|
|
||||||
|
FreeEXRHeader(&exrHeader);
|
||||||
FreeEXRImage(&exrImage);
|
FreeEXRImage(&exrImage);
|
||||||
|
|
||||||
return img;
|
return img;
|
||||||
}
|
}
|
||||||
|
|
||||||
FormatHandler::EncodedImage EXRHandler::encode(const DecodedImage & /*img*/, EncodedFormat /*encodedFormat*/)
|
FormatHandler::EncodedImage EXRHandler::encode(const DecodedImage &img, EncodedFormat encodedFormat)
|
||||||
{
|
{
|
||||||
throw love::Exception("Invalid format.");
|
if (!canEncode(img.format, encodedFormat))
|
||||||
|
{
|
||||||
|
if (encodedFormat != ENCODED_EXR)
|
||||||
|
throw love::Exception("EXR encoder cannot encode to non-EXR format.");
|
||||||
|
else
|
||||||
|
throw love::Exception("EXR encoder cannot encode the given pixel format.");
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto &formatinfo = getPixelFormatInfo(img.format);
|
||||||
|
|
||||||
|
EXRHeader exrHeader;
|
||||||
|
InitEXRHeader(&exrHeader);
|
||||||
|
|
||||||
|
exrHeader.num_channels = formatinfo.components;
|
||||||
|
|
||||||
|
// TODO: this could be configurable.
|
||||||
|
exrHeader.compression_type = TINYEXR_COMPRESSIONTYPE_ZIP;
|
||||||
|
|
||||||
|
// TinyEXR expects malloc here because FreeEXRHeader uses free().
|
||||||
|
exrHeader.channels = (EXRChannelInfo *) malloc(sizeof(EXRChannelInfo) * exrHeader.num_channels);
|
||||||
|
exrHeader.pixel_types = (int *) malloc(sizeof(int) * exrHeader.num_channels);
|
||||||
|
exrHeader.requested_pixel_types = (int *) malloc(sizeof(int) * exrHeader.num_channels);
|
||||||
|
|
||||||
|
int pixeltype = -1;
|
||||||
|
if (formatinfo.dataType == PIXELFORMATTYPE_UINT)
|
||||||
|
{
|
||||||
|
pixeltype = TINYEXR_PIXELTYPE_UINT;
|
||||||
|
}
|
||||||
|
else if (formatinfo.dataType == PIXELFORMATTYPE_SFLOAT)
|
||||||
|
{
|
||||||
|
if (formatinfo.blockSize / formatinfo.components == 2)
|
||||||
|
pixeltype = TINYEXR_PIXELTYPE_HALF;
|
||||||
|
else if (formatinfo.blockSize / formatinfo.components == 4)
|
||||||
|
pixeltype = TINYEXR_PIXELTYPE_FLOAT;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixeltype == -1)
|
||||||
|
{
|
||||||
|
FreeEXRHeader(&exrHeader);
|
||||||
|
throw love::Exception("Cannot convert the given pixel format to an EXR pixel type.");
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < exrHeader.num_channels; i++)
|
||||||
|
{
|
||||||
|
exrHeader.channels[i] = EXRChannelInfo();
|
||||||
|
|
||||||
|
const char names[] = {'R', 'G', 'B', 'A'};
|
||||||
|
exrHeader.channels[i].name[0] = names[i];
|
||||||
|
|
||||||
|
exrHeader.pixel_types[i] = pixeltype;
|
||||||
|
exrHeader.requested_pixel_types[i] = pixeltype;
|
||||||
|
}
|
||||||
|
|
||||||
|
EXRImage exrImage;
|
||||||
|
InitEXRImage(&exrImage);
|
||||||
|
|
||||||
|
exrImage.width = img.width;
|
||||||
|
exrImage.height = img.height;
|
||||||
|
exrImage.num_channels = exrHeader.num_channels;
|
||||||
|
|
||||||
|
exrImage.images = (unsigned char **) malloc(sizeof(unsigned char *) * exrImage.num_channels);
|
||||||
|
|
||||||
|
for (int i = 0; i < exrImage.num_channels; i++)
|
||||||
|
{
|
||||||
|
size_t componentsize = pixeltype == TINYEXR_PIXELTYPE_HALF ? 2 : 4;
|
||||||
|
|
||||||
|
exrImage.images[i] = (unsigned char *) malloc(img.width * img.height * componentsize);
|
||||||
|
|
||||||
|
if (exrImage.images[i] == nullptr)
|
||||||
|
{
|
||||||
|
FreeEXRHeader(&exrHeader);
|
||||||
|
FreeEXRImage(&exrImage);
|
||||||
|
throw love::Exception("Out of memory.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pixeltype == TINYEXR_PIXELTYPE_UINT)
|
||||||
|
{
|
||||||
|
writeEXRChannels(img.width, img.height, formatinfo.components, (const uint32 *) img.data, (uint32 **) exrImage.images);
|
||||||
|
}
|
||||||
|
else if (pixeltype == TINYEXR_PIXELTYPE_HALF)
|
||||||
|
{
|
||||||
|
writeEXRChannels(img.width, img.height, formatinfo.components, (const float16 *) img.data, (float16 **) exrImage.images);
|
||||||
|
}
|
||||||
|
else if (pixeltype == TINYEXR_PIXELTYPE_FLOAT)
|
||||||
|
{
|
||||||
|
writeEXRChannels(img.width, img.height, formatinfo.components, (const float *) img.data, (float **) exrImage.images);
|
||||||
|
}
|
||||||
|
|
||||||
|
EncodedImage encimg;
|
||||||
|
|
||||||
|
const char *err = nullptr;
|
||||||
|
encimg.size = SaveEXRImageToMemory(&exrImage, &exrHeader, &encimg.data, &err);
|
||||||
|
|
||||||
|
FreeEXRHeader(&exrHeader);
|
||||||
|
FreeEXRImage(&exrImage);
|
||||||
|
|
||||||
|
std::string errstring;
|
||||||
|
if (err != nullptr)
|
||||||
|
{
|
||||||
|
errstring = err;
|
||||||
|
FreeEXRErrorMessage(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (encimg.size == 0)
|
||||||
|
{
|
||||||
|
if (!errstring.empty())
|
||||||
|
throw love::Exception("Could not encode EXR image: %s", errstring.c_str());
|
||||||
|
else
|
||||||
|
throw love::Exception("Could not encode EXR image");
|
||||||
|
}
|
||||||
|
|
||||||
|
return encimg;
|
||||||
}
|
}
|
||||||
|
|
||||||
void EXRHandler::freeRawPixels(unsigned char *mem)
|
void EXRHandler::freeRawPixels(unsigned char *mem)
|
||||||
@@ -210,6 +381,13 @@ void EXRHandler::freeRawPixels(unsigned char *mem)
|
|||||||
delete[] mem;
|
delete[] mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EXRHandler::freeEncodedImage(unsigned char *mem)
|
||||||
|
{
|
||||||
|
// SaveEXRImageToMemory uses malloc.
|
||||||
|
if (mem != nullptr)
|
||||||
|
::free(mem);
|
||||||
|
}
|
||||||
|
|
||||||
} // magpie
|
} // magpie
|
||||||
} // image
|
} // image
|
||||||
} // love
|
} // love
|
||||||
|
|||||||
@@ -36,15 +36,18 @@ class EXRHandler : public FormatHandler
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
virtual ~EXRHandler() {}
|
||||||
|
|
||||||
// Implements FormatHandler.
|
// Implements FormatHandler.
|
||||||
|
|
||||||
virtual bool canDecode(Data *data);
|
bool canDecode(Data *data) override;
|
||||||
virtual bool canEncode(PixelFormat rawFormat, EncodedFormat encodedFormat);
|
bool canEncode(PixelFormat rawFormat, EncodedFormat encodedFormat) override;
|
||||||
|
|
||||||
virtual DecodedImage decode(Data *data);
|
DecodedImage decode(Data *data) override;
|
||||||
virtual EncodedImage encode(const DecodedImage &img, EncodedFormat format);
|
EncodedImage encode(const DecodedImage &img, EncodedFormat format) override;
|
||||||
|
|
||||||
virtual void freeRawPixels(unsigned char *mem);
|
void freeRawPixels(unsigned char *mem) override;
|
||||||
|
void freeEncodedImage(unsigned char *mem) override;
|
||||||
|
|
||||||
}; // EXRHandler
|
}; // EXRHandler
|
||||||
|
|
||||||
|
|||||||
@@ -264,6 +264,12 @@ void PNGHandler::freeRawPixels(unsigned char *mem)
|
|||||||
::free(mem);
|
::free(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PNGHandler::freeEncodedImage(unsigned char *mem)
|
||||||
|
{
|
||||||
|
if (mem)
|
||||||
|
::free(mem);
|
||||||
|
}
|
||||||
|
|
||||||
} // magpie
|
} // magpie
|
||||||
} // image
|
} // image
|
||||||
} // love
|
} // love
|
||||||
|
|||||||
@@ -37,15 +37,18 @@ class PNGHandler : public FormatHandler
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
virtual ~PNGHandler() {}
|
||||||
|
|
||||||
// Implements FormatHandler.
|
// Implements FormatHandler.
|
||||||
|
|
||||||
virtual bool canDecode(Data *data);
|
bool canDecode(Data *data) override;
|
||||||
virtual bool canEncode(PixelFormat rawFormat, EncodedFormat encodedFormat);
|
bool canEncode(PixelFormat rawFormat, EncodedFormat encodedFormat) override;
|
||||||
|
|
||||||
virtual DecodedImage decode(Data *data);
|
DecodedImage decode(Data *data) override;
|
||||||
virtual EncodedImage encode(const DecodedImage &img, EncodedFormat format);
|
EncodedImage encode(const DecodedImage &img, EncodedFormat format) override;
|
||||||
|
|
||||||
virtual void freeRawPixels(unsigned char *mem);
|
void freeRawPixels(unsigned char *mem) override;
|
||||||
|
void freeEncodedImage(unsigned char *mem) override;
|
||||||
|
|
||||||
}; // PNGHandler
|
}; // PNGHandler
|
||||||
|
|
||||||
|
|||||||
@@ -123,15 +123,14 @@ FormatHandler::EncodedImage STBHandler::encode(const DecodedImage &img, EncodedF
|
|||||||
|
|
||||||
encimg.size = (img.width * img.height * bpp) + headerlen;
|
encimg.size = (img.width * img.height * bpp) + headerlen;
|
||||||
|
|
||||||
// We need to use malloc because we use stb_image_free (which uses free())
|
try
|
||||||
// as our custom free() function, which is called by the ImageData after
|
{
|
||||||
// encode() is complete.
|
encimg.data = new unsigned char[encimg.size];
|
||||||
// stb_image's source code is compiled with this source, so calling malloc()
|
}
|
||||||
// directly is fine.
|
catch (std::exception &)
|
||||||
encimg.data = (unsigned char *) malloc(encimg.size);
|
{
|
||||||
|
|
||||||
if (encimg.data == nullptr)
|
|
||||||
throw love::Exception("Out of memory.");
|
throw love::Exception("Out of memory.");
|
||||||
|
}
|
||||||
|
|
||||||
// here's the header for the Targa file format.
|
// here's the header for the Targa file format.
|
||||||
encimg.data[0] = 0; // ID field size
|
encimg.data[0] = 0; // ID field size
|
||||||
@@ -176,6 +175,11 @@ void STBHandler::freeRawPixels(unsigned char *mem)
|
|||||||
stbi_image_free(mem);
|
stbi_image_free(mem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void STBHandler::freeEncodedImage(unsigned char *mem)
|
||||||
|
{
|
||||||
|
delete[] mem;
|
||||||
|
}
|
||||||
|
|
||||||
} // magpie
|
} // magpie
|
||||||
} // image
|
} // image
|
||||||
} // love
|
} // love
|
||||||
|
|||||||
@@ -40,6 +40,8 @@ class STBHandler final : public FormatHandler
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
|
virtual ~STBHandler() {}
|
||||||
|
|
||||||
// Implements FormatHandler.
|
// Implements FormatHandler.
|
||||||
|
|
||||||
bool canDecode(Data *data) override;
|
bool canDecode(Data *data) override;
|
||||||
@@ -49,6 +51,7 @@ public:
|
|||||||
EncodedImage encode(const DecodedImage &img, EncodedFormat format) override;
|
EncodedImage encode(const DecodedImage &img, EncodedFormat format) override;
|
||||||
|
|
||||||
void freeRawPixels(unsigned char *mem) override;
|
void freeRawPixels(unsigned char *mem) override;
|
||||||
|
void freeEncodedImage(unsigned char *mem) override;
|
||||||
|
|
||||||
}; // STBHandler
|
}; // STBHandler
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user