{"size": 15497, "ext": "js", "max_stars_repo_path": "src/main/misc/equatorie-src/lib/coffeegl/shader.js", "max_stars_repo_name": "UoMLibrary/cudl-viewer", "max_stars_repo_stars_event_min_datetime": "2021-03-09T12:51:36.000Z", "max_stars_repo_stars_event_max_datetime": "2021-03-09T12:51:36.000Z", "max_issues_repo_path": "src/main/misc/equatorie-src/lib/coffeegl/shader.js", "max_issues_repo_name": "UoMLibrary/cudl-viewer", "max_issues_repo_issues_event_min_datetime": "2021-04-14T06:29:09.000Z", "max_issues_repo_issues_event_max_datetime": "2021-04-14T06:29:09.000Z", "max_forks_repo_path": "src/main/misc/equatorie-src/lib/coffeegl/shader.js", "max_forks_repo_name": "UoMLibrary/cudl-viewer", "max_forks_repo_forks_event_min_datetime": "2022-03-23T13:07:50.000Z", "max_forks_repo_forks_event_max_datetime": "2022-03-23T13:07:50.000Z"}
{"max_stars_count": 1, "max_issues_count": 1, "max_forks_count": 1, "avg_line_length": 31.1184738956, "max_line_length": 140, "alphanum_fraction": 0.5513970446}
// Generated by CoffeeScript 1.6.1

/* ABOUT
                       __  .__              ________ 
   ______ ____   _____/  |_|__| ____   ____/   __   \
  /  ___// __ \_/ ___\   __\  |/  _ \ /    \____    /
  \___ \\  ___/\  \___|  | |  (  <_> )   |  \ /    / 
 /____  >\___  >\___  >__| |__|\____/|___|  //____/  .co.uk
      \/     \/     \/                    \/         
                                              CoffeeGL
                                              Benjamin Blundell - ben@section9.co.uk
                                              http://www.section9.co.uk

This software is released under the MIT Licence. See LICENCE.txt for details



- TODO - Tighten up the contract
- TODO - Caching needs to go in here
*/


(function() {
  var CoffeeGLError, CoffeeGLLog, CoffeeGLWarning, Contract, Light, Matrix4, Shader, ShaderLibrary, Vec2, Vec3, Vec4, _ref, _ref1;

  _ref = require('./math'), Matrix4 = _ref.Matrix4, Vec2 = _ref.Vec2, Vec3 = _ref.Vec3, Vec4 = _ref.Vec4;

  Light = require('./light').Light;

  ShaderLibrary = require('./shader_library').ShaderLibrary;

  _ref1 = require('./error'), CoffeeGLError = _ref1.CoffeeGLError, CoffeeGLWarning = _ref1.CoffeeGLWarning, CoffeeGLLog = _ref1.CoffeeGLLog;

  /* Contract
  */


  Contract = (function() {

    function Contract(attributes, uniforms, textures) {
      this.attributes = attributes;
      this.uniforms = uniforms;
      this.textures = textures;
      if (this.attributes == null) {
        this.attributes = [];
      }
      if (this.uniforms == null) {
        this.uniforms = [];
      }
      if (this.textures == null) {
        this.textures = [];
      }
    }

    Contract.prototype.setUniformRole = function(uniform, role) {
      var u, _i, _len, _ref2;
      _ref2 = this.uniforms;
      for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
        u = _ref2[_i];
        if (u.name === uniform) {
          u.role = role;
        }
      }
      return this;
    };

    Contract.prototype.setAttributeRole = function(attribute, role) {
      var a, _i, _len, _ref2;
      _ref2 = this.attributes;
      for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
        a = _ref2[_i];
        if (a.name === attribute) {
          a.role = role;
        }
      }
      return this;
    };

    return Contract;

  })();

  /* Shader
  */


  Shader = (function() {

    function Shader(s, roles) {
      var gl, match, matches, type, _i, _j, _len, _len1;
      this._splitShader(s);
      if (this.sv == null) {
        CoffeeGLError("No Vertex Shader Provided");
        return;
      }
      if (this.sf == null) {
        CoffeeGLError("No Fragment Shader Provided");
        return;
      }
      if (CoffeeGL.Context == null) {
        CoffeeGLError("No Context for Shader Provided");
        return;
      }
      gl = CoffeeGL.Context.gl;
      matches = this.sv.match(/\{\{(ShaderLibrary\.[a-zA-Z]+)\}\}/g);
      if (matches != null) {
        for (_i = 0, _len = matches.length; _i < _len; _i++) {
          match = matches[_i];
          type = match.replace("}}", "").split(".")[1];
          if (ShaderLibrary[type] == null) {
            CoffeeGLError("Could not find " + type + "in Shader Library");
          } else {
            this.sv = this.sv.replace(match, ShaderLibrary[type].vertex);
          }
        }
      }
      matches = this.sf.match(/\{\{(ShaderLibrary\.[a-zA-Z]+)\}\}/g);
      if (matches != null) {
        for (_j = 0, _len1 = matches.length; _j < _len1; _j++) {
          match = matches[_j];
          type = match.replace("}}", "").split(".")[1];
          if (ShaderLibrary[type] == null) {
            CoffeeGLError("Could not find " + type + "in Shader Library");
          } else {
            this.sf = this.sf.replace(match, ShaderLibrary[type].fragment);
          }
        }
      }
      this.sv = this.sv.replace(/;(?! [a-zA-Z0-9])/g, ';\n');
      this.sv = this.sv.replace(/\{/g, '{\n');
      this.sv = this.sv.replace(/\}/g, '}\n');
      this.sf = this.sf.replace(/;(?! [a-zA-Z0-9])/g, ';\n');
      this.sf = this.sf.replace(/;(?! [a-zA-Z0-9])/g, ';\n');
      this.sf = this.sf.replace(/\{/g, '{\n');
      this.sf = this.sf.replace(/\}/g, '}\n');
      this.compile(roles);
    }

    Shader.prototype.compile = function(roles) {
      var attr, attrs, compilationLog, gl, idx, success, _i, _len;
      gl = CoffeeGL.Context.gl;
      this.vertexShader = gl.createShader(gl.VERTEX_SHADER);
      if (!this.vertexShader) {
        CoffeeGLError("No vertex shader object could be created");
      }
      this.fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
      if (!this.fragmentShader) {
        CoffeeGLError("No Fragment shader object could be created");
      }
      gl.shaderSource(this.vertexShader, this.sv);
      gl.compileShader(this.vertexShader);
      if (!gl.getShaderParameter(this.vertexShader, gl.COMPILE_STATUS)) {
        compilationLog = gl.getShaderInfoLog(this.vertexShader);
        CoffeeGLLog('Shader compiler log: ' + compilationLog);
        this._splitError(compilationLog, this.sv);
        CoffeeGLError("Could not compile vertex shader");
      }
      gl.shaderSource(this.fragmentShader, this.sf);
      gl.compileShader(this.fragmentShader);
      if (!gl.getShaderParameter(this.fragmentShader, gl.COMPILE_STATUS)) {
        compilationLog = gl.getShaderInfoLog(this.fragmentShader);
        CoffeeGLLog("Shader compiler log: " + compilationLog);
        this._splitError(compilationLog, this.sf);
        CoffeeGLError("Could not compile fragment shader");
      }
      this.shaderProgram = gl.createProgram();
      attrs = this._parseShader("attribute");
      idx = 0;
      for (_i = 0, _len = attrs.length; _i < _len; _i++) {
        attr = attrs[_i];
        gl.bindAttribLocation(this.shaderProgram, idx, attr.name);
        idx++;
      }
      gl.attachShader(this.shaderProgram, this.vertexShader);
      gl.attachShader(this.shaderProgram, this.fragmentShader);
      gl.linkProgram(this.shaderProgram);
      success = gl.getProgramParameter(this.shaderProgram, gl.LINK_STATUS);
      if (!success) {
        CoffeeGLWarning(gl.getProgramInfoLog(this.shaderProgram));
        CoffeeGLError("Failed to Link Shader");
      }
      this._makeContract(roles);
      return this;
    };

    Shader.prototype._addToNode = function(node) {
      node.shader = this;
      return this;
    };

    Shader.prototype._splitError = function(s, data) {
      var datalines, fileno, line, lineno, lines, match, message, _i, _len;
      lines = s.split('\n');
      for (_i = 0, _len = lines.length; _i < _len; _i++) {
        line = lines[_i];
        match = line.match(/ERROR: (\d+):(\d+): (.*)/);
        if (match) {
          fileno = parseInt(match[1], 10) - 1;
          lineno = parseInt(match[2], 10) - 1;
          message = match[3];
          datalines = data.split('\n');
          CoffeeGLLog("Shader Error Log: " + fileno + ", " + lineno + ", " + message + "," + datalines[lineno]);
        }
      }
      return this;
    };

    Shader.prototype._splitShader = function(s) {
      var pf, pv;
      pv = s.indexOf("##>VERTEX");
      pf = s.indexOf("##>FRAGMENT");
      if (pv < pf) {
        this.sv = s.slice(pv + 9, pf);
        this.sf = s.slice(pf + 11);
      } else {
        this.sf = s.slice(pf + 11, pv);
        this.sv = s.slice(pv + 9);
      }
      return this;
    };

    Shader.prototype._getLocation = function(name) {
      var gl;
      gl = CoffeeGL.Context.gl;
      return gl.getUniformLocation(this.shaderProgram, name);
    };

    Shader.prototype.bind = function() {
      var gl;
      gl = CoffeeGL.Context.gl;
      gl.useProgram(this.shaderProgram);
      CoffeeGL.Context.shader = this;
      return this;
    };

    Shader.prototype.unbind = function() {
      var gl;
      gl = CoffeeGL.Context.gl;
      gl.useProgram(null);
      return this;
    };

    Shader.prototype.washUp = function() {
      var gl;
      gl = CoffeeGL.Context.gl;
      gl.detachShader(this.shaderProgram, this.vertexShader);
      gl.detachShader(this.shaderProgram, this.fragmentShader);
      gl.deleteProgram(this.shaderProgram);
      gl.deleteShader(this.vertexShader);
      gl.deleteShader(this.fragmentShader);
      return this;
    };

    Shader.prototype._makeContract = function(user_roles) {
      var key, role, roles;
      this.contract = new Contract(this._getAttributes(), this._getUniforms(), this._getTextures());
      roles = {};
      roles.uModelMatrix = "_modelMatrix";
      roles.uProjectionMatrix = "_camera/p";
      roles.uCameraMatrix = "_camera/m";
      roles.uCameraInverseMatrix = "_camera/i";
      roles.uNormalMatrix = "_normalMatrix";
      roles.uMaterialAmbientColor = "_material/ambient";
      roles.uMaterialDiffuseColor = "_material/diffuse";
      roles.uMaterialSpecularColor = "_material/specular";
      roles.uMaterialShininess = "_material/shine";
      roles.uMaterialEmissiveColor = "_material/emissive";
      roles.uNumLights = "_numPointLightsGlobal";
      roles.uPointLightPos = "pointlight/pos";
      roles.uPointLightDiffuse = "pointlight/colour";
      roles.uPointLightSpecular = "pointlight/specular";
      roles.uPointLightAttenuation = "pointlight/attenuation";
      roles.aVertexPosition = "vertexPositionBuffer";
      roles.aVertexTexCoord = "vertexTextureBuffer";
      roles.aVertexNormal = "vertexNormalBuffer";
      roles.aVertexColour = "vertexColourBuffer";
      roles.aVertexTangent = "vertexTangentBuffer";
      roles.uCameraNear = "_camera/near";
      roles.uCameraFar = "_camera/far";
      if (user_roles != null) {
        for (key in user_roles) {
          roles[key] = user_roles[key];
        }
      }
      for (role in roles) {
        this.contract.setUniformRole(role, roles[role]);
        this.contract.setAttributeRole(role, roles[role]);
      }
      return this;
    };

    Shader.prototype._posForAttrRole = function(role) {
      var a, _i, _len, _ref2;
      _ref2 = this.contract.attributes;
      for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
        a = _ref2[_i];
        if (a.role === role) {
          return a.pos;
        }
      }
      return -1;
    };

    Shader.prototype._getAttributes = function() {
      var a, d, p, _i, _len;
      d = this._parseShader("attribute");
      for (_i = 0, _len = d.length; _i < _len; _i++) {
        a = d[_i];
        p = this.getAttribLocation(a.name);
        if ((p != null) && p !== -1) {
          a.pos = p;
        }
      }
      return d;
    };

    Shader.prototype._getUniforms = function() {
      var a, d, p, _i, _len;
      d = this._parseShader("uniform");
      for (_i = 0, _len = d.length; _i < _len; _i++) {
        a = d[_i];
        p = this._getLocation(a.name);
        if ((p != null) && p !== -1) {
          a.pos = p;
        }
      }
      return d;
    };

    Shader.prototype._getTextures = function() {
      var a, d, p, x, _i, _len;
      d = this._parseShader("uniform");
      x = [];
      for (_i = 0, _len = d.length; _i < _len; _i++) {
        a = d[_i];
        if (a.type === "sampler2D") {
          p = this._getLocation(a.name);
          if ((p != null) && p !== -1) {
            a.pos = p;
            x.push(a);
          }
        }
      }
      return x;
    };

    Shader.prototype._parseShader = function(token) {
      var attr, data, finals, l, lines, matches, re, t, tokens, _i, _j, _len, _len1;
      data = [];
      lines = this.sv.split(";").concat(this.sf.split(";"));
      for (_i = 0, _len = lines.length; _i < _len; _i++) {
        l = lines[_i];
        re = RegExp("\\b" + token + "\\b");
        if (l.match(re) != null) {
          tokens = l.split(" ");
          finals = [];
          for (_j = 0, _len1 = tokens.length; _j < _len1; _j++) {
            t = tokens[_j];
            t = t.replace(/\n/, "");
            t = t.replace(/\s/, "");
            if (t.length !== 0) {
              finals.push(t);
            }
          }
          finals.push(1);
          matches = finals[2].match(/\[([0-9]+)\]/);
          if (matches != null) {
            finals[3] = matches[1];
          }
          finals[2] = finals[2].match(/([a-zA-Z]+)/g)[0];
          if (finals.length === 4) {
            attr = {};
            attr.name = finals[2];
            attr.type = finals[1];
            attr.role = attr.name;
            attr.pos = -1;
            attr.size = finals[3];
            data.push(attr);
          }
        }
      }
      return data;
    };

    Shader.prototype.setUniform3f = function(name, a, b, c) {
      var gl;
      if ((a == null) || (b == null) || (c == null)) {
        CoffeeGLWarning("Not enough parameters to setUniform3f");
      }
      gl = CoffeeGL.Context.gl;
      gl.uniform3f(this._getLocation(name), a, b, c);
      return this;
    };

    Shader.prototype.setUniform3v = function(name, v) {
      var a, gl;
      gl = CoffeeGL.Context.gl;
      a = v.flatten();
      gl.uniform3f(this._getLocation(name), a[0], a[1], a[2]);
      return this;
    };

    Shader.prototype.setUniform4f = function(name, a, b, c, d) {
      var gl;
      gl = CoffeeGL.Context.gl;
      gl.uniform4f(this._getLocation(name), a, b, c, d);
      return this;
    };

    Shader.prototype.setUniform4v = function(name, v) {
      var a, gl;
      gl = CoffeeGL.Context.gl;
      a = v.flatten();
      gl.uniform4f(this._getLocation(name), a[0], a[1], a[2], a[3]);
      return this;
    };

    Shader.prototype.setUniform1f = function(name, a) {
      var gl;
      gl = CoffeeGL.Context.gl;
      gl.uniform1f(this._getLocation(name), a);
      return this;
    };

    Shader.prototype.setUniform1i = function(name, a) {
      var gl;
      gl = CoffeeGL.Context.gl;
      gl.uniform1i(this._getLocation(name), a);
      return this;
    };

    Shader.prototype.setUniform1fv = function(name, a) {
      var gl;
      gl = CoffeeGL.Context.gl;
      gl.uniform1fv(this._getLocation(name), a);
      return this;
    };

    Shader.prototype.setUniform2fv = function(name, a) {
      var gl;
      gl = CoffeeGL.Context.gl;
      gl.uniform2fv(this._getLocation(name), a);
      return this;
    };

    Shader.prototype.setUniform2v = function(name, v) {
      var a, gl;
      gl = CoffeeGL.Context.gl;
      a = v.flatten();
      gl.uniform3f(this._getLocation(name), a[0], a[1]);
      return this;
    };

    Shader.prototype.setUniform3fv = function(name, a) {
      var gl;
      gl = CoffeeGL.Context.gl;
      gl.uniform3fv(this._getLocation(name), a);
      return this;
    };

    Shader.prototype.setUniform4fv = function(name, a) {
      var gl;
      gl = CoffeeGL.Context.gl;
      gl.uniform4fv(this._getLocation(name), a);
      return this;
    };

    Shader.prototype.setMatrix4f = function(name, m) {
      var gl;
      gl = CoffeeGL.Context.gl;
      gl.uniformMatrix4fv(this._getLocation(name), false, m.a);
      return this;
    };

    Shader.prototype.enableAttribArray = function(name) {
      var gl, position;
      gl = CoffeeGL.Context.gl;
      position = gl.getAttribLocation(this.shaderProgram, name);
      gl.enableVertexAttribArray(position);
      return this;
    };

    Shader.prototype.getAttribLocation = function(name) {
      var gl;
      gl = CoffeeGL.Context.gl;
      return gl.getAttribLocation(this.shaderProgram, name);
    };

    return Shader;

  })();

  module.exports = {
    Shader: Shader
  };

}).call(this);
