/**
 * Sigma.js WebGL Renderer Node Program
 * =====================================
 *
 * Simple program rendering nodes as triangles.
 * It does not extend AbstractNodeProgram, which works very differently, and
 * really targets the gl.POINTS drawing methods.
 * @module
 */

import { floatColor } from "sigma/utils";
import { NodeProgram } from "sigma/rendering";

import VERTEX_SHADER_SOURCE from "./triangle-vert.glsl";
import FRAGMENT_SHADER_SOURCE from "./triangle-frag.glsl";

const { UNSIGNED_BYTE, FLOAT } = WebGLRenderingContext;

const UNIFORMS = ["u_sizeRatio", "u_correctionRatio", "u_matrix"];

export default class NodeTriangleProgram extends NodeProgram {
  static ANGLE_1 = - (0.5 * Math.PI) / 3;
  static ANGLE_2 =   (1.5 * Math.PI) / 3;
  static ANGLE_3 =   (3.5 * Math.PI) / 3;

  getDefinition() {
    return {
      VERTICES: 3,
      VERTEX_SHADER_SOURCE,
      FRAGMENT_SHADER_SOURCE,
      METHOD: WebGLRenderingContext.TRIANGLES,
      UNIFORMS,
      ATTRIBUTES: [
        { name: "a_position", size: 2, type: FLOAT },
        { name: "a_size", size: 1, type: FLOAT },
        { name: "a_color", size: 4, type: UNSIGNED_BYTE, normalized: true },
        { name: "a_id", size: 4, type: UNSIGNED_BYTE, normalized: true },
      ],
      CONSTANT_ATTRIBUTES: [{ name: "a_angle", size: 1, type: FLOAT }],
      CONSTANT_DATA: [[NodeTriangleProgram.ANGLE_1], [NodeTriangleProgram.ANGLE_2], [NodeTriangleProgram.ANGLE_3]],
    };
  }

  processVisibleItem(nodeIndex, startIndex, data) {
    const array = this.array;
    const color = floatColor(data.color);
    const size = data.size / 1.7;  // experimental...

    array[startIndex++] = data.x;
    array[startIndex++] = data.y;
    array[startIndex++] = size;
    array[startIndex++] = color;
    array[startIndex++] = nodeIndex;
  }

  setUniforms(params, { gl, uniformLocations }) {
    const { u_sizeRatio, u_correctionRatio, u_matrix } = uniformLocations;

    gl.uniform1f(u_correctionRatio, params.correctionRatio);
    gl.uniform1f(u_sizeRatio, params.sizeRatio);
    gl.uniformMatrix3fv(u_matrix, false, params.matrix);
  }
}
