#include "Model3D.h"
#include "Model2D.h"
#include "DXBuffer.h"
#include "Textur.h"
#include "Animation3D.h"
#include "Welt3D.h"
#include "Textur.h"
#include "Bild.h"
#ifdef WIN32
#include <d3d11.h>
#endif
#include <stdexcept>

using namespace Framework;

// Inhalt der Knochen Klasse

// Konstruktor
Knochen::Knochen( int id )
{
    pos = Vec3< float >( 0, 0, 0 );
    winkel = Vec3< float >( 0, 0, 0 );
    geschwister = 0;
    kinder = 0;
    this->id = id;
}

// Destruktor
Knochen::~Knochen()
{
    delete geschwister;
    delete kinder;
}

// public

// Setzt die Position des Knochens relativ zum Model Ursprung
//  pos: Die Position
void Knochen::setPosition( Vec3< float >& pos )
{
    this->pos = pos;
}

// Setzt die Drehung des Knochens relativ zum Model Ursprung
//  winkel: Ein Vektor der die Drehung um die verschiedenen Achsen als Komponenten hat
void Knochen::setDrehung( Vec3< float >& winkel )
{
    this->winkel = winkel;
}

// F�gt dem Knochen ein Geschwister Knochen hinzu
//  k: Der Knochen, der hinzugef�gt werden soll
void Knochen::addGeschwisterKnochen( Knochen* k )
{
    if( !geschwister )
        geschwister = k;
    else
        geschwister->addGeschwisterKnochen( k );
}

// F�gt einem bestimmten Knochen ein Kind Knochen hinzu
//  id: Die id des Knochens, wo der Knochen als Kind hinzugef�gt werden soll
//  k: Der Knochen, der hinzugef�gt werden soll
void Knochen::addKind( int id, Knochen* k )
{
    if( this->id == id )
    {
        if( !kinder )
            kinder = k;
        else
            kinder->addGeschwisterKnochen( k );
    }
    else
    {
        if( kinder )
            kinder->addKind( id, k );
        else
        {
            Text err = "Es wurde kein Knochen mit der Id: ";
            err += id;
            err += " im Skelett gefunden, um ein Kind Knochen hinzuzuf�gen. Datei:" __FILE__ ", Zeile: ";
            err += __LINE__;
            err += "!";
            delete k;
            throw std::out_of_range( (const char*)err );
        }
    }
}

// Berechnet die Matrizen des Knochen und die von all seinen Geschwister Knochen und Kind Knochen
//  elternMat: Die fertig berechnete Matrix des Elternknochens
//  matBuffer: Ein Array, in dem alle berechneten Matrizen gespeichert werden sollen
//  scaleFactor: Die Skallierung des Modells
//  kamMatrix: Die vereiniegung der view und projektions Matrizen
void Knochen::kalkulateMatrix( Mat4< float >& elternMat, Mat4< float >* matBuffer, float scaleFactor, Mat4< float >& kamMat )
{
    if( geschwister )
        geschwister->kalkulateMatrix( elternMat, matBuffer, scaleFactor, kamMat );
    matBuffer[ id ] = matBuffer[ id ].translation( pos * scaleFactor ) * matBuffer[ id ].rotationZ( winkel.z ) * matBuffer[ id ].rotationX( winkel.x ) * matBuffer[ id ].rotationY( winkel.y ) * matBuffer[ id ].scaling( scaleFactor );
    matBuffer[ id ] = elternMat * matBuffer[ id ];
    if( kinder )
        kinder->kalkulateMatrix( matBuffer[ id ], matBuffer, scaleFactor, kamMat );
    matBuffer[ id ] = kamMat * matBuffer[ id ];
}

Knochen* Framework::Knochen::zGeschwister() const
{
    return geschwister;
}

Knochen* Framework::Knochen::zKind() const
{
    return kinder;
}

// Kopiert den Knochen mit allen Geschwister Knochen und Kind Knochen
Knochen* Knochen::kopiereKnochen() const
{
    Knochen* ret = new Knochen( id );
    ret->pos = pos;
    ret->winkel = winkel;
    if( geschwister )
        ret->geschwister = geschwister->kopiereKnochen();
    if( kinder )
        ret->kinder = kinder->kopiereKnochen();
    return ret;
}

// Gibt die Id des Knochens zur�ck
int Knochen::getId() const
{
    return id;
}

// Gibt die Drehung des Knochens zur�ck
Vec3< float > Knochen::getDrehung() const
{
    return winkel;
}

// Gibt die Position des Knochens zur�ck
Vec3< float > Knochen::getPosition() const
{
    return pos;
}

// Gibt den Radius des Knochens zur�ck
float Knochen::getRadius() const
{
    float r = pos.getLength();
    if( geschwister )
        r = MAX( r, geschwister->getRadius() );
    if( kinder )
        r += kinder->getRadius();
    return r;
}

// Inhalt der Skelett Klasse

// Konstruktor
Skelett::Skelett()
    : ReferenceCounter()
{
    k = 0;
    nextId = 0;
}

// Destruktor
Skelett::~Skelett()
{
    if( k )
        delete k;
}

// Gibt die Id des n�chsten Knochens zur�ck und berechnet die neue Id f�r den Knochen danach
// Es k�nnen maximal MAX_KNOCHEN_ANZ Knochen f�r ein Skelett existieren. Wenn diese Zahl �berschritten wird, so wird -1 zur�ckgegeben
int Skelett::getNextKnochenId()
{
    return nextId++;
}

void Framework::Skelett::setNextKnochenId( int id )
{
    nextId = id;
}

// F�gt dem Skellet einen Knochen hinzu
//  k: Der Knochen
//  elternId: Die Id des Eltern Knochens. Wenn der Knochen kein Elternknochen besitzt, kannder Parameter weggelassen werden.
void Skelett::addKnochen( Knochen* k, int elternId )
{
    if( !this->k )
        this->k = k;
    else
        this->k->addKind( elternId, k );
    if( k->getId() >= nextId )
        nextId = k->getId() + 1;
}

// Berechnet die Matrizen der Knochen
//  modelMatrix: Die Matrix, die das Skelett in den Raum der Welt transformiert
//  matBuffer: Ein Array von Matrizen, der durch die Knochen Matrizen gef�llt wird
//  scaleFactor: Die skallierung des Objektes
//  kamMatrix: Die vereiniegung der view und projektions Matrizen
//  return: gibt die Anzahl der verwendeten Matrizen zur�ck
int Skelett::kalkulateMatrix( Mat4< float >& modelMatrix, Mat4< float >* matBuffer, float scaleFactor, Mat4< float >& kamMatrix )
{
    k->kalkulateMatrix( modelMatrix, matBuffer, scaleFactor, kamMatrix );
    return nextId;
}

// Berechnet den Radius des Skeletts
float Skelett::getRadius() const
{
    if( k )
        return k->getRadius();
    return 0;
}

// gibt den Wurzel Knochen zur�ck
Knochen* Framework::Skelett::zKnochen() const
{
    return k;
}

// Kopiert das Skelett
Skelett* Skelett::kopiereSkelett() const
{
    Skelett* ret = new Skelett();
    ret->nextId = nextId;
    if( k )
        ret->addKnochen( k->kopiereKnochen() );
    return ret;
}

int Framework::Skelett::zNextKnochenId() const
{
    return nextId;
}

// Inhalt des Polygon3D Struct

// Konstruktor
Polygon3D::Polygon3D()
{
    indexAnz = 0;
    indexList = 0;
}

// Destruktor
Polygon3D::~Polygon3D()
{
    delete[] indexList;
}

// Inhalt der Model3DData Klasse

// Konstruktor
Model3DData::Model3DData( DXBuffer* dxVertexBuffer, DXBuffer* dxIndexBuffer, int id )
    : ReferenceCounter(),
    dxIndexBuffer( dxIndexBuffer ),
    dxVertexBuffer( dxVertexBuffer ),
    id( id )
{
    skelett = 0;
    vertexList = 0;
    vertexCount = 0;
    polygons = new Array< Polygon3D* >();
    ambientFactor = 1.f;
    diffusFactor = 0.f;
    specularFactor = 0.f;
    indexCount = 0;
    indexBuffer = 0;
    radius = 0;
}

// Destruktor
Model3DData::~Model3DData()
{
    clearModel();
    polygons->release();
    dxIndexBuffer->release();
    dxVertexBuffer->release();
    delete[] indexBuffer;
}

// updates the DX Buffer gpu memory if changed
DLLEXPORT void Model3DData::updateGPUMemory()
{
    dxIndexBuffer->copieren();
    dxVertexBuffer->copieren();
}

// L�scht alle Model daten
void Model3DData::clearModel()
{
    delete[] vertexList;
    vertexCount = 0;
    vertexList = 0;
    for( Polygon3D* i : *polygons )
        delete i;
    polygons->leeren();
    if( skelett )
        skelett->release();
    skelett = 0;
    radius = 0;
    delete[] indexBuffer;
    indexBuffer = 0;
    indexCount = 0;
}

// Berechnet die normalen f�r die Eckpunkte des Modells
void Model3DData::calculateNormals()
{
    for( int i = 0; i < vertexCount; i++ )
    {
        Vec3< float > normal( 0, 0, 0 );
        for( Polygon3D* p : *polygons )
        {
            int begin = 0;
            for( int j = 0; j < p->indexAnz; j++ )
            {
                if( j % 3 == 0 )
                    begin = j;
                if( p->indexList[ j ] == i )
                {
                    Vec3< float > a = vertexList[ p->indexList[ begin ] ].pos;
                    Vec3< float > b = vertexList[ p->indexList[ begin + 1 ] ].pos;
                    Vec3< float > c = vertexList[ p->indexList[ begin + 2 ] ].pos;
                    normal += (b - a).crossProduct( c - a ).normalize();
                    normal.normalize();
                }
            }
        }
        vertexList[ i ].normal = normal;
    }
}

//! Erstellt einen buffer f�r alle polygon indizes
void Model3DData::buildIndexBuffer()
{
    delete[] indexBuffer;
    indexCount = 0;
    for( Polygon3D* p : *polygons )
        indexCount += p->indexAnz;
    indexBuffer = new int[ indexCount ];
    int current = 0;
    for( Polygon3D* p : *polygons )
    {
        memcpy( indexBuffer + current, p->indexList, sizeof( int ) * p->indexAnz );
        current += p->indexAnz;
    }
    dxIndexBuffer->setLength( (int)(indexCount * sizeof( int )) );
    dxIndexBuffer->setData( indexBuffer );
}

// Setzt den Zeiger auf ein standartm��ig verwendete Skelett
//  s: Das Skelett, das verwendet werden soll
void Model3DData::setSkelettZ( Skelett* s )
{
    if( skelett )
        skelett->release();
    skelett = s;
}

// Setzt einen Zeiger auf eine Liste mit allen Vertecies des Models
//  vertexList: Ein Array mit Vertecies
//  anz: Die Anzahl der Vertecies im Array
void Model3DData::setVertecies( Vertex3D* vertexList, int anz )
{
    delete[] this->vertexList;
    this->vertexList = vertexList;
    vertexCount = anz;
    radius = 0;
    for( int i = 0; i < anz; i++ )
    {
        float r = vertexList[ i ].pos.getLength();
        if( r > radius )
            radius = r;
    }
    dxVertexBuffer->setLength( (int)(anz * sizeof( Vertex3D )) );
    dxVertexBuffer->setData( vertexList );
}

// F�gt ein Polygon zum Model hinzu
//  polygon: Das Polygon, das hinzugef�gt erden soll
void Model3DData::addPolygon( Polygon3D* polygon )
{
    polygons->add( polygon );
    buildIndexBuffer();
}

// Git den Factor an, mit dem das umgebungslicht (textur farbe) multipliziert wird
//  f: der neue Faktor (von 0 bis 1, ambient + specular + diffuse = 1)
void Model3DData::setAmbientFactor( float f )
{
    ambientFactor = f;
}

// Git den Factor an, mit dem die Lichtfarbe von Lichtquellen multipliziert wird
//  f: der neue Faktor (von 0 bis 1, ambient + specular + diffuse = 1)
void Model3DData::setDiffusFactor( float f )
{
    diffusFactor = f;
}

// Git den Factor an, mit dem die Reflektion von Lichtquellen multipliziert wird
//  f: der neue Faktor (von 0 bis 1, ambient + specular + diffuse = 1)
void Model3DData::setSpecularFactor( float f )
{
    specularFactor = f;
}

// Konvertiert ein 2d Model zu 3D
//  model: Das 2d Model, das zu 3d konvertiert werden soll
//  z: Die z koordinate aller punkte des Models
void Model3DData::copyModel2D( Model2DData* model, float z )
{
    if( model && model->vListen && model->polygons )
    {
        clearModel();
        int vAnz = 0;
        for( Polygon2D p : *model->polygons )
            vAnz += p.vertex->getEintragAnzahl();
        vertexList = new Vertex3D[ vAnz ];
        int index = 0;
        for( auto i : *model->vListen )
        {
            Polygon3D* p = new Polygon3D();
            p->indexAnz = 0;
            for( auto j : *i )
            {
                for( auto k = j->zListe()->begin(); k.hasNext() && k.next().hasNext(); k++ )
                    p->indexAnz += 3;
            }
            p->indexList = new int[ p->indexAnz ];
            p->indexAnz = 0;
            for( auto j : *i )
            {
                for( auto k = j->zListe()->begin(); k; k++ )
                {
                    vertexList[ index ].pos = Vec3< float >( k->punkt->x, k->punkt->y, z );
                    vertexList[ index ].tPos = (Vec2< float >) * k->textur;
                    if( k.hasNext() && k.next().hasNext() )
                    {
                        p->indexList[ p->indexAnz ] = index;
                        p->indexAnz++;
                        p->indexList[ p->indexAnz ] = index + 1;
                        p->indexAnz++;
                        p->indexList[ p->indexAnz ] = index + 2;
                        p->indexAnz++;
                    }
                    index++;
                }
            }
            addPolygon( p );
        }
        dxVertexBuffer->setLength( (int)(vAnz * sizeof( Vertex3D )) );
        dxVertexBuffer->setData( vertexList );
    }
}

// Entfernt ein Polygon
//  index: Der Index des Polygons
void Model3DData::removePolygon( int index )
{
    if( !polygons->hat( index ) )
        return;
    delete polygons->get( index );
    polygons->remove( index );
    buildIndexBuffer();
}

// Berechnet die Matrizen der Knochen
//  modelMatrix: Die Matrix, die das Skelett in den Raum der Welt transformiert
//  matBuffer: Ein Array von Matrizen, der durch die Knochen Matrizen gef�llt wird
//  scaleFactor: Die Skallierung des Modells
//  kamMatrix: Die vereiniegung der view und projektions Matrizen
//  return: gibt die Anzahl der verwendeten Matrizen zur�ck
int Model3DData::kalkulateMatrix( Mat4< float >& modelMatrix, Mat4< float >* matBuffer, float scaleFactor, Mat4< float >& kamMatrix ) const
{
    if( !skelett )
        return 0;
    return skelett->kalkulateMatrix( modelMatrix, matBuffer, scaleFactor, kamMatrix );
}

// Gibt die Anzahl an Polygonen zur�ck
int Model3DData::getPolygonAnzahl() const
{
    return polygons->getEintragAnzahl();
}

// Gibt ein bestimmtes Polygon zur�ck
//  index: Der Index des Polygons
Polygon3D* Model3DData::getPolygon( int index ) const
{
    if( !polygons->hat( index ) )
        return 0;
    return polygons->get( index );
}

// Gibt einen Iterator zur�ck, mit dem sich die Polygons auflisten lassen
Iterator< Polygon3D* > Model3DData::getPolygons() const
{
    return polygons->begin();
}

// Gibt den radius einer Kugel zur�ck, die das gesammte Model umschlie�t
float Model3DData::getRadius() const
{
    return radius;
}

// Gibt die Id der Daten zur�ck, wenn sie in einer Model3DList registriert wurden. (siehe Framework::zM3DRegister())
int Model3DData::getId() const
{
    return id;
}

// Git den Factor an, mit dem das umgebungslicht (textur farbe) multipliziert wird
float Model3DData::getAmbientFactor() const
{
    return ambientFactor;
}

// Git den Factor an, mit dem die Lichtfarbe von Lichtquellen multipliziert wird
float Model3DData::getDiffusFactor() const
{
    return diffusFactor;
}

// Git den Factor an, mit dem die Reflektion von Lichtquellen multipliziert wird
float Model3DData::getSpecularFactor() const
{
    return specularFactor;
}

// Gibt eine Kopie des Skeletts zur�ck, welches f�r annimationen verwendet werden kann
Skelett* Model3DData::copySkelett() const
{
    return skelett ? skelett->kopiereSkelett() : 0;
}

// Gibt die Anzahl an Vertices zur�ck
int Model3DData::getVertexAnzahl() const
{
    return vertexCount;
}

// Gibt einen Buffer mit allen Vertecies des Models zur�ck
const Vertex3D* Model3DData::zVertexBuffer() const
{
    return vertexList;
}

//! Gibt eine refferenz auf den beginn des indexBuffers zur�ck
const int* Model3DData::getIndexBuffer() const
{
    return indexBuffer;
}

//! Gibt eine die Anzahl der indizes im indexBuffer zur�ck
int Model3DData::getIndexCount() const
{
    return indexCount;
}

//! Gibt den Index buffer zur�ck;
DXBuffer* Model3DData::zDXIndexBuffer() const
{
    return dxIndexBuffer;
}

//! Gibt den Vertex buffer zur�ck;
DXBuffer* Model3DData::zDXVertexBuffer() const
{
    return dxVertexBuffer;
}


// Inhalt der Model3DTextur

// Konstruktor
Model3DTextur::Model3DTextur()
    : ReferenceCounter()
{
    textures = new RCArray< Textur >();
}

// Destruktor
Model3DTextur::~Model3DTextur()
{
    textures->release();
}

// Legt fest, welche Textur f�r welches Polygon ist
//  pI: Der Index des Polygons
//  txt: Die Textur des Polygons
void Model3DTextur::setPolygonTextur( int pI, Textur* txt )
{
    while( pI > textures->getLastIndex() )
        textures->add( 0 );
    textures->set( txt, pI );
}

// Gibt einen Zeiger auf die Textur eines Polygons zur�ck ohne erh�hten Reference Counter
//  i: Der Index des Polygons
Textur* Model3DTextur::zPolygonTextur( int i ) const
{
    return textures->z( i );
}

// Inhalt der AnimationData Struktur
Model3D::AnimationData* Model3D::AnimationData::getThis()
{
    return this;
}

Model3D::AnimationData* Model3D::AnimationData::release()
{
    a->release();
    delete this;
    return 0;
}

// Inhalt der Model3D Klasse
// Konstruktor
Model3D::Model3D()
    : Zeichnung3D()
{
    model = 0;
    textur = 0;
    skelett = 0;
    animations = new RCArray< AnimationData >();
    ambientFactor = 1.f;
    diffusFactor = 0.f;
    specularFactor = 0.f;
}

// Destruktor
Model3D::~Model3D()
{
    if( model )
        model->release();
    if( textur )
        textur->release();
    if( skelett )
        skelett->release();
    animations->release();
}

// F�gt eine Animation hinzu
//  a: Die neue Animation
void Model3D::addAnimation( Animation3D* a, double speed )
{
    AnimationData* d = new AnimationData();
    d->a = a;
    d->speed = speed;
    d->offset = 0;
    animations->add( d );
}

// Entfernt eine Animation
//  zA: Die zu entfernende Animation
void Model3D::removeAnimation( Animation3D* zA )
{
    for( int i = 0; i < animations->getEintragAnzahl(); i++ )
    {
        if( animations->z( i )->a == zA )
        {
            animations->remove( i );
            return;
        }
    }
}

// Setzt die Daten des Models
//  data: Die Daten
void Model3D::setModelDaten( Model3DData* data )
{
    if( model )
        model->release();
    if( skelett )
        skelett = (Skelett*)skelett->release();
    model = data;
    if( model )
    {
        skelett = model->copySkelett();
        this->ambientFactor = model->getAmbientFactor();
        this->specularFactor = model->getSpecularFactor();
        this->diffusFactor = model->getDiffusFactor();
    }
}

// Setzt die zum Zeichnen zu benutzenden Texturen
//  txt: Ein Liste mit Texturen zu den verschiedenen Polygonen zugeordnet
void Model3D::setModelTextur( Model3DTextur* txt )
{
    if( textur )
        textur->release();
    textur = txt;
}

// Git den Factor an, mit dem das umgebungslicht (textur farbe) multipliziert wird
//  f: der neue Faktor (von 0 bis 1, ambient + specular + diffuse = 1)
void Framework::Model3D::setAmbientFactor( float f )
{
    this->ambientFactor = f;
}

// Git den Factor an, mit dem die Lichtfarbe von Lichtquellen multipliziert wird
//  f: der neue Faktor (von 0 bis 1, ambient + specular + diffuse = 1)
void Framework::Model3D::setDiffusFactor( float f )
{
    diffusFactor = f;
}

// Git den Factor an, mit dem das umgebungslicht (textur farbe) multipliziert wird
//  f: der neue Faktor (von 0 bis 1, ambient + specular + diffuse = 1)
void Framework::Model3D::setSpecularFactor( float f )
{
    specularFactor = f;
}

// Errechnet die Matrizen aller Knochen des Skeletts des Models
//  viewProj: Die miteinander multiplizierten Kameramatrizen
//  matBuffer: Ein Array mit Matrizen, der gef�llt werden soll
//  return: Die Anzahl der Matrizen, die das Model ben�tigt
int Model3D::errechneMatrizen( Mat4< float >& viewProj, Mat4< float >* matBuffer )
{
    int ret = 0;
    if( skelett )
        ret = skelett->kalkulateMatrix( welt, matBuffer, size, viewProj );
    else if( model )
        ret = model->kalkulateMatrix( welt, matBuffer, size, viewProj );
    if( !ret )
        return Zeichnung3D::errechneMatrizen( viewProj, matBuffer );
    return ret;
}

// Verarbeitet die vergangene Zeit
//  tickval: Die zeit in sekunden, die seit dem letzten Aufruf der Funktion vergangen ist
//  return: true, wenn sich das Objekt ver�ndert hat, false sonnst.
bool Model3D::tick( double tickval )
{
    radius = model ? model->getRadius() : 0;
    if( skelett )
    {
        radius += skelett->getRadius();
        for( auto i = animations->begin(); i && i._; i++ )
        {
            rend = i->speed > 0;
            i->a->apply( skelett, i->offset, tickval * i->speed );
        }
    }
    return Zeichnung3D::tick( tickval );
}

// Gibt die Textur zur�ck
Model3DTextur* Model3D::getTextur()
{
    return textur ? dynamic_cast<Model3DTextur*>(textur->getThis()) : 0;
}

// Gibt die Textur zur�ck (ohne erh�hten Reference Counter)
Model3DTextur* Model3D::zTextur()
{
    return textur;
}

// Gibt die ModelDaten zur�ck
Model3DData* Model3D::getModelData()
{
    return model ? dynamic_cast<Model3DData*>(model->getThis()) : 0;
}

// Gibt die ModelDaten zur�ck (ohne erh�hten Reference Counter)
Model3DData* Model3D::zModelData()
{
    return model;
}

// pr�ft, ob ein Strahl dieses Objekt trifft
//  point: der startpunkt des Strahls in Weltkoordinaten
//  dir: die Richtung des Strahls in Weltkoordinaten
//  maxSqDist: Die maximale quadratische distanz die erlaubt ist
//  pId: die Id des Polygons, zu dem der Schnittpunkt geh�rt
//  return: den quadratischen Abstand des Schnittpunktes zum Ursprung des Strahls oder -1, wenn kein schnittpunkt existiert 
float Model3D::traceRay( Vec3< float >& p, Vec3< float >& d, float maxSqDist, int& pId ) const
{
    if( !model )
        return -1;
    Vec3< float > dir = d;
    dir.rotateY( -angle.y );
    dir.rotateX( -angle.x );
    dir.rotateZ( -angle.z );
    Vec3< float > point = p;
    point.rotateY( -angle.y );
    point.rotateX( -angle.x );
    point.rotateZ( -angle.z );
    point -= pos;
    float nearest = (-dir.x * point.x - dir.y * point.y - dir.z * point.z) / (dir.x * dir.x + dir.y * dir.y + dir.z * dir.z);
    float dist = (point + dir * nearest).getLengthSq();
    if( dist > (radius * size) * (radius * size) || (dir * nearest).getLength() - radius * size > sqrt( maxSqDist ) || (nearest < 0 && (dir * nearest).getLengthSq() > radius * size * radius * size) ) // es gibt kein schnittpunkt
        return -1;
    bool existsHit = 0;
    if( skelett )
    { // todo

    }
    else
    {
        int index = 0;
        for( auto p = model->getPolygons(); p; p++ )
        {
            for( int j = 0; j < p->indexAnz; j++ )
            {
                if( j % 3 == 0 )
                {
                    Vec3< float > a = model->zVertexBuffer()[ p->indexList[ j ] ].pos;
                    Vec3< float > b = model->zVertexBuffer()[ p->indexList[ j + 1 ] ].pos;
                    Vec3< float > c = model->zVertexBuffer()[ p->indexList[ j + 2 ] ].pos;
                    Vec3< float > normal = (b - a).crossProduct( c - a ).normalize();
                    if( normal * dir < 0 ) // Pr�fe ob die Normale in Richtung des Strahl ursprungs zeigt
                    {
                        nearest = (a * normal - point * normal) / (dir * normal);
                        Vec3< float > hit = point + dir * nearest;
                        if( (b - a).angle( hit - a ) <= (b - a).angle( c - a ) &&
                            (c - a).angle( hit - a ) <= (b - a).angle( c - a ) &&
                            (a - b).angle( hit - b ) <= (a - b).angle( c - b ) )
                        {
                            maxSqDist = (hit - point).getLengthSq();
                            pId = index;
                            existsHit = 1;
                        }
                    }
                    index++;
                }
            }
        }
    }
    return existsHit ? maxSqDist : -1;
}

// berechnet die Farbe des Schnittpunktes deines Strahls
//  point: der startpunkt des Strahls in Weltkoordinaten
//  dir: die Richtung des Strahls in Weltkoordinaten
//  zWelt: die Welt, aus der der Strahl kommt
//  return: die Farbe des Schnittpunktes 
int Model3D::traceRay( Vec3< float >& p, Vec3< float >& d, int pId, Welt3D* zWelt ) const
{
    Vec3< float > dir = d;
    dir.rotateY( -angle.y );
    dir.rotateX( -angle.x );
    dir.rotateZ( -angle.z );
    Vec3< float > point = p;
    point.rotateY( -angle.y );
    point.rotateX( -angle.x );
    point.rotateZ( -angle.z );
    point -= pos;
    int index = 0;
    for( auto p = model->getPolygons(); p; p++, index++ )
    {
        for( int j = 0; j < p->indexAnz; j++ )
        {
            if( j % 3 == 0 )
            {
                if( pId == 0 )
                {
                    const Vec3< float >& a = model->zVertexBuffer()[ p->indexList[ j ] ].pos;
                    const Vec3< float >& b = model->zVertexBuffer()[ p->indexList[ j + 1 ] ].pos;
                    const Vec3< float >& c = model->zVertexBuffer()[ p->indexList[ j + 2 ] ].pos;
                    Vertex at = model->zVertexBuffer()[ p->indexList[ j ] ].tPos;
                    Vertex bt = model->zVertexBuffer()[ p->indexList[ j + 1 ] ].tPos;
                    Vertex ct = model->zVertexBuffer()[ p->indexList[ j + 2 ] ].tPos;
                    Vec3< float > normal = (b - a).crossProduct( c - a ).normalize();
                    float t = (a * normal - point * normal) / (dir * normal);
                    Vec3< float > hit = point + dir * t;
                    float a0 = (a - b).crossProduct( a - c ).getLength() / 2;
                    float a1 = (b - hit).crossProduct( c - hit ).getLength() / 2 / a0;
                    float a2 = (c - hit).crossProduct( a - hit ).getLength() / 2 / a0;
                    float a3 = (a - hit).crossProduct( b - hit ).getLength() / 2 / a0;
                    Vertex ht = at * a1 + bt * a2 + ct * a3;
                    Bild* tex = textur->zPolygonTextur( index )->zBild();
                    if( ht.x >= 0 && ht.y >= 0 && ht.x <= 1 && ht.y <= 1 )
                        return tex->getPixel( (int)(ht.x * ((float)tex->getBreite() - 1.f) + 0.5f), (int)(ht.y * ((float)tex->getHeight() - 1.f) + 0.5f) );
                    return 0xFF000000;
                }
                pId--;
            }
        }
    }
    return 0xFF000000;
}

// Gibt die Id der Daten zur�ck, wenn sie in einer Model3DList registriert wurden. (siehe Framework::zM3DRegister())
int Model3D::getDatenId() const
{
    return model ? model->getId() : -1;
}

// Git den Factor an, mit dem das umgebungslicht (textur farbe) multipliziert wird
float Model3D::getAmbientFactor() const
{
    return ambientFactor;
}

// Git den Factor an, mit dem die Lichtfarbe von Lichtquellen multipliziert wird
float Model3D::getDiffusFactor() const
{
    return diffusFactor;
}

// Git den Factor an, mit dem die Reflektion von Lichtquellen multipliziert wird
float Model3D::getSpecularFactor() const
{
    return specularFactor;
}

// Gibt die Anzahl an Vertices zur�ck
int Model3D::getVertexAnzahl() const
{
    return model ? model->getVertexAnzahl() : 0;
}

// Gibt einen Buffer mit allen Vertecies des Models zur�ck
const Vertex3D* Model3D::zVertexBuffer() const
{
    return model ? model->zVertexBuffer() : 0;
}

//! Gibt true zur�ck wenn ein bestimmtes polygon gezeichnet werden muss
bool Model3D::needRenderPolygon( int index )
{
    return 1;
}

Textur* Model3D::zEffectTextur()
{
    return 0;
}

float Model3D::getEffectPercentage()
{
    return 0;
}