vec3, color, bit and math
The helper types and functions we write in Lua for you, the extra math functions, and the list of standard Lua names that remain.
On this page
vec3, color, bit and the extra math functions are not part of the host. They are Lua code that we run inside your own state before your script starts. They cost your script nothing except the memory of their closures. If a script replaces one of them, only that script is affected.
vec3
vec3([x [, y [, z]]]) -> vec3
A vec3 is a table with the fields x, y and z and a metatable that gives it operators and methods. A missing argument is 0. The constructor does not check its arguments, and arithmetic on a vec3 that holds something other than numbers raises an ordinary Lua error.
Operators
| expression | result |
|---|---|
a + b, a - b | a new vec3. Both sides have to be vec3. |
a * b | a new vec3. b may be a number, or a vec3 for a component by component product. A number on the left works as well. |
a / b | a new vec3. b may be a number or a vec3 (component by component). |
-a | a new vec3 |
a == b | true if all three components are equal |
tostring(a) | vec3(1, 2, 3) |
Methods. A method marked "in place" changes the vec3 it is called on and returns it. All others leave it alone.
| method | returns | what it does |
|---|---|---|
v:clone() | new vec3 | a copy |
v:init([x [, y [, z]]]) | v | sets the three components, in place. Missing ones become 0. |
v:unpack() | x, y, z | the three components as numbers |
v:length() | number | length |
v:lengthsqr() | number | length squared |
v:length2d() | number | length of the x and y part |
v:length2dsqr() | number | the same, squared |
v:dist(o) | number | distance to the vec3 o |
v:distsqr(o) | number | distance squared |
v:dist2d(o) | number | distance on the x and y plane |
v:dist2dsqr(o) | number | the same, squared |
v:in_range(o, range) | boolean | true if the distance to o is range or less |
v:dot(o) | number | dot product |
v:cross(o) | new vec3 | cross product |
v:scale(s) | v | multiplies by the number s, in place |
v:scaled(s) | new vec3 | the same, as a new vec3 |
v:normalize() | number | scales to length 1, in place, and returns the length it had. A vec3 of length 0 stays 0 and returns 0. |
v:normalized() | new vec3 | the same direction at length 1. A vec3 of length 0 gives a zero vec3. |
v:lerp(o, t) | new vec3 | v + (o - v) * t. t is not clamped. |
v:floor() | v | rounds each component down, in place |
v:ceil() | v | rounds each component up, in place |
v:to(o) | new vec3 | the unit vector that points from v to o |
v:angles() | new vec3 | treats v as a direction and returns vec3(pitch, yaw, 0) in degrees. Positive pitch looks down. |
v:angles(pitch, yaw) | v | the other way: sets v, in place, to the unit direction for these angles. A vec3 can be passed instead, its x is the pitch and its y the yaw. |
v:vectors() | right, up | two new vec3: the right and up directions of a view that looks along v |
v:closest_ray_point(a, b) | new vec3 | the point on the segment from a to b that is closest to v. It stops at both ends. |
v:dist_to_ray(a, dir) | number | the distance from v to the half-line that starts at a and runs along dir. It stops at a and runs on without end. |
v:to_screen() | vec3 or nil | the screen position as vec3(x, y, 0), or nil where game.to_screen would return nil |
game.to_screen takes three numbers. To pass a vec3, unpack it: game.to_screen(v:unpack()).
local a, b = vec3(0, 0, 0), vec3(30, 40, 0)
local d = b - a
log.info(d:length()) -- 50
log.info(a:dist(b)) -- 50
log.info(tostring(d:normalized()))
local pitch_yaw = vec3(1, 0, 0):angles()
log.info(pitch_yaw.y) -- 0
color
color([r [, g [, b [, a]]]]) -> color
color(hex) -> color
A color is a table with the fields r, g, b and a and a metatable. Draw functions accept it wherever a colour is expected, and the gradient functions require it.
The four numbers are rounded and clamped to 0 to 255. A missing channel is 255, so color() is opaque white.
A string selects the hex form. The digits are read in pairs:
| string | meaning |
|---|---|
"C8" | grey 0xC8, opaque |
"FFA0" | grey 0xFF with alpha 0xA0 |
"FFC319" | red, green, blue |
"AABBCCDD" | red, green, blue, alpha |
Any other string leaves the colour opaque white.
Operators a == b is true when all four channels are equal. tostring(c) gives color(10, 20, 30, 40).
Methods. "In place" works as for vec3.
| method | returns | what it does |
|---|---|---|
c:clone() | new color | a copy |
c:unpack() | r, g, b, a | the four channels |
c:init(r, g, b, a) | c | sets the channels in place, a missing one becomes 255. c:init("AABBCCDD") takes a hex string. |
c:as_fraction(r, g, b, a) | c | sets the channels from numbers between 0 and 1, in place. A missing one is 1. |
c:to_fraction() | r, g, b, a | the channels as numbers between 0 and 1 |
c:to_hex() | string | RRGGBBAA in capital letters |
c:as_int32(v) | c | sets the channels, in place, from an integer packed as alpha, red, green, blue |
c:to_int32() | integer | the same packing: alpha in the top byte, then red, green and blue |
c:lerp(o, t) | new color | blends towards o. t is not clamped, the channels are. |
c:alpha_modulate(a) | new color | a copy with the alpha set to a, 0 to 255. It replaces the alpha and does not multiply it. |
c:grayscale([t]) | new color | blends towards the grey of the same brightness. t is 1 if left out, 0 changes nothing. |
c:as_hsv(h, s, v [, a]) | c | sets the colour, in place, from hue, saturation and value, each 0 to 1. a is 0 to 1 and 1 if left out. |
c:to_hsv() | h, s, v | each 0 to 1 |
c:as_hsl(h, s, l [, a]) | c | like as_hsv, with lightness |
c:to_hsl() | h, s, l | each 0 to 1 |
local red = color(255, 0, 0)
local half = red:alpha_modulate(128)
local mix = red:lerp(color("3C78FF"), 0.5)
log.info(mix:to_hex())
local rainbow = color():as_hsv(0.33, 1, 1)
log.info(rainbow.g)
bit
Bit operations on 32-bit integers. Every result is a signed 32-bit integer, from -2147483648 to 2147483647. An argument is rounded to the nearest whole number and read modulo 2^32. NaN and infinity count as 0. An argument that is not a number raises an error. Shift counts are taken modulo 32.
| function | result |
|---|---|
bit.tobit(x) | x as a signed 32-bit integer |
bit.band(a, ...) | bitwise and of all arguments |
bit.bor(a, ...) | bitwise or of all arguments |
bit.bxor(a, ...) | bitwise exclusive or of all arguments |
bit.bnot(x) | bitwise not |
bit.lshift(x, n) | shift left by n bits |
bit.rshift(x, n) | logical shift right: zeros come in from the left |
bit.arshift(x, n) | arithmetic shift right: the sign bit is copied |
bit.rol(x, n) | rotate left |
bit.ror(x, n) | rotate right |
bit.bswap(x) | reverse the four bytes |
bit.tohex(x [, n]) | the last n hex digits of x as a string. n is 8 if left out, and is limited to 1 to 8. A negative n gives capital letters. |
log.info(bit.band(0xFF, 0x0F)) -- 15
log.info(bit.lshift(1, 31)) -- -2147483648
log.info(bit.tohex(255, 2)) -- ff
log.info(bit.tohex(255, -4)) -- 00FF
log.info(bit.bswap(0x12345678) == 0x78563412)
math extras
These are added to your own math table.
| function | result |
|---|---|
math.clamp(v, lo, hi) | v limited to lo and hi. Either bound may be nil to leave that side open. |
math.lerp(a, b, t) | a + (b - a) * t |
math.map(v, in_from, in_to, out_from, out_to [, clamp]) | moves v from the range in_from to in_to onto the range out_from to out_to. If clamp is true the position is limited to the ends. |
math.normalize_yaw(x) | the angle x in degrees wrapped to -180 to 180 |
math.atan2(y, x) | the angle of the point x, y in radians. The same as math.atan(y, x). |
math.pow(x, y) | x ^ y |
math.log10(x) | logarithm to base 10 |
math.sinh(x), math.cosh(x), math.tanh(x) | hyperbolic functions. math.tanh is exactly 1 above 20 and exactly -1 below -20. |
math.frexp(x) | m, e with x = m * 2^e and m between 0.5 and 1 in size. For 0, NaN and infinity it returns x, 0. |
math.ldexp(x, e) | x * 2^e |
local yaw = math.normalize_yaw(190) -- -170
local alpha = math.clamp(300, 0, 255) -- 255
local x = math.map(5, 0, 10, 100, 200) -- 150.0
local half = math.lerp(10, 20, 0.5) -- 15.0
log.info(yaw .. " " .. alpha .. " " .. x .. " " .. half)
Standard library
These names of standard Lua are available. Everything else of the standard library is not. The differences in behaviour are in How scripts run.
Base functions. unpack is the same function as table.unpack.
assert error getmetatable ipairs next pairs pcall rawequal rawget rawlen rawset
select setmetatable tonumber tostring type unpack xpcall
string. The methods work on string values too, as in ("text"):upper().
string.byte string.char string.find string.format string.gmatch string.gsub
string.len string.lower string.match string.rep string.reverse string.sub string.upper
table.
table.concat table.insert table.move table.pack table.remove table.sort table.unpack
math. The standard names, 27 of them. The extras above are in addition.
math.abs math.acos math.asin math.atan math.ceil math.cos math.deg math.exp
math.floor math.fmod math.huge math.log math.max math.maxinteger math.min
math.mininteger math.modf math.pi math.rad math.random math.randomseed math.sin
math.sqrt math.tan math.tointeger math.type math.ult
utf8.
utf8.char utf8.charpattern utf8.codepoint utf8.codes utf8.len utf8.offset