22#ifdef WITH_RIVE_SCRIPTING
33#include " rive/lua/rive_lua_libs.hpp"
44#include " lualib.h"
5+ #include < cmath>
6+ #include < cstring>
57
68using namespace rive ;
79
@@ -40,49 +42,59 @@ static int vector_index(lua_State* L)
4042 return 0 ;
4143}
4244
45+ // All magnitude and interpolation ops read all 3 components. For genuine 2D
46+ // vectors z is 0, so results are identical to the old 2D math.
47+ static inline float dot3 (const float * a, const float * b)
48+ {
49+ return a[0 ] * b[0 ] + a[1 ] * b[1 ] + a[2 ] * b[2 ];
50+ }
51+
4352static int vector_length (lua_State* L)
4453{
45- auto vec = lua_checkvec2d (L, 1 );
46- lua_pushnumber (L, vec-> length ( ));
54+ const float * vec = luaL_checkvector (L, 1 );
55+ lua_pushnumber (L, std::sqrt ( dot3 (vec, vec) ));
4756 return 1 ;
4857}
4958
5059static int vector_normalized (lua_State* L)
5160{
52- auto vec = lua_checkvec2d (L, 1 );
53- lua_pushvec2d (L, vec->normalized ());
61+ const float * vec = luaL_checkvector (L, 1 );
62+ float len2 = dot3 (vec, vec);
63+ float scale = len2 > 0 ? 1 .f / std::sqrt (len2) : 1 .f ;
64+ lua_pushvector (L, vec[0 ] * scale, vec[1 ] * scale, vec[2 ] * scale);
5465 return 1 ;
5566}
5667
5768static int vector_lengthSquared (lua_State* L)
5869{
59- auto vec = lua_checkvec2d (L, 1 );
60- lua_pushnumber (L, vec-> lengthSquared ( ));
70+ const float * vec = luaL_checkvector (L, 1 );
71+ lua_pushnumber (L, dot3 (vec, vec ));
6172 return 1 ;
6273}
6374
64- static int vector_distance (lua_State* L)
75+ static int vector_distanceSquared (lua_State* L)
6576{
66- auto lhs = lua_checkvec2d (L, 1 );
67- auto rhs = lua_checkvec2d (L, 2 );
68- lua_pushnumber (L, Vec2D::distance (*lhs, *rhs));
77+ const float * lhs = luaL_checkvector (L, 1 );
78+ const float * rhs = luaL_checkvector (L, 2 );
79+ float d[3 ] = {rhs[0 ] - lhs[0 ], rhs[1 ] - lhs[1 ], rhs[2 ] - lhs[2 ]};
80+ lua_pushnumber (L, dot3 (d, d));
6981 return 1 ;
7082}
7183
72- static int vector_distanceSquared (lua_State* L)
84+ static int vector_distance (lua_State* L)
7385{
74- auto lhs = lua_checkvec2d (L, 1 );
75- auto rhs = lua_checkvec2d (L, 2 );
76- lua_pushnumber (L, Vec2D::distanceSquared (*lhs, *rhs));
86+ const float * lhs = luaL_checkvector (L, 1 );
87+ const float * rhs = luaL_checkvector (L, 2 );
88+ float d[3 ] = {rhs[0 ] - lhs[0 ], rhs[1 ] - lhs[1 ], rhs[2 ] - lhs[2 ]};
89+ lua_pushnumber (L, std::sqrt (dot3 (d, d)));
7790 return 1 ;
7891}
7992
8093static int vector_dot (lua_State* L)
8194{
82- auto lhs = lua_checkvec2d (L, 1 );
83- auto rhs = lua_checkvec2d (L, 2 );
84-
85- lua_pushnumber (L, Vec2D::dot (*lhs, *rhs));
95+ const float * lhs = luaL_checkvector (L, 1 );
96+ const float * rhs = luaL_checkvector (L, 2 );
97+ lua_pushnumber (L, dot3 (lhs, rhs));
8698 return 1 ;
8799}
88100
@@ -94,33 +106,98 @@ static int vector_cross(lua_State* L)
94106 return 1 ;
95107}
96108
109+ // 3D cross product. Distinct from `cross`, which returns the scalar 2D
110+ // perp-dot.
111+ static int vector_cross3 (lua_State* L)
112+ {
113+ const float * a = luaL_checkvector (L, 1 );
114+ const float * b = luaL_checkvector (L, 2 );
115+ lua_pushvector (L,
116+ a[1 ] * b[2 ] - a[2 ] * b[1 ],
117+ a[2 ] * b[0 ] - a[0 ] * b[2 ],
118+ a[0 ] * b[1 ] - a[1 ] * b[0 ]);
119+ return 1 ;
120+ }
121+
97122static int vector_scaleAndAdd (lua_State* L)
98123{
99- auto a = lua_checkvec2d (L, 1 );
100- auto b = lua_checkvec2d (L, 2 );
124+ const float * a = luaL_checkvector (L, 1 );
125+ const float * b = luaL_checkvector (L, 2 );
101126 float scale = float (luaL_checknumber (L, 3 ));
102- lua_pushvec2d (L, Vec2D::scaleAndAdd (*a, *b, scale));
127+ lua_pushvector (L,
128+ a[0 ] + b[0 ] * scale,
129+ a[1 ] + b[1 ] * scale,
130+ a[2 ] + b[2 ] * scale);
103131 return 1 ;
104132}
105133
106134static int vector_scaleAndSub (lua_State* L)
107135{
108- auto a = lua_checkvec2d (L, 1 );
109- auto b = lua_checkvec2d (L, 2 );
136+ const float * a = luaL_checkvector (L, 1 );
137+ const float * b = luaL_checkvector (L, 2 );
110138 float scale = float (luaL_checknumber (L, 3 ));
111- lua_pushvec2d (L, *a - *b * scale);
139+ lua_pushvector (L,
140+ a[0 ] - b[0 ] * scale,
141+ a[1 ] - b[1 ] * scale,
142+ a[2 ] - b[2 ] * scale);
112143 return 1 ;
113144}
114145
146+ // Exact at t=1, mirroring the VM fastcall's luai_lerpf so both dispatch
147+ // paths return bit-identical results.
148+ static inline float lerpf (float a, float b, float t)
149+ {
150+ return t == 1 .f ? b : a + (b - a) * t;
151+ }
152+
115153static int vector_lerp (lua_State* L)
116154{
117- auto lhs = lua_checkvec2d (L, 1 );
118- auto rhs = lua_checkvec2d (L, 2 );
119- float factor = float (luaL_checknumber (L, 3 ));
120- lua_pushvec2d (L, Vec2D::lerp (*lhs, *rhs, factor));
155+ const float * a = luaL_checkvector (L, 1 );
156+ const float * b = luaL_checkvector (L, 2 );
157+ float t = float (luaL_checknumber (L, 3 ));
158+ lua_pushvector (L,
159+ lerpf (a[0 ], b[0 ], t),
160+ lerpf (a[1 ], b[1 ], t),
161+ lerpf (a[2 ], b[2 ], t));
121162 return 1 ;
122163}
123164
165+ // vec:writeToBuffer(buf, byteOffset) — 12 bytes (x, y, z as float32).
166+ static int vector_writeToBuffer (lua_State* L)
167+ {
168+ const float * vec = luaL_checkvector (L, 1 );
169+ size_t bufLen = 0 ;
170+ void * buf = luaL_checkbuffer (L, 2 , &bufLen);
171+ int off = int (luaL_checkinteger (L, 3 ));
172+ if (off < 0 || size_t (off) + 12 > bufLen)
173+ {
174+ luaL_error (L, " Vector:writeToBuffer offset out of range" );
175+ return 0 ;
176+ }
177+ std::memcpy (static_cast <uint8_t *>(buf) + off, vec, 12 );
178+ return 0 ;
179+ }
180+
181+ // vec:writeVec4(buf, byteOffset, w) — 16 bytes (x, y, z, w as float32),
182+ // matching a vec4 uniform-buffer slot.
183+ static int vector_writeVec4 (lua_State* L)
184+ {
185+ const float * vec = luaL_checkvector (L, 1 );
186+ size_t bufLen = 0 ;
187+ void * buf = luaL_checkbuffer (L, 2 , &bufLen);
188+ int off = int (luaL_checkinteger (L, 3 ));
189+ float w = float (luaL_checknumber (L, 4 ));
190+ if (off < 0 || size_t (off) + 16 > bufLen)
191+ {
192+ luaL_error (L, " Vector:writeVec4 offset out of range" );
193+ return 0 ;
194+ }
195+ uint8_t * dst = static_cast <uint8_t *>(buf) + off;
196+ std::memcpy (dst, vec, 12 );
197+ std::memcpy (dst + 12 , &w, 4 );
198+ return 0 ;
199+ }
200+
124201static int vector_xy (lua_State* L)
125202{
126203 float x = (float )lua_tonumber (L, 1 );
@@ -130,6 +207,16 @@ static int vector_xy(lua_State* L)
130207 return 1 ;
131208}
132209
210+ static int vector_xyz (lua_State* L)
211+ {
212+ float x = (float )lua_tonumber (L, 1 );
213+ float y = (float )lua_tonumber (L, 2 );
214+ float z = (float )lua_tonumber (L, 3 );
215+
216+ lua_pushvector (L, x, y, z);
217+ return 1 ;
218+ }
219+
133220static int vector_origin (lua_State* L)
134221{
135222 lua_pushvector2 (L, 0 .0f , 0 .0f );
@@ -158,6 +245,10 @@ static int vector_namecall(lua_State* L)
158245 return vector_dot (L);
159246 case (int )LuaAtoms::lerp:
160247 return vector_lerp (L);
248+ case (int )LuaAtoms::writeToBuffer:
249+ return vector_writeToBuffer (L);
250+ case (int )LuaAtoms::writeVec4:
251+ return vector_writeVec4 (L);
161252 }
162253 }
163254
@@ -170,10 +261,12 @@ static const luaL_Reg vectorStaticMethods[] = {
170261 {" distanceSquared" , vector_distanceSquared},
171262 {" dot" , vector_dot},
172263 {" cross" , vector_cross},
264+ {" cross3" , vector_cross3},
173265 {" scaleAndAdd" , vector_scaleAndAdd},
174266 {" scaleAndSub" , vector_scaleAndSub},
175267 {" lerp" , vector_lerp},
176268 {" xy" , vector_xy},
269+ {" xyz" , vector_xyz},
177270 {" origin" , vector_origin},
178271 {" length" , vector_length},
179272 {" lengthSquared" , vector_lengthSquared},
0 commit comments