Source: primitives/geometry.js

const THREE = require('three');
const toBufferGeometry = require('../utilities').toBufferGeometry;

const createMeshForGeometry =  (geometryIn, materialIn, options) => {
  // First copy the geometry
  let geometry = toBufferGeometry(geometryIn, options);

  let isTransparent = false;
  if (1.0 > options.opacity)
      isTransparent = true;

  let material = undefined;
  if (geometry._video === undefined) {
    const morphTargets = options.localTimeEnabled || options.localMorphColour;
    if (materialIn) {
      material = materialIn;
      material.morphTargets = morphTargets;
      material.morphNormals = options.localTimeEnabled;
    } else {
      if (geometry instanceof THREE.BufferGeometry && geometry.attributes.color === undefined) {
        material = new THREE.MeshPhongMaterial({
          color : options.colour,
          morphTargets : morphTargets,
          morphNormals : options.localTimeEnabled,
          transparent : isTransparent,
          opacity : options.opacity,
          side : THREE.DoubleSide
        });
      } else {
        material = new THREE.MeshPhongMaterial({
          color : options.colour,
          morphTargets : morphTargets,
          morphNormals : options.localTimeEnabled,
          vertexColors : THREE.VertexColors,
          transparent : isTransparent,
          opacity : options.opacity,
          side : THREE.DoubleSide
        });
      }
    }
    //material = PhongToToon(material);
    if (options.localMorphColour && geometry.morphAttributes[ "color" ]) {
      material.onBeforeCompile = (require("./augmentShader").augmentMorphColor)();
    }
  } else {
    let videoTexture = geometry._video.createCanvasVideoTexture();
    material = new THREE.MeshBasicMaterial({
      morphTargets : options.localTimeEnabled,
      color : new THREE.Color(1, 1, 1),
      transparent : isTransparent,
      opacity : options.opacity,
      map : videoTexture,
      side : THREE.DoubleSide
    });
    this.videoHandler = geometry._video;
  }
  return new THREE.Mesh(geometry, material); 
}

/**
 * Provides an object which stores geometry and provides method which controls its animations.
 * This is created when a valid json file containging geometry is read into a {@link Zinc.Scene}
 * object.
 * 
 * @class
 * @author Alan Wu
 * @return {Geometry}
 */
const Geometry = function () {
  (require('./zincObject').ZincObject).call(this);
	// THREE.Geometry or THREE.BufferGeometry
	this.videoHandler = undefined;
  this.isGeometry = true;

  /**
   * Create the mesh for rendering
   * 
   * @param {THREE.Geomtry} geometryIn - Geometry to be rendered.
   * @param {THREE.Material} materialIn - Material to be set for the geometry.
   * @param {Object} options - Provide various options
   * @param {THREE.Color}  options.colour - colour to be set for the geometry
   * @param {Boolean} options.localTimeEnabled - A flag to indicate either the geometry is
   * time dependent.
   * @param {Boolean} options.localMorphColour - A flag to indicate either the colour is
   * time dependent.
   * @param {Number} options.opacity - Opacity to be set for the geometry
   */
	this.createMesh = (geometryIn, materialIn, options) => {
    //Skip if there is a morph already
		if (this.morph && this.morph.geometry && (geometryIn != undefined))
			return;
		const mesh = createMeshForGeometry(geometryIn, materialIn, options); 
		this.setMesh(mesh, options.localTimeEnabled, options.localMorphColour);
	}

  /**
   * Calculate the UV for texture rendering.
   */
	this.calculateUVs = () => {
    //Multilayers
		this.geometry.computeBoundingBox();
		const max = this.geometry.boundingBox.max, min = this.geometry.boundingBox.min;
		const offset = new THREE.Vector2(0 - min.x, 0 - min.y);
		const range = new THREE.Vector2(max.x - min.x, max.y - min.y);
		this.geometry.faceVertexUvs[0] = [];
		for (let i = 0; i < this.geometry.faces.length ; i++) {
		    const v1 = this.geometry.vertices[this.geometry.faces[i].a];
		    const v2 = this.geometry.vertices[this.geometry.faces[i].b];
		    const v3 = this.geometry.vertices[this.geometry.faces[i].c];
		    geometry.faceVertexUvs[0].push(
		        [
		            new THREE.Vector2((v1.x + offset.x)/range.x ,(v1.y + offset.y)/range.y),
		            new THREE.Vector2((v2.x + offset.x)/range.x ,(v2.y + offset.y)/range.y),
		            new THREE.Vector2((v3.x + offset.x)/range.x ,(v3.y + offset.y)/range.y)
		        ]);
		}
		geometry.uvsNeedUpdate = true;	
	}

  /**
   * Handle transparent mesh, create a clone for backside rendering if it is
   * transparent.
   */
  this.checkTransparentMesh = function() {
    this._lod.checkTransparentMesh();
  }
	
	/**
	 * Set wireframe display for this geometry.
	 * 
	 * @param {Boolean} wireframe - Flag to turn on/off wireframe display.
	 */
	this.setWireframe = wireframe => {
		this.morph.material.wireframe = wireframe;
	}

  /**
   * Edit Vertice in index.
   */
  this.editVertices = function(coords, i) {
    if (coords && coords.length) {
      let mesh = this.getMorph();
      const attribute = mesh.geometry.getAttribute("position");
      if (!mesh || 0 > i) {
        return;
      } else {
        let index = i * 3;
        coords.forEach(coord => {
          attribute.array[index++] = coord[0];
          attribute.array[index++] = coord[1];
          attribute.array[index++] = coord[2];
        });
        attribute.needsUpdate = true;
        mesh.geometry.computeBoundingBox();
        mesh.geometry.computeBoundingSphere();
        this.boundingBoxUpdateRequired = true;
      }
    }
  }
	

}

Geometry.prototype = Object.create((require('./zincObject').ZincObject).prototype);
exports.Geometry = Geometry;