File SceneNode.cs

File List > Render > src > SceneNode.cs

Go to the documentation of this file.

using System;
using System.Collections;
using System.Collections.Generic;
using Qkmaxware.Geometry;

namespace Qkmaxware.Rendering {

public class SceneNode : IEnumerable<SceneNode> {
    public Scene? Scene => (Parent != null) ? Parent.Scene : this.root_scene;

    // Use this to hide the property from doxygen
    internal Scene? root_scene = null;
    public SceneNode? Parent {get; private set;} = null;
    public Transformation Transform = Transformation.Identity();
    public Vec3 Position => LocalToWorldMatrix * Vec3.Zero;
    public Vec3 Forward => LocalToWorldMatrix * Vec3.J;
    public Vec3 Backward => -Forward;
    public Vec3 Up => LocalToWorldMatrix * Vec3.K;
    public Vec3 Down => -Up;
    public Vec3 Left => -Right;
    public Vec3 Right => LocalToWorldMatrix * Vec3.I;

    public Transformation LocalToWorldMatrix => (Parent != null) ? Parent.LocalToWorldMatrix * this.Transform : this.Transform;

    public Transformation WorldToLocalMatrix => LocalToWorldMatrix.Inverse;

    private List<SceneNode> children = new List<SceneNode>();

    public IEnumerable<SceneNode> Children => children.AsReadOnly();

    public void Add(SceneNode node) {
        // Remove from old parent
        node.Parent?.Remove(node);
        // Add to new parent
        this.children.Add(node);
        node.Parent = this;
    }

    public void Remove(SceneNode node) {
        if (this.children.Remove(node)) {
            node.Parent = null;
        }
    }

    public void Detach() {
        this.Parent?.Remove(this);
    }

    public IEnumerator<SceneNode> GetEnumerator() {
        foreach (var child in children) {
            yield return child;
            foreach (var subchild in child) {
                yield return subchild;
            }
        }
    }

    IEnumerator IEnumerable.GetEnumerator() {
        return GetEnumerator();
    }

    public void Rotate(Vec3 axis, double angle) {
        var norm = axis.Normalized;
        double c = Math.Cos(angle);
        double s = Math.Sin(angle);
        double t = 1.0 - c;
        double x = norm.X;
        double y = norm.Y;
        double z = norm.Z;

        var rotation = new Transformation(
            t * x * x + c,          t * x * y - z * s,      t * x * z + y * s,      0,
            t * x * y + z * s,      t * y * y + c,          t * y * z - x * s,      0,
            t * x * z - y * s,      t * y * z + x * s,      t * z * z + c,          0
        );

        this.Transform = rotation * this.Transform;
    }

    public void RotateAround(Vec3 point, Vec3 axis, double angle) {
        var norm = axis.Normalized;
        double c = Math.Cos(angle);
        double s = Math.Sin(angle);
        double t = 1.0 - c;
        double x = norm.X;
        double y = norm.Y;
        double z = norm.Z;

        var rotation = new Transformation(
            t * x * x + c,          t * x * y - z * s,      t * x * z + y * s,      0,
            t * x * y + z * s,      t * y * y + c,          t * y * z - x * s,      0,
            t * x * z - y * s,      t * y * z + x * s,      t * z * z + c,          0
        );

        this.Transform = (Transformation.Offset(point) * rotation * Transformation.Offset(-point)) * this.Transform;
    }

    public void Move(Vec3 delta) {
        this.Transform = Transformation.Offset(delta) * this.Transform;
    }
}

}