#include "Model2D.h" #include "Textur2D.h" #include "FrameworkMath.h" #include "Mat3.h" #include "MausEreignis.h" #include "Bild.h" using namespace Framework; // Inhalt der Model2DData Klasse aus Model2D.h // Konstruktor Model2DData::Model2DData() : polygons( 0 ), vListen( 0 ), minP( 0, 0 ), maxP( 0, 0 ) { ref = 1; } // Destruktor Model2DData::~Model2DData() { if( polygons ) { int anz = polygons->getEintragAnzahl(); for( int i = 0; i < anz; i++ ) { if( polygons->get( i ).name ) polygons->get( i ).name->release(); if( polygons->get( i ).tKordinaten ) polygons->get( i ).tKordinaten->release(); if( polygons->get( i ).vertex ) polygons->get( i ).vertex->release(); if( polygons->get( i ).schwerpunkt ) delete polygons->get( i ).schwerpunkt; } polygons = polygons->release(); } if( vListen ) vListen->release(); } // privat bool Model2DData::istPunktInnen( Vertex p, int polygonId ) const { if( p < minP || p > maxP || !polygons ) return 0; int num = 0; auto outListP = outList.getIterator(); for( auto polygon = polygons->getIterator(); polygon; polygon++, num++, outListP++ ) { if( polygonId >= 0 && num != polygonId ) continue; int anz = polygon._.vertex->getEintragAnzahl(); bool c = 0; int j = anz - 1; for( auto outListPP = outListP->getIterator(); outListPP; outListPP++ ) { Punkt out = outListPP; if( out.x < out.y && j > out.x && j < out.y ) j = out.x; if( out.x > out.y && ( j > out.x || j < out.y ) ) j = out.x; } auto point = polygon._.vertex->getIterator(); for( int i = 0; i < anz; i++, point++ ) { bool cont = 0; for( auto outListPP = outListP->getIterator(); outListPP; outListPP++ ) { Punkt out = outListPP; if( out.x < out.y && i > out.x && i < out.y ) cont = 1; if( out.x > out.y && ( i > out.x || i < out.y ) ) cont = 1; } if( cont ) continue; Vertex a = point; Vertex b = polygon._.vertex->get( j ); if( ( ( a.y >= p.y ) != ( b.y >= p.y ) ) && ( p.x <= ( b.x - a.x ) * ( p.y - a.y ) / (float)( b.y - a.y ) + a.x ) ) c = !c; j = i; } if( c ) return 1; } return 0; } bool Model2DData::istLinieInnen( Vertex a, Vertex b, int polygonId ) const { if( !polygons ) return 0; int pAnz = polygons->getEintragAnzahl(); for( int p = 0; p < pAnz; p++ ) { if( polygonId >= 0 && p != polygonId ) continue; int ola = outList.z( p )->getEintragAnzahl(); int anz = polygons->get( p ).vertex->getEintragAnzahl(); int j = anz - 1; for( int k = 0; k < ola; k++ ) { Punkt out = outList.z( p )->get( k ); if( out.x < out.y && j > out.x && j < out.y ) j = out.x; if( out.x > out.y && ( j > out.x || j < out.y ) ) j = out.x; } for( int i = 0; i < anz; i++ ) { bool cont = 0; for( int k = 0; k < ola; k++ ) { Punkt out = outList.z( p )->get( k ); if( out.x < out.y && i > out.x && i < out.y ) cont = 1; if( out.x > out.y && ( i > out.x || i < out.y ) ) cont = 1; } if( cont ) continue; Punkt va = polygons->get( p ).vertex->get( i ); Punkt vb = polygons->get( p ).vertex->get( j ); if( (Punkt)a == va && (Punkt)b == vb ) return 1; if( (Punkt)a == vb && (Punkt)b == va ) return 1; j = i; } Vertex len = b - a; Vertex speed( len.x > 0 ? 1 : -1.f, len.y > 0 ? 1 : -1.f ); int mLen = 0; if( fabs( len.x ) > fabs( len.y ) ) { mLen = (int)fabs( len.x ); speed.y = len.y / (float)fabs( len.x ); } else { mLen = (int)fabs( len.y ); speed.x = len.x / (float)fabs( len.y ); } int i = 1; bool inside = 1; for( Vertex vp = speed + a; (Punkt)vp != (Punkt)( b - speed ) && inside && i < mLen - 1; vp += speed, i++ ) inside &= istPunktInnen( vp, p ); if( inside ) return 1; } return 0; } // nicht constant bool Model2DData::erstelleModell( Array< Polygon2D > *polygons ) { removeModell(); if( !polygons || !polygons->getEintragAnzahl() ) { this->polygons = polygons; vListen = new RCArray< RCArray< DreieckListe< Vertex > > >(); return 1; } this->polygons = polygons; int pAnz = polygons->getEintragAnzahl(); vListen = new RCArray< RCArray< DreieckListe< Vertex > > >(); for( int p = 0; p < pAnz; p++ ) { Polygon2D pg = polygons->get( p ); if( !pg.vertex || pg.vertex->getEintragAnzahl() < 3 ) continue; vListen->add( new RCArray< DreieckListe< Vertex > >() ); outList.set( new Array< Punkt >, p ); int vAnz = pg.vertex->getEintragAnzahl(); bool textur = pg.tKordinaten != 0; for( int i = 0; i < vAnz && textur; i++ ) textur &= pg.tKordinaten->hat( i ); for( int i = 0; i < vAnz; i++ ) { if( maxP.x < fabs( pg.vertex->get( i ).x ) ) { maxP.x = abs( (int)pg.vertex->get( i ).x ) + 1; maxP.y = abs( (int)pg.vertex->get( i ).x ) + 1; } if( maxP.y < fabs( pg.vertex->get( i ).y ) ) { maxP.x = abs( (int)pg.vertex->get( i ).y ) + 1; maxP.y = abs( (int)pg.vertex->get( i ).y ) + 1; } } minP = -maxP; if( !textur ) { if( pg.tKordinaten ) pg.tKordinaten->leeren(); } RCArray< RCArray< DreieckListe< Vertex > > > lists; int lauf = 0; while( 1 ) { lists.set( new RCArray< DreieckListe< Vertex > >(), lauf ); outList.z( p )->set( Punkt( 0, 0 ), lauf ); bool fertig = 0; Vertex a; Vertex b; Array< Punkt > tmpOutList; for( int i = 0; i < vAnz; i++ ) { bool cont = 0; int vorher = i - 1; int nachher = i + 1; if( nachher >= vAnz ) nachher = 0; if( vorher < 0 ) vorher = vAnz - 1; int ola = outList.z( p )->getEintragAnzahl(); for( int j = 0; j < ola; j++ ) { Punkt out = outList.z( p )->get( j ); if( out.x < out.y ) { if( nachher > out.x && nachher < out.y ) nachher = out.y; if( vorher > out.x && vorher < out.y ) vorher = out.x; } if( out.x > out.y ) { if( nachher > out.x || nachher < out.y ) nachher = out.y; if( vorher > out.x || vorher < out.y ) vorher = out.x; } if( out.x < out.y && i > out.x && i < out.y ) cont = 1; if( out.x > out.y && ( i > out.x || i < out.y ) ) cont = 1; } if( cont ) continue; if( vorher < 0 ) a = pg.vertex->get( vAnz + vorher ); else a = pg.vertex->get( vorher ); if( nachher > vAnz - 1 ) b = pg.vertex->get( nachher - vAnz + 1 ); else b = pg.vertex->get( nachher ); if( istLinieInnen( a, b, p ) ) { DreieckListe< Vertex > *lowL = new DreieckListe< Vertex >(); DreieckListe< Vertex > *heightL = new DreieckListe< Vertex >(); lowL->addPunkt( new Vertex( pg.vertex->get( i ) ), textur ? new Vertex( pg.tKordinaten->get( i ) ) : 0 ); heightL->addPunkt( new Vertex( pg.vertex->get( i ) ), textur ? new Vertex( pg.tKordinaten->get( i ) ) : 0 ); int height = i + 1; int low = i - 1; Punkt outL( 0, 0 ); Punkt outH( 0, 0 ); for( int k = 0; k < 2; k++ ) { bool lowp = !k; while( 1 ) { if( height >= vAnz ) height = 0; if( low < 0 ) low = vAnz - 1; for( int j = 0; j <= lauf; j++ ) { Punkt out = outList.z( p )->get( j ); if( out.x < out.y ) { if( height > out.x && height < out.y ) height = out.y; if( low > out.x && low < out.y ) low = out.x; } if( out.x > out.y ) { if( height > out.x || height < out.y ) height = out.y; if( low > out.x || low < out.y ) low = out.x; } } Vertex a = pg.vertex->get( height ); Vertex b = pg.vertex->get( low ); if( low == height ) { fertig = 1; outList.z( p )->set( Punkt( 0, 0 ), lauf ); if( !k ) lowL->addPunkt( new Vertex( b ), textur ? new Vertex( pg.tKordinaten->get( low ) ) : 0 ); else heightL->addPunkt( new Vertex( b ), textur ? new Vertex( pg.tKordinaten->get( low ) ) : 0 ); break; } bool inside = istLinieInnen( a, b, p ); if( inside ) { if( !k ) outL = Punkt( low, height ); else outH = Punkt( low, height ); outList.z( p )->set( Punkt( low, height ), lauf ); } if( lowp ) { if( !k ) lowL->addPunkt( new Vertex( b ), textur ? new Vertex( pg.tKordinaten->get( low ) ) : 0 ); else heightL->addPunkt( new Vertex( b ), textur ? new Vertex( pg.tKordinaten->get( low ) ) : 0 ); low--; } else { if( !k ) lowL->addPunkt( new Vertex( a ), textur ? new Vertex( pg.tKordinaten->get( height ) ) : 0 ); else heightL->addPunkt( new Vertex( a ), textur ? new Vertex( pg.tKordinaten->get( height ) ) : 0 ); height++; } lowp = !lowp; if( !inside ) { height = i + 1; low = i - 1; outList.z( p )->set( Punkt( 0, 0 ), lauf ); break; } } if( fertig ) break; } if( lowL->getDreieckAnzahl() > heightL->getDreieckAnzahl() ) { lists.z( lauf )->set( lowL, i ); tmpOutList.set( outL, i ); heightL->release(); } else { lists.z( lauf )->set( heightL, i ); tmpOutList.set( outH, i ); lowL->release(); } } else lists.z( lauf )->set( new DreieckListe< Vertex >(), i ); if( fertig ) break; } int maxP = -1; int max = 0; for( int i = 0; i < vAnz; i++ ) { if( lists.z( lauf )->z( i ) && lists.z( lauf )->z( i )->getDreieckAnzahl() > max ) { max = lists.z( lauf )->z( i )->getDreieckAnzahl(); maxP = i; } } if( !max || maxP < 0 ) break; vListen->z( p )->add( lists.z( lauf )->get( maxP ) ); outList.z( p )->set( tmpOutList.get( maxP ), lauf ); if( fertig ) break; lauf++; } outList.z( p )->leeren(); } return 1; } void Model2DData::removeModell() // setzt die Vertex daten zurück { if( polygons ) { int anz = polygons->getEintragAnzahl(); for( int i = 0; i < anz; i++ ) { if( polygons->get( i ).name ) polygons->get( i ).name->release(); if( polygons->get( i ).tKordinaten ) polygons->get( i ).tKordinaten->release(); if( polygons->get( i ).vertex ) polygons->get( i ).vertex->release(); if( polygons->get( i ).schwerpunkt ) delete polygons->get( i ).schwerpunkt; } polygons = polygons->release(); } if( vListen ) vListen = vListen->release(); outList.leeren(); minP = Punkt( 0, 0 ); maxP = Punkt( 0, 0 ); } bool Model2DData::calcHitPoint( Vertex pos, Vertex dir, const char *polygonName, Vertex &hitpoint, Vertex &moveSpeed, float &rotSpeed ) const { bool ret = 0; for( auto polygon = polygons->getIterator(); polygon; polygon++ ) { if( polygon._.name->istGleich( polygonName ) ) { int anz = polygon._.vertex->getEintragAnzahl(); for( int i = 0; i < anz; i++ ) { Vertex a = polygon._.vertex->get( i ); Vertex b = polygon._.vertex->get( ( i + 1 ) % anz ); b -= a; float offset = 0; if( dir.y != 0 && dir.x != 0 ) offset = ( ( a.y - pos.y ) / dir.y - ( a.x - pos.x ) / dir.x ) / ( b.x / dir.x - b.y / dir.y ); // solve hitpoint equasion else if( dir.y == 0 ) offset = ( pos.y - a.y ) / b.y; else if( dir.x == 0 ) offset = ( pos.x - a.x ) / b.x; Vertex point = a + ( b * offset ); if( offset >= 0 && offset <= 1 ) { float f = ( point.x - pos.x ) / dir.x; if( !dir.x ) f = ( point.y - pos.y ) / dir.y; if( ( !ret || ( hitpoint - pos ).getLengthSq() > ( point - pos ).getLengthSq() ) && f > 0 ) { Vertex normal = b.CW90().normalize(); Vertex kNorm = Vertex( dir ).normalize(); moveSpeed = normal * ( normal * kNorm ) * dir.getLength(); normal = ( point - *polygon._.schwerpunkt ).CW90().normalize(); Vertex rotKraft = normal * ( normal * kNorm ) * dir.getLength(); rotSpeed = ( (float)sqrt( rotKraft.getLength() * ( point - *polygon._.schwerpunkt ).getLength() ) / 180.f ) * 3.14f * ( normal * kNorm ); hitpoint = point; ret = 1; } } } } } return ret; } bool Model2DData::split( Vertex pos, Vertex dir, char *polygonName, Polygon2D &partA, Polygon2D &partB, Punkt &posA, Punkt &posB, std::function< double() > random ) const { Vertex originalDir = dir; bool ret = 0; int num = 0; for( auto polygon = polygons->getIterator(); polygon; polygon++, num++ ) { if( polygon._.name->istGleich( polygonName ) ) { while( istPunktInnen( pos, num ) ) { pos -= dir; } int anz = polygon._.vertex->getEintragAnzahl(); Vertex startPoint; Vertex texturSP; int leftI = 0; int rightI = 0; Vertex txtChpPix( 0, 0 ); for( int i = 0; i < anz; i++ ) { Vertex a = polygon._.vertex->get( i ); Vertex b = polygon._.vertex->get( ( i + 1 ) % anz ); b -= a; if( ( txtChpPix.x == 0 || txtChpPix.y == 0 ) && b.x != 0 && b.y != 0 ) { Vertex ta = polygon._.tKordinaten->get( i ); Vertex tb = polygon._.tKordinaten->get( ( i + 1 ) % anz ); tb -= ta; txtChpPix = Vertex( tb.x / b.x, tb.y / b.y ); } float offset = 0; if( dir.y != 0 && dir.x != 0 ) offset = ( ( a.y - pos.y ) / dir.y - ( a.x - pos.x ) / dir.x ) / ( b.x / dir.x - b.y / dir.y ); // solve hitpoint equasion else if( dir.y == 0 ) offset = ( pos.y - a.y ) / b.y; else if( dir.x == 0 ) offset = ( pos.x - a.x ) / b.x; Vertex point = a + ( b * offset ); if( offset >= 0 && offset <= 1 ) { if( !ret || ( startPoint - pos ).getLengthSq() > ( point - pos ).getLengthSq() ) { leftI = i; rightI = ( i + 1 ) % anz; startPoint = point; texturSP = polygon._.tKordinaten->get( i ) + ( polygon._.tKordinaten->get( ( i + 1 ) % anz ) - polygon._.tKordinaten->get( i ) ) * offset; } ret = 1; } } if( ret ) { partA.transparent = polygon._.transparent; partA.schwerpunkt = new Vertex( 0, 0 ); partA.tKordinaten = new Array< Vertex >(); partA.name = new Text( polygon._.name->getText() ); partA.vertex = new Array< Vertex >(); partB.transparent = polygon._.transparent; partB.schwerpunkt = new Vertex( 0, 0 ); partB.tKordinaten = new Array< Vertex >(); partB.name = new Text( polygon._.name->getText() ); partB.vertex = new Array< Vertex >(); *partA.schwerpunkt += startPoint; *partB.schwerpunkt += startPoint; partA.vertex->add( startPoint ); partB.vertex->add( startPoint ); partA.tKordinaten->add( texturSP ); partB.tKordinaten->add( texturSP ); int leftIE = 0; int rightIE = 0; while( 1 ) { pos = startPoint; Vertex next = startPoint + dir; Vertex nextT = texturSP + Vertex( dir.x * txtChpPix.x, dir.y * txtChpPix.y ); ret = 0; bool needOne = !istPunktInnen( next ); int bestI = -1; float bo1 = 1000; float bo2 = 1000; for( int i = 0; i < anz; i++ ) { if( i == leftI ) continue; Vertex a = polygon._.vertex->get( i ); Vertex b = polygon._.vertex->get( ( i + 1 ) % anz ); b -= a; float offset1 = 0; if( dir.y != 0 && dir.x != 0 ) offset1 = ( ( a.y - pos.y ) / dir.y - ( a.x - pos.x ) / dir.x ) / ( b.x / dir.x - b.y / dir.y ); // solve hitpoint equasion else if( dir.y == 0 ) offset1 = ( pos.y - a.y ) / b.y; else if( dir.x == 0 ) offset1 = ( pos.x - a.x ) / b.x; Vertex point = a + ( b * offset1 ); float offset2 = 0; if( dir.x != 0 ) offset2 = ( point.x - pos.x ) / dir.x; else offset2 = ( point.y - pos.y ) / dir.y; if( needOne && MIN( abs( bo1 ), abs( bo1 - 1 ) ) + MIN( abs( bo2 ), bo2 - 1 ) > MIN( abs( offset1 ), abs( offset1 - 1 ) ) + MIN( abs( offset2 ), abs( offset2 - 1 ) ) ) { bo1 = offset1; bo2 = offset2; bestI = i; } if( offset1 >= 0 && offset1 <= 1 && offset2 >= 0 && offset2 <= 1 ) { if( !ret || ( startPoint - pos ).getLengthSq() > ( point - pos ).getLengthSq() ) { leftIE = i; rightIE = ( i + 1 ) % anz; startPoint = point; texturSP = polygon._.tKordinaten->get( i ) + ( polygon._.tKordinaten->get( ( i + 1 ) % anz ) - polygon._.tKordinaten->get( i ) ) * offset1; } ret = 1; } } if( needOne && !ret ) { Vertex a = polygon._.vertex->get( bestI ); Vertex b = polygon._.vertex->get( ( bestI + 1 ) % anz ); b -= a; leftIE = bestI; rightIE = ( bestI + 1 ) % anz; startPoint = a + ( b * bo1 ); texturSP = polygon._.tKordinaten->get( bestI ) + ( polygon._.tKordinaten->get( ( bestI + 1 ) % anz ) - polygon._.tKordinaten->get( bestI ) ) * bo1; ret = 1; } if( ret ) break; *partA.schwerpunkt += next; *partB.schwerpunkt += next; partA.vertex->add( next ); partB.vertex->add( next ); partA.tKordinaten->add( nextT ); partB.tKordinaten->add( nextT ); startPoint = next; texturSP = nextT; dir = originalDir.rotation( (float)( random() - 0.5 ) ); } *partA.schwerpunkt += startPoint; *partB.schwerpunkt += startPoint; partA.vertex->add( startPoint ); partB.vertex->add( startPoint ); partA.tKordinaten->add( texturSP ); partB.tKordinaten->add( texturSP ); for( int i = rightIE; i != leftI; i++ ) { i = i % anz; if( i == leftI ) break; *partA.schwerpunkt += polygon._.vertex->get( i ); partA.vertex->add( polygon._.vertex->get( i ) ); partA.tKordinaten->add( polygon._.tKordinaten->get( i ) ); } *partA.schwerpunkt += polygon._.vertex->get( leftI ); partA.vertex->add( polygon._.vertex->get( leftI ) ); partA.tKordinaten->add( polygon._.tKordinaten->get( leftI ) ); for( int i = leftIE; i != rightI; i-- ) { if( i < 0 ) i += anz; if( i == rightI ) break; *partB.schwerpunkt += polygon._.vertex->get( i ); partB.vertex->add( polygon._.vertex->get( i ) ); partB.tKordinaten->add( polygon._.tKordinaten->get( i ) ); } *partB.schwerpunkt += polygon._.vertex->get( rightI ); partB.vertex->add( polygon._.vertex->get( rightI ) ); partB.tKordinaten->add( polygon._.tKordinaten->get( rightI ) ); *partA.schwerpunkt /= (float)partA.vertex->getEintragAnzahl(); *partB.schwerpunkt /= (float)partB.vertex->getEintragAnzahl(); posA = (Punkt)*partA.schwerpunkt; posB = (Punkt)*partB.schwerpunkt; for( int i = 0; i < partA.vertex->getEintragAnzahl(); i++ ) partA.vertex->set( partA.vertex->get( i ) - *partA.schwerpunkt, i ); for( int i = 0; i < partB.vertex->getEintragAnzahl(); i++ ) partB.vertex->set( partB.vertex->get( i ) - *partB.schwerpunkt, i ); *partA.schwerpunkt = Vertex( 0, 0 ); *partB.schwerpunkt = Vertex( 0, 0 ); } } } return ret; } float Model2DData::getMasse() const { float m = 0; for( auto p = polygons->getIterator(); p; p++ ) { if( p._.transparent ) continue; int anz = p._.vertex->getEintragAnzahl(); if( anz < 3 ) continue; Vertex p1 = p._.vertex->get( anz - 1 ); Vertex p2 = p._.vertex->get( 0 ); m += ( p1.y + p2.y ) * ( p1.x - p2.x ); for( int i = 1; i < anz; i++ ) { p1 = p._.vertex->get( i - 1 ); p2 = p._.vertex->get( i ); m += ( p1.y + p2.y ) * ( p1.x - p2.x ); } } m *= 0.5f; return m; } // Reference Counting Model2DData *Model2DData::getThis() { ref++; return this; } Model2DData *Model2DData::release() { ref--; if( !ref ) delete this; return 0; } // Inhalt der Model2D Klasse aus Model2D.h // Konstruktor Model2DObject::Model2DObject() : Object2D() { rData = 0; textur = new RCArray< Textur2D >(); ref = 1; } // Destruktor Model2DObject::~Model2DObject() { if( rData ) rData->release(); textur->release(); } // nicht constant void Model2DObject::setModel( Model2DData *mdl ) { if( rData ) rData->release(); rData = mdl; } void Model2DObject::setTextur( Textur2D *t ) { int index = 0; if( rData ) { for( auto i = rData->polygons->getIterator(); i; i++ ) textur->set( t->getThis(), index++ ); } t->release(); } void Model2DObject::impuls( Vertex start, Vertex speed ) { start = getObjectPos( start ); speed = getObjectDir( speed ); if( rData ) { Vertex resSpeed; float resRotSpeed = 0; Vertex hp; Vertex mSpeed; float rSpeed; float dist = INFINITY; for( auto p = rData->polygons->getIterator(); p; p++ ) { if( !p._.transparent && rData->calcHitPoint( start, speed, p._.name->getText(), hp, mSpeed, rSpeed ) ) { float f = ( hp.x - start.x ) / speed.x; if( !speed.x ) f = ( hp.y - start.y ) / speed.y; if( ( hp - start ).getLengthSq() < dist && f > 0 ) { resSpeed = mSpeed.rotation( rotation ); resRotSpeed = rSpeed; dist = ( hp - start ).getLengthSq(); } } } // TODO schleife über alle polygone und translation von start und speed in Object koordinaten if( dist < INFINITY ) { this->speed += resSpeed; this->rSpeed += resRotSpeed; } } } void Model2DObject::setTextur( Textur2D *t, const char *polygonName ) { int index = 0; for( auto i = rData->polygons->getIterator(); i; i++, index++ ) { if( i._.name->istGleich( polygonName ) ) textur->set( t->getThis(), index ); } t->release(); } void Model2DObject::render( Mat3< float > &kamMat, Bild &zRObj, const char *kamName ) { if( !rData || !rData->polygons || !textur ) return; int num = 0; for( auto p = rData->vListen->getIterator(); p; p++, num++ ) { Mat3< float > mat = kamMat * getObjectMatrix(); if( textur->z( num ) ) { Bild *txt = textur->z( num )->zTextur(); for( auto i = p->getIterator(); i && txt; i++ ) { for( auto j = i->zListe()->getIterator(); j.hasNext() && j.next().hasNext(); j++ ) { Vertex a = mat * *j->punkt; Vertex b = mat * *j.next()->punkt; Vertex c = mat * *j.next().next()->punkt; Punkt ta = (Punkt)Vertex( j->textur->x * (float)txt->getBreite(), j->textur->y * (float)txt->getHeight() ); Punkt tb = (Punkt)Vertex( j.next()->textur->x * (float)txt->getBreite(), j.next()->textur->y * (float)txt->getHeight() ); Punkt tc = (Punkt)Vertex( j.next().next()->textur->x * (float)txt->getBreite(), j.next().next()->textur->y * (float)txt->getHeight() ); zRObj.drawDreieckTexturAlpha( a, b, c, ta, tb, tc, *txt ); } } } } /* Draws 2D Mesh for( auto *p = &rData->vListen->getIterator(); p && p->set; p = p->next, num++ ) { Mat3< float > mat = kamMat * getObjectMatrix(); for( auto *i = &p->var->getArray(); i && i->set; i = i->next ) { for( auto *j = &i->var->zListe()->getArray(); j->next->next && j->next->next->set; j = j->next ) { Vertex a = mat * *j->var->punkt; Vertex b = mat * *j->next->var->punkt; Vertex c = mat * *j->next->next->var->punkt; zRObj.drawLinie( a, b, 0xFFFFFFFF ); zRObj.drawLinie( a, c, 0xFFFFFFFF ); zRObj.drawLinie( b, c, 0xFFFFFFFF ); } } } */ } // constant bool Model2DObject::istPunktInnen( Vertex p ) const { if( !rData ) return 0; p -= position; if( p < Mat3< float >::scaling( size ) * rData->minP || p > Mat3< float >::scaling( size ) * rData->maxP || !rData->polygons ) return 0; int num = 0; Mat3< float > mat = Mat3< float >::rotation( -rotation ) * Mat3< float >::scaling( 1 / size ); p = mat * p; for( auto polygon = rData->polygons->getIterator(); polygon; polygon++, num++ ) { if( polygon._.transparent ) continue; bool c = 0; for( auto point = polygon._.vertex->getIterator(); point; point++ ) { Vertex a; if( point.next() ) a = point.next(); else a = polygon._.vertex->get( 0 ); Vertex b = point; if( ( ( a.y >= p.y ) != ( b.y >= p.y ) ) && ( p.x <= ( b.x - a.x ) * ( p.y - a.y ) / (float)( b.y - a.y ) + a.x ) ) c = !c; } if( c ) return 1; } return 0; } bool Model2DObject::istLinieInnen( Vertex a, Vertex b ) const { if( !rData || !rData->polygons ) return 0; int pAnz = rData->polygons->getEintragAnzahl(); for( int p = 0; p < pAnz; p++ ) { if( rData->polygons->get( p ).transparent ) continue; Mat3< float > mat = Mat3< float >::rotation( rotation ) * Mat3< float >::scaling( size ); int anz = rData->polygons->get( p ).vertex->getEintragAnzahl(); int j = anz - 1; for( int i = 0; i < anz; i++ ) { Punkt va = mat * rData->polygons->get( p ).vertex->get( i ); Punkt vb = mat * rData->polygons->get( p ).vertex->get( j ); if( (Punkt)a == position + va && (Punkt)b == position + vb ) return 1; if( (Punkt)a == position + vb && (Punkt)b == position + va ) return 1; j = i; } Vertex len = b - a; Vertex speed( len.x > 0 ? 1 : -1.f, len.y > 0 ? 1 : -1.f ); int mLen = 0; if( fabs( len.x ) > fabs( len.y ) ) { mLen = (int)fabs( len.x ); speed.y = len.y / (float)fabs( len.x ); } else { mLen = (int)fabs( len.y ); speed.x = len.x / (float)fabs( len.y ); } int i = 1; bool inside = 1; for( Vertex vp = speed + a; (Punkt)vp != (Punkt)( b - speed ) && inside && i < mLen - 1; vp += speed, i++ ) inside &= istPunktInnen( vp ); if( inside ) return 1; } return 0; } bool Model2DObject::istModelInnen( const Object2D *zObj, Vertex *sp, bool end ) const { if( !end ) { if( !getBoundingBox().collidesWith( zObj->getBoundingBox() ) ) return 0; } Mat3< float > mat = getObjectMatrix(); for( auto polygon = rData->polygons->getIterator(); polygon; polygon++ ) { if( polygon._.transparent ) continue; int anz = polygon._.vertex->getEintragAnzahl(); for( int i = 0; i < anz; i++ ) { if( zObj->istPunktInnen( mat * polygon._.vertex->get( i ) ) ) { if( sp ) *sp = mat * polygon._.vertex->get( i ); return 1; } } } if( end ) return 0; return zObj->istModelInnen( this, sp, 1 ); } Rect2< float > Model2DObject::getBoundingBox() const { if( rData ) return Rect2< float >{ (Vertex)rData->minP * size + position, (Vertex)rData->maxP * size + position }; return Rect2< float >(); } bool Model2DObject::calcHitPoint( Vertex pos, Vertex dir, Vertex &hitpoint ) const { pos = getObjectPos( pos ); dir = getObjectDir( dir ); Vertex ms; Vertex hp; float rs; float dist = INFINITY; if( rData ) { for( auto p = rData->polygons->getIterator(); p; p++ ) { if( !p._.transparent && rData->calcHitPoint( pos, dir, p._.name->getText(), hp, ms, rs ) ) { float f = ( hp.x - pos.x ) / dir.x; if( !speed.x ) f = ( hp.y - pos.y ) / dir.y; if( ( hp - pos ).getLengthSq() < dist && f > 0 ) { hitpoint = getObjectMatrix() * hp; dist = ( hp - pos ).getLengthSq(); } } } if( dist < INFINITY ) return 1; } return 0; } float Model2DObject::getLuftWiederstand() const { if( !rData ) return 0; float angle = speed.angle( Vertex( 1, 0 ) ); float faktor = -1; if( getDrehung() > PI ) faktor = -faktor; if( getDrehung() < -PI ) faktor = -faktor; Mat3< float > m = Mat3< float >::rotation( rotation + faktor * angle ) * Mat3< float >::scaling( size ); float yMin = INFINITY; float yMax = -INFINITY; for( auto p = rData->polygons->getIterator(); p; p++ ) { if( p._.transparent ) continue; for( auto point = p._.vertex->getIterator(); point; point++ ) { Vertex v = m * point._; if( v.y > yMax ) yMax = v.y; if( v.y < yMin ) yMin = v.y; } } if( yMin != INFINITY ) { return yMax - yMin; } return 0; } float Model2DObject::getMasse() const { if( !rData ) return 0; return abs( rData->getMasse() * size * size ); } // Gibt die Textur des ersten Polygons zurück Textur2D *Model2DObject::getTextur() const { return textur->get( 0 ); } // Gibt die Textur eines Polygons zurück // polygonName: Der Name des Polygons Textur2D *Model2DObject::getTextur( const char *polygonName ) const { int index = 0; for( auto i = rData->polygons->getIterator(); i; i++, index++ ) { if( i._.name->istGleich( polygonName ) ) return textur->get( index ); } return 0; } // Gibt die Textur des ersten Polygons ohne erhöhten Reference Counter zurück Textur2D *Model2DObject::zTextur() const { return textur->z( 0 ); } // Gibt die Textur eines Polygons ohne erhöhten Reference Counter zurück // polygonName: Der Name des Polygons Textur2D *Model2DObject::zTextur( const char *polygonName ) const { int index = 0; for( auto i = rData->polygons->getIterator(); i; i++, index++ ) { if( i._.name->istGleich( polygonName ) ) return textur->z( index ); } return 0; } Model2DData *Model2DObject::getModel() const { return rData ? rData->getThis() : 0; } Model2DData *Model2DObject::zModel() const { return rData; } // Inhalt der Model2D Klasse aus Model2D.h // Konstruktor Model2D::Model2D() : Zeichnung() { farbe = 0; style = 0; rData = 0; drehung = 0; size = 1; textur = new RCArray< Textur2D >; ref = 1; } // Destruktor Model2D::~Model2D() { if( rData ) rData->release(); textur->release(); } // nicht constant void Model2D::setModel( Model2DData *mdl ) { if( rData ) rData->release(); rData = mdl; } void Model2D::setDrehung( float drehung ) { this->drehung = drehung; while( this->drehung > PI * 2 ) this->drehung -= (float)PI * 2; while( this->drehung < 0 ) this->drehung += (float)PI * 2; rend = 1; } void Model2D::addDrehung( float drehung ) { this->drehung += drehung; while( this->drehung > PI * 2 ) this->drehung -= (float)PI * 2; while( this->drehung < 0 ) this->drehung += (float)PI * 2; rend = 1; } void Model2D::setSize( float size ) { this->size = size; rend = 1; } void Model2D::addSize( float size ) { this->size += size; rend = 1; } void Model2D::setTextur( Textur2D *t ) { int index = 0; if( rData ) { for( auto i = rData->polygons->getIterator(); i; i++ ) textur->set( t->getThis(), index++ ); } t->release(); } void Model2D::setTextur( Textur2D *t, const char *polygonName ) { int index = 0; for( auto i = rData->polygons->getIterator(); i; i++, index++ ) { if( i._.name->istGleich( polygonName ) ) textur->set( t->getThis(), index ); } t->release(); } void Model2D::setFarbe( int f ) { farbe = f; rend = 1; } void Model2D::doMausEreignis( MausEreignis &me ) { if( !mak || me.verarbeitet || !istPunktInnen( Punkt( me.mx, me.my ) ) ) return; me.mx -= pos.x; me.my -= pos.y; mak( makParam, this, me ); me.mx += pos.x; me.my += pos.y; me.verarbeitet = 1; } bool Model2D::tick( double tickVal ) { bool ret = rend; rend = 0; return ret; } void Model2D::render( Bild &zRObj ) { if( !rData || hatStyleNicht( Model2D::Style::Sichtbar ) || !rData->polygons ) return; Zeichnung::render( zRObj ); int num = 0; for( auto p = rData->vListen->getIterator(); p; p++, num++ ) { Mat3< float > mat = Mat3< float >::translation( pos ) * Mat3< float >::rotation( drehung ) * Mat3< float >::scaling( size ); if( hatStyle( Model2D::Style::Textur ) ) { if( !textur || !textur->z( num ) || !textur->z( num )->zTextur() || !rData->polygons->get( num ).tKordinaten ) { for( auto i = p->getIterator(); i; i++ ) { for( auto j = i->zListe()->getIterator(); j.hasNext() && j.next().hasNext(); j++ ) { Vertex a = mat * *j->punkt; Vertex b = mat * *j.next()->punkt; Vertex c = mat * *j.next().next()->punkt; if( hatStyle( Model2D::Style::Alpha ) ) zRObj.drawDreieckAlpha( a, b, c, farbe ); else zRObj.drawDreieck( a, b, c, farbe ); } } } else { Bild *txt = textur->z( num )->zTextur(); for( auto i = p->getIterator(); i; i++ ) { for( auto j = i->zListe()->getIterator(); j.hasNext() && j.next().hasNext(); j++ ) { Vertex a = mat * *j->punkt; Vertex b = mat * *j.next()->punkt; Vertex c = mat * *j.next().next()->punkt; Punkt ta = (Punkt)Vertex( j->textur->x * (float)txt->getBreite(), j->textur->y * (float)txt->getHeight() ); Punkt tb = (Punkt)Vertex( j.next()->textur->x * (float)txt->getBreite(), j.next()->textur->y * (float)txt->getHeight() ); Punkt tc = (Punkt)Vertex( j.next().next()->textur->x * (float)txt->getBreite(), j.next().next()->textur->y * (float)txt->getHeight() ); if( hatStyle( Model2D::Style::Alpha ) ) zRObj.drawDreieckTexturAlpha( a, b, c, ta, tb, tc, *txt ); else zRObj.drawDreieckTextur( a, b, c, ta, tb, tc, *txt ); } } } } if( hatStyle( Model2D::Style::Mesh ) ) { for( auto i = p->getIterator(); i; i++ ) { for( auto j = i->zListe()->getIterator(); j.hasNext() && j.next().hasNext(); j++ ) { Vertex a = mat * *j->punkt; Vertex b = mat * *j.next()->punkt; Vertex c = mat * *j.next().next()->punkt; if( hatStyle( Model2D::Style::Alpha ) ) { zRObj.drawLinieAlpha( a, b, farbe ); zRObj.drawLinieAlpha( b, c, farbe ); zRObj.drawLinieAlpha( c, a, farbe ); } else { zRObj.drawLinie( a, b, farbe ); zRObj.drawLinie( b, c, farbe ); zRObj.drawLinie( c, a, farbe ); } } } } if( hatStyle( Model2D::Style::Rahmen ) ) { auto beg = rData->polygons->get( num ).vertex->getIterator(); if( beg ) { Vertex letzter; for( auto e = beg; e && e.hasNext(); e++ ) { if( hatStyle( Model2D::Style::Alpha ) ) zRObj.drawLinieAlpha( mat * e._, mat * e.next()._, farbe ); else zRObj.drawLinie( mat * e._, mat * e.next()._, farbe ); letzter = e.next(); } if( beg.hasNext() ) { if( hatStyle( Model2D::Style::Alpha ) ) zRObj.drawLinieAlpha( mat * letzter, mat * beg._, farbe ); else zRObj.drawLinie( mat * letzter, mat * beg._, farbe ); } } } } } // constant float Model2D::getDrehung() const { return drehung; } float Model2D::getSize() const { return size; } bool Model2D::istPunktInnen( Vertex p ) const { if( !rData ) return 0; p -= pos; if( p < Mat3< float >::scaling( size ) * rData->minP || p > Mat3< float >::scaling( size ) * rData->maxP || !rData->polygons ) return 0; int num = 0; for( auto polygon = rData->polygons->getIterator(); polygon; polygon++, num++ ) { if( polygon._.transparent ) continue; Mat3< float > mat = Mat3< float >::rotation( drehung ) * Mat3< float >::scaling( size ); int anz = polygon._.vertex->getEintragAnzahl(); bool c = 0; int j = anz - 1; for( int i = 0; i < anz; i++ ) { Vertex a = mat * polygon._.vertex->get( i ); Vertex b = mat * polygon._.vertex->get( j ); if( ( ( a.y >= p.y ) != ( b.y >= p.y ) ) && ( p.x <= ( b.x - a.x ) * ( p.y - a.y ) / (float)( b.y - a.y ) + a.x ) ) c = !c; j = i; } if( c ) return 1; } return 0; } bool Model2D::istLinieInnen( Vertex a, Vertex b ) const { if( !rData || !rData->polygons ) return 0; int pAnz = rData->polygons->getEintragAnzahl(); for( int p = 0; p < pAnz; p++ ) { if( rData->polygons->get( p ).transparent ) continue; Mat3< float > mat = Mat3< float >::rotation( drehung ) * Mat3< float >::scaling( size ); int anz = rData->polygons->get( p ).vertex->getEintragAnzahl(); int j = anz - 1; for( int i = 0; i < anz; i++ ) { Punkt va = mat * rData->polygons->get( p ).vertex->get( i ); Punkt vb = mat * rData->polygons->get( p ).vertex->get( j ); if( (Punkt)a == pos + va && (Punkt)b == pos + vb ) return 1; if( (Punkt)a == pos + vb && (Punkt)b == pos + va ) return 1; j = i; } Vertex len = b - a; Vertex speed( len.x > 0 ? 1 : -1.f, len.y > 0 ? 1 : -1.f ); int mLen = 0; if( fabs( len.x ) > fabs( len.y ) ) { mLen = (int)fabs( len.x ); speed.y = len.y / (float)fabs( len.x ); } else { mLen = (int)fabs( len.y ); speed.x = len.x / (float)fabs( len.y ); } int i = 1; bool inside = 1; for( Vertex vp = speed + a; (Punkt)vp != (Punkt)( b - speed ) && inside && i < mLen - 1; vp += speed, i++ ) inside &= istPunktInnen( vp ); if( inside ) return 1; } return 0; } bool Model2D::istModelInnen( const Model2D *zMdl, bool end ) const { if( !end ) { Vertex min = (Vertex)rData->minP * size + pos; Vertex max = (Vertex)rData->maxP * size + pos; Vertex min2 = (Vertex)zMdl->zModel()->minP * zMdl->getSize() + zMdl->getPosition(); Vertex max2 = (Vertex)zMdl->zModel()->maxP * zMdl->getSize() + zMdl->getPosition(); if( max.x < min2.x || min.x > max2.x || max.y < min2.y || min.y > max2.y ) return 0; } Mat3< float > mat = Mat3< float >::translation( pos ) * Mat3< float >::rotation( drehung ) * Mat3< float >::scaling( size ); for( auto polygon = rData->polygons->getIterator(); polygon; polygon++ ) { if( polygon._.transparent ) continue; int anz = polygon._.vertex->getEintragAnzahl(); for( int i = 0; i < anz; i++ ) { if( zMdl->istPunktInnen( mat * polygon._.vertex->get( i ) ) ) return 1; } } if( end ) return 0; return zMdl->istModelInnen( this, 1 ); } Model2DData *Model2D::getModel() const { return rData ? rData->getThis() : 0; } Model2DData *Model2D::zModel() const { return rData; } // Reference Counting Model2D *Model2D::getThis() { ++ref; return this; } Model2D *Model2D::release() { --ref; if( !ref ) delete this; return 0; }