//function createPerspectiveMatrix(fFoVVy,  ... ) Erzeugt aus den übergebenen Blickfeldparametern eine Perspektivmatrix (Pyramidenstumpf)
function createPerspectiveMatrix(fFoVVy,     //Field of View vertical (halber Öffnungswinkel in Grad)
                                 fAspect,    // Bildhöhe zu Bildbreite
								 fZnear,     //Mindestabstand sichtbarer Punkte
								 fZfar)      //Höchstabstand sichtbarer Punkte
{
  var fYmaxTop    = fZnear * Math.tan(fFoVVy * Math.PI / 360.0); //Maximaler Y-Wert nach über Tangens des Öffnungswinkels
  var fYminBottom = -fYmaxTop;
  var fXminLeft   = fYminBottom * fAspect;
  var fXmaxRight  = fYmaxTop * fAspect;
  
  // Dies Perspektivmatrix wird wie folgt berechnet:
  //  ______________________________________________________________
  //  (     2*fZnear                                                )
  //  ( X=----------------------      0               A       0     ) 
  //  (   fXmaxRight - fXminLeft                                    )
  //  (                                                             )
  //  (                                                             )
  //  (                        2*fZnear                             )
  //  (            0   Y=-----------------------      B       0     )
  //  (                  fYmaxTop - fYminBottom                     )
  //  (                                                             )
  //  (                                                             )
  //  (            0                0                 C       D     )
  //  (                                                             )
  //  (                                                             )
  //  (            0                0                -1      0      )
  //  (                                                             )
  //  _____________________________________________________________
  //  mit          fXmaxRight + fXminLeft
  //          A = ------------------------  
  //               fXmaxRight - fXminLeft
  
  //  mit          fYmaxTop  + fYminBottom
  //          B = ------------------------  
  //               fYmaxTop  - fYminBottom
  
  //  mit          fZfar + fZnear
  //          C = ------------------------  
  //               fZfar - fZnear
  
  //  mit          2*fZfar * fXminLeft
  //          D = ------------------------  
  //               fZfar - fZnear
  
  
  var X = 2*fZnear/(fXmaxRight-fXminLeft);
  var Y = 2*fZnear/(fYmaxTop-fYminBottom);
  var A = (fXmaxRight+fXminLeft)/(fXmaxRight-fXminLeft);
  var B = (fYmaxTop+fYminBottom)/(fYmaxTop-fYminBottom);
  var C = -(fZfar+fZnear)/(fZfar-fZnear);
  var D = -2*fZfar*fZnear/(fZfar-fZnear);
 
  return (Matrix.create([[X, 0, A, 0],
               [0, Y, B, 0],
               [0, 0, C, D],
               [0, 0, -1, 0]]));
} ;// createPerspectiveMatrix


////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//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 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////



//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)
function create3DRotationMatrix(angle,v)
{
  if(v.elements.length != 3)
  {
    throw "Invalid vector length";
  }
  var Mrot = Matrix.I(4); //Einheitsmatrix anlegen
  Mrot.elements[0][3] = v.elements[0];
  Mrot.elements[1][3] = v.elements[1];
  Mrot.elements[2][3] = v.elements[2];
  return(Mrot);
};//function create3DTranslationMatrix(v)


function sleep(ms){ 
var zeit=(new Date()).getTime(); 
var stoppZeit=zeit+ms; 
while((new Date()).getTime()<stoppZeit){}; 
}

//Klassendefinition JSVertexTriangle (Dreieck aus einzelnen Vertizes)
function JSVertexTriangle(xyz1, xyz2, xyz3)
{
  /*this.vertex1 = Vector.create([0,0,0]);
  this.vertex2 = Vector.create([1,0,0]);
  this.vertex3 = Vector.create([1,1,0]);*/
  this.vertex1 = Vector.create(xyz1);
  this.vertex2 = Vector.create(xyz2);
  this.vertex3 = Vector.create(xyz3);
  this.textureCoords1 = [0.0,0.0];
  this.textureCoords2 = [1.0,0.0];
  this.textureCoords3 = [1.0,1.0];
  this.getNormal = function()
  {
    var sideOne=this.vertex2.subtract(this.vertex1);
	var sideTwo=this.vertex3.subtract(this.vertex1);
	var normal = sideOne.cross(sideTwo);
    normal= normal.toUnitVector();
	//alert("NORMALE Berechnet:" + normal.e(1) +" / " + normal.e(2) + " / "+ normal.e(3) + "\n" );
  
	return(normal);
  }
  this.TransRotCopy = function(mvMatrix)
  {
    var trTriangle = new JSVertexTriangle([0,0,0],[0,0,0],[0,0,0]);
	trTriangle.vertex1 = mvMatrix.x(this.vertex1);
	trTriangle.vertex2 = mvMatrix.x(this.vertex2);
	trTriangle.vertex3 = mvMatrix.x(this.vertex3);
	return(trTriangle);
  }
}
  

function JSIndexedFaceSet()
{
  this.m_avVertices      = new Array(); //Vector Array
  this.m_avNormals       = new Array(); //NormalenVektoren
  this.m_aiIndices       = new Array(); //Indizes zur Erzeugung der Facetten
  this.m_afTextureCoords = new Array(); //Texturkoordinaten zu den Indizes
  this.m_vBoundingBoxMin = Vector.create([999999.0,999999.0,999999.0,]);
  this.m_vBoundingBoxMax = Vector.create([-999999.0,-999999.0,-999999.0,]);
  
}












