Browse Source

Unify pixel format enums for ImageData, CompressedImageData, and Canvas into a single PixelFormat enum.

Replace love.graphics.getRawImageFormats and love.graphics.getCompressedImageFormats with love.graphics.getImageFormats.

--HG--
branch : minor
Alex Szpakowski 8 years ago
parent
commit
0a3adc0839
50 changed files with 1030 additions and 994 deletions
  1. 2 0
      CMakeLists.txt
  2. 10 0
      platform/xcode/liblove.xcodeproj/project.pbxproj
  3. 146 0
      src/common/pixelformat.cpp
  4. 113 0
      src/common/pixelformat.h
  5. 1 1
      src/modules/font/BMFontRasterizer.cpp
  6. 1 1
      src/modules/font/ImageRasterizer.cpp
  7. 7 1
      src/modules/graphics/Texture.cpp
  8. 5 0
      src/modules/graphics/Texture.h
  9. 29 254
      src/modules/graphics/opengl/Canvas.cpp
  10. 6 43
      src/modules/graphics/opengl/Canvas.h
  11. 25 25
      src/modules/graphics/opengl/Graphics.cpp
  12. 1 1
      src/modules/graphics/opengl/Graphics.h
  13. 20 255
      src/modules/graphics/opengl/Image.cpp
  14. 1 7
      src/modules/graphics/opengl/Image.h
  15. 407 0
      src/modules/graphics/opengl/OpenGL.cpp
  16. 11 0
      src/modules/graphics/opengl/OpenGL.h
  17. 3 3
      src/modules/graphics/opengl/wrap_Canvas.cpp
  18. 17 44
      src/modules/graphics/opengl/wrap_Graphics.cpp
  19. 2 55
      src/modules/image/CompressedImageData.cpp
  20. 3 53
      src/modules/image/CompressedImageData.h
  21. 2 2
      src/modules/image/Image.h
  22. 13 33
      src/modules/image/ImageData.cpp
  23. 4 18
      src/modules/image/ImageData.h
  24. 20 20
      src/modules/image/magpie/ASTCHandler.cpp
  25. 1 1
      src/modules/image/magpie/ASTCHandler.h
  26. 1 1
      src/modules/image/magpie/CompressedFormatHandler.h
  27. 1 1
      src/modules/image/magpie/CompressedImageData.cpp
  28. 4 4
      src/modules/image/magpie/EXRHandler.cpp
  29. 1 1
      src/modules/image/magpie/EXRHandler.h
  30. 1 1
      src/modules/image/magpie/FormatHandler.cpp
  31. 2 2
      src/modules/image/magpie/FormatHandler.h
  32. 2 2
      src/modules/image/magpie/Image.cpp
  33. 2 2
      src/modules/image/magpie/Image.h
  34. 16 10
      src/modules/image/magpie/ImageData.cpp
  35. 3 3
      src/modules/image/magpie/ImageData.h
  36. 44 44
      src/modules/image/magpie/KTXHandler.cpp
  37. 1 1
      src/modules/image/magpie/KTXHandler.h
  38. 13 13
      src/modules/image/magpie/PKMHandler.cpp
  39. 1 1
      src/modules/image/magpie/PKMHandler.h
  40. 4 4
      src/modules/image/magpie/PNGHandler.cpp
  41. 1 1
      src/modules/image/magpie/PNGHandler.h
  42. 36 36
      src/modules/image/magpie/PVRHandler.cpp
  43. 1 1
      src/modules/image/magpie/PVRHandler.h
  44. 4 4
      src/modules/image/magpie/STBHandler.cpp
  45. 1 1
      src/modules/image/magpie/STBHandler.h
  46. 16 16
      src/modules/image/magpie/ddsHandler.cpp
  47. 2 2
      src/modules/image/magpie/ddsHandler.h
  48. 2 2
      src/modules/image/wrap_CompressedImageData.cpp
  49. 3 3
      src/modules/image/wrap_Image.cpp
  50. 18 21
      src/modules/image/wrap_ImageData.cpp

+ 2 - 0
CMakeLists.txt

@@ -274,6 +274,8 @@ set(LOVE_SRC_COMMON
 	src/common/Module.h
 	src/common/Object.cpp
 	src/common/Object.h
+	src/common/pixelformat.cpp
+	src/common/pixelformat.h
 	src/common/Reference.cpp
 	src/common/Reference.h
 	src/common/runtime.cpp

+ 10 - 0
platform/xcode/liblove.xcodeproj/project.pbxproj

@@ -954,6 +954,9 @@
 		FA91591F1CF1ED7500A7053F /* halffloat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA91591C1CF1ED7500A7053F /* halffloat.cpp */; };
 		FA9159201CF1ED7500A7053F /* halffloat.h in Headers */ = {isa = PBXBuildFile; fileRef = FA91591D1CF1ED7500A7053F /* halffloat.h */; };
 		FA9B4A0816E1578300074F42 /* SDL2.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA9B4A0716E1578300074F42 /* SDL2.framework */; };
+		FA9D8DD11DEB56C3002CD881 /* pixelformat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA9D8DCF1DEB56C3002CD881 /* pixelformat.cpp */; };
+		FA9D8DD21DEB56C3002CD881 /* pixelformat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA9D8DCF1DEB56C3002CD881 /* pixelformat.cpp */; };
+		FA9D8DD31DEB56C3002CD881 /* pixelformat.h in Headers */ = {isa = PBXBuildFile; fileRef = FA9D8DD01DEB56C3002CD881 /* pixelformat.h */; };
 		FAA3A9AE1B7D465A00CED060 /* android.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAA3A9AC1B7D465A00CED060 /* android.cpp */; };
 		FAA3A9AF1B7D465A00CED060 /* android.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FAA3A9AC1B7D465A00CED060 /* android.cpp */; };
 		FAA3A9B01B7D465A00CED060 /* android.h in Headers */ = {isa = PBXBuildFile; fileRef = FAA3A9AD1B7D465A00CED060 /* android.h */; };
@@ -1662,6 +1665,8 @@
 		FA91591C1CF1ED7500A7053F /* halffloat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = halffloat.cpp; sourceTree = "<group>"; };
 		FA91591D1CF1ED7500A7053F /* halffloat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = halffloat.h; sourceTree = "<group>"; };
 		FA9B4A0716E1578300074F42 /* SDL2.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SDL2.framework; path = /Library/Frameworks/SDL2.framework; sourceTree = "<absolute>"; };
+		FA9D8DCF1DEB56C3002CD881 /* pixelformat.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = pixelformat.cpp; sourceTree = "<group>"; };
+		FA9D8DD01DEB56C3002CD881 /* pixelformat.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = pixelformat.h; sourceTree = "<group>"; };
 		FAA3A9AC1B7D465A00CED060 /* android.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = android.cpp; sourceTree = "<group>"; };
 		FAA3A9AD1B7D465A00CED060 /* android.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = android.h; sourceTree = "<group>"; };
 		FAA627CD18E7E1560080752D /* CoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreServices.framework; path = System/Library/Frameworks/CoreServices.framework; sourceTree = SDKROOT; };
@@ -1799,6 +1804,8 @@
 				FA0B79071A958E3B000E1D17 /* Module.h */,
 				FA0B79081A958E3B000E1D17 /* Object.cpp */,
 				FA0B79091A958E3B000E1D17 /* Object.h */,
+				FA9D8DCF1DEB56C3002CD881 /* pixelformat.cpp */,
+				FA9D8DD01DEB56C3002CD881 /* pixelformat.h */,
 				FA0B790C1A958E3B000E1D17 /* Reference.cpp */,
 				FA0B790D1A958E3B000E1D17 /* Reference.h */,
 				FA0B790E1A958E3B000E1D17 /* runtime.cpp */,
@@ -3402,6 +3409,7 @@
 				217DFBE01D9F6D490055D849 /* except.h in Headers */,
 				FA0B79311A958E3B000E1D17 /* Module.h in Headers */,
 				217DFBF51D9F6D490055D849 /* mime.lua.h in Headers */,
+				FA9D8DD31DEB56C3002CD881 /* pixelformat.h in Headers */,
 				FA0B7D5A1A95902C000E1D17 /* wrap_Canvas.h in Headers */,
 				FA0B7E4A1A95902C000E1D17 /* wrap_DistanceJoint.h in Headers */,
 				FA0B7D2E1A95902C000E1D17 /* Color.h in Headers */,
@@ -3750,6 +3758,7 @@
 				FA0B7CF51A95902C000E1D17 /* File.cpp in Sources */,
 				FA0B7E341A95902C000E1D17 /* WeldJoint.cpp in Sources */,
 				FA4F2C091DE936E200CA37D7 /* luasocket.c in Sources */,
+				FA9D8DD21DEB56C3002CD881 /* pixelformat.cpp in Sources */,
 				FA0B7D5C1A95902C000E1D17 /* wrap_Font.cpp in Sources */,
 				FA0B7B221A958EA3000E1D17 /* luasocket.cpp in Sources */,
 				FA0B7D311A95902C000E1D17 /* Graphics.cpp in Sources */,
@@ -4058,6 +4067,7 @@
 				FA0B7EB21A95902C000E1D17 /* System.cpp in Sources */,
 				FA0B7D1B1A95902C000E1D17 /* GlyphData.cpp in Sources */,
 				FA0B7AD11A958EA3000E1D17 /* protocol.c in Sources */,
+				FA9D8DD11DEB56C3002CD881 /* pixelformat.cpp in Sources */,
 				FA0B7E661A95902C000E1D17 /* wrap_PrismaticJoint.cpp in Sources */,
 				FA0B7DCD1A95902C000E1D17 /* wrap_Keyboard.cpp in Sources */,
 				FA0B7EE51A95902D000E1D17 /* Window.cpp in Sources */,

+ 146 - 0
src/common/pixelformat.cpp

@@ -0,0 +1,146 @@
+/**
+ * Copyright (c) 2006-2016 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#include "pixelformat.h"
+#include "StringMap.h"
+
+namespace love
+{
+
+static StringMap<PixelFormat, PIXELFORMAT_MAX_ENUM>::Entry formatEntries[] =
+{
+    { "unknown", PIXELFORMAT_UNKNOWN },
+
+	{ "normal",  PIXELFORMAT_NORMAL  },
+	{ "hdr",     PIXELFORMAT_HDR     },
+
+	{ "r8",      PIXELFORMAT_R8      },
+	{ "rg8",     PIXELFORMAT_RG8     },
+	{ "rgba8",   PIXELFORMAT_RGBA8   },
+	{ "srgba8",  PIXELFORMAT_sRGBA8  },
+	{ "r16",     PIXELFORMAT_R16     },
+	{ "rg16",    PIXELFORMAT_RG16    },
+	{ "rgba16",  PIXELFORMAT_RGBA16  },
+	{ "r16f",    PIXELFORMAT_R16F    },
+	{ "rg16f",   PIXELFORMAT_RG16F   },
+	{ "rgba16f", PIXELFORMAT_RGBA16F },
+	{ "r32f",    PIXELFORMAT_R32F    },
+	{ "rg32f",   PIXELFORMAT_RG32F   },
+	{ "rgba32f", PIXELFORMAT_RGBA32F },
+
+	{ "rgba4",    PIXELFORMAT_RGBA4    },
+	{ "rgb5a1",   PIXELFORMAT_RGB5A1   },
+	{ "rgb565",   PIXELFORMAT_RGB565   },
+	{ "rgb10a2",  PIXELFORMAT_RGB10A2  },
+	{ "rg11b10f", PIXELFORMAT_RG11B10F },
+	
+    { "DXT1",      PIXELFORMAT_DXT1       },
+    { "DXT3",      PIXELFORMAT_DXT3       },
+    { "DXT5",      PIXELFORMAT_DXT5       },
+    { "BC4",       PIXELFORMAT_BC4        },
+    { "BC4s",      PIXELFORMAT_BC4s       },
+    { "BC5",       PIXELFORMAT_BC5        },
+    { "BC5s",      PIXELFORMAT_BC5s       },
+    { "BC6h",      PIXELFORMAT_BC6H       },
+    { "BC6hs",     PIXELFORMAT_BC6Hs      },
+    { "BC7",       PIXELFORMAT_BC7        },
+    { "PVR1rgb2",  PIXELFORMAT_PVR1_RGB2  },
+    { "PVR1rgb4",  PIXELFORMAT_PVR1_RGB4  },
+    { "PVR1rgba2", PIXELFORMAT_PVR1_RGBA2 },
+    { "PVR1rgba4", PIXELFORMAT_PVR1_RGBA4 },
+    { "ETC1",      PIXELFORMAT_ETC1       },
+    { "ETC2rgb",   PIXELFORMAT_ETC2_RGB   },
+    { "ETC2rgba",  PIXELFORMAT_ETC2_RGBA  },
+    { "ETC2rgba1", PIXELFORMAT_ETC2_RGBA1 },
+    { "EACr",      PIXELFORMAT_EAC_R      },
+    { "EACrs",     PIXELFORMAT_EAC_Rs     },
+    { "EACrg",     PIXELFORMAT_EAC_RG     },
+    { "EACrgs",    PIXELFORMAT_EAC_RGs    },
+    { "ASTC4x4",   PIXELFORMAT_ASTC_4x4   },
+    { "ASTC5x4",   PIXELFORMAT_ASTC_5x4   },
+    { "ASTC5x5",   PIXELFORMAT_ASTC_5x5   },
+    { "ASTC6x5",   PIXELFORMAT_ASTC_6x5   },
+    { "ASTC6x6",   PIXELFORMAT_ASTC_6x6   },
+    { "ASTC8x5",   PIXELFORMAT_ASTC_8x5   },
+    { "ASTC8x6",   PIXELFORMAT_ASTC_8x6   },
+    { "ASTC8x8",   PIXELFORMAT_ASTC_8x8   },
+    { "ASTC10x5",  PIXELFORMAT_ASTC_10x5  },
+    { "ASTC10x6",  PIXELFORMAT_ASTC_10x6  },
+    { "ASTC10x8",  PIXELFORMAT_ASTC_10x8  },
+    { "ASTC10x10", PIXELFORMAT_ASTC_10x10 },
+    { "ASTC12x10", PIXELFORMAT_ASTC_12x10 },
+    { "ASTC12x12", PIXELFORMAT_ASTC_12x12 },
+};
+
+static_assert(sizeof(formatEntries) / sizeof(formatEntries[0]) == (size_t) PIXELFORMAT_MAX_ENUM, "pixel format string map is missing entries!");
+
+static StringMap<PixelFormat, PIXELFORMAT_MAX_ENUM> formats(formatEntries, sizeof(formatEntries));
+
+bool getConstant(const char *in, PixelFormat &out)
+{
+	return formats.find(in, out);
+}
+
+bool getConstant(PixelFormat in, const char *&out)
+{
+	return formats.find(in, out);
+}
+
+bool isPixelFormatCompressed(PixelFormat format)
+{
+	// I'm lazy
+	int iformat = (int) format;
+	return iformat >= (int) PIXELFORMAT_DXT1 && iformat < (int) PIXELFORMAT_MAX_ENUM;
+}
+
+size_t getPixelFormatSize(PixelFormat format)
+{
+	switch (format)
+	{
+	case PIXELFORMAT_R8:
+		return 1;
+	case PIXELFORMAT_RG8:
+	case PIXELFORMAT_R16:
+	case PIXELFORMAT_R16F:
+	case PIXELFORMAT_RGBA4:
+	case PIXELFORMAT_RGB5A1:
+	case PIXELFORMAT_RGB565:
+		return 2;
+	case PIXELFORMAT_RGBA8:
+	case PIXELFORMAT_sRGBA8:
+	case PIXELFORMAT_RG16:
+	case PIXELFORMAT_RG16F:
+	case PIXELFORMAT_R32F:
+	case PIXELFORMAT_RGB10A2:
+	case PIXELFORMAT_RG11B10F:
+		return 4;
+	case PIXELFORMAT_RGBA16:
+	case PIXELFORMAT_RGBA16F:
+	case PIXELFORMAT_RG32F:
+		return 8;
+	case PIXELFORMAT_RGBA32F:
+		return 16;
+	default:
+		// TODO: compressed formats
+		return 0;
+	}
+}
+
+} // love

+ 113 - 0
src/common/pixelformat.h

@@ -0,0 +1,113 @@
+/**
+ * Copyright (c) 2006-2016 LOVE Development Team
+ *
+ * This software is provided 'as-is', without any express or implied
+ * warranty.  In no event will the authors be held liable for any damages
+ * arising from the use of this software.
+ *
+ * Permission is granted to anyone to use this software for any purpose,
+ * including commercial applications, and to alter it and redistribute it
+ * freely, subject to the following restrictions:
+ *
+ * 1. The origin of this software must not be misrepresented; you must not
+ *    claim that you wrote the original software. If you use this software
+ *    in a product, an acknowledgment in the product documentation would be
+ *    appreciated but is not required.
+ * 2. Altered source versions must be plainly marked as such, and must not be
+ *    misrepresented as being the original software.
+ * 3. This notice may not be removed or altered from any source distribution.
+ **/
+
+#pragma once
+
+#include "stddef.h"
+
+namespace love
+{
+
+enum PixelFormat
+{
+    PIXELFORMAT_UNKNOWN,
+
+	// these are converted to an actual format by love
+	PIXELFORMAT_NORMAL,
+	PIXELFORMAT_HDR,
+
+	// "regular" formats
+	PIXELFORMAT_R8,
+	PIXELFORMAT_RG8,
+	PIXELFORMAT_RGBA8,
+	PIXELFORMAT_sRGBA8,
+	PIXELFORMAT_R16,
+	PIXELFORMAT_RG16,
+	PIXELFORMAT_RGBA16,
+	PIXELFORMAT_R16F,
+	PIXELFORMAT_RG16F,
+	PIXELFORMAT_RGBA16F,
+	PIXELFORMAT_R32F,
+	PIXELFORMAT_RG32F,
+	PIXELFORMAT_RGBA32F,
+
+	// packed formats
+	PIXELFORMAT_RGBA4,
+	PIXELFORMAT_RGB5A1,
+	PIXELFORMAT_RGB565,
+	PIXELFORMAT_RGB10A2,
+	PIXELFORMAT_RG11B10F,
+
+	// compressed formats
+	PIXELFORMAT_DXT1,
+	PIXELFORMAT_DXT3,
+	PIXELFORMAT_DXT5,
+	PIXELFORMAT_BC4,
+	PIXELFORMAT_BC4s,
+	PIXELFORMAT_BC5,
+	PIXELFORMAT_BC5s,
+	PIXELFORMAT_BC6H,
+	PIXELFORMAT_BC6Hs,
+	PIXELFORMAT_BC7,
+	PIXELFORMAT_PVR1_RGB2,
+	PIXELFORMAT_PVR1_RGB4,
+	PIXELFORMAT_PVR1_RGBA2,
+	PIXELFORMAT_PVR1_RGBA4,
+	PIXELFORMAT_ETC1,
+	PIXELFORMAT_ETC2_RGB,
+	PIXELFORMAT_ETC2_RGBA,
+	PIXELFORMAT_ETC2_RGBA1,
+	PIXELFORMAT_EAC_R,
+	PIXELFORMAT_EAC_Rs,
+	PIXELFORMAT_EAC_RG,
+	PIXELFORMAT_EAC_RGs,
+	PIXELFORMAT_ASTC_4x4,
+	PIXELFORMAT_ASTC_5x4,
+	PIXELFORMAT_ASTC_5x5,
+	PIXELFORMAT_ASTC_6x5,
+	PIXELFORMAT_ASTC_6x6,
+	PIXELFORMAT_ASTC_8x5,
+	PIXELFORMAT_ASTC_8x6,
+	PIXELFORMAT_ASTC_8x8,
+	PIXELFORMAT_ASTC_10x5,
+	PIXELFORMAT_ASTC_10x6,
+	PIXELFORMAT_ASTC_10x8,
+	PIXELFORMAT_ASTC_10x10,
+	PIXELFORMAT_ASTC_12x10,
+	PIXELFORMAT_ASTC_12x12,
+
+	PIXELFORMAT_MAX_ENUM
+};
+
+bool getConstant(PixelFormat in, const char *&out);
+bool getConstant(const char *in, PixelFormat &out);
+
+/**
+ * Gets whether the specified pixel format is a compressed type.
+ **/
+bool isPixelFormatCompressed(PixelFormat format);
+
+/**
+ * Gets the size in bytes of the specified pixel format.
+ * NOTE: Currently returns 0 for compressed formats.
+ **/
+size_t getPixelFormatSize(PixelFormat format);
+
+} // love

+ 1 - 1
src/modules/font/BMFontRasterizer.cpp

@@ -204,7 +204,7 @@ void BMFontRasterizer::parseConfig(const std::string &configtext)
 
 				ImageData *imagedata = imagemodule->newImageData(data.get());
 
-				if (imagedata->getFormat() != ImageData::FORMAT_RGBA8)
+				if (imagedata->getFormat() != PIXELFORMAT_RGBA8)
 				{
 					imagedata->release();
 					throw love::Exception("Only 32-bit RGBA images are supported in BMFonts.");

+ 1 - 1
src/modules/font/ImageRasterizer.cpp

@@ -40,7 +40,7 @@ ImageRasterizer::ImageRasterizer(love::image::ImageData *data, uint32 *glyphs, i
 	, numglyphs(numglyphs)
 	, extraSpacing(extraspacing)
 {
-	if (data->getFormat() != image::ImageData::FORMAT_RGBA8)
+	if (data->getFormat() != PIXELFORMAT_RGBA8)
 		throw love::Exception("Only 32-bit RGBA images are supported in Image Fonts!");
 
 	load();

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

@@ -28,7 +28,8 @@ namespace graphics
 Texture::Filter Texture::defaultFilter;
 
 Texture::Texture()
-	: width(0)
+	: format(PIXELFORMAT_UNKNOWN)
+	, width(0)
 	, height(0)
 	, filter(getDefaultFilter())
 	, wrap()
@@ -40,6 +41,11 @@ Texture::~Texture()
 {
 }
 
+PixelFormat Texture::getPixelFormat() const
+{
+	return format;
+}
+
 int Texture::getWidth() const
 {
 	return width;

+ 5 - 0
src/modules/graphics/Texture.h

@@ -24,6 +24,7 @@
 // LOVE
 #include "common/StringMap.h"
 #include "common/math.h"
+#include "common/pixelformat.h"
 #include "Drawable.h"
 #include "Quad.h"
 
@@ -79,6 +80,8 @@ public:
 	 **/
 	virtual void drawq(Quad *quad, const Matrix4 &m) = 0;
 
+	PixelFormat getPixelFormat() const;
+
 	virtual int getWidth() const;
 	virtual int getHeight() const;
 
@@ -106,6 +109,8 @@ public:
 
 protected:
 
+	PixelFormat format;
+
 	int width;
 	int height;
 

+ 29 - 254
src/modules/graphics/opengl/Canvas.cpp

@@ -56,8 +56,11 @@ static GLenum createFBO(GLuint &framebuffer, GLuint texture)
 	return status;
 }
 
-static bool createMSAABuffer(int width, int height, int &samples, GLenum iformat, GLuint &buffer)
+static bool createMSAABuffer(int width, int height, int &samples, PixelFormat pixelformat, GLuint &buffer)
 {
+	bool unusedSRGB = false;
+	OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(pixelformat, true, unusedSRGB);
+
 	GLuint current_fbo = gl.getFramebuffer(OpenGL::FRAMEBUFFER_ALL);
 
 	// Temporary FBO used to clear the renderbuffer.
@@ -68,7 +71,7 @@ static bool createMSAABuffer(int width, int height, int &samples, GLenum iformat
 	glGenRenderbuffers(1, &buffer);
 	glBindRenderbuffer(GL_RENDERBUFFER, buffer);
 
-	glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, iformat, width, height);
+	glRenderbufferStorageMultisample(GL_RENDERBUFFER, samples, fmt.internalformat, width, height);
 	glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, buffer);
 
 	glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_SAMPLES, &samples);
@@ -98,11 +101,11 @@ static bool createMSAABuffer(int width, int height, int &samples, GLenum iformat
 
 int Canvas::canvasCount = 0;
 
-Canvas::Canvas(int width, int height, Format format, int msaa)
+Canvas::Canvas(int width, int height, PixelFormat format, int msaa)
 	: fbo(0)
 	, texture(0)
     , msaa_buffer(0)
-	, format(format)
+	, requested_format(format)
     , requested_samples(msaa)
 	, actual_samples(0)
 	, texture_memory(0)
@@ -138,6 +141,8 @@ Canvas::Canvas(int width, int height, Format format, int msaa)
 	vertices[3].s = 1;
 	vertices[3].t = 1;
 
+	this->format = getSizedFormat(requested_format);
+
 	loadVolatile();
 
 	++canvasCount;
@@ -181,22 +186,14 @@ bool Canvas::loadVolatile()
 	setFilter(filter);
 	setWrap(wrap);
 
-	GLenum internalformat = GL_RGBA;
-	GLenum externalformat = GL_RGBA;
-	GLenum textype = GL_UNSIGNED_BYTE;
-
-	convertFormat(format, internalformat, externalformat, textype);
-
-	// in GLES2, the internalformat and format params of TexImage have to match.
-	GLint iformat = (GLint) internalformat;
-	if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
-		iformat = (GLint) externalformat;
+	bool unusedSRGB = false;
+	OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format, false, unusedSRGB);
 
 	while (glGetError() != GL_NO_ERROR)
 		/* Clear the error buffer. */;
 
-	glTexImage2D(GL_TEXTURE_2D, 0, iformat, width, height, 0, externalformat,
-	             textype, nullptr);
+	glTexImage2D(GL_TEXTURE_2D, 0, fmt.internalformat, width, height, 0,
+	             fmt.externalformat, fmt.type, nullptr);
 
 	if (glGetError() != GL_NO_ERROR)
 	{
@@ -221,12 +218,12 @@ bool Canvas::loadVolatile()
 
 	actual_samples = requested_samples == 1 ? 0 : requested_samples;
 
-	if (actual_samples > 0 && !createMSAABuffer(width, height, actual_samples, internalformat, msaa_buffer))
+	if (actual_samples > 0 && !createMSAABuffer(width, height, actual_samples, format, msaa_buffer))
 		actual_samples = 0;
 
 	size_t prevmemsize = texture_memory;
 
-	texture_memory = ((getFormatBitsPerPixel(format) * width) / 8) * height;
+	texture_memory = getPixelFormatSize(format) * width * height;
 	if (msaa_buffer != 0)
 		texture_memory += (texture_memory * actual_samples);
 
@@ -338,149 +335,25 @@ const void *Canvas::getHandle() const
 	return &texture;
 }
 
-Canvas::Format Canvas::getSizedFormat(Canvas::Format format)
+PixelFormat Canvas::getSizedFormat(PixelFormat format)
 {
 	switch (format)
 	{
-	case FORMAT_NORMAL:
+	case PIXELFORMAT_NORMAL:
 		if (isGammaCorrect())
-			return FORMAT_SRGB;
-		else if (GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_rgb8_rgba8 || GLAD_ARM_rgba8))
+			return PIXELFORMAT_sRGBA8;
+		else if (!OpenGL::isPixelFormatSupported(PIXELFORMAT_RGBA8, true, false))
 			// 32-bit render targets don't have guaranteed support on GLES2.
-			return FORMAT_RGBA4;
+			return PIXELFORMAT_RGBA4;
 		else
-			return FORMAT_RGBA8;
-	case FORMAT_HDR:
-		return FORMAT_RGBA16F;
+			return PIXELFORMAT_RGBA8;
+	case PIXELFORMAT_HDR:
+		return PIXELFORMAT_RGBA16F;
 	default:
 		return format;
 	}
 }
 
-void Canvas::convertFormat(Canvas::Format format, GLenum &internalformat, GLenum &externalformat, GLenum &type)
-{
-	format = getSizedFormat(format);
-	externalformat = GL_RGBA;
-
-	switch (format)
-	{
-	case FORMAT_RGBA4:
-		internalformat = GL_RGBA4;
-		type = GL_UNSIGNED_SHORT_4_4_4_4;
-		break;
-	case FORMAT_RGB5A1:
-		internalformat = GL_RGB5_A1;
-		type = GL_UNSIGNED_SHORT_5_5_5_1;
-		break;
-	case FORMAT_RGB565:
-		internalformat = GL_RGB565;
-		externalformat = GL_RGB;
-		type = GL_UNSIGNED_SHORT_5_6_5;
-		break;
-	case FORMAT_R8:
-		internalformat = GL_R8;
-		externalformat = GL_RED;
-		type = GL_UNSIGNED_BYTE;
-		break;
-	case FORMAT_RG8:
-		internalformat = GL_RG8;
-		externalformat = GL_RG;
-		type = GL_UNSIGNED_BYTE;
-		break;
-	case FORMAT_RGBA8:
-	default:
-		internalformat = GL_RGBA8;
-		type = GL_UNSIGNED_BYTE;
-		break;
-	case FORMAT_RGB10A2:
-		internalformat = GL_RGB10_A2;
-		type = GL_UNSIGNED_INT_2_10_10_10_REV;
-		break;
-	case FORMAT_RG11B10F:
-		internalformat = GL_R11F_G11F_B10F;
-		externalformat = GL_RGB;
-		type = GL_UNSIGNED_INT_10F_11F_11F_REV;
-		break;
-	case FORMAT_R16F:
-		internalformat = GL_R16F;
-		externalformat = GL_RED;
-		if (GLAD_OES_texture_half_float)
-			type = GL_HALF_FLOAT_OES;
-		else if (GLAD_VERSION_1_0)
-			type = GL_FLOAT;
-		else
-			type = GL_HALF_FLOAT;
-		break;
-	case FORMAT_RG16F:
-		internalformat = GL_RG16F;
-		externalformat = GL_RG;
-		if (GLAD_OES_texture_half_float)
-			type = GL_HALF_FLOAT_OES;
-		else if (GLAD_VERSION_1_0)
-			type = GL_FLOAT;
-		else
-			type = GL_HALF_FLOAT;
-		break;
-	case FORMAT_RGBA16F:
-		internalformat = GL_RGBA16F;
-		if (GLAD_OES_texture_half_float)
-			type = GL_HALF_FLOAT_OES;
-		else if (GLAD_VERSION_1_0)
-			type = GL_FLOAT;
-		else
-			type = GL_HALF_FLOAT;
-		break;
-	case FORMAT_R32F:
-		internalformat = GL_R32F;
-		externalformat = GL_RED;
-		type = GL_FLOAT;
-		break;
-	case FORMAT_RG32F:
-		internalformat = GL_RG32F;
-		externalformat = GL_RG;
-		type = GL_FLOAT;
-		break;
-	case FORMAT_RGBA32F:
-		internalformat = GL_RGBA32F;
-		type = GL_FLOAT;
-		break;
-	case FORMAT_SRGB:
-		internalformat = GL_SRGB8_ALPHA8;
-		type = GL_UNSIGNED_BYTE;
-		if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
-			externalformat = GL_SRGB_ALPHA;
-		break;
-	}
-}
-
-size_t Canvas::getFormatBitsPerPixel(Format format)
-{
-	switch (getSizedFormat(format))
-	{
-	case FORMAT_R8:
-		return 8;
-	case FORMAT_RGBA4:
-	case FORMAT_RGB5A1:
-	case FORMAT_RGB565:
-	case FORMAT_RG8:
-	case FORMAT_R16F:
-		return 16;
-	case FORMAT_RGBA8:
-	case FORMAT_RGB10A2:
-	case FORMAT_RG11B10F:
-	case FORMAT_RG16F:
-	case FORMAT_R32F:
-	case FORMAT_SRGB:
-	default:
-		return 32;
-	case FORMAT_RGBA16F:
-	case FORMAT_RG32F:
-		return 64;
-	case FORMAT_RGBA32F:
-		return 128;
-	}
-}
-
 bool Canvas::isSupported()
 {
 	return GLAD_ES_VERSION_2_0 || GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_object || GLAD_EXT_framebuffer_object;
@@ -494,7 +367,7 @@ bool Canvas::isMultiFormatMultiCanvasSupported()
 bool Canvas::supportedFormats[] = {false};
 bool Canvas::checkedFormats[] = {false};
 
-bool Canvas::isFormatSupported(Canvas::Format format)
+bool Canvas::isFormatSupported(PixelFormat format)
 {
 	if (!isSupported())
 		return false;
@@ -502,66 +375,7 @@ bool Canvas::isFormatSupported(Canvas::Format format)
 	bool supported = true;
 	format = getSizedFormat(format);
 
-	switch (format)
-	{
-	case FORMAT_RGBA4:
-	case FORMAT_RGB5A1:
-		supported = true;
-		break;
-	case FORMAT_RGB565:
-		supported = GLAD_ES_VERSION_2_0 || GLAD_VERSION_4_2 || GLAD_ARB_ES2_compatibility;
-		break;
-	case FORMAT_R8:
-	case FORMAT_RG8:
-		if (GLAD_VERSION_1_0)
-			supported = GLAD_VERSION_3_0 || GLAD_ARB_texture_rg;
-		else if (GLAD_ES_VERSION_2_0)
-			supported = GLAD_ES_VERSION_3_0 || GLAD_EXT_texture_rg;
-		break;
-	case FORMAT_RGBA8:
-		supported = GLAD_VERSION_1_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_rgb8_rgba8 || GLAD_ARM_rgba8;
-		break;
-	case FORMAT_RGB10A2:
-		supported = GLAD_ES_VERSION_3_0 || GLAD_VERSION_1_0;
-		break;
-	case FORMAT_RG11B10F:
-		supported = GLAD_VERSION_3_0 || GLAD_EXT_packed_float || GLAD_APPLE_color_buffer_packed_float;
-		break;
-	case FORMAT_R16F:
-	case FORMAT_RG16F:
-		if (GLAD_VERSION_1_0)
-			supported = GLAD_VERSION_3_0 || (GLAD_ARB_texture_float && GLAD_ARB_texture_rg);
-		else
-			supported = GLAD_EXT_color_buffer_half_float && (GLAD_ES_VERSION_3_0 || (GLAD_OES_texture_half_float && GLAD_EXT_texture_rg));
-		break;
-	case FORMAT_RGBA16F:
-		if (GLAD_VERSION_1_0)
-			supported = GLAD_VERSION_3_0 || GLAD_ARB_texture_float;
-		else if (GLAD_ES_VERSION_2_0)
-			supported = GLAD_EXT_color_buffer_half_float && (GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float);
-		break;
-	case FORMAT_R32F:
-	case FORMAT_RG32F:
-		supported = GLAD_VERSION_3_0 || (GLAD_ARB_texture_float && GLAD_ARB_texture_rg);
-		break;
-	case FORMAT_RGBA32F:
-		supported = GLAD_VERSION_3_0 || GLAD_ARB_texture_float;
-		break;
-	case FORMAT_SRGB:
-		if (GLAD_VERSION_1_0)
-		{
-			supported = GLAD_VERSION_3_0 || ((GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB)
-				&& (GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB));
-		}
-		else
-			supported = GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB;
-		break;
-	default:
-		supported = false;
-		break;
-	}
-
-	if (!supported)
+	if (!OpenGL::isPixelFormatSupported(format, true, false))
 		return false;
 
 	if (checkedFormats[format])
@@ -572,15 +386,6 @@ bool Canvas::isFormatSupported(Canvas::Format format)
 	// a texture to a FBO whose format the driver doesn't like. So we should
 	// test with an actual FBO.
 
-	GLenum internalformat = GL_RGBA;
-	GLenum externalformat = GL_RGBA;
-	GLenum textype = GL_UNSIGNED_BYTE;
-	convertFormat(format, internalformat, externalformat, textype);
-
-	// in GLES2, the internalformat and format params of TexImage have to match.
-	if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
-		internalformat = externalformat;
-
 	GLuint texture = 0;
 	glGenTextures(1, &texture);
 	gl.bindTextureToUnit(texture, 0, false);
@@ -592,7 +397,10 @@ bool Canvas::isFormatSupported(Canvas::Format format)
 	Texture::Wrap w;
 	gl.setTextureWrap(w);
 
-	glTexImage2D(GL_TEXTURE_2D, 0, internalformat, 2, 2, 0, externalformat, textype, nullptr);
+	bool unusedSRGB = false;
+	OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format, false, unusedSRGB);
+
+	glTexImage2D(GL_TEXTURE_2D, 0, fmt.internalformat, 2, 2, 0, fmt.externalformat, fmt.type, nullptr);
 
 	GLuint fbo = 0;
 	supported = (createFBO(fbo, texture) == GL_FRAMEBUFFER_COMPLETE);
@@ -607,39 +415,6 @@ bool Canvas::isFormatSupported(Canvas::Format format)
 	return supported;
 }
 
-bool Canvas::getConstant(const char *in, Format &out)
-{
-	return formats.find(in, out);
-}
-
-bool Canvas::getConstant(Format in, const char *&out)
-{
-	return formats.find(in, out);
-}
-
-StringMap<Canvas::Format, Canvas::FORMAT_MAX_ENUM>::Entry Canvas::formatEntries[] =
-{
-	{"normal", FORMAT_NORMAL},
-	{"hdr", FORMAT_HDR},
-	{"rgba4", FORMAT_RGBA4},
-	{"rgb5a1", FORMAT_RGB5A1},
-	{"rgb565", FORMAT_RGB565},
-	{"r8", FORMAT_R8},
-	{"rg8", FORMAT_RG8},
-	{"rgba8", FORMAT_RGBA8},
-	{"rgb10a2", FORMAT_RGB10A2},
-	{"rg11b10f", FORMAT_RG11B10F},
-	{"r16f", FORMAT_R16F},
-	{"rg16f", FORMAT_RG16F},
-	{"rgba16f", FORMAT_RGBA16F},
-	{"r32f", FORMAT_R32F},
-	{"rg32f", FORMAT_RG32F},
-	{"rgba32f", FORMAT_RGBA32F},
-	{"srgb", FORMAT_SRGB},
-};
-
-StringMap<Canvas::Format, Canvas::FORMAT_MAX_ENUM> Canvas::formats(Canvas::formatEntries, sizeof(Canvas::formatEntries));
-
 } // opengl
 } // graphics
 } // love

+ 6 - 43
src/modules/graphics/opengl/Canvas.h

@@ -43,30 +43,7 @@ class Canvas : public Texture, public Volatile
 {
 public:
 
-	// Different Canvas render target formats.
-	enum Format
-	{
-		FORMAT_NORMAL,   // Usually SRGB, RGBA8 or a similar fallback. Always supported.
-		FORMAT_HDR,      // Usually RGBA16F. Not always supported.
-		FORMAT_RGBA4,    // RGBA with 4 bits per channel.
-		FORMAT_RGB5A1,   // RGB with 5 bits per channel, and A with 1 bit.
-		FORMAT_RGB565,   // RGB with 5, 6, and 5 bits each, respectively.
-		FORMAT_R8,       // Single (red) 8-bit channel.
-		FORMAT_RG8,      // Two-channel (red and green) with 8 bits per channel.
-		FORMAT_RGBA8,    // RGBA with 8 bits per channel.
-		FORMAT_RGB10A2,  // RGB with 10 bits each, and A with 2 bits.
-		FORMAT_RG11B10F, // Floating point [0, +65024]. RG with 11 FP bits each, and B with 10 FP bits.
-		FORMAT_R16F,     // Floating point [-65504, +65504]. R with 16 FP bits.
-		FORMAT_RG16F,    // Floating point [-65504, +65504]. RG with 16 FP bits per channel.
-		FORMAT_RGBA16F,  // Floating point [-65504, +65504]. RGBA with 16 FP bits per channel.
-		FORMAT_R32F,     // Floating point [-65504, +65504]. R with 32 FP bits.
-		FORMAT_RG32F,    // Floating point [-65504, +65504]. RG with 32 FP bits per channel.
-		FORMAT_RGBA32F,  // Floating point [-65504, +65504]. RGBA with 32 FP bits per channel.
-		FORMAT_SRGB,     // sRGB with 8 bits per channel, plus 8 bit linear A.
-		FORMAT_MAX_ENUM
-	};
-
-	Canvas(int width, int height, Format format = FORMAT_NORMAL, int msaa = 0);
+	Canvas(int width, int height, PixelFormat format = PIXELFORMAT_NORMAL, int msaa = 0);
 	virtual ~Canvas();
 
 	// Implements Volatile.
@@ -87,11 +64,6 @@ public:
 		return status;
 	}
 
-	inline Format getTextureFormat() const
-	{
-		return format;
-	}
-
 	inline int getMSAA() const
 	{
 		return actual_samples;
@@ -112,29 +84,23 @@ public:
 		return fbo;
 	}
 
-	static Format getSizedFormat(Format format);
+	static PixelFormat getSizedFormat(PixelFormat format);
 	static bool isSupported();
 	static bool isMultiFormatMultiCanvasSupported();
-	static bool isFormatSupported(Format format);
+	static bool isFormatSupported(PixelFormat format);
 
 	static int canvasCount;
 
-	static bool getConstant(const char *in, Format &out);
-	static bool getConstant(Format in, const char *&out);
-
 private:
 
 	void drawv(const Matrix4 &t, const Vertex *v);
 
-	static void convertFormat(Format format, GLenum &internalformat, GLenum &externalformat, GLenum &type);
-	static size_t getFormatBitsPerPixel(Format format);
-
 	GLuint fbo;
 
 	GLuint texture;
 	GLuint msaa_buffer;
 
-	Format format;
+	PixelFormat requested_format;
 
 	GLenum status;
 
@@ -143,11 +109,8 @@ private:
 
 	size_t texture_memory;
 
-	static bool supportedFormats[FORMAT_MAX_ENUM];
-	static bool checkedFormats[FORMAT_MAX_ENUM];
-
-	static StringMap<Format, FORMAT_MAX_ENUM>::Entry formatEntries[];
-	static StringMap<Format, FORMAT_MAX_ENUM> formats;
+	static bool supportedFormats[PIXELFORMAT_MAX_ENUM];
+	static bool checkedFormats[PIXELFORMAT_MAX_ENUM];
 
 }; // Canvas
 

+ 25 - 25
src/modules/graphics/opengl/Graphics.cpp

@@ -492,9 +492,9 @@ void Graphics::beginPass(const PassInfo &info)
 	Canvas *firstcanvas = info.colorAttachments[0].canvas;
 
 	bool multiformatsupported = isSupported(Feature::FEATURE_MULTI_CANVAS_FORMATS);
-	Canvas::Format firstformat = firstcanvas->getTextureFormat();
+	PixelFormat firstformat = firstcanvas->getPixelFormat();
 
-	bool hasSRGBcanvas = Canvas::getSizedFormat(firstformat) == Canvas::FORMAT_SRGB;
+	bool hasSRGBcanvas = firstformat == PIXELFORMAT_sRGBA8;
 
 	for (int i = 1; i < info.colorAttachmentCount; i++)
 	{
@@ -503,13 +503,13 @@ void Graphics::beginPass(const PassInfo &info)
 		if (c->getWidth() != firstcanvas->getWidth() || c->getHeight() != firstcanvas->getHeight())
 			throw love::Exception("All canvases in a render pass must have the same dimensions.");
 
-		if (!multiformatsupported && c->getTextureFormat() != firstformat)
+		if (!multiformatsupported && c->getPixelFormat() != firstformat)
 			throw love::Exception("This system doesn't support multi-canvas rendering with different canvas formats.");
 
 		if (c->getRequestedMSAA() != firstcanvas->getRequestedMSAA())
 			throw love::Exception("All Canvases in a render pass must have the same requested MSAA value.");
 
-		if (Canvas::getSizedFormat(c->getTextureFormat()) == Canvas::FORMAT_SRGB)
+		if (c->getPixelFormat() == PIXELFORMAT_sRGBA8)
 			hasSRGBcanvas = true;
 	}
 
@@ -639,25 +639,25 @@ void Graphics::endPass(int sX, int sY, int sW, int sH, const ScreenshotInfo *inf
 		if (imagemodule == nullptr)
 			throw love::Exception("The love.image module must be loaded to capture a Canvas' contents.");
 
-		image::ImageData::Format format;
-		switch (Canvas::getSizedFormat(attachments[0].canvas->getTextureFormat()))
+		PixelFormat format;
+		switch (attachments[0].canvas->getPixelFormat())
 		{
-		case Canvas::FORMAT_RGB10A2: // FIXME: Conversions aren't supported in GLES
-			format = image::ImageData::FORMAT_RGBA16;
+		case PIXELFORMAT_RGB10A2: // FIXME: Conversions aren't supported in GLES
+			format = PIXELFORMAT_RGBA16;
 			break;
-		case Canvas::FORMAT_R16F:
-		case Canvas::FORMAT_RG16F:
-		case Canvas::FORMAT_RGBA16F:
-		case Canvas::FORMAT_RG11B10F: // FIXME: Conversions aren't supported in GLES
-			format = image::ImageData::FORMAT_RGBA16F;
+		case PIXELFORMAT_R16F:
+		case PIXELFORMAT_RG16F:
+		case PIXELFORMAT_RGBA16F:
+		case PIXELFORMAT_RG11B10F: // FIXME: Conversions aren't supported in GLES
+			format = PIXELFORMAT_RGBA16F;
 			break;
-		case Canvas::FORMAT_R32F:
-		case Canvas::FORMAT_RG32F:
-		case Canvas::FORMAT_RGBA32F:
-			format = image::ImageData::FORMAT_RGBA32F;
+		case PIXELFORMAT_R32F:
+		case PIXELFORMAT_RG32F:
+		case PIXELFORMAT_RGBA32F:
+			format = PIXELFORMAT_RGBA32F;
 			break;
 		default:
-			format = image::ImageData::FORMAT_RGBA8;
+			format = PIXELFORMAT_RGBA8;
 			break;
 		}
 
@@ -695,13 +695,13 @@ void Graphics::endPass(int sX, int sY, int sW, int sH, const ScreenshotInfo *inf
 		GLenum datatype;
 		switch (imagedata->getFormat())
 		{
-		case image::ImageData::FORMAT_RGBA16:
+		case PIXELFORMAT_RGBA16:
 			datatype = GL_UNSIGNED_SHORT;
 			break;
-		case image::ImageData::FORMAT_RGBA16F:
+		case PIXELFORMAT_RGBA16F:
 			datatype = GL_HALF_FLOAT;
 			break;
-		case image::ImageData::FORMAT_RGBA32F:
+		case PIXELFORMAT_RGBA32F:
 			datatype = GL_FLOAT;
 			break;
 		default:
@@ -831,7 +831,7 @@ void Graphics::bindCachedFBOForPass(const PassInfo &pass)
 		if (drawbuffers.size() > 1)
 			glDrawBuffers(1, &drawbuffers[0]);
 
-		GLuint stencil = attachCachedStencilBuffer(w, h, msaa);
+		GLuint stencil = attachCachedStencilBuffer(w, h, info.canvases[0]->getRequestedMSAA());
 
 		if (stencil == 0)
 		{
@@ -1011,7 +1011,7 @@ void Graphics::present(void *screenshotCallbackData)
 
 			try
 			{
-				img = imagemodule->newImageData(w, h, image::ImageData::FORMAT_RGBA8, screenshot);
+				img = imagemodule->newImageData(w, h, PIXELFORMAT_RGBA8, screenshot);
 			}
 			catch (love::Exception &)
 			{
@@ -1303,7 +1303,7 @@ ParticleSystem *Graphics::newParticleSystem(Texture *texture, int size)
 	return new ParticleSystem(texture, size);
 }
 
-Canvas *Graphics::newCanvas(int width, int height, Canvas::Format format, int msaa)
+Canvas *Graphics::newCanvas(int width, int height, PixelFormat format, int msaa)
 {
 	if (!Canvas::isSupported())
 		throw love::Exception("Canvases are not supported by your OpenGL drivers!");
@@ -1311,7 +1311,7 @@ Canvas *Graphics::newCanvas(int width, int height, Canvas::Format format, int ms
 	if (!Canvas::isFormatSupported(format))
 	{
 		const char *fstr = "rgba8";
-		Canvas::getConstant(Canvas::getSizedFormat(format), fstr);
+		love::getConstant(Canvas::getSizedFormat(format), fstr);
 		throw love::Exception("The %s canvas format is not supported by your OpenGL drivers.", fstr);
 	}
 

+ 1 - 1
src/modules/graphics/opengl/Graphics.h

@@ -226,7 +226,7 @@ public:
 
 	ParticleSystem *newParticleSystem(Texture *texture, int size);
 
-	Canvas *newCanvas(int width, int height, Canvas::Format format = Canvas::FORMAT_NORMAL, int msaa = 0);
+	Canvas *newCanvas(int width, int height, PixelFormat format = PIXELFORMAT_NORMAL, int msaa = 0);
 
 	Shader *newShader(const Shader::ShaderSource &source);
 

+ 20 - 255
src/modules/graphics/opengl/Image.cpp

@@ -113,6 +113,8 @@ Image::Image(const std::vector<love::image::ImageData *> &imagedata, const Flags
 	for (const auto &id : imagedata)
 		data.push_back(id);
 
+	format = data[0]->getFormat();
+
 	preload();
 	loadVolatile();
 
@@ -148,6 +150,8 @@ Image::Image(const std::vector<love::image::CompressedImageData *> &compressedda
 	for (image::CompressedImageData *cd : compresseddata)
 		cdata.push_back(cd);
 
+	format = cdata[0]->getFormat();
+
 	preload();
 	loadVolatile();
 
@@ -230,7 +234,7 @@ void Image::loadDefaultTexture()
 
 void Image::loadFromCompressedData()
 {
-	GLenum iformat = getCompressedFormat(cdata[0]->getFormat(), sRGB);
+	OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format, false, sRGB);
 
 	if (isGammaCorrect() && !sRGB)
 		flags.linear = true;
@@ -249,17 +253,15 @@ void Image::loadFromCompressedData()
 		auto cd = cdata.size() > 1 ? cdata[i].get() : cdata[0].get();
 		int datamip = cdata.size() > 1 ? 0 : i;
 
-		glCompressedTexImage2D(GL_TEXTURE_2D, i, iformat, cd->getWidth(datamip),
-		                       cd->getHeight(datamip), 0,
+		glCompressedTexImage2D(GL_TEXTURE_2D, i, fmt.internalformat,
+		                       cd->getWidth(datamip), cd->getHeight(datamip), 0,
 		                       (GLsizei) cd->getSize(datamip), cd->getData(datamip));
 	}
 }
 
 void Image::loadFromImageData()
 {
-	GLenum glformat = GL_RGBA;
-	GLenum gltype = GL_UNSIGNED_BYTE;
-	GLenum iformat = getFormat(data[0]->getFormat(), glformat, gltype, sRGB);
+	OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format, false, sRGB);
 
 	if (isGammaCorrect() && !sRGB)
 		flags.linear = true;
@@ -271,8 +273,8 @@ void Image::loadFromImageData()
 		love::image::ImageData *id = data[i].get();
 		love::thread::Lock lock(id->getMutex());
 
-		glTexImage2D(GL_TEXTURE_2D, i, iformat, id->getWidth(), id->getHeight(),
-		             0, glformat, gltype, id->getData());
+		glTexImage2D(GL_TEXTURE_2D, i, fmt.internalformat, id->getWidth(), id->getHeight(),
+		             0, fmt.externalformat, fmt.type, id->getData());
 	}
 
 	if (data.size() <= 1)
@@ -286,13 +288,13 @@ bool Image::loadVolatile()
 
 	OpenGL::TempDebugGroup debuggroup("Image load");
 
-	if (isCompressed() && !hasCompressedTextureSupport(cdata[0]->getFormat(), sRGB))
+	if (!OpenGL::isPixelFormatSupported(format, false, sRGB))
 	{
 		const char *str;
-		if (image::CompressedImageData::getConstant(cdata[0]->getFormat(), str))
+		if (love::getConstant(format, str))
 		{
 			throw love::Exception("Cannot create image: "
-			                      "%s%s compressed images are not supported on this system.", sRGB ? "sRGB " : "", str);
+			                      "%s%s images are not supported on this system.", sRGB ? "sRGB " : "", str);
 		}
 		else
 			throw love::Exception("cannot create image: format is not supported on this system.");
@@ -417,9 +419,8 @@ bool Image::refresh(int xoffset, int yoffset, int w, int h)
 		return true;
 	}
 
-	GLenum glformat = GL_RGBA;
-	GLenum gltype = GL_UNSIGNED_BYTE;
-	getFormat(data[0]->getFormat(), glformat, gltype, sRGB);
+	bool isSRGB = sRGB;
+	OpenGL::TextureFormat fmt = OpenGL::convertPixelFormat(format, false, isSRGB);
 
 	int mipcount = flags.mipmaps ? (int) data.size() : 1;
 
@@ -430,8 +431,8 @@ bool Image::refresh(int xoffset, int yoffset, int w, int h)
 		pdata += yoffset * data[i]->getWidth() + xoffset;
 
 		thread::Lock lock(data[i]->getMutex());
-		glTexSubImage2D(GL_TEXTURE_2D, i, xoffset, yoffset, w, h, glformat,
-		                gltype, pdata);
+		glTexSubImage2D(GL_TEXTURE_2D, i, xoffset, yoffset, w, h,
+		                fmt.externalformat, fmt.type, pdata);
 
 		xoffset /= 2;
 		yoffset /= 2;
@@ -501,7 +502,7 @@ void Image::setFilter(const Texture::Filter &f)
 
 	filter = f;
 
-	if (!data.empty() && !hasTextureFilteringSupport(data[0]->getFormat()))
+	if (!data.empty() && !OpenGL::hasTextureFilteringSupport(data[0]->getFormat()))
 	{
 		filter.mag = filter.min = FILTER_NEAREST;
 
@@ -599,245 +600,9 @@ bool Image::isCompressed() const
 	return compressed;
 }
 
-GLenum Image::getFormat(image::ImageData::Format format, GLenum &glformat, GLenum &gltype, bool &isSRGB) const
-{
-	using image::ImageData;
-
-	GLenum internalformat = GL_RGBA8;
-	glformat = GL_RGBA;
-	gltype = GL_UNSIGNED_BYTE;
-
-	switch (format)
-	{
-	case ImageData::FORMAT_RGBA8:
-		if (isSRGB)
-		{
-			internalformat = GL_SRGB8_ALPHA8;
-			if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
-				glformat = GL_SRGB_ALPHA;
-		}
-		break;
-	case ImageData::FORMAT_RGBA16:
-		internalformat = GL_RGBA16;
-		gltype = GL_UNSIGNED_SHORT;
-		isSRGB = false;
-		break;
-	case ImageData::FORMAT_RGBA16F:
-		internalformat = GL_RGBA16F;
-		// HALF_FLOAT_OES has a different value than HALF_FLOAT... of course
-		if (GLAD_OES_texture_half_float && !GLAD_ES_VERSION_3_0)
-			gltype = GL_HALF_FLOAT_OES;
-		else
-			gltype = GL_HALF_FLOAT;
-		isSRGB = false;
-		break;
-	case ImageData::FORMAT_RGBA32F:
-		internalformat = GL_RGBA32F;
-		gltype = GL_FLOAT;
-		isSRGB = false;
-		break;
-	default:
-		break;
-	}
-
-	if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
-		internalformat = glformat;
-
-	return internalformat;
-}
-
-GLenum Image::getCompressedFormat(image::CompressedImageData::Format cformat, bool &isSRGB) const
-{
-	using image::CompressedImageData;
-
-	switch (cformat)
-	{
-	case CompressedImageData::FORMAT_DXT1:
-		return isSRGB ? GL_COMPRESSED_SRGB_S3TC_DXT1_EXT : GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
-	case CompressedImageData::FORMAT_DXT3:
-		return isSRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT : GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
-	case CompressedImageData::FORMAT_DXT5:
-		return isSRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
-	case CompressedImageData::FORMAT_BC4:
-		isSRGB = false;
-		return GL_COMPRESSED_RED_RGTC1;
-	case CompressedImageData::FORMAT_BC4s:
-		isSRGB = false;
-		return GL_COMPRESSED_SIGNED_RED_RGTC1;
-	case CompressedImageData::FORMAT_BC5:
-		isSRGB = false;
-		return GL_COMPRESSED_RG_RGTC2;
-	case CompressedImageData::FORMAT_BC5s:
-		isSRGB = false;
-		return GL_COMPRESSED_SIGNED_RG_RGTC2;
-	case CompressedImageData::FORMAT_BC6H:
-		isSRGB = false;
-		return GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT;
-	case CompressedImageData::FORMAT_BC6Hs:
-		isSRGB = false;
-		return GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT;
-	case CompressedImageData::FORMAT_BC7:
-		return isSRGB ? GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM : GL_COMPRESSED_RGBA_BPTC_UNORM;
-	case CompressedImageData::FORMAT_PVR1_RGB2:
-		return isSRGB ? GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT : GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
-	case CompressedImageData::FORMAT_PVR1_RGB4:
-		return isSRGB ? GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT : GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
-	case CompressedImageData::FORMAT_PVR1_RGBA2:
-		return isSRGB ? GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT : GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
-	case CompressedImageData::FORMAT_PVR1_RGBA4:
-		return isSRGB ? GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT : GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
-	case CompressedImageData::FORMAT_ETC1:
-		// The ETC2 format can load ETC1 textures.
-		if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility)
-			return isSRGB ? GL_COMPRESSED_SRGB8_ETC2 : GL_COMPRESSED_RGB8_ETC2;
-		else
-		{
-			isSRGB = false;
-			return GL_ETC1_RGB8_OES;
-		}
-	case CompressedImageData::FORMAT_ETC2_RGB:
-		return isSRGB ? GL_COMPRESSED_SRGB8_ETC2 : GL_COMPRESSED_RGB8_ETC2;
-	case CompressedImageData::FORMAT_ETC2_RGBA:
-		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : GL_COMPRESSED_RGBA8_ETC2_EAC;
-	case CompressedImageData::FORMAT_ETC2_RGBA1:
-		return isSRGB ? GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 : GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
-	case CompressedImageData::FORMAT_EAC_R:
-		isSRGB = false;
-		return GL_COMPRESSED_R11_EAC;
-	case CompressedImageData::FORMAT_EAC_Rs:
-		isSRGB = false;
-		return GL_COMPRESSED_SIGNED_R11_EAC;
-	case CompressedImageData::FORMAT_EAC_RG:
-		isSRGB = false;
-		return GL_COMPRESSED_RG11_EAC;
-	case CompressedImageData::FORMAT_EAC_RGs:
-		isSRGB = false;
-		return GL_COMPRESSED_SIGNED_RG11_EAC;
-	case CompressedImageData::FORMAT_ASTC_4x4:
-		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : GL_COMPRESSED_RGBA_ASTC_4x4_KHR;
-	case CompressedImageData::FORMAT_ASTC_5x4:
-		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : GL_COMPRESSED_RGBA_ASTC_5x4_KHR;
-	case CompressedImageData::FORMAT_ASTC_5x5:
-		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : GL_COMPRESSED_RGBA_ASTC_5x5_KHR;
-	case CompressedImageData::FORMAT_ASTC_6x5:
-		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : GL_COMPRESSED_RGBA_ASTC_6x5_KHR;
-	case CompressedImageData::FORMAT_ASTC_6x6:
-		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : GL_COMPRESSED_RGBA_ASTC_6x6_KHR;
-	case CompressedImageData::FORMAT_ASTC_8x5:
-		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : GL_COMPRESSED_RGBA_ASTC_8x5_KHR;
-	case CompressedImageData::FORMAT_ASTC_8x6:
-		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : GL_COMPRESSED_RGBA_ASTC_8x6_KHR;
-	case CompressedImageData::FORMAT_ASTC_8x8:
-		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : GL_COMPRESSED_RGBA_ASTC_8x8_KHR;
-	case CompressedImageData::FORMAT_ASTC_10x5:
-		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : GL_COMPRESSED_RGBA_ASTC_10x5_KHR;
-	case CompressedImageData::FORMAT_ASTC_10x6:
-		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : GL_COMPRESSED_RGBA_ASTC_10x6_KHR;
-	case CompressedImageData::FORMAT_ASTC_10x8:
-		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : GL_COMPRESSED_RGBA_ASTC_10x8_KHR;
-	case CompressedImageData::FORMAT_ASTC_10x10:
-		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : GL_COMPRESSED_RGBA_ASTC_10x10_KHR;
-	case CompressedImageData::FORMAT_ASTC_12x10:
-		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : GL_COMPRESSED_RGBA_ASTC_12x10_KHR;
-	case CompressedImageData::FORMAT_ASTC_12x12:
-		return isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : GL_COMPRESSED_RGBA_ASTC_12x12_KHR;
-	default:
-		return isSRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8;
-	}
-}
-
-bool Image::hasAnisotropicFilteringSupport()
-{
-	return GLAD_EXT_texture_filter_anisotropic != GL_FALSE;
-}
-
-bool Image::hasTextureSupport(image::ImageData::Format format)
-{
-	using image::ImageData;
-
-	switch (format)
-	{
-	case ImageData::FORMAT_RGBA8:
-		return true;
-	case ImageData::FORMAT_RGBA16:
-		return GLAD_VERSION_1_1 || GLAD_EXT_texture_norm16;
-	case ImageData::FORMAT_RGBA16F:
-		return GLAD_VERSION_3_0 || (GLAD_ARB_texture_float && GLAD_ARB_half_float_pixel) || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float;
-	case ImageData::FORMAT_RGBA32F:
-		return GLAD_VERSION_3_0 || GLAD_ARB_texture_float || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_float;
-	default:
-		return false;
-	}
-}
-
-bool Image::hasTextureFilteringSupport(image::ImageData::Format format)
+bool Image::isFormatSupported(PixelFormat pixelformat)
 {
-	switch (format)
-	{
-	case image::ImageData::FORMAT_RGBA16F:
-		return GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float_linear;
-	case image::ImageData::FORMAT_RGBA32F:
-		return GLAD_VERSION_1_1;
-	default:
-		return true;
-	}
-}
-
-bool Image::hasCompressedTextureSupport(image::CompressedImageData::Format format, bool sRGB)
-{
-	using image::CompressedImageData;
-
-	switch (format)
-	{
-	case CompressedImageData::FORMAT_DXT1:
-		return GLAD_EXT_texture_compression_s3tc || GLAD_EXT_texture_compression_dxt1;
-	case CompressedImageData::FORMAT_DXT3:
-		return GLAD_EXT_texture_compression_s3tc || GLAD_ANGLE_texture_compression_dxt3;
-	case CompressedImageData::FORMAT_DXT5:
-		return GLAD_EXT_texture_compression_s3tc || GLAD_ANGLE_texture_compression_dxt5;
-	case CompressedImageData::FORMAT_BC4:
-	case CompressedImageData::FORMAT_BC4s:
-	case CompressedImageData::FORMAT_BC5:
-	case CompressedImageData::FORMAT_BC5s:
-		return (GLAD_VERSION_3_0 || GLAD_ARB_texture_compression_rgtc || GLAD_EXT_texture_compression_rgtc);
-	case CompressedImageData::FORMAT_BC6H:
-	case CompressedImageData::FORMAT_BC6Hs:
-	case CompressedImageData::FORMAT_BC7:
-		return GLAD_VERSION_4_2 || GLAD_ARB_texture_compression_bptc;
-	case CompressedImageData::FORMAT_PVR1_RGB2:
-	case CompressedImageData::FORMAT_PVR1_RGB4:
-	case CompressedImageData::FORMAT_PVR1_RGBA2:
-	case CompressedImageData::FORMAT_PVR1_RGBA4:
-		return sRGB ? GLAD_EXT_pvrtc_sRGB : GLAD_IMG_texture_compression_pvrtc;
-	case CompressedImageData::FORMAT_ETC1:
-		// ETC2 support guarantees ETC1 support as well.
-		return GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility || GLAD_OES_compressed_ETC1_RGB8_texture;
-	case CompressedImageData::FORMAT_ETC2_RGB:
-	case CompressedImageData::FORMAT_ETC2_RGBA:
-	case CompressedImageData::FORMAT_ETC2_RGBA1:
-	case CompressedImageData::FORMAT_EAC_R:
-	case CompressedImageData::FORMAT_EAC_Rs:
-	case CompressedImageData::FORMAT_EAC_RG:
-	case CompressedImageData::FORMAT_EAC_RGs:
-		return GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility;
-	case CompressedImageData::FORMAT_ASTC_4x4:
-	case CompressedImageData::FORMAT_ASTC_5x4:
-	case CompressedImageData::FORMAT_ASTC_5x5:
-	case CompressedImageData::FORMAT_ASTC_6x5:
-	case CompressedImageData::FORMAT_ASTC_6x6:
-	case CompressedImageData::FORMAT_ASTC_8x5:
-	case CompressedImageData::FORMAT_ASTC_8x6:
-	case CompressedImageData::FORMAT_ASTC_8x8:
-	case CompressedImageData::FORMAT_ASTC_10x5:
-	case CompressedImageData::FORMAT_ASTC_10x6:
-	case CompressedImageData::FORMAT_ASTC_10x8:
-	case CompressedImageData::FORMAT_ASTC_10x10:
-	case CompressedImageData::FORMAT_ASTC_12x10:
-	case CompressedImageData::FORMAT_ASTC_12x12:
-		return GLAD_ES_VERSION_3_2 || GLAD_KHR_texture_compression_astc_ldr;
-	default:
-		return false;
-	}
+	return OpenGL::isPixelFormatSupported(pixelformat, false, false);
 }
 
 bool Image::hasSRGBSupport()

+ 1 - 7
src/modules/graphics/opengl/Image.h

@@ -127,10 +127,7 @@ public:
 	static void setDefaultMipmapFilter(FilterMode f);
 	static FilterMode getDefaultMipmapFilter();
 
-	static bool hasAnisotropicFilteringSupport();
-	static bool hasTextureSupport(image::ImageData::Format format);
-	static bool hasTextureFilteringSupport(image::ImageData::Format format);
-	static bool hasCompressedTextureSupport(image::CompressedImageData::Format format, bool sRGB);
+	static bool isFormatSupported(PixelFormat pixelformat);
 	static bool hasSRGBSupport();
 
 	static bool getConstant(const char *in, FlagType &out);
@@ -149,9 +146,6 @@ private:
 	void loadFromCompressedData();
 	void loadFromImageData();
 
-	GLenum getFormat(image::ImageData::Format format, GLenum &glformat, GLenum &gltype, bool &isSRGB) const;
-	GLenum getCompressedFormat(image::CompressedImageData::Format cformat, bool &isSRGB) const;
-
 	// The ImageData from which the texture is created. May be empty if
 	// Compressed image data was used to create the texture.
 	// Each element in the array is a mipmap level.

+ 407 - 0
src/modules/graphics/opengl/OpenGL.cpp

@@ -772,6 +772,413 @@ OpenGL::Vendor OpenGL::getVendor() const
 	return vendor;
 }
 
+OpenGL::TextureFormat OpenGL::convertPixelFormat(PixelFormat pixelformat, bool renderbuffer, bool &isSRGB)
+{
+	TextureFormat f;
+
+	if (pixelformat == PIXELFORMAT_RGBA8 && isSRGB)
+		pixelformat = PIXELFORMAT_sRGBA8;
+	else if (pixelformat == PIXELFORMAT_ETC1)
+	{
+		// The ETC2 format can load ETC1 textures.
+		if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility)
+			pixelformat = PIXELFORMAT_ETC2_RGB;
+	}
+
+	switch (pixelformat)
+	{
+	case PIXELFORMAT_R8:
+		f.internalformat = GL_R8;
+		f.externalformat = GL_RED;
+		f.type = GL_UNSIGNED_BYTE;
+		break;
+	case PIXELFORMAT_RG8:
+		f.internalformat = GL_RG8;
+		f.externalformat = GL_RG;
+		f.type = GL_UNSIGNED_BYTE;
+		break;
+	case PIXELFORMAT_RGBA8:
+		f.internalformat = GL_RGBA8;
+		f.externalformat = GL_RGBA;
+		f.type = GL_UNSIGNED_BYTE;
+		break;
+	case PIXELFORMAT_sRGBA8:
+		f.internalformat = GL_SRGB8_ALPHA8;
+		f.type = GL_UNSIGNED_BYTE;
+		if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
+			f.externalformat = GL_SRGB_ALPHA;
+		else
+			f.externalformat = GL_RGBA;
+		break;
+	case PIXELFORMAT_R16:
+		f.internalformat = GL_R16;
+		f.externalformat = GL_RED;
+		f.type = GL_UNSIGNED_SHORT;
+		break;
+	case PIXELFORMAT_RG16:
+		f.internalformat = GL_RG16;
+		f.externalformat = GL_RG;
+		f.type = GL_UNSIGNED_SHORT;
+		break;
+	case PIXELFORMAT_RGBA16:
+		f.internalformat = GL_RGBA16;
+		f.externalformat = GL_RGBA;
+		f.type = GL_UNSIGNED_SHORT;
+		break;
+	case PIXELFORMAT_R16F:
+		f.internalformat = GL_R16F;
+		f.externalformat = GL_RED;
+		if (GLAD_OES_texture_half_float)
+			f.type = GL_HALF_FLOAT_OES;
+		else
+			f.type = GL_HALF_FLOAT;
+		break;
+	case PIXELFORMAT_RG16F:
+		f.internalformat = GL_RG16F;
+		f.externalformat = GL_RG;
+		if (GLAD_OES_texture_half_float)
+			f.type = GL_HALF_FLOAT_OES;
+		else
+			f.type = GL_HALF_FLOAT;
+		break;
+	case PIXELFORMAT_RGBA16F:
+		f.internalformat = GL_RGBA16F;
+		f.externalformat = GL_RGBA;
+		if (GLAD_OES_texture_half_float)
+			f.type = GL_HALF_FLOAT_OES;
+		else
+			f.type = GL_HALF_FLOAT;
+		break;
+	case PIXELFORMAT_R32F:
+		f.internalformat = GL_R32F;
+		f.externalformat = GL_RED;
+		f.type = GL_FLOAT;
+		break;
+	case PIXELFORMAT_RG32F:
+		f.internalformat = GL_RG32F;
+		f.externalformat = GL_RG;
+		f.type = GL_FLOAT;
+		break;
+	case PIXELFORMAT_RGBA32F:
+		f.internalformat = GL_RGBA32F;
+		f.externalformat = GL_RGBA;
+		f.type = GL_FLOAT;
+		break;
+
+	case PIXELFORMAT_RGBA4:
+		f.internalformat = GL_RGBA4;
+		f.externalformat = GL_RGBA;
+		f.type = GL_UNSIGNED_SHORT_4_4_4_4;
+		break;
+	case PIXELFORMAT_RGB5A1:
+		f.internalformat = GL_RGB5_A1;
+		f.externalformat = GL_RGBA;
+		f.type = GL_UNSIGNED_SHORT_5_5_5_1;
+		break;
+	case PIXELFORMAT_RGB565:
+		f.internalformat = GL_RGB565;
+		f.externalformat = GL_RGB;
+		f.type = GL_UNSIGNED_SHORT_5_6_5;
+		break;
+	case PIXELFORMAT_RGB10A2:
+		f.internalformat = GL_RGB10_A2;
+		f.externalformat = GL_RGBA;
+		f.type = GL_UNSIGNED_INT_2_10_10_10_REV;
+		break;
+	case PIXELFORMAT_RG11B10F:
+		f.internalformat = GL_R11F_G11F_B10F;
+		f.externalformat = GL_RGB;
+		f.type = GL_UNSIGNED_INT_10F_11F_11F_REV;
+		break;
+
+	case PIXELFORMAT_DXT1:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_S3TC_DXT1_EXT : GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
+		break;
+	case PIXELFORMAT_DXT3:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT : GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
+		break;
+	case PIXELFORMAT_DXT5:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT : GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
+		break;
+	case PIXELFORMAT_BC4:
+		isSRGB = false;
+		f.internalformat = GL_COMPRESSED_RED_RGTC1;
+		break;
+	case PIXELFORMAT_BC4s:
+		isSRGB = false;
+		f.internalformat = GL_COMPRESSED_SIGNED_RED_RGTC1;
+		break;
+	case PIXELFORMAT_BC5:
+		isSRGB = false;
+		f.internalformat = GL_COMPRESSED_RG_RGTC2;
+		break;
+	case PIXELFORMAT_BC5s:
+		isSRGB = false;
+		f.internalformat = GL_COMPRESSED_SIGNED_RG_RGTC2;
+		break;
+	case PIXELFORMAT_BC6H:
+		isSRGB = false;
+		f.internalformat = GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT;
+		break;
+	case PIXELFORMAT_BC6Hs:
+		isSRGB = false;
+		f.internalformat = GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT;
+		break;
+	case PIXELFORMAT_BC7:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM : GL_COMPRESSED_RGBA_BPTC_UNORM;
+		break;
+	case PIXELFORMAT_PVR1_RGB2:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT : GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
+		break;
+	case PIXELFORMAT_PVR1_RGB4:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT : GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
+		break;
+	case PIXELFORMAT_PVR1_RGBA2:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT : GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
+		break;
+	case PIXELFORMAT_PVR1_RGBA4:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT : GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
+		break;
+	case PIXELFORMAT_ETC1:
+		isSRGB = false;
+		f.internalformat = GL_ETC1_RGB8_OES;
+		break;
+	case PIXELFORMAT_ETC2_RGB:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ETC2 : GL_COMPRESSED_RGB8_ETC2;
+		break;
+	case PIXELFORMAT_ETC2_RGBA:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : GL_COMPRESSED_RGBA8_ETC2_EAC;
+		break;
+	case PIXELFORMAT_ETC2_RGBA1:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 : GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
+		break;
+	case PIXELFORMAT_EAC_R:
+		isSRGB = false;
+		f.internalformat = GL_COMPRESSED_R11_EAC;
+		break;
+	case PIXELFORMAT_EAC_Rs:
+		isSRGB = false;
+		f.internalformat = GL_COMPRESSED_SIGNED_R11_EAC;
+		break;
+	case PIXELFORMAT_EAC_RG:
+		isSRGB = false;
+		f.internalformat = GL_COMPRESSED_RG11_EAC;
+		break;
+	case PIXELFORMAT_EAC_RGs:
+		isSRGB = false;
+		f.internalformat = GL_COMPRESSED_SIGNED_RG11_EAC;
+		break;
+	case PIXELFORMAT_ASTC_4x4:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR : GL_COMPRESSED_RGBA_ASTC_4x4_KHR;
+		break;
+	case PIXELFORMAT_ASTC_5x4:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR : GL_COMPRESSED_RGBA_ASTC_5x4_KHR;
+		break;
+	case PIXELFORMAT_ASTC_5x5:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR : GL_COMPRESSED_RGBA_ASTC_5x5_KHR;
+		break;
+	case PIXELFORMAT_ASTC_6x5:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR : GL_COMPRESSED_RGBA_ASTC_6x5_KHR;
+		break;
+	case PIXELFORMAT_ASTC_6x6:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR : GL_COMPRESSED_RGBA_ASTC_6x6_KHR;
+		break;
+	case PIXELFORMAT_ASTC_8x5:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR : GL_COMPRESSED_RGBA_ASTC_8x5_KHR;
+		break;
+	case PIXELFORMAT_ASTC_8x6:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR : GL_COMPRESSED_RGBA_ASTC_8x6_KHR;
+		break;
+	case PIXELFORMAT_ASTC_8x8:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR : GL_COMPRESSED_RGBA_ASTC_8x8_KHR;
+		break;
+	case PIXELFORMAT_ASTC_10x5:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR : GL_COMPRESSED_RGBA_ASTC_10x5_KHR;
+		break;
+	case PIXELFORMAT_ASTC_10x6:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR : GL_COMPRESSED_RGBA_ASTC_10x6_KHR;
+		break;
+	case PIXELFORMAT_ASTC_10x8:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR : GL_COMPRESSED_RGBA_ASTC_10x8_KHR;
+		break;
+	case PIXELFORMAT_ASTC_10x10:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR : GL_COMPRESSED_RGBA_ASTC_10x10_KHR;
+		break;
+	case PIXELFORMAT_ASTC_12x10:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR : GL_COMPRESSED_RGBA_ASTC_12x10_KHR;
+		break;
+	case PIXELFORMAT_ASTC_12x12:
+		f.internalformat = isSRGB ? GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR : GL_COMPRESSED_RGBA_ASTC_12x12_KHR;
+		break;
+
+	default:
+		printf("Unhandled pixel format when converting to OpenGL enums!");
+		break;
+	}
+
+	if (!isPixelFormatCompressed(pixelformat))
+	{
+		if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0 && !renderbuffer)
+			f.internalformat = f.externalformat;
+
+		if (pixelformat != PIXELFORMAT_sRGBA8)
+			isSRGB = false;
+	}
+
+	return f;
+}
+
+bool OpenGL::isPixelFormatSupported(PixelFormat pixelformat, bool rendertarget, bool isSRGB)
+{
+	if (rendertarget && isPixelFormatCompressed(pixelformat))
+		return false;
+
+	if (pixelformat == PIXELFORMAT_RGBA8 && isSRGB)
+		pixelformat = PIXELFORMAT_sRGBA8;
+
+	switch (pixelformat)
+	{
+	case PIXELFORMAT_R8:
+	case PIXELFORMAT_RG8:
+		return GLAD_VERSION_3_0 || GLAD_ES_VERSION_3_0 || GLAD_ARB_texture_rg || GLAD_EXT_texture_rg;
+	case PIXELFORMAT_RGBA8:
+		if (rendertarget)
+			return GLAD_VERSION_1_0 || GLAD_ES_VERSION_3_0 || GLAD_OES_rgb8_rgba8 || GLAD_ARM_rgba8;
+		else
+			return true;
+	case PIXELFORMAT_sRGBA8:
+		if (rendertarget)
+		{
+			if (GLAD_VERSION_1_0)
+			{
+				return GLAD_VERSION_3_0 || ((GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB)
+					   && (GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB));
+			}
+			else
+				return GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB;
+		}
+		else
+			return GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB || GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB;
+	case PIXELFORMAT_R16:
+	case PIXELFORMAT_RG16:
+		if (rendertarget)
+			return false;
+		else
+			return (GLAD_VERSION_1_1 && GLAD_EXT_texture_rg) || (GLAD_EXT_texture_norm16 && (GLAD_ES_VERSION_3_0 || GLAD_EXT_texture_rg));
+	case PIXELFORMAT_RGBA16:
+		if (rendertarget)
+			return false;
+		else
+			return GLAD_VERSION_1_1 || GLAD_EXT_texture_norm16;
+	case PIXELFORMAT_R16F:
+	case PIXELFORMAT_RG16F:
+		if (GLAD_VERSION_1_0)
+			return GLAD_VERSION_3_0 || (GLAD_ARB_texture_float && GLAD_ARB_half_float_pixel && GLAD_ARB_texture_rg);
+		else if (rendertarget && !GLAD_EXT_color_buffer_half_float)
+			return false;
+		else
+			return GLAD_ES_VERSION_3_0 || (GLAD_OES_texture_half_float && GLAD_EXT_texture_rg);
+	case PIXELFORMAT_RGBA16F:
+		if (GLAD_VERSION_1_0)
+			return GLAD_VERSION_3_0 || (GLAD_ARB_texture_float && GLAD_ARB_half_float_pixel);
+		else if (rendertarget && !GLAD_EXT_color_buffer_half_float)
+			return false;
+		else
+			return GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float;
+	case PIXELFORMAT_R32F:
+	case PIXELFORMAT_RG32F:
+		if (GLAD_VERSION_1_0)
+			return GLAD_VERSION_3_0 || (GLAD_ARB_texture_float && GLAD_ARB_texture_rg);
+		else if (!rendertarget)
+			return GLAD_ES_VERSION_3_0 || (GLAD_OES_texture_float && GLAD_EXT_texture_rg);
+		else
+			return false;
+	case PIXELFORMAT_RGBA32F:
+		if (GLAD_VERSION_1_0)
+			return GLAD_VERSION_3_0 || GLAD_ARB_texture_float;
+		else if (!rendertarget)
+			return GLAD_ES_VERSION_3_0 || GLAD_OES_texture_float;
+		else
+			return false;
+
+	case PIXELFORMAT_RGBA4:
+	case PIXELFORMAT_RGB5A1:
+		return true;
+	case PIXELFORMAT_RGB565:
+		return GLAD_ES_VERSION_2_0 || GLAD_VERSION_4_2 || GLAD_ARB_ES2_compatibility;
+	case PIXELFORMAT_RGB10A2:
+		return GLAD_ES_VERSION_3_0 || GLAD_VERSION_1_0;
+	case PIXELFORMAT_RG11B10F:
+		if (rendertarget)
+			return GLAD_VERSION_3_0 || GLAD_EXT_packed_float || GLAD_APPLE_color_buffer_packed_float;
+		else
+			return GLAD_VERSION_3_0 || GLAD_EXT_packed_float || GLAD_APPLE_texture_packed_float;
+
+	case PIXELFORMAT_DXT1:
+		return GLAD_EXT_texture_compression_s3tc || GLAD_EXT_texture_compression_dxt1;
+	case PIXELFORMAT_DXT3:
+		return GLAD_EXT_texture_compression_s3tc || GLAD_ANGLE_texture_compression_dxt3;
+	case PIXELFORMAT_DXT5:
+		return GLAD_EXT_texture_compression_s3tc || GLAD_ANGLE_texture_compression_dxt5;
+	case PIXELFORMAT_BC4:
+	case PIXELFORMAT_BC4s:
+	case PIXELFORMAT_BC5:
+	case PIXELFORMAT_BC5s:
+		return (GLAD_VERSION_3_0 || GLAD_ARB_texture_compression_rgtc || GLAD_EXT_texture_compression_rgtc);
+	case PIXELFORMAT_BC6H:
+	case PIXELFORMAT_BC6Hs:
+	case PIXELFORMAT_BC7:
+		return GLAD_VERSION_4_2 || GLAD_ARB_texture_compression_bptc;
+	case PIXELFORMAT_PVR1_RGB2:
+	case PIXELFORMAT_PVR1_RGB4:
+	case PIXELFORMAT_PVR1_RGBA2:
+	case PIXELFORMAT_PVR1_RGBA4:
+		return isSRGB ? GLAD_EXT_pvrtc_sRGB : GLAD_IMG_texture_compression_pvrtc;
+	case PIXELFORMAT_ETC1:
+		// ETC2 support guarantees ETC1 support as well.
+		return GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility || GLAD_OES_compressed_ETC1_RGB8_texture;
+	case PIXELFORMAT_ETC2_RGB:
+	case PIXELFORMAT_ETC2_RGBA:
+	case PIXELFORMAT_ETC2_RGBA1:
+	case PIXELFORMAT_EAC_R:
+	case PIXELFORMAT_EAC_Rs:
+	case PIXELFORMAT_EAC_RG:
+	case PIXELFORMAT_EAC_RGs:
+		return GLAD_ES_VERSION_3_0 || GLAD_VERSION_4_3 || GLAD_ARB_ES3_compatibility;
+	case PIXELFORMAT_ASTC_4x4:
+	case PIXELFORMAT_ASTC_5x4:
+	case PIXELFORMAT_ASTC_5x5:
+	case PIXELFORMAT_ASTC_6x5:
+	case PIXELFORMAT_ASTC_6x6:
+	case PIXELFORMAT_ASTC_8x5:
+	case PIXELFORMAT_ASTC_8x6:
+	case PIXELFORMAT_ASTC_8x8:
+	case PIXELFORMAT_ASTC_10x5:
+	case PIXELFORMAT_ASTC_10x6:
+	case PIXELFORMAT_ASTC_10x8:
+	case PIXELFORMAT_ASTC_10x10:
+	case PIXELFORMAT_ASTC_12x10:
+	case PIXELFORMAT_ASTC_12x12:
+		return GLAD_ES_VERSION_3_2 || GLAD_KHR_texture_compression_astc_ldr;
+
+	default:
+		return false;
+	}
+}
+
+bool OpenGL::hasTextureFilteringSupport(PixelFormat pixelformat)
+{
+	switch (pixelformat)
+	{
+	case PIXELFORMAT_RGBA16F:
+		return GLAD_VERSION_1_1 || GLAD_ES_VERSION_3_0 || GLAD_OES_texture_half_float_linear;
+	case PIXELFORMAT_RGBA32F:
+		return GLAD_VERSION_1_1;
+	default:
+		return true;
+	}
+}
+
 const char *OpenGL::errorString(GLenum errorcode)
 {
 	switch (errorcode)

+ 11 - 0
src/modules/graphics/opengl/OpenGL.h

@@ -123,6 +123,13 @@ public:
 		}
 	};
 
+	struct TextureFormat
+	{
+		GLenum internalformat = 0;
+		GLenum externalformat = 0;
+		GLenum type = 0;
+	};
+
 	struct
 	{
 		std::vector<Matrix4> transform;
@@ -427,6 +434,10 @@ public:
 	static GLenum getGLBufferType(BufferType type);
 	static GLint getGLWrapMode(Texture::WrapMode wmode);
 
+	static TextureFormat convertPixelFormat(PixelFormat pixelformat, bool renderbuffer, bool &isSRGB);
+	static bool isPixelFormatSupported(PixelFormat pixelformat, bool rendertarget, bool isSRGB);
+	static bool hasTextureFilteringSupport(PixelFormat pixelformat);
+
 	static const char *errorString(GLenum errorcode);
 	static const char *framebufferStatusString(GLenum status);
 

+ 3 - 3
src/modules/graphics/opengl/wrap_Canvas.cpp

@@ -36,10 +36,10 @@ Canvas *luax_checkcanvas(lua_State *L, int idx)
 int w_Canvas_getFormat(lua_State *L)
 {
 	Canvas *canvas = luax_checkcanvas(L, 1);
-	Canvas::Format format = canvas->getTextureFormat();
+	PixelFormat format = canvas->getPixelFormat();
 	const char *str;
-	if (!Canvas::getConstant(format, str))
-		return luaL_error(L, "Unknown Canvas format.");
+	if (!getConstant(format, str))
+		return luaL_error(L, "Unknown pixel format.");
 
 	lua_pushstring(L, str);
 	return 1;

+ 17 - 44
src/modules/graphics/opengl/wrap_Graphics.cpp

@@ -749,9 +749,9 @@ int w_newCanvas(lua_State *L)
 	const char *str = luaL_optstring(L, 3, "normal");
 	int msaa        = (int) luaL_optnumber(L, 4, 0);
 
-	Canvas::Format format;
-	if (!Canvas::getConstant(str, format))
-		return luaL_error(L, "Invalid Canvas format: %s", str);
+	PixelFormat format;
+	if (!getConstant(str, format))
+		return luaL_error(L, "Invalid pixel format: %s", str);
 
 	Canvas *canvas = nullptr;
 	luax_catchexcept(L,
@@ -1524,64 +1524,38 @@ int w_getSupported(lua_State *L)
 	return 1;
 }
 
-int w_getCanvasFormats(lua_State *L)
+static int w__getFormats(lua_State *L, bool (*isFormatSupported)(PixelFormat), bool (*ignore)(PixelFormat))
 {
-	lua_createtable(L, 0, (int) Canvas::FORMAT_MAX_ENUM);
+	lua_createtable(L, 0, (int) PIXELFORMAT_MAX_ENUM);
 
-	for (int i = 0; i < (int) Canvas::FORMAT_MAX_ENUM; i++)
+	for (int i = 0; i < (int) PIXELFORMAT_MAX_ENUM; i++)
 	{
-		Canvas::Format format = (Canvas::Format) i;
+		PixelFormat format = (PixelFormat) i;
 		const char *name = nullptr;
 
-		if (!Canvas::getConstant(format, name))
+		if (format == PIXELFORMAT_UNKNOWN || !love::getConstant(format, name) || ignore(format))
 			continue;
 
-		luax_pushboolean(L, Canvas::isFormatSupported(format));
+		luax_pushboolean(L, isFormatSupported(format));
 		lua_setfield(L, -2, name);
 	}
 
 	return 1;
 }
 
-int w_getRawImageFormats(lua_State *L)
+int w_getCanvasFormats(lua_State *L)
 {
-	lua_createtable(L, 0, (int) image::ImageData::FORMAT_MAX_ENUM);
-
-	for (int i = 0; i < (int) image::ImageData::FORMAT_MAX_ENUM; i++)
-	{
-		auto format = (image::ImageData::Format) i;
-		const char *name = nullptr;
-
-		if (!image::ImageData::getConstant(format, name))
-			continue;
-
-		luax_pushboolean(L, Image::hasTextureSupport(format));
-		lua_setfield(L, -2, name);
-	}
-
-	return 1;
+	return w__getFormats(L, Canvas::isFormatSupported, isPixelFormatCompressed);
 }
 
-int w_getCompressedImageFormats(lua_State *L)
+int w_getImageFormats(lua_State *L)
 {
-	lua_createtable(L, 0, (int) image::CompressedImageData::FORMAT_MAX_ENUM);
-
-	for (int i = 0; i < (int) image::CompressedImageData::FORMAT_MAX_ENUM; i++)
+	const auto ignore = [](PixelFormat format)
 	{
-		auto format = (image::CompressedImageData::Format) i;
-		const char *name = nullptr;
+		return !(image::ImageData::validPixelFormat(format) || isPixelFormatCompressed(format));
+	};
 
-		if (format == image::CompressedImageData::FORMAT_UNKNOWN)
-			continue;
-
-		if (!image::CompressedImageData::getConstant(format, name))
-			continue;
-
-		luax_pushboolean(L, Image::hasCompressedTextureSupport(format, false));
-		lua_setfield(L, -2, name);
-	}
-
-	return 1;
+	return w__getFormats(L, Image::isFormatSupported, ignore);
 }
 
 int w_getRendererInfo(lua_State *L)
@@ -2214,8 +2188,7 @@ static const luaL_Reg functions[] =
 
 	{ "getSupported", w_getSupported },
 	{ "getCanvasFormats", w_getCanvasFormats },
-	{ "getRawImageFormats", w_getRawImageFormats },
-	{ "getCompressedImageFormats", w_getCompressedImageFormats },
+	{ "getImageFormats", w_getImageFormats },
 	{ "getRendererInfo", w_getRendererInfo },
 	{ "getSystemLimits", w_getSystemLimits },
 	{ "getStats", w_getStats },

+ 2 - 55
src/modules/image/CompressedImageData.cpp

@@ -26,7 +26,7 @@ namespace image
 {
 
 CompressedImageData::CompressedImageData()
-	: format(FORMAT_UNKNOWN)
+	: format(PIXELFORMAT_UNKNOWN)
 	, sRGB(false)
 	, data(nullptr)
 	, dataSize(0)
@@ -80,7 +80,7 @@ int CompressedImageData::getHeight(int miplevel) const
 	return dataImages[miplevel].height;
 }
 
-CompressedImageData::Format CompressedImageData::getFormat() const
+PixelFormat CompressedImageData::getFormat() const
 {
 	return format;
 }
@@ -96,58 +96,5 @@ void CompressedImageData::checkMipmapLevelExists(int miplevel) const
 		throw love::Exception("Mipmap level %d does not exist", miplevel + 1);
 }
 
-bool CompressedImageData::getConstant(const char *in, CompressedImageData::Format &out)
-{
-	return formats.find(in, out);
-}
-
-bool CompressedImageData::getConstant(CompressedImageData::Format in, const char *&out)
-{
-	return formats.find(in, out);
-}
-
-StringMap<CompressedImageData::Format, CompressedImageData::FORMAT_MAX_ENUM>::Entry CompressedImageData::formatEntries[] =
-{
-	{"unknown", FORMAT_UNKNOWN},
-	{"DXT1", FORMAT_DXT1},
-	{"DXT3", FORMAT_DXT3},
-	{"DXT5", FORMAT_DXT5},
-	{"BC4", FORMAT_BC4},
-	{"BC4s", FORMAT_BC4s},
-	{"BC5", FORMAT_BC5},
-	{"BC5s", FORMAT_BC5s},
-	{"BC6h", FORMAT_BC6H},
-	{"BC6hs", FORMAT_BC6Hs},
-	{"BC7", FORMAT_BC7},
-	{"PVR1rgb2", FORMAT_PVR1_RGB2},
-	{"PVR1rgb4", FORMAT_PVR1_RGB4},
-	{"PVR1rgba2", FORMAT_PVR1_RGBA2},
-	{"PVR1rgba4", FORMAT_PVR1_RGBA4},
-	{"ETC1", FORMAT_ETC1},
-	{"ETC2rgb", FORMAT_ETC2_RGB},
-	{"ETC2rgba", FORMAT_ETC2_RGBA},
-	{"ETC2rgba1", FORMAT_ETC2_RGBA1},
-	{"EACr", FORMAT_EAC_R},
-	{"EACrs", FORMAT_EAC_Rs},
-	{"EACrg", FORMAT_EAC_RG},
-	{"EACrgs", FORMAT_EAC_RGs},
-	{"ASTC4x4", FORMAT_ASTC_4x4},
-	{"ASTC5x4", FORMAT_ASTC_5x4},
-	{"ASTC5x5", FORMAT_ASTC_5x5},
-	{"ASTC6x5", FORMAT_ASTC_6x5},
-	{"ASTC6x6", FORMAT_ASTC_6x6},
-	{"ASTC8x5", FORMAT_ASTC_8x5},
-	{"ASTC8x6", FORMAT_ASTC_8x6},
-	{"ASTC8x8", FORMAT_ASTC_8x8},
-	{"ASTC10x5", FORMAT_ASTC_10x5},
-	{"ASTC10x6", FORMAT_ASTC_10x6},
-	{"ASTC10x8", FORMAT_ASTC_10x8},
-	{"ASTC10x10", FORMAT_ASTC_10x10},
-	{"ASTC12x10", FORMAT_ASTC_12x10},
-	{"ASTC12x12", FORMAT_ASTC_12x12},
-};
-
-StringMap<CompressedImageData::Format, CompressedImageData::FORMAT_MAX_ENUM> CompressedImageData::formats(CompressedImageData::formatEntries, sizeof(CompressedImageData::formatEntries));
-
 } // image
 } // love

+ 3 - 53
src/modules/image/CompressedImageData.h

@@ -25,6 +25,7 @@
 #include "common/Data.h"
 #include "common/StringMap.h"
 #include "common/int.h"
+#include "common/pixelformat.h"
 
 // STL
 #include <vector>
@@ -43,49 +44,6 @@ class CompressedImageData : public Data
 {
 public:
 
-	// Recognized compressed image data formats.
-	enum Format
-	{
-		FORMAT_UNKNOWN,
-		FORMAT_DXT1,
-		FORMAT_DXT3,
-		FORMAT_DXT5,
-		FORMAT_BC4,
-		FORMAT_BC4s,
-		FORMAT_BC5,
-		FORMAT_BC5s,
-		FORMAT_BC6H,
-		FORMAT_BC6Hs,
-		FORMAT_BC7,
-		FORMAT_PVR1_RGB2,
-		FORMAT_PVR1_RGB4,
-		FORMAT_PVR1_RGBA2,
-		FORMAT_PVR1_RGBA4,
-		FORMAT_ETC1,
-		FORMAT_ETC2_RGB,
-		FORMAT_ETC2_RGBA,
-		FORMAT_ETC2_RGBA1,
-		FORMAT_EAC_R,
-		FORMAT_EAC_Rs,
-		FORMAT_EAC_RG,
-		FORMAT_EAC_RGs,
-		FORMAT_ASTC_4x4,
-		FORMAT_ASTC_5x4,
-		FORMAT_ASTC_5x5,
-		FORMAT_ASTC_6x5,
-		FORMAT_ASTC_6x6,
-		FORMAT_ASTC_8x5,
-		FORMAT_ASTC_8x6,
-		FORMAT_ASTC_8x8,
-		FORMAT_ASTC_10x5,
-		FORMAT_ASTC_10x6,
-		FORMAT_ASTC_10x8,
-		FORMAT_ASTC_10x10,
-		FORMAT_ASTC_12x10,
-		FORMAT_ASTC_12x12,
-		FORMAT_MAX_ENUM
-	};
-
 	// Compressed image data can have multiple mipmap levels, each represented
 	// by a sub-image.
 	struct SubImage
@@ -131,16 +89,13 @@ public:
 	/**
 	 * Gets the format of the compressed data.
 	 **/
-	Format getFormat() const;
+	PixelFormat getFormat() const;
 
 	bool isSRGB() const;
 
-	static bool getConstant(const char *in, Format &out);
-	static bool getConstant(Format in, const char *&out);
-
 protected:
 
-	Format format;
+	PixelFormat format;
 
 	bool sRGB;
 
@@ -153,11 +108,6 @@ protected:
 
 	void checkMipmapLevelExists(int miplevel) const;
 
-private:
-
-	static StringMap<Format, FORMAT_MAX_ENUM>::Entry formatEntries[];
-	static StringMap<Format, FORMAT_MAX_ENUM> formats;
-
 }; // CompressedImageData
 
 } // image

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

@@ -62,7 +62,7 @@ public:
 	 * @param height The height of the ImageData.
 	 * @return The new ImageData.
 	 **/
-	virtual ImageData *newImageData(int width, int height, ImageData::Format format = ImageData::FORMAT_RGBA8) = 0;
+	virtual ImageData *newImageData(int width, int height, PixelFormat format = PIXELFORMAT_RGBA8) = 0;
 
 	/**
 	 * Creates empty ImageData with the given size.
@@ -73,7 +73,7 @@ public:
 	 *        copy it.
 	 * @return The new ImageData.
 	 **/
-	virtual ImageData *newImageData(int width, int height, ImageData::Format format, void *data, bool own = false) = 0;
+	virtual ImageData *newImageData(int width, int height, PixelFormat format, void *data, bool own = false) = 0;
 
 	/**
 	 * Creates new CompressedImageData from FileData.

+ 13 - 33
src/modules/image/ImageData.cpp

@@ -28,7 +28,10 @@ namespace image
 {
 
 ImageData::ImageData()
-	: data(nullptr)
+	: format(PIXELFORMAT_UNKNOWN)
+	, width(0)
+	, height(0)
+	, data(nullptr)
 {
 }
 
@@ -51,7 +54,7 @@ bool ImageData::inside(int x, int y) const
 	return x >= 0 && x < getWidth() && y >= 0 && y < getHeight();
 }
 
-ImageData::Format ImageData::getFormat() const
+PixelFormat ImageData::getFormat() const
 {
 	return format;
 }
@@ -166,35 +169,23 @@ love::thread::Mutex *ImageData::getMutex() const
 
 size_t ImageData::getPixelSize() const
 {
-	return getPixelSize(format);
+	return getPixelFormatSize(format);
 }
 
-size_t ImageData::getPixelSize(Format format)
+bool ImageData::validPixelFormat(PixelFormat format)
 {
 	switch (format)
 	{
-	case FORMAT_RGBA8:
-		return 4;
-	case FORMAT_RGBA16:
-	case FORMAT_RGBA16F:
-		return 8;
-	case FORMAT_RGBA32F:
-		return 16;
+	case PIXELFORMAT_RGBA8:
+	case PIXELFORMAT_RGBA16:
+	case PIXELFORMAT_RGBA16F:
+	case PIXELFORMAT_RGBA32F:
+		return true;
 	default:
-		return 0;
+		return false;
 	}
 }
 
-bool ImageData::getConstant(const char *in, Format &out)
-{
-	return formats.find(in, out);
-}
-
-bool ImageData::getConstant(Format in, const char *&out)
-{
-	return formats.find(in, out);
-}
-
 bool ImageData::getConstant(const char *in, EncodedFormat &out)
 {
 	return encodedFormats.find(in, out);
@@ -205,17 +196,6 @@ bool ImageData::getConstant(EncodedFormat in, const char *&out)
 	return encodedFormats.find(in, out);
 }
 
-StringMap<ImageData::Format, ImageData::FORMAT_MAX_ENUM>::Entry ImageData::formatEntries[] =
-{
-	{"rgba8",   FORMAT_RGBA8  },
-	{"rgba16",  FORMAT_RGBA16 },
-	{"rgba16f", FORMAT_RGBA16F},
-	{"rgba32f", FORMAT_RGBA32F},
-};
-
-StringMap<ImageData::Format, ImageData::FORMAT_MAX_ENUM> ImageData::formats(ImageData::formatEntries, sizeof(ImageData::formatEntries));
-
-
 StringMap<ImageData::EncodedFormat, ImageData::ENCODED_MAX_ENUM>::Entry ImageData::encodedFormatEntries[] =
 {
 	{"tga", ENCODED_TGA},

+ 4 - 18
src/modules/image/ImageData.h

@@ -25,6 +25,7 @@
 #include "common/Data.h"
 #include "common/StringMap.h"
 #include "common/int.h"
+#include "common/pixelformat.h"
 #include "common/halffloat.h"
 #include "filesystem/FileData.h"
 #include "thread/threads.h"
@@ -58,15 +59,6 @@ class ImageData : public Data
 {
 public:
 
-	enum Format
-	{
-		FORMAT_RGBA8,
-		FORMAT_RGBA16,
-		FORMAT_RGBA16F,
-		FORMAT_RGBA32F,
-		FORMAT_MAX_ENUM
-	};
-
 	enum EncodedFormat
 	{
 		ENCODED_TGA,
@@ -77,7 +69,7 @@ public:
 	ImageData();
 	virtual ~ImageData();
 
-	Format getFormat() const;
+	PixelFormat getFormat() const;
 
 	/**
 	 * Paste part of one ImageData onto another. The subregion defined by the top-left
@@ -139,17 +131,14 @@ public:
 
 	size_t getPixelSize() const;
 
-	static size_t getPixelSize(Format format);
-
-	static bool getConstant(const char *in, Format &out);
-	static bool getConstant(Format in, const char *&out);
+	static bool validPixelFormat(PixelFormat format);
 
 	static bool getConstant(const char *in, EncodedFormat &out);
 	static bool getConstant(EncodedFormat in, const char *&out);
 
 protected:
 
-	Format format;
+	PixelFormat format;
 
 	// The width of the image data.
 	int width;
@@ -167,9 +156,6 @@ protected:
 
 private:
 
-	static StringMap<Format, FORMAT_MAX_ENUM>::Entry formatEntries[];
-	static StringMap<Format, FORMAT_MAX_ENUM> formats;
-
 	static StringMap<EncodedFormat, ENCODED_MAX_ENUM>::Entry encodedFormatEntries[];
 	static StringMap<EncodedFormat, ENCODED_MAX_ENUM> encodedFormats;
 

+ 20 - 20
src/modules/image/magpie/ASTCHandler.cpp

@@ -47,41 +47,41 @@ struct ASTCHeader
 };
 #pragma pack(pop)
 
-static CompressedImageData::Format convertFormat(uint32 blockX, uint32 blockY, uint32 blockZ)
+static PixelFormat convertFormat(uint32 blockX, uint32 blockY, uint32 blockZ)
 {
 	if (blockZ > 1)
-		return CompressedImageData::FORMAT_UNKNOWN;
+		return PIXELFORMAT_UNKNOWN;
 
 	if (blockX == 4 && blockY == 4)
-		return CompressedImageData::FORMAT_ASTC_4x4;
+		return PIXELFORMAT_ASTC_4x4;
 	else if (blockX == 5 && blockY == 4)
-		return CompressedImageData::FORMAT_ASTC_5x4;
+		return PIXELFORMAT_ASTC_5x4;
 	else if (blockX == 5 && blockY == 5)
-		return CompressedImageData::FORMAT_ASTC_5x5;
+		return PIXELFORMAT_ASTC_5x5;
 	else if (blockX == 6 && blockY == 5)
-		return CompressedImageData::FORMAT_ASTC_6x5;
+		return PIXELFORMAT_ASTC_6x5;
 	else if (blockX == 6 && blockY == 6)
-		return CompressedImageData::FORMAT_ASTC_6x6;
+		return PIXELFORMAT_ASTC_6x6;
 	else if (blockX == 8 && blockY == 5)
-		return CompressedImageData::FORMAT_ASTC_8x5;
+		return PIXELFORMAT_ASTC_8x5;
 	else if (blockX == 8 && blockY == 6)
-		return CompressedImageData::FORMAT_ASTC_8x6;
+		return PIXELFORMAT_ASTC_8x6;
 	else if (blockX == 8 && blockY == 8)
-		return CompressedImageData::FORMAT_ASTC_8x8;
+		return PIXELFORMAT_ASTC_8x8;
 	else if (blockX == 10 && blockY == 5)
-		return CompressedImageData::FORMAT_ASTC_10x5;
+		return PIXELFORMAT_ASTC_10x5;
 	else if (blockX == 10 && blockY == 6)
-		return CompressedImageData::FORMAT_ASTC_10x6;
+		return PIXELFORMAT_ASTC_10x6;
 	else if (blockX == 10 && blockY == 8)
-		return CompressedImageData::FORMAT_ASTC_10x8;
+		return PIXELFORMAT_ASTC_10x8;
 	else if (blockX == 10 && blockY == 10)
-		return CompressedImageData::FORMAT_ASTC_10x10;
+		return PIXELFORMAT_ASTC_10x10;
 	else if (blockX == 12 && blockY == 10)
-		return CompressedImageData::FORMAT_ASTC_12x10;
+		return PIXELFORMAT_ASTC_12x10;
 	else if (blockX == 12 && blockY == 12)
-		return CompressedImageData::FORMAT_ASTC_12x12;
+		return PIXELFORMAT_ASTC_12x12;
 
-	return CompressedImageData::FORMAT_UNKNOWN;
+	return PIXELFORMAT_UNKNOWN;
 }
 
 } // Anonymous namespace.
@@ -104,16 +104,16 @@ bool ASTCHandler::canParse(const filesystem::FileData *data)
 	return true;
 }
 
-uint8 *ASTCHandler::parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, CompressedImageData::Format &format, bool &sRGB)
+uint8 *ASTCHandler::parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB)
 {
 	if (!canParse(filedata))
 		throw love::Exception("Could not decode compressed data (not an .astc file?)");
 
 	ASTCHeader header = *(const ASTCHeader *) filedata->getData();
 
-	CompressedImageData::Format cformat = convertFormat(header.blockdimX, header.blockdimY, header.blockdimZ);
+	PixelFormat cformat = convertFormat(header.blockdimX, header.blockdimY, header.blockdimZ);
 
-	if (cformat == CompressedImageData::FORMAT_UNKNOWN)
+	if (cformat == PIXELFORMAT_UNKNOWN)
 		throw love::Exception("Could not parse .astc file: unsupported ASTC format %dx%dx%d.", header.blockdimX, header.blockdimY, header.blockdimZ);
 
 	uint32 sizeX = header.sizeX[0] + (header.sizeX[1] << 8) + (header.sizeX[2] << 16);

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

@@ -43,7 +43,7 @@ public:
 
 	// Implements CompressedFormatHandler.
 	virtual bool canParse(const filesystem::FileData *data);
-	virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, CompressedImageData::Format &format, bool &sRGB);
+	virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB);
 
 }; // ASTCHandler
 

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

@@ -65,7 +65,7 @@ public:
 	 * @return The single block of memory containing the parsed images.
 	 **/
 	virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images,
-	                     size_t &dataSize, CompressedImageData::Format &format, bool &sRGB) = 0;
+	                     size_t &dataSize, PixelFormat &format, bool &sRGB) = 0;
 
 }; // CompressedFormatHandler
 

+ 1 - 1
src/modules/image/magpie/CompressedImageData.cpp

@@ -48,7 +48,7 @@ CompressedImageData::CompressedImageData(std::list<CompressedFormatHandler *> fo
 	if (data == nullptr)
 		throw love::Exception("Could not parse compressed data.");
 
-	if (format == FORMAT_UNKNOWN)
+	if (format == PIXELFORMAT_UNKNOWN)
 	{
 		delete[] data;
 		throw love::Exception("Could not parse compressed data: Unknown format.");

+ 4 - 4
src/modules/image/magpie/EXRHandler.cpp

@@ -41,7 +41,7 @@ bool EXRHandler::canDecode(love::filesystem::FileData *data)
 	return ParseEXRVersionFromMemory(&version, (const unsigned char *) data->getData(), data->getSize()) == TINYEXR_SUCCESS;
 }
 
-bool EXRHandler::canEncode(ImageData::Format /*rawFormat*/, ImageData::EncodedFormat /*encodedFormat*/)
+bool EXRHandler::canEncode(PixelFormat /*rawFormat*/, ImageData::EncodedFormat /*encodedFormat*/)
 {
 	return false;
 }
@@ -141,7 +141,7 @@ FormatHandler::DecodedImage EXRHandler::decode(love::filesystem::FileData *data)
 
 	if (pixelType == TINYEXR_PIXELTYPE_HALF)
 	{
-		img.format = ImageData::FORMAT_RGBA16F;
+		img.format = PIXELFORMAT_RGBA16F;
 
 		half *rgba[4] = {nullptr};
 		getEXRChannels(exrHeader, exrImage, rgba);
@@ -158,7 +158,7 @@ FormatHandler::DecodedImage EXRHandler::decode(love::filesystem::FileData *data)
 	}
 	else if (pixelType == TINYEXR_PIXELTYPE_FLOAT)
 	{
-		img.format = ImageData::FORMAT_RGBA32F;
+		img.format = PIXELFORMAT_RGBA32F;
 
 		float *rgba[4] = {nullptr};
 		getEXRChannels(exrHeader, exrImage, rgba);
@@ -179,7 +179,7 @@ FormatHandler::DecodedImage EXRHandler::decode(love::filesystem::FileData *data)
 		throw love::Exception("Could not decode EXR image: unknown pixel format.");
 	}
 
-	img.size = img.width * img.height * ImageData::getPixelSize(img.format);
+	img.size = img.width * img.height * getPixelFormatSize(img.format);
 
 	FreeEXRImage(&exrImage);
 

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

@@ -40,7 +40,7 @@ public:
 	// Implements FormatHandler.
 
 	virtual bool canDecode(love::filesystem::FileData *data);
-	virtual bool canEncode(ImageData::Format rawFormat, ImageData::EncodedFormat encodedFormat);
+	virtual bool canEncode(PixelFormat rawFormat, ImageData::EncodedFormat encodedFormat);
 
 	virtual DecodedImage decode(love::filesystem::FileData *data);
 	virtual EncodedImage encode(const DecodedImage &img, ImageData::EncodedFormat format);

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

@@ -42,7 +42,7 @@ bool FormatHandler::canDecode(love::filesystem::FileData* /*data*/)
 	return false;
 }
 
-bool FormatHandler::canEncode(ImageData::Format /*rawFormat*/, ImageData::EncodedFormat /*encodedFormat*/)
+bool FormatHandler::canEncode(PixelFormat /*rawFormat*/, ImageData::EncodedFormat /*encodedFormat*/)
 {
 	return false;
 }

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

@@ -44,7 +44,7 @@ public:
 	// Raw RGBA pixel data.
 	struct DecodedImage
 	{
-		ImageData::Format format = ImageData::FORMAT_RGBA8;
+		PixelFormat format = PIXELFORMAT_RGBA8;
 		int width   = 0;
 		int height  = 0;
 		size_t size = 0;
@@ -76,7 +76,7 @@ public:
 	/**
 	 * Whether this format handler can encode to a particular format.
 	 **/
-	virtual bool canEncode(ImageData::Format rawFormat, ImageData::EncodedFormat encodedFormat);
+	virtual bool canEncode(PixelFormat rawFormat, ImageData::EncodedFormat encodedFormat);
 
 	/**
 	 * Decodes an image from its encoded form into raw pixel data.

+ 2 - 2
src/modules/image/magpie/Image.cpp

@@ -82,12 +82,12 @@ love::image::ImageData *Image::newImageData(love::filesystem::FileData *data)
 	return new ImageData(formatHandlers, data);
 }
 
-love::image::ImageData *Image::newImageData(int width, int height, ImageData::Format format)
+love::image::ImageData *Image::newImageData(int width, int height, PixelFormat format)
 {
 	return new ImageData(formatHandlers, width, height, format);
 }
 
-love::image::ImageData *Image::newImageData(int width, int height, ImageData::Format format, void *data, bool own)
+love::image::ImageData *Image::newImageData(int width, int height, PixelFormat format, void *data, bool own)
 {
 	return new ImageData(formatHandlers, width, height, format, data, own);
 }

+ 2 - 2
src/modules/image/magpie/Image.h

@@ -52,8 +52,8 @@ public:
 	const char *getName() const;
 
 	love::image::ImageData *newImageData(love::filesystem::FileData *data);
-	love::image::ImageData *newImageData(int width, int height, ImageData::Format format = ImageData::FORMAT_RGBA8);
-	love::image::ImageData *newImageData(int width, int height, ImageData::Format format, void *data, bool own = false);
+	love::image::ImageData *newImageData(int width, int height, PixelFormat format = PIXELFORMAT_RGBA8);
+	love::image::ImageData *newImageData(int width, int height, PixelFormat format, void *data, bool own = false);
 
 	love::image::CompressedImageData *newCompressedData(love::filesystem::FileData *data);
 

+ 16 - 10
src/modules/image/magpie/ImageData.cpp

@@ -38,12 +38,12 @@ ImageData::ImageData(std::list<FormatHandler *> formatHandlers, love::filesystem
 	decode(data);
 }
 
-ImageData::ImageData(std::list<FormatHandler *> formatHandlers, int width, int height, Format format)
+ImageData::ImageData(std::list<FormatHandler *> formatHandlers, int width, int height, PixelFormat format)
 	: formatHandlers(formatHandlers)
 	, decodeHandler(nullptr)
 {
-	for (FormatHandler *handler : formatHandlers)
-		handler->retain();
+	if (!validPixelFormat(format))
+		throw love::Exception("Unsupported pixel format for ImageData");
 
 	this->width = width;
 	this->height = height;
@@ -53,14 +53,17 @@ ImageData::ImageData(std::list<FormatHandler *> formatHandlers, int width, int h
 
 	// Set to black/transparency.
 	memset(data, 0, getSize());
+
+	for (FormatHandler *handler : formatHandlers)
+		handler->retain();
 }
 
-ImageData::ImageData(std::list<FormatHandler *> formatHandlers, int width, int height, Format format, void *data, bool own)
+ImageData::ImageData(std::list<FormatHandler *> formatHandlers, int width, int height, PixelFormat format, void *data, bool own)
 	: formatHandlers(formatHandlers)
 	, decodeHandler(nullptr)
 {
-	for (FormatHandler *handler : formatHandlers)
-		handler->retain();
+	if (!validPixelFormat(format))
+		throw love::Exception("Unsupported pixel format for ImageData");
 
 	this->width = width;
 	this->height = height;
@@ -70,6 +73,9 @@ ImageData::ImageData(std::list<FormatHandler *> formatHandlers, int width, int h
 		this->data = (unsigned char *) data;
 	else
 		create(width, height, format, data);
+
+	for (FormatHandler *handler : formatHandlers)
+		handler->retain();
 }
 
 ImageData::~ImageData()
@@ -83,9 +89,9 @@ ImageData::~ImageData()
 		handler->release();
 }
 
-void ImageData::create(int width, int height, Format format, void *data)
+void ImageData::create(int width, int height, PixelFormat format, void *data)
 {
-	size_t datasize = width * height * getPixelSize(format);
+	size_t datasize = width * height * getPixelFormatSize(format);
 
 	try
 	{
@@ -126,7 +132,7 @@ void ImageData::decode(love::filesystem::FileData *data)
 		throw love::Exception("Could not decode file '%s' to ImageData: unsupported file format", name.c_str());
 	}
 
-	if (decodedimage.size != decodedimage.width * decodedimage.height * getPixelSize(decodedimage.format))
+	if (decodedimage.size != decodedimage.width * decodedimage.height * getPixelFormatSize(decodedimage.format))
 	{
 		decoder->free(decodedimage.data);
 		throw love::Exception("Could not convert image!");
@@ -176,7 +182,7 @@ love::filesystem::FileData *ImageData::encode(EncodedFormat encodedFormat, const
 	if (encoder == nullptr || encodedimage.data == nullptr)
 	{
 		const char *fname = "unknown";
-		getConstant(format, fname);
+		love::getConstant(format, fname);
 		throw love::Exception("No suitable image encoder for %s format.", fname);
 	}
 

+ 3 - 3
src/modules/image/magpie/ImageData.h

@@ -40,8 +40,8 @@ class ImageData : public love::image::ImageData
 public:
 
 	ImageData(std::list<FormatHandler *> formatHandlers, love::filesystem::FileData *data);
-	ImageData(std::list<FormatHandler *> formatHandlers, int width, int height, Format format = FORMAT_RGBA8);
-	ImageData(std::list<FormatHandler *> formatHandlers, int width, int height, Format format, void *data, bool own);
+	ImageData(std::list<FormatHandler *> formatHandlers, int width, int height, PixelFormat format = PIXELFORMAT_RGBA8);
+	ImageData(std::list<FormatHandler *> formatHandlers, int width, int height, PixelFormat format, void *data, bool own);
 	virtual ~ImageData();
 
 	// Implements image::ImageData.
@@ -50,7 +50,7 @@ public:
 private:
 
 	// Create imagedata. Initialize with data if not null.
-	void create(int width, int height, Format format, void *data = nullptr);
+	void create(int width, int height, PixelFormat format, void *data = nullptr);
 
 	// Decode and load an encoded format.
 	void decode(love::filesystem::FileData *data);

+ 44 - 44
src/modules/image/magpie/KTXHandler.cpp

@@ -136,7 +136,7 @@ enum KTXGLInternalFormat
 	KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD
 };
 
-CompressedImageData::Format convertFormat(uint32 glformat, bool &sRGB)
+PixelFormat convertFormat(uint32 glformat, bool &sRGB)
 {
 	sRGB = false;
 
@@ -145,136 +145,136 @@ CompressedImageData::Format convertFormat(uint32 glformat, bool &sRGB)
 	switch (glformat)
 	{
 	case KTX_GL_ETC1_RGB8_OES:
-		return CompressedImageData::FORMAT_ETC1;
+		return PIXELFORMAT_ETC1;
 
 	// EAC and ETC2.
 	case KTX_GL_COMPRESSED_R11_EAC:
-		return CompressedImageData::FORMAT_EAC_R;
+		return PIXELFORMAT_EAC_R;
 	case KTX_GL_COMPRESSED_SIGNED_R11_EAC:
-		return CompressedImageData::FORMAT_EAC_Rs;
+		return PIXELFORMAT_EAC_Rs;
 	case KTX_GL_COMPRESSED_RG11_EAC:
-		return CompressedImageData::FORMAT_EAC_RG;
+		return PIXELFORMAT_EAC_RG;
 	case KTX_GL_COMPRESSED_SIGNED_RG11_EAC:
-		return CompressedImageData::FORMAT_EAC_RGs;
+		return PIXELFORMAT_EAC_RGs;
 	case KTX_GL_COMPRESSED_RGB8_ETC2:
-		return CompressedImageData::FORMAT_ETC2_RGB;
+		return PIXELFORMAT_ETC2_RGB;
 	case KTX_GL_COMPRESSED_SRGB8_ETC2:
 		sRGB = true;
-		return CompressedImageData::FORMAT_ETC2_RGB;
+		return PIXELFORMAT_ETC2_RGB;
 	case KTX_GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
-		return CompressedImageData::FORMAT_ETC2_RGBA1;
+		return PIXELFORMAT_ETC2_RGBA1;
 	case KTX_GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
 		sRGB = true;
-		return CompressedImageData::FORMAT_ETC2_RGBA1;
+		return PIXELFORMAT_ETC2_RGBA1;
 	case KTX_GL_COMPRESSED_RGBA8_ETC2_EAC:
-		return CompressedImageData::FORMAT_ETC2_RGBA;
+		return PIXELFORMAT_ETC2_RGBA;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
 		sRGB = true;
-		return CompressedImageData::FORMAT_ETC2_RGBA;
+		return PIXELFORMAT_ETC2_RGBA;
 
 	// PVRTC.
 	case KTX_GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG:
-		return CompressedImageData::FORMAT_PVR1_RGB4;
+		return PIXELFORMAT_PVR1_RGB4;
 	case KTX_GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG:
-		return CompressedImageData::FORMAT_PVR1_RGB2;
+		return PIXELFORMAT_PVR1_RGB2;
 	case KTX_GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG:
-		return CompressedImageData::FORMAT_PVR1_RGBA4;
+		return PIXELFORMAT_PVR1_RGBA4;
 	case KTX_GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG:
-		return CompressedImageData::FORMAT_PVR1_RGBA2;
+		return PIXELFORMAT_PVR1_RGBA2;
 
 	// DXT.
 	case KTX_GL_COMPRESSED_SRGB_S3TC_DXT1_EXT:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGB_S3TC_DXT1_EXT:
-		return CompressedImageData::FORMAT_DXT1;
+		return PIXELFORMAT_DXT1;
 	case KTX_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
-		return CompressedImageData::FORMAT_DXT3;
+		return PIXELFORMAT_DXT3;
 	case KTX_GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
-		return CompressedImageData::FORMAT_DXT5;
+		return PIXELFORMAT_DXT5;
 
 	// BC4 and BC5.
 	case KTX_GL_COMPRESSED_RED_RGTC1:
-		return CompressedImageData::FORMAT_BC4;
+		return PIXELFORMAT_BC4;
 	case KTX_GL_COMPRESSED_SIGNED_RED_RGTC1:
-		return CompressedImageData::FORMAT_BC4s;
+		return PIXELFORMAT_BC4s;
 	case KTX_GL_COMPRESSED_RG_RGTC2:
-		return CompressedImageData::FORMAT_BC5;
+		return PIXELFORMAT_BC5;
 	case KTX_GL_COMPRESSED_SIGNED_RG_RGTC2:
-		return CompressedImageData::FORMAT_BC5s;
+		return PIXELFORMAT_BC5s;
 
 	// BC6 and BC7.
 	case KTX_GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_BPTC_UNORM:
-		return CompressedImageData::FORMAT_BC7;
+		return PIXELFORMAT_BC7;
 	case KTX_GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT:
-		return CompressedImageData::FORMAT_BC6Hs;
+		return PIXELFORMAT_BC6Hs;
 	case KTX_GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT:
-		return CompressedImageData::FORMAT_BC6H;
+		return PIXELFORMAT_BC6H;
 
 	// ASTC.
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_4x4_KHR:
-		return CompressedImageData::FORMAT_ASTC_4x4;
+		return PIXELFORMAT_ASTC_4x4;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_5x4_KHR:
-		return CompressedImageData::FORMAT_ASTC_5x4;
+		return PIXELFORMAT_ASTC_5x4;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_5x5_KHR:
-		return CompressedImageData::FORMAT_ASTC_5x5;
+		return PIXELFORMAT_ASTC_5x5;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_6x5_KHR:
-		return CompressedImageData::FORMAT_ASTC_6x5;
+		return PIXELFORMAT_ASTC_6x5;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_6x6_KHR:
-		return CompressedImageData::FORMAT_ASTC_6x6;
+		return PIXELFORMAT_ASTC_6x6;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_8x5_KHR:
-		return CompressedImageData::FORMAT_ASTC_8x5;
+		return PIXELFORMAT_ASTC_8x5;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_8x6_KHR:
-		return CompressedImageData::FORMAT_ASTC_8x6;
+		return PIXELFORMAT_ASTC_8x6;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_8x8_KHR:
-		return CompressedImageData::FORMAT_ASTC_8x8;
+		return PIXELFORMAT_ASTC_8x8;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_10x5_KHR:
-		return CompressedImageData::FORMAT_ASTC_10x5;
+		return PIXELFORMAT_ASTC_10x5;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_10x6_KHR:
-		return CompressedImageData::FORMAT_ASTC_10x6;
+		return PIXELFORMAT_ASTC_10x6;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_10x8_KHR:
-		return CompressedImageData::FORMAT_ASTC_10x8;
+		return PIXELFORMAT_ASTC_10x8;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_10x10_KHR:
-		return CompressedImageData::FORMAT_ASTC_10x10;
+		return PIXELFORMAT_ASTC_10x10;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_12x10_KHR:
-		return CompressedImageData::FORMAT_ASTC_12x10;
+		return PIXELFORMAT_ASTC_12x10;
 	case KTX_GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR:
 		sRGB = true;
 	case KTX_GL_COMPRESSED_RGBA_ASTC_12x12_KHR:
-		return CompressedImageData::FORMAT_ASTC_12x12;
+		return PIXELFORMAT_ASTC_12x12;
 	default:
-		return CompressedImageData::FORMAT_UNKNOWN;
+		return PIXELFORMAT_UNKNOWN;
 	}
 }
 
@@ -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, CompressedImageData::Format &format, bool &sRGB)
+uint8 *KTXHandler::parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB)
 {
 	if (!canParse(filedata))
 		throw love::Exception("Could not decode compressed data (not a KTX file?)");
@@ -314,9 +314,9 @@ uint8 *KTXHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
 	header.numberOfMipmapLevels = std::max(header.numberOfMipmapLevels, 1u);
 
 	bool isSRGB = false;
-	CompressedImageData::Format cformat = convertFormat(header.glInternalFormat, isSRGB);
+	PixelFormat cformat = convertFormat(header.glInternalFormat, isSRGB);
 
-	if (cformat == CompressedImageData::FORMAT_UNKNOWN)
+	if (cformat == PIXELFORMAT_UNKNOWN)
 		throw love::Exception("Unsupported image format in KTX file.");
 
 	if (header.numberOfArrayElements > 0)

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

@@ -42,7 +42,7 @@ public:
 
 	// Implements CompressedFormatHandler.
 	virtual bool canParse(const filesystem::FileData *data);
-	virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, CompressedImageData::Format &format, bool &sRGB);
+	virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB);
 
 }; // KTXHandler
 

+ 13 - 13
src/modules/image/magpie/PKMHandler.cpp

@@ -68,29 +68,29 @@ enum PKMTextureFormat
 	ETC2PACKAGE_RG_SIGNED_NO_MIPMAPS
 };
 
-static CompressedImageData::Format convertFormat(uint16 texformat)
+static PixelFormat convertFormat(uint16 texformat)
 {
 	switch (texformat)
 	{
 	case ETC1_RGB_NO_MIPMAPS:
-		return CompressedImageData::FORMAT_ETC1;
+		return PIXELFORMAT_ETC1;
 	case ETC2PACKAGE_RGB_NO_MIPMAPS:
-		return CompressedImageData::FORMAT_ETC2_RGB;
+		return PIXELFORMAT_ETC2_RGB;
 	case ETC2PACKAGE_RGBA_NO_MIPMAPS_OLD:
 	case ETC2PACKAGE_RGBA_NO_MIPMAPS:
-		return CompressedImageData::FORMAT_ETC2_RGBA;
+		return PIXELFORMAT_ETC2_RGBA;
 	case ETC2PACKAGE_RGBA1_NO_MIPMAPS:
-		return CompressedImageData::FORMAT_ETC2_RGBA1;
+		return PIXELFORMAT_ETC2_RGBA1;
 	case ETC2PACKAGE_R_NO_MIPMAPS:
-		return CompressedImageData::FORMAT_EAC_R;
+		return PIXELFORMAT_EAC_R;
 	case ETC2PACKAGE_RG_NO_MIPMAPS:
-		return CompressedImageData::FORMAT_EAC_RG;
+		return PIXELFORMAT_EAC_RG;
 	case ETC2PACKAGE_R_SIGNED_NO_MIPMAPS:
-		return CompressedImageData::FORMAT_EAC_Rs;
+		return PIXELFORMAT_EAC_Rs;
 	case ETC2PACKAGE_RG_SIGNED_NO_MIPMAPS:
-		return CompressedImageData::FORMAT_EAC_RGs;
+		return PIXELFORMAT_EAC_RGs;
 	default:
-		return CompressedImageData::FORMAT_UNKNOWN;
+		return PIXELFORMAT_UNKNOWN;
 	}
 }
 
@@ -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, CompressedImageData::Format &format, bool &sRGB)
+uint8 *PKMHandler::parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB)
 {
 	if (!canParse(filedata))
 		throw love::Exception("Could not decode compressed data (not a PKM file?)");
@@ -126,9 +126,9 @@ uint8 *PKMHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
 	header.widthBig = swap16big(header.widthBig);
 	header.heightBig = swap16big(header.heightBig);
 
-	CompressedImageData::Format cformat = convertFormat(header.textureFormatBig);
+	PixelFormat cformat = convertFormat(header.textureFormatBig);
 
-	if (cformat == CompressedImageData::FORMAT_UNKNOWN)
+	if (cformat == PIXELFORMAT_UNKNOWN)
 		throw love::Exception("Could not parse PKM file: unsupported texture format.");
 
 	// The rest of the file after the header is all texture data.

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

@@ -42,7 +42,7 @@ public:
 
 	// Implements CompressedFormatHandler.
 	virtual bool canParse(const filesystem::FileData *data);
-	virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, CompressedImageData::Format &format, bool &sRGB);
+	virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB);
 
 }; // PKMHandler
 

+ 4 - 4
src/modules/image/magpie/PNGHandler.cpp

@@ -140,10 +140,10 @@ bool PNGHandler::canDecode(love::filesystem::FileData *data)
 	return status == 0 && width > 0 && height > 0;
 }
 
-bool PNGHandler::canEncode(ImageData::Format rawFormat, ImageData::EncodedFormat encodedFormat)
+bool PNGHandler::canEncode(PixelFormat rawFormat, ImageData::EncodedFormat encodedFormat)
 {
 	return encodedFormat == ImageData::ENCODED_PNG
-		&& (rawFormat == ImageData::FORMAT_RGBA8 || rawFormat == ImageData::FORMAT_RGBA16);
+		&& (rawFormat == PIXELFORMAT_RGBA8 || rawFormat == PIXELFORMAT_RGBA16);
 }
 
 PNGHandler::DecodedImage PNGHandler::decode(love::filesystem::FileData *fdata)
@@ -182,7 +182,7 @@ PNGHandler::DecodedImage PNGHandler::decode(love::filesystem::FileData *fdata)
 	img.width  = (int) width;
 	img.height = (int) height;
 	img.size   = width * height * (state.info_raw.bitdepth * 4 / 8);
-	img.format = state.info_raw.bitdepth == 16 ? ImageData::FORMAT_RGBA16 : ImageData::FORMAT_RGBA8;
+	img.format = state.info_raw.bitdepth == 16 ? PIXELFORMAT_RGBA16 : PIXELFORMAT_RGBA8;
 
 	// LodePNG keeps raw 16 bit images stored as big-endian.
 #ifndef LOVE_BIG_ENDIAN
@@ -209,7 +209,7 @@ PNGHandler::EncodedImage PNGHandler::encode(const DecodedImage &img, ImageData::
 	lodepng::State state;
 
 	state.info_raw.colortype = LCT_RGBA;
-	state.info_raw.bitdepth = img.format == ImageData::FORMAT_RGBA16 ? 16 : 8;
+	state.info_raw.bitdepth = img.format == PIXELFORMAT_RGBA16 ? 16 : 8;
 
 	state.info_png.color.colortype = LCT_RGBA;
 	state.info_png.color.bitdepth = state.info_raw.bitdepth;

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

@@ -41,7 +41,7 @@ public:
 	// Implements FormatHandler.
 
 	virtual bool canDecode(love::filesystem::FileData *data);
-	virtual bool canEncode(ImageData::Format rawFormat, ImageData::EncodedFormat encodedFormat);
+	virtual bool canEncode(PixelFormat rawFormat, ImageData::EncodedFormat encodedFormat);
 
 	virtual DecodedImage decode(love::filesystem::FileData *data);
 	virtual EncodedImage encode(const DecodedImage &img, ImageData::EncodedFormat format);

+ 36 - 36
src/modules/image/magpie/PVRHandler.cpp

@@ -203,7 +203,7 @@ void ConvertPVRHeader(PVRTexHeaderV2 header2, PVRTexHeaderV3 *header3)
 	}
 }
 
-static CompressedImageData::Format convertFormat(PVRV3PixelFormat format, PVRV3ChannelType channeltype)
+static PixelFormat convertFormat(PVRV3PixelFormat format, PVRV3ChannelType channeltype)
 {
 	bool snorm = false;
 
@@ -221,69 +221,69 @@ static CompressedImageData::Format convertFormat(PVRV3PixelFormat format, PVRV3C
 	switch (format)
 	{
 	case ePVRTPF_PVRTCI_2bpp_RGB:
-		return CompressedImageData::FORMAT_PVR1_RGB2;
+		return PIXELFORMAT_PVR1_RGB2;
 	case ePVRTPF_PVRTCI_2bpp_RGBA:
-		return CompressedImageData::FORMAT_PVR1_RGBA2;
+		return PIXELFORMAT_PVR1_RGBA2;
 	case ePVRTPF_PVRTCI_4bpp_RGB:
-		return CompressedImageData::FORMAT_PVR1_RGB4;
+		return PIXELFORMAT_PVR1_RGB4;
 	case ePVRTPF_PVRTCI_4bpp_RGBA:
-		return CompressedImageData::FORMAT_PVR1_RGBA4;
+		return PIXELFORMAT_PVR1_RGBA4;
 	case ePVRTPF_ETC1:
-		return CompressedImageData::FORMAT_ETC1;
+		return PIXELFORMAT_ETC1;
 	case ePVRTPF_DXT1:
-		return CompressedImageData::FORMAT_DXT1;
+		return PIXELFORMAT_DXT1;
 	case ePVRTPF_DXT3:
-		return CompressedImageData::FORMAT_DXT3;
+		return PIXELFORMAT_DXT3;
 	case ePVRTPF_DXT5:
-		return CompressedImageData::FORMAT_DXT5;
+		return PIXELFORMAT_DXT5;
 	case ePVRTPF_BC4:
-		return snorm ? CompressedImageData::FORMAT_BC4s : CompressedImageData::FORMAT_BC4;
+		return snorm ? PIXELFORMAT_BC4s : PIXELFORMAT_BC4;
 	case ePVRTPF_BC5:
-		return snorm ? CompressedImageData::FORMAT_BC5s : CompressedImageData::FORMAT_BC5;
+		return snorm ? PIXELFORMAT_BC5s : PIXELFORMAT_BC5;
 	case ePVRTPF_BC6:
-		return snorm ? CompressedImageData::FORMAT_BC6Hs : CompressedImageData::FORMAT_BC6H;
+		return snorm ? PIXELFORMAT_BC6Hs : PIXELFORMAT_BC6H;
 	case ePVRTPF_BC7:
-		return CompressedImageData::FORMAT_BC7;
+		return PIXELFORMAT_BC7;
 	case ePVRTPF_ETC2_RGB:
-		return CompressedImageData::FORMAT_ETC2_RGB;
+		return PIXELFORMAT_ETC2_RGB;
 	case ePVRTPF_ETC2_RGBA:
-		return CompressedImageData::FORMAT_ETC2_RGBA;
+		return PIXELFORMAT_ETC2_RGBA;
 	case ePVRTPF_ETC2_RGBA1:
-		return CompressedImageData::FORMAT_ETC2_RGBA1;
+		return PIXELFORMAT_ETC2_RGBA1;
 	case ePVRTPF_EAC_R:
-		return snorm ? CompressedImageData::FORMAT_EAC_Rs : CompressedImageData::FORMAT_EAC_R;
+		return snorm ? PIXELFORMAT_EAC_Rs : PIXELFORMAT_EAC_R;
 	case ePVRTPF_EAC_RG:
-		return snorm ? CompressedImageData::FORMAT_EAC_RGs : CompressedImageData::FORMAT_EAC_RG;
+		return snorm ? PIXELFORMAT_EAC_RGs : PIXELFORMAT_EAC_RG;
 	case ePVRTPF_ASTC_4x4:
-		return CompressedImageData::FORMAT_ASTC_4x4;
+		return PIXELFORMAT_ASTC_4x4;
 	case ePVRTPF_ASTC_5x4:
-		return CompressedImageData::FORMAT_ASTC_5x4;
+		return PIXELFORMAT_ASTC_5x4;
 	case ePVRTPF_ASTC_5x5:
-		return CompressedImageData::FORMAT_ASTC_5x5;
+		return PIXELFORMAT_ASTC_5x5;
 	case ePVRTPF_ASTC_6x5:
-		return CompressedImageData::FORMAT_ASTC_6x5;
+		return PIXELFORMAT_ASTC_6x5;
 	case ePVRTPF_ASTC_6x6:
-		return CompressedImageData::FORMAT_ASTC_6x6;
+		return PIXELFORMAT_ASTC_6x6;
 	case ePVRTPF_ASTC_8x5:
-		return CompressedImageData::FORMAT_ASTC_8x5;
+		return PIXELFORMAT_ASTC_8x5;
 	case ePVRTPF_ASTC_8x6:
-		return CompressedImageData::FORMAT_ASTC_8x6;
+		return PIXELFORMAT_ASTC_8x6;
 	case ePVRTPF_ASTC_8x8:
-		return CompressedImageData::FORMAT_ASTC_8x8;
+		return PIXELFORMAT_ASTC_8x8;
 	case ePVRTPF_ASTC_10x5:
-		return CompressedImageData::FORMAT_ASTC_10x5;
+		return PIXELFORMAT_ASTC_10x5;
 	case ePVRTPF_ASTC_10x6:
-		return CompressedImageData::FORMAT_ASTC_10x6;
+		return PIXELFORMAT_ASTC_10x6;
 	case ePVRTPF_ASTC_10x8:
-		return CompressedImageData::FORMAT_ASTC_10x8;
+		return PIXELFORMAT_ASTC_10x8;
 	case ePVRTPF_ASTC_10x10:
-		return CompressedImageData::FORMAT_ASTC_10x10;
+		return PIXELFORMAT_ASTC_10x10;
 	case ePVRTPF_ASTC_12x10:
-		return CompressedImageData::FORMAT_ASTC_12x10;
+		return PIXELFORMAT_ASTC_12x10;
 	case ePVRTPF_ASTC_12x12:
-		return CompressedImageData::FORMAT_ASTC_12x12;
+		return PIXELFORMAT_ASTC_12x12;
 	default:
-		return CompressedImageData::FORMAT_UNKNOWN;
+		return PIXELFORMAT_UNKNOWN;
 	}
 }
 
@@ -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, CompressedImageData::Format &format, bool &sRGB)
+uint8 *PVRHandler::parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB)
 {
 	if (!canParse(filedata))
 		throw love::Exception("Could not decode compressed data (not a PVR file?)");
@@ -507,9 +507,9 @@ uint8 *PVRHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
 	PVRV3PixelFormat pixelformat = (PVRV3PixelFormat) header3.pixelFormat;
 	PVRV3ChannelType channeltype = (PVRV3ChannelType) header3.channelType;
 
-	CompressedImageData::Format cformat = convertFormat(pixelformat, channeltype);
+	PixelFormat cformat = convertFormat(pixelformat, channeltype);
 
-	if (cformat == CompressedImageData::FORMAT_UNKNOWN)
+	if (cformat == PIXELFORMAT_UNKNOWN)
 		throw love::Exception("Could not parse PVR file: unsupported image format.");
 
 	size_t totalsize = 0;

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

@@ -40,7 +40,7 @@ public:
 
 	// Implements CompressedFormatHandler.
 	virtual bool canParse(const filesystem::FileData *data);
-	virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, CompressedImageData::Format &format, bool &sRGB);
+	virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB);
 
 }; // PVRHandler
 

+ 4 - 4
src/modules/image/magpie/STBHandler.cpp

@@ -60,9 +60,9 @@ bool STBHandler::canDecode(love::filesystem::FileData *data)
 	return status == 1 && w > 0 && h > 0;
 }
 
-bool STBHandler::canEncode(ImageData::Format rawFormat, ImageData::EncodedFormat encodedFormat)
+bool STBHandler::canEncode(PixelFormat rawFormat, ImageData::EncodedFormat encodedFormat)
 {
-	return encodedFormat == ImageData::ENCODED_TGA && rawFormat == ImageData::FORMAT_RGBA8;
+	return encodedFormat == ImageData::ENCODED_TGA && rawFormat == PIXELFORMAT_RGBA8;
 }
 
 FormatHandler::DecodedImage STBHandler::decode(love::filesystem::FileData *data)
@@ -77,13 +77,13 @@ FormatHandler::DecodedImage STBHandler::decode(love::filesystem::FileData *data)
 	{
 		img.data = (unsigned char *) stbi_loadf_from_memory(buffer, bufferlen, &img.width, &img.height, &comp, 4);
 		img.size = img.width * img.height * 4 * sizeof(float);
-		img.format = ImageData::FORMAT_RGBA32F;
+		img.format = PIXELFORMAT_RGBA32F;
 	}
 	else
 	{
 		img.data = stbi_load_from_memory(buffer, bufferlen, &img.width, &img.height, &comp, 4);
 		img.size = img.width * img.height * 4;
-		img.format = ImageData::FORMAT_RGBA8;
+		img.format = PIXELFORMAT_RGBA8;
 	}
 
 	if (img.data == nullptr || img.width <= 0 || img.height <= 0)

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

@@ -44,7 +44,7 @@ public:
 	// Implements FormatHandler.
 
 	virtual bool canDecode(love::filesystem::FileData *data);
-	virtual bool canEncode(ImageData::Format rawFormat, ImageData::EncodedFormat encodedFormat);
+	virtual bool canEncode(PixelFormat rawFormat, ImageData::EncodedFormat encodedFormat);
 
 	virtual DecodedImage decode(love::filesystem::FileData *data);
 	virtual EncodedImage encode(const DecodedImage &img, ImageData::EncodedFormat format);

+ 16 - 16
src/modules/image/magpie/ddsHandler.cpp

@@ -32,12 +32,12 @@ 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, CompressedImageData::Format &format, bool &sRGB)
+uint8 *DDSHandler::parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB)
 {
 	if (!dds::isDDS(filedata->getData(), filedata->getSize()))
 		throw love::Exception("Could not decode compressed data (not a DDS file?)");
 
-	CompressedImageData::Format texformat = CompressedImageData::FORMAT_UNKNOWN;
+	PixelFormat texformat = PIXELFORMAT_UNKNOWN;
 	bool isSRGB = false;
 
 	uint8 *data = nullptr;
@@ -51,7 +51,7 @@ uint8 *DDSHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
 
 		texformat = convertFormat(parser.getFormat(), isSRGB);
 
-		if (texformat == CompressedImageData::FORMAT_UNKNOWN)
+		if (texformat == PIXELFORMAT_UNKNOWN)
 			throw love::Exception("Could not parse compressed data: Unsupported format.");
 
 		if (parser.getMipmapCount() == 0)
@@ -101,37 +101,37 @@ uint8 *DDSHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
 	return data;
 }
 
-CompressedImageData::Format DDSHandler::convertFormat(dds::Format ddsformat, bool &sRGB)
+PixelFormat DDSHandler::convertFormat(dds::Format ddsformat, bool &sRGB)
 {
 	sRGB = false;
 
 	switch (ddsformat)
 	{
 	case dds::FORMAT_DXT1:
-		return CompressedImageData::FORMAT_DXT1;
+		return PIXELFORMAT_DXT1;
 	case dds::FORMAT_DXT3:
-		return CompressedImageData::FORMAT_DXT3;
+		return PIXELFORMAT_DXT3;
 	case dds::FORMAT_DXT5:
-		return CompressedImageData::FORMAT_DXT5;
+		return PIXELFORMAT_DXT5;
 	case dds::FORMAT_BC4:
-		return CompressedImageData::FORMAT_BC4;
+		return PIXELFORMAT_BC4;
 	case dds::FORMAT_BC4s:
-		return CompressedImageData::FORMAT_BC4s;
+		return PIXELFORMAT_BC4s;
 	case dds::FORMAT_BC5:
-		return CompressedImageData::FORMAT_BC5;
+		return PIXELFORMAT_BC5;
 	case dds::FORMAT_BC5s:
-		return CompressedImageData::FORMAT_BC5s;
+		return PIXELFORMAT_BC5s;
 	case dds::FORMAT_BC6H:
-		return CompressedImageData::FORMAT_BC6H;
+		return PIXELFORMAT_BC6H;
 	case dds::FORMAT_BC6Hs:
-		return CompressedImageData::FORMAT_BC6Hs;
+		return PIXELFORMAT_BC6Hs;
 	case dds::FORMAT_BC7:
-		return CompressedImageData::FORMAT_BC7;
+		return PIXELFORMAT_BC7;
 	case dds::FORMAT_BC7srgb:
 		sRGB = true;
-		return CompressedImageData::FORMAT_BC7;
+		return PIXELFORMAT_BC7;
 	default:
-		return CompressedImageData::FORMAT_UNKNOWN;
+		return PIXELFORMAT_UNKNOWN;
 	}
 }
 

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

@@ -48,11 +48,11 @@ public:
 
 	// Implements CompressedFormatHandler.
 	virtual bool canParse(const filesystem::FileData *data);
-	virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, CompressedImageData::Format &format, bool &sRGB);
+	virtual uint8 *parse(filesystem::FileData *filedata, std::vector<CompressedImageData::SubImage> &images, size_t &dataSize, PixelFormat &format, bool &sRGB);
 
 private:
 
-	static CompressedImageData::Format convertFormat(dds::Format ddsformat, bool &sRGB);
+	static PixelFormat convertFormat(dds::Format ddsformat, bool &sRGB);
 
 }; // DDSHandler
 

+ 2 - 2
src/modules/image/wrap_CompressedImageData.cpp

@@ -83,10 +83,10 @@ int w_CompressedImageData_getFormat(lua_State *L)
 {
 	CompressedImageData *t = luax_checkcompressedimagedata(L, 1);
 
-	image::CompressedImageData::Format format = t->getFormat();
+	PixelFormat format = t->getFormat();
 	const char *str;
 
-	if (image::CompressedImageData::getConstant(format, str))
+	if (getConstant(format, str))
 		lua_pushstring(L, str);
 	else
 		lua_pushstring(L, "unknown");

+ 3 - 3
src/modules/image/wrap_Image.cpp

@@ -44,13 +44,13 @@ int w_newImageData(lua_State *L)
 		if (w <= 0 || h <= 0)
 			return luaL_error(L, "Invalid image size.");
 
-		ImageData::Format format = ImageData::FORMAT_RGBA8;
+		PixelFormat format = PIXELFORMAT_RGBA8;
 
 		if (!lua_isnoneornil(L, 3))
 		{
 			const char *fstr = luaL_checkstring(L, 3);
-			if (!ImageData::getConstant(fstr, format))
-				return luaL_error(L, "Invalid ImageData format: %s", fstr);
+			if (!getConstant(fstr, format))
+				return luaL_error(L, "Invalid pixel format: %s", fstr);
 		}
 
 		size_t numbytes = 0;

+ 18 - 21
src/modules/image/wrap_ImageData.cpp

@@ -46,11 +46,11 @@ ImageData *luax_checkimagedata(lua_State *L, int idx)
 int w_ImageData_getFormat(lua_State *L)
 {
 	ImageData *t = luax_checkimagedata(L, 1);
-	ImageData::Format format = t->getFormat();
+	PixelFormat format = t->getFormat();
 	const char *fstr = nullptr;
 
-	if (!ImageData::getConstant(format, fstr))
-		return luaL_error(L, "Unknown ImageData format.");
+	if (!getConstant(format, fstr))
+		return luaL_error(L, "Unknown pixel format.");
 
 	lua_pushstring(L, fstr);
 	return 1;
@@ -143,21 +143,8 @@ static int luax_pushpixel_rgba32f(lua_State *L, const Pixel &p)
 typedef void(*checkpixel)(lua_State *L, int startidx, Pixel &p);
 typedef int(*pushpixel)(lua_State *L, const Pixel &p);
 
-static checkpixel checkFormats[ImageData::FORMAT_MAX_ENUM] =
-{
-	luax_checkpixel_rgba8,
-	luax_checkpixel_rgba16,
-	luax_checkpixel_rgba16f,
-	luax_checkpixel_rgba32f,
-};
-
-static pushpixel pushFormats[ImageData::FORMAT_MAX_ENUM] =
-{
-	luax_pushpixel_rgba8,
-	luax_pushpixel_rgba16,
-	luax_pushpixel_rgba16f,
-	luax_pushpixel_rgba32f,
-};
+static checkpixel checkFormats[PIXELFORMAT_MAX_ENUM] = {};
+static pushpixel pushFormats[PIXELFORMAT_MAX_ENUM] = {};
 
 int w_ImageData_getPixel(lua_State *L)
 {
@@ -165,7 +152,7 @@ int w_ImageData_getPixel(lua_State *L)
 	int x = (int) luaL_checknumber(L, 2);
 	int y = (int) luaL_checknumber(L, 3);
 
-	ImageData::Format format = t->getFormat();
+	PixelFormat format = t->getFormat();
 
 	Pixel p;
 	luax_catchexcept(L, [&](){ t->getPixel(x, y, p); });
@@ -179,7 +166,7 @@ int w_ImageData_setPixel(lua_State *L)
 	int x = (int) luaL_checknumber(L, 2);
 	int y = (int) luaL_checknumber(L, 3);
 
-	ImageData::Format format = t->getFormat();
+	PixelFormat format = t->getFormat();
 
 	Pixel p;
 
@@ -217,7 +204,7 @@ int w_ImageData__mapPixelUnsafe(lua_State *L)
 
 	int iw = t->getWidth();
 
-	ImageData::Format format = t->getFormat();
+	PixelFormat format = t->getFormat();
 
 	auto checkpixel = checkFormats[format];
 	auto pushpixel = pushFormats[format];
@@ -366,6 +353,16 @@ static const luaL_Reg w_ImageData_functions[] =
 
 extern "C" int luaopen_imagedata(lua_State *L)
 {
+	checkFormats[PIXELFORMAT_RGBA8]   = luax_checkpixel_rgba8;
+	checkFormats[PIXELFORMAT_RGBA16]  = luax_checkpixel_rgba16;
+	checkFormats[PIXELFORMAT_RGBA16F] = luax_checkpixel_rgba16f;
+	checkFormats[PIXELFORMAT_RGBA32F] = luax_checkpixel_rgba32f;
+
+	pushFormats[PIXELFORMAT_RGBA8]   = luax_pushpixel_rgba8;
+	pushFormats[PIXELFORMAT_RGBA16]  = luax_pushpixel_rgba16;
+	pushFormats[PIXELFORMAT_RGBA16F] = luax_pushpixel_rgba16f;
+	pushFormats[PIXELFORMAT_RGBA32F] = luax_pushpixel_rgba32f;
+
 	int ret = luax_register_type(L, IMAGE_IMAGE_DATA_ID, "ImageData", w_Data_functions, w_ImageData_functions, nullptr);
 
 	luax_gettypemetatable(L, IMAGE_IMAGE_DATA_ID);