Skip to content

Commit

Permalink
Expose Luau 3-vectors support
Browse files Browse the repository at this point in the history
The Luau VM supports native f32 3-vectors so that typical
linear algebra operations are fast in game code.

TODO: Luau can also be built for native 4-vectors through a
compilation option.  This path should be supported also, as that's
most probably a better default for 3d-games.  3-vectors are fine
for 2d-games :)
  • Loading branch information
nurpax committed Jan 7, 2024
1 parent 7f1e80c commit a962fc3
Show file tree
Hide file tree
Showing 2 changed files with 63 additions and 2 deletions.
39 changes: 37 additions & 2 deletions src/zigluau/lib.zig
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,14 @@ pub const Lua = struct {
}
}

fn vectorCtor(l: *Lua) i32 {
const x = l.toNumber(1) catch unreachable;
const y = l.toNumber(2) catch unreachable;
const z = l.toNumber(3) catch unreachable;
c.lua_pushvector(l.state, @floatCast(x), @floatCast(y), @floatCast(z));
return 1;
}

/// Initialize a Lua state with the given allocator
/// See https://www.lua.org/manual/5.1/manual.html#lua_newstate
pub fn init(allocator: Allocator) !Lua {
Expand All @@ -255,10 +263,12 @@ pub const Lua = struct {
allocator_ptr.* = allocator;

const state = c.lua_newstate(alloc, allocator_ptr) orelse return error.Memory;
return Lua{
var lua = Lua{
.allocator = allocator_ptr,
.state = state,
};
lua.register("vector", wrap(vectorCtor));
return lua;
}

/// Deinitialize a Lua state and free all memory
Expand Down Expand Up @@ -670,6 +680,12 @@ pub const Lua = struct {
c.lua_pushvalue(lua.state, index);
}

/// Pushes a floating point 3-vector (or 4-vector if configured) `v` onto the stack
/// See https://www.lua.org/manual/5.1/manual.html#lua_pushinteger
pub fn pushVector(lua: *Lua, v: @Vector(3, f32)) void {
c.lua_pushvector(lua.state, v[0], v[1], v[2]);
}

/// Returns true if the two values in indices `index1` and `index2` are primitively equal
/// Bypasses __eq metamethods
/// Returns false if not equal, or if any index is invalid
Expand Down Expand Up @@ -879,6 +895,17 @@ pub const Lua = struct {
return error.Fail;
}

/// Converts the Lua value at the given `index` to a f32 3-vector
/// The Lua value must be an integer, or a number, or a string convertible to an integer otherwise toInteger returns 0
/// See https://www.lua.org/manual/5.1/manual.html#lua_tointeger
pub fn toVector(lua: *Lua, index: i32) !@Vector(3, f32) {
const res = c.lua_tovector(lua.state, index);
if (res) |r| {
return @Vector(3, f32){ r[0], r[1], r[2] };
}
return @Vector(3, f32){ 0, 0, 0 };
}

/// Returns the `LuaType` of the value at the given index
/// Note that this is equivalent to lua_type but because type is a Zig primitive it is renamed to `typeOf`
/// See https://www.lua.org/manual/5.1/manual.html#lua_type
Expand Down Expand Up @@ -1136,7 +1163,15 @@ pub const Lua = struct {
/// TODO: does it make sense to have this in Luau?
pub fn loadString(lua: *Lua, str: [:0]const u8) !void {
var size: usize = 0;
const bytecode = c.luau_compile(str.ptr, str.len, null, &size);
var opts = c.lua_CompileOptions{
.optimizationLevel = 1,
.debugLevel = 1,
.coverageLevel = 0,
.vectorLib = null,
.vectorCtor = "vector",
.mutableGlobals = null,
};
const bytecode = c.luau_compile(str.ptr, str.len, &opts, &size);

// Failed to allocate memory for the out buffer
if (bytecode == null) return error.Memory;
Expand Down
26 changes: 26 additions & 0 deletions src/zigluau/tests.zig
Original file line number Diff line number Diff line change
Expand Up @@ -1089,6 +1089,32 @@ test "objectLen" {
try testing.expectEqual(@as(i32, 3), lua.objectLen(-1));
}

// Luau supports a 'vector' type that's either a 3-vector or 4-vector (if configured at build-time)
test "luau vectors" {
var lua = try Lua.init(testing.allocator);
defer lua.deinit();
lua.openLibs();

try lua.doString(
\\function test()
\\ local a = vector(1, 2, 3)
\\ local b = vector(4, 5, 6)
\\ local c = (a + b) * vector(2, 2, 2)
\\ return c
\\end
);
_ = lua.getGlobal("test");
try lua.protectedCall(0, 1, 0);
var v = try lua.toVector(-1);
try testing.expectEqual(v[0], 10.0);
try testing.expectEqual(v[1], 14.0);
try testing.expectEqual(v[2], 18.0);

lua.pushVector(@Vector(3, f32){ 1, 2, 3 });
v = try lua.toVector(-1);
try testing.expectEqual(v, @Vector(3, f32){ 1, 2, 3 });
}

test {
testing.refAllDecls(Lua);
testing.refAllDecls(Buffer);
Expand Down

0 comments on commit a962fc3

Please sign in to comment.