Vectors and Colors
Vectors and colors are a built-in family of seven types: vec2 / vec3 / vec4 (float components), vec2i / vec3i / vec4i (int components), and color (four float components, rgba, by convention in the 0..1 range and not clamped at runtime).
Construction
Construct by calling; new is not available for vectors and colors:
val v = vec2(1.0, 2.0);
print(v);
print(vec2(1.0));
print(vec2i(v));
val c = color("#ff8000");
print(c);
print(color(1.0, 0.5, 0.25));
print(color(0.25));vec2(1.0, 2.0)
vec2(1.0, 1.0)
vec2i(1, 2)
color(1.0, 0.502, 0.0, 1.0)
color(1.0, 0.5, 0.25, 1.0)
color(0.25, 0.25, 0.25, 0.25)- A single numeric argument broadcasts (
vec2(1.0)gives(1.0, 1.0)); a single vector argument converts between same-width family members (float to int truncates toward zero). colortakes three arguments (alpha defaults to 1.0) or four; it also takes a hex string (#RGB/#RGBA/#RRGGBB/#RRGGBBAA).- color component arguments must be float; int is rejected. For 8-bit values, write a hex string.
Components and swizzle
Two-alphabet discipline: vec components are xyzw, color components are rgba, and the two alphabets must not be mixed. A swizzle takes 1 to 4 letters, and the result is always interpreted by the xyzw alphabet (c.rgb.y fetches the green component):
print(c.rgb);
print(c.rgb.y);
print(v[1]);
val (x, y) = vec2i(3, 4);
print(x, y);vec3(1.0, 0.502, 0.0)
0.5019608
2
3 4Numeric indexing v[1] is the assertion form; out of bounds is a hard error on the spot. Get(i) is the corresponding fallible form: out of bounds fails with IndexOutOfRange; after try? consumes it, out of bounds gives null and a hit gives the component value (int in the vec2i family, float in the vec family and color):
print(try? v.Get(1), try? v.Get(9));
print(try? c.Get(3) ?? 0.0);2 null
1Components are read-only: v.x = 1.0 and write-side swizzles are rejected at compile time. The only way to change a value is the non-destructive update (see the with section of struct):
val moved = v with { x: 9.0 };
print(moved);vec2(9.0, 2.0)Arithmetic
+ - * / work component-wise (between same types). A scalar may join multiplication and division on either side; with the scalar on the left, - and / run component-wise in reverse: 1.0 / vec2(2.0, 4.0) gives vec2(0.5, 0.25). == / != compare by value. Ordering comparisons, bitwise operations, and exponentiation are not available.
Method surface
Method dispatch is built in and does not depend on imports:
| Member | Applies to | Description |
|---|---|---|
Length | vec family | magnitude, property form (no parentheses) |
Dot / Distance | vec family | dot product / distance between two points |
Normalized | vec family | normalize to unit length |
Cross | vec3 only | cross product |
Lerp | vec family | interpolate by a coefficient |
Hex | color only | to a hex string (alpha included, #ff8000ff) |
ToHsv / FromHsv | color / vec3 | hsv channels by convention 0..1, clamped when out of range |
print(v.Length);
print(vec2(1.0, 0.0).Dot(vec2(0.0, 1.0)));
print(vec2(1.0, 2.0).Lerp(vec2(3.0, 4.0), 0.5));
print(c.Hex());2.23606797749979
0
vec2(2.0, 3.0)
#ff8000ffCompile-time folding
Construction from pure literals, unary negation, the four arithmetic operations, and swizzle chains fold into constants at compile time. The const position supports this too: const V = vec2(1.0, 2.0); is legal, and V.x is 1 (see const funcs). A color’s single string argument goes through compile-time hex parsing in a const position.
Notes
- color’s 0..1 is a convention, not clamped at runtime:
color(2.0, 0.5, 0.25)is legal, and what falls outside is interpreted by the renderer. - match constructor pattern arms support vectors (
vec2(1.0, 0.0) => ...); see Patterns.
