Source: TestObjects.js

/*jshint esversion: 6 */
// @ts-check

/**
 * CS559 3D World Framework Code
 * 
 * Test Objects - these examples are for use in testing the framework
 * and are less generally useful
 *  
 */

 /** @module TestObjects */

// we need to have the BaseClass definition
import { GrObject } from "./GrObject.js";

// a global variable to keep track of how many objects we create
// this allows us to give unique names
let testobjsctr = 0;

// these four lines fake out TypeScript into thinking that THREE
// has the same type as the T.js module, so things work for type checking
// type inferencing figures out that THREE has the same type as T
// and then I have to use T (not THREE) to avoid the "UMD Module" warning
/**  @type typeof import("./../THREE/threets/index"); */
let T;
// @ts-ignore
T = THREE;

function degreesToRadians(deg) {
    return deg * Math.PI / 180;
}

/**
 * A simple object that is like a dump truck (with a hinge), but just made of 
 * boxes.
 * A simple way to test a parametric object
 */
export class HingeCube extends GrObject {
    constructor() {
        let group = new T.Group();
        let box = new T.BoxGeometry(1,0.5,1);
        let mesh1 = new T.Mesh(box,new T.MeshStandardMaterial({color:0xA0A000}));
        mesh1.position.y = 0.25;
        group.add(mesh1);

        let mesh2 = new T.Mesh(box,new T.MeshStandardMaterial({color:0xFFFF00}));
        // set group with origin at pivot point
        let g2 = new T.Group();
        g2.position.set(0,0.5,-0.5);
        g2.add(mesh2);
        mesh2.position.y = 0.25;
        mesh2.position.z = 0.5;
        group.add(g2);

        super(`DumpCube-${testobjsctr++}`,group,
              [ ['x',-5,5,2],['z',-5,5,2],['theta',-180,180,0],
                ['tilt',0,90,0]
              ]);
        
        this.group = group;
        this.mesh1 = mesh1;
        this.mesh2 = mesh2;
        this.g2 = g2;
    }

    update(paramValues) {
        this.group.position.x = paramValues[0];
        this.group.position.z = paramValues[1];
        this.group.rotation.y = degreesToRadians(paramValues[2]);
        this.g2.rotation.x = degreesToRadians(-paramValues[3]);
    }
}


// for faking deferred loading
// from https://flaviocopes.com/javascript-sleep/
const sleep = (milliseconds) => {
    return new Promise(resolve => setTimeout(resolve, milliseconds));
};

/**
 * test for an object that is created slowly (like loading an OBJ)
 * 
 * the catch is that we need to have an object to install in the world
 * (since we can't defer that), but we don't have "the" object
 * 
 * the trick: make a Group - when the deferred object finally arrives,
 * stick it in the group
 * 
 * here, we fake OBJ loading with sleep
 */
export class DelayTest extends GrObject {
    constructor() {
        let group = new T.Group();
        super("Delay-Test", group);
        this.group = group;
        // use sleep, rather than OBJ loader
        sleep(1500).then(function() {
            group.add(new T.Mesh(new T.TorusKnotGeometry(), new T.MeshStandardMaterial({color:"red"})));
        });
    }
}
  
/**
 * Better delayed object - put a proxy object in its place, and then remove it
 */
export class BetterDelayTest extends GrObject {
    constructor() {
        let group = new T.Group();
        super("Delay-Test", group);
        this.group = group;
        // make a cube that will be there temporarily
        let tempCube = new T.Mesh(new T.BoxGeometry(), new T.MeshStandardMaterial());
        group.add(tempCube);
        // use sleep, rather than OBJ loader
        sleep(2000).then(function() {
            group.remove(tempCube);
            group.add(new T.Mesh(new T.TorusKnotGeometry(), new T.MeshStandardMaterial({color:"purple"})));
        });
    }
}

/**
 * test for changing an object's material
 */
export class MaterialDelayTest extends GrObject {
    constructor() {
        let group = new T.Group();
        super("Delay-Test", group);
        this.material = new T.MeshStandardMaterial({color:"white"});
        this.geometry = new T.TorusGeometry();
        this.mesh = new T.Mesh(this.geometry,this.material);
        let self=this;
        group.add(this.mesh);
        group.position.x = -3;
        // use sleep, rather than OBJ loader
        sleep(1000).then(function() {
            // note: we can't use "this" because this isn't lexically scoped
            self.material.setValues({color:"red"});
            self.material.needsUpdate = true;
        });
    }
}