Source: primitives/geometry.js

import * as THREE from 'three/webgpu';
import { toBufferGeometry } from '../utilities';
import { applyMorphColorNode } from '../tsl/morphColorMaterial';
import { ZincObject } from './zincObject';

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) {
    if (materialIn) {
      material = materialIn;
    } else {
      material = new THREE.MeshPhongMaterial({
        color: options.colour,
        vertexColors: false,
        transparent: isTransparent,
        opacity: options.opacity,
        side: THREE.DoubleSide,
      });
    }
    if (options.localMorphColour && geometry.morphAttributes['color']) {
      //Force vertexColors off (even if materialIn already had it true) -
      //NodeMaterial would otherwise multiply our morph colour blend by
      //the static, non-morph 'color' attribute (vertexColor() in
      //setupDiffuseColor), which zeroes out whatever channel that static
      //colour never needed (e.g. blue on an originally pure-red vertex),
      //turning parts of the blend black instead of the intended hue.
      //applyMorphColorNode's colorNode fully replaces vertex colouring.
      material.vertexColors = false;
      material = applyMorphColorNode(material);
    }
  } else {
    let videoTexture = geometry._video.createCanvasVideoTexture();
    material = new THREE.MeshBasicMaterial({
      color: new THREE.Color(1, 1, 1),
      transparent: isTransparent,
      opacity: options.opacity,
      map: videoTexture,
      side: THREE.DoubleSide,
    });
  }
  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 () {
  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.videoHandler = mesh.geometry._video;
    this.setMesh(mesh, options.localTimeEnabled, options.localMorphColour);
  };

  /**
   * 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.requestRender();
    this.morph.material.wireframe = wireframe;
  };

  /**
   * Edit Vertice in index.
   */
  this.editVertices = function (coords, i) {
    this.requestRender();
    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;
      }
    }
  };

  /**
   * Check if the geometry is time varying.
   *
   * @return {Boolean}
   */
  this.isTimeVarying = function () {
    if (this.timeEnabled || this.morphColour || this.videoHandler) return true;
    return false;
  };
};

Geometry.prototype = Object.create(ZincObject.prototype);
export { Geometry };