-
Notifications
You must be signed in to change notification settings - Fork 7
/
VectorMath.macro.hx
130 lines (111 loc) · 3.27 KB
/
VectorMath.macro.hx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
/**
Macros required by VectorMath
xyzw
rgba
stpq
**/
import haxe.macro.Expr;
import haxe.macro.Context;
class Swizzle {
static public function generateFields(vectorLength: Int) {
var fields = Context.getBuildFields();
// for vector length N, we generate all possible combinations of 4 (or less)
// for swizzles that do not repeat, we also add a setter
generateSwizzles(fields, vectorLength, xyzw, true);
// add .rgba and .stpq swizzles
generateSwizzles(fields, vectorLength, ['r','g','b','a'], false);
generateSwizzles(fields, vectorLength, ['s','t','p','q'], false);
return fields;
}
static function generateSwizzles(fields: Array<Field>, vectorLength: Int, keys: Array<String>, skipLength1: Bool) {
// length 1 fields
if (!skipLength1) for (i in 0...vectorLength) {
generateProperty(fields, [i], keys);
}
// length 2 fields
for (i in 0...vectorLength) {
for (j in 0...vectorLength) {
generateProperty(fields, [i,j], keys);
}
}
// length 3 fields
for (i in 0...vectorLength) {
for (j in 0...vectorLength) {
for (k in 0...vectorLength) {
generateProperty(fields, [i,j,k], keys);
}
}
}
// length 4 fields
for (i in 0...vectorLength) {
for (j in 0...vectorLength) {
for (k in 0...vectorLength) {
for (l in 0...vectorLength) {
generateProperty(fields, [i,j,k,l], keys);
}
}
}
}
}
static final xyzw = ['x', 'y', 'z', 'w'];
// build some useful lookups
static final thisReadExpr = xyzw.map(c -> macro this.$c);
static final vReadExpr = xyzw.map(c -> macro v.$c);
static final vectorTypeMap: Array<TypePath> = [
{ pack: [], name: 'Float' },
{ pack: [], name: 'Vec2' },
{ pack: [], name: 'Vec3' },
{ pack: [], name: 'Vec4' }
];
static function generateProperty(fields: Array<Field>, swizzle: Array<Int>, keys: Array<String>) {
var ident = swizzle.map(i -> keys[i]).join('');
var readonly = hasDuplicate(swizzle);
var typePath = vectorTypeMap[swizzle.length - 1];
var type: ComplexType = TPath(typePath);
var declaration = if (readonly) {
(macro class { public var $ident(get, never): $type; }).fields[0];
} else {
(macro class { public var $ident(get, set): $type; }).fields[0];
}
// add @:noCompletion if swizzle is not a single component
if (swizzle.length > 1) {
declaration.meta = [{
name: ':noCompletion',
pos: Context.currentPos(),
}];
}
var getterName = 'get_$ident';
var getter = (macro class {
inline function $getterName(): $type
return ${
if (swizzle.length > 1) {
macro new $typePath( $a{swizzle.map(i -> thisReadExpr[i])} );
} else {
thisReadExpr[swizzle[0]];
}
}
}).fields[0];
fields.push(declaration);
fields.push(getter);
if (!readonly) {
var setterName = 'set_$ident';
var setter = (macro class {
inline function $setterName(v: $type): $type {
$b{[for (i in 0...swizzle.length)
macro ${thisReadExpr[swizzle[i]]} = ${swizzle.length > 1 ? vReadExpr[i] : macro v}
]}
return ${swizzle.length > 1 ? macro v.clone() : macro v};
}
}).fields[0];
fields.push(setter);
}
}
static function hasDuplicate(array: Array<Int>) {
for (i in 0...array.length) {
for (j in (i + 1)...array.length) {
if (array[i] == array[j]) return true;
}
}
return false;
}
}