Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/VM/src/lveclib.cpp
2725 views
1
// This file is part of the Luau programming language and is licensed under MIT License; see LICENSE.txt for details
2
#include "lualib.h"
3
4
#include "lcommon.h"
5
#include "lnumutils.h"
6
7
#include <math.h>
8
9
static int vector_create(lua_State* L)
10
{
11
// checking argument count to avoid accepting 'nil' as a valid value
12
int count = lua_gettop(L);
13
14
double x = luaL_checknumber(L, 1);
15
double y = luaL_checknumber(L, 2);
16
double z = count >= 3 ? luaL_checknumber(L, 3) : 0.0;
17
18
#if LUA_VECTOR_SIZE == 4
19
double w = count >= 4 ? luaL_checknumber(L, 4) : 0.0;
20
21
lua_pushvector(L, float(x), float(y), float(z), float(w));
22
#else
23
lua_pushvector(L, float(x), float(y), float(z));
24
#endif
25
26
return 1;
27
}
28
29
static int vector_magnitude(lua_State* L)
30
{
31
const float* v = luaL_checkvector(L, 1);
32
33
#if LUA_VECTOR_SIZE == 4
34
lua_pushnumber(L, sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]));
35
#else
36
lua_pushnumber(L, sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]));
37
#endif
38
39
return 1;
40
}
41
42
static int vector_normalize(lua_State* L)
43
{
44
const float* v = luaL_checkvector(L, 1);
45
46
#if LUA_VECTOR_SIZE == 4
47
float invSqrt = 1.0f / sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2] + v[3] * v[3]);
48
49
lua_pushvector(L, v[0] * invSqrt, v[1] * invSqrt, v[2] * invSqrt, v[3] * invSqrt);
50
#else
51
float invSqrt = 1.0f / sqrtf(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]);
52
53
lua_pushvector(L, v[0] * invSqrt, v[1] * invSqrt, v[2] * invSqrt);
54
#endif
55
56
return 1;
57
}
58
59
static int vector_cross(lua_State* L)
60
{
61
const float* a = luaL_checkvector(L, 1);
62
const float* b = luaL_checkvector(L, 2);
63
64
#if LUA_VECTOR_SIZE == 4
65
lua_pushvector(L, a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0], 0.0f);
66
#else
67
lua_pushvector(L, a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]);
68
#endif
69
70
return 1;
71
}
72
73
static int vector_dot(lua_State* L)
74
{
75
const float* a = luaL_checkvector(L, 1);
76
const float* b = luaL_checkvector(L, 2);
77
78
#if LUA_VECTOR_SIZE == 4
79
lua_pushnumber(L, a[0] * b[0] + a[1] * b[1] + a[2] * b[2] + a[3] * b[3]);
80
#else
81
lua_pushnumber(L, a[0] * b[0] + a[1] * b[1] + a[2] * b[2]);
82
#endif
83
84
return 1;
85
}
86
87
static int vector_angle(lua_State* L)
88
{
89
const float* a = luaL_checkvector(L, 1);
90
const float* b = luaL_checkvector(L, 2);
91
const float* axis = luaL_optvector(L, 3, nullptr);
92
93
// cross(a, b)
94
float cross[] = {a[1] * b[2] - a[2] * b[1], a[2] * b[0] - a[0] * b[2], a[0] * b[1] - a[1] * b[0]};
95
96
double sinA = sqrt(cross[0] * cross[0] + cross[1] * cross[1] + cross[2] * cross[2]);
97
double cosA = a[0] * b[0] + a[1] * b[1] + a[2] * b[2];
98
double angle = atan2(sinA, cosA);
99
100
if (axis)
101
{
102
if (cross[0] * axis[0] + cross[1] * axis[1] + cross[2] * axis[2] < 0.0f)
103
angle = -angle;
104
}
105
106
lua_pushnumber(L, angle);
107
return 1;
108
}
109
110
static int vector_floor(lua_State* L)
111
{
112
const float* v = luaL_checkvector(L, 1);
113
114
#if LUA_VECTOR_SIZE == 4
115
lua_pushvector(L, floorf(v[0]), floorf(v[1]), floorf(v[2]), floorf(v[3]));
116
#else
117
lua_pushvector(L, floorf(v[0]), floorf(v[1]), floorf(v[2]));
118
#endif
119
120
return 1;
121
}
122
123
static int vector_ceil(lua_State* L)
124
{
125
const float* v = luaL_checkvector(L, 1);
126
127
#if LUA_VECTOR_SIZE == 4
128
lua_pushvector(L, ceilf(v[0]), ceilf(v[1]), ceilf(v[2]), ceilf(v[3]));
129
#else
130
lua_pushvector(L, ceilf(v[0]), ceilf(v[1]), ceilf(v[2]));
131
#endif
132
133
return 1;
134
}
135
136
static int vector_abs(lua_State* L)
137
{
138
const float* v = luaL_checkvector(L, 1);
139
140
#if LUA_VECTOR_SIZE == 4
141
lua_pushvector(L, fabsf(v[0]), fabsf(v[1]), fabsf(v[2]), fabsf(v[3]));
142
#else
143
lua_pushvector(L, fabsf(v[0]), fabsf(v[1]), fabsf(v[2]));
144
#endif
145
146
return 1;
147
}
148
149
static int vector_sign(lua_State* L)
150
{
151
const float* v = luaL_checkvector(L, 1);
152
153
#if LUA_VECTOR_SIZE == 4
154
lua_pushvector(L, luaui_signf(v[0]), luaui_signf(v[1]), luaui_signf(v[2]), luaui_signf(v[3]));
155
#else
156
lua_pushvector(L, luaui_signf(v[0]), luaui_signf(v[1]), luaui_signf(v[2]));
157
#endif
158
159
return 1;
160
}
161
162
static int vector_clamp(lua_State* L)
163
{
164
const float* v = luaL_checkvector(L, 1);
165
const float* min = luaL_checkvector(L, 2);
166
const float* max = luaL_checkvector(L, 3);
167
168
luaL_argcheck(L, min[0] <= max[0], 3, "max.x must be greater than or equal to min.x");
169
luaL_argcheck(L, min[1] <= max[1], 3, "max.y must be greater than or equal to min.y");
170
luaL_argcheck(L, min[2] <= max[2], 3, "max.z must be greater than or equal to min.z");
171
172
#if LUA_VECTOR_SIZE == 4
173
lua_pushvector(
174
L,
175
luaui_clampf(v[0], min[0], max[0]),
176
luaui_clampf(v[1], min[1], max[1]),
177
luaui_clampf(v[2], min[2], max[2]),
178
luaui_clampf(v[3], min[3], max[3])
179
);
180
#else
181
lua_pushvector(L, luaui_clampf(v[0], min[0], max[0]), luaui_clampf(v[1], min[1], max[1]), luaui_clampf(v[2], min[2], max[2]));
182
#endif
183
184
return 1;
185
}
186
187
static int vector_min(lua_State* L)
188
{
189
int n = lua_gettop(L);
190
const float* v = luaL_checkvector(L, 1);
191
192
#if LUA_VECTOR_SIZE == 4
193
float result[] = {v[0], v[1], v[2], v[3]};
194
#else
195
float result[] = {v[0], v[1], v[2]};
196
#endif
197
198
for (int i = 2; i <= n; i++)
199
{
200
const float* b = luaL_checkvector(L, i);
201
202
if (b[0] < result[0])
203
result[0] = b[0];
204
if (b[1] < result[1])
205
result[1] = b[1];
206
if (b[2] < result[2])
207
result[2] = b[2];
208
#if LUA_VECTOR_SIZE == 4
209
if (b[3] < result[3])
210
result[3] = b[3];
211
#endif
212
}
213
214
#if LUA_VECTOR_SIZE == 4
215
lua_pushvector(L, result[0], result[1], result[2], result[3]);
216
#else
217
lua_pushvector(L, result[0], result[1], result[2]);
218
#endif
219
220
return 1;
221
}
222
223
static int vector_max(lua_State* L)
224
{
225
int n = lua_gettop(L);
226
const float* v = luaL_checkvector(L, 1);
227
228
#if LUA_VECTOR_SIZE == 4
229
float result[] = {v[0], v[1], v[2], v[3]};
230
#else
231
float result[] = {v[0], v[1], v[2]};
232
#endif
233
234
for (int i = 2; i <= n; i++)
235
{
236
const float* b = luaL_checkvector(L, i);
237
238
if (b[0] > result[0])
239
result[0] = b[0];
240
if (b[1] > result[1])
241
result[1] = b[1];
242
if (b[2] > result[2])
243
result[2] = b[2];
244
#if LUA_VECTOR_SIZE == 4
245
if (b[3] > result[3])
246
result[3] = b[3];
247
#endif
248
}
249
250
#if LUA_VECTOR_SIZE == 4
251
lua_pushvector(L, result[0], result[1], result[2], result[3]);
252
#else
253
lua_pushvector(L, result[0], result[1], result[2]);
254
#endif
255
256
return 1;
257
}
258
259
static int vector_index(lua_State* L)
260
{
261
const float* v = luaL_checkvector(L, 1);
262
size_t namelen = 0;
263
const char* name = luaL_checklstring(L, 2, &namelen);
264
265
// field access implementation mirrors the fast-path we have in the VM
266
if (namelen == 1)
267
{
268
int ic = (name[0] | ' ') - 'x';
269
270
#if LUA_VECTOR_SIZE == 4
271
// 'w' is before 'x' in ascii, so ic is -1 when indexing with 'w'
272
if (ic == -1)
273
ic = 3;
274
#endif
275
276
if (unsigned(ic) < LUA_VECTOR_SIZE)
277
{
278
lua_pushnumber(L, v[ic]);
279
return 1;
280
}
281
}
282
283
luaL_error(L, "attempt to index vector with '%s'", name);
284
}
285
286
static int vector_lerp(lua_State* L)
287
{
288
const float* a = luaL_checkvector(L, 1);
289
const float* b = luaL_checkvector(L, 2);
290
const float t = static_cast<float>(luaL_checknumber(L, 3));
291
292
#if LUA_VECTOR_SIZE == 4
293
lua_pushvector(L, luai_lerpf(a[0], b[0], t), luai_lerpf(a[1], b[1], t), luai_lerpf(a[2], b[2], t), luai_lerpf(a[3], b[3], t));
294
#else
295
lua_pushvector(L, luai_lerpf(a[0], b[0], t), luai_lerpf(a[1], b[1], t), luai_lerpf(a[2], b[2], t));
296
#endif
297
298
return 1;
299
}
300
301
static const luaL_Reg vectorlib[] = {
302
{"create", vector_create},
303
{"magnitude", vector_magnitude},
304
{"normalize", vector_normalize},
305
{"cross", vector_cross},
306
{"dot", vector_dot},
307
{"angle", vector_angle},
308
{"floor", vector_floor},
309
{"ceil", vector_ceil},
310
{"abs", vector_abs},
311
{"sign", vector_sign},
312
{"clamp", vector_clamp},
313
{"max", vector_max},
314
{"min", vector_min},
315
{"lerp", vector_lerp},
316
{NULL, NULL},
317
};
318
319
static void createmetatable(lua_State* L)
320
{
321
lua_createtable(L, 0, 1); // create metatable for vectors
322
323
// push dummy vector
324
#if LUA_VECTOR_SIZE == 4
325
lua_pushvector(L, 0.0f, 0.0f, 0.0f, 0.0f);
326
#else
327
lua_pushvector(L, 0.0f, 0.0f, 0.0f);
328
#endif
329
330
lua_pushvalue(L, -2);
331
lua_setmetatable(L, -2); // set vector metatable
332
lua_pop(L, 1); // pop dummy vector
333
334
lua_pushcfunction(L, vector_index, nullptr);
335
lua_setfield(L, -2, "__index");
336
337
lua_setreadonly(L, -1, true);
338
lua_pop(L, 1); // pop the metatable
339
}
340
341
int luaopen_vector(lua_State* L)
342
{
343
luaL_register(L, LUA_VECLIBNAME, vectorlib);
344
345
#if LUA_VECTOR_SIZE == 4
346
lua_pushvector(L, 0.0f, 0.0f, 0.0f, 0.0f);
347
lua_setfield(L, -2, "zero");
348
lua_pushvector(L, 1.0f, 1.0f, 1.0f, 1.0f);
349
lua_setfield(L, -2, "one");
350
#else
351
lua_pushvector(L, 0.0f, 0.0f, 0.0f);
352
lua_setfield(L, -2, "zero");
353
lua_pushvector(L, 1.0f, 1.0f, 1.0f);
354
lua_setfield(L, -2, "one");
355
#endif
356
357
createmetatable(L);
358
359
return 1;
360
}
361
362