Updated to latest love-android code (b615972822cb)

This commit is contained in:
fysx
2015-08-13 17:21:53 +02:00
parent f3dd769e98
commit 9cbddc2f5e
50 changed files with 827 additions and 663 deletions
@@ -175,25 +175,13 @@ bool Filesystem::setIdentity(const char *ident, bool appendToPath)
save_identity = "unnamed";
std::string internal_storage_path = SDL_AndroidGetInternalStoragePath();
std::string save_directory = internal_storage_path + "/save";
save_path_full = std::string(SDL_AndroidGetInternalStoragePath()) + std::string("/save/") + save_identity;
if (love::android::directoryExists(save_path_full.c_str()))
SDL_Log("dir exists");
else
SDL_Log("does not exist");
if (!love::android::directoryExists(save_path_full.c_str()))
{
if (!love::android::mkdir(save_path_full.c_str()))
SDL_Log("Error: Could not create save directory %s!", save_path_full.c_str());
else
SDL_Log("Save directory %s successfuly created!", save_path_full.c_str());
}
else
SDL_Log("Save directory %s exists!", save_path_full.c_str());
if (!love::android::directoryExists(save_path_full.c_str()) &&
!love::android::mkdir(save_path_full.c_str()))
SDL_Log("Error: Could not create save directory %s!", save_path_full.c_str());
#endif
// We now have something like:
@@ -253,9 +241,7 @@ bool Filesystem::setSource(const char *source)
if (archive_loaded)
{
if (PHYSFS_mountMemory(game_archive_ptr, game_archive_size, love::android::freeGameArchiveMemory, "archive.zip", "/", 0))
SDL_Log("Mounting of in-memory game archive successful!");
else
if (!PHYSFS_mountMemory(game_archive_ptr, game_archive_size, love::android::freeGameArchiveMemory, "archive.zip", "/", 0))
{
SDL_Log("Mounting of in-memory game archive failed!");
love::android::freeGameArchiveMemory(game_archive_ptr);
@@ -278,7 +264,6 @@ bool Filesystem::setSource(const char *source)
if (sdcard_main)
{
SDL_Log("using game from %s", game_path.c_str());
new_search_path = game_path;
sdcard_main->close(sdcard_main);
+33 -1
View File
@@ -19,12 +19,45 @@
**/
#include "Graphics.h"
#include "math/MathModule.h"
namespace love
{
namespace graphics
{
static bool gammaCorrect = false;
void setGammaCorrect(bool gammacorrect)
{
gammaCorrect = gammacorrect;
}
bool isGammaCorrect()
{
return gammaCorrect;
}
void gammaCorrectColor(Colorf &c)
{
if (isGammaCorrect())
{
c.r = math::Math::instance.gammaToLinear(c.r);
c.g = math::Math::instance.gammaToLinear(c.g);
c.b = math::Math::instance.gammaToLinear(c.b);
}
}
void unGammaCorrectColor(Colorf &c)
{
if (isGammaCorrect())
{
c.r = math::Math::instance.linearToGamma(c.r);
c.g = math::Math::instance.linearToGamma(c.g);
c.b = math::Math::instance.linearToGamma(c.b);
}
}
Graphics::~Graphics()
{
}
@@ -150,7 +183,6 @@ StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM>::Entry Graphics::suppor
{
{ "multicanvas", SUPPORT_MULTI_CANVAS },
{ "multicanvasformats", SUPPORT_MULTI_CANVAS_FORMATS },
{ "srgb", SUPPORT_SRGB },
};
StringMap<Graphics::Support, Graphics::SUPPORT_MAX_ENUM> Graphics::support(Graphics::supportEntries, sizeof(Graphics::supportEntries));
+35 -2
View File
@@ -24,6 +24,7 @@
// LOVE
#include "common/Module.h"
#include "common/StringMap.h"
#include "Color.h"
// C++
#include <string>
@@ -33,6 +34,31 @@ namespace love
namespace graphics
{
/**
* Globally sets whether gamma correction is enabled. Ideally this should be set
* prior to using any Graphics module function.
**/
void setGammaCorrect(bool gammacorrect);
/**
* Gets whether global gamma correction is enabled.
**/
bool isGammaCorrect();
/**
* Gamma-corrects a color (converts it from sRGB to linear RGB, if
* gamma correction is enabled.)
* The color's components are expected to be in the range of [0, 1].
**/
void gammaCorrectColor(Colorf &c);
/**
* Un-gamma-corrects a color (converts it from linear RGB to sRGB, if
* gamma correction is enabled.)
* The color's components are expected to be in the range of [0, 1].
**/
void unGammaCorrectColor(Colorf &c);
class Graphics : public Module
{
public:
@@ -74,7 +100,6 @@ public:
{
SUPPORT_MULTI_CANVAS,
SUPPORT_MULTI_CANVAS_FORMATS,
SUPPORT_SRGB,
SUPPORT_MAX_ENUM
};
@@ -134,6 +159,14 @@ public:
{
bool r, g, b, a;
ColorMask()
: r(true), g(true), b(true), a(true)
{}
ColorMask(bool _r, bool _g, bool _b, bool _a)
: r(_r), g(_g), b(_b), a(_a)
{}
bool operator == (const ColorMask &m) const
{
return r == m.r && g == m.g && b == m.b && a == m.a;
@@ -160,7 +193,7 @@ public:
* @param width The viewport width.
* @param height The viewport height.
**/
virtual bool setMode(int width, int height, bool &sRGB) = 0;
virtual bool setMode(int width, int height) = 0;
/**
* Un-sets the current graphics display mode (uninitializing objects if
@@ -398,7 +398,7 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
// Whether the new canvas list is different from the old one.
// A more thorough check is done below.
bool canvaseschanged = canvases.size() != attachedCanvases.size();
bool hasSRGBcanvas = (format == FORMAT_SRGB);
bool hasSRGBcanvas = getSizedFormat(format) == FORMAT_SRGB;
if (canvases.size() > 0)
{
@@ -430,7 +430,7 @@ void Canvas::startGrab(const std::vector<Canvas *> &canvases)
if (!canvaseschanged && canvases[i] != attachedCanvases[i])
canvaseschanged = true;
if (otherformat == FORMAT_SRGB)
if (getSizedFormat(otherformat) == FORMAT_SRGB)
hasSRGBcanvas = true;
}
@@ -484,9 +484,10 @@ void Canvas::startGrab()
// Make sure the correct sRGB setting is used when drawing to the canvas.
if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
{
if (format == FORMAT_SRGB && !gl.hasFramebufferSRGB())
bool isSRGB = getSizedFormat(format) == FORMAT_SRGB;
if (isSRGB && !gl.hasFramebufferSRGB())
gl.setFramebufferSRGB(true);
else if (format != FORMAT_SRGB && gl.hasFramebufferSRGB())
else if (!isSRGB && gl.hasFramebufferSRGB())
gl.setFramebufferSRGB(false);
}
@@ -655,8 +656,10 @@ Canvas::Format Canvas::getSizedFormat(Canvas::Format format)
switch (format)
{
case FORMAT_NORMAL:
// 32-bit render targets don't have guaranteed support on OpenGL ES 2.
if (GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_rgb8_rgba8 || GLAD_ARM_rgba8))
if (isGammaCorrect())
return FORMAT_SRGB;
else if (GLAD_ES_VERSION_2_0 && !(GLAD_ES_VERSION_3_0 || GLAD_OES_rgb8_rgba8 || GLAD_ARM_rgba8))
// 32-bit render targets don't have guaranteed support on GLES2.
return FORMAT_RGBA4;
else
return FORMAT_RGBA8;
@@ -46,7 +46,7 @@ public:
// Different Canvas render target formats.
enum Format
{
FORMAT_NORMAL, // Usually RGBA8 or a similar fallback. Always supported.
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.
@@ -34,7 +34,7 @@ namespace graphics
namespace opengl
{
GLBuffer::GLBuffer(size_t size, const void *data, GLenum target, GLenum usage)
GLBuffer::GLBuffer(size_t size, const void *data, GLenum target, GLenum usage, uint32 mapflags)
: is_bound(false)
, is_mapped(false)
, size(size)
@@ -42,6 +42,9 @@ GLBuffer::GLBuffer(size_t size, const void *data, GLenum target, GLenum usage)
, usage(usage)
, vbo(0)
, memory_map(nullptr)
, modified_offset(0)
, modified_size(0)
, map_flags(mapflags)
{
try
{
@@ -79,6 +82,9 @@ void *GLBuffer::map()
is_mapped = true;
modified_offset = 0;
modified_size = 0;
return memory_map;
}
@@ -96,13 +102,21 @@ void GLBuffer::unmapStream()
glBufferData(getTarget(), (GLsizeiptr) getSize(), memory_map, getUsage());
}
void GLBuffer::unmap(size_t usedOffset, size_t usedSize)
void GLBuffer::unmap()
{
if (!is_mapped)
return;
usedOffset = std::min(usedOffset, getSize());
usedSize = std::min(usedSize, getSize() - usedOffset);
if ((map_flags & MAP_EXPLICIT_RANGE_MODIFY) != 0)
{
modified_offset = std::min(modified_offset, getSize() - 1);
modified_size = std::min(modified_size, getSize() - modified_offset);
}
else
{
modified_offset = 0;
modified_size = getSize();
}
// VBO::bind is a no-op when the VBO is mapped, so we have to make sure it's
// bound here.
@@ -112,28 +126,52 @@ void GLBuffer::unmap(size_t usedOffset, size_t usedSize)
is_bound = true;
}
switch (getUsage())
if (modified_size > 0)
{
case GL_STATIC_DRAW:
unmapStatic(usedOffset, usedSize);
break;
case GL_STREAM_DRAW:
unmapStream();
break;
case GL_DYNAMIC_DRAW:
default:
// It's probably more efficient to treat it like a streaming buffer if
// more than a third of its contents have been modified during the map().
if (usedSize >= getSize() / 3)
switch (getUsage())
{
case GL_STATIC_DRAW:
unmapStatic(modified_offset, modified_size);
break;
case GL_STREAM_DRAW:
unmapStream();
else
unmapStatic(usedOffset, usedSize);
break;
break;
case GL_DYNAMIC_DRAW:
default:
// It's probably more efficient to treat it like a streaming buffer if
// at least a third of its contents have been modified during the map().
if (modified_size >= getSize() / 3)
unmapStream();
else
unmapStatic(modified_offset, modified_size);
break;
}
}
modified_offset = 0;
modified_size = 0;
is_mapped = false;
}
void GLBuffer::setMappedRangeModified(size_t offset, size_t modifiedsize)
{
if (!is_mapped || !(map_flags & MAP_EXPLICIT_RANGE_MODIFY))
return;
// We're being conservative right now by internally marking the whole range
// from the start of section a to the end of section b as modified if both
// a and b are marked as modified.
size_t old_range_end = modified_offset + modified_offset;
modified_offset = std::min(modified_offset, offset);
size_t new_range_end = std::max(offset + modifiedsize, old_range_end);
modified_size = new_range_end - modified_offset;
}
void GLBuffer::bind()
{
if (!is_mapped)
@@ -155,7 +193,9 @@ void GLBuffer::fill(size_t offset, size_t size, const void *data)
{
memcpy(memory_map + offset, data, size);
if (!is_mapped)
if (is_mapped)
setMappedRangeModified(offset, size);
else
glBufferSubData(getTarget(), (GLintptr) offset, (GLsizeiptr) size, data);
}
@@ -47,6 +47,11 @@ class GLBuffer : public Volatile
{
public:
enum MapFlags
{
MAP_EXPLICIT_RANGE_MODIFY = 0x01, // see setMappedRangeModified.
};
/**
* Constructor.
*
@@ -54,7 +59,7 @@ public:
* @param target The target GLBuffer object, e.g. GL_ARRAY_BUFFER.
* @param usage Usage hint, e.g. GL_DYNAMIC_DRAW.
*/
GLBuffer(size_t size, const void *data, GLenum target, GLenum usage);
GLBuffer(size_t size, const void *data, GLenum target, GLenum usage, uint32 mapflags = 0);
/**
* Destructor.
@@ -118,12 +123,14 @@ public:
* when used to draw elements.
*
* The GLBuffer must be bound to use this function.
*
* @param usedOffset The offset into the mapped buffer indicating the
* sub-range of data modified. Optional.
* @param usedSize The size of the sub-range of modified data. Optional.
*/
void unmap(size_t usedOffset = 0, size_t usedSize = -1);
void unmap();
/**
* Marks a range of mapped data as modified.
* NOTE: GLBuffer::fill calls this internally for you.
**/
void setMappedRangeModified(size_t offset, size_t size);
/**
* Bind the GLBuffer to its specified target.
@@ -137,7 +144,7 @@ public:
void unbind();
/**
* Fill a portion of the buffer with data.
* Fill a portion of the buffer with data and marks the range as modified.
*
* The GLBuffer must be bound to use this function.
*
@@ -155,6 +162,11 @@ public:
*/
const void *getPointer(size_t offset) const;
uint32 getMapFlags() const
{
return map_flags;
}
// Implements Volatile.
bool loadVolatile() override;
void unloadVolatile() override;
@@ -262,6 +274,11 @@ private:
// A pointer to mapped memory.
char *memory_map;
size_t modified_offset;
size_t modified_size;
uint32 map_flags;
}; // GLBuffer
+38 -100
View File
@@ -26,6 +26,7 @@
#include "Graphics.h"
#include "font/Font.h"
#include "Polyline.h"
#include "math/MathModule.h"
// C++
#include <vector>
@@ -70,7 +71,7 @@ Graphics::Graphics()
currentWindow->getWindow(w, h, wsettings);
if (currentWindow->isOpen())
setMode(w, h, wsettings.sRGB);
setMode(w, h);
}
}
@@ -235,7 +236,7 @@ void Graphics::setViewportSize(int width, int height)
setCanvas(canvases);
}
bool Graphics::setMode(int width, int height, bool &sRGB)
bool Graphics::setMode(int width, int height)
{
currentWindow.set(Module::getInstance<love::window::Window>(Module::M_WINDOW));
@@ -275,12 +276,12 @@ bool Graphics::setMode(int width, int height, bool &sRGB)
|| GLAD_ES_VERSION_3_0 || GLAD_EXT_sRGB)
{
if (GLAD_VERSION_1_0 || GLAD_EXT_sRGB_write_control)
gl.setFramebufferSRGB(sRGB);
gl.setFramebufferSRGB(isGammaCorrect());
}
else
sRGB = false;
setGammaCorrect(false);
Canvas::screenHasSRGB = sRGB;
Canvas::screenHasSRGB = isGammaCorrect();
bool enabledebug = false;
@@ -345,7 +346,7 @@ void Graphics::unSetMode()
void Graphics::setActive(bool enable)
{
// Make sure all pending OpenGL commands have fully executed before
// returning, if we're going from active to inactive.
// returning, when going from active to inactive. This is required on iOS.
if (isCreated() && this->active && !enable)
glFinish();
@@ -426,13 +427,17 @@ void Graphics::reset()
origin();
}
void Graphics::clear(Color c)
void Graphics::clear(Colorf c)
{
glClearColor(c.r / 255.0f, c.g / 255.0f, c.b / 255.0f, c.a / 255.0f);
Colorf nc = Colorf(c.r/255.0f, c.g/255.0f, c.b/255.0f, c.a/255.0f);
gammaCorrectColor(nc);
glClearColor(nc.r, nc.g, nc.b, nc.a);
glClear(GL_COLOR_BUFFER_BIT | GL_STENCIL_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
}
void Graphics::clear(const std::vector<Color> &colors)
void Graphics::clear(const std::vector<Colorf> &colors)
{
if (colors.size() == 0)
return;
@@ -447,7 +452,16 @@ void Graphics::clear(const std::vector<Color> &colors)
for (int i = 0; i < (int) colors.size(); i++)
{
const GLfloat c[] = {colors[i].r/255.f, colors[i].g/255.f, colors[i].b/255.f, colors[i].a/255.f};
GLfloat c[] = {colors[i].r/255.f, colors[i].g/255.f, colors[i].b/255.f, colors[i].a/255.f};
// TODO: Investigate a potential bug on AMD drivers in Windows/Linux
// which apparently causes the clear color to be incorrect when mixed
// sRGB and linear render targets are active.
if (isGammaCorrect())
{
for (int i = 0; i < 3; i++)
c[i] = math::Math::instance.gammaToLinear(c[i]);
}
if (GLAD_ES_VERSION_3_0 || GLAD_VERSION_3_0)
glClearBufferfv(GL_COLOR, i, c);
@@ -785,23 +799,32 @@ Text *Graphics::newText(Font *font, const std::string &text)
return new Text(font, text);
}
void Graphics::setColor(Color c)
bool Graphics::isGammaCorrect() const
{
glVertexAttrib4f(ATTRIB_CONSTANTCOLOR, c.r/255.0f, c.g/255.0f, c.b/255.0f, c.a/255.0f);
return love::graphics::isGammaCorrect();
}
void Graphics::setColor(Colorf c)
{
Colorf nc = Colorf(c.r/255.0f, c.g/255.0f, c.b/255.0f, c.a/255.0f);
gammaCorrectColor(nc);
glVertexAttrib4f(ATTRIB_CONSTANTCOLOR, nc.r, nc.g, nc.b, nc.a);
states.back().color = c;
}
Color Graphics::getColor() const
Colorf Graphics::getColor() const
{
return states.back().color;
}
void Graphics::setBackgroundColor(Color c)
void Graphics::setBackgroundColor(Colorf c)
{
states.back().backgroundColor = c;
}
Color Graphics::getBackgroundColor() const
Colorf Graphics::getBackgroundColor() const
{
return states.back().backgroundColor;
}
@@ -1456,10 +1479,6 @@ bool Graphics::isSupported(Support feature) const
return Canvas::isMultiCanvasSupported();
case SUPPORT_MULTI_CANVAS_FORMATS:
return Canvas::isMultiFormatMultiCanvasSupported();
case SUPPORT_SRGB:
// sRGB support for the screen is guaranteed if it's supported as a
// Canvas format.
return Canvas::isFormatSupported(Canvas::FORMAT_SRGB);
default:
return false;
}
@@ -1528,87 +1547,6 @@ void Graphics::origin()
pixelSizeStack.back() = 1;
}
Graphics::DisplayState::DisplayState()
: color(255, 255, 255, 255)
, backgroundColor(0, 0, 0, 255)
, blendMode(BLEND_ALPHA)
, blendMultiplyAlpha(true)
, lineWidth(1.0f)
, lineStyle(LINE_SMOOTH)
, lineJoin(LINE_JOIN_MITER)
, pointSize(1.0f)
, scissor(false)
, scissorBox()
, stencilTest(false)
, stencilInvert(false)
, font(nullptr)
, shader(nullptr)
, colorMask({true, true, true, true})
, wireframe(false)
, defaultFilter()
, defaultMipmapFilter(Texture::FILTER_NEAREST)
, defaultMipmapSharpness(0.0f)
{
}
Graphics::DisplayState::DisplayState(const DisplayState &other)
: color(other.color)
, backgroundColor(other.backgroundColor)
, blendMode(other.blendMode)
, blendMultiplyAlpha(other.blendMultiplyAlpha)
, lineWidth(other.lineWidth)
, lineStyle(other.lineStyle)
, lineJoin(other.lineJoin)
, pointSize(other.pointSize)
, scissor(other.scissor)
, scissorBox(other.scissorBox)
, stencilTest(other.stencilTest)
, stencilInvert(other.stencilInvert)
, font(other.font)
, shader(other.shader)
, canvases(other.canvases)
, colorMask(other.colorMask)
, wireframe(other.wireframe)
, defaultFilter(other.defaultFilter)
, defaultMipmapFilter(other.defaultMipmapFilter)
, defaultMipmapSharpness(other.defaultMipmapSharpness)
{
}
Graphics::DisplayState::~DisplayState()
{
}
Graphics::DisplayState &Graphics::DisplayState::operator = (const DisplayState &other)
{
color = other.color;
backgroundColor = other.backgroundColor;
blendMode = other.blendMode;
blendMultiplyAlpha = other.blendMultiplyAlpha;
lineWidth = other.lineWidth;
lineStyle = other.lineStyle;
lineJoin = other.lineJoin;
pointSize = other.pointSize;
scissor = other.scissor;
scissorBox = other.scissorBox;
stencilTest = other.stencilTest;
stencilInvert = other.stencilInvert;
font = other.font;
shader = other.shader;
canvases = other.canvases;
colorMask = other.colorMask;
wireframe = other.wireframe;
defaultFilter = other.defaultFilter;
defaultMipmapFilter = other.defaultMipmapFilter;
defaultMipmapSharpness = other.defaultMipmapSharpness;
return *this;
}
} // opengl
} // graphics
} // love
+26 -30
View File
@@ -66,7 +66,7 @@ public:
const char *getName() const;
virtual void setViewportSize(int width, int height);
virtual bool setMode(int width, int height, bool &sRGB);
virtual bool setMode(int width, int height);
virtual void unSetMode();
virtual void setActive(bool active);
@@ -84,12 +84,12 @@ public:
/**
* Clears the screen to a specific color.
**/
void clear(Color c);
void clear(Colorf c);
/**
* Clears each active canvas to a different color.
**/
void clear(const std::vector<Color> &colors);
void clear(const std::vector<Colorf> &colors);
/**
* Discards the contents of the screen.
@@ -183,26 +183,28 @@ public:
Text *newText(Font *font, const std::string &text = "");
bool isGammaCorrect() const;
/**
* Sets the foreground color.
* @param c The new foreground color.
**/
void setColor(Color c);
void setColor(Colorf c);
/**
* Gets current color.
**/
Color getColor() const;
Colorf getColor() const;
/**
* Sets the background Color.
**/
void setBackgroundColor(Color c);
void setBackgroundColor(Colorf c);
/**
* Gets the current background color.
**/
Color getBackgroundColor() const;
Colorf getBackgroundColor() const;
void setFont(Font *font);
Font *getFont();
@@ -463,44 +465,38 @@ private:
struct DisplayState
{
Color color;
Color backgroundColor;
Colorf color = Colorf(255.0, 255.0, 255.0, 255.0);
Colorf backgroundColor = Colorf(0.0, 0.0, 0.0, 255.0);
BlendMode blendMode;
bool blendMultiplyAlpha;
BlendMode blendMode = BLEND_ALPHA;
bool blendMultiplyAlpha = true;
float lineWidth;
LineStyle lineStyle;
LineJoin lineJoin;
float lineWidth = 1.0f;
LineStyle lineStyle = LINE_SMOOTH;
LineJoin lineJoin = LINE_JOIN_MITER;
float pointSize;
float pointSize = 1.0f;
bool scissor;
OpenGL::Viewport scissorBox;
bool scissor = false;
OpenGL::Viewport scissorBox = OpenGL::Viewport();
// Stencil.
bool stencilTest;
bool stencilInvert;
bool stencilTest = false;
bool stencilInvert = false;
StrongRef<Font> font;
StrongRef<Shader> shader;
std::vector<StrongRef<Canvas>> canvases;
ColorMask colorMask;
ColorMask colorMask = ColorMask(true, true, true, true);
bool wireframe;
bool wireframe = false;
Texture::Filter defaultFilter;
Texture::Filter defaultFilter = Texture::Filter();
Texture::FilterMode defaultMipmapFilter;
float defaultMipmapSharpness;
DisplayState();
DisplayState(const DisplayState &other);
~DisplayState();
DisplayState &operator = (const DisplayState &other);
Texture::FilterMode defaultMipmapFilter = Texture::FILTER_NEAREST;
float defaultMipmapSharpness = 0.0f;
};
void restoreState(const DisplayState &s);
+61 -26
View File
@@ -20,6 +20,7 @@
#include "Image.h"
#include "graphics/Graphics.h"
#include "common/int.h"
// STD
@@ -91,6 +92,7 @@ Image::Image(const std::vector<love::image::ImageData *> &imagedata, const Flags
, mipmapSharpness(defaultMipmapSharpness)
, compressed(false)
, flags(flags)
, sRGB(false)
, usingDefaultTexture(false)
, textureMemorySize(0)
{
@@ -117,18 +119,22 @@ Image::Image(const std::vector<love::image::CompressedImageData *> &compressedda
, mipmapSharpness(defaultMipmapSharpness)
, compressed(true)
, flags(flags)
, sRGB(false)
, usingDefaultTexture(false)
, textureMemorySize(0)
{
this->flags.sRGB = (flags.sRGB || compresseddata[0]->isSRGB());
width = compresseddata[0]->getWidth(0);
height = compresseddata[0]->getHeight(0);
if (verifyMipmapLevels(compresseddata))
this->flags.mipmaps = true;
else if (flags.mipmaps && getMipmapCount(width, height) != compresseddata[0]->getMipmapCount())
throw love::Exception("Image cannot have mipmaps: compressed image data does not have all required mipmap levels.");
{
if (compresseddata[0]->getMipmapCount() == 1)
this->flags.mipmaps = false;
else
throw love::Exception("Image cannot have mipmaps: compressed image data does not have all required mipmap levels.");
}
for (const auto &cd : compresseddata)
{
@@ -179,6 +185,14 @@ void Image::preload()
if (flags.mipmaps)
filter.mipmap = defaultMipmapFilter;
if (!isGammaCorrect())
flags.linear = false;
if (isGammaCorrect() && !flags.linear)
sRGB = true;
else
sRGB = false;
}
void Image::generateMipmaps()
@@ -214,7 +228,10 @@ void Image::loadDefaultTexture()
void Image::loadFromCompressedData()
{
GLenum iformat = getCompressedFormat(cdata[0]->getFormat());
GLenum iformat = getCompressedFormat(cdata[0]->getFormat(), sRGB);
if (isGammaCorrect() && !sRGB)
flags.linear = true;
int count = 1;
@@ -238,13 +255,13 @@ void Image::loadFromCompressedData()
void Image::loadFromImageData()
{
GLenum iformat = flags.sRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8;
GLenum iformat = sRGB ? GL_SRGB8_ALPHA8 : GL_RGBA8;
GLenum format = GL_RGBA;
// in GLES2, the internalformat and format params of TexImage have to match.
if (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0)
{
format = flags.sRGB ? GL_SRGB_ALPHA : GL_RGBA;
format = sRGB ? GL_SRGB_ALPHA : GL_RGBA;
iformat = format;
}
@@ -267,24 +284,24 @@ bool Image::loadVolatile()
{
OpenGL::TempDebugGroup debuggroup("Image load");
if (isCompressed() && !hasCompressedTextureSupport(cdata[0]->getFormat(), flags.sRGB))
if (isCompressed() && !hasCompressedTextureSupport(cdata[0]->getFormat(), sRGB))
{
const char *str;
if (image::CompressedImageData::getConstant(cdata[0]->getFormat(), str))
{
throw love::Exception("Cannot create image: "
"%s%s compressed images are not supported on this system.", flags.sRGB ? "sRGB " : "", str);
"%s%s compressed images are not supported on this system.", sRGB ? "sRGB " : "", str);
}
else
throw love::Exception("cannot create image: format is not supported on this system.");
}
else if (!isCompressed())
{
if (flags.sRGB && !hasSRGBSupport())
if (sRGB && !hasSRGBSupport())
throw love::Exception("sRGB images are not supported on this system.");
// GL_EXT_sRGB doesn't support glGenerateMipmap for sRGB textures.
if (flags.sRGB && (GLAD_ES_VERSION_2_0 && GLAD_EXT_sRGB && !GLAD_ES_VERSION_3_0)
if (sRGB && (GLAD_ES_VERSION_2_0 && GLAD_EXT_sRGB && !GLAD_ES_VERSION_3_0)
&& data.size() <= 1)
{
flags.mipmaps = false;
@@ -402,7 +419,7 @@ bool Image::refresh(int xoffset, int yoffset, int w, int h)
// In ES2, the format parameter of TexSubImage must match the internal
// format of the texture.
if (flags.sRGB && (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0))
if (sRGB && (GLAD_ES_VERSION_2_0 && !GLAD_ES_VERSION_3_0))
format = GL_SRGB_ALPHA;
int mipcount = flags.mipmaps ? (int) data.size() : 1;
@@ -570,93 +587,111 @@ bool Image::isCompressed() const
return compressed;
}
GLenum Image::getCompressedFormat(image::CompressedImageData::Format cformat) const
GLenum Image::getCompressedFormat(image::CompressedImageData::Format cformat, bool &isSRGB) const
{
switch (cformat)
{
case image::CompressedImageData::FORMAT_DXT1:
if (flags.sRGB)
if (isSRGB)
return GL_COMPRESSED_SRGB_S3TC_DXT1_EXT;
else
return GL_COMPRESSED_RGB_S3TC_DXT1_EXT;
case image::CompressedImageData::FORMAT_DXT3:
if (flags.sRGB)
if (isSRGB)
return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT3_EXT;
else
return GL_COMPRESSED_RGBA_S3TC_DXT3_EXT;
case image::CompressedImageData::FORMAT_DXT5:
if (flags.sRGB)
if (isSRGB)
return GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT;
else
return GL_COMPRESSED_RGBA_S3TC_DXT5_EXT;
case image::CompressedImageData::FORMAT_BC4:
isSRGB = false;
return GL_COMPRESSED_RED_RGTC1;
case image::CompressedImageData::FORMAT_BC4s:
isSRGB = false;
return GL_COMPRESSED_SIGNED_RED_RGTC1;
case image::CompressedImageData::FORMAT_BC5:
isSRGB = false;
return GL_COMPRESSED_RG_RGTC2;
case image::CompressedImageData::FORMAT_BC5s:
isSRGB = false;
return GL_COMPRESSED_SIGNED_RG_RGTC2;
case image::CompressedImageData::FORMAT_BC6H:
isSRGB = false;
return GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT;
case image::CompressedImageData::FORMAT_BC6Hs:
isSRGB = false;
return GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT;
case image::CompressedImageData::FORMAT_BC7:
if (flags.sRGB)
if (isSRGB)
return GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM;
else
return GL_COMPRESSED_RGBA_BPTC_UNORM;
case image::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 GL_COMPRESSED_RGB8_ETC2;
{
if (isSRGB)
return GL_COMPRESSED_SRGB8_ETC2;
else
return GL_COMPRESSED_RGB8_ETC2;
}
else
{
isSRGB = false;
return GL_ETC1_RGB8_OES;
}
case image::CompressedImageData::FORMAT_ETC2_RGB:
if (flags.sRGB)
if (isSRGB)
return GL_COMPRESSED_SRGB8_ETC2;
else
return GL_COMPRESSED_RGB8_ETC2;
case image::CompressedImageData::FORMAT_ETC2_RGBA:
if (flags.sRGB)
if (isSRGB)
return GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
else
return GL_COMPRESSED_RGBA8_ETC2_EAC;
case image::CompressedImageData::FORMAT_ETC2_RGBA1:
if (flags.sRGB)
if (isSRGB)
return GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;
else
return GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
case image::CompressedImageData::FORMAT_EAC_R:
isSRGB = false;
return GL_COMPRESSED_R11_EAC;
case image::CompressedImageData::FORMAT_EAC_Rs:
isSRGB = false;
return GL_COMPRESSED_SIGNED_R11_EAC;
case image::CompressedImageData::FORMAT_EAC_RG:
isSRGB = false;
return GL_COMPRESSED_RG11_EAC;
case image::CompressedImageData::FORMAT_EAC_RGs:
isSRGB = false;
return GL_COMPRESSED_SIGNED_RG11_EAC;
case image::CompressedImageData::FORMAT_PVR1_RGB2:
if (flags.sRGB)
if (isSRGB)
return GL_COMPRESSED_SRGB_PVRTC_2BPPV1_EXT;
else
return GL_COMPRESSED_RGB_PVRTC_2BPPV1_IMG;
case image::CompressedImageData::FORMAT_PVR1_RGB4:
if (flags.sRGB)
if (isSRGB)
return GL_COMPRESSED_SRGB_PVRTC_4BPPV1_EXT;
else
return GL_COMPRESSED_RGB_PVRTC_4BPPV1_IMG;
case image::CompressedImageData::FORMAT_PVR1_RGBA2:
if (flags.sRGB)
if (isSRGB)
return GL_COMPRESSED_SRGB_ALPHA_PVRTC_2BPPV1_EXT;
else
return GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
case image::CompressedImageData::FORMAT_PVR1_RGBA4:
if (flags.sRGB)
if (isSRGB)
return GL_COMPRESSED_SRGB_ALPHA_PVRTC_4BPPV1_EXT;
else
return GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
default:
if (flags.sRGB)
if (isSRGB)
return GL_SRGB8_ALPHA8;
else
return GL_RGBA8;
@@ -729,7 +764,7 @@ bool Image::getConstant(FlagType in, const char *&out)
StringMap<Image::FlagType, Image::FLAG_TYPE_MAX_ENUM>::Entry Image::flagNameEntries[] =
{
{"mipmaps", Image::FLAG_TYPE_MIPMAPS},
{"srgb", Image::FLAG_TYPE_SRGB},
{"linear", Image::FLAG_TYPE_LINEAR},
};
StringMap<Image::FlagType, Image::FLAG_TYPE_MAX_ENUM> Image::flagNames(Image::flagNameEntries, sizeof(Image::flagNameEntries));
+5 -3
View File
@@ -55,14 +55,14 @@ public:
enum FlagType
{
FLAG_TYPE_MIPMAPS,
FLAG_TYPE_SRGB,
FLAG_TYPE_LINEAR,
FLAG_TYPE_MAX_ENUM
};
struct Flags
{
bool mipmaps = false;
bool sRGB = false;;
bool linear = false;
};
/**
@@ -147,7 +147,7 @@ private:
void loadFromCompressedData();
void loadFromImageData();
GLenum getCompressedFormat(image::CompressedImageData::Format cformat) 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.
@@ -170,6 +170,8 @@ private:
// The flags used to initialize this Image.
Flags flags;
bool sRGB;
// True if the image wasn't able to be properly created and it had to fall
// back to a default texture.
bool usingDefaultTexture;
+9 -28
View File
@@ -63,8 +63,6 @@ Mesh::Mesh(const std::vector<AttribFormat> &vertexformat, const void *data, size
, vbo(nullptr)
, vertexCount(0)
, vertexStride(0)
, vboUsedOffset(0)
, vboUsedSize(0)
, ibo(nullptr)
, elementCount(0)
, elementDataType(0)
@@ -81,7 +79,7 @@ Mesh::Mesh(const std::vector<AttribFormat> &vertexformat, const void *data, size
if (vertexCount == 0)
throw love::Exception("Data size is too small for specified vertex attribute formats.");
vbo = new GLBuffer(datasize, data, GL_ARRAY_BUFFER, getGLBufferUsage(usage));
vbo = new GLBuffer(datasize, data, GL_ARRAY_BUFFER, getGLBufferUsage(usage), GLBuffer::MAP_EXPLICIT_RANGE_MODIFY);
vertexScratchBuffer = new char[vertexStride];
}
@@ -91,8 +89,6 @@ Mesh::Mesh(const std::vector<AttribFormat> &vertexformat, int vertexcount, DrawM
, vbo(nullptr)
, vertexCount((size_t) vertexcount)
, vertexStride(0)
, vboUsedOffset(0)
, vboUsedSize(0)
, ibo(nullptr)
, elementCount(0)
, elementDataType(getGLDataTypeFromMax(vertexcount))
@@ -108,11 +104,12 @@ Mesh::Mesh(const std::vector<AttribFormat> &vertexformat, int vertexcount, DrawM
size_t buffersize = vertexCount * vertexStride;
vbo = new GLBuffer(buffersize, nullptr, GL_ARRAY_BUFFER, getGLBufferUsage(usage));
vbo = new GLBuffer(buffersize, nullptr, GL_ARRAY_BUFFER, getGLBufferUsage(usage), GLBuffer::MAP_EXPLICIT_RANGE_MODIFY);
// Initialize the buffer's contents to 0.
GLBuffer::Bind bind(*vbo);
memset(vbo->map(), 0, buffersize);
vbo->setMappedRangeModified(0, vbo->getSize());
vbo->unmap();
vertexScratchBuffer = new char[vertexStride];
@@ -198,8 +195,7 @@ void Mesh::setVertex(size_t vertindex, const void *data, size_t datasize)
memcpy(bufferdata + offset, data, size);
vboUsedOffset = std::min(vboUsedOffset, offset);
vboUsedSize = std::max(vboUsedSize, (offset + size) - vboUsedOffset);
vbo->setMappedRangeModified(offset, size);
}
size_t Mesh::getVertex(size_t vertindex, void *data, size_t datasize)
@@ -216,12 +212,6 @@ size_t Mesh::getVertex(size_t vertindex, void *data, size_t datasize)
memcpy(data, bufferdata + offset, size);
if (vboUsedSize == 0)
{
vboUsedOffset = std::min(vboUsedOffset, offset);
vboUsedSize = std::max(vboUsedSize, (offset + size) - vboUsedOffset);
}
return size;
}
@@ -246,8 +236,7 @@ void Mesh::setVertexAttribute(size_t vertindex, int attribindex, const void *dat
memcpy(bufferdata + offset, data, size);
vboUsedOffset = std::min(vboUsedOffset, offset);
vboUsedSize = std::max(vboUsedSize, (offset + size) - vboUsedOffset);
vbo->setMappedRangeModified(offset, size);
}
size_t Mesh::getVertexAttribute(size_t vertindex, int attribindex, void *data, size_t datasize)
@@ -267,12 +256,6 @@ size_t Mesh::getVertexAttribute(size_t vertindex, int attribindex, void *data, s
memcpy(data, bufferdata + offset, size);
if (vboUsedSize == 0)
{
vboUsedOffset = std::min(vboUsedOffset, offset);
vboUsedSize = std::max(vboUsedSize, (offset + size) - vboUsedOffset);
}
return size;
}
@@ -298,6 +281,7 @@ Mesh::DataType Mesh::getAttributeInfo(int attribindex, int &components) const
DataType type = vertexFormat[attribindex].type;
components = vertexFormat[attribindex].components;
return type;
}
@@ -377,17 +361,15 @@ void Mesh::unmapVertexData()
{
// Assume the whole buffer was modified.
GLBuffer::Bind bind(*vbo);
vbo->setMappedRangeModified(0, vbo->getSize());
vbo->unmap();
vboUsedOffset = vboUsedSize = 0;
}
void Mesh::flush()
{
{
GLBuffer::Bind vbobind(*vbo);
vbo->unmap(vboUsedOffset, vboUsedSize);
vboUsedOffset = vboUsedSize = 0;
vbo->unmap();
}
if (ibo != nullptr)
@@ -574,8 +556,7 @@ void Mesh::draw(float x, float y, float angle, float sx, float sy, float ox, flo
GLBuffer::Bind vbobind(*mesh->vbo);
// Make sure the buffer isn't mapped (sends data to GPU if needed.)
mesh->vbo->unmap(mesh->vboUsedOffset, mesh->vboUsedSize);
mesh->vboUsedOffset = mesh->vboUsedSize = 0;
mesh->vbo->unmap();
size_t offset = mesh->getAttributeOffset(attrib.second.index);
const void *gloffset = mesh->vbo->getPointer(offset);
@@ -240,11 +240,6 @@ private:
// avoid memory allocations when using Mesh::setVertex etc.
char *vertexScratchBuffer;
// Tracks the range of the vertex buffer that has been used, to make unmap()
// calls as efficient as possible.
size_t vboUsedOffset;
size_t vboUsedSize;
// Element (vertex index) buffer, for the vertex map.
GLBuffer *ibo;
size_t elementCount;
@@ -43,11 +43,6 @@ namespace
love::math::RandomGenerator rng;
Colorf colorToFloat(const Color &c)
{
return Colorf((float)c.r/255.0f, (float)c.g/255.0f, (float)c.b/255.0f, (float)c.a/255.0f);
}
float calculate_variation(float inner, float outer, float var)
{
float low = inner - (outer/2.0f)*var;
@@ -261,35 +256,34 @@ void ParticleSystem::initParticle(Particle *p, float t)
p->life = (float) rng.random(min, max);
p->lifetime = p->life;
p->position[0] = pos.x;
p->position[1] = pos.y;
p->position = pos;
switch (areaSpreadDistribution)
{
case DISTRIBUTION_UNIFORM:
p->position[0] += (float) rng.random(-areaSpread.getX(), areaSpread.getX());
p->position[1] += (float) rng.random(-areaSpread.getY(), areaSpread.getY());
p->position.x += (float) rng.random(-areaSpread.getX(), areaSpread.getX());
p->position.y += (float) rng.random(-areaSpread.getY(), areaSpread.getY());
break;
case DISTRIBUTION_NORMAL:
p->position[0] += (float) rng.randomNormal(areaSpread.getX());
p->position[1] += (float) rng.randomNormal(areaSpread.getY());
p->position.x += (float) rng.randomNormal(areaSpread.getX());
p->position.y += (float) rng.randomNormal(areaSpread.getY());
break;
case DISTRIBUTION_NONE:
default:
break;
}
min = direction - spread/2.0f;
max = direction + spread/2.0f;
p->direction = (float) rng.random(min, max);
p->origin = pos;
min = speedMin;
max = speedMax;
float speed = (float) rng.random(min, max);
p->velocity = love::Vector(cosf(p->direction), sinf(p->direction));
p->velocity *= speed;
min = direction - spread/2.0f;
max = direction + spread/2.0f;
float dir = (float) rng.random(min, max);
p->velocity = love::Vector(cosf(dir), sinf(dir)) * speed;
p->linearAcceleration.x = (float) rng.random(linearAccelerationMin.x, linearAccelerationMax.x);
p->linearAcceleration.y = (float) rng.random(linearAccelerationMin.y, linearAccelerationMax.y);
@@ -706,30 +700,31 @@ love::Vector ParticleSystem::getOffset() const
return offset;
}
void ParticleSystem::setColor(const Color &color)
void ParticleSystem::setColor(const std::vector<Colorf> &newColors)
{
colors.resize(1);
colors[0] = colorToFloat(color);
}
colors = newColors;
void ParticleSystem::setColor(const std::vector<Color> &newColors)
{
colors.resize(newColors.size());
for (size_t i = 0; i < newColors.size(); ++i)
colors[i] = colorToFloat(newColors[i]);
}
std::vector<Color> ParticleSystem::getColor() const
{
// The particle system stores colors as floats...
std::vector<Color> ncolors(colors.size());
for (size_t i = 0; i < colors.size(); ++i)
for (Colorf &c : colors)
{
ncolors[i].r = (unsigned char) (colors[i].r * 255);
ncolors[i].g = (unsigned char) (colors[i].g * 255);
ncolors[i].b = (unsigned char) (colors[i].b * 255);
ncolors[i].a = (unsigned char) (colors[i].a * 255);
// We want to store the colors as [0, 1], rather than [0, 255].
c.r /= 255.0f;
c.g /= 255.0f;
c.b /= 255.0f;
c.a /= 255.0f;
}
}
std::vector<Colorf> ParticleSystem::getColor() const
{
// The particle system stores colors in the range of [0, 1]...
std::vector<Colorf> ncolors(colors);
for (Colorf &c : ncolors)
{
c.r *= 255.0f;
c.g *= 255.0f;
c.b *= 255.0f;
c.a *= 255.0f;
}
return ncolors;
@@ -854,10 +849,8 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo
OpenGL::TempDebugGroup debuggroup("ParticleSystem draw");
Matrix4 t(x, y, angle, sx, sy, ox, oy, kx, ky);
OpenGL::TempTransform transform(gl);
transform.get() *= t;
transform.get() *= Matrix4(x, y, angle, sx, sy, ox, oy, kx, ky);
const Vertex *textureVerts = texture->getVertices();
Vertex *pVerts = particleVerts;
@@ -865,14 +858,16 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo
bool useQuads = !quads.empty();
Matrix3 t;
// set the vertex data for each particle (transformation, texcoords, color)
while (p)
{
if (useQuads)
textureVerts = quads[p->quadIndex]->getVertices();
// particle vertices are image vertices transformed by particle information
t.setTransformation(p->position[0], p->position[1], p->angle, p->size, p->size, offset.x, offset.y, 0.0f, 0.0f);
// particle vertices are image vertices transformed by particle info
t.setTransformation(p->position.x, p->position.y, p->angle, p->size, p->size, offset.x, offset.y, 0.0f, 0.0f);
t.transform(pVerts, textureVerts, 4);
// set the texture coordinate and color data for particle vertices
@@ -881,7 +876,8 @@ void ParticleSystem::draw(float x, float y, float angle, float sx, float sy, flo
pVerts[v].s = textureVerts[v].s;
pVerts[v].t = textureVerts[v].t;
// particle colors are stored as floats (0-1) but vertex colors are stored as unsigned bytes (0-255)
// Particle colors are stored as floats (0-1) but vertex colors are
// unsigned bytes (0-255).
pVerts[v].r = (unsigned char) (p->color.r*255);
pVerts[v].g = (unsigned char) (p->color.g*255);
pVerts[v].b = (unsigned char) (p->color.b*255);
@@ -927,7 +923,7 @@ void ParticleSystem::update(float dt)
{
// Temp variables.
love::Vector radial, tangential;
love::Vector ppos(p->position[0], p->position[1]);
love::Vector ppos = p->position;
// Get vector from particle center to particle.
radial = ppos - p->origin;
@@ -956,8 +952,7 @@ void ParticleSystem::update(float dt)
// Modify position.
ppos += p->velocity * dt;
p->position[0] = ppos.getX();
p->position[1] = ppos.getY();
p->position = ppos;
const float t = 1.0f - p->life / p->lifetime;
@@ -417,22 +417,16 @@ public:
**/
love::Vector getOffset() const;
/**
* Sets the color of the particles.
* @param color The color.
**/
void setColor(const Color &color);
/**
* Sets the color of the particles.
* @param newColors Array of colors
**/
void setColor(const std::vector<Color> &newColors);
void setColor(const std::vector<Colorf> &newColors);
/**
* Returns the color of the particles.
**/
std::vector<Color> getColor() const;
std::vector<Colorf> getColor() const;
/**
* Sets a list of Quads to use for particles over their lifetime.
@@ -534,8 +528,7 @@ protected:
float lifetime;
float life;
float position[2];
float direction;
love::Vector position;
// Particles gravitate towards this point.
love::Vector origin;
@@ -48,8 +48,6 @@ SpriteBatch::SpriteBatch(Texture *texture, int size, Mesh::Usage usage)
, color(0)
, array_buf(nullptr)
, quad_indices(size)
, buffer_used_offset(0)
, buffer_used_size(0)
{
if (size <= 0)
throw love::Exception("Invalid SpriteBatch size.");
@@ -60,7 +58,7 @@ SpriteBatch::SpriteBatch(Texture *texture, int size, Mesh::Usage usage)
try
{
array_buf = new GLBuffer(vertex_size, nullptr, GL_ARRAY_BUFFER, gl_usage);
array_buf = new GLBuffer(vertex_size, nullptr, GL_ARRAY_BUFFER, gl_usage, GLBuffer::MAP_EXPLICIT_RANGE_MODIFY);
}
catch (love::Exception &)
{
@@ -86,7 +84,7 @@ 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;
Matrix4 t(x, y, a, sx, sy, ox, oy, kx, ky);
Matrix3 t(x, y, a, sx, sy, ox, oy, kx, ky);
addv(texture->getVertices(), t, (index == -1) ? next : index);
@@ -103,7 +101,7 @@ 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;
Matrix4 t(x, y, a, sx, sy, ox, oy, kx, ky);
Matrix3 t(x, y, a, sx, sy, ox, oy, kx, ky);
addv(quad->getVertices(), t, (index == -1) ? next : index);
@@ -123,9 +121,7 @@ void SpriteBatch::clear()
void SpriteBatch::flush()
{
GLBuffer::Bind bind(*array_buf);
array_buf->unmap(buffer_used_offset, buffer_used_size);
buffer_used_offset = buffer_used_size = 0;
array_buf->unmap();
}
void SpriteBatch::setTexture(Texture *newtexture)
@@ -182,7 +178,7 @@ void SpriteBatch::setBufferSize(int newsize)
try
{
new_array_buf = new GLBuffer(vertex_size, nullptr, array_buf->getTarget(), array_buf->getUsage());
new_array_buf = new GLBuffer(vertex_size, nullptr, array_buf->getTarget(), array_buf->getUsage(), array_buf->getMapFlags());
// Copy as much of the old data into the new GLBuffer as can fit.
GLBuffer::Bind bind(*new_array_buf);
@@ -222,10 +218,8 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float
OpenGL::TempDebugGroup debuggroup("SpriteBatch draw");
Matrix4 t(x, y, angle, sx, sy, ox, oy, kx, ky);
OpenGL::TempTransform transform(gl);
transform.get() *= t;
transform.get() *= Matrix4(x, y, angle, sx, sy, ox, oy, kx, ky);
gl.bindTexture(*(GLuint *) texture->getHandle());
@@ -233,8 +227,7 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float
GLBuffer::Bind element_bind(*quad_indices.getBuffer());
// Make sure the VBO isn't mapped when we draw (sends data to GPU if needed.)
array_buf->unmap(buffer_used_offset, buffer_used_size);
buffer_used_offset = buffer_used_size = 0;
array_buf->unmap();
uint32 enabledattribs = ATTRIBFLAG_POS | ATTRIBFLAG_TEXCOORD;
@@ -254,7 +247,7 @@ void SpriteBatch::draw(float x, float y, float angle, float sx, float sy, float
gl.drawElements(GL_TRIANGLES, (GLsizei) quad_indices.getIndexCount(next), quad_indices.getType(), quad_indices.getPointer(0));
}
void SpriteBatch::addv(const Vertex *v, const Matrix4 &m, int index)
void SpriteBatch::addv(const Vertex *v, const Matrix3 &m, int index)
{
// Needed for colors.
Vertex sprite[4] = {v[0], v[1], v[2], v[3]};
@@ -272,9 +265,6 @@ void SpriteBatch::addv(const Vertex *v, const Matrix4 &m, int index)
array_buf->map();
array_buf->fill(index * sprite_size, sprite_size, sprite);
buffer_used_offset = std::min(buffer_used_offset, index * sprite_size);
buffer_used_size = std::max(buffer_used_size, (index + 1) * sprite_size - buffer_used_offset);
}
void SpriteBatch::setColorv(Vertex *v, const Color &color)
@@ -103,7 +103,7 @@ public:
private:
void addv(const Vertex *v, const Matrix4 &m, int index);
void addv(const Vertex *v, const Matrix3 &m, int index);
/**
* Set the color for vertices.
@@ -129,10 +129,6 @@ private:
GLBuffer *array_buf;
QuadIndices quad_indices;
// The portion of the vertex buffer that's been modified while mapped.
size_t buffer_used_offset;
size_t buffer_used_size;
}; // SpriteBatch
} // opengl
@@ -170,7 +170,7 @@ void Text::set(const std::string &text)
if (text.empty())
return set();
addTextData({text, -1.0f, Font::ALIGN_MAX_ENUM, false, false, Matrix4()});
addTextData({text, -1.0f, Font::ALIGN_MAX_ENUM, false, false, Matrix3()});
}
void Text::set(const std::string &text, float wrap, Font::AlignMode align)
@@ -178,7 +178,7 @@ void Text::set(const std::string &text, float wrap, Font::AlignMode align)
if (text.empty())
return set();
addTextData({text, wrap, align, false, false, Matrix4()});
addTextData({text, wrap, align, false, false, Matrix3()});
}
void Text::set()
@@ -191,7 +191,7 @@ void Text::add(const std::string &text, float x, float y, float angle, float sx,
if (text.empty())
return;
Matrix4 m(x, y, angle, sx, sy, ox, oy, kx, ky);
Matrix3 m(x, y, angle, sx, sy, ox, oy, kx, ky);
addTextData({text, -1.0f, Font::ALIGN_MAX_ENUM, true, true, m});
}
@@ -201,7 +201,7 @@ void Text::addf(const std::string &text, float wrap, Font::AlignMode align, floa
if (text.empty())
return;
Matrix4 m(x, y, angle, sx, sy, ox, oy, kx, ky);
Matrix3 m(x, y, angle, sx, sy, ox, oy, kx, ky);
addTextData({text, wrap, align, true, true, m});
}
@@ -230,10 +230,8 @@ void Text::draw(float x, float y, float angle, float sx, float sy, float ox, flo
const size_t tex_offset = offsetof(Font::GlyphVertex, s);
const size_t stride = sizeof(Font::GlyphVertex);
Matrix4 t(ceilf(x), ceilf(y), angle, sx, sy, ox, oy, kx, ky);
OpenGL::TempTransform transform(gl);
transform.get() *= t;
transform.get() *= Matrix4(ceilf(x), ceilf(y), angle, sx, sy, ox, oy, kx, ky);
{
GLBuffer::Bind bind(*vbo);
+1 -1
View File
@@ -74,7 +74,7 @@ private:
Font::AlignMode align;
bool use_matrix;
bool append_vertices;
Matrix4 matrix;
Matrix3 matrix;
};
void uploadVertices(const std::vector<Font::GlyphVertex> &vertices, size_t vertoffset);
@@ -51,12 +51,15 @@ int w_Canvas_renderTo(lua_State *L)
luax_catchexcept(L, [&](){ graphics->setCanvas(canvas); });
lua_settop(L, 2); // make sure the function is on top of the stack
lua_call(L, 0, 0);
int status = lua_pcall(L, 0, 0, 0);
graphics->setCanvas(oldcanvases);
for (Canvas *c : oldcanvases)
c->release();
if (status != 0)
return lua_error(L);
}
return 0;
@@ -54,7 +54,7 @@ int w_reset(lua_State *)
int w_clear(lua_State *L)
{
std::vector<Color> colors(1);
std::vector<Colorf> colors(1);
if (lua_isnoneornil(L, 1))
colors[0].set(0, 0, 0, 0);
@@ -67,20 +67,20 @@ int w_clear(lua_State *L)
for (int j = 1; j <= 4; j++)
lua_rawgeti(L, i + 1, j);
colors[i].r = (unsigned char) luaL_checkinteger(L, -4);
colors[i].g = (unsigned char) luaL_checkinteger(L, -3);
colors[i].b = (unsigned char) luaL_checkinteger(L, -2);
colors[i].a = (unsigned char) luaL_optinteger(L, -1, 255);
colors[i].r = (float) luaL_checknumber(L, -4);
colors[i].g = (float) luaL_checknumber(L, -3);
colors[i].b = (float) luaL_checknumber(L, -2);
colors[i].a = (float) luaL_optnumber(L, -1, 255);
lua_pop(L, 4);
}
}
else
{
colors[0].r = (unsigned char) luaL_checkinteger(L, 1);
colors[0].g = (unsigned char) luaL_checkinteger(L, 2);
colors[0].b = (unsigned char) luaL_checkinteger(L, 3);
colors[0].a = (unsigned char) luaL_optinteger(L, 4, 255);
colors[0].r = (float) luaL_checknumber(L, 1);
colors[0].g = (float) luaL_checknumber(L, 2);
colors[0].b = (float) luaL_checknumber(L, 3);
colors[0].a = (float) luaL_optnumber(L, 4, 255);
}
luax_catchexcept(L, [&]() {
@@ -136,6 +136,12 @@ int w_isActive(lua_State *L)
return 1;
}
int w_isGammaCorrect(lua_State *L)
{
luax_pushboolean(L, instance()->isGammaCorrect());
return 1;
}
int w_getWidth(lua_State *L)
{
lua_pushinteger(L, instance()->getWidth());
@@ -245,7 +251,7 @@ int w_newImage(lua_State *L)
{
luaL_checktype(L, 2, LUA_TTABLE);
flags.mipmaps = luax_boolflag(L, 2, imageFlagName(Image::FLAG_TYPE_MIPMAPS), flags.mipmaps);
flags.sRGB = luax_boolflag(L, 2, imageFlagName(Image::FLAG_TYPE_SRGB), flags.sRGB);
flags.linear = luax_boolflag(L, 2, imageFlagName(Image::FLAG_TYPE_LINEAR), flags.linear);
}
bool releasedata = false;
@@ -617,24 +623,6 @@ static Mesh::DrawMode luax_optmeshdrawmode(lua_State *L, int idx, Mesh::DrawMode
return def;
}
static inline size_t writeVertexByteData(lua_State *L, int startidx, int components, char *data)
{
uint8 *componentdata = (uint8 *) data;
for (int i = 0; i < components; i++)
componentdata[i] = (uint8) luaL_optnumber(L, startidx + i, 255);
return sizeof(uint8) * components;
}
static inline size_t writeVertexFloatData(lua_State *L, int startidx, int components, char *data)
{
float *componentdata = (float *) data;
for (int i = 0; i < components; i++)
componentdata[i] = (float) luaL_optnumber(L, startidx + i, 0);
return sizeof(float) * components;
}
static Mesh *newStandardMesh(lua_State *L)
{
Mesh *t = nullptr;
@@ -670,10 +658,20 @@ static Mesh *newStandardMesh(lua_State *L)
v.y = (float) luaL_checknumber(L, -7);
v.s = (float) luaL_optnumber(L, -6, 0.0);
v.t = (float) luaL_optnumber(L, -5, 0.0);
v.r = (unsigned char) luaL_optinteger(L, -4, 255);
v.g = (unsigned char) luaL_optinteger(L, -3, 255);
v.b = (unsigned char) luaL_optinteger(L, -2, 255);
v.a = (unsigned char) luaL_optinteger(L, -1, 255);
Colorf c = {
(float) luaL_optnumber(L, -4, 255) / 255.0f,
(float) luaL_optnumber(L, -3, 255) / 255.0f,
(float) luaL_optnumber(L, -2, 255) / 255.0f,
(float) luaL_optnumber(L, -1, 255) / 255.0f
};
gammaCorrectColor(c);
v.r = (unsigned char) (c.r * 255.0f);
v.g = (unsigned char) (c.g * 255.0f);
v.b = (unsigned char) (c.b * 255.0f);
v.a = (unsigned char) (c.a * 255.0f);
lua_pop(L, 9);
vertices.push_back(v);
@@ -799,16 +797,7 @@ static Mesh *newCustomMesh(lua_State *L)
}
// Fetch the values from Lua and store them in data buffer.
switch (vertexformat[i].type)
{
case Mesh::DATA_BYTE:
writeVertexByteData(L, -components, components, data);
break;
case Mesh::DATA_FLOAT:
default:
writeVertexFloatData(L, -components, components, data);
break;
}
luax_writeAttributeData(L, -components, vertexformat[i].type, components, data);
lua_pop(L, components);
@@ -867,25 +856,25 @@ int w_newText(lua_State *L)
int w_setColor(lua_State *L)
{
Color c;
Colorf c;
if (lua_istable(L, 1))
{
for (int i = 1; i <= 4; i++)
lua_rawgeti(L, 1, i);
c.r = (unsigned char) luaL_checknumber(L, -4);
c.g = (unsigned char) luaL_checknumber(L, -3);
c.b = (unsigned char) luaL_checknumber(L, -2);
c.a = (unsigned char) luaL_optnumber(L, -1, 255);
c.r = (float) luaL_checknumber(L, -4);
c.g = (float) luaL_checknumber(L, -3);
c.b = (float) luaL_checknumber(L, -2);
c.a = (float) luaL_optnumber(L, -1, 255);
lua_pop(L, 4);
}
else
{
c.r = (unsigned char) luaL_checknumber(L, 1);
c.g = (unsigned char) luaL_checknumber(L, 2);
c.b = (unsigned char) luaL_checknumber(L, 3);
c.a = (unsigned char) luaL_optnumber(L, 4, 255);
c.r = (float) luaL_checknumber(L, 1);
c.g = (float) luaL_checknumber(L, 2);
c.b = (float) luaL_checknumber(L, 3);
c.a = (float) luaL_optnumber(L, 4, 255);
}
instance()->setColor(c);
return 0;
@@ -893,35 +882,35 @@ int w_setColor(lua_State *L)
int w_getColor(lua_State *L)
{
Color c = instance()->getColor();
lua_pushinteger(L, c.r);
lua_pushinteger(L, c.g);
lua_pushinteger(L, c.b);
lua_pushinteger(L, c.a);
Colorf c = instance()->getColor();
lua_pushnumber(L, c.r);
lua_pushnumber(L, c.g);
lua_pushnumber(L, c.b);
lua_pushnumber(L, c.a);
return 4;
}
int w_setBackgroundColor(lua_State *L)
{
Color c;
Colorf c;
if (lua_istable(L, 1))
{
for (int i = 1; i <= 4; i++)
lua_rawgeti(L, 1, i);
c.r = (unsigned char) luaL_checknumber(L, -4);
c.g = (unsigned char) luaL_checknumber(L, -3);
c.b = (unsigned char) luaL_checknumber(L, -2);
c.a = (unsigned char) luaL_optnumber(L, -1, 255);
c.r = (float) luaL_checknumber(L, -4);
c.g = (float) luaL_checknumber(L, -3);
c.b = (float) luaL_checknumber(L, -2);
c.a = (float) luaL_optnumber(L, -1, 255);
lua_pop(L, 4);
}
else
{
c.r = (unsigned char) luaL_checknumber(L, 1);
c.g = (unsigned char) luaL_checknumber(L, 2);
c.b = (unsigned char) luaL_checknumber(L, 3);
c.a = (unsigned char) luaL_optnumber(L, 4, 255);
c.r = (float) luaL_checknumber(L, 1);
c.g = (float) luaL_checknumber(L, 2);
c.b = (float) luaL_checknumber(L, 3);
c.a = (float) luaL_optnumber(L, 4, 255);
}
instance()->setBackgroundColor(c);
return 0;
@@ -929,11 +918,11 @@ int w_setBackgroundColor(lua_State *L)
int w_getBackgroundColor(lua_State *L)
{
Color c = instance()->getBackgroundColor();
lua_pushinteger(L, c.r);
lua_pushinteger(L, c.g);
lua_pushinteger(L, c.b);
lua_pushinteger(L, c.a);
Colorf c = instance()->getBackgroundColor();
lua_pushnumber(L, c.r);
lua_pushnumber(L, c.g);
lua_pushnumber(L, c.b);
lua_pushnumber(L, c.a);
return 4;
}
@@ -1837,6 +1826,7 @@ static const luaL_Reg functions[] =
{ "isCreated", w_isCreated },
{ "isActive", w_isActive },
{ "isGammaCorrect", w_isGammaCorrect },
{ "getWidth", w_getWidth },
{ "getHeight", w_getHeight },
{ "getDimensions", w_getDimensions },
@@ -47,6 +47,7 @@ int w_discard(lua_State *L);
int w_present(lua_State *L);
int w_isCreated(lua_State *L);
int w_isActive(lua_State *L);
int w_isGammaCorrect(lua_State *L);
int w_getWidth(lua_State *L);
int w_getHeight(lua_State *L);
int w_getDimensions(lua_State *L);
@@ -66,9 +66,66 @@ uniform LOVE_UNIFORM_PRECISION mat3 NormalMatrix;
#endif
uniform mediump vec4 love_ScreenSize;]]
GLSL.FUNCTIONS = [[
float gammaToLinearPrecise(float c) {
return c <= 0.04045 ? c * 0.077399380804954 : pow((c + 0.055) * 0.9478672985782, 2.4);
}
vec3 gammaToLinearPrecise(vec3 c) {
bvec3 leq = lessThanEqual(c, vec3(0.04045));
c.r = leq.r ? c.r * 0.077399380804954 : pow((c.r + 0.055) * 0.9478672985782, 2.4);
c.g = leq.g ? c.g * 0.077399380804954 : pow((c.g + 0.055) * 0.9478672985782, 2.4);
c.b = leq.b ? c.b * 0.077399380804954 : pow((c.b + 0.055) * 0.9478672985782, 2.4);
return c;
}
vec4 gammaToLinearPrecise(vec4 c) { return vec4(gammaToLinearPrecise(c.rgb), c.a); }
float linearToGammaPrecise(float c) {
return c < 0.0031308 ? c * 12.92 : 1.055 * pow(c, 1.0 / 2.4) - 0.055;
}
vec3 linearToGammaPrecise(vec3 c) {
bvec3 lt = lessThan(c, vec3(0.0031308));
c.r = lt.r ? c.r * 12.92 : 1.055 * pow(c.r, 1.0 / 2.4) - 0.055;
c.g = lt.g ? c.g * 12.92 : 1.055 * pow(c.g, 1.0 / 2.4) - 0.055;
c.b = lt.b ? c.b * 12.92 : 1.055 * pow(c.b, 1.0 / 2.4) - 0.055;
return c;
}
vec4 linearToGammaPrecise(vec4 c) { return vec4(linearToGammaPrecise(c.rgb), c.a); }
// pow(x, 2.2) isn't an amazing approximation, but at least it's efficient...
mediump float gammaToLinearFast(mediump float c) { return pow(max(c, 0.0), 2.2); }
mediump vec3 gammaToLinearFast(mediump vec3 c) { return pow(max(c, vec3(0.0)), vec3(2.2)); }
mediump vec4 gammaToLinearFast(mediump vec4 c) { return vec4(gammaToLinearFast(c.rgb), c.a); }
mediump float linearToGammaFast(mediump float c) { return pow(max(c, 0.0), 1.0 / 2.2); }
mediump vec3 linearToGammaFast(mediump vec3 c) { return pow(max(c, vec3(0.0)), vec3(1.0 / 2.2)); }
mediump vec4 linearToGammaFast(mediump vec4 c) { return vec4(linearToGammaFast(c.rgb), c.a); }
#ifdef LOVE_PRECISE_GAMMA
#define gammaToLinear gammaToLinearPrecise
#define linearToGamma linearToGammaPrecise
#else
#define gammaToLinear gammaToLinearFast
#define linearToGamma linearToGammaFast
#endif
#ifdef LOVE_GAMMA_CORRECT
#define gammaCorrectColor gammaToLinear
#define unGammaCorrectColor linearToGamma
#define gammaCorrectColorPrecise gammaToLinearPrecise
#define unGammaCorrectColorPrecise linearToGammaPrecise
#define gammaCorrectColorFast gammaToLinearFast
#define unGammaCorrectColorFast linearToGammaFast
#else
#define gammaCorrectColor
#define unGammaCorrectColor
#define gammaCorrectColorPrecise
#define unGammaCorrectColorPrecise
#define gammaCorrectColorFast
#define unGammaCorrectColorFast
#endif]]
GLSL.VERTEX = {
HEADER = [[
#define VERTEX
#define LOVE_PRECISE_GAMMA
attribute vec4 VertexPosition;
attribute vec4 VertexTexCoord;
@@ -85,7 +142,7 @@ uniform mediump float love_PointSize;
FOOTER = [[
void main() {
VaryingTexCoord = VertexTexCoord;
VaryingColor = VertexColor * ConstantColor;
VaryingColor = gammaCorrectColor(VertexColor) * ConstantColor;
#ifdef GL_ES
gl_PointSize = love_PointSize;
#endif
@@ -134,7 +191,10 @@ void main() {
local function createVertexCode(vertexcode, lang)
local vertexcodes = {
lang == "glsles" and GLSL.VERSION_ES or GLSL.VERSION,
GLSL.SYNTAX, GLSL.VERTEX.HEADER, GLSL.UNIFORMS,
GLSL.SYNTAX,
love.graphics.isGammaCorrect() and "#define LOVE_GAMMA_CORRECT 1" or "",
GLSL.VERTEX.HEADER, GLSL.UNIFORMS,
GLSL.FUNCTIONS,
lang == "glsles" and "#line 1" or "#line 0",
vertexcode,
GLSL.VERTEX.FOOTER,
@@ -145,7 +205,10 @@ end
local function createPixelCode(pixelcode, is_multicanvas, lang)
local pixelcodes = {
lang == "glsles" and GLSL.VERSION_ES or GLSL.VERSION,
GLSL.SYNTAX, GLSL.PIXEL.HEADER, GLSL.UNIFORMS,
GLSL.SYNTAX,
love.graphics.isGammaCorrect() and "#define LOVE_GAMMA_CORRECT 1" or "",
GLSL.PIXEL.HEADER, GLSL.UNIFORMS,
GLSL.FUNCTIONS,
lang == "glsles" and "#line 1" or "#line 0",
pixelcode,
is_multicanvas and GLSL.PIXEL.FOOTER_MULTI_CANVAS or GLSL.PIXEL.FOOTER,
@@ -131,8 +131,8 @@ int w_Image_getFlags(lua_State *L)
lua_pushboolean(L, flags.mipmaps);
lua_setfield(L, -2, imageFlagName(Image::FLAG_TYPE_MIPMAPS));
lua_pushboolean(L, flags.sRGB);
lua_setfield(L, -2, imageFlagName(Image::FLAG_TYPE_SRGB));
lua_pushboolean(L, flags.linear);
lua_setfield(L, -2, imageFlagName(Image::FLAG_TYPE_LINEAR));
return 1;
}
@@ -42,6 +42,7 @@ Mesh *luax_checkmesh(lua_State *L, int idx)
static inline size_t writeByteData(lua_State *L, int startidx, int components, char *data)
{
uint8 *componentdata = (uint8 *) data;
for (int i = 0; i < components; i++)
componentdata[i] = (uint8) luaL_optnumber(L, startidx + i, 255);
@@ -51,13 +52,14 @@ static inline size_t writeByteData(lua_State *L, int startidx, int components, c
static inline size_t writeFloatData(lua_State *L, int startidx, int components, char *data)
{
float *componentdata = (float *) data;
for (int i = 0; i < components; i++)
componentdata[i] = (float) luaL_optnumber(L, startidx + i, 0);
return sizeof(float) * components;
}
static inline char *writeAttributeData(lua_State *L, int startidx, Mesh::DataType type, int components, char *data)
char *luax_writeAttributeData(lua_State *L, int startidx, Mesh::DataType type, int components, char *data)
{
switch (type)
{
@@ -70,24 +72,34 @@ static inline char *writeAttributeData(lua_State *L, int startidx, Mesh::DataTyp
}
}
template <typename T>
static inline size_t readData(lua_State *L, int components, const char *data)
static inline size_t readByteData(lua_State *L, int components, const char *data)
{
const T *componentdata = (const T *) data;
const uint8 *componentdata = (const uint8 *) data;
for (int i = 0; i < components; i++)
lua_pushnumber(L, (lua_Number) componentdata[i]);
return sizeof(T) * components;
return sizeof(uint8) * components;
}
static inline const char *readAttributeData(lua_State *L, Mesh::DataType type, int components, const char *data)
static inline size_t readFloatData(lua_State *L, int components, const char *data)
{
const float *componentdata = (const float *) data;
for (int i = 0; i < components; i++)
lua_pushnumber(L, componentdata[i]);
return sizeof(float) * components;
}
const char *luax_readAttributeData(lua_State *L, Mesh::DataType type, int components, const char *data)
{
switch (type)
{
case Mesh::DATA_BYTE:
return data + readData<uint8>(L, components, data);
return data + readByteData(L, components, data);
case Mesh::DATA_FLOAT:
return data + readData<float>(L, components, data);
return data + readFloatData(L, components, data);
default:
return data;
}
@@ -125,7 +137,7 @@ int w_Mesh_setVertices(lua_State *L)
for (const Mesh::AttribFormat &format : vertexformat)
{
// Fetch the values from Lua and store them in data buffer.
data = writeAttributeData(L, idx, format.type, format.components, data);
data = luax_writeAttributeData(L, idx, format.type, format.components, data);
idx += format.components;
}
@@ -159,7 +171,7 @@ int w_Mesh_setVertex(lua_State *L)
lua_rawgeti(L, 3, i);
// Fetch the values from Lua and store them in data buffer.
writtendata = writeAttributeData(L, -format.components, format.type, format.components, writtendata);
writtendata = luax_writeAttributeData(L, -format.components, format.type, format.components, writtendata);
idx += format.components;
lua_pop(L, format.components);
@@ -170,7 +182,7 @@ int w_Mesh_setVertex(lua_State *L)
for (const Mesh::AttribFormat &format : vertexformat)
{
// Fetch the values from Lua and store them in data buffer.
writtendata = writeAttributeData(L, idx, format.type, format.components, writtendata);
writtendata = luax_writeAttributeData(L, idx, format.type, format.components, writtendata);
idx += format.components;
}
}
@@ -195,7 +207,7 @@ int w_Mesh_getVertex(lua_State *L)
for (const Mesh::AttribFormat &format : vertexformat)
{
readdata = readAttributeData(L, format.type, format.components, readdata);
readdata = luax_readAttributeData(L, format.type, format.components, readdata);
n += format.components;
}
@@ -216,7 +228,7 @@ int w_Mesh_setVertexAttribute(lua_State *L)
char data[sizeof(float) * 4];
// Fetch the values from Lua and store them in the data buffer.
writeAttributeData(L, 4, type, components, data);
luax_writeAttributeData(L, 4, type, components, data);
luax_catchexcept(L, [&](){ t->setVertexAttribute(vertindex, attribindex, data, sizeof(float) * 4); });
return 0;
@@ -237,7 +249,7 @@ int w_Mesh_getVertexAttribute(lua_State *L)
luax_catchexcept(L, [&](){ t->getVertexAttribute(vertindex, attribindex, data, sizeof(float) * 4); });
readAttributeData(L, type, components, data);
luax_readAttributeData(L, type, components, data);
return components;
}
@@ -32,6 +32,9 @@ namespace graphics
namespace opengl
{
char *luax_writeAttributeData(lua_State *L, int startidx, Mesh::DataType type, int components, char *data);
const char *luax_readAttributeData(lua_State *L, Mesh::DataType type, int components, const char *data);
Mesh *luax_checkmesh(lua_State *L, int idx);
int w_Mesh_setVertices(lua_State *L);
int w_Mesh_setVertex(lua_State *L);
@@ -499,7 +499,7 @@ int w_ParticleSystem_setColors(lua_State *L)
if (nColors > 8)
return luaL_error(L, "At most eight (8) colors may be used.");
std::vector<Color> colors(nColors);
std::vector<Colorf> colors(nColors);
for (int i = 0; i < nColors; i++)
{
@@ -512,15 +512,13 @@ int w_ParticleSystem_setColors(lua_State *L)
// push args[i+2][j+1] onto the stack
lua_rawgeti(L, i + 2, j + 1);
unsigned char r = (unsigned char) luaL_checkinteger(L, -4);
unsigned char g = (unsigned char) luaL_checkinteger(L, -3);
unsigned char b = (unsigned char) luaL_checkinteger(L, -2);
unsigned char a = (unsigned char) luaL_optinteger(L, -1, 255);
colors[i].r = (float) luaL_checknumber(L, -4);
colors[i].g = (float) luaL_checknumber(L, -3);
colors[i].b = (float) luaL_checknumber(L, -2);
colors[i].a = (float) luaL_optnumber(L, -1, 255);
// pop the color components from the stack
lua_pop(L, 4);
colors[i] = Color(r, g, b, a);
}
t->setColor(colors);
@@ -536,27 +534,17 @@ int w_ParticleSystem_setColors(lua_State *L)
if (nColors > 8)
return luaL_error(L, "At most eight (8) colors may be used.");
if (nColors == 1)
std::vector<Colorf> colors(nColors);
for (int i = 0; i < nColors; ++i)
{
unsigned char r = (unsigned char) luaL_checkinteger(L, 2);
unsigned char g = (unsigned char) luaL_checkinteger(L, 3);
unsigned char b = (unsigned char) luaL_checkinteger(L, 4);
unsigned char a = (unsigned char) luaL_optinteger(L, 5, 255);
t->setColor(Color(r,g,b,a));
}
else
{
std::vector<Color> colors(nColors);
for (int i = 0; i < nColors; ++i)
{
unsigned char r = (unsigned char) luaL_checkinteger(L, 1 + i*4 + 1);
unsigned char g = (unsigned char) luaL_checkinteger(L, 1 + i*4 + 2);
unsigned char b = (unsigned char) luaL_checkinteger(L, 1 + i*4 + 3);
unsigned char a = (unsigned char) luaL_checkinteger(L, 1 + i*4 + 4);
colors[i] = Color(r,g,b,a);
}
t->setColor(colors);
colors[i].r = (float) luaL_checknumber(L, 1 + i*4 + 1);
colors[i].g = (float) luaL_checknumber(L, 1 + i*4 + 2);
colors[i].b = (float) luaL_checknumber(L, 1 + i*4 + 3);
colors[i].a = (float) luaL_checknumber(L, 1 + i*4 + 4);
}
t->setColor(colors);
}
return 0;
@@ -566,19 +554,19 @@ int w_ParticleSystem_getColors(lua_State *L)
{
ParticleSystem *t = luax_checkparticlesystem(L, 1);
const std::vector<Color> &colors =t->getColor();
const std::vector<Colorf> &colors =t->getColor();
for (size_t i = 0; i < colors.size(); i++)
{
lua_createtable(L, 4, 0);
lua_pushinteger(L, colors[i].r);
lua_pushnumber(L, colors[i].r);
lua_rawseti(L, -2, 1);
lua_pushinteger(L, colors[i].g);
lua_pushnumber(L, colors[i].g);
lua_rawseti(L, -2, 2);
lua_pushinteger(L, colors[i].b);
lua_pushnumber(L, colors[i].b);
lua_rawseti(L, -2, 3);
lua_pushinteger(L, colors[i].a);
lua_pushnumber(L, colors[i].a);
lua_rawseti(L, -2, 4);
}
@@ -20,8 +20,11 @@
#include "wrap_Shader.h"
#include "graphics/wrap_Texture.h"
#include "math/MathModule.h"
#include <string>
#include <iostream>
#include <algorithm>
namespace love
{
@@ -148,7 +151,7 @@ int w_Shader_sendInt(lua_State *L)
return 0;
}
int w_Shader_sendFloat(lua_State *L)
static int w__Shader_sendFloat(lua_State *L, bool colors)
{
Shader *shader = luax_checkshader(L, 1);
const char *name = luaL_checkstring(L, 2);
@@ -157,7 +160,7 @@ int w_Shader_sendFloat(lua_State *L)
if (count < 1)
return luaL_error(L, "No variable to send.");
float *values = 0;
float *values = nullptr;
size_t dimension = 1;
if (lua_isnumber(L, 3) || lua_isboolean(L, 3))
@@ -170,6 +173,24 @@ int w_Shader_sendFloat(lua_State *L)
if (!values)
return luaL_error(L, "Error in arguments.");
if (colors)
{
bool gammacorrect = love::graphics::isGammaCorrect();
const auto &m = love::math::Math::instance;
for (int i = 0; i < count; i++)
{
for (int j = 0; j < (int) dimension; j++)
{
// the fourth component (alpha) is always already linear, if it exists.
if (gammacorrect && i < 4)
values[i * dimension + j] = m.gammaToLinear(values[i * dimension + j] / 255.0f);
else
values[i * dimension + j] /= 255.0f;
}
}
}
bool should_error = false;
try
{
@@ -189,6 +210,16 @@ int w_Shader_sendFloat(lua_State *L)
return 0;
}
int w_Shader_sendFloat(lua_State *L)
{
return w__Shader_sendFloat(L, false);
}
int w_Shader_sendColor(lua_State *L)
{
return w__Shader_sendFloat(L, true);
}
int w_Shader_sendMatrix(lua_State *L)
{
int count = lua_gettop(L) - 2;
@@ -372,6 +403,7 @@ static const luaL_Reg functions[] =
{ "sendInt", w_Shader_sendInt },
{ "sendBoolean", w_Shader_sendInt },
{ "sendFloat", w_Shader_sendFloat },
{ "sendColor", w_Shader_sendColor },
{ "sendMatrix", w_Shader_sendMatrix },
{ "sendTexture", w_Shader_sendTexture },
{ "send", w_Shader_send },
@@ -22,6 +22,7 @@
#define LOVE_GRAPHICS_OPENGL_WRAP_PROGRAM_H
#include "common/runtime.h"
#include "common/config.h"
#include "Shader.h"
namespace love
@@ -35,6 +36,7 @@ Shader *luax_checkshader(lua_State *L, int idx);
int w_Shader_getWarnings(lua_State *L);
int w_Shader_sendInt(lua_State *L);
int w_Shader_sendFloat(lua_State *L);
int w_Shader_sendColor(lua_State *L);
int w_Shader_sendMatrix(lua_State *L);
int w_Shader_sendTexture(lua_State *L);
int w_Shader_send(lua_State *L);
@@ -144,19 +144,19 @@ int w_SpriteBatch_setColor(lua_State *L)
for (int i = 1; i <= 4; i++)
lua_rawgeti(L, 2, i);
c.r = (unsigned char) luaL_checkinteger(L, -4);
c.g = (unsigned char) luaL_checkinteger(L, -3);
c.b = (unsigned char) luaL_checkinteger(L, -2);
c.a = (unsigned char) luaL_optinteger(L, -1, 255);
c.r = (unsigned char) luaL_checknumber(L, -4);
c.g = (unsigned char) luaL_checknumber(L, -3);
c.b = (unsigned char) luaL_checknumber(L, -2);
c.a = (unsigned char) luaL_optnumber(L, -1, 255);
lua_pop(L, 4);
}
else
{
c.r = (unsigned char)luaL_checkinteger(L, 2);
c.g = (unsigned char)luaL_checkinteger(L, 3);
c.b = (unsigned char)luaL_checkinteger(L, 4);
c.a = (unsigned char)luaL_optinteger(L, 5, 255);
c.r = (unsigned char) luaL_checknumber(L, 2);
c.g = (unsigned char) luaL_checknumber(L, 3);
c.b = (unsigned char) luaL_checknumber(L, 4);
c.a = (unsigned char) luaL_optnumber(L, 5, 255);
}
t->setColor(c);
@@ -169,14 +169,14 @@ int w_SpriteBatch_getColor(lua_State *L)
SpriteBatch *t = luax_checkspritebatch(L, 1);
const Color *color = t->getColor();
// getColor returns NULL if no color is set.
// getColor returns null if no color is set.
if (!color)
return 0;
lua_pushinteger(L, (lua_Integer) color->r);
lua_pushinteger(L, (lua_Integer) color->g);
lua_pushinteger(L, (lua_Integer) color->b);
lua_pushinteger(L, (lua_Integer) color->a);
lua_pushnumber(L, color->r);
lua_pushnumber(L, color->g);
lua_pushnumber(L, color->b);
lua_pushnumber(L, color->a);
return 4;
}
@@ -170,7 +170,7 @@ uint8 *KTXHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
{
uint32 *headerArray = (uint32 *) &header.glType;
for (int i = 0; i < 12; i++)
headerArray[i] = swap32(headerArray[i]);
headerArray[i] = swapuint32(headerArray[i]);
}
header.numberOfMipmapLevels = std::max(header.numberOfMipmapLevels, 1u);
@@ -203,7 +203,7 @@ uint8 *KTXHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
uint32 mipsize = *(uint32 *) (filebytes + fileoffset);
if (header.endianness == KTX_ENDIAN_REF_REV)
mipsize = swap32(mipsize);
mipsize = swapuint32(mipsize);
fileoffset += sizeof(uint32);
@@ -235,7 +235,7 @@ uint8 *KTXHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
uint32 mipsize = *(uint32 *) (filebytes + fileoffset);
if (header.endianness == KTX_ENDIAN_REF_REV)
mipsize = swap32(mipsize);
mipsize = swapuint32(mipsize);
fileoffset += sizeof(uint32);
@@ -38,7 +38,7 @@ inline uint16 swap16big(uint16 x)
#ifdef LOVE_BIG_ENDIAN
return x;
#else
return swap16(x);
return swapuint16(x);
#endif
}
@@ -117,7 +117,7 @@ void ConvertPVRHeader(PVRTexHeaderV2 header2, PVRTexHeaderV3 *header3)
// All of the struct's members are uint32 values, so we can do this.
uint32 *headerArray = (uint32 *) &header2;
for (size_t i = 0; i < sizeof(PVRTexHeaderV2) / sizeof(uint32); i++)
headerArray[i] = swap32(headerArray[i]);
headerArray[i] = swapuint32(headerArray[i]);
}
memset(header3, 0, sizeof(PVRTexHeaderV3));
@@ -309,16 +309,16 @@ uint8 *PVRHandler::parse(filesystem::FileData *filedata, std::vector<CompressedI
if (header3.version == PVRTEX3_IDENT_REV)
{
header3.version = PVRTEX3_IDENT;
header3.flags = swap32(header3.flags);
header3.pixelFormat = swap64(header3.pixelFormat);
header3.colorSpace = swap32(header3.colorSpace);
header3.channelType = swap32(header3.channelType);
header3.height = swap32(header3.height);
header3.width = swap32(header3.width);
header3.depth = swap32(header3.depth);
header3.numFaces = swap32(header3.numFaces);
header3.numMipmaps = swap32(header3.numMipmaps);
header3.metaDataSize = swap32(header3.metaDataSize);
header3.flags = swapuint32(header3.flags);
header3.pixelFormat = swapuint64(header3.pixelFormat);
header3.colorSpace = swapuint32(header3.colorSpace);
header3.channelType = swapuint32(header3.channelType);
header3.height = swapuint32(header3.height);
header3.width = swapuint32(header3.width);
header3.depth = swapuint32(header3.depth);
header3.numFaces = swapuint32(header3.numFaces);
header3.numMipmaps = swapuint32(header3.numMipmaps);
header3.metaDataSize = swapuint32(header3.metaDataSize);
}
if (header3.depth > 1)
+16
View File
@@ -55,6 +55,11 @@
# include "libraries/luautf8/lutf8lib.h"
#endif
// For love::graphics::setGammaCorrect.
#ifdef LOVE_ENABLE_GRAPHICS
# include "graphics/Graphics.h"
#endif
// Scripts
#include "scripts/nogame.lua.h"
#include "scripts/boot.lua.h"
@@ -238,6 +243,14 @@ static int w_love_isVersionCompatible(lua_State *L)
return 1;
}
static int w__setGammaCorrect(lua_State *L)
{
#ifdef LOVE_ENABLE_GRAPHICS
love::graphics::setGammaCorrect((bool) lua_toboolean(L, 1));
#endif
return 0;
}
int luaopen_love(lua_State *L)
{
love::luax_insistpinnedthread(L);
@@ -268,6 +281,9 @@ int luaopen_love(lua_State *L)
lua_setfield(L, -2, "_setAccelerometerAsJoystick");
#endif
lua_pushcfunction(L, w__setGammaCorrect);
lua_setfield(L, -2, "_setGammaCorrect");
lua_newtable(L);
for (int i = 0; love::VERSION_COMPATIBILITY[i] != nullptr; i++)
+2 -2
View File
@@ -63,7 +63,7 @@ public:
// Store the size of the uncompressed data as a header.
#ifdef LOVE_BIG_ENDIAN
// Make sure it's little-endian for storage.
*(uint32 *) compressedbytes = swap32((uint32) dataSize);
*(uint32 *) compressedbytes = swapuint32((uint32) dataSize);
#else
*(uint32 *) compressedbytes = (uint32) dataSize;
#endif
@@ -110,7 +110,7 @@ public:
// Extract the original uncompressed size (stored in our custom header.)
#ifdef LOVE_BIG_ENDIAN
// Convert from stored little-endian to big-endian.
uint32 rawsize = swap32(*(uint32 *) data);
uint32 rawsize = swapuint32(*(uint32 *) data);
#else
uint32 rawsize = *(uint32 *) data;
#endif
+3 -11
View File
@@ -208,11 +208,7 @@ bool Math::isConvex(const std::vector<Vertex> &polygon)
**/
float Math::gammaToLinear(float c) const
{
if (c > 1.0f)
return 1.0f;
else if (c < 0.0f)
return 0.0f;
else if (c <= 0.04045)
if (c <= 0.04045f)
return c / 12.92f;
else
return powf((c + 0.055f) / 1.055f, 2.4f);
@@ -223,14 +219,10 @@ float Math::gammaToLinear(float c) const
**/
float Math::linearToGamma(float c) const
{
if (c > 1.0f)
return 1.0f;
else if (c < 0.0f)
return 0.0f;
else if (c < 0.0031308f)
if (c < 0.0031308f)
return c * 12.92f;
else
return 1.055f * powf(c, 0.41666f) - 0.055f;
return 1.055f * powf(c, 1.0f / 2.4f) - 0.055f;
}
CompressedData *Math::compress(Compressor::Format format, love::Data *rawdata, int level)
-1
View File
@@ -77,7 +77,6 @@ StringMap<Window::Setting, Window::SETTING_MAX_ENUM>::Entry Window::settingEntri
{"centered", SETTING_CENTERED},
{"display", SETTING_DISPLAY},
{"highdpi", SETTING_HIGHDPI},
{"srgb", SETTING_SRGB},
{"refreshrate", SETTING_REFRESHRATE},
{"x", SETTING_X},
{"y", SETTING_Y},
-2
View File
@@ -57,7 +57,6 @@ public:
SETTING_CENTERED,
SETTING_DISPLAY,
SETTING_HIGHDPI,
SETTING_SRGB,
SETTING_REFRESHRATE,
SETTING_X,
SETTING_Y,
@@ -210,7 +209,6 @@ struct WindowSettings
bool centered = true;
int display = 0;
bool highdpi = false;
bool sRGB = false;
double refreshrate = 0.0;
bool useposition = false;
int x = 0;
+31 -15
View File
@@ -62,9 +62,14 @@ Window::Window()
, context(nullptr)
, displayedWindowError(false)
, displayedContextError(false)
, hasSDL203orEarlier(false)
{
if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0)
throw love::Exception("Could not initialize SDL video subsystem (%s)", SDL_GetError());
SDL_version version = {};
SDL_GetVersion(&version);
hasSDL203orEarlier = (version.major == 2 && version.minor == 0 && version.patch <= 3);
}
Window::~Window()
@@ -88,12 +93,17 @@ void Window::setGLFramebufferAttributes(int msaa, bool sRGB)
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLEBUFFERS, (msaa > 0) ? 1 : 0);
SDL_GL_SetAttribute(SDL_GL_MULTISAMPLESAMPLES, (msaa > 0) ? msaa : 0);
// SDL or GLX may have bugs with this: https://bugzilla.libsdl.org/show_bug.cgi?id=2897
// It's fine to leave the attribute disabled on desktops though, because in
// practice the framebuffer will be sRGB-capable even if it's not requested.
#if !defined(LOVE_LINUX)
SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, sRGB ? 1 : 0);
#endif
const char *driver = SDL_GetCurrentVideoDriver();
if (driver && strstr(driver, "x11") == driver)
{
// Always disable the sRGB flag when GLX is used with older SDL versions,
// because of this bug: https://bugzilla.libsdl.org/show_bug.cgi?id=2897
// In practice GLX will always give an sRGB-capable framebuffer anyway.
if (hasSDL203orEarlier)
SDL_GL_SetAttribute(SDL_GL_FRAMEBUFFER_SRGB_CAPABLE, 0);
}
#if defined(LOVE_WINDOWS)
// Avoid the Microsoft OpenGL 1.1 software renderer on Windows. Apparently
@@ -158,7 +168,7 @@ bool Window::checkGLVersion(const ContextAttribs &attribs)
return true;
}
bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowflags, int msaa, bool sRGB)
bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowflags, int msaa)
{
bool preferGLES = false;
@@ -175,6 +185,14 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla
if (curdriver && strstr(curdriver, glesdriver) == curdriver)
{
preferGLES = true;
// Prior to SDL 2.0.4, backends that use OpenGL ES didn't properly
// ask for a sRGB framebuffer when requested by SDL_GL_SetAttribute.
// FIXME: This doesn't account for windowing backends that sometimes
// use EGL, e.g. the X11 and windows SDL backends.
if (hasSDL203orEarlier)
graphics::setGammaCorrect(false);
break;
}
}
@@ -196,11 +214,8 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla
{2, 0, true, debug}, // OpenGL ES 2.
};
SDL_version sdlversion = {};
SDL_GetVersion(&sdlversion);
// OpenGL ES 3+ contexts are only properly supported in SDL 2.0.4+.
if (sdlversion.major == 2 && sdlversion.minor == 0 && sdlversion.patch <= 3)
if (hasSDL203orEarlier)
attribslist.erase(attribslist.begin() + 1);
// Move OpenGL ES to the front of the list if we should prefer GLES.
@@ -229,7 +244,7 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla
}
int curMSAA = msaa;
bool curSRGB = sRGB;
bool curSRGB = love::graphics::isGammaCorrect();
setGLFramebufferAttributes(curMSAA, curSRGB);
setGLContextAttributes(attribs);
@@ -312,7 +327,10 @@ bool Window::createWindowAndContext(int x, int y, int w, int h, Uint32 windowfla
}
if (context)
{
love::graphics::setGammaCorrect(curSRGB);
break;
}
}
if (!context || !window)
@@ -437,7 +455,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
close();
if (!createWindowAndContext(x, y, width, height, sdlflags, f.msaa, f.sRGB))
if (!createWindowAndContext(x, y, width, height, sdlflags, f.msaa))
return false;
// Make sure the window keeps any previously set icon.
@@ -460,7 +478,7 @@ bool Window::setWindow(int width, int height, WindowSettings *settings)
auto gfx = Module::getInstance<graphics::Graphics>(Module::M_GRAPHICS);
if (gfx != nullptr)
gfx->setMode(curMode.pixelwidth, curMode.pixelheight, curMode.settings.sRGB);
gfx->setMode(curMode.pixelwidth, curMode.pixelheight);
#ifdef LOVE_ANDROID
love::android::setImmersive(f.fullscreen);
@@ -538,8 +556,6 @@ void Window::updateSettings(const WindowSettings &newsettings)
else
SDL_SetHint(SDL_HINT_VIDEO_MINIMIZE_ON_FOCUS_LOSS, "0");
curMode.settings.sRGB = newsettings.sRGB;
// Verify MSAA setting.
int buffers = 0;
int samples = 0;
+3 -1
View File
@@ -119,7 +119,7 @@ private:
void setGLFramebufferAttributes(int msaa, bool sRGB);
void setGLContextAttributes(const ContextAttribs &attribs);
bool checkGLVersion(const ContextAttribs &attribs);
bool createWindowAndContext(int x, int y, int w, int h, Uint32 windowflags, int msaa, bool sRGB);
bool createWindowAndContext(int x, int y, int w, int h, Uint32 windowflags, int msaa);
// Update the saved window settings based on the window's actual state.
void updateSettings(const WindowSettings &newsettings);
@@ -149,6 +149,8 @@ private:
bool displayedWindowError;
bool displayedContextError;
bool hasSDL203orEarlier;
}; // Window
} // sdl
@@ -107,7 +107,6 @@ 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) - 1;
settings.highdpi = luax_boolflag(L, 3, settingName(Window::SETTING_HIGHDPI), false);
settings.sRGB = luax_boolflag(L, 3, settingName(Window::SETTING_SRGB), false);
lua_getfield(L, 3, settingName(Window::SETTING_X));
lua_getfield(L, 3, settingName(Window::SETTING_Y));
@@ -175,9 +174,6 @@ 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));
lua_pushnumber(L, settings.refreshrate);
lua_setfield(L, -2, settingName(Window::SETTING_REFRESHRATE));