diff --git a/src/common/runtime.h b/src/common/runtime.h index b3d193da9..43807f5c6 100644 --- a/src/common/runtime.h +++ b/src/common/runtime.h @@ -22,6 +22,7 @@ #define LOVE_RUNTIME_H // LOVE +#include "config.h" #include "types.h" #include "deprecation.h" @@ -35,6 +36,7 @@ extern "C" { // C++ #include +#include namespace love { @@ -204,6 +206,16 @@ inline float luax_checkfloat(lua_State *L, int idx) return static_cast(luaL_checknumber(L, idx)); } +inline lua_Number luax_checknumberclamped01(lua_State *L, int idx) +{ + return std::min(std::max(luaL_checknumber(L, idx), 0.0), 1.0); +} + +inline lua_Number luax_optnumberclamped01(lua_State *L, int idx, double def) +{ + return std::min(std::max(luaL_optnumber(L, idx, def), 0.0), 1.0); +} + /** * Require at least 'min' number of items on the stack. * @param L The Lua state. diff --git a/src/modules/graphics/Font.cpp b/src/modules/graphics/Font.cpp index feda0dd2a..48b032add 100644 --- a/src/modules/graphics/Font.cpp +++ b/src/modules/graphics/Font.cpp @@ -947,7 +947,7 @@ bool Font::hasGlyph(uint32 glyph) const if (r->hasGlyph(glyph)) return true; } - + return false; } @@ -955,7 +955,7 @@ bool Font::hasGlyphs(const std::string &text) const { if (text.size() == 0) return false; - + try { utf8::iterator i(text.begin(), text.begin(), text.end()); @@ -973,7 +973,7 @@ bool Font::hasGlyphs(const std::string &text) const { throw love::Exception("UTF-8 decoding error: %s", e.what()); } - + return true; } @@ -984,9 +984,9 @@ void Font::setFallbacks(const std::vector &fallbacks) if (f->rasterizers[0]->getDataType() != this->rasterizers[0]->getDataType()) throw love::Exception("Font fallbacks must be of the same font type."); } - + rasterizers.resize(1); - + // NOTE: this won't invalidate already-rasterized glyphs. for (const Font *f : fallbacks) rasterizers.push_back(f->rasterizers[0]); diff --git a/src/modules/graphics/wrap_Graphics.cpp b/src/modules/graphics/wrap_Graphics.cpp index 184b2fcf9..61f77782c 100644 --- a/src/modules/graphics/wrap_Graphics.cpp +++ b/src/modules/graphics/wrap_Graphics.cpp @@ -2445,10 +2445,10 @@ int w_points(lua_State *L) positions[i].x = luax_checkfloat(L, -6); positions[i].y = luax_checkfloat(L, -5); - colors[i].r = (float) luaL_optnumber(L, -4, 1.0); - colors[i].g = (float) luaL_optnumber(L, -3, 1.0); - colors[i].b = (float) luaL_optnumber(L, -2, 1.0); - colors[i].a = (float) luaL_optnumber(L, -1, 1.0); + colors[i].r = (float) luax_optnumberclamped01(L, -4, 1.0); + colors[i].g = (float) luax_optnumberclamped01(L, -3, 1.0); + colors[i].b = (float) luax_optnumberclamped01(L, -2, 1.0); + colors[i].a = (float) luax_optnumberclamped01(L, -1, 1.0); lua_pop(L, 7); } diff --git a/src/modules/graphics/wrap_Mesh.cpp b/src/modules/graphics/wrap_Mesh.cpp index de32ddc77..77446a0dd 100644 --- a/src/modules/graphics/wrap_Mesh.cpp +++ b/src/modules/graphics/wrap_Mesh.cpp @@ -42,7 +42,7 @@ static inline size_t writeUnorm8Data(lua_State *L, int startidx, int components, uint8 *componentdata = (uint8 *) data; for (int i = 0; i < components; i++) - componentdata[i] = (uint8) (luaL_optnumber(L, startidx + i, 1.0) * 255.0); + componentdata[i] = (uint8) (luax_optnumberclamped01(L, startidx + i, 1.0) * 255.0); return sizeof(uint8) * components; } @@ -52,7 +52,7 @@ static inline size_t writeUnorm16Data(lua_State *L, int startidx, int components uint16 *componentdata = (uint16 *) data; for (int i = 0; i < components; i++) - componentdata[i] = (uint16) (luaL_optnumber(L, startidx + i, 1.0) * 65535.0); + componentdata[i] = (uint16) (luax_optnumberclamped01(L, startidx + i, 1.0) * 65535.0); return sizeof(uint16) * components; } diff --git a/src/modules/graphics/wrap_Shader.cpp b/src/modules/graphics/wrap_Shader.cpp index 080d906b8..6114fb709 100644 --- a/src/modules/graphics/wrap_Shader.cpp +++ b/src/modules/graphics/wrap_Shader.cpp @@ -52,13 +52,13 @@ static int _getCount(lua_State *L, int startidx, const Shader::UniformInfo *info return std::min(std::max(lua_gettop(L) - startidx + 1, 1), info->count); } -template +template static void _updateNumbers(lua_State *L, int startidx, T *values, int components, int count) { if (components == 1) { for (int i = 0; i < count; ++i) - values[i] = (T) luaL_checknumber(L, startidx + i); + values[i] = (T) checknum(L, startidx + i); } else { @@ -69,7 +69,7 @@ static void _updateNumbers(lua_State *L, int startidx, T *values, int components for (int k = 1; k <= components; k++) { lua_rawgeti(L, startidx + i, k); - values[i * components + k - 1] = (T) luaL_checknumber(L, -1); + values[i * components + k - 1] = (T) checknum(L, -1); } lua_pop(L, components); @@ -83,7 +83,10 @@ int w_Shader_sendFloats(lua_State *L, int startidx, Shader *shader, const Shader int components = info->components; float *values = info->floats; - _updateNumbers(L, startidx, values, components, count); + if (colors) + _updateNumbers(L, startidx, values, components, count); + else + _updateNumbers(L, startidx, values, components, count); if (colors && graphics::isGammaCorrect()) { @@ -104,7 +107,7 @@ int w_Shader_sendFloats(lua_State *L, int startidx, Shader *shader, const Shader int w_Shader_sendInts(lua_State *L, int startidx, Shader *shader, const Shader::UniformInfo *info) { int count = _getCount(L, startidx, info); - _updateNumbers(L, startidx, info->ints, info->components, count); + _updateNumbers(L, startidx, info->ints, info->components, count); luax_catchexcept(L, [&]() { shader->updateUniform(info, count); }); return 0; } @@ -112,7 +115,7 @@ int w_Shader_sendInts(lua_State *L, int startidx, Shader *shader, const Shader:: int w_Shader_sendUnsignedInts(lua_State *L, int startidx, Shader *shader, const Shader::UniformInfo *info) { int count = _getCount(L, startidx, info); - _updateNumbers(L, startidx, info->uints, info->components, count); + _updateNumbers(L, startidx, info->uints, info->components, count); luax_catchexcept(L, [&]() { shader->updateUniform(info, count); }); return 0; } diff --git a/src/modules/image/wrap_ImageData.cpp b/src/modules/image/wrap_ImageData.cpp index a5dd2607b..731420588 100644 --- a/src/modules/image/wrap_ImageData.cpp +++ b/src/modules/image/wrap_ImageData.cpp @@ -88,22 +88,20 @@ int w_ImageData_getDimensions(lua_State *L) return 2; } -// TODO: rgba16f - static void luax_checkpixel_rgba8(lua_State *L, int startidx, Pixel &p) { for (int i = 0; i < 3; i++) - p.rgba8[i] = (uint8) (luaL_checknumber(L, startidx + i) * 255.0); + p.rgba8[i] = (uint8) (luax_checknumberclamped01(L, startidx + i) * 255.0); - p.rgba8[3] = (uint8) (luaL_optnumber(L, startidx + 3, 1.0) * 255.0); + p.rgba8[3] = (uint8) (luax_optnumberclamped01(L, startidx + 3, 1.0) * 255.0); } static void luax_checkpixel_rgba16(lua_State *L, int startidx, Pixel &p) { for (int i = 0; i < 3; i++) - p.rgba16[i] = (uint16) (luaL_checknumber(L, startidx + i) * 65535.0); + p.rgba16[i] = (uint16) (luax_checknumberclamped01(L, startidx + i) * 65535.0); - p.rgba16[3] = (uint16) (luaL_optnumber(L, startidx + 3, 1.0) * 65535.0); + p.rgba16[3] = (uint16) (luax_optnumberclamped01(L, startidx + 3, 1.0) * 65535.0); } static void luax_checkpixel_rgba16f(lua_State *L, int startidx, Pixel &p) diff --git a/src/modules/image/wrap_ImageData.lua b/src/modules/image/wrap_ImageData.lua index 37cea1399..5a9df6e34 100644 --- a/src/modules/image/wrap_ImageData.lua +++ b/src/modules/image/wrap_ImageData.lua @@ -27,10 +27,15 @@ local ImageData = ImageData_mt.__index local tonumber, assert, error = tonumber, assert, error local type, pcall = type, pcall -local floor = math.floor +local floor = math.floor +local min, max = math.min, math.max local function inside(x, y, w, h) return x >= 0 and x < w and y >= 0 and y < h +end + +local function clamp01(x) + return min(max(x, 0), 1) end -- Implement thread-safe ImageData:mapPixel regardless of whether the FFI is @@ -111,10 +116,10 @@ local conversions = { return tonumber(self.r) / 255, tonumber(self.g) / 255, tonumber(self.b) / 255, tonumber(self.a) / 255 end, fromlua = function(self, r, g, b, a) - self.r = r * 255 - self.g = g * 255 - self.b = b * 255 - self.a = a == nil and 255 or a * 255 + self.r = clamp01(r) * 255 + self.g = clamp01(g) * 255 + self.b = clamp01(b) * 255 + self.a = a == nil and 255 or clamp01(a) * 255 end, }, rgba16 = { @@ -123,10 +128,10 @@ local conversions = { return tonumber(self.r) / 65535, tonumber(self.g) / 65535, tonumber(self.b) / 65535, tonumber(self.a) / 65535 end, fromlua = function(self, r, g, b, a) - self.r = r * 65535 - self.g = g * 65535 - self.b = b * 65535 - self.a = a == nil and 65535 or a * 65535 + self.r = clamp01(r) * 65535 + self.g = clamp01(g) * 65535 + self.b = clamp01(b) * 65535 + self.a = a == nil and 65535 or clamp01(a) * 65535 end, }, rgba16f = { diff --git a/src/modules/math/wrap_Math.cpp b/src/modules/math/wrap_Math.cpp index 08366c70d..5829b826e 100644 --- a/src/modules/math/wrap_Math.cpp +++ b/src/modules/math/wrap_Math.cpp @@ -264,7 +264,7 @@ static int getGammaArgs(lua_State *L, float color[4]) for (int i = 1; i <= n && i <= 4; i++) { lua_rawgeti(L, 1, i); - color[i - 1] = (float) luaL_checknumber(L, -1); + color[i - 1] = (float) luax_checknumberclamped01(L, -1); numcomponents++; } @@ -275,7 +275,7 @@ static int getGammaArgs(lua_State *L, float color[4]) int n = lua_gettop(L); for (int i = 1; i <= n && i <= 4; i++) { - color[i - 1] = (float) luaL_checknumber(L, i); + color[i - 1] = (float) luax_checknumberclamped01(L, i); numcomponents++; } } diff --git a/src/modules/math/wrap_Math.lua b/src/modules/math/wrap_Math.lua index 0e2aa8232..888151165 100644 --- a/src/modules/math/wrap_Math.lua +++ b/src/modules/math/wrap_Math.lua @@ -26,6 +26,11 @@ local love_math, ffifuncspointer = ... local type, tonumber, error = type, tonumber, error local floor = math.floor +local min, max = math.min, math.max + +local function clamp01(x) + return min(max(x, 0), 1) +end local rng = love_math._getRandomGenerator() @@ -95,7 +100,7 @@ end local function gammaToLinear(c) if c ~= nil then - return tonumber(ffifuncs.gammaToLinear(c)) + return tonumber(ffifuncs.gammaToLinear(clamp01(c))) end return c end @@ -110,7 +115,7 @@ end local function linearToGamma(c) if c ~= nil then - return tonumber(ffifuncs.linearToGamma(c)) + return tonumber(ffifuncs.linearToGamma(clamp01(c))) end return c end