updated to changeset 80f0adedfaa5 of love-android (including newest mobile-common changes)

This commit is contained in:
fysx
2014-02-13 00:44:51 +01:00
parent 667c4750ea
commit 0bde453b2e
43 changed files with 797 additions and 405 deletions
@@ -1,3 +1,6 @@
#ifndef LUA_WRAP_H
#define LUA_WRAP_H
#define LUA_COMPAT_ALL
#include <lua.h>
#include <lualib.h>
@@ -10,3 +13,5 @@
extern int luax_typerror(lua_State *L, int narg, const char *type);
#endif
#endif // LUA_WRAP_H
@@ -61,11 +61,13 @@ Pool::Pool()
// Make all sources available initially.
for (int i = 0; i < totalSources; i++)
{
#ifdef AL_SOFT_direct_channels
if (hasext)
{
// Bypass virtualization of speakers for multi-channel sources in OpenAL Soft.
alSourcei(sources[i], AL_DIRECT_CHANNELS_SOFT, AL_TRUE);
}
#endif
available.push(sources[i]);
}
@@ -176,6 +176,7 @@ StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM>::Entry Graphics::suppor
{ "dxt", Graphics::SUPPORT_DXT },
{ "bc5", Graphics::SUPPORT_BC5 },
{ "instancing", Graphics::SUPPORT_INSTANCING },
{ "srgb", Graphics::SUPPORT_SRGB },
};
StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM> Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries));
+2 -1
View File
@@ -95,6 +95,7 @@ public:
SUPPORT_DXT,
SUPPORT_BC5,
SUPPORT_INSTANCING,
SUPPORT_SRGB,
SUPPORT_MAX_ENUM
};
@@ -135,7 +136,7 @@ public:
* @param width The viewport width.
* @param height The viewport height.
**/
virtual bool setMode(int width, int height) = 0;
virtual bool setMode(int width, int height, bool &sRGB) = 0;
/**
* Un-sets the current graphics display mode (uninitializing objects if
+19
View File
@@ -109,6 +109,16 @@ bool Texture::getConstant(WrapMode in, const char *&out)
return wrapModes.find(in, out);
}
bool Texture::getConstant(const char *in, Format &out)
{
return formats.find(in, out);
}
bool Texture::getConstant(Format in, const char *&out)
{
return formats.find(in, out);
}
StringMap<Texture::FilterMode, Texture::FILTER_MAX_ENUM>::Entry Texture::filterModeEntries[] =
{
{ "linear", Texture::FILTER_LINEAR },
@@ -125,6 +135,15 @@ StringMap<Texture::WrapMode, Texture::WRAP_MAX_ENUM>::Entry Texture::wrapModeEnt
StringMap<Texture::WrapMode, Texture::WRAP_MAX_ENUM> Texture::wrapModes(Texture::wrapModeEntries, sizeof(Texture::wrapModeEntries));
StringMap<Texture::Format, Texture::FORMAT_MAX_ENUM>::Entry Texture::formatEntries[] =
{
{"normal", Texture::FORMAT_NORMAL},
{"hdr", Texture::FORMAT_HDR},
{"srgb", Texture::FORMAT_SRGB},
};
StringMap<Texture::Format, Texture::FORMAT_MAX_ENUM> Texture::formats(Texture::formatEntries, sizeof(Texture::formatEntries));
} // graphics
} // love
+14
View File
@@ -55,6 +55,14 @@ public:
FILTER_MAX_ENUM
};
enum Format
{
FORMAT_NORMAL,
FORMAT_HDR,
FORMAT_SRGB,
FORMAT_MAX_ENUM
};
struct Filter
{
Filter();
@@ -111,6 +119,9 @@ public:
static bool getConstant(const char *in, WrapMode &out);
static bool getConstant(WrapMode in, const char *&out);
static bool getConstant(const char *in, Format &out);
static bool getConstant(Format in, const char *&out);
protected:
int width;
@@ -132,6 +143,9 @@ private:
static StringMap<WrapMode, WRAP_MAX_ENUM>::Entry wrapModeEntries[];
static StringMap<WrapMode, WRAP_MAX_ENUM> wrapModes;
static StringMap<Format, FORMAT_MAX_ENUM>::Entry formatEntries[];
static StringMap<Format, FORMAT_MAX_ENUM> formats;
}; // Texture
} // graphics
+63 -44
View File
@@ -389,7 +389,7 @@ struct FramebufferStrategyEXT : public FramebufferStrategyPackedEXT
}
};
FramebufferStrategy *strategy = NULL;
FramebufferStrategy *strategy = nullptr;
FramebufferStrategy strategyNone;
@@ -401,8 +401,9 @@ FramebufferStrategyPackedEXT strategyPackedEXT;
FramebufferStrategyEXT strategyEXT;
Canvas *Canvas::current = NULL;
Canvas *Canvas::current = nullptr;
OpenGL::Viewport Canvas::systemViewport = OpenGL::Viewport();
bool Canvas::screenHasSRGB = false;
static void getStrategy()
{
@@ -421,16 +422,13 @@ static void getStrategy()
}
}
static int maxFBOColorAttachments = 0;
static int maxDrawBuffers = 0;
Canvas::Canvas(int width, int height, TextureType texture_type, int fsaa)
Canvas::Canvas(int width, int height, Texture::Format format, int fsaa)
: fbo(0)
, resolve_fbo(0)
, texture(0)
, fsaa_buffer(0)
, depth_stencil(0)
, texture_type(texture_type)
, format(format)
, fsaa_samples(fsaa)
, fsaa_dirty(false)
{
@@ -534,15 +532,19 @@ bool Canvas::loadVolatile()
GLint internalformat;
GLenum textype;
switch (texture_type)
switch (format)
{
case TYPE_HDR:
case Texture::FORMAT_HDR:
internalformat = GL_RGBA16F;
textype = GL_FLOAT;
break;
case TYPE_NORMAL:
case Texture::FORMAT_SRGB:
internalformat = GL_SRGB_ALPHA;
textype = GL_UNSIGNED_BYTE;
break;
case Texture::FORMAT_NORMAL:
default:
internalformat = GL_RGBA8;
internalformat = GL_RGBA;
textype = GL_UNSIGNED_BYTE;
}
@@ -682,20 +684,30 @@ void Canvas::setupGrab()
if (current == this)
return;
// cleanup after previous fbo
if (current != NULL)
current->stopGrab();
// cleanup after previous Canvas
if (current != nullptr)
{
systemViewport = current->systemViewport;
current->stopGrab(true);
}
else
systemViewport = gl.getViewport();
// indicate we are using this Canvas.
current = this;
// bind the framebuffer object.
systemViewport = gl.getViewport();
strategy->bindFBO(fbo);
gl.setViewport(OpenGL::Viewport(0, 0, width, height));
// Set up orthographic view (no depth)
gl.matrices.projection.push(Matrix::ortho(0.0, width, 0.0, height));
// indicate we are using this fbo
current = this;
// Make sure the correct sRGB setting is used when drawing to the canvas.
if (format == FORMAT_SRGB)
glEnable(GL_FRAMEBUFFER_SRGB);
else if (screenHasSRGB)
glDisable(GL_FRAMEBUFFER_SRGB);
if (fsaa_buffer != 0)
fsaa_dirty = true;
@@ -712,7 +724,7 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
if (!isMultiCanvasSupported())
throw love::Exception("Multi-canvas rendering is not supported on this system.");
if (canvases.size()+1 > size_t(maxDrawBuffers) || canvases.size()+1 > size_t(maxFBOColorAttachments))
if ((int) canvases.size() + 1 > gl.getMaxRenderTargets())
throw love::Exception("This system can't simultaniously render to %d canvases.", canvases.size()+1);
if (fsaa_samples != 0)
@@ -724,8 +736,8 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
if (canvases[i]->getWidth() != width || canvases[i]->getHeight() != height)
throw love::Exception("All canvas arguments must have the same dimensions.");
if (canvases[i]->getTextureType() != texture_type)
throw love::Exception("All canvas arguments must have the same texture type.");
if (canvases[i]->getTextureFormat() != format)
throw love::Exception("All canvas arguments must have the same texture format.");
if (canvases[i]->getFSAA() != 0)
throw love::Exception("Multi-canvas rendering is not supported with FSAA.");
@@ -769,7 +781,7 @@ void Canvas::startGrab()
attachedCanvases.clear();
}
void Canvas::stopGrab()
void Canvas::stopGrab(bool switchingToOtherCanvas)
{
// i am not grabbing. leave me alone
if (current != this)
@@ -782,13 +794,25 @@ void Canvas::stopGrab()
glDiscardFramebufferEXT(GL_FRAMEBUFFER, 2, attachments);
}
// bind default
strategy->bindFBO(gl.getDefaultFBO());
if (switchingToOtherCanvas)
{
if (format == FORMAT_SRGB)
glDisable(GL_FRAMEBUFFER_SRGB);
}
else
{
// bind the default framebuffer.
strategy->bindFBO(gl.getDefaultFBO());
current = nullptr;
gl.setViewport(systemViewport);
if (format == FORMAT_SRGB && !screenHasSRGB)
glDisable(GL_FRAMEBUFFER_SRGB);
else if (format != FORMAT_SRGB && screenHasSRGB)
glEnable(GL_FRAMEBUFFER_SRGB);
}
gl.matrices.projection.pop();
current = nullptr;
gl.setViewport(systemViewport);
}
void Canvas::clear(Color c)
@@ -959,6 +983,18 @@ bool Canvas::isHDRSupported()
return GLAD_VERSION_3_0 || (isSupported() && GLAD_ARB_texture_float);
}
bool Canvas::isSRGBSupported()
{
if (GLAD_VERSION_3_0)
return true;
if (!isSupported())
return false;
return (GLAD_ARB_framebuffer_sRGB || GLAD_EXT_framebuffer_sRGB)
&& GLAD_EXT_texture_sRGB;
}
bool Canvas::isMultiCanvasSupported()
{
// system must support at least 4 simultanious active canvases.
@@ -971,23 +1007,6 @@ void Canvas::bindDefaultCanvas()
current->stopGrab();
}
bool Canvas::getConstant(const char *in, Canvas::TextureType &out)
{
return textureTypes.find(in, out);
}
bool Canvas::getConstant(Canvas::TextureType in, const char *&out)
{
return textureTypes.find(in, out);
}
StringMap<Canvas::TextureType, Canvas::TYPE_MAX_ENUM>::Entry Canvas::textureTypeEntries[] =
{
{"normal", Canvas::TYPE_NORMAL},
{"hdr", Canvas::TYPE_HDR},
};
StringMap<Canvas::TextureType, Canvas::TYPE_MAX_ENUM> Canvas::textureTypes(Canvas::textureTypeEntries, sizeof(Canvas::textureTypeEntries));
} // opengl
} // graphics
} // love
+10 -18
View File
@@ -39,14 +39,7 @@ class Canvas : public Texture
{
public:
enum TextureType
{
TYPE_NORMAL,
TYPE_HDR,
TYPE_MAX_ENUM
};
Canvas(int width, int height, TextureType texture_type = TYPE_NORMAL, int fsaa = 0);
Canvas(int width, int height, Texture::Format format = Texture::FORMAT_NORMAL, int fsaa = 0);
virtual ~Canvas();
// Implements Volatile.
@@ -69,7 +62,7 @@ public:
**/
void startGrab(const std::vector<Canvas *> &canvases);
void startGrab();
void stopGrab();
void stopGrab(bool switchingToOtherCanvas = false);
void clear(Color c);
@@ -92,9 +85,9 @@ public:
return status;
}
inline TextureType getTextureType() const
inline Texture::Format getTextureFormat() const
{
return texture_type;
return format;
}
inline int getFSAA() const
@@ -106,17 +99,18 @@ public:
static bool isSupported();
static bool isHDRSupported();
static bool isSRGBSupported();
static bool isMultiCanvasSupported();
static bool getConstant(const char *in, TextureType &out);
static bool getConstant(TextureType in, const char *&out);
static Canvas *current;
static void bindDefaultCanvas();
// The viewport dimensions of the system (default) framebuffer.
static OpenGL::Viewport systemViewport;
// Whether the main screen should have linear -> sRGB conversions enabled.
static bool screenHasSRGB;
private:
bool createFSAAFBO(GLenum internalformat);
@@ -128,7 +122,7 @@ private:
GLuint fsaa_buffer;
GLuint depth_stencil;
TextureType texture_type;
Format format;
GLenum status;
@@ -140,9 +134,7 @@ private:
void setupGrab();
void drawv(const Matrix &t, const Vertex *v);
static StringMap<TextureType, TYPE_MAX_ENUM>::Entry textureTypeEntries[];
static StringMap<TextureType, TYPE_MAX_ENUM> textureTypes;
};
}; // Canvas
} // opengl
} // graphics
@@ -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;
OpenGL::BlendState state = gl.getBlendState();
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);
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)
@@ -81,6 +81,8 @@ struct DisplayState
// Color mask.
bool colorMask[4];
bool wireframe;
// Default values.
DisplayState()
{
@@ -93,6 +95,7 @@ struct DisplayState
pointStyle = Graphics::POINT_SMOOTH;
scissor = false;
colorMask[0] = colorMask[1] = colorMask[2] = colorMask[3] = true;
wireframe = false;
}
};
@@ -112,7 +115,7 @@ public:
void restoreState(const DisplayState &s);
virtual void setViewportSize(int width, int height);
virtual bool setMode(int width, int height);
virtual bool setMode(int width, int height, bool &sRGB);
virtual void unSetMode();
void setDebug(bool enable);
@@ -191,8 +194,8 @@ public:
/**
* Creates an Image object with padding and/or optimization.
**/
Image *newImage(love::image::ImageData *data);
Image *newImage(love::image::CompressedData *cdata);
Image *newImage(love::image::ImageData *data, Texture::Format format = Texture::FORMAT_NORMAL);
Image *newImage(love::image::CompressedData *cdata, Texture::Format format = Texture::FORMAT_NORMAL);
Quad *newQuad(Quad::Viewport v, float sw, float sh);
@@ -205,7 +208,7 @@ public:
ParticleSystem *newParticleSystem(Texture *texture, int size);
Canvas *newCanvas(int width, int height, Canvas::TextureType texture_type = Canvas::TYPE_NORMAL, int fsaa = 0);
Canvas *newCanvas(int width, int height, Texture::Format format = Texture::FORMAT_NORMAL, int fsaa = 0);
Shader *newShader(const Shader::ShaderSources &sources);
@@ -334,6 +337,19 @@ public:
**/
PointStyle getPointStyle() const;
/**
* Sets whether graphics will be drawn as wireframe lines instead of filled
* triangles (has no effect for drawn points.)
* This should only be used as a debugging tool. The wireframe lines do not
* behave the same as regular love.graphics lines.
**/
void setWireframe(bool enable);
/**
* Gets whether wireframe drawing mode is enabled.
**/
bool isWireframe() const;
/**
* Draws text at the specified coordinates, with rotation and
* scaling along both axes.
@@ -459,6 +475,7 @@ private:
float lineWidth;
size_t matrixLimit;
bool colorMask[4];
bool wireframe;
int width;
int height;
+41 -10
View File
@@ -36,7 +36,7 @@ float Image::maxMipmapSharpness = 0.0f;
Texture::FilterMode Image::defaultMipmapFilter = Texture::FILTER_NONE;
float Image::defaultMipmapSharpness = 0.0f;
Image::Image(love::image::ImageData *data)
Image::Image(love::image::ImageData *data, Texture::Format format)
: data(data)
, cdata(nullptr)
, paddedWidth(width)
@@ -45,6 +45,7 @@ Image::Image(love::image::ImageData *data)
, mipmapSharpness(defaultMipmapSharpness)
, mipmapsCreated(false)
, compressed(false)
, format(format)
, usingDefaultTexture(false)
{
width = data->getWidth();
@@ -54,7 +55,7 @@ Image::Image(love::image::ImageData *data)
preload();
}
Image::Image(love::image::CompressedData *cdata)
Image::Image(love::image::CompressedData *cdata, Texture::Format format)
: data(nullptr)
, cdata(cdata)
, paddedWidth(width)
@@ -63,6 +64,7 @@ Image::Image(love::image::CompressedData *cdata)
, mipmapSharpness(defaultMipmapSharpness)
, mipmapsCreated(false)
, compressed(true)
, format(format)
, usingDefaultTexture(false)
{
width = cdata->getWidth(0);
@@ -328,6 +330,9 @@ void Image::unload()
bool Image::loadVolatile()
{
if (format == FORMAT_SRGB && !hasSRGBSupport())
throw love::Exception("sRGB images are not supported on this system.");
if (isCompressed() && cdata && !hasCompressedTextureSupport(cdata->getFormat()))
{
const char *str;
@@ -400,9 +405,10 @@ void Image::uploadTexturePadded()
}
else if (data)
{
GLenum iformat = (format == FORMAT_SRGB) ? GL_SRGB_ALPHA : GL_RGBA;
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGBA,
iformat,
(GLsizei)paddedWidth,
(GLsizei)paddedHeight,
0,
@@ -437,9 +443,10 @@ void Image::uploadTexture()
}
else if (data)
{
GLenum iformat = (format == FORMAT_SRGB) ? GL_SRGB_ALPHA : GL_RGBA;
glTexImage2D(GL_TEXTURE_2D,
0,
GL_RGBA,
iformat,
(GLsizei)width,
(GLsizei)height,
0,
@@ -497,6 +504,11 @@ bool Image::refresh()
return true;
}
Texture::Format Image::getFormat() const
{
return format;
}
void Image::uploadDefaultTexture()
{
usingDefaultTexture = true;
@@ -561,16 +573,27 @@ bool Image::isCompressed() const
return compressed;
}
GLenum Image::getCompressedFormat(image::CompressedData::Format format) const
GLenum Image::getCompressedFormat(image::CompressedData::Format cformat) const
{
switch (format)
bool srgb = format == FORMAT_SRGB;
switch (cformat)
{
case image::CompressedData::FORMAT_DXT1:
return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
if (srgb)
return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
else
return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
case image::CompressedData::FORMAT_DXT3:
return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
if (srgb)
return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
else
return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
case image::CompressedData::FORMAT_DXT5:
return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
if (srgb)
return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
else
return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
case image::CompressedData::FORMAT_BC4:
return GL_COMPRESSED_RED_RGTC1;
case image::CompressedData::FORMAT_BC4s:
@@ -580,7 +603,10 @@ GLenum Image::getCompressedFormat(image::CompressedData::Format format) const
case image::CompressedData::FORMAT_BC5s:
return GL_COMPRESSED_SIGNED_RG_RGTC2;
default:
return GL_RGBA;
if (srgb)
return GL_SRGB_ALPHA;
else
return GL_RGBA;
}
}
@@ -624,6 +650,11 @@ bool Image::hasCompressedTextureSupport(image::CompressedData::Format format)
return false;
}
bool Image::hasSRGBSupport()
{
return GLAD_VERSION_2_1 || GLAD_EXT_texture_sRGB || GLAD_EXT_sRGB;
}
} // opengl
} // graphics
} // love
+10 -3
View File
@@ -56,14 +56,14 @@ public:
*
* @param data The data from which to load the image.
**/
Image(love::image::ImageData *data);
Image(love::image::ImageData *data, Texture::Format format = Texture::FORMAT_NORMAL);
/**
* Creates a new Image with compressed image data.
*
* @param cdata The compressed data from which to load the image.
**/
Image(love::image::CompressedData *cdata);
Image(love::image::CompressedData *cdata, Texture::Format format = Texture::FORMAT_NORMAL);
/**
* Destructor. Deletes the hardware texture and other resources.
@@ -120,6 +120,8 @@ public:
**/
bool refresh();
Texture::Format getFormat() const;
static void setDefaultMipmapSharpness(float sharpness);
static float getDefaultMipmapSharpness();
static void setDefaultMipmapFilter(FilterMode f);
@@ -132,6 +134,8 @@ public:
static bool hasCompressedTextureSupport(image::CompressedData::Format format);
static bool hasSRGBSupport();
private:
void uploadDefaultTexture();
@@ -161,6 +165,9 @@ private:
// Whether this Image is using a compressed texture.
bool compressed;
// The format to interpret the texture's data as.
Texture::Format format;
// True if the image wasn't able to be properly created and it had to fall
// back to a default texture.
bool usingDefaultTexture;
@@ -179,7 +186,7 @@ private:
static FilterMode defaultMipmapFilter;
static float defaultMipmapSharpness;
GLenum getCompressedFormat(image::CompressedData::Format format) const;
GLenum getCompressedFormat(image::CompressedData::Format cformat) const;
}; // Image
@@ -44,7 +44,6 @@ Mesh::Mesh(const std::vector<Vertex> &verts, Mesh::DrawMode mode)
, range_max(-1)
, texture(nullptr)
, colors_enabled(false)
, wireframe(false)
{
setVertices(verts);
}
@@ -59,7 +58,6 @@ Mesh::Mesh(int vertexcount, Mesh::DrawMode mode)
, range_max(-1)
, texture(nullptr)
, colors_enabled(false)
, wireframe(false)
{
if (vertexcount < 1)
throw love::Exception("Invalid number of vertices.");
@@ -278,16 +276,6 @@ bool Mesh::hasVertexColors() const
return colors_enabled;
}
void Mesh::setWireframe(bool enable)
{
wireframe = enable;
}
bool Mesh::isWireframe() const
{
return wireframe;
}
void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky)
{
const size_t pos_offset = offsetof(Vertex, x);
@@ -326,9 +314,6 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo
gl.setVertexAttribArray(OpenGL::ATTRIB_COLOR, 4, GL_UNSIGNED_BYTE, sizeof(Vertex), vbo->getPointer(color_offset));
}
if (wireframe && GLAD_VERSION_1_0)
glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
GLenum mode = getGLDrawMode(draw_mode);
gl.prepareDraw();
@@ -377,9 +362,6 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo
gl.disableVertexAttribArray(OpenGL::ATTRIB_POS);
gl.disableVertexAttribArray(OpenGL::ATTRIB_TEXCOORD);
if (wireframe && GLAD_VERSION_1_0)
glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
if (hasVertexColors())
{
gl.disableVertexAttribArray(OpenGL::ATTRIB_COLOR);
@@ -162,15 +162,6 @@ public:
void setVertexColors(bool enable);
bool hasVertexColors() const;
/**
* Sets whether the Mesh will be drawn as wireframe lines instead of filled
* triangles (has no effect for DRAW_MODE_POINTS.)
* This should only be used as a debugging tool. The wireframe lines do not
* behave the same as regular love.graphics lines.
**/
void setWireframe(bool enable);
bool isWireframe() const;
// Implements Drawable.
void draw(float x, float y, float angle, float sx, float sy, float ox, float oy, float kx, float ky);
@@ -201,8 +192,6 @@ private:
// Whether the per-vertex colors are used when drawing.
bool colors_enabled;
bool wireframe;
static StringMap<DrawMode, DRAW_MODE_MAX_ENUM>::Entry drawModeEntries[];
static StringMap<DrawMode, DRAW_MODE_MAX_ENUM> drawModes;
@@ -127,6 +127,9 @@ bool OpenGL::initContext()
if (Canvas::isSupported())
glGetIntegerv(GL_DRAW_FRAMEBUFFER_BINDING, (GLint *) &state.defaultFBO);
BlendState blend = {GL_ONE, GL_ONE, GL_ZERO, GL_ZERO, GL_FUNC_ADD};
setBlendState(blend);
initMaxValues();
createDefaultTexture();
@@ -492,6 +495,40 @@ OpenGL::Viewport OpenGL::getScissor() const
return state.scissor;
}
void OpenGL::setBlendState(const BlendState &blend)
{
if (GLAD_ES_VERSION_2_0 || GLAD_VERSION_1_4)
glBlendEquation(blend.func);
else if (GLAD_EXT_blend_minmax && GLAD_EXT_blend_subtract)
glBlendEquationEXT(blend.func);
else
{
if (blend.func == GL_FUNC_REVERSE_SUBTRACT)
throw love::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 (blend.srcRGB == blend.srcA && blend.dstRGB == blend.dstA)
glBlendFunc(blend.srcRGB, blend.dstRGB);
else
{
if (GLAD_ES_VERSION_2_0 || GLAD_VERSION_1_4)
glBlendFuncSeparate(blend.srcRGB, blend.dstRGB, blend.srcA, blend.dstA);
else if (GLAD_EXT_blend_func_separate)
glBlendFuncSeparateEXT(blend.srcRGB, blend.dstRGB, blend.srcA, blend.dstA);
else
throw love::Exception("This graphics card does not support separated rgb and alpha blend functions!");
}
state.blend = blend;
}
OpenGL::BlendState OpenGL::getBlendState() const
{
return state.blend;
}
void OpenGL::setPointSize(float size)
{
if (GLAD_VERSION_1_0)
@@ -103,6 +103,13 @@ public:
}
};
struct BlendState
{
GLenum srcRGB, srcA;
GLenum dstRGB, dstA;
GLenum func;
};
// Transformation matrix stacks.
struct
{
@@ -202,6 +209,17 @@ public:
**/
Viewport getScissor() const;
/**
* Sets blending functionality.
* Note: This does not globally enable or disable blending.
**/
void setBlendState(const BlendState &blend);
/**
* Gets the currently set blending functionality.
**/
BlendState getBlendState() const;
/**
* Sets the global point size.
**/
@@ -332,6 +350,8 @@ private:
GLuint defaultFBO;
BlendState blend;
// The last ID value used for pseudo-instancing.
int lastPseudoInstanceID;
@@ -95,6 +95,7 @@ ParticleSystem::ParticleSystem(Texture *texture, uint32 size)
, spinVariation(0)
, offsetX(float(texture->getWidth())*0.5f)
, offsetY(float(texture->getHeight())*0.5f)
, relativeRotation(false)
{
if (size == 0 || size > MAX_PARTICLES)
throw love::Exception("Invalid ParticleSystem size.");
@@ -146,6 +147,7 @@ ParticleSystem::ParticleSystem(const ParticleSystem &p)
, offsetX(p.offsetX)
, offsetY(p.offsetY)
, colors(p.colors)
, relativeRotation(p.relativeRotation)
{
setBufferSize(maxParticles);
@@ -170,7 +172,7 @@ void ParticleSystem::createBuffers(size_t size)
{
try
{
pFree = pMem = new particle[size];
pFree = pMem = new Particle[size];
particleVerts = new love::Vertex[size * 4];
ibo = new VertexIndex(size);
maxParticles = (uint32) size;
@@ -222,7 +224,7 @@ void ParticleSystem::addParticle(float t)
return;
// Gets a free particle and updates the allocation pointer.
particle *p = pFree++;
Particle *p = pFree++;
initParticle(p, t);
switch (insertMode)
@@ -242,7 +244,7 @@ void ParticleSystem::addParticle(float t)
activeParticles++;
}
void ParticleSystem::initParticle(particle *p, float t)
void ParticleSystem::initParticle(Particle *p, float t)
{
float min,max;
@@ -308,10 +310,14 @@ void ParticleSystem::initParticle(particle *p, float t)
p->spinEnd = calculate_variation(spinEnd, spinStart, spinVariation);
p->rotation = (float) rng.random(min, max);
p->angle = p->rotation;
if (relativeRotation)
p->angle += atan2f(p->speed.y, p->speed.x);
p->color = colors[0];
}
void ParticleSystem::insertTop(particle *p)
void ParticleSystem::insertTop(Particle *p)
{
if (pHead == nullptr)
{
@@ -327,7 +333,7 @@ void ParticleSystem::insertTop(particle *p)
pTail = p;
}
void ParticleSystem::insertBottom(particle *p)
void ParticleSystem::insertBottom(Particle *p)
{
if (pTail == nullptr)
{
@@ -343,7 +349,7 @@ void ParticleSystem::insertBottom(particle *p)
pHead = p;
}
void ParticleSystem::insertRandom(particle *p)
void ParticleSystem::insertRandom(Particle *p)
{
// Nonuniform, but 64-bit is so large nobody will notice. Hopefully.
uint64 pos = rng.rand() % ((int64) activeParticles + 1);
@@ -351,7 +357,7 @@ void ParticleSystem::insertRandom(particle *p)
// Special case where the particle gets inserted before the head.
if (pos == activeParticles)
{
particle *pA = pHead;
Particle *pA = pHead;
if (pA)
pA->prev = p;
p->prev = nullptr;
@@ -361,8 +367,8 @@ void ParticleSystem::insertRandom(particle *p)
}
// Inserts the particle after the randomly selected particle.
particle *pA = pMem + pos;
particle *pB = pA->next;
Particle *pA = pMem + pos;
Particle *pB = pA->next;
pA->next = p;
if (pB)
pB->prev = p;
@@ -372,12 +378,12 @@ void ParticleSystem::insertRandom(particle *p)
p->next = pB;
}
ParticleSystem::particle *ParticleSystem::removeParticle(particle *p)
ParticleSystem::Particle *ParticleSystem::removeParticle(Particle *p)
{
// The linked list is updated in this function and old pointers may be
// invalidated. The returned pointer will inform the caller of the new
// pointer to the next particle.
particle *pNext = nullptr;
Particle *pNext = nullptr;
// Removes the particle from the linked list.
if (p->prev)
@@ -725,6 +731,16 @@ std::vector<Color> ParticleSystem::getColor() const
return ncolors;
}
void ParticleSystem::setRelativeRotation(bool enable)
{
relativeRotation = enable;
}
bool ParticleSystem::hasRelativeRotation() const
{
return relativeRotation;
}
uint32 ParticleSystem::getCount() const
{
return activeParticles;
@@ -812,13 +828,13 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo
const Vertex *textureVerts = texture->getVertices();
Vertex *pVerts = particleVerts;
particle *p = pHead;
Particle *p = pHead;
// set the vertex data for each particle (transformation, texcoords, color)
while (p)
{
// particle vertices are image vertices transformed by particle information
t.setTransformation(p->position[0], p->position[1], p->rotation, p->size, p->size, offsetX, offsetY, 0.0f, 0.0f);
t.setTransformation(p->position[0], p->position[1], p->angle, p->size, p->size, offsetX, offsetY, 0.0f, 0.0f);
t.transform(pVerts, textureVerts, 4);
// set the texture coordinate and color data for particle vertices
@@ -871,7 +887,7 @@ void ParticleSystem::update(float dt)
return;
// Traverse all particles and update.
particle *p = pHead;
Particle *p = pHead;
while (p)
{
@@ -916,7 +932,12 @@ void ParticleSystem::update(float dt)
const float t = 1.0f - p->life / p->lifetime;
// Rotate.
p->rotation += (p->spinStart * (1.0f - t) + p->spinEnd * t)*dt;
p->rotation += (p->spinStart * (1.0f - t) + p->spinEnd * t) * dt;
p->angle = p->rotation;
if (relativeRotation)
p->angle += atan2f(p->speed.y, p->speed.x);
// Change size according to given intervals:
// i = 0 1 2 3 n-1
@@ -422,6 +422,12 @@ public:
**/
std::vector<Color> getColor() const;
/**
* sets whether particle angles & rotations are relative to their velocities.
**/
void setRelativeRotation(bool enable);
bool hasRelativeRotation() const;
/**
* Returns the amount of particles that are currently active in the system.
**/
@@ -495,11 +501,12 @@ public:
static bool getConstant(InsertMode in, const char *&out);
protected:
// Represents a single particle.
struct particle
struct Particle
{
particle *prev;
particle *next;
Particle *prev;
Particle *next;
float lifetime;
float life;
@@ -519,7 +526,8 @@ protected:
float sizeOffset;
float sizeIntervalSize;
float rotation;
float rotation; // Amount of rotation applied to the final angle.
float angle;
float spinStart;
float spinEnd;
@@ -527,16 +535,16 @@ protected:
};
// Pointer to the beginning of the allocated memory.
particle *pMem;
Particle *pMem;
// Pointer to a free particle.
particle *pFree;
Particle *pFree;
// Pointer to the start of the linked list.
particle *pHead;
Particle *pHead;
// Pointer to the end of the linked list.
particle *pTail;
Particle *pTail;
// array of transformed vertex data for all particles, for drawing
Vertex *particleVerts;
@@ -621,17 +629,19 @@ protected:
// Color.
std::vector<Colorf> colors;
bool relativeRotation;
void createBuffers(size_t size);
void deleteBuffers();
void addParticle(float t);
particle *removeParticle(particle *p);
Particle *removeParticle(Particle *p);
// Called by addParticle.
void initParticle(particle *p, float t);
void insertTop(particle *p);
void insertBottom(particle *p);
void insertRandom(particle *p);
void initParticle(Particle *p, float t);
void insertTop(Particle *p);
void insertBottom(Particle *p);
void insertRandom(Particle *p);
static StringMap<AreaSpreadDistribution, DISTRIBUTION_MAX_ENUM>::Entry distributionsEntries[];
static StringMap<AreaSpreadDistribution, DISTRIBUTION_MAX_ENUM> distributions;
@@ -105,6 +105,8 @@ int SpriteBatch::add(float x, float y, float a, float sx, float sy, float ox, fl
if ((index == -1 && next >= size) || index < -1 || index >= size)
return -1;
Vertex sprite[4];
// Needed for colors.
memcpy(sprite, texture->getVertices(), sizeof(Vertex) * 4);
@@ -131,6 +133,8 @@ int SpriteBatch::addq(Quad *quad, float x, float y, float a, float sx, float sy,
if ((index == -1 && next >= size) || index < -1 || index >= next)
return -1;
Vertex sprite[4];
// Needed for colors.
memcpy(sprite, quad->getVertices(), sizeof(Vertex) * 4);
@@ -135,8 +135,6 @@ private:
// The next free element.
int next;
Vertex sprite[4];
// Current color. This color, if present, will be applied to the next
// added sprite.
Color *color;
@@ -110,12 +110,14 @@ int w_Canvas_clear(lua_State *L)
return 0;
}
int w_Canvas_getType(lua_State *L)
int w_Canvas_getFormat(lua_State *L)
{
Canvas *canvas = luax_checkcanvas(L, 1);
Canvas::TextureType type = canvas->getTextureType();
Texture::Format format = canvas->getTextureFormat();
const char *str;
Canvas::getConstant(type, str);
if (!Texture::getConstant(format, str))
return luaL_error(L, "Unknown texture format.");
lua_pushstring(L, str);
return 1;
}
@@ -142,8 +144,11 @@ static const luaL_Reg functions[] =
{ "getImageData", w_Canvas_getImageData },
{ "getPixel", w_Canvas_getPixel },
{ "clear", w_Canvas_clear },
{ "getType", w_Canvas_getType },
{ "getFormat", w_Canvas_getFormat },
{ "getFSAA", w_Canvas_getFSAA },
// Deprecated since 0.9.1.
{ "getType", w_Canvas_getFormat },
{ 0, 0 }
};
@@ -39,7 +39,7 @@ int w_Canvas_renderTo(lua_State *L);
int w_Canvas_getImageData(lua_State *L);
int w_Canvas_getPixel(lua_State * L);
int w_Canvas_clear(lua_State *L);
int w_Canvas_getType(lua_State *L);
int w_Canvas_getFormat(lua_State *L);
int w_Canvas_getFSAA(lua_State *L);
extern "C" int luaopen_canvas(lua_State *L);
@@ -152,8 +152,17 @@ int w_getMaxTextureSize(lua_State *L)
int w_newImage(lua_State *L)
{
love::image::ImageData *data = 0;
love::image::CompressedData *cdata = 0;
love::image::ImageData *data = nullptr;
love::image::CompressedData *cdata = nullptr;
Texture::Format format = Texture::FORMAT_NORMAL;
const char *fstr = lua_isnoneornil(L, 2) ? nullptr : luaL_checkstring(L, 2);
if (fstr != nullptr && !Texture::getConstant(fstr, format))
return luaL_error(L, "Invalid texture format: %s", fstr);
if (format == Texture::FORMAT_HDR) // For now...
return luaL_error(L, "HDR images are not supported.");
// Convert to FileData, if necessary.
if (lua_isstring(L, 1) || luax_istype(L, 1, FILESYSTEM_FILE_T))
@@ -185,15 +194,15 @@ int w_newImage(lua_State *L)
return luaL_error(L, "Error creating image.");
// Create the image.
Image *image = 0;
Image *image = nullptr;
EXCEPT_GUARD(
if (cdata)
image = instance->newImage(cdata);
image = instance->newImage(cdata, format);
else if (data)
image = instance->newImage(data);
image = instance->newImage(data, format);
)
if (image == 0)
if (image == nullptr)
return luaL_error(L, "Could not load image.");
// Push the type.
@@ -325,12 +334,12 @@ int w_newCanvas(lua_State *L)
const char *str = luaL_optstring(L, 3, "normal");
int fsaa = luaL_optint(L, 4, 0);
Canvas::TextureType texture_type;
if (!Canvas::getConstant(str, texture_type))
return luaL_error(L, "Invalid canvas type: %s", str);
Texture::Format format;
if (!Texture::getConstant(str, format))
return luaL_error(L, "Invalid texture format: %s", str);
Canvas *canvas = nullptr;
EXCEPT_GUARD(canvas = instance->newCanvas(width, height, texture_type, fsaa);)
EXCEPT_GUARD(canvas = instance->newCanvas(width, height, format, fsaa);)
if (canvas == nullptr)
return luaL_error(L, "Canvas not created, but no error thrown. I don't even...");
@@ -835,6 +844,18 @@ int w_getMaxPointSize(lua_State *L)
return 1;
}
int w_setWireframe(lua_State *L)
{
instance->setWireframe(luax_toboolean(L, 1));
return 0;
}
int w_isWireframe(lua_State *L)
{
luax_pushboolean(L, instance->isWireframe());
return 1;
}
int w_newScreenshot(lua_State *L)
{
love::image::Image *image = luax_getmodule<love::image::Image>(L, "image", MODULE_IMAGE_T);
@@ -1029,6 +1050,10 @@ int w_isSupported(lua_State *L)
if (!(GLAD_ARB_draw_instanced || (GLAD_ES_VERSION_2_0 && GLAD_EXT_draw_instanced)))
supported = false;
break;
case Graphics::SUPPORT_SRGB:
if (!Canvas::isSRGBSupported())
supported = false;
break;
default:
supported = false;
}
@@ -1405,6 +1430,8 @@ static const luaL_Reg functions[] =
{ "setPointStyle", w_setPointStyle },
{ "getPointSize", w_getPointSize },
{ "getPointStyle", w_getPointStyle },
{ "setWireframe", w_setWireframe },
{ "isWireframe", w_isWireframe },
{ "newScreenshot", w_newScreenshot },
{ "setCanvas", w_setCanvas },
{ "getCanvas", w_getCanvas },
@@ -85,6 +85,8 @@ int w_setPointStyle(lua_State *L);
int w_getPointSize(lua_State *L);
int w_getPointStyle(lua_State *L);
int w_getMaxPointSize(lua_State *L);
int w_setWireframe(lua_State *L);
int w_isWireframe(lua_State *L);
int w_newScreenshot(lua_State *L);
int w_setCanvas(lua_State *L);
int w_getCanvas(lua_State *L);
@@ -361,20 +361,6 @@ int w_Mesh_hasVertexColors(lua_State *L)
return 1;
}
int w_Mesh_setWireframe(lua_State *L)
{
Mesh *t = luax_checkmesh(L, 1);
t->setWireframe(luax_toboolean(L, 2));
return 0;
}
int w_Mesh_isWireframe(lua_State *L)
{
Mesh *t = luax_checkmesh(L, 1);
luax_pushboolean(L, t->isWireframe());
return 1;
}
static const luaL_Reg functions[] =
{
{ "setVertex", w_Mesh_setVertex },
@@ -394,8 +380,6 @@ static const luaL_Reg functions[] =
{ "getDrawRange", w_Mesh_getDrawRange },
{ "setVertexColors", w_Mesh_setVertexColors },
{ "hasVertexColors", w_Mesh_hasVertexColors },
{ "setWireframe", w_Mesh_setWireframe },
{ "isWireframe", w_Mesh_isWireframe },
// Deprecated since 0.9.1.
{ "setImage", w_Mesh_setTexture },
@@ -51,8 +51,6 @@ int w_Mesh_setDrawRange(lua_State *L);
int w_Mesh_getDrawRange(lua_State *L);
int w_Mesh_setVertexColors(lua_State *L);
int w_Mesh_hasVertexColors(lua_State *L);
int w_Mesh_setWireframe(lua_State *L);
int w_Mesh_isWireframe(lua_State *L);
extern "C" int luaopen_mesh(lua_State *L);
@@ -569,6 +569,20 @@ int w_ParticleSystem_getColors(lua_State *L)
return colors.size();
}
int w_ParticleSystem_setRelativeRotation(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
t->setRelativeRotation(luax_toboolean(L, 2));
return 0;
}
int w_ParticleSystem_hasRelativeRotation(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
luax_pushboolean(L, t->hasRelativeRotation());
return 1;
}
int w_ParticleSystem_getCount(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
@@ -687,6 +701,8 @@ static const luaL_Reg functions[] =
{ "getColors", w_ParticleSystem_getColors },
{ "setOffset", w_ParticleSystem_setOffset },
{ "getOffset", w_ParticleSystem_getOffset },
{ "setRelativeRotation", w_ParticleSystem_setRelativeRotation },
{ "hasRelativeRotation", w_ParticleSystem_hasRelativeRotation },
{ "getCount", w_ParticleSystem_getCount },
{ "start", w_ParticleSystem_start },
{ "stop", w_ParticleSystem_stop },
@@ -77,6 +77,8 @@ int w_ParticleSystem_setColors(lua_State *L);
int w_ParticleSystem_getColors(lua_State *L);
int w_ParticleSystem_setOffset(lua_State *L);
int w_ParticleSystem_getOffset(lua_State *L);
int w_ParticleSystem_setRelativeRotation(lua_State *L);
int w_ParticleSystem_hasRelativeRotation(lua_State *L);
int w_ParticleSystem_getCount(lua_State *L);
int w_ParticleSystem_start(lua_State *L);
int w_ParticleSystem_stop(lua_State *L);
+30
View File
@@ -193,5 +193,35 @@ bool Math::isConvex(const std::vector<Vertex> &polygon)
return true;
}
/**
* http://en.wikipedia.org/wiki/SRGB#The_reverse_transformation
**/
float Math::gammaToLinear(float c) const
{
if (c > 1.0)
return 1.0;
else if (c < 0.0)
return 0.0;
else if (c <= 0.04045)
return c / 12.92;
else
return powf((c + 0.055) / 1.055, 2.4);
}
/**
* http://en.wikipedia.org/wiki/SRGB#The_forward_transformation_.28CIE_xyY_or_CIE_XYZ_to_sRGB.29
**/
float Math::linearToGamma(float c) const
{
if (c > 1.0)
return 1.0;
else if (c < 0.0)
return 0.0;
else if (c < 0.0031308)
return c * 12.92;
else
return 1.055 * powf(c, 0.41666) - 0.055;
}
} // math
} // love
+30 -20
View File
@@ -53,26 +53,6 @@ public:
virtual ~Math()
{}
inline void setRandomSeed(RandomGenerator::Seed seed)
{
rng.setSeed(seed);
}
inline void setRandomSeed(uint32 low, uint32 high)
{
rng.setSeed(low, high);
}
inline RandomGenerator::Seed getRandomSeed() const
{
return rng.getSeed();
}
inline void getRandomSeed(uint32 &low, uint32 &high) const
{
rng.getSeed(low, high);
}
/**
* @copydoc RandomGenerator::random()
**/
@@ -105,6 +85,26 @@ public:
return rng.randomNormal(stddev);
}
inline void setRandomSeed(RandomGenerator::Seed seed)
{
rng.setSeed(seed);
}
inline RandomGenerator::Seed getRandomSeed() const
{
return rng.getSeed();
}
inline void setRandomState(const std::string &statestr)
{
rng.setState(statestr);
}
inline std::string getRandomState() const
{
return rng.getState();
}
/**
* Create a new random number generator.
**/
@@ -136,6 +136,16 @@ public:
**/
bool isConvex(const std::vector<Vertex> &polygon);
/**
* Converts a value from the sRGB (gamma) colorspace to linear RGB.
**/
float gammaToLinear(float c) const;
/**
* Converts a value from linear RGB to the sRGB (gamma) colorspace.
**/
float linearToGamma(float c) const;
/**
* Calculate Simplex noise for the specified coordinate(s).
*
+76 -20
View File
@@ -20,8 +20,13 @@
#include "RandomGenerator.h"
// STL
// C++
#include <cmath>
#include <sstream>
#include <iomanip>
// C
#include <cstdlib>
namespace love
{
@@ -36,25 +41,10 @@ RandomGenerator::RandomGenerator()
{
// because it is too big for some compilers to handle ... if you know what
// i mean
#ifdef LOVE_BIG_ENDIAN
seed.b32.a = 0x0139408D;
seed.b32.b = 0xCBBF7A44;
#else
seed.b32.b = 0x0139408D;
seed.b32.a = 0xCBBF7A44;
#endif
rng_state = seed;
}
void RandomGenerator::setSeed(RandomGenerator::Seed newseed)
{
// 0 xor 0 is still 0, so Xorshift can't generate new numbers.
if (newseed.b64 == 0)
throw love::Exception("Invalid random seed.");
seed = newseed;
rng_state = seed;
Seed newseed;
newseed.b32.low = 0xCBBF7A44;
newseed.b32.high = 0x0139408D;
setSeed(newseed);
}
uint64 RandomGenerator::rand()
@@ -83,5 +73,71 @@ double RandomGenerator::randomNormal(double stddev)
return r * sin(phi) * stddev;
}
void RandomGenerator::setSeed(RandomGenerator::Seed newseed)
{
// 0 xor 0 is still 0, so Xorshift can't generate new numbers.
if (newseed.b64 == 0)
throw love::Exception("Invalid random seed.");
seed = newseed;
rng_state = seed;
}
RandomGenerator::Seed RandomGenerator::getSeed() const
{
return seed;
}
void RandomGenerator::setState(const std::string &statestr)
{
// For this implementation we'll accept a hex string representing the
// 64-bit state integer xorshift uses.
Seed state = {};
// Hex string must start with 0x.
if (statestr.find("0x") != 0 || statestr.size() < 3)
throw love::Exception("Invalid random state.");
// standardized strtoull (or 64 bit integer support for stringstream)
// requires C++11's standard library, which we can't use yet.
// I use strtol like this not because it's the best solution, but because
// it's "good enough".
// Convert the hex string to the state integer character-by-character.
for (size_t i = 2; i < statestr.size(); i++)
{
char hex[2] = {statestr[i], 0};
char *end = nullptr;
// Convert the current hex character to a number.
int nibble = strtol(hex, &end, 16);
// Check if strtol failed to convert it.
if (end != nullptr && *end != 0)
throw love::Exception("Invalid random state.");
state.b64 = (state.b64 << 4) + nibble;
}
rng_state = state;
}
std::string RandomGenerator::getState() const
{
// For this implementation we'll return a hex string representing the 64-bit
// state integer xorshift uses.
std::stringstream ss;
ss << "0x";
// Again with the stringstream not dealing with 64 bit integers...
ss << std::setfill('0') << std::setw(8) << std::hex << rng_state.b32.high;
ss << std::setfill('0') << std::setw(8) << std::hex << rng_state.b32.low;
return ss.str();
}
} // math
} // love
+31 -43
View File
@@ -28,8 +28,9 @@
#include "common/int.h"
#include "common/Object.h"
// STL
// C++
#include <limits>
#include <string>
namespace love
{
@@ -45,54 +46,19 @@ public:
uint64 b64;
struct
{
uint32 a;
uint32 b;
#ifdef LOVE_BIG_ENDIAN
uint32 high;
uint32 low;
#else
uint32 low;
uint32 high;
#endif
} b32;
};
RandomGenerator();
virtual ~RandomGenerator() {}
/**
* Set pseudo-random seed.
* It's up to the implementation how to use this.
**/
void setSeed(Seed seed);
/**
* Separately set the low and high bits of the pseudo-random seed.
**/
inline void setSeed(uint32 low, uint32 high)
{
Seed newseed;
#ifdef LOVE_BIG_ENDIAN
newseed.b32.a = high;
newseed.b32.b = low;
#else
newseed.b32.b = high;
newseed.b32.a = low;
#endif
setSeed(newseed);
}
inline Seed getSeed() const
{
return seed;
}
inline void getSeed(uint32 &low, uint32 &high) const
{
#ifdef LOVE_BIG_ENDIAN
high = seed.b32.a;
low = seed.b32.b;
#else
high = seed.b32.b;
low = seed.b32.a;
#endif
}
/**
* Return uniformly distributed pseudo random integer.
*
@@ -138,6 +104,28 @@ public:
**/
double randomNormal(double stddev);
/**
* Set pseudo-random seed.
* It's up to the implementation how to use this.
**/
void setSeed(Seed seed);
/**
* Get the previously set pseudo-random seed.
**/
Seed getSeed() const;
/**
* Set the internal implementation-dependent state value based on a string.
**/
void setState(const std::string &statestr);
/**
* Get a string representation of the implementation-dependent internal
* state value.
**/
std::string getState() const;
private:
Seed seed;
+96 -17
View File
@@ -32,21 +32,6 @@ namespace love
namespace math
{
int w_setRandomSeed(lua_State *L)
{
EXCEPT_GUARD(Math::instance.setRandomSeed(luax_checkrandomseed(L, 1));)
return 0;
}
int w_getRandomSeed(lua_State *L)
{
uint32 low = 0, high = 0;
Math::instance.getRandomSeed(low, high);
lua_pushnumber(L, (lua_Number) low);
lua_pushnumber(L, (lua_Number) high);
return 2;
}
int w_random(lua_State *L)
{
return luax_getrandom(L, 1, Math::instance.random());
@@ -62,6 +47,32 @@ int w_randomNormal(lua_State *L)
return 1;
}
int w_setRandomSeed(lua_State *L)
{
EXCEPT_GUARD(Math::instance.setRandomSeed(luax_checkrandomseed(L, 1));)
return 0;
}
int w_getRandomSeed(lua_State *L)
{
RandomGenerator::Seed s = Math::instance.getRandomSeed();
lua_pushnumber(L, (lua_Number) s.b32.low);
lua_pushnumber(L, (lua_Number) s.b32.high);
return 2;
}
int w_setRandomState(lua_State *L)
{
EXCEPT_GUARD(Math::instance.setRandomState(luax_checkstring(L, 1));)
return 0;
}
int w_getRandomState(lua_State *L)
{
luax_pushstring(L, Math::instance.getRandomState());
return 1;
}
int w_newRandomGenerator(lua_State *L)
{
RandomGenerator::Seed s;
@@ -238,6 +249,70 @@ int w_isConvex(lua_State *L)
return 1;
}
static int getGammaArgs(lua_State *L, float color[4])
{
int numcomponents = 0;
if (lua_istable(L, 1))
{
int n = lua_objlen(L, 1);
for (int i = 1; i <= n && i <= 4; i++)
{
lua_rawgeti(L, 1, i);
color[i - 1] = (float) luaL_checknumber(L, -1) / 255.0;
numcomponents++;
}
lua_pop(L, numcomponents);
}
else
{
int n = lua_gettop(L);
for (int i = 1; i <= n && i <= 4; i++)
{
color[i - 1] = (float) luaL_checknumber(L, i) / 255.0;
numcomponents++;
}
}
if (numcomponents == 0)
luaL_checknumber(L, 1);
return numcomponents;
}
int w_gammaToLinear(lua_State *L)
{
float color[4];
int numcomponents = getGammaArgs(L, color);
for (int i = 0; i < numcomponents; i++)
{
// Alpha should always be linear.
if (i < 3)
color[i] = Math::instance.gammaToLinear(color[i]);
lua_pushnumber(L, color[i] * 255);
}
return numcomponents;
}
int w_linearToGamma(lua_State *L)
{
float color[4];
int numcomponents = getGammaArgs(L, color);
for (int i = 0; i < numcomponents; i++)
{
// Alpha should always be linear.
if (i < 3)
color[i] = Math::instance.linearToGamma(color[i]);
lua_pushnumber(L, color[i] * 255);
}
return numcomponents;
}
int w_noise(lua_State *L)
{
float w, x, y, z;
@@ -277,14 +352,18 @@ int w_noise(lua_State *L)
// List of functions to wrap.
static const luaL_Reg functions[] =
{
{ "setRandomSeed", w_setRandomSeed },
{ "getRandomSeed", w_getRandomSeed },
{ "random", w_random },
{ "randomNormal", w_randomNormal },
{ "setRandomSeed", w_setRandomSeed },
{ "getRandomSeed", w_getRandomSeed },
{ "setRandomState", w_setRandomState },
{ "getRandomState", w_getRandomState },
{ "newRandomGenerator", w_newRandomGenerator },
{ "newBezierCurve", w_newBezierCurve },
{ "triangulate", w_triangulate },
{ "isConvex", w_isConvex },
{ "gammaToLinear", w_gammaToLinear },
{ "linearToGamma", w_linearToGamma },
{ "noise", w_noise },
{ 0, 0 }
};
+6 -2
View File
@@ -30,14 +30,18 @@ namespace love
namespace math
{
int w_setRandomSeed(lua_State *L);
int w_getRandomSeed(lua_State *L);
int w_random(lua_State *L);
int w_randomNormal(lua_State *L);
int w_setRandomSeed(lua_State *L);
int w_getRandomSeed(lua_State *L);
int w_setRandomState(lua_State *L);
int w_getRandomState(lua_State *L);
int w_newRandomGenerator(lua_State *L);
int w_newBezierCurve(lua_State *L);
int w_triangulate(lua_State *L);
int w_isConvex(lua_State *L);
int w_gammaToLinear(lua_State *L);
int w_linearToGamma(lua_State *L);
int w_noise(lua_State *L);
extern "C" LOVE_EXPORT int luaopen_love_math(lua_State *L);
@@ -47,16 +47,8 @@ RandomGenerator::Seed luax_checkrandomseed(lua_State *L, int idx)
if (!lua_isnoneornil(L, idx + 1))
{
uint32 low = checkrandomseed_part<uint32>(L, idx);
uint32 high = checkrandomseed_part<uint32>(L, idx + 1);
#ifdef LOVE_BIG_ENDIAN
s.b32.a = high;
s.b32.b = low;
#else
s.b32.b = high;
s.b32.a = low;
#endif
s.b32.low = checkrandomseed_part<uint32>(L, idx);
s.b32.high = checkrandomseed_part<uint32>(L, idx + 1);
}
else
s.b64 = checkrandomseed_part<uint64>(L, idx);
@@ -95,25 +87,6 @@ RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx)
return luax_checktype<RandomGenerator>(L, idx, "RandomGenerator", MATH_RANDOM_GENERATOR_T);
}
int w_RandomGenerator_setSeed(lua_State *L)
{
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
EXCEPT_GUARD(rng->setSeed(luax_checkrandomseed(L, 2));)
return 0;
}
int w_RandomGenerator_getSeed(lua_State *L)
{
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
uint32 low = 0, high = 0;
rng->getSeed(low, high);
lua_pushnumber(L, (lua_Number) low);
lua_pushnumber(L, (lua_Number) high);
return 2;
}
int w_RandomGenerator_random(lua_State *L)
{
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
@@ -132,12 +105,44 @@ int w_RandomGenerator_randomNormal(lua_State *L)
return 1;
}
int w_RandomGenerator_setSeed(lua_State *L)
{
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
EXCEPT_GUARD(rng->setSeed(luax_checkrandomseed(L, 2));)
return 0;
}
int w_RandomGenerator_getSeed(lua_State *L)
{
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
RandomGenerator::Seed s = rng->getSeed();
lua_pushnumber(L, (lua_Number) s.b32.low);
lua_pushnumber(L, (lua_Number) s.b32.high);
return 2;
}
int w_RandomGenerator_setState(lua_State *L)
{
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
EXCEPT_GUARD(rng->setState(luax_checkstring(L, 2));)
return 0;
}
int w_RandomGenerator_getState(lua_State *L)
{
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
luax_pushstring(L, rng->getState());
return 1;
}
static const luaL_Reg functions[] =
{
{ "setSeed", w_RandomGenerator_setSeed },
{ "getSeed", w_RandomGenerator_getSeed },
{ "random", w_RandomGenerator_random },
{ "randomNormal", w_RandomGenerator_randomNormal },
{ "setSeed", w_RandomGenerator_setSeed },
{ "getSeed", w_RandomGenerator_getSeed },
{ "setState", w_RandomGenerator_setState },
{ "getState", w_RandomGenerator_getState },
{ 0, 0 }
};
@@ -36,10 +36,12 @@ RandomGenerator::Seed luax_checkrandomseed(lua_State *L, int idx);
int luax_getrandom(lua_State *L, int startidx, double r);
RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx);
int w_RandomGenerator_setSeed(lua_State *L);
int w_RandomGenerator_getSeed(lua_State *L);
int w_RandomGenerator_random(lua_State *L);
int w_RandomGenerator_randomNormal(lua_State *L);
int w_RandomGenerator_setSeed(lua_State *L);
int w_RandomGenerator_getSeed(lua_State *L);
int w_RandomGenerator_setState(lua_State *L);
int w_RandomGenerator_getState(lua_State *L);
extern "C" int luaopen_randomgenerator(lua_State *L);
} // math
+2
View File
@@ -50,6 +50,7 @@ WindowSettings::WindowSettings()
, centered(true)
, display(0)
, highdpi(false)
, sRGB(false)
{
}
@@ -86,6 +87,7 @@ StringMap<Window::Setting, Window::SETTING_MAX_ENUM>::Entry Window::settingEntri
{"centered", SETTING_CENTERED},
{"display", SETTING_DISPLAY},
{"highdpi", SETTING_HIGHDPI},
{"srgb", SETTING_SRGB},
};
StringMap<Window::Setting, Window::SETTING_MAX_ENUM> Window::settings(Window::settingEntries, sizeof(Window::settingEntries));
+2
View File
@@ -57,6 +57,7 @@ public:
SETTING_CENTERED,
SETTING_DISPLAY,
SETTING_HIGHDPI,
SETTING_SRGB,
SETTING_MAX_ENUM
};
@@ -157,6 +158,7 @@ struct WindowSettings
bool centered; // = true
int display; // = 0
bool highdpi; // false
bool sRGB; // false
}; // WindowSettings
+18 -7
View File
@@ -89,7 +89,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
f.minwidth = std::max(f.minwidth, 1);
f.minheight = std::max(f.minheight, 1);
f.display = std::min(std::max(f.display, 0), getDisplayCount());
f.display = std::min(std::max(f.display, 0), getDisplayCount() - 1);
// Use the desktop resolution if a width or height of 0 is specified.
if (width == 0 || height == 0)
@@ -161,7 +161,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
if (!window)
{
// In Windows and Linux, some GL attributes are set on window creation.
setWindowGLAttributes(f.fsaa);
setWindowGLAttributes(f.fsaa, f.sRGB);
const char *title = windowTitle.c_str();
int pos = f.centered ? centeredpos : uncenteredpos;
@@ -197,7 +197,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
SDL_RaiseWindow(window);
if (!setContext(f.fsaa, f.vsync))
if (!setContext(f.fsaa, f.vsync, f.sRGB))
{
created = false;
return false;
@@ -216,7 +216,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
SDL_GL_GetDrawableSize(window, &width, &height);
#endif
if (!gfx->setMode(width, height))
if (!gfx->setMode(width, height, curMode.settings.sRGB))
displayError("Could not set graphics mode", "Unsupported OpenGL version?");
}
@@ -237,7 +237,7 @@ bool Window::onWindowResize(int width, int height)
return true;
}
bool Window::setContext(int fsaa, bool vsync)
bool Window::setContext(int fsaa, bool vsync, bool sRGB)
{
// We would normally only need to recreate the context if FSAA changes or
// SDL_GL_MakeCurrent is unsuccessful, but in Windows MakeCurrent can
@@ -249,7 +249,7 @@ bool Window::setContext(int fsaa, bool vsync)
}
// Make sure the proper attributes are set.
setWindowGLAttributes(fsaa);
setWindowGLAttributes(fsaa, sRGB);
context = SDL_GL_CreateContext(window);
@@ -301,7 +301,7 @@ bool Window::setContext(int fsaa, bool vsync)
return true;
}
void Window::setWindowGLAttributes(int fsaa) const
void Window::setWindowGLAttributes(int fsaa, bool /* sRGB */) const
{
// Set GL window attributes.
SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8);
@@ -315,6 +315,15 @@ void Window::setWindowGLAttributes(int fsaa) const
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (fsaa > 0) ? 1 : 0);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (fsaa > 0) ? fsaa : 0);
/* FIXME: Enable this code but make sure to try to re-create the window and
* context with this disabled, if creation fails with it enabled.
* We can leave this out for now because in practice the framebuffer will
* already be sRGB-capable (on desktops at least.)
#if SDL_VERSION_ATLEAST(2,0,1)
SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, sRGB ? 1 : 0);
#endif
*/
int contextprofile = 0;
bool tryES2 = false;
@@ -410,6 +419,8 @@ void Window::updateSettings(const WindowSettings &newsettings)
else
#endif
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
curMode.settings.sRGB = newsettings.sRGB;
}
void Window::displayError(const std::string &title, const std::string &text) const
+2 -2
View File
@@ -90,8 +90,8 @@ public:
private:
bool setContext(int fsaa, bool vsync);
void setWindowGLAttributes(int fsaa) const;
bool setContext(int fsaa, bool vsync, bool sRGB);
void setWindowGLAttributes(int fsaa, bool sRGB) const;
// Update the saved window settings based on the window's actual state.
void updateSettings(const WindowSettings &newsettings);
@@ -96,6 +96,7 @@ int w_setMode(lua_State *L)
settings.centered = luax_boolflag(L, 3, settingName(Window::SETTING_CENTERED), true);
settings.display = luax_intflag(L, 3, settingName(Window::SETTING_DISPLAY), 1);
settings.highdpi = luax_boolflag(L, 3, settingName(Window::SETTING_HIGHDPI), false);
settings.sRGB = luax_boolflag(L, 3, settingName(Window::SETTING_SRGB), false);
// Display index is 1-based in Lua and 0-based internally.
settings.display--;
@@ -151,6 +152,9 @@ int w_getMode(lua_State *L)
luax_pushboolean(L, settings.highdpi);
lua_setfield(L, -2, settingName(Window::SETTING_HIGHDPI));
luax_pushboolean(L, settings.sRGB);
lua_setfield(L, -2, settingName(Window::SETTING_SRGB));
return 3;
}
+2
View File
@@ -313,6 +313,7 @@ function love.init()
resizable = false,
centered = true,
highdpi = false,
srgb = false,
},
modules = {
event = true,
@@ -404,6 +405,7 @@ function love.init()
centered = c.window.centered,
display = c.window.display,
highdpi = c.window.highdpi,
srgb = c.window.srgb,
}), "Could not set window mode")
love.window.setTitle(c.window.title or c.title)
if c.window.icon then
+3
View File
@@ -570,6 +570,7 @@ const unsigned char boot_lua[] =
0x2c, 0x0a,
0x09, 0x09, 0x09, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65,
0x2c, 0x0a,
0x09, 0x09, 0x09, 0x73, 0x72, 0x67, 0x62, 0x20, 0x3d, 0x20, 0x66, 0x61, 0x6c, 0x73, 0x65, 0x2c, 0x0a,
0x09, 0x09, 0x7d, 0x2c, 0x0a,
0x09, 0x09, 0x6d, 0x6f, 0x64, 0x75, 0x6c, 0x65, 0x73, 0x20, 0x3d, 0x20, 0x7b, 0x0a,
0x09, 0x09, 0x09, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x20, 0x3d, 0x20, 0x74, 0x72, 0x75, 0x65, 0x2c, 0x0a,
@@ -705,6 +706,8 @@ const unsigned char boot_lua[] =
0x64, 0x6f, 0x77, 0x2e, 0x64, 0x69, 0x73, 0x70, 0x6c, 0x61, 0x79, 0x2c, 0x0a,
0x09, 0x09, 0x09, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e,
0x64, 0x6f, 0x77, 0x2e, 0x68, 0x69, 0x67, 0x68, 0x64, 0x70, 0x69, 0x2c, 0x0a,
0x09, 0x09, 0x09, 0x73, 0x72, 0x67, 0x62, 0x20, 0x3d, 0x20, 0x63, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77,
0x2e, 0x73, 0x72, 0x67, 0x62, 0x2c, 0x0a,
0x09, 0x09, 0x7d, 0x29, 0x2c, 0x20, 0x22, 0x43, 0x6f, 0x75, 0x6c, 0x64, 0x20, 0x6e, 0x6f, 0x74, 0x20, 0x73,
0x65, 0x74, 0x20, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x20, 0x6d, 0x6f, 0x64, 0x65, 0x22, 0x29, 0x0a,
0x09, 0x09, 0x6c, 0x6f, 0x76, 0x65, 0x2e, 0x77, 0x69, 0x6e, 0x64, 0x6f, 0x77, 0x2e, 0x73, 0x65, 0x74, 0x54,