///|
/// Luna's platform-independent virtual node, with typed three.js properties.
pub type Node = @luna.Node[Unit, Property]
///|
pub type Prop = @luna.Attr[Unit, Property]
///|
/// Constructed geometry is owned by the renderer. Borrowed geometry is never disposed.
pub(all) enum Geometry {
Box(Double, Double, Double)
Sphere(Double, Int, Int)
Plane(Double, Double)
Cylinder(Double, Double, Double, Int)
Cone(Double, Double, Int)
Torus(Double, Double, Int, Int)
Borrowed(@three.BufferGeometry)
}
///|
/// Standard takes color, roughness, and metalness.
pub(all) enum Material {
Basic(Int)
Standard(Int, Double, Double)
Normal
Borrowed(@three.Material)
}
///|
pub(all) enum Property {
Key(String)
Name(String)
Position(Double, Double, Double)
Rotation(Double, Double, Double)
Scale(Double, Double, Double)
Visible(Bool)
CastShadow(Bool)
ReceiveShadow(Bool)
Geometry(Geometry)
Material(Material)
Light(Int, Double)
Perspective(Double, Double, Double, Double)
Object(@three.Object3D)
}
///|
pub fn prop(value : Property) -> Prop {
@luna.attr_static(value)
}
///|
/// Signal reads in the getter update this element without rerunning its component.
/// Key and Object are construction-time properties and must be static.
pub fn dynamic(get : () -> Property) -> Prop {
@luna.attr_dynamic(get)
}
///|
fn element(
tag : String,
props : Array[Prop],
children : Array[Node],
key : String?,
) -> Node {
let attrs = props.map(fn(p) { ("prop", p) })
if key is Some(key) {
attrs.push(("key", prop(Key(key))))
}
@luna.h(tag, attrs, children)
}
///|
pub fn group(
children : Array[Node],
props? : Array[Prop] = [],
key? : String,
) -> Node {
element("group", props, children, key)
}
///|
pub fn mesh(
geometry~ : Geometry,
material~ : Material,
props? : Array[Prop] = [],
children? : Array[Node] = [],
key? : String,
) -> Node {
element(
"mesh",
[prop(Geometry(geometry)), prop(Material(material))] + props,
children,
key,
)
}
///|
/// Mount an existing Object3D without cloning or taking ownership of its resources.
pub fn primitive(
object : @three.Object3D,
props? : Array[Prop] = [],
children? : Array[Node] = [],
key? : String,
) -> Node {
element("primitive", [prop(Object(object))] + props, children, key)
}
///|
pub fn ambient_light(
color? : Int = 0xffffff,
intensity? : Double = 1,
props? : Array[Prop] = [],
key? : String,
) -> Node {
element("ambientLight", [prop(Light(color, intensity))] + props, [], key)
}
///|
pub fn directional_light(
color? : Int = 0xffffff,
intensity? : Double = 1,
props? : Array[Prop] = [],
key? : String,
) -> Node {
element("directionalLight", [prop(Light(color, intensity))] + props, [], key)
}
///|
/// The host selects this camera for rendering; mounting does not change a global camera.
pub fn perspective_camera(
fov? : Double = 50,
aspect? : Double = 1,
near? : Double = 0.1,
far? : Double = 2000,
props? : Array[Prop] = [],
key? : String,
) -> Node {
element(
"perspectiveCamera",
[prop(Perspective(fov, aspect, near, far))] + props,
[],
key,
)
}