///|
pub(all) struct MeshId {
value : Int
} derive(Eq, Debug, ToJson)
///|
pub extend MeshId with Debug::{to_repr}
///|
pub extend MeshId with Eq::{not_equal, equal}
///|
pub extend MeshId with ToJson::{to_json}
///|
pub(all) struct MaterialId {
value : Int
} derive(Eq, Debug, ToJson)
///|
pub extend MaterialId with Debug::{to_repr}
///|
pub extend MaterialId with Eq::{not_equal, equal}
///|
pub extend MaterialId with ToJson::{to_json}
///|
pub(all) struct TextureId {
value : Int
} derive(Eq, Debug, ToJson)
///|
pub extend TextureId with Debug::{to_repr}
///|
pub extend TextureId with Eq::{not_equal, equal}
///|
pub extend TextureId with ToJson::{to_json}
///|
pub(all) struct SamplerId {
value : Int
} derive(Eq, Debug, ToJson)
///|
pub extend SamplerId with Debug::{to_repr}
///|
pub extend SamplerId with Eq::{not_equal, equal}
///|
pub extend SamplerId with ToJson::{to_json}
///|
pub(all) struct NodeId {
value : Int
} derive(Eq, Debug, ToJson)
///|
pub extend NodeId with Debug::{to_repr}
///|
pub extend NodeId with Eq::{not_equal, equal}
///|
pub extend NodeId with ToJson::{to_json}
///|
pub fn MeshId::new(value : Int) -> MeshId {
{ value, }
}
///|
pub fn MaterialId::new(value : Int) -> MaterialId {
{ value, }
}
///|
pub fn TextureId::new(value : Int) -> TextureId {
{ value, }
}
///|
pub fn SamplerId::new(value : Int) -> SamplerId {
{ value, }
}
///|
pub fn NodeId::new(value : Int) -> NodeId {
{ value, }
}
///|
pub fn MeshId::value(self : MeshId) -> Int {
self.value
}
///|
pub fn MaterialId::value(self : MaterialId) -> Int {
self.value
}
///|
pub fn TextureId::value(self : TextureId) -> Int {
self.value
}
///|
pub fn SamplerId::value(self : SamplerId) -> Int {
self.value
}
///|
pub fn NodeId::value(self : NodeId) -> Int {
self.value
}
///|
pub(all) struct Vertex {
position : Vec3
normal : Vec3
texcoord : Vec2
joints : (Int, Int, Int, Int)
weights : Vec4
} derive(Eq, Debug, ToJson)
///|
pub extend Vertex with Debug::{to_repr}
///|
pub extend Vertex with Eq::{not_equal, equal}
///|
pub extend Vertex with ToJson::{to_json}
///|
pub fn Vertex::new(
position~ : Vec3,
normal? : Vec3 = Vec3::new(x=0.0, y=1.0, z=0.0),
texcoord? : Vec2 = Vec2::zero(),
joints? : (Int, Int, Int, Int) = (0, 0, 0, 0),
weights? : Vec4 = Vec4::zero(),
) -> Vertex {
{ position, normal, texcoord, joints, weights, }
}
///|
pub fn Vertex::position(self : Vertex) -> Vec3 {
self.position
}
///|
pub fn Vertex::normal(self : Vertex) -> Vec3 {
self.normal
}
///|
pub fn Vertex::texcoord(self : Vertex) -> Vec2 {
self.texcoord
}
///|
pub fn Vertex::joints(self : Vertex) -> (Int, Int, Int, Int) {
self.joints
}
///|
pub fn Vertex::weights(self : Vertex) -> Vec4 {
self.weights
}
///|
pub(all) enum TextureSource {
Uri(String)
Embedded(Bytes)
} derive(Debug)
///|
pub extend TextureSource with Debug::{to_repr}
///|
pub(all) enum SamplerFilter {
Nearest
Linear
NearestMipmapNearest
LinearMipmapNearest
NearestMipmapLinear
LinearMipmapLinear
} derive(Eq, Debug, ToJson)
///|
pub extend SamplerFilter with Debug::{to_repr}
///|
pub extend SamplerFilter with Eq::{not_equal, equal}
///|
pub extend SamplerFilter with ToJson::{to_json}
///|
pub(all) enum SamplerWrap {
Repeat
MirroredRepeat
ClampToEdge
} derive(Eq, Debug, ToJson)
///|
pub extend SamplerWrap with Debug::{to_repr}
///|
pub extend SamplerWrap with Eq::{not_equal, equal}
///|
pub extend SamplerWrap with ToJson::{to_json}
///|
pub(all) struct Sampler {
mag_filter : SamplerFilter
min_filter : SamplerFilter
wrap_s : SamplerWrap
wrap_t : SamplerWrap
} derive(Eq, Debug, ToJson)
///|
pub extend Sampler with Debug::{to_repr}
///|
pub extend Sampler with Eq::{not_equal, equal}
///|
pub extend Sampler with ToJson::{to_json}
///|
pub fn Sampler::new(
mag_filter? : SamplerFilter = Linear,
min_filter? : SamplerFilter = LinearMipmapLinear,
wrap_s? : SamplerWrap = Repeat,
wrap_t? : SamplerWrap = Repeat,
) -> Sampler {
{ mag_filter, min_filter, wrap_s, wrap_t, }
}
///|
pub fn Sampler::mag_filter(self : Sampler) -> SamplerFilter {
self.mag_filter
}
///|
pub fn Sampler::min_filter(self : Sampler) -> SamplerFilter {
self.min_filter
}
///|
pub fn Sampler::wrap_s(self : Sampler) -> SamplerWrap {
self.wrap_s
}
///|
pub fn Sampler::wrap_t(self : Sampler) -> SamplerWrap {
self.wrap_t
}
///|
pub(all) struct Texture {
source : TextureSource
mime_type : String?
sampler : SamplerId?
} derive(Debug)
///|
pub extend Texture with Debug::{to_repr}
///|
pub fn Texture::uri(
uri : String,
mime_type? : String? = None,
sampler? : SamplerId? = None,
) -> Texture {
{ source: Uri(uri), mime_type, sampler, }
}
///|
pub fn Texture::embedded(
bytes : Bytes,
mime_type? : String? = None,
sampler? : SamplerId? = None,
) -> Texture {
{ source: Embedded(bytes), mime_type, sampler, }
}
///|
pub fn Texture::source(self : Texture) -> TextureSource {
self.source
}
///|
pub fn Texture::mime_type(self : Texture) -> String? {
self.mime_type
}
///|
pub fn Texture::sampler(self : Texture) -> SamplerId? {
self.sampler
}
///|
pub(all) struct Material {
base_color : Vec4
metallic : Double
roughness : Double
base_color_texture : TextureId?
normal_texture : TextureId?
occlusion_texture : TextureId?
emissive_texture : TextureId?
emissive_factor : Vec3
alpha_mode : AlphaMode
alpha_cutoff : Double
double_sided : Bool
} derive(Eq, Debug, ToJson)
///|
pub extend Material with Debug::{to_repr}
///|
pub extend Material with Eq::{not_equal, equal}
///|
pub extend Material with ToJson::{to_json}
///|
pub(all) enum CameraProjection {
Perspective(Double, Double, Double, Double)
Orthographic(Double, Double, Double, Double)
} derive(Eq, Debug, ToJson)
///|
pub extend CameraProjection with Debug::{to_repr}
///|
pub extend CameraProjection with Eq::{not_equal, equal}
///|
pub extend CameraProjection with ToJson::{to_json}
///|
pub(all) struct Camera {
name : String
projection : CameraProjection
} derive(Eq, Debug, ToJson)
///|
pub extend Camera with Debug::{to_repr}
///|
pub extend Camera with Eq::{not_equal, equal}
///|
pub extend Camera with ToJson::{to_json}
///|
pub fn Camera::new(
name? : String = "",
projection~ : CameraProjection,
) -> Camera {
{ name, projection, }
}
///|
pub fn Camera::name(self : Camera) -> String {
self.name
}
///|
pub fn Camera::projection(self : Camera) -> CameraProjection {
self.projection
}
///|
pub(all) struct SceneDefinition {
name : String
roots : Array[NodeId]
} derive(Eq, Debug, ToJson)
///|
pub extend SceneDefinition with Debug::{to_repr}
///|
pub extend SceneDefinition with Eq::{not_equal, equal}
///|
pub extend SceneDefinition with ToJson::{to_json}
///|
pub fn SceneDefinition::new(
name? : String = "",
roots~ : Array[NodeId],
) -> SceneDefinition {
{ name, roots: roots.copy(), }
}
///|
pub fn SceneDefinition::name(self : SceneDefinition) -> String {
self.name
}
///|
pub fn SceneDefinition::roots(self : SceneDefinition) -> Array[NodeId] {
self.roots.copy()
}
///|
pub(all) struct VertexDelta {
position : Vec3
normal : Vec3
tangent : Vec3
} derive(Eq, Debug, ToJson)
///|
pub extend VertexDelta with Debug::{to_repr}
///|
pub extend VertexDelta with Eq::{not_equal, equal}
///|
pub extend VertexDelta with ToJson::{to_json}
///|
pub fn VertexDelta::new(
position? : Vec3 = Vec3::zero(),
normal? : Vec3 = Vec3::zero(),
tangent? : Vec3 = Vec3::zero(),
) -> VertexDelta {
{ position, normal, tangent, }
}
///|
pub fn VertexDelta::position(self : VertexDelta) -> Vec3 {
self.position
}
///|
pub fn VertexDelta::normal(self : VertexDelta) -> Vec3 {
self.normal
}
///|
pub fn VertexDelta::tangent(self : VertexDelta) -> Vec3 {
self.tangent
}
///|
pub(all) struct Skin {
name : String
joints : Array[NodeId]
inverse_bind_matrices : Array[Mat4]
skeleton : NodeId?
} derive(Debug)
///|
pub extend Skin with Debug::{to_repr}
///|
pub fn Skin::new(
name? : String = "",
joints~ : Array[NodeId],
inverse_bind_matrices? : Array[Mat4] = [],
skeleton? : NodeId? = None,
) -> Skin {
{
name,
joints: joints.copy(),
inverse_bind_matrices: inverse_bind_matrices.copy(),
skeleton,
}
}
///|
pub fn Skin::name(self : Skin) -> String {
self.name
}
///|
pub fn Skin::joints(self : Skin) -> Array[NodeId] {
self.joints.copy()
}
///|
pub fn Skin::inverse_bind_matrices(self : Skin) -> Array[Mat4] {
self.inverse_bind_matrices.copy()
}
///|
pub fn Skin::skeleton(self : Skin) -> NodeId? {
self.skeleton
}
///|
pub(all) enum AlphaMode {
Opaque
Mask
Blend
} derive(Eq, Debug, ToJson)
///|
pub extend AlphaMode with Debug::{to_repr}
///|
pub extend AlphaMode with Eq::{not_equal, equal}
///|
pub extend AlphaMode with ToJson::{to_json}
///|
pub fn Material::pbr(
base_color? : Vec4 = Vec4::new(x=1.0, y=1.0, z=1.0, w=1.0),
metallic? : Double = 0.0,
roughness? : Double = 1.0,
base_color_texture? : TextureId? = None,
normal_texture? : TextureId? = None,
occlusion_texture? : TextureId? = None,
emissive_texture? : TextureId? = None,
emissive_factor? : Vec3 = Vec3::zero(),
alpha_mode? : AlphaMode = Opaque,
alpha_cutoff? : Double = 0.5,
double_sided? : Bool = false,
) -> Material {
{
base_color,
metallic: clamp01(metallic),
roughness: clamp_min(roughness, 0.04),
base_color_texture,
normal_texture,
occlusion_texture,
emissive_texture,
emissive_factor,
alpha_mode,
alpha_cutoff: clamp01(alpha_cutoff),
double_sided,
}
}
///|
pub fn Material::base_color(self : Material) -> Vec4 {
self.base_color
}
///|
pub fn Material::metallic(self : Material) -> Double {
self.metallic
}
///|
pub fn Material::roughness(self : Material) -> Double {
self.roughness
}
///|
pub fn Material::base_color_texture(self : Material) -> TextureId? {
self.base_color_texture
}
///|
pub fn Material::normal_texture(self : Material) -> TextureId? {
self.normal_texture
}
///|
pub fn Material::occlusion_texture(self : Material) -> TextureId? {
self.occlusion_texture
}
///|
pub fn Material::emissive_texture(self : Material) -> TextureId? {
self.emissive_texture
}
///|
pub fn Material::emissive_factor(self : Material) -> Vec3 {
self.emissive_factor
}
///|
pub fn Material::alpha_mode(self : Material) -> AlphaMode {
self.alpha_mode
}
///|
pub fn Material::alpha_cutoff(self : Material) -> Double {
self.alpha_cutoff
}
///|
pub fn Material::double_sided(self : Material) -> Bool {
self.double_sided
}
///|
pub(all) struct Primitive {
vertices : Array[Vertex]
indices : Array[Int]
material : MaterialId?
bounds : Aabb
morph_targets : Array[Array[VertexDelta]]
} derive(Debug)
///|
pub extend Primitive with Debug::{to_repr}
///|
pub fn Primitive::new(
vertices~ : Array[Vertex],
indices~ : Array[Int],
material? : MaterialId? = None,
morph_targets? : Array[Array[VertexDelta]] = [],
) -> Primitive {
let points = vertices.map(vertex => vertex.position)
{
vertices: vertices.copy(),
indices: indices.copy(),
material,
bounds: Aabb::from_points(points),
morph_targets: morph_targets.map(target => target.copy()),
}
}
///|
pub fn Primitive::vertices(self : Primitive) -> Array[Vertex] {
self.vertices.copy()
}
///|
pub fn Primitive::indices(self : Primitive) -> Array[Int] {
self.indices.copy()
}
///|
pub fn Primitive::material(self : Primitive) -> MaterialId? {
self.material
}
///|
pub fn Primitive::bounds(self : Primitive) -> Aabb {
self.bounds
}
///|
pub fn Primitive::morph_targets(self : Primitive) -> Array[Array[VertexDelta]] {
self.morph_targets.map(target => target.copy())
}
///|
pub(all) struct Mesh {
name : String
primitives : Array[Primitive]
weights : Array[Double]
bounds : Aabb
} derive(Debug)
///|
pub extend Mesh with Debug::{to_repr}
///|
pub fn Mesh::new(
name? : String = "",
primitives~ : Array[Primitive],
weights? : Array[Double] = [],
) -> Mesh {
let mut bounds = Aabb::empty()
for primitive in primitives {
bounds = bounds.union(primitive.bounds)
}
{ name, primitives: primitives.copy(), weights: weights.copy(), bounds, }
}
///|
pub fn Mesh::name(self : Mesh) -> String {
self.name
}
///|
pub fn Mesh::primitives(self : Mesh) -> Array[Primitive] {
self.primitives.copy()
}
///|
pub fn Mesh::weights(self : Mesh) -> Array[Double] {
self.weights.copy()
}
///|
pub fn Mesh::bounds(self : Mesh) -> Aabb {
self.bounds
}
///|
pub(all) struct Node {
name : String
parent : NodeId?
children : Array[NodeId]
local_transform : Mat4
mesh : MeshId?
camera : Int?
skin : Int?
weights : Array[Double]?
} derive(Debug)
///|
pub extend Node with Debug::{to_repr}
///|
pub fn Node::new(
name? : String = "",
parent? : NodeId? = None,
local_transform? : Mat4 = Mat4::identity(),
mesh? : MeshId? = None,
camera? : Int? = None,
skin? : Int? = None,
weights? : Array[Double]? = None,
) -> Node {
{ name, parent, children: [], local_transform, mesh, camera, skin, weights, }
}
///|
pub fn Node::name(self : Node) -> String {
self.name
}
///|
pub fn Node::parent(self : Node) -> NodeId? {
self.parent
}
///|
pub fn Node::children(self : Node) -> Array[NodeId] {
self.children.copy()
}
///|
pub fn Node::local_transform(self : Node) -> Mat4 {
self.local_transform
}
///|
/// Return a node with a replaced local transform. Scene animation applies
/// poses to a copied scene so the authored/rest transform remains reusable.
pub fn Node::with_local_transform(self : Node, local_transform : Mat4) -> Node {
{ ..self, local_transform, }
}
///|
pub fn Node::mesh(self : Node) -> MeshId? {
self.mesh
}
///|
pub fn Node::camera(self : Node) -> Int? {
self.camera
}
///|
pub fn Node::skin(self : Node) -> Int? {
self.skin
}
///|
pub fn Node::weights(self : Node) -> Array[Double]? {
self.weights
}
///|
pub fn Node::with_child(self : Node, child : NodeId) -> Node {
self.children.push(child)
self
}
///|
pub(all) struct PickHit {
node : NodeId
primitive_index : Int
distance : Double
position : Vec3
} derive(Eq, Debug, ToJson)
///|
pub extend PickHit with Debug::{to_repr}
///|
pub extend PickHit with Eq::{not_equal, equal}
///|
pub extend PickHit with ToJson::{to_json}
///|
pub fn PickHit::node(self : PickHit) -> NodeId {
self.node
}
///|
pub fn PickHit::primitive_index(self : PickHit) -> Int {
self.primitive_index
}
///|
pub fn PickHit::distance(self : PickHit) -> Double {
self.distance
}
///|
pub fn PickHit::position(self : PickHit) -> Vec3 {
self.position
}
///|
pub(all) struct Scene {
meshes : Array[Mesh]
materials : Array[Material]
textures : Array[Texture]
samplers : Array[Sampler]
cameras : Array[Camera]
definitions : Array[SceneDefinition]
skins : Array[Skin]
mut default_scene : Int?
nodes : Array[Node]
animations : Array[AnimationClip]
} derive(Debug)
///|
pub extend Scene with Debug::{to_repr}
///|
pub fn Scene::empty() -> Scene {
{
meshes: [],
materials: [],
textures: [],
samplers: [],
cameras: [],
definitions: [],
skins: [],
default_scene: None,
nodes: [],
animations: [],
}
}
///|
pub fn Scene::meshes(self : Scene) -> Array[Mesh] {
self.meshes.copy()
}
///|
pub fn Scene::materials(self : Scene) -> Array[Material] {
self.materials.copy()
}
///|
pub fn Scene::textures(self : Scene) -> Array[Texture] {
self.textures.copy()
}
///|
pub fn Scene::nodes(self : Scene) -> Array[Node] {
self.nodes.copy()
}
///|
/// Copy the scene containers before applying a transient animation pose.
/// Mesh/material/animation values are immutable, while nodes are replaced in
/// the returned scene and never mutated in the authored scene.
pub fn Scene::copy(self : Scene) -> Scene {
{
meshes: self.meshes.copy(),
materials: self.materials.copy(),
textures: self.textures.copy(),
samplers: self.samplers.copy(),
cameras: self.cameras.copy(),
definitions: self.definitions.copy(),
skins: self.skins.copy(),
default_scene: self.default_scene,
nodes: self.nodes.copy(),
animations: self.animations.copy(),
}
}
///|
/// Apply sampled animation channels to a copied scene. Unknown node ids and
/// unsupported/empty samples are ignored so malformed optional channels do
/// not invalidate an otherwise renderable scene.
pub fn Scene::apply_animation_samples(
self : Scene,
samples : Array[AnimationSample],
) -> Scene {
let result = self.copy()
for sample in samples {
let index = sample.node().value()
if index >= 0 && index < result.nodes.length() {
let node = result.nodes[index]
let transform = apply_animation_sample(
node.local_transform(),
sample.path(),
sample.value(),
)
result.nodes[index] = node.with_local_transform(transform)
}
}
result
}
///|
fn apply_animation_sample(
authored : Mat4,
path : AnimationPath,
values : Array[Double],
) -> Mat4 {
match path {
Translation if values.length() >= 3 => {
let matrix = authored.values()
matrix[3] = values[0]
matrix[7] = values[1]
matrix[11] = values[2]
Mat4::from_values(matrix)
}
Scale if values.length() >= 3 => {
let matrix = authored.values()
matrix[0] = values[0]
matrix[5] = values[1]
matrix[10] = values[2]
Mat4::from_values(matrix)
}
Rotation if values.length() >= 4 => {
let x = values[0]
let y = values[1]
let z = values[2]
let w = values[3]
let length = (x * x + y * y + z * z + w * w).sqrt()
let rotation = if length <= 1.0e-12 {
Quat::identity()
} else {
Quat::new(x=x / length, y=y / length, z=z / length, w=w / length)
}
let authored_values = authored.values()
let sx = (authored_values[0] * authored_values[0] +
authored_values[4] * authored_values[4] +
authored_values[8] * authored_values[8]).sqrt()
let sy = (authored_values[1] * authored_values[1] +
authored_values[5] * authored_values[5] +
authored_values[9] * authored_values[9]).sqrt()
let sz = (authored_values[2] * authored_values[2] +
authored_values[6] * authored_values[6] +
authored_values[10] * authored_values[10]).sqrt()
Mat4::translation(
Vec3::new(
x=authored_values[3],
y=authored_values[7],
z=authored_values[11],
),
)
.mul(rotation.to_mat4())
.mul(
Mat4::from_values([
sx, 0.0, 0.0, 0.0, 0.0, sy, 0.0, 0.0, 0.0, 0.0, sz, 0.0, 0.0, 0.0, 0.0,
1.0,
]),
)
}
_ => authored
}
}
///|
pub fn Scene::animations(self : Scene) -> Array[AnimationClip] {
self.animations.copy()
}
///|
pub fn Scene::add_animation(self : Scene, animation : AnimationClip) -> Int {
let index = self.animations.length()
self.animations.push(animation)
index
}
///|
pub fn Scene::add_mesh(self : Scene, mesh : Mesh) -> MeshId {
let id = MeshId::new(self.meshes.length())
self.meshes.push(mesh)
id
}
///|
pub fn Scene::add_material(self : Scene, material : Material) -> MaterialId {
let id = MaterialId::new(self.materials.length())
self.materials.push(material)
id
}
///|
pub fn Scene::add_texture(self : Scene, texture : Texture) -> TextureId {
let id = TextureId::new(self.textures.length())
self.textures.push(texture)
id
}
///|
pub fn Scene::samplers(self : Scene) -> Array[Sampler] {
self.samplers.copy()
}
///|
pub fn Scene::add_sampler(self : Scene, sampler : Sampler) -> SamplerId {
let id = SamplerId::new(self.samplers.length())
self.samplers.push(sampler)
id
}
///|
pub fn Scene::cameras(self : Scene) -> Array[Camera] {
self.cameras.copy()
}
///|
pub fn Scene::add_camera(self : Scene, camera : Camera) -> Int {
let index = self.cameras.length()
self.cameras.push(camera)
index
}
///|
pub fn Scene::scene_definitions(self : Scene) -> Array[SceneDefinition] {
self.definitions.copy()
}
///|
pub fn Scene::add_scene_definition(
self : Scene,
definition : SceneDefinition,
) -> Int {
let index = self.definitions.length()
self.definitions.push(definition)
index
}
///|
pub fn Scene::skins(self : Scene) -> Array[Skin] {
self.skins.copy()
}
///|
pub fn Scene::add_skin(self : Scene, skin : Skin) -> Int {
let index = self.skins.length()
self.skins.push(skin)
index
}
///|
pub fn Scene::default_scene(self : Scene) -> Int? {
self.default_scene
}
///|
pub fn Scene::set_default_scene(self : Scene, index : Int?) -> Unit {
self.default_scene = index
}
///|
pub fn Scene::add_node(self : Scene, node : Node) -> NodeId {
let id = NodeId::new(self.nodes.length())
self.nodes.push(node)
match node.parent {
Some(parent) =>
if parent.value >= 0 && parent.value < self.nodes.length() {
let parent_node = self.nodes[parent.value]
self.nodes[parent.value] = parent_node.with_child(id)
}
None => ()
}
// glTF permits a child to appear before its parent in the nodes array.
// Back-link those already-added children when their parent arrives.
let mut child_index = 0
while child_index < self.nodes.length() - 1 {
match self.nodes[child_index].parent {
Some(parent) =>
if parent == id {
let parent_node = self.nodes[id.value]
if !parent_node.children.contains(NodeId::new(child_index)) {
self.nodes[id.value] = parent_node.with_child(
NodeId::new(child_index),
)
}
}
None => ()
}
child_index = child_index + 1
}
id
}
///|
pub fn Scene::mesh(self : Scene, id : MeshId) -> Mesh? {
if id.value < 0 || id.value >= self.meshes.length() {
None
} else {
Some(self.meshes[id.value])
}
}
///|
pub fn Scene::node(self : Scene, id : NodeId) -> Node? {
if id.value < 0 || id.value >= self.nodes.length() {
None
} else {
Some(self.nodes[id.value])
}
}
///|
pub fn Scene::world_transform(self : Scene, id : NodeId) -> Mat4 {
match self.node(id) {
None => Mat4::identity()
Some(node) =>
match node.parent {
None => node.local_transform
Some(parent) => self.world_transform(parent).mul(node.local_transform)
}
}
}
///|
pub fn Scene::bounds(self : Scene) -> Aabb {
let mut result = Aabb::empty()
for index, node in self.nodes {
match node.mesh {
None => ()
Some(mesh_id) =>
match self.mesh(mesh_id) {
None => ()
Some(mesh) => {
let node_id = NodeId::new(index)
result = result.union(
mesh.bounds.transformed(self.world_transform(node_id)),
)
}
}
}
}
result
}
///|
pub fn Scene::pick(self : Scene, ray : Ray) -> PickHit? {
let mut best : PickHit? = None
for node_index, node in self.nodes {
match node.mesh {
None => ()
Some(mesh_id) =>
match self.mesh(mesh_id) {
None => ()
Some(mesh) => {
let node_id = NodeId::new(node_index)
let transform = self.world_transform(node_id)
let world_bounds = mesh.bounds.transformed(transform)
if ray.intersect_aabb(world_bounds) {
for primitive_index, primitive in mesh.primitives {
let indices = primitive.indices
let vertices = primitive.vertices
let mut index = 0
while index + 2 < indices.length() {
let first = indices[index]
let second = indices[index + 1]
let third = indices[index + 2]
if first >= 0 &&
second >= 0 &&
third >= 0 &&
first < vertices.length() &&
second < vertices.length() &&
third < vertices.length() {
let a = transform.transform_point(vertices[first].position)
let b = transform.transform_point(vertices[second].position)
let c = transform.transform_point(vertices[third].position)
match ray.intersect_triangle(a, b, c) {
None => ()
Some(distance) =>
match best {
None =>
best = Some({
node: node_id,
primitive_index,
distance,
position: ray.at(distance),
})
Some(previous) =>
if distance < previous.distance {
best = Some({
node: node_id,
primitive_index,
distance,
position: ray.at(distance),
})
}
}
}
}
index = index + 3
}
}
}
}
}
}
}
best
}
///|
fn clamp01(value : Double) -> Double {
if value < 0.0 {
0.0
} else if value > 1.0 {
1.0
} else {
value
}
}
///|
fn clamp_min(value : Double, minimum : Double) -> Double {
if value < minimum {
minimum
} else {
value
}
}