Created
March 18, 2020 09:55
-
-
Save randName/74378c84c4c356b1cec6c1a74e85c75c to your computer and use it in GitHub Desktop.
GLSL-style swizzling in Javascript
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const a = vec(1, 2, 3, 4) | |
console.log(a.length, a) | |
// standard property access | |
console.log(a[0], a.y, a.b, a.t) | |
// swizzling | |
console.log(a.xy, a.zyx, a.xxyy) | |
// same rules from GLSL apply | |
console.log(a.xyr, a.xxyyz) | |
// setters are also available | |
a.x = 3 | |
a.yz = [1, 2] | |
console.log([...a]) | |
// cloning works | |
const b = vec(...a) | |
a.x -= 3 | |
b.x += 2 | |
console.log([...a], [...b]) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
const masks = new Map(Object.entries({ | |
xyzw: /^[xyzw]{1,4}$/, | |
rgba: /^[rgba]{1,4}$/, | |
stpq: /^[stpq]{1,4}$/, | |
})) | |
const propIndex = (p) => { | |
for (const mask of masks.keys()) { | |
const idx = mask.indexOf(p) | |
if (idx === -1) { continue } | |
return idx | |
} | |
return p | |
} | |
const propMask = (p) => { | |
for (const [mask, re] of masks) { | |
if (!re.test(p)) { continue } | |
return mask | |
} | |
return null | |
} | |
function getComponent (obj, prop) { | |
if (typeof prop === 'symbol' || prop > -1) { | |
return obj[prop] | |
} else if (prop.length === 1) { | |
return obj[propIndex(prop)] | |
} | |
const m = propMask(prop) | |
if (m) { | |
return prop.split('').map((c) => obj[m.indexOf(c)]) | |
} | |
return obj[prop] | |
} | |
function setComponent (obj, prop, val) { | |
if (prop > -1) { | |
obj[prop] = val | |
return true | |
} else if (prop.length === 1) { | |
obj[propIndex(prop)] = val | |
return true | |
} | |
const plen = prop.length | |
if (plen === val.length) { | |
const m = propMask(prop) | |
if (m && plen === (new Set(prop)).size) { | |
for (let i = 0; i < plen; ++i) { | |
obj[m.indexOf(prop[i])] = val[i] | |
} | |
return true | |
} | |
} | |
return false | |
} | |
function vec (...components) { | |
return new Proxy(components, { | |
get: getComponent, | |
set: setComponent, | |
}) | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment