function createPerspectiveMatrix(fFoVVy,     //Field of View vertical (Öffnungswinkel in Grad)
                                 fAspect,    // Bildhöhe zu Bildbreite
								 fZnear,     //Mindestabstand sichtbarer Punkte
								 fZfar)   {   //Höchstabstand sichtbarer Punkte

  return (Matrix.create([[fAspect/Math.tan(fFoVVy* Math.PI / 180.0), 0, 0, 0],
               [0, 1/Math.tan(fFoVVy* Math.PI / 180.0), 0, 0],
               [0, 0, (fZnear+fZfar)/(fZnear-fZfar), 2*fZnear*fZfar/(fZnear-fZfar)],
               [0, 0, -1, 0]]));
};

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//BEGINN Erweiterungen für sylvester.js 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//flatten konvertiert eine 2D-Matrix in ein 1D-Feld
Matrix.prototype.flatten = function () {

    var result = [];
    if (this.elements.length == 0)
        return [];


    for (var j = 0; j < this.elements[0].length; j++)
        for (var i = 0; i < this.elements.length; i++)
            result.push(this.elements[i][j]);
    return result;
};

Matrix.prototype.ensure4x4 = function(){

    if (this.elements.length == 4 &&
        this.elements[0].length == 4)
        return this;

    if (this.elements.length > 4 ||
        this.elements[0].length > 4)
        return null;

    for (var i = 0; i < this.elements.length; i++) 	{
	
        for (var j = this.elements[i].length; j < 4; j++) {
            if (i == j)
                this.elements[i].push(1);
            else
                this.elements[i].push(0);
        }
    }

    for (var i = this.elements.length; i < 4; i++) 	{
	
        if (i == 0)
            this.elements.push([1, 0, 0, 0]);
        else if (i == 1)
            this.elements.push([0, 1, 0, 0]);
        else if (i == 2)
            this.elements.push([0, 0, 1, 0]);
        else if (i == 3)
            this.elements.push([0, 0, 0, 1]);
    }

    return this;
};
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//ENDE Erweiterungen für sylvester.js 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/// Die Funktion initGL erkennt den Browser (derzeit webkit und Minefield)
  function initGL()  {
  
    var canvas = document.getElementById("WebGL-canvas"); //herkömmliche Javascript-Funktion um auf die Zeichenfläche zugreifen zu können.
    try    {
      gl = canvas.getContext("experimental-webgl");
    }  catch(e)  {  }
    if (!gl)    {
	
      try      {
	  
        gl = canvas.getContext("webkit-3d");
      }   catch(e)   {   }
    }
    if (!gl)    {
	
      try      {
	  
        gl = canvas.getContext("moz-webgl");
      }   catch(e)  {   }
    }
    if (!gl)    {
	
      alert("WebGL not found. Please check if your browser supports WebGL.");
    }
  }


//Die Funktion getShader durchsucht die Quelldatei (diese hier vor dir!) nach den Shader Scripten und
  // sorgt dafür, dass die Shader im WebGL-Kontext benutzt werden können.
  function getShader(gl, id)  {
  
      var shaderScript = document.getElementById(id); //die id ist ein String mit dem Namen des Script-Objektes, z.B. "shader-fs"
      if (!shaderScript)
          return null;

      var str = "";
      var k = shaderScript.firstChild;
      while (k)      {
	  
          if (k.nodeType == 3)
              str += k.textContent;
          k = k.nextSibling;
      }

      var shader;
      if (shaderScript.type == "x-shader/x-fragment")      {
	  
          shader = gl.createShader(gl.FRAGMENT_SHADER);
      }
      else if (shaderScript.type == "x-shader/x-vertex")      {
	  
          shader = gl.createShader(gl.VERTEX_SHADER);
      }
      else      {
	  
          return null;
      }

      gl.shaderSource(shader, str); //str enhält hier den kompletten Quellcode des Shaderscripts
      gl.compileShader(shader);     

      if (!gl.getShaderParameter(shader, gl.COMPILE_STATUS))      {
	  
          alert(gl.getShaderInfoLog(shader));
          return null;
      }

      return shader;
  }

  function initShaders()  {
  
    var fragmentShader = getShader(gl, "shader-fs");
    var vertexShader   = getShader(gl, "shader-vs");

    shaderProgram      = gl.createProgram();
    gl.attachShader(shaderProgram, vertexShader);
    gl.attachShader(shaderProgram, fragmentShader);
    gl.linkProgram(shaderProgram);

    if (!gl.getProgramParameter(shaderProgram, gl.LINK_STATUS))    {
	
      alert("Could not initialise shaders");
    }

    gl.useProgram(shaderProgram);

    vertexPositionAttribute = gl.getAttribLocation(shaderProgram, "aVertexPosition");
    gl.enableVertexAttribArray(vertexPositionAttribute);
	
    vertexColorAttribute = gl.getAttribLocation(shaderProgram, "aVertexColor");
    gl.enableVertexAttribArray(vertexColorAttribute);
 
  }

  function setMatrixUniforms()  {
  
    var pUniform = gl.getUniformLocation(shaderProgram, "uPMatrix");
    gl.uniformMatrix4fv(pUniform, false, new Float32Array(pMatrix.flatten()));
	
	var mvUniform = gl.getUniformLocation(shaderProgram, "uMVMatrix");
    gl.uniformMatrix4fv(mvUniform, false, new Float32Array(mvMatrix.flatten()));
	
	 
  }

//function create3DTranslationMatrix(v) konvertiert einen Vektor in eine Translationsmatrix
function create3DTranslationMatrix(v) {

  if(v.elements.length != 3)  {
  
    throw "Invalid vector length";
  }
  var Mtrans = Matrix.I(4); //Einheitsmatrix anlegen
  Mtrans.elements[0][3] = v.elements[0];
  Mtrans.elements[1][3] = v.elements[1];
  Mtrans.elements[2][3] = v.elements[2];
  return(Mtrans);
};//function create3DTranslationMatrix(v)
  

  






