Browse Source

ImageData can track whether they're meant to be loaded into a Texture with a non-sRGB format when gamma correct rendering is enabled.

Fixes #1556.

* Add ImageData/CompressedImageData:setLinear and ImageData/CompressedImageData:isLinear.
  The flag is used as a hint when loading a texture from the data to determine if the format should not be treated as sRGB-encoded. The 'linear' flag in newImage overrides this.

* love.graphics.readbackTexture automatically sets the linear flag on ImageData it returns when the texture's format is linear.
  This allows an ImageData generated via readback to be fed back into a new Texture and the format will match the original Canvas.

* Also clean up some image decoding code.
Sasha Szpakowski 1 year ago
parent
commit
8c13943f64

+ 2 - 8
src/common/pixelformat.cpp

@@ -364,11 +364,8 @@ PixelFormat getSRGBPixelFormat(PixelFormat format)
 	case PIXELFORMAT_ASTC_10x10_UNORM: return PIXELFORMAT_ASTC_10x10_sRGB;
 	case PIXELFORMAT_ASTC_12x10_UNORM: return PIXELFORMAT_ASTC_12x10_sRGB;
 	case PIXELFORMAT_ASTC_12x12_UNORM: return PIXELFORMAT_ASTC_12x12_sRGB;
-	default:
-		break;
+	default: return format;
 	}
-
-	return format;
 }
 
 PixelFormat getLinearPixelFormat(PixelFormat format)
@@ -398,11 +395,8 @@ PixelFormat getLinearPixelFormat(PixelFormat format)
 	case PIXELFORMAT_ASTC_10x10_sRGB: return PIXELFORMAT_ASTC_10x10_UNORM;
 	case PIXELFORMAT_ASTC_12x10_sRGB: return PIXELFORMAT_ASTC_12x10_UNORM;
 	case PIXELFORMAT_ASTC_12x12_sRGB: return PIXELFORMAT_ASTC_12x12_UNORM;
-	default:
-		break;
+	default: return format;
 	}
-
-	return format;
 }
 
 size_t getPixelFormatBlockSize(PixelFormat format)

+ 3 - 1
src/modules/graphics/GraphicsReadback.cpp

@@ -81,6 +81,7 @@ GraphicsReadback::GraphicsReadback(Graphics *gfx, ReadbackMethod method, Texture
 	}
 
 	textureFormat = getLinearPixelFormat(texture->getPixelFormat());
+	isFormatLinear = isGammaCorrect() && !isPixelFormatSRGB(texture->getPixelFormat());
 
 	if (!image::ImageData::validPixelFormat(textureFormat))
 	{
@@ -96,7 +97,7 @@ GraphicsReadback::GraphicsReadback(Graphics *gfx, ReadbackMethod method, Texture
 		if (isRT && !caps.features[Graphics::FEATURE_COPY_RENDER_TARGET_TO_BUFFER])
 			throw love::Exception("readbackTextureAsync is not supported on this system.");
 		else if (!isRT && !caps.features[Graphics::FEATURE_COPY_TEXTURE_TO_BUFFER])
-			throw love::Exception("readbackTextureAsync a with non-render-target textures is not supported on this system.");
+			throw love::Exception("readbackTextureAsync with a non-render-target texture is not supported on this system.");
 	}
 	else
 	{
@@ -158,6 +159,7 @@ void *GraphicsReadback::prepareReadbackDest(size_t size)
 				throw love::Exception("The love.image module must be loaded for readbackTexture.");
 
 			imageData.set(module->newImageData(rect.w, rect.h, textureFormat, nullptr), Acquire::NORETAIN);
+			imageData->setLinear(isFormatLinear);
 			return imageData->getData();
 		}
 	}

+ 1 - 0
src/modules/graphics/GraphicsReadback.h

@@ -103,6 +103,7 @@ protected:
 	StrongRef<love::image::ImageData> imageData;
 	Rect rect = {};
 	PixelFormat textureFormat = PIXELFORMAT_UNKNOWN;
+	bool isFormatLinear = false;
 	int imageDataX = 0;
 	int imageDataY = 0;
 

+ 5 - 1
src/modules/graphics/Texture.cpp

@@ -203,7 +203,7 @@ Texture::Texture(Graphics *gfx, const Settings &settings, const Slices *slices)
 		love::image::ImageDataBase *slice = slices->get(0, 0);
 
 		format = slice->getFormat();
-		if (isGammaCorrect() && !settings.linear)
+		if (isGammaCorrect() && !slice->isLinear())
 			format = getSRGBPixelFormat(format);
 
 		pixelWidth = slice->getWidth();
@@ -886,6 +886,7 @@ bool Texture::Slices::validate() const
 	int w = firstdata->getWidth();
 	int h = firstdata->getHeight();
 	PixelFormat format = firstdata->getFormat();
+	bool linear = firstdata->isLinear();
 
 	if (textureType == TEXTURE_CUBE && w != h)
 		throw love::Exception("Cube textures must have equal widths and heights for each cube face.");
@@ -925,6 +926,9 @@ bool Texture::Slices::validate() const
 
 			if (format != slicedata->getFormat())
 				throw love::Exception("All texture slices and mipmaps must have the same pixel format.");
+
+			if (linear != slicedata->isLinear())
+				throw love::Exception("All texture slices and mipmaps must have the same linear setting.");
 		}
 
 		mipw = std::max(mipw / 2, 1);

+ 13 - 5
src/modules/image/CompressedImageData.cpp

@@ -30,7 +30,6 @@ love::Type CompressedImageData::type("CompressedImageData", &Data::type);
 
 CompressedImageData::CompressedImageData(const std::list<FormatHandler *> &formats, Data *filedata)
 	: format(PIXELFORMAT_UNKNOWN)
-	, sRGB(false)
 {
 	FormatHandler *parser = nullptr;
 
@@ -46,7 +45,7 @@ CompressedImageData::CompressedImageData(const std::list<FormatHandler *> &forma
 	if (parser == nullptr)
 		throw love::Exception("Could not parse compressed data: Unknown format.");
 
-	memory = parser->parseCompressed(filedata, dataImages, format, sRGB);
+	memory = parser->parseCompressed(filedata, dataImages, format);
 
 	if (memory == nullptr)
 		throw love::Exception("Could not parse compressed data.");
@@ -56,11 +55,14 @@ CompressedImageData::CompressedImageData(const std::list<FormatHandler *> &forma
 
 	if (dataImages.size() == 0 || memory->getSize() == 0)
 		throw love::Exception("Could not parse compressed data: No valid data?");
+
+	// This throws away some information the decoder could give us, but we
+	// can't really rely on it I think...
+	format = getLinearPixelFormat(format);
 }
 
 CompressedImageData::CompressedImageData(const CompressedImageData &c)
 	: format(c.format)
-	, sRGB(c.sRGB)
 {
 	memory.set(c.memory->clone(), Acquire::NORETAIN);
 
@@ -134,9 +136,15 @@ PixelFormat CompressedImageData::getFormat() const
 	return format;
 }
 
-bool CompressedImageData::isSRGB() const
+void CompressedImageData::setLinear(bool linear)
+{
+	for (auto &slice : dataImages)
+		slice->setLinear(linear);
+}
+
+bool CompressedImageData::isLinear() const
 {
-	return sRGB;
+	return dataImages.empty() ? false : dataImages[0]->isLinear();
 }
 
 CompressedSlice *CompressedImageData::getSlice(int slice, int miplevel) const

+ 2 - 2
src/modules/image/CompressedImageData.h

@@ -93,14 +93,14 @@ public:
 	 **/
 	PixelFormat getFormat() const;
 
-	bool isSRGB() const;
+	void setLinear(bool linear);
+	bool isLinear() const;
 
 	CompressedSlice *getSlice(int slice, int miplevel) const;
 
 protected:
 
 	PixelFormat format;
-	bool sRGB;
 
 	// Single block of memory containing all of the sub-images.
 	StrongRef<ByteData> memory;

+ 0 - 2
src/modules/image/CompressedSlice.cpp

@@ -31,7 +31,6 @@ CompressedSlice::CompressedSlice(PixelFormat format, int width, int height, Byte
 	, memory(memory)
 	, offset(offset)
 	, dataSize(size)
-	, sRGB(false)
 {
 }
 
@@ -40,7 +39,6 @@ CompressedSlice::CompressedSlice(const CompressedSlice &s)
 	, memory(s.memory)
 	, offset(s.offset)
 	, dataSize(s.dataSize)
-	, sRGB(s.sRGB)
 {
 }
 

+ 0 - 2
src/modules/image/CompressedSlice.h

@@ -46,7 +46,6 @@ public:
 	CompressedSlice *clone() const override;
 	void *getData() const override { return (uint8 *) memory->getData() + offset; }
 	size_t getSize() const override { return dataSize; }
-	bool isSRGB() const override { return sRGB; }
 	size_t getOffset() const { return offset; }
 
 private:
@@ -54,7 +53,6 @@ private:
 	StrongRef<ByteData> memory;
 	size_t offset;
 	size_t dataSize;
-	bool sRGB;
 
 }; // CompressedSlice
 

+ 1 - 1
src/modules/image/FormatHandler.cpp

@@ -60,7 +60,7 @@ bool FormatHandler::canParseCompressed(Data* /*data*/)
 	return false;
 }
 
-StrongRef<ByteData> FormatHandler::parseCompressed(Data* /*filedata*/, std::vector<StrongRef<CompressedSlice>>& /*images*/, PixelFormat& /*format*/, bool& /*sRGB*/)
+StrongRef<ByteData> FormatHandler::parseCompressed(Data* /*filedata*/, std::vector<StrongRef<CompressedSlice>>& /*images*/, PixelFormat& /*format*/)
 {
 	throw love::Exception("Compressed image parsing is not implemented for this format backend.");
 }

+ 1 - 2
src/modules/image/FormatHandler.h

@@ -106,13 +106,12 @@ public:
 	 * @param[out] images The list of sub-images generated. Byte data is a
 	 *             pointer to 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 StrongRef<ByteData> parseCompressed(Data *filedata,
 	        std::vector<StrongRef<CompressedSlice>> &images,
-	        PixelFormat &format, bool &sRGB);
+	        PixelFormat &format);
 
 	/**
 	 * Frees raw pixel memory allocated by the format handler.

+ 4 - 5
src/modules/image/ImageData.cpp

@@ -152,6 +152,10 @@ void ImageData::decode(Data *data)
 	else
 		delete[] this->data;
 
+	// This throws away some information the decoder could give us, but we
+	// can't really rely on it I think...
+	decodedimage.format = getLinearPixelFormat(decodedimage.format);
+
 	this->width  = decodedimage.width;
 	this->height = decodedimage.height;
 	this->data   = decodedimage.data;
@@ -247,11 +251,6 @@ void *ImageData::getData() const
 	return data;
 }
 
-bool ImageData::isSRGB() const
-{
-	return false;
-}
-
 bool ImageData::inside(int x, int y) const
 {
 	return x >= 0 && x < getWidth() && y >= 0 && y < getHeight();

+ 1 - 2
src/modules/image/ImageData.h

@@ -62,7 +62,7 @@ public:
 	static love::Type type;
 
 	ImageData(Data *data);
-	ImageData(int width, int height, PixelFormat format = PIXELFORMAT_RGBA8_UNORM);
+	ImageData(int width, int height, PixelFormat format);
 	ImageData(int width, int height, PixelFormat format, void *data, bool own);
 	ImageData(const ImageData &c);
 	virtual ~ImageData();
@@ -116,7 +116,6 @@ public:
 	ImageData *clone() const override;
 	void *getData() const override;
 	size_t getSize() const override;
-	bool isSRGB() const override;
 
 	size_t getPixelSize() const;
 

+ 11 - 0
src/modules/image/ImageDataBase.cpp

@@ -29,6 +29,7 @@ ImageDataBase::ImageDataBase(PixelFormat format, int width, int height)
 	: format(format)
 	, width(width)
 	, height(height)
+	, linear(false)
 {
 }
 
@@ -47,5 +48,15 @@ int ImageDataBase::getHeight() const
 	return height;
 }
 
+void ImageDataBase::setLinear(bool linear)
+{
+	this->linear = linear;
+}
+
+bool ImageDataBase::isLinear() const
+{
+	return linear;
+}
+
 } // image
 } // love

+ 4 - 1
src/modules/image/ImageDataBase.h

@@ -40,7 +40,8 @@ public:
 	int getWidth() const;
 	int getHeight() const;
 
-	virtual bool isSRGB() const = 0;
+	void setLinear(bool linear);
+	bool isLinear() const;
 
 protected:
 
@@ -50,6 +51,8 @@ protected:
 	int width;
 	int height;
 
+	bool linear;
+
 }; // ImageDataBase
 
 } // image

+ 1 - 3
src/modules/image/magpie/ASTCHandler.cpp

@@ -105,7 +105,7 @@ bool ASTCHandler::canParseCompressed(Data *data)
 	return true;
 }
 
-StrongRef<ByteData> ASTCHandler::parseCompressed(Data *filedata, std::vector<StrongRef<CompressedSlice>> &images, PixelFormat &format, bool &sRGB)
+StrongRef<ByteData> ASTCHandler::parseCompressed(Data *filedata, std::vector<StrongRef<CompressedSlice>> &images, PixelFormat &format)
 {
 	if (!canParseCompressed(filedata))
 		throw love::Exception("Could not decode compressed data (not an .astc file?)");
@@ -138,8 +138,6 @@ StrongRef<ByteData> ASTCHandler::parseCompressed(Data *filedata, std::vector<Str
 	images.emplace_back(new CompressedSlice(cformat, sizeX, sizeY, memory, 0, totalsize), Acquire::NORETAIN);
 
 	format = cformat;
-	sRGB = false;
-
 	return memory;
 }
 

+ 1 - 1
src/modules/image/magpie/ASTCHandler.h

@@ -45,7 +45,7 @@ public:
 
 	StrongRef<ByteData> parseCompressed(Data *filedata,
 	        std::vector<StrongRef<CompressedSlice>> &images,
-	        PixelFormat &format, bool &sRGB) override;
+	        PixelFormat &format) override;
 
 }; // ASTCHandler
 

+ 24 - 32
src/modules/image/magpie/KTXHandler.cpp

@@ -137,10 +137,8 @@ enum KTXGLInternalFormat
 	KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD
 };
 
-PixelFormat convertFormat(uint32 glformat, bool &sRGB)
+PixelFormat convertFormat(uint32 glformat)
 {
-	sRGB = false;
-
 	// hnnngg ASTC...
 
 	switch (glformat)
@@ -160,18 +158,15 @@ PixelFormat convertFormat(uint32 glformat, bool &sRGB)
 	case KTX_GL_COMPRESSED_RGB8_ETC2:
 		return PIXELFORMAT_ETC2_RGB_UNORM;
 	case KTX_GL_COMPRESSED_SRGB8_ETC2:
-		sRGB = true;
-		return PIXELFORMAT_ETC2_RGB_UNORM;
+		return PIXELFORMAT_ETC2_RGB_sRGB;
 	case KTX_GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
 		return PIXELFORMAT_ETC2_RGBA1_UNORM;
 	case KTX_GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
-		sRGB = true;
-		return PIXELFORMAT_ETC2_RGBA1_UNORM;
+		return PIXELFORMAT_ETC2_RGBA1_sRGB;
 	case KTX_GL_COMPRESSED_RGBA8_ETC2_EAC:
 		return PIXELFORMAT_ETC2_RGBA_UNORM;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
-		sRGB = true;
-		return PIXELFORMAT_ETC2_RGBA_UNORM;
+		return PIXELFORMAT_ETC2_RGBA_sRGB;
 
 	// PVRTC.
 	case KTX_GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
@@ -185,15 +180,15 @@ PixelFormat convertFormat(uint32 glformat, bool &sRGB)
 
 	// DXT.
 	case KTX_GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
-		sRGB = true;
+		return PIXELFORMAT_DXT1_sRGB;
 	case KTX_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
 		return PIXELFORMAT_DXT1_UNORM;
 	case KTX_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
-		sRGB = true;
+		return PIXELFORMAT_DXT3_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
 		return PIXELFORMAT_DXT3_UNORM;
 	case KTX_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
-		sRGB = true;
+		return PIXELFORMAT_DXT5_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
 		return PIXELFORMAT_DXT5_UNORM;
 
@@ -209,7 +204,7 @@ PixelFormat convertFormat(uint32 glformat, bool &sRGB)
 
 	// BC6 and BC7.
 	case KTX_GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
-		sRGB = true;
+		return PIXELFORMAT_BC7_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_BPTC_UNORM:
 		return PIXELFORMAT_BC7_UNORM;
 	case KTX_GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
@@ -219,59 +214,59 @@ PixelFormat convertFormat(uint32 glformat, bool &sRGB)
 
 	// ASTC.
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
-		sRGB = true;
+		return PIXELFORMAT_ASTC_4x4_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
 		return PIXELFORMAT_ASTC_4x4_UNORM;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
-		sRGB = true;
+		return PIXELFORMAT_ASTC_5x4_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
 		return PIXELFORMAT_ASTC_5x4_UNORM;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
-		sRGB = true;
+		return PIXELFORMAT_ASTC_5x5_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
 		return PIXELFORMAT_ASTC_5x5_UNORM;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
-		sRGB = true;
+		return PIXELFORMAT_ASTC_6x5_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
 		return PIXELFORMAT_ASTC_6x5_UNORM;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
-		sRGB = true;
+		return PIXELFORMAT_ASTC_6x6_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
 		return PIXELFORMAT_ASTC_6x6_UNORM;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
-		sRGB = true;
+		return PIXELFORMAT_ASTC_8x5_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
 		return PIXELFORMAT_ASTC_8x5_UNORM;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
-		sRGB = true;
+		return PIXELFORMAT_ASTC_8x6_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
 		return PIXELFORMAT_ASTC_8x6_UNORM;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
-		sRGB = true;
+		return PIXELFORMAT_ASTC_8x8_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
 		return PIXELFORMAT_ASTC_8x8_UNORM;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
-		sRGB = true;
+		return PIXELFORMAT_ASTC_10x5_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
 		return PIXELFORMAT_ASTC_10x5_UNORM;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
-		sRGB = true;
+		return PIXELFORMAT_ASTC_10x6_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
 		return PIXELFORMAT_ASTC_10x6_UNORM;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
-		sRGB = true;
+		return PIXELFORMAT_ASTC_10x8_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
 		return PIXELFORMAT_ASTC_10x8_UNORM;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
-		sRGB = true;
+		return PIXELFORMAT_ASTC_10x10_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
 		return PIXELFORMAT_ASTC_10x10_UNORM;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
-		sRGB = true;
+		return PIXELFORMAT_ASTC_12x10_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
 		return PIXELFORMAT_ASTC_12x10_UNORM;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
-		sRGB = true;
+		return PIXELFORMAT_ASTC_12x12_sRGB;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
 		return PIXELFORMAT_ASTC_12x12_UNORM;
 	default:
@@ -298,7 +293,7 @@ bool KTXHandler::canParseCompressed(Data *data)
 	return true;
 }
 
-StrongRef<ByteData> KTXHandler::parseCompressed(Data *filedata, std::vector<StrongRef<CompressedSlice>> &images, PixelFormat &format, bool &sRGB)
+StrongRef<ByteData> KTXHandler::parseCompressed(Data *filedata, std::vector<StrongRef<CompressedSlice>> &images, PixelFormat &format)
 {
 	if (!canParseCompressed(filedata))
 		throw love::Exception("Could not decode compressed data (not a KTX file?)");
@@ -314,8 +309,7 @@ StrongRef<ByteData> KTXHandler::parseCompressed(Data *filedata, std::vector<Stro
 
 	header.numberOfMipmapLevels = std::max(header.numberOfMipmapLevels, 1u);
 
-	bool isSRGB = false;
-	PixelFormat cformat = convertFormat(header.glInternalFormat, isSRGB);
+	PixelFormat cformat = convertFormat(header.glInternalFormat);
 
 	if (cformat == PIXELFORMAT_UNKNOWN)
 		throw love::Exception("Unsupported image format in KTX file.");
@@ -386,8 +380,6 @@ StrongRef<ByteData> KTXHandler::parseCompressed(Data *filedata, std::vector<Stro
 	}
 
 	format = cformat;
-	sRGB = isSRGB;
-
 	return memory;
 }
 

+ 1 - 1
src/modules/image/magpie/KTXHandler.h

@@ -44,7 +44,7 @@ public:
 
 	StrongRef<ByteData> parseCompressed(Data *filedata,
 	        std::vector<StrongRef<CompressedSlice>> &images,
-	        PixelFormat &format, bool &sRGB) override;
+	        PixelFormat &format) override;
 
 }; // KTXHandler
 

+ 1 - 3
src/modules/image/magpie/PKMHandler.cpp

@@ -114,7 +114,7 @@ bool PKMHandler::canParseCompressed(Data *data)
 	return true;
 }
 
-StrongRef<ByteData> PKMHandler::parseCompressed(Data *filedata, std::vector<StrongRef<CompressedSlice>> &images, PixelFormat &format, bool &sRGB)
+StrongRef<ByteData> PKMHandler::parseCompressed(Data *filedata, std::vector<StrongRef<CompressedSlice>> &images, PixelFormat &format)
 {
 	if (!canParseCompressed(filedata))
 		throw love::Exception("Could not decode compressed data (not a PKM file?)");
@@ -148,8 +148,6 @@ StrongRef<ByteData> PKMHandler::parseCompressed(Data *filedata, std::vector<Stro
 	images.emplace_back(new CompressedSlice(cformat, width, height, memory, 0, totalsize), Acquire::NORETAIN);
 
 	format = cformat;
-	sRGB = false;
-
 	return memory;
 }
 

+ 1 - 1
src/modules/image/magpie/PKMHandler.h

@@ -44,7 +44,7 @@ public:
 
 	StrongRef<ByteData> parseCompressed(Data *filedata,
 	        std::vector<StrongRef<CompressedSlice>> &images,
-	        PixelFormat &format, bool &sRGB) override;
+	        PixelFormat &format) override;
 
 }; // PKMHandler
 

+ 4 - 3
src/modules/image/magpie/PVRHandler.cpp

@@ -475,7 +475,7 @@ bool PVRHandler::canParseCompressed(Data *data)
 	return false;
 }
 
-StrongRef<ByteData> PVRHandler::parseCompressed(Data *filedata, std::vector<StrongRef<CompressedSlice>> &images, PixelFormat &format, bool &sRGB)
+StrongRef<ByteData> PVRHandler::parseCompressed(Data *filedata, std::vector<StrongRef<CompressedSlice>> &images, PixelFormat &format)
 {
 	if (!canParseCompressed(filedata))
 		throw love::Exception("Could not decode compressed data (not a PVR file?)");
@@ -510,6 +510,9 @@ StrongRef<ByteData> PVRHandler::parseCompressed(Data *filedata, std::vector<Stro
 
 	PixelFormat cformat = convertFormat(pixelformat, channeltype);
 
+	if (header3.colorSpace == 1)
+		cformat == getSRGBPixelFormat(cformat);
+
 	if (cformat == PIXELFORMAT_UNKNOWN)
 		throw love::Exception("Could not parse PVR file: unsupported image format.");
 
@@ -551,8 +554,6 @@ StrongRef<ByteData> PVRHandler::parseCompressed(Data *filedata, std::vector<Stro
 	}
 
 	format = cformat;
-	sRGB = (header3.colorSpace == 1);
-
 	return memory;
 }
 

+ 1 - 1
src/modules/image/magpie/PVRHandler.h

@@ -42,7 +42,7 @@ public:
 
 	StrongRef<ByteData> parseCompressed(Data *filedata,
 	        std::vector<StrongRef<CompressedSlice>> &images,
-	        PixelFormat &format, bool &sRGB) override;
+	        PixelFormat &format) override;
 
 }; // PVRHandler
 

+ 34 - 27
src/modules/image/magpie/ddsHandler.cpp

@@ -32,13 +32,10 @@ namespace image
 namespace magpie
 {
 
-static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat, bool &sRGB, bool &bgra)
+static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat)
 {
 	using namespace dds::dxinfo;
 
-	sRGB = false;
-	bgra = false;
-
 	switch (dxformat)
 	{
 	case DXGI_FORMAT_R32G32B32A32_TYPELESS:
@@ -65,9 +62,9 @@ static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat, bool &sRGB, b
 
 	case DXGI_FORMAT_R8G8B8A8_TYPELESS:
 	case DXGI_FORMAT_R8G8B8A8_UNORM:
-	case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
-		sRGB = (dxformat == DXGI_FORMAT_R8G8B8A8_UNORM_SRGB);
 		return PIXELFORMAT_RGBA8_UNORM;
+	case DXGI_FORMAT_R8G8B8A8_UNORM_SRGB:
+		return PIXELFORMAT_RGBA8_sRGB;
 
 	case DXGI_FORMAT_R16G16_TYPELESS:
 	case DXGI_FORMAT_R16G16_FLOAT:
@@ -98,21 +95,21 @@ static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat, bool &sRGB, b
 
 	case DXGI_FORMAT_BC1_TYPELESS:
 	case DXGI_FORMAT_BC1_UNORM:
-	case DXGI_FORMAT_BC1_UNORM_SRGB:
-		sRGB = (dxformat == DXGI_FORMAT_BC1_UNORM_SRGB);
 		return PIXELFORMAT_DXT1_UNORM;
+	case DXGI_FORMAT_BC1_UNORM_SRGB:
+		return PIXELFORMAT_DXT1_sRGB;
 
 	case DXGI_FORMAT_BC2_TYPELESS:
 	case DXGI_FORMAT_BC2_UNORM:
-	case DXGI_FORMAT_BC2_UNORM_SRGB:
-		sRGB = (dxformat == DXGI_FORMAT_BC2_UNORM_SRGB);
 		return PIXELFORMAT_DXT3_UNORM;
+	case DXGI_FORMAT_BC2_UNORM_SRGB:
+		return PIXELFORMAT_DXT3_sRGB;
 
 	case DXGI_FORMAT_BC3_TYPELESS:
 	case DXGI_FORMAT_BC3_UNORM:
-	case DXGI_FORMAT_BC3_UNORM_SRGB:
-		sRGB = (dxformat == DXGI_FORMAT_BC3_UNORM_SRGB);
 		return PIXELFORMAT_DXT5_UNORM;
+	case DXGI_FORMAT_BC3_UNORM_SRGB:
+		return PIXELFORMAT_DXT5_sRGB;
 
 	case DXGI_FORMAT_BC4_TYPELESS:
 	case DXGI_FORMAT_BC4_UNORM:
@@ -136,10 +133,9 @@ static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat, bool &sRGB, b
 
 	case DXGI_FORMAT_B8G8R8A8_UNORM:
 	case DXGI_FORMAT_B8G8R8A8_TYPELESS:
+		return PIXELFORMAT_BGRA8_UNORM;
 	case DXGI_FORMAT_B8G8R8A8_UNORM_SRGB:
-		sRGB = (dxformat == DXGI_FORMAT_B8G8R8A8_UNORM_SRGB);
-		bgra = true;
-		return PIXELFORMAT_RGBA8_UNORM;
+		return PIXELFORMAT_BGRA8_sRGB;
 
 	case DXGI_FORMAT_BC6H_TYPELESS:
 	case DXGI_FORMAT_BC6H_UF16:
@@ -150,9 +146,9 @@ static PixelFormat convertFormat(dds::dxinfo::DXGIFormat dxformat, bool &sRGB, b
 
 	case DXGI_FORMAT_BC7_TYPELESS:
 	case DXGI_FORMAT_BC7_UNORM:
-	case DXGI_FORMAT_BC7_UNORM_SRGB:
-		sRGB = (dxformat == DXGI_FORMAT_BC7_UNORM_SRGB);
 		return PIXELFORMAT_BC7_UNORM;
+	case DXGI_FORMAT_BC7_UNORM_SRGB:
+		return PIXELFORMAT_BC7_sRGB;
 
 	default:
 		return PIXELFORMAT_UNKNOWN;
@@ -164,9 +160,13 @@ bool DDSHandler::canDecode(Data *data)
 	using namespace dds::dxinfo;
 
 	DXGIFormat dxformat = dds::getDDSPixelFormat(data->getData(), data->getSize());
-	bool isSRGB = false;
-	bool bgra = false;
-	PixelFormat format = convertFormat(dxformat, isSRGB, bgra);
+	PixelFormat format = convertFormat(dxformat);
+
+	// We convert BGRA to RGBA
+	if (format == PIXELFORMAT_BGRA8_UNORM)
+		format = PIXELFORMAT_RGBA8_UNORM;
+	else if (format == PIXELFORMAT_BGRA8_sRGB)
+		format = PIXELFORMAT_RGBA8_sRGB;
 
 	return ImageData::validPixelFormat(format);
 }
@@ -177,9 +177,19 @@ FormatHandler::DecodedImage DDSHandler::decode(Data *data)
 
 	dds::Parser parser(data->getData(), data->getSize());
 
-	bool isSRGB = false;
+	img.format = convertFormat(parser.getFormat());
+
 	bool bgra = false;
-	img.format = convertFormat(parser.getFormat(), isSRGB, bgra);
+	if (img.format == PIXELFORMAT_BGRA8_UNORM)
+	{
+		img.format = PIXELFORMAT_RGBA8_UNORM;
+		bgra = true;
+	}
+	else if (img.format == PIXELFORMAT_BGRA8_sRGB)
+	{
+		img.format = PIXELFORMAT_RGBA8_sRGB;
+		bgra = true;
+	}
 
 	if (!ImageData::validPixelFormat(img.format))
 		throw love::Exception("Could not parse DDS pixel data: Unsupported format.");
@@ -229,14 +239,12 @@ bool DDSHandler::canParseCompressed(Data *data)
 	return dds::isCompressedDDS(data->getData(), data->getSize());
 }
 
-StrongRef<ByteData> DDSHandler::parseCompressed(Data *filedata, std::vector<StrongRef<CompressedSlice>> &images, PixelFormat &format, bool &sRGB)
+StrongRef<ByteData> DDSHandler::parseCompressed(Data *filedata, std::vector<StrongRef<CompressedSlice>> &images, PixelFormat &format)
 {
 	if (!dds::isCompressedDDS(filedata->getData(), filedata->getSize()))
 		throw love::Exception("Could not decode compressed data (not a DDS file?)");
 
 	PixelFormat texformat = PIXELFORMAT_UNKNOWN;
-	bool isSRGB = false;
-	bool bgra = false;
 
 	size_t dataSize = 0;
 
@@ -245,7 +253,7 @@ StrongRef<ByteData> DDSHandler::parseCompressed(Data *filedata, std::vector<Stro
 	// Attempt to parse the dds file.
 	dds::Parser parser(filedata->getData(), filedata->getSize());
 
-	texformat = convertFormat(parser.getFormat(), isSRGB, bgra);
+	texformat = convertFormat(parser.getFormat());
 
 	if (texformat == PIXELFORMAT_UNKNOWN)
 		throw love::Exception("Could not parse compressed data: Unsupported format.");
@@ -280,7 +288,6 @@ StrongRef<ByteData> DDSHandler::parseCompressed(Data *filedata, std::vector<Stro
 	}
 
 	format = texformat;
-	sRGB = isSRGB;
 	return memory;
 }
 

+ 1 - 1
src/modules/image/magpie/ddsHandler.h

@@ -48,7 +48,7 @@ public:
 	bool canParseCompressed(Data *data) override;
 	StrongRef<ByteData> parseCompressed(Data *filedata,
 	        std::vector<StrongRef<CompressedSlice>> &images,
-	        PixelFormat &format, bool &sRGB) override;
+	        PixelFormat &format) override;
 
 }; // DDSHandler
 

+ 16 - 0
src/modules/image/wrap_CompressedImageData.cpp

@@ -103,6 +103,20 @@ int w_CompressedImageData_getFormat(lua_State *L)
 	return 1;
 }
 
+int w_CompressedImageData_setLinear(lua_State *L)
+{
+	CompressedImageData *t = luax_checkcompressedimagedata(L, 1);
+	t->setLinear(luax_checkboolean(L, 2));
+	return 0;
+}
+
+int w_CompressedImageData_isLinear(lua_State *L)
+{
+	CompressedImageData *t = luax_checkcompressedimagedata(L, 1);
+	luax_pushboolean(L, t->isLinear());
+	return 1;
+}
+
 static const luaL_Reg w_CompressedImageData_functions[] =
 {
 	{ "clone", w_CompressedImageData_clone },
@@ -111,6 +125,8 @@ static const luaL_Reg w_CompressedImageData_functions[] =
 	{ "getDimensions", w_CompressedImageData_getDimensions },
 	{ "getMipmapCount", w_CompressedImageData_getMipmapCount },
 	{ "getFormat", w_CompressedImageData_getFormat },
+	{ "setLinear", w_CompressedImageData_setLinear },
+	{ "isLinear", w_CompressedImageData_isLinear },
 	{ 0, 0 },
 };
 

+ 16 - 0
src/modules/image/wrap_ImageData.cpp

@@ -66,6 +66,20 @@ int w_ImageData_getFormat(lua_State *L)
 	return 1;
 }
 
+int w_ImageData_setLinear(lua_State *L)
+{
+	ImageData *t = luax_checkimagedata(L, 1);
+	t->setLinear(luax_checkboolean(L, 2));
+	return 0;
+}
+
+int w_ImageData_isLinear(lua_State *L)
+{
+	ImageData *t = luax_checkimagedata(L, 1);
+	luax_pushboolean(L, t->isLinear());
+	return 1;
+}
+
 int w_ImageData_getWidth(lua_State *L)
 {
 	ImageData *t = luax_checkimagedata(L, 1);
@@ -314,6 +328,8 @@ static const luaL_Reg w_ImageData_functions[] =
 {
 	{ "clone", w_ImageData_clone },
 	{ "getFormat", w_ImageData_getFormat },
+	{ "setLinear", w_ImageData_setLinear },
+	{ "isLinear", w_ImageData_isLinear },
 	{ "getWidth", w_ImageData_getWidth },
 	{ "getHeight", w_ImageData_getHeight },
 	{ "getDimensions", w_ImageData_getDimensions },