import { CoreMapboxTransform } from "../../../../core/mapbox/Transform";
import { WebGLRenderer } from "three/src/renderers/WebGLRenderer";
import { Vector3 } from "three/src/math/Vector3";
import { Matrix4 } from "three/src/math/Matrix4";
import mapboxgl from "mapbox-gl";
import { Mesh } from "three/src/objects/Mesh";
import { PlaneBufferGeometry } from "three/src/geometries/PlaneGeometry";
import { Clock } from "three/src/core/Clock";
const ID = "threejs_layer";
export class ThreejsLayer {
  constructor(_camera_node, _display_scene, _viewer) {
    this._camera_node = _camera_node;
    this._display_scene = _display_scene;
    this._viewer = _viewer;
    this.id = ID;
    this.type = "custom";
    this.renderingMode = "3d";
    this._clock = new Clock();
    this._delta = 0;
    this._vX = new Vector3(1, 0, 0);
    this._vY = new Vector3(0, 1, 0);
    this._vZ = new Vector3(0, 0, 1);
    this.mRX = new Matrix4();
    this.mRY = new Matrix4();
    this.mRZ = new Matrix4();
    this.s = new Vector3();
    this.m = new Matrix4();
    this.l = new Matrix4();
    this._camera = this._camera_node.object;
    this._scene = this._camera_node.scene();
  }
  onAdd(map, gl) {
    this._map = map;
    this._gl = gl;
    this.createRenderer();
  }
  onRemove() {
    var _a;
    (_a = this._renderer) == null ? void 0 : _a.dispose();
  }
  createRenderer() {
    if (this._renderer != null) {
      this._renderer.dispose();
    }
    if (!this._map) {
      console.error("no map given");
      return;
    }
    if (!this._gl) {
      console.error("no gl context given");
      return;
    }
    this._renderer = new WebGLRenderer({
      canvas: this._map.getCanvas(),
      context: this._gl
    });
    this._renderer.autoClear = false;
    this._renderer.shadowMap.enabled = true;
    this._hack();
  }
  resize() {
    this.createRenderer();
  }
  async render(gl, matrix) {
    if (!this._renderer || !this._map) {
      return;
    }
    const delta = this._clock.getDelta();
    this._delta = delta;
    this._scene.timeController.incrementTimeIfPlaying(this._delta);
    this._updateCameraMatrix(matrix);
    this._renderer.state.reset();
    this._renderer.render(this._display_scene, this._camera);
    this._map.triggerRepaint();
  }
  _updateCameraMatrix(matrix) {
    const lng_lat = this._viewer.cameraLngLat();
    if (!lng_lat) {
      return;
    }
    const mercator = mapboxgl.MercatorCoordinate.fromLngLat([lng_lat.lng, lng_lat.lat], 0);
    const transform = {
      position: mercator,
      rotation: { x: Math.PI / 2, y: 0, z: 0 },
      scale: CoreMapboxTransform.WORLD_SCALE
    };
    this.mRX.identity();
    this.mRY.identity();
    this.mRZ.identity();
    const rotationX = this.mRX.makeRotationAxis(this._vX, transform.rotation.x);
    const rotationY = this.mRY.makeRotationAxis(this._vY, transform.rotation.y);
    const rotationZ = this.mRZ.makeRotationAxis(this._vZ, transform.rotation.z);
    this.s.x = transform.scale;
    this.s.y = -transform.scale;
    this.s.z = transform.scale;
    this.m.fromArray(matrix);
    this.l.identity();
    this.l.makeTranslation(1 * transform.position.x, 1 * transform.position.y, 1 * (transform.position.z || 0)).scale(this.s).multiply(rotationX).multiply(rotationY).multiply(rotationZ);
    this._camera.projectionMatrix.elements = matrix;
    this._camera.projectionMatrix = this.m.multiply(this.l);
  }
  _hack() {
    const hackObject = new Mesh(new PlaneBufferGeometry());
    hackObject.frustumCulled = false;
    hackObject.position.z = -1e3;
    hackObject.scale.set(0.01, 0.01, 0.01);
    const scene = this._scene.threejsScene();
    scene.add(hackObject);
  }
}
