#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() : ReferenceCounter(), polygons( 0 ), vListen( 0 ), minP( 0, 0 ), maxP( 0, 0 ) {} // 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 = (Array *)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.begin(); for( auto polygon = polygons->begin(); 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->begin(); 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->begin(); for( int i = 0; i < anz; i++, point++ ) { bool cont = 0; for( auto outListPP = outListP->begin(); 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.add( new Array< Punkt > ); 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( (float)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( (float)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.add( new RCArray< DreieckListe< Vertex > >() ); outList.z( p )->add( Punkt( 0, 0 ) ); 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 )->add( lowL ); tmpOutList.add( outL ); heightL->release(); } else { lists.z( lauf )->add( heightL ); tmpOutList.add( outH ); lowL->release(); } } else lists.z( lauf )->add( new DreieckListe< Vertex >() ); if( fertig ) break; } int maxP = -1; int max = 0; for( int i = 0; i < vAnz; i++ ) { if( lists.z( lauf )->hat( 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 = (Array*)polygons->release(); } if( vListen ) vListen = (RCArray< RCArray< DreieckListe< Vertex > > > *)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 { if( dir.x == 0 && dir.y == 0 ) return 0; bool ret = 0; for( Polygon2D polygon : *polygons ) { 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 ) { if( b.y == 0 ) continue; offset = (pos.y - a.y) / b.y; } else if( dir.x == 0 ) { if( b.x == 0 ) continue; 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; if( isnan( moveSpeed.x ) || isnan( moveSpeed.y ) || isnan( rotSpeed ) ) return 0; 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( Polygon2D polygon : *polygons ) { 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 ); } } num++; } return ret; } float Model2DData::getMasse() const { float m = 0; for( Polygon2D p : *polygons ) { 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; } // Inhalt der Model2D Klasse aus Model2D.h // Konstruktor Model2DObject::Model2DObject() : Object2D() { rData = 0; textur = new RCArray< Textur2D >(); } // 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 ) { if( rData ) { textur->leeren(); for( int i = 0; i < rData->polygons->getEintragAnzahl(); i++ ) textur->add( dynamic_cast(t->getThis()) ); } t->release(); } void Model2DObject::impuls( Vertex start, Vertex speed, float strength ) { start = getObjectPos( start ); speed = getObjectDir( speed ); if( rData ) { Vertex resSpeed; float resRotSpeed = 0; Vertex hp; Vertex mSpeed; float rSpeed; float dist = INFINITY; for( Polygon2D p : *rData->polygons ) { 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 * strength; this->rSpeed += resRotSpeed * strength; } } } void Model2DObject::setTextur( Textur2D* t, const char* polygonName ) { int index = 0; for( Polygon2D i : *rData->polygons ) { if( i.name->istGleich( polygonName ) ) textur->set( dynamic_cast(t->getThis()), index ); 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 ) { Mat3< float > mat = kamMat * getObjectMatrix(); if( textur->hat( num ) ) { Bild* txt = textur->z( num )->zTextur(); for( auto i = p->begin(); i && txt; i++ ) { for( auto j = i->zListe()->begin(); 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() - 1), j->textur->y * (float)(txt->getHeight() - 1) ); Punkt tb = (Punkt)Vertex( j.next()->textur->x * (float)(txt->getBreite() - 1), j.next()->textur->y * (float)(txt->getHeight() - 1) ); Punkt tc = (Punkt)Vertex( j.next().next()->textur->x * (float)(txt->getBreite() - 1), j.next().next()->textur->y * (float)(txt->getHeight() - 1) ); zRObj.drawDreieckTexturAlpha( a, b, c, ta, tb, tc, *txt ); } } } num++; } /* 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, bool ignoreTransparent ) 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; Mat3< float > mat = Mat3< float >::rotation( -rotation ) * Mat3< float >::scaling( 1 / size ); p = mat * p; for( Polygon2D polygon : *rData->polygons ) { if( polygon.transparent && !ignoreTransparent ) continue; bool c = 0; for( auto point = polygon.vertex->begin(); 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, bool ignoreTransparent ) 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 && !ignoreTransparent ) 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, ignoreTransparent ); if( inside ) return 1; } return 0; } bool Model2DObject::istModelInnen( const Object2D* zObj, Vertex* sp, bool end, bool ignoreTransparent ) const { if( !end ) { if( !getBoundingBox().collidesWith( zObj->getBoundingBox() ) ) return 0; } Mat3< float > mat = getObjectMatrix(); for( Polygon2D polygon : *rData->polygons ) { if( polygon.transparent && !ignoreTransparent ) continue; int anz = polygon.vertex->getEintragAnzahl(); for( int i = 0; i < anz; i++ ) { if( zObj->istPunktInnen( mat * polygon.vertex->get( i ), ignoreTransparent ) ) { if( sp ) *sp = mat * polygon.vertex->get( i ); return 1; } } } if( end ) return 0; return zObj->istModelInnen( this, sp, 1, ignoreTransparent ); } 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( Polygon2D p : *rData->polygons ) { 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( Polygon2D p : *rData->polygons ) { if( p.transparent ) continue; for( Vertex point : *p.vertex ) { 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( Polygon2D p : *rData->polygons ) { if( p.name->istGleich( polygonName ) ) return textur->get( index ); 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( Polygon2D p : *rData->polygons ) { if( p.name->istGleich( polygonName ) ) return textur->z( index ); index++; } return 0; } Model2DData* Model2DObject::getModel() const { return rData ? dynamic_cast(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 >; } // 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 ) { if( rData ) { for( int i = 0; i < rData->polygons->getEintragAnzahl(); i++ ) textur->set( dynamic_cast(t->getThis()), i ); } t->release(); } void Model2D::setTextur( Textur2D* t, const char* polygonName ) { int index = 0; for( Polygon2D p : *rData->polygons ) { if( p.name->istGleich( polygonName ) ) textur->set( dynamic_cast(t->getThis()), index ); index++; } t->release(); } void Model2D::setFarbe( int f ) { farbe = f; rend = 1; } bool Model2D::tick( double tickVal ) { return Zeichnung::tick( tickVal ); } 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 ) { 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 ) { for( auto j = i->zListe()->begin(); 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 ) { for( auto j = i->zListe()->begin(); 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() - 1), j->textur->y * (float)(txt->getHeight() - 1) ); Punkt tb = (Punkt)Vertex( j.next()->textur->x * (float)(txt->getBreite() - 1), j.next()->textur->y * (float)(txt->getHeight() - 1) ); Punkt tc = (Punkt)Vertex( j.next().next()->textur->x * (float)(txt->getBreite() - 1), j.next().next()->textur->y * (float)(txt->getHeight() - 1) ); 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 ) { for( auto j = i->zListe()->begin(); 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->begin(); 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 ); } } } num++; } } // constant float Model2D::getDrehung() const { return drehung; } float Model2D::getSize() const { return size; } // Gibt zurück, ob ein Punkt in dem Model enthalten ist // p: Der Punkt bool Model2D::istPunktInnen( int x, int y ) const { return istPunktInnen( Vertex( (float)x, (float)y ) ); } 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; for( Polygon2D polygon : *rData->polygons ) { 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( Polygon2D polygon : *rData->polygons ) { 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 ? dynamic_cast(rData->getThis()) : 0; } Model2DData* Model2D::zModel() const { return rData; }