Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Roblox
GitHub Repository: Roblox/luau
Path: blob/master/bench/tests/sunspider/3d-cube.lua
2727 views
1
-- 3D Cube Rotation
2
-- http://www.speich.net/computer/moztesting/3d.htm
3
-- Created by Simon Speich
4
5
local function prequire(name) local success, result = pcall(require, name); return success and result end
6
local bench = script and require(script.Parent.bench_support) or prequire("bench_support") or require("../../bench_support")
7
8
function test()
9
10
local Q = {}
11
local MTrans = {}; -- transformation matrix
12
local MQube = {} -- position information of qube
13
local I = {} -- entity matrix
14
local Origin = {}
15
local Testing = {}
16
local LoopTimer;
17
18
local validation = {
19
[20] = 2889,
20
[40] = 2889,
21
[80] = 2889,
22
[160] = 2889
23
};
24
25
local DisplArea = {}
26
DisplArea.Width = 300;
27
DisplArea.Height = 300;
28
29
local function DrawLine(From, To)
30
local x1 = From.V[1];
31
local x2 = To.V[1];
32
local y1 = From.V[2];
33
local y2 = To.V[2];
34
local dx = math.abs(x2 - x1);
35
local dy = math.abs(y2 - y1);
36
local x = x1;
37
local y = y1;
38
local IncX1, IncY1;
39
local IncX2, IncY2;
40
local Den;
41
local Num;
42
local NumAdd;
43
local NumPix;
44
45
if (x2 >= x1) then IncX1 = 1; IncX2 = 1;
46
else IncX1 = -1; IncX2 = -1; end
47
48
if (y2 >= y1) then IncY1 = 1; IncY2 = 1;
49
else IncY1 = -1; IncY2 = -1; end
50
51
if (dx >= dy) then
52
IncX1 = 0;
53
IncY2 = 0;
54
Den = dx;
55
Num = dx / 2;
56
NumAdd = dy;
57
NumPix = dx;
58
else
59
IncX2 = 0;
60
IncY1 = 0;
61
Den = dy;
62
Num = dy / 2;
63
NumAdd = dx;
64
NumPix = dy;
65
end
66
67
NumPix = math.floor(Q.LastPx + NumPix + 0.5);
68
69
local i = Q.LastPx;
70
while i < NumPix do
71
Num = Num + NumAdd;
72
if (Num >= Den) then
73
Num = Num - Den;
74
x = x + IncX1;
75
y = y + IncY1;
76
end
77
x = x + IncX2;
78
y = y + IncY2;
79
80
i = i + 1;
81
end
82
Q.LastPx = NumPix;
83
end
84
85
local function CalcCross(V0, V1)
86
local Cross = {};
87
Cross[1] = V0[2]*V1[3] - V0[3]*V1[2];
88
Cross[2] = V0[3]*V1[1] - V0[1]*V1[3];
89
Cross[3] = V0[1]*V1[2] - V0[2]*V1[1];
90
return Cross;
91
end
92
93
local function CalcNormal(V0, V1, V2)
94
local A = {}; local B = {};
95
for i = 1,3 do
96
A[i] = V0[i] - V1[i];
97
B[i] = V2[i] - V1[i];
98
end
99
A = CalcCross(A, B);
100
local Length = math.sqrt(A[1]*A[1] + A[2]*A[2] + A[3]*A[3]);
101
for i = 1,3 do A[i] = A[i] / Length; end
102
A[4] = 1;
103
return A;
104
end
105
106
local function CreateP(X,Y,Z)
107
local result = {}
108
result.V = {X,Y,Z,1};
109
return result
110
end
111
112
-- multiplies two matrices
113
local function MMulti(M1, M2)
114
local M = {{},{},{},{}};
115
for i = 1,4 do
116
for j = 1,4 do
117
M[i][j] = M1[i][1] * M2[1][j] + M1[i][2] * M2[2][j] + M1[i][3] * M2[3][j] + M1[i][4] * M2[4][j];
118
end
119
end
120
return M;
121
end
122
123
-- multiplies matrix with vector
124
local function VMulti(M, V)
125
local Vect = {};
126
for i = 1,4 do
127
Vect[i] = M[i][1] * V[1] + M[i][2] * V[2] + M[i][3] * V[3] + M[i][4] * V[4];
128
end
129
return Vect;
130
end
131
132
local function VMulti2(M, V)
133
local Vect = {};
134
for i = 1,3 do
135
Vect[i] = M[i][1] * V[1] + M[i][2] * V[2] + M[i][3] * V[3];
136
end
137
return Vect;
138
end
139
140
-- add to matrices
141
local function MAdd(M1, M2)
142
local M = {{},{},{},{}};
143
for i = 1,4 do
144
for j = 1,4 do
145
M[i][j] = M1[i][j] + M2[i][j];
146
end
147
end
148
return M;
149
end
150
151
local function Translate(M, Dx, Dy, Dz)
152
local T = {
153
{1,0,0,Dx},
154
{0,1,0,Dy},
155
{0,0,1,Dz},
156
{0,0,0,1}
157
};
158
return MMulti(T, M);
159
end
160
161
local function RotateX(M, Phi)
162
local a = Phi;
163
a = a * math.pi / 180;
164
local Cos = math.cos(a);
165
local Sin = math.sin(a);
166
local R = {
167
{1,0,0,0},
168
{0,Cos,-Sin,0},
169
{0,Sin,Cos,0},
170
{0,0,0,1}
171
};
172
return MMulti(R, M);
173
end
174
175
local function RotateY(M, Phi)
176
local a = Phi;
177
a = a * math.pi / 180;
178
local Cos = math.cos(a);
179
local Sin = math.sin(a);
180
local R = {
181
{Cos,0,Sin,0},
182
{0,1,0,0},
183
{-Sin,0,Cos,0},
184
{0,0,0,1}
185
};
186
return MMulti(R, M);
187
end
188
189
local function RotateZ(M, Phi)
190
local a = Phi;
191
a = a * math.pi / 180;
192
local Cos = math.cos(a);
193
local Sin = math.sin(a);
194
local R = {
195
{Cos,-Sin,0,0},
196
{Sin,Cos,0,0},
197
{0,0,1,0},
198
{0,0,0,1}
199
};
200
return MMulti(R, M);
201
end
202
203
local function DrawQube()
204
-- calc current normals
205
local CurN = {};
206
local i = 5;
207
Q.LastPx = 0;
208
while i > -1 do CurN[i+1] = VMulti2(MQube, Q.Normal[i+1]); i = i - 1 end
209
if (CurN[1][3] < 0) then
210
if (not Q.Line[1]) then DrawLine(Q[1], Q[2]); Q.Line[1] = true; end
211
if (not Q.Line[2]) then DrawLine(Q[2], Q[3]); Q.Line[2] = true; end
212
if (not Q.Line[3]) then DrawLine(Q[3], Q[4]); Q.Line[3] = true; end
213
if (not Q.Line[4]) then DrawLine(Q[4], Q[1]); Q.Line[4] = true; end
214
end
215
if (CurN[2][3] < 0) then
216
if (not Q.Line[3]) then DrawLine(Q[4], Q[3]); Q.Line[3] = true; end
217
if (not Q.Line[10]) then DrawLine(Q[3], Q[7]); Q.Line[10] = true; end
218
if (not Q.Line[7]) then DrawLine(Q[7], Q[8]); Q.Line[7] = true; end
219
if (not Q.Line[11]) then DrawLine(Q[8], Q[4]); Q.Line[11] = true; end
220
end
221
if (CurN[3][3] < 0) then
222
if (not Q.Line[5]) then DrawLine(Q[5], Q[6]); Q.Line[6] = true; end
223
if (not Q.Line[6]) then DrawLine(Q[6], Q[7]); Q.Line[6] = true; end
224
if (not Q.Line[7]) then DrawLine(Q[7], Q[8]); Q.Line[7] = true; end
225
if (not Q.Line[8]) then DrawLine(Q[8], Q[5]); Q.Line[8] = true; end
226
end
227
if (CurN[4][3] < 0) then
228
if (not Q.Line[5]) then DrawLine(Q[5], Q[6]); Q.Line[5] = true; end
229
if (not Q.Line[9]) then DrawLine(Q[6], Q[2]); Q.Line[9] = true; end
230
if (not Q.Line[1]) then DrawLine(Q[2], Q[1]); Q.Line[1] = true; end
231
if (not Q.Line[12]) then DrawLine(Q[1], Q[5]); Q.Line[12] = true; end
232
end
233
if (CurN[5][3] < 0) then
234
if (not Q.Line[12]) then DrawLine(Q[5], Q[1]); Q.Line[12] = true; end
235
if (not Q.Line[4]) then DrawLine(Q[1], Q[4]); Q.Line[4] = true; end
236
if (not Q.Line[11]) then DrawLine(Q[4], Q[8]); Q.Line[11] = true; end
237
if (not Q.Line[8]) then DrawLine(Q[8], Q[5]); Q.Line[8] = true; end
238
end
239
if (CurN[6][3] < 0) then
240
if (not Q.Line[9]) then DrawLine(Q[2], Q[6]); Q.Line[9] = true; end
241
if (not Q.Line[6]) then DrawLine(Q[6], Q[7]); Q.Line[6] = true; end
242
if (not Q.Line[10]) then DrawLine(Q[7], Q[3]); Q.Line[10] = true; end
243
if (not Q.Line[2]) then DrawLine(Q[3], Q[2]); Q.Line[2] = true; end
244
end
245
Q.Line = {false,false,false,false,false,false,false,false,false,false,false,false}
246
Q.LastPx = 0;
247
end
248
249
local function Loop()
250
if (Testing.LoopCount > Testing.LoopMax) then return; end
251
local TestingStr = tostring(Testing.LoopCount);
252
while (#TestingStr < 3) do TestingStr = "0" .. TestingStr; end
253
MTrans = Translate(I, -Q[9].V[1], -Q[9].V[2], -Q[9].V[3]);
254
MTrans = RotateX(MTrans, 1);
255
MTrans = RotateY(MTrans, 3);
256
MTrans = RotateZ(MTrans, 5);
257
MTrans = Translate(MTrans, Q[9].V[1], Q[9].V[2], Q[9].V[3]);
258
MQube = MMulti(MTrans, MQube);
259
local i = 8;
260
while i > -1 do
261
Q[i+1].V = VMulti(MTrans, Q[i+1].V);
262
i = i - 1
263
end
264
DrawQube();
265
Testing.LoopCount = Testing.LoopCount + 1;
266
Loop();
267
end
268
269
local function Init(CubeSize)
270
-- init/reset vars
271
Origin.V = {150,150,20,1};
272
Testing.LoopCount = 0;
273
Testing.LoopMax = 50;
274
Testing.TimeMax = 0;
275
Testing.TimeAvg = 0;
276
Testing.TimeMin = 0;
277
Testing.TimeTemp = 0;
278
Testing.TimeTotal = 0;
279
Testing.Init = false;
280
281
-- transformation matrix
282
MTrans = {
283
{1,0,0,0},
284
{0,1,0,0},
285
{0,0,1,0},
286
{0,0,0,1}
287
};
288
289
-- position information of qube
290
MQube = {
291
{1,0,0,0},
292
{0,1,0,0},
293
{0,0,1,0},
294
{0,0,0,1}
295
};
296
297
-- entity matrix
298
I = {
299
{1,0,0,0},
300
{0,1,0,0},
301
{0,0,1,0},
302
{0,0,0,1}
303
};
304
305
-- create qube
306
Q[1] = CreateP(-CubeSize,-CubeSize, CubeSize);
307
Q[2] = CreateP(-CubeSize, CubeSize, CubeSize);
308
Q[3] = CreateP( CubeSize, CubeSize, CubeSize);
309
Q[4] = CreateP( CubeSize,-CubeSize, CubeSize);
310
Q[5] = CreateP(-CubeSize,-CubeSize,-CubeSize);
311
Q[6] = CreateP(-CubeSize, CubeSize,-CubeSize);
312
Q[7] = CreateP( CubeSize, CubeSize,-CubeSize);
313
Q[8] = CreateP( CubeSize,-CubeSize,-CubeSize);
314
315
-- center of gravity
316
Q[9] = CreateP(0, 0, 0);
317
318
-- anti-clockwise edge check
319
Q.Edge = {{1,2,3},{4,5,7},{8,7,6},{5,6,2},{5,1,4},{2,6,7}};
320
321
-- calculate squad normals
322
Q.Normal = {};
323
for i = 1,#Q.Edge do
324
Q.Normal[i] = CalcNormal(Q[Q.Edge[i][1]].V, Q[Q.Edge[i][2]].V, Q[Q.Edge[i][3]].V);
325
end
326
327
-- line drawn ?
328
Q.Line = {false,false,false,false,false,false,false,false,false,false,false,false};
329
330
-- create line pixels
331
Q.NumPx = 9 * 2 * CubeSize;
332
for i = 1,Q.NumPx do CreateP(0,0,0); end
333
334
MTrans = Translate(MTrans, Origin.V[1], Origin.V[2], Origin.V[3]);
335
MQube = MMulti(MTrans, MQube);
336
337
local i = 0;
338
while i < 9 do
339
Q[i+1].V = VMulti(MTrans, Q[i+1].V);
340
i = i + 1
341
end
342
DrawQube();
343
Testing.Init = true;
344
Loop();
345
346
-- Perform a simple sum-based verification.
347
local sum = 0;
348
for i = 1,#Q do
349
local vector = Q[i].V;
350
for j = 1,#vector do
351
sum = sum + vector[j];
352
end
353
end
354
if (math.floor(sum) ~= validation[CubeSize]) then
355
assert(false, "Error: bad vector sum for CubeSize = " .. CubeSize .. "; expected " .. validation[CubeSize] .. " but got " .. math.floor(sum))
356
end
357
end
358
359
local i = 20
360
while i <= 160 do
361
Init(i);
362
i = i * 2
363
end
364
365
Q = nil;
366
MTrans = nil;
367
MQube = nil;
368
I = nil;
369
Origin = nil;
370
Testing = nil;
371
LoopTime = nil;
372
DisplArea = nil;
373
374
end
375
376
bench.runCode(test, "3d-cube")
377
378