Implemented LuaJIT FFI versions of love.math.random and RandomGenerator:random.

This commit is contained in:
Alex Szpakowski
2015-12-10 12:45:53 -04:00
parent 7ee02e8d37
commit 52b1bd78f2
6 changed files with 175 additions and 40 deletions
@@ -840,6 +840,7 @@
FA27B3C61B4985D8008A9DCE /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA27B3C31B4985D8008A9DCE /* Video.cpp */; };
FA27B3C71B4985D8008A9DCE /* Video.h in Headers */ = {isa = PBXBuildFile; fileRef = FA27B3C41B4985D8008A9DCE /* Video.h */; };
FA27B3C91B498623008A9DCE /* Theora.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FA27B3C81B498623008A9DCE /* Theora.framework */; };
FA2E9BFF1C19E00C0004A1EE /* wrap_RandomGenerator.lua in Resources */ = {isa = PBXBuildFile; fileRef = FA2E9BFE1C19E00C0004A1EE /* wrap_RandomGenerator.lua */; };
FA317EBA18F28B6D00B0BCD7 /* libz.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = FA317EB918F28B6D00B0BCD7 /* libz.dylib */; };
FA41A3C81C0A1F950084430C /* ASTCHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA41A3C61C0A1F950084430C /* ASTCHandler.cpp */; };
FA41A3C91C0A1F950084430C /* ASTCHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = FA41A3C61C0A1F950084430C /* ASTCHandler.cpp */; };
@@ -1519,6 +1520,7 @@
FA27B3C81B498623008A9DCE /* Theora.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Theora.framework; path = /Library/Frameworks/Theora.framework; sourceTree = "<absolute>"; };
FA283EDC1B27CFAA00C70067 /* nogame.lua */ = {isa = PBXFileReference; lastKnownFileType = text; path = nogame.lua; sourceTree = "<group>"; };
FA283EDD1B27CFAA00C70067 /* nogame.lua.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = nogame.lua.h; sourceTree = "<group>"; };
FA2E9BFE1C19E00C0004A1EE /* wrap_RandomGenerator.lua */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = wrap_RandomGenerator.lua; sourceTree = "<group>"; };
FA317EB918F28B6D00B0BCD7 /* libz.dylib */ = {isa = PBXFileReference; lastKnownFileType = "compiled.mach-o.dylib"; name = libz.dylib; path = usr/lib/libz.dylib; sourceTree = SDKROOT; };
FA41A3C61C0A1F950084430C /* ASTCHandler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ASTCHandler.cpp; sourceTree = "<group>"; };
FA41A3C71C0A1F950084430C /* ASTCHandler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASTCHandler.h; sourceTree = "<group>"; };
@@ -2461,6 +2463,7 @@
FA7DA04C1C16874A0056B200 /* wrap_Math.lua */,
FA0B7C0B1A95902C000E1D17 /* wrap_RandomGenerator.cpp */,
FA0B7C0C1A95902C000E1D17 /* wrap_RandomGenerator.h */,
FA2E9BFE1C19E00C0004A1EE /* wrap_RandomGenerator.lua */,
);
path = math;
sourceTree = "<group>";
@@ -3297,6 +3300,7 @@
buildActionMask = 2147483647;
files = (
FA19C4C81B4B0BD50059B0B3 /* wrap_Video.lua in Resources */,
FA2E9BFF1C19E00C0004A1EE /* wrap_RandomGenerator.lua in Resources */,
FA7DA04D1C16874A0056B200 /* wrap_Math.lua in Resources */,
);
runOnlyForDeploymentPostprocessing = 0;
+11 -3
View File
@@ -39,9 +39,10 @@ namespace love
namespace math
{
int w_random(lua_State *L)
int w__random(lua_State *L)
{
return luax_getrandom(L, 1, Math::instance.random());
lua_pushnumber(L, Math::instance.random());
return 1;
}
int w_randomNormal(lua_State *L)
@@ -422,6 +423,8 @@ int w_decompress(lua_State *L)
// C functions in a struct, necessary for the FFI versions of math functions.
struct FFI_Math
{
double (*random)(void);
float (*noise1)(float x);
float (*noise2)(float x, float y);
float (*noise3)(float x, float y, float z);
@@ -433,6 +436,11 @@ struct FFI_Math
static FFI_Math ffifuncs =
{
[](void) -> double // random
{
return Math::instance.random();
},
[](float x) -> float // noise1
{
return Math::instance.noise(x);
@@ -463,7 +471,7 @@ static FFI_Math ffifuncs =
// List of functions to wrap.
static const luaL_Reg functions[] =
{
{ "random", w_random },
{ "_random", w__random }, // love.math.random is inside wrap_Math.lua.
{ "randomNormal", w_randomNormal },
{ "setRandomSeed", w_setRandomSeed },
{ "getRandomSeed", w_getRandomSeed },
+34 -6
View File
@@ -22,7 +22,30 @@ misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
--]]
local math, ffifuncspointer = ...
local love_math, ffifuncspointer = ...
local type, tonumber, error = type, tonumber, error
local floor = math.floor
local _random = love_math._random
local function getrandom(r, l, u)
if u ~= nil then
if type(r) ~= "number" then error("bad argument #1 to 'random' (number expected)", 2) end
if type(l) ~= "number" then error("bad argument #2 to 'random' (number expected)", 2) end
return floor(r * (u - l + 1)) + l
elseif l ~= nil then
if type(l) ~= "number" then error("bad argument #1 to 'random' (number expected)", 2) end
return floor(r * l) + 1
else
return r
end
end
function love_math.random(l, u)
local r = _random()
return getrandom(r, l, u)
end
if type(jit) ~= "table" or not jit.status() then
-- LuaJIT's FFI is *much* slower than LOVE's regular methods when the JIT
@@ -33,12 +56,12 @@ end
local status, ffi = pcall(require, "ffi")
if not status then return end
local type, tonumber = type, tonumber
-- Matches the struct declaration in wrap_Math.cpp.
pcall(ffi.cdef, [[
typedef struct FFI_Math
{
double (*random)(void);
float (*noise1)(float x);
float (*noise2)(float x, float y);
float (*noise3)(float x, float y, float z);
@@ -54,7 +77,12 @@ local ffifuncs = ffi.cast("FFI_Math *", ffifuncspointer)
-- Overwrite some regular love.math functions with FFI implementations.
function math.noise(x, y, z, w)
function love_math.random(l, u)
local r = tonumber(ffifuncs.random())
return getrandom(r, l, u)
end
function love_math.noise(x, y, z, w)
if w ~= nil then
return tonumber(ffifuncs.noise4(x, y, z, w))
elseif z ~= nil then
@@ -73,7 +101,7 @@ local function gammaToLinear(c)
return c
end
function math.gammaToLinear(r, g, b, a)
function love_math.gammaToLinear(r, g, b, a)
if type(r) == "table" then
local t = r
return gammaToLinear(t[1]), gammaToLinear(t[2]), gammaToLinear(t[3]), t[4]
@@ -88,7 +116,7 @@ local function linearToGamma(c)
return c
end
function math.linearToGamma(r, g, b, a)
function love_math.linearToGamma(r, g, b, a)
if type(r) == "table" then
local t = r
return linearToGamma(t[1]), linearToGamma(t[2]), linearToGamma(t[3]), t[4]
+46 -30
View File
@@ -23,6 +23,11 @@
#include <cmath>
#include <algorithm>
// Put the Lua code directly into a raw string literal.
static const char randomgenerator_lua[] =
#include "wrap_RandomGenerator.lua"
;
namespace love
{
namespace math
@@ -56,41 +61,16 @@ RandomGenerator::Seed luax_checkrandomseed(lua_State *L, int idx)
return s;
}
int luax_getrandom(lua_State *L, int startidx, double r)
{
int l, u;
// from lua 5.1.4 source code: lmathlib.c:185 ff.
switch (lua_gettop(L) - (startidx - 1))
{
case 0:
lua_pushnumber(L, r);
break;
case 1:
u = (int) luaL_checknumber(L, startidx);
luaL_argcheck(L, 1 <= u, startidx, "interval is empty");
lua_pushnumber(L, floor(r * u) + 1);
break;
case 2:
l = (int) luaL_checknumber(L, startidx);
u = (int) luaL_checknumber(L, startidx + 1);
luaL_argcheck(L, l <= u, startidx + 1, "interval is empty");
lua_pushnumber(L, floor(r * (u - l + 1)) + l);
break;
default:
return luaL_error(L, "wrong number of arguments");
}
return 1;
}
RandomGenerator *luax_checkrandomgenerator(lua_State *L, int idx)
{
return luax_checktype<RandomGenerator>(L, idx, MATH_RANDOM_GENERATOR_ID);
}
int w_RandomGenerator_random(lua_State *L)
int w_RandomGenerator__random(lua_State *L)
{
RandomGenerator *rng = luax_checkrandomgenerator(L, 1);
return luax_getrandom(L, 2, rng->random());
lua_pushnumber(L, rng->random());
return 1;
}
int w_RandomGenerator_randomNormal(lua_State *L)
@@ -135,9 +115,28 @@ int w_RandomGenerator_getState(lua_State *L)
return 1;
}
// C functions in a struct, necessary for the FFI versions of RandomGenerator functions.
struct FFI_RandomGenerator
{
double (*random)(Proxy *p);
};
static FFI_RandomGenerator ffifuncs =
{
[](Proxy *p) -> double // random()
{
// FIXME: We need better type-checking...
if (!typeFlags[p->type][MATH_RANDOM_GENERATOR_ID])
return 0.0;
RandomGenerator *rng = (RandomGenerator *) p->object;
return rng->random();
}
};
static const luaL_Reg w_RandomGenerator_functions[] =
{
{ "random", w_RandomGenerator_random },
{ "_random", w_RandomGenerator__random }, // random() is defined in wrap_RandomGenerator.lua.
{ "randomNormal", w_RandomGenerator_randomNormal },
{ "setSeed", w_RandomGenerator_setSeed },
{ "getSeed", w_RandomGenerator_getSeed },
@@ -148,7 +147,24 @@ static const luaL_Reg w_RandomGenerator_functions[] =
extern "C" int luaopen_randomgenerator(lua_State *L)
{
return luax_register_type(L, MATH_RANDOM_GENERATOR_ID, "RandomGenerator", w_RandomGenerator_functions, nullptr);
int n = luax_register_type(L, MATH_RANDOM_GENERATOR_ID, "RandomGenerator", w_RandomGenerator_functions, nullptr);
luax_gettypemetatable(L, MATH_RANDOM_GENERATOR_ID);
// Load and execute wrap_RandomGenerator.lua, sending the metatable and the
// ffi functions struct pointer as arguments.
if (lua_istable(L, -1))
{
luaL_loadbuffer(L, randomgenerator_lua, sizeof(randomgenerator_lua), "wrap_RandomGenerator.lua");
lua_pushvalue(L, -2);
lua_pushlightuserdata(L, &ffifuncs);
lua_call(L, 2, 0);
}
// Pop the metatable.
lua_pop(L, 1);
return n;
}
} // math
-1
View File
@@ -33,7 +33,6 @@ namespace math
// Helper functions.
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);
extern "C" int luaopen_randomgenerator(lua_State *L);
+80
View File
@@ -0,0 +1,80 @@
R"luastring"--(
-- DO NOT REMOVE THE ABOVE LINE. It is used to load this file as a C++ string.
-- There is a matching delimiter at the bottom of the file.
--[[
Copyright (c) 2006-2015 LOVE Development Team
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
--]]
local RandomGenerator_mt, ffifuncspointer = ...
local RandomGenerator = RandomGenerator_mt.__index
local type, tonumber, error = type, tonumber, error
local floor = math.floor
local _random = RandomGenerator._random
local function getrandom(r, l, u)
if u ~= nil then
if type(r) ~= "number" then error("bad argument #1 to 'random' (number expected)", 2) end
if type(l) ~= "number" then error("bad argument #2 to 'random' (number expected)", 2) end
return floor(r * (u - l + 1)) + l
elseif l ~= nil then
if type(l) ~= "number" then error("bad argument #1 to 'random' (number expected)", 2) end
return floor(r * l) + 1
else
return r
end
end
function RandomGenerator:random(l, u)
local r = _random(self)
return getrandom(r, l, u)
end
if type(jit) ~= "table" or not jit.status() then
-- LuaJIT's FFI is *much* slower than LOVE's regular methods when the JIT
-- compiler is disabled.
return
end
local status, ffi = pcall(require, "ffi")
if not status then return end
pcall(ffi.cdef, [[
typedef struct Proxy Proxy;
typedef struct FFI_RandomGenerator
{
double (*random)(Proxy *p);
} FFI_RandomGenerator;
]])
local ffifuncs = ffi.cast("FFI_RandomGenerator *", ffifuncspointer)
-- Overwrite some regular love.math functions with FFI implementations.
function RandomGenerator:random(l, u)
local r = tonumber(ffifuncs.random(self))
return getrandom(r, l, u)
end
-- DO NOT REMOVE THE NEXT LINE. It is used to load this file as a C++ string.
--)luastring"--"