|
|
@@ -56,8 +56,13 @@ Graphics::Graphics()
|
|
|
{
|
|
|
currentWindow = love::window::sdl::Window::createSingleton();
|
|
|
|
|
|
+ int w, h;
|
|
|
+ love::window::WindowSettings wsettings;
|
|
|
+
|
|
|
+ currentWindow->getWindow(w, h, wsettings);
|
|
|
+
|
|
|
if (currentWindow->isCreated())
|
|
|
- setMode(currentWindow->getWidth(), currentWindow->getHeight());
|
|
|
+ setMode(w, h, wsettings.sRGB);
|
|
|
}
|
|
|
|
|
|
Graphics::~Graphics()
|
|
|
@@ -104,6 +109,8 @@ DisplayState Graphics::saveState()
|
|
|
for (int i = 0; i < 4; i++)
|
|
|
s.colorMask[i] = colorMask[i];
|
|
|
|
|
|
+ wireframe = isWireframe();
|
|
|
+
|
|
|
return s;
|
|
|
}
|
|
|
|
|
|
@@ -121,6 +128,7 @@ void Graphics::restoreState(const DisplayState &s)
|
|
|
else
|
|
|
setScissor();
|
|
|
setColorMask(s.colorMask[0], s.colorMask[1], s.colorMask[2], s.colorMask[3]);
|
|
|
+ setWireframe(s.wireframe);
|
|
|
}
|
|
|
|
|
|
void Graphics::setViewportSize(int width, int height)
|
|
|
@@ -151,7 +159,7 @@ void Graphics::setViewportSize(int width, int height)
|
|
|
c->startGrab(c->getAttachedCanvases());
|
|
|
}
|
|
|
|
|
|
-bool Graphics::setMode(int width, int height)
|
|
|
+bool Graphics::setMode(int width, int height, bool &sRGB)
|
|
|
{
|
|
|
this->width = width;
|
|
|
this->height = height;
|
|
|
@@ -181,9 +189,6 @@ bool Graphics::setMode(int width, int height)
|
|
|
// Enable blending
|
|
|
glEnable(GL_BLEND);
|
|
|
|
|
|
- // "Normal" blending
|
|
|
- glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
|
-
|
|
|
// Enable all color component writes.
|
|
|
setColorMask(true, true, true, true);
|
|
|
|
|
|
@@ -228,6 +233,19 @@ bool Graphics::setMode(int width, int height)
|
|
|
Shader::defaultShader->attach();
|
|
|
}
|
|
|
|
|
|
+ // Set whether drawing converts input from linear -> sRGB colorspace.
|
|
|
+ if (GLAD_VERSION_3_0 || GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB)
|
|
|
+ {
|
|
|
+ if (sRGB)
|
|
|
+ glEnable(GL_FRAMEBUFFER_SRGB);
|
|
|
+ else
|
|
|
+ glDisable(GL_FRAMEBUFFER_SRGB);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ sRGB = false;
|
|
|
+
|
|
|
+ Canvas::screenHasSRGB = sRGB;
|
|
|
+
|
|
|
bool enabledebug = false;
|
|
|
|
|
|
if (GLAD_VERSION_3_0)
|
|
|
@@ -238,6 +256,8 @@ bool Graphics::setMode(int width, int height)
|
|
|
enabledebug = (flags & GL_CONTEXT_FLAG_DEBUG_BIT) != 0;
|
|
|
}
|
|
|
|
|
|
+ // FIXME: workaround for KHR_debug being supported but function pointers
|
|
|
+ // resolving to null on Ouya.
|
|
|
if (!GLAD_ES_VERSION_2_0)
|
|
|
setDebug(enabledebug);
|
|
|
|
|
|
@@ -313,6 +333,9 @@ void Graphics::setDebug(bool enable)
|
|
|
glDebugMessageControl(GL_DEBUG_SOURCE_API, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE);
|
|
|
glDebugMessageControl(GL_DEBUG_SOURCE_SHADER_COMPILER, GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR, GL_DONT_CARE, 0, 0, GL_FALSE);
|
|
|
|
|
|
+ if (GLAD_VERSION_4_3 || GLAD_KHR_debug)
|
|
|
+ glEnable(GL_DEBUG_OUTPUT);
|
|
|
+
|
|
|
::printf("OpenGL debug output enabled (LOVE_GRAPHICS_DEBUG=1)\n");
|
|
|
}
|
|
|
|
|
|
@@ -431,10 +454,10 @@ void Graphics::discardStencil()
|
|
|
glDisable(GL_STENCIL_TEST);
|
|
|
}
|
|
|
|
|
|
-Image *Graphics::newImage(love::image::ImageData *data)
|
|
|
+Image *Graphics::newImage(love::image::ImageData *data, Texture::Format format)
|
|
|
{
|
|
|
// Create the image.
|
|
|
- Image *image = new Image(data);
|
|
|
+ Image *image = new Image(data, format);
|
|
|
|
|
|
if (!isCreated())
|
|
|
return image;
|
|
|
@@ -458,10 +481,10 @@ Image *Graphics::newImage(love::image::ImageData *data)
|
|
|
return image;
|
|
|
}
|
|
|
|
|
|
-Image *Graphics::newImage(love::image::CompressedData *cdata)
|
|
|
+Image *Graphics::newImage(love::image::CompressedData *cdata, Texture::Format format)
|
|
|
{
|
|
|
// Create the image.
|
|
|
- Image *image = new Image(cdata);
|
|
|
+ Image *image = new Image(cdata, format);
|
|
|
|
|
|
if (!isCreated())
|
|
|
return image;
|
|
|
@@ -505,11 +528,14 @@ ParticleSystem *Graphics::newParticleSystem(Texture *texture, int size)
|
|
|
return new ParticleSystem(texture, size);
|
|
|
}
|
|
|
|
|
|
-Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_type, int fsaa)
|
|
|
+Canvas *Graphics::newCanvas(int width, int height, Texture::Format format, int fsaa)
|
|
|
{
|
|
|
- if (texture_type == Canvas::TYPE_HDR && !Canvas::isHDRSupported())
|
|
|
+ if (format == Texture::FORMAT_HDR && !Canvas::isHDRSupported())
|
|
|
throw Exception("HDR Canvases are not supported by your OpenGL implementation");
|
|
|
|
|
|
+ if (format == Texture::FORMAT_SRGB && !Canvas::isSRGBSupported())
|
|
|
+ throw Exception("sRGB Canvases are not supported by your OpenGL implementation");
|
|
|
+
|
|
|
if (width > gl.getMaxTextureSize())
|
|
|
throw Exception("Cannot create canvas: width of %d pixels is too large for this system.", width);
|
|
|
else if (height > gl.getMaxTextureSize())
|
|
|
@@ -518,7 +544,7 @@ Canvas *Graphics::newCanvas(int width, int height, Canvas::TextureType texture_t
|
|
|
while (GL_NO_ERROR != glGetError())
|
|
|
/* clear opengl error flag */;
|
|
|
|
|
|
- Canvas *canvas = new Canvas(width, height, texture_type, fsaa);
|
|
|
+ Canvas *canvas = new Canvas(width, height, format, fsaa);
|
|
|
GLenum err = canvas->getStatus();
|
|
|
|
|
|
// everything ok, return canvas (early out)
|
|
|
@@ -630,22 +656,16 @@ const bool *Graphics::getColorMask() const
|
|
|
|
|
|
void Graphics::setBlendMode(Graphics::BlendMode mode)
|
|
|
{
|
|
|
- const int gl_1_4 = GLAD_VERSION_1_4;
|
|
|
-
|
|
|
- GLenum func = GL_FUNC_ADD;
|
|
|
- GLenum src_rgb = GL_ONE;
|
|
|
- GLenum src_a = GL_ONE;
|
|
|
- GLenum dst_rgb = GL_ZERO;
|
|
|
- GLenum dst_a = GL_ZERO;
|
|
|
+ OpenGL::BlendState state = {GL_ONE, GL_ONE, GL_ZERO, GL_ZERO, GL_FUNC_ADD};
|
|
|
|
|
|
switch (mode)
|
|
|
{
|
|
|
case BLEND_ALPHA:
|
|
|
- if (gl_1_4 || GLAD_ES_VERSION_2_0 || GLAD_EXT_blend_func_separate)
|
|
|
+ if (GLAD_ES_VERSION_2_0 || GLAD_VERSION_1_4 || GLAD_EXT_blend_func_separate)
|
|
|
{
|
|
|
- src_rgb = GL_SRC_ALPHA;
|
|
|
- src_a = GL_ONE;
|
|
|
- dst_rgb = dst_a = GL_ONE_MINUS_SRC_ALPHA;
|
|
|
+ state.srcRGB = GL_SRC_ALPHA;
|
|
|
+ state.srcA = GL_ONE;
|
|
|
+ state.dstRGB = state.dstA = GL_ONE_MINUS_SRC_ALPHA;
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
@@ -653,100 +673,56 @@ void Graphics::setBlendMode(Graphics::BlendMode mode)
|
|
|
// This will most likely only be used for the Microsoft software renderer and
|
|
|
// since it's still stuck with OpenGL 1.1, the only expected difference is a
|
|
|
// different alpha value when reading back the default framebuffer (newScreenshot).
|
|
|
- src_rgb = src_a = GL_SRC_ALPHA;
|
|
|
- dst_rgb = dst_a = GL_ONE_MINUS_SRC_ALPHA;
|
|
|
+ state.srcRGB = state.srcA = GL_SRC_ALPHA;
|
|
|
+ state.dstRGB = state.dstA = GL_ONE_MINUS_SRC_ALPHA;
|
|
|
}
|
|
|
break;
|
|
|
case BLEND_MULTIPLICATIVE:
|
|
|
- src_rgb = src_a = GL_DST_COLOR;
|
|
|
- dst_rgb = dst_a = GL_ZERO;
|
|
|
+ state.srcRGB = state.srcA = GL_DST_COLOR;
|
|
|
+ state.dstRGB = state.dstA = GL_ZERO;
|
|
|
break;
|
|
|
case BLEND_PREMULTIPLIED:
|
|
|
- src_rgb = src_a = GL_ONE;
|
|
|
- dst_rgb = dst_a = GL_ONE_MINUS_SRC_ALPHA;
|
|
|
+ state.srcRGB = state.srcA = GL_ONE;
|
|
|
+ state.dstRGB = state.dstA = GL_ONE_MINUS_SRC_ALPHA;
|
|
|
break;
|
|
|
case BLEND_SUBTRACTIVE:
|
|
|
- func = GL_FUNC_REVERSE_SUBTRACT;
|
|
|
+ state.func = GL_FUNC_REVERSE_SUBTRACT;
|
|
|
case BLEND_ADDITIVE:
|
|
|
- src_rgb = src_a = GL_SRC_ALPHA;
|
|
|
- dst_rgb = dst_a = GL_ONE;
|
|
|
+ state.srcRGB = state.srcA = GL_SRC_ALPHA;
|
|
|
+ state.dstRGB = state.dstA = GL_ONE;
|
|
|
break;
|
|
|
case BLEND_REPLACE:
|
|
|
default:
|
|
|
- src_rgb = src_a = GL_ONE;
|
|
|
- dst_rgb = dst_a = GL_ZERO;
|
|
|
+ state.srcRGB = state.srcA = GL_ONE;
|
|
|
+ state.dstRGB = state.dstA = GL_ZERO;
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
- if (gl_1_4 || GLAD_ES_VERSION_2_0)
|
|
|
- glBlendEquation(func);
|
|
|
- else if (GLAD_EXT_blend_minmax && GLAD_EXT_blend_subtract)
|
|
|
- glBlendEquationEXT(func);
|
|
|
- else
|
|
|
- {
|
|
|
- if (func == GL_FUNC_REVERSE_SUBTRACT)
|
|
|
- throw Exception("This graphics card does not support the subtractive blend mode!");
|
|
|
- // GL_FUNC_ADD is the default even without access to glBlendEquation, so that'll still work.
|
|
|
- }
|
|
|
-
|
|
|
- if (src_rgb == src_a && dst_rgb == dst_a)
|
|
|
- glBlendFunc(src_rgb, dst_rgb);
|
|
|
- else
|
|
|
- {
|
|
|
- if (gl_1_4 || GLAD_ES_VERSION_2_0)
|
|
|
- glBlendFuncSeparate(src_rgb, dst_rgb, src_a, dst_a);
|
|
|
- else if (GLAD_EXT_blend_func_separate)
|
|
|
- glBlendFuncSeparateEXT(src_rgb, dst_rgb, src_a, dst_a);
|
|
|
- else
|
|
|
- throw Exception("This graphics card does not support separated rgb and alpha blend functions!");
|
|
|
- }
|
|
|
+ gl.setBlendState(state);
|
|
|
}
|
|
|
|
|
|
Graphics::BlendMode Graphics::getBlendMode() const
|
|
|
{
|
|
|
- const int gl_1_4 = GLAD_VERSION_1_4;
|
|
|
-
|
|
|
- GLint src_rgb, src_a, dst_rgb, dst_a;
|
|
|
- GLint equation = GL_FUNC_ADD;
|
|
|
-
|
|
|
- if (gl_1_4 || GLAD_ES_VERSION_2_0 || GLAD_EXT_blend_func_separate)
|
|
|
- {
|
|
|
- glGetIntegerv(GL_BLEND_SRC_RGB, &src_rgb);
|
|
|
- glGetIntegerv(GL_BLEND_SRC_ALPHA, &src_a);
|
|
|
- glGetIntegerv(GL_BLEND_DST_RGB, &dst_rgb);
|
|
|
- glGetIntegerv(GL_BLEND_DST_ALPHA, &dst_a);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- glGetIntegerv(GL_BLEND_SRC, &src_rgb);
|
|
|
- glGetIntegerv(GL_BLEND_DST, &dst_rgb);
|
|
|
- src_a = src_rgb;
|
|
|
- dst_a = dst_rgb;
|
|
|
- }
|
|
|
-
|
|
|
- if (GLAD_ES_VERSION_2_0)
|
|
|
- glGetIntegerv(GL_BLEND_EQUATION_RGB, &equation);
|
|
|
- else if (gl_1_4 || (GLAD_EXT_blend_minmax && GLAD_EXT_blend_subtract))
|
|
|
- glGetIntegerv(GL_BLEND_EQUATION, &equation);
|
|
|
+ OpenGL::BlendState state = gl.getBlendState();
|
|
|
|
|
|
- if (equation == GL_FUNC_REVERSE_SUBTRACT) // && src == GL_SRC_ALPHA && dst == GL_ONE
|
|
|
+ if (state.func == GL_FUNC_REVERSE_SUBTRACT) // && src == GL_SRC_ALPHA && dst == GL_ONE
|
|
|
return BLEND_SUBTRACTIVE;
|
|
|
// Everything else has equation == GL_FUNC_ADD.
|
|
|
- else if (src_rgb == src_a && dst_rgb == dst_a)
|
|
|
+ else if (state.srcRGB == state.srcA && state.dstRGB == state.dstA)
|
|
|
{
|
|
|
- if (src_rgb == GL_SRC_ALPHA && dst_rgb == GL_ONE)
|
|
|
+ if (state.srcRGB == GL_SRC_ALPHA && state.dstRGB == GL_ONE)
|
|
|
return BLEND_ADDITIVE;
|
|
|
- else if (src_rgb == GL_SRC_ALPHA && dst_rgb == GL_ONE_MINUS_SRC_ALPHA)
|
|
|
+ else if (state.srcRGB == GL_SRC_ALPHA && state.dstRGB == GL_ONE_MINUS_SRC_ALPHA)
|
|
|
return BLEND_ALPHA; // alpha blend mode fallback for very old OpenGL versions.
|
|
|
- else if (src_rgb == GL_DST_COLOR && dst_rgb == GL_ZERO)
|
|
|
+ else if (state.srcRGB == GL_DST_COLOR && state.dstRGB == GL_ZERO)
|
|
|
return BLEND_MULTIPLICATIVE;
|
|
|
- else if (src_rgb == GL_ONE && dst_rgb == GL_ONE_MINUS_SRC_ALPHA)
|
|
|
+ else if (state.srcRGB == GL_ONE && state.dstRGB == GL_ONE_MINUS_SRC_ALPHA)
|
|
|
return BLEND_PREMULTIPLIED;
|
|
|
- else if (src_rgb == GL_ONE && dst_rgb == GL_ZERO)
|
|
|
+ else if (state.srcRGB == GL_ONE && state.dstRGB == GL_ZERO)
|
|
|
return BLEND_REPLACE;
|
|
|
}
|
|
|
- else if (src_rgb == GL_SRC_ALPHA && src_a == GL_ONE &&
|
|
|
- dst_rgb == GL_ONE_MINUS_SRC_ALPHA && dst_a == GL_ONE_MINUS_SRC_ALPHA)
|
|
|
+ else if (state.srcRGB == GL_SRC_ALPHA && state.srcA == GL_ONE &&
|
|
|
+ state.dstRGB == GL_ONE_MINUS_SRC_ALPHA && state.dstA == GL_ONE_MINUS_SRC_ALPHA)
|
|
|
return BLEND_ALPHA;
|
|
|
|
|
|
throw Exception("Unknown blend mode");
|
|
|
@@ -836,6 +812,21 @@ Graphics::PointStyle Graphics::getPointStyle() const
|
|
|
return POINT_ROUGH;
|
|
|
}
|
|
|
|
|
|
+void Graphics::setWireframe(bool enable)
|
|
|
+{
|
|
|
+ // Not supported in OpenGL ES.
|
|
|
+ if (GLAD_ES_VERSION_2_0)
|
|
|
+ return;
|
|
|
+
|
|
|
+ wireframe = enable;
|
|
|
+ glPolygonMode(GL_FRONT_AND_BACK, enable ? GL_LINE : GL_FILL);
|
|
|
+}
|
|
|
+
|
|
|
+bool Graphics::isWireframe() const
|
|
|
+{
|
|
|
+ return wireframe;
|
|
|
+}
|
|
|
+
|
|
|
void Graphics::print(const std::string &str, float x, float y , float angle, float sx, float sy, float ox, float oy, float kx, float ky)
|
|
|
{
|
|
|
if (currentFont != nullptr)
|