@axpecter/lync 2.3.1 → 2.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,124 @@
1
+ --!strict
2
+ --!native
3
+ -- Smallest-three quaternion packing into a single u32 for rotation wire forms.
4
+
5
+ -- Constants --------------------------------------------------------------
6
+
7
+ local INV_SQRT2 = 1 / math.sqrt(2)
8
+ local Q_SCALE = 1023 / (2 * INV_SQRT2)
9
+ local Q_INV = (2 * INV_SQRT2) / 1023
10
+ local EPSILON_SQ = 5.76e-14
11
+
12
+ -- Private ----------------------------------------------------------------
13
+
14
+ local abs = math.abs
15
+ local clamp = math.clamp
16
+ local round = math.round
17
+ local sin = math.sin
18
+ local cos = math.cos
19
+ local acos = math.acos
20
+ local sqrt = math.sqrt
21
+ local band = bit32.band
22
+ local bor = bit32.bor
23
+ local lshift = bit32.lshift
24
+ local rshift = bit32.rshift
25
+
26
+ -- Public -----------------------------------------------------------------
27
+
28
+ local Quat = {}
29
+
30
+ --[[
31
+ Quaternion from a CFrame's rotation portion. Returns (qx, qy, qz, qw)
32
+ so callers can pack without rebuilding the conversion table.
33
+ ]]
34
+ function Quat.fromCFrame(cf: CFrame): (number, number, number, number)
35
+ local axis, angle = cf:ToAxisAngle()
36
+ local h = angle * 0.5
37
+ local s = sin(h)
38
+ return axis.X * s, axis.Y * s, axis.Z * s, cos(h)
39
+ end
40
+
41
+ --[[
42
+ Pack a unit quaternion into a single u32:
43
+ [largest:2][a:10][b:10][c:10]
44
+ Drops the largest |component|; reconstructed from the other three with
45
+ the constraint qx²+qy²+qz²+qw² = 1. Forces the dropped value
46
+ non-negative so the +sqrt path on decode yields the correct sign.
47
+ ]]
48
+ function Quat.pack(qx: number, qy: number, qz: number, qw: number): number
49
+ local ax, ay, az, aw = abs(qx), abs(qy), abs(qz), abs(qw)
50
+ local largest, maxVal = 3, aw
51
+ if ax > maxVal then
52
+ largest, maxVal = 0, ax
53
+ end
54
+ if ay > maxVal then
55
+ largest, maxVal = 1, ay
56
+ end
57
+ if az > maxVal then
58
+ largest, maxVal = 2, az
59
+ end
60
+
61
+ local a: number, b: number, c: number
62
+ if largest == 0 then
63
+ if qx < 0 then
64
+ qy, qz, qw = -qy, -qz, -qw
65
+ end
66
+ a, b, c = qy, qz, qw
67
+ elseif largest == 1 then
68
+ if qy < 0 then
69
+ qx, qz, qw = -qx, -qz, -qw
70
+ end
71
+ a, b, c = qx, qz, qw
72
+ elseif largest == 2 then
73
+ if qz < 0 then
74
+ qx, qy, qw = -qx, -qy, -qw
75
+ end
76
+ a, b, c = qx, qy, qw
77
+ else
78
+ if qw < 0 then
79
+ qx, qy, qz = -qx, -qy, -qz
80
+ end
81
+ a, b, c = qx, qy, qz
82
+ end
83
+
84
+ local qa = clamp(round((a + INV_SQRT2) * Q_SCALE), 0, 1023)
85
+ local qb = clamp(round((b + INV_SQRT2) * Q_SCALE), 0, 1023)
86
+ local qc = clamp(round((c + INV_SQRT2) * Q_SCALE), 0, 1023)
87
+ return bor(lshift(largest, 30), lshift(qa, 20), lshift(qb, 10), qc)
88
+ end
89
+
90
+ -- Reverse Quat.pack into a rotation-only CFrame. Identity for near-zero magnitudes.
91
+ function Quat.unpack(packed: number): CFrame
92
+ local largest = rshift(packed, 30)
93
+ local qa = band(rshift(packed, 20), 0x3FF)
94
+ local qb = band(rshift(packed, 10), 0x3FF)
95
+ local qc = band(packed, 0x3FF)
96
+
97
+ local a = qa * Q_INV - INV_SQRT2
98
+ local b = qb * Q_INV - INV_SQRT2
99
+ local c = qc * Q_INV - INV_SQRT2
100
+
101
+ local sqSum = a * a + b * b + c * c
102
+ local d = sqrt(if sqSum < 1 then 1 - sqSum else 0)
103
+
104
+ local qx: number, qy: number, qz: number, qw: number
105
+ if largest == 0 then
106
+ qx, qy, qz, qw = d, a, b, c
107
+ elseif largest == 1 then
108
+ qx, qy, qz, qw = a, d, b, c
109
+ elseif largest == 2 then
110
+ qx, qy, qz, qw = a, b, d, c
111
+ else
112
+ qx, qy, qz, qw = a, b, c, d
113
+ end
114
+
115
+ local sqLen = qx * qx + qy * qy + qz * qz
116
+ if sqLen < EPSILON_SQ then
117
+ return CFrame.identity
118
+ end
119
+ local angle = 2 * acos(clamp(qw, -1, 1))
120
+ local inv = 1 / sqrt(sqLen)
121
+ return CFrame.fromAxisAngle(Vector3.new(qx * inv, qy * inv, qz * inv), angle)
122
+ end
123
+
124
+ return table.freeze(Quat)