#include "Model2D.h" #include "Bild.h" #include "FrameworkMath.h" #include "Mat3.h" #include "MausEreignis.h" #include "Textur2D.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* polygons) { removeModell(); if (!polygons || !polygons->getEintragAnzahl()) { this->polygons = polygons; vListen = new RCArray>>(); return 1; } this->polygons = polygons; int pAnz = polygons->getEintragAnzahl(); vListen = new RCArray>>(); for (int p = 0; p < pAnz; p++) { Polygon2D pg = polygons->get(p); if (!pg.vertex || pg.vertex->getEintragAnzahl() < 3) continue; vListen->add(new RCArray>()); outList.add(new Array); 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>> lists; int lauf = 0; while (1) { lists.add(new RCArray>()); outList.z(p)->add(Punkt(0, 0)); bool fertig = 0; Vertex a; Vertex b; Array 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* lowL = new DreieckListe(); DreieckListe* heightL = new DreieckListe(); 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()); 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>>*)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 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(); partA.name = new Text(polygon.name->getText()); partA.vertex = new Array(); partB.transparent = polygon.transparent; partB.schwerpunkt = new Vertex(0, 0); partB.tKordinaten = new Array(); partB.name = new Text(polygon.name->getText()); partB.vertex = new Array(); *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(); } // 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& kamMat, Bild& zRObj, const char* kamName) { if (!rData || !rData->polygons || !textur) return; int num = 0; for (auto p : *rData->vListen) { Mat3 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::scaling(size) * rData->minP || p > Mat3::scaling(size) * rData->maxP || !rData->polygons) return 0; Mat3 mat = Mat3::rotation(-rotation) * Mat3::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 mat = Mat3::rotation(rotation) * Mat3::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 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 Model2DObject::getBoundingBox() const { if (rData) return Rect2{(Vertex)rData->minP * size + position, (Vertex)rData->maxP * size + position}; return Rect2(); } 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 m = Mat3::rotation(rotation + faktor * angle) * Mat3::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; } // 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 mat = Mat3::translation(pos) * Mat3::rotation(drehung) * Mat3::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::scaling(size) * rData->minP || p > Mat3::scaling(size) * rData->maxP || !rData->polygons) return 0; for (Polygon2D polygon : *rData->polygons) { if (polygon.transparent) continue; Mat3 mat = Mat3::rotation(drehung) * Mat3::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 mat = Mat3::rotation(drehung) * Mat3::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 mat = Mat3::translation(pos) * Mat3::rotation(drehung) * Mat3::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; }