/**
 * 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 NodeSquareProgram extends NodeProgram {
  static ANGLE_1_1 = - (1 * Math.PI) / 4;
  static ANGLE_1_2 =   (1 * Math.PI) / 4;
  static ANGLE_1_3 =   (3 * Math.PI) / 4;
  static ANGLE_2_1 =   (3 * Math.PI) / 4;
  static ANGLE_2_2 =   (5 * Math.PI) / 4;
  static ANGLE_2_3 =   (7 * Math.PI) / 4;


  getDefinition() {
    return {
      VERTICES: 6,
      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: [[NodeSquareProgram.ANGLE_1_1], [NodeSquareProgram.ANGLE_1_2], [NodeSquareProgram.ANGLE_1_3]
                     ,[NodeSquareProgram.ANGLE_2_1], [NodeSquareProgram.ANGLE_2_2], [NodeSquareProgram.ANGLE_2_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);
  }
}
