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
This commit is contained in:
Alex Szpakowski
2016-11-27 22:53:23 -04:00
parent cbba8c40a6
commit 0a3adc0839
50 changed files with 1042 additions and 1006 deletions
+7 -1
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
bool Image::isFormatSupported(PixelFormat pixelformat)
{
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)
{
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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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;
+29 -56
View File
@@ -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;
}
static int w__getFormats(lua_State *L, bool (*isFormatSupported)(PixelFormat), bool (*ignore)(PixelFormat))
{
lua_createtable(L, 0, (int) PIXELFORMAT_MAX_ENUM);
for (int i = 0; i < (int) PIXELFORMAT_MAX_ENUM; i++)
{
PixelFormat format = (PixelFormat) i;
const char *name = nullptr;
if (format == PIXELFORMAT_UNKNOWN || !love::getConstant(format, name) || ignore(format))
continue;
luax_pushboolean(L, isFormatSupported(format));
lua_setfield(L, -2, name);
}
return 1;
}
int w_getCanvasFormats(lua_State *L)
{
lua_createtable(L, 0, (int) Canvas::FORMAT_MAX_ENUM);
for (int i = 0; i < (int) Canvas::FORMAT_MAX_ENUM; i++)
{
Canvas::Format format = (Canvas::Format) i;
const char *name = nullptr;
if (!Canvas::getConstant(format, name))
continue;
luax_pushboolean(L, Canvas::isFormatSupported(format));
lua_setfield(L, -2, name);
}
return 1;
return w__getFormats(L, Canvas::isFormatSupported, isPixelFormatCompressed);
}
int w_getRawImageFormats(lua_State *L)
int w_getImageFormats(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++)
const auto ignore = [](PixelFormat format)
{
auto format = (image::ImageData::Format) i;
const char *name = nullptr;
return !(image::ImageData::validPixelFormat(format) || isPixelFormatCompressed(format));
};
if (!image::ImageData::getConstant(format, name))
continue;
luax_pushboolean(L, Image::hasTextureSupport(format));
lua_setfield(L, -2, name);
}
return 1;
}
int w_getCompressedImageFormats(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++)
{
auto format = (image::CompressedImageData::Format) i;
const char *name = nullptr;
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 },