diff --git a/geometry/triangle.hh b/geometry/triangle.hh index 6c3c3bb..61392df 100644 --- a/geometry/triangle.hh +++ b/geometry/triangle.hh @@ -41,4 +41,29 @@ public : Triangle insetProportionnal(float prop); }; +class TriBool { + private: + bool c[3]; + + public : + TriBool(); + TriBool(bool leftside, bool rightside, bool base) { + c[LEFTSIDE] = leftside; + c[RIGHTSIDE] = rightside; + c[BASE] = base; + }; + inline bool& operator[] (CoteTriangle x) { + return c[x]; + } + inline const bool& operator[] (CoteTriangle x) const { + return c[x]; + } + inline TriBool operator>> (int rot) const { + return TriBool(c[LEFTSIDE - rot], c[RIGHTSIDE - rot], c[BASE - rot]); + } + inline TriBool operator<< (int rot) const { + return TriBool(c[LEFTSIDE + rot], c[RIGHTSIDE + rot], c[BASE + rot]); + } +}; + #endif diff --git a/rules/batiment.cpp b/rules/batiment.cpp index 0e7a9f4..7f1435e 100644 --- a/rules/batiment.cpp +++ b/rules/batiment.cpp @@ -63,7 +63,6 @@ void BatimentQuad::sousBatiments() { } void BatimentQuad::etages() { - // TODO : indiquer aux bâtiments où est-ce qu'ils peuvent faire des fenêtres. float randEtages = floatInRange(seed, 0, 0.f, 1.f); int nbEtages = 1 + (int)(randEtages * randEtages * (Dimensions::maxEtages - 1)); Quad q = c; // c.insetNESW(30) @@ -91,21 +90,92 @@ void BatimentQuad::getBoundingBoxPoints() { addBBPoints(c, Dimensions::hauteurEtage * 2 + Dimensions::hauteurToit); } -BatimentTri_::BatimentTri_(Triangle _c) : Chose(), c(_c) { +BatimentTri::BatimentTri(Triangle _c, bool _isSub, TriBool _w) + : Chose(), c(_c), isSub(_isSub), w(_w) { addEntropy(c); + for (int i = 0; i < 3; i++) + addEntropy(w[LEFTSIDE+i] ? 0 : 1); } -void BatimentTri_::split() { - // TODO : BatimentTri::split() +void BatimentTri::split() { + if (!isSub) { + bordureRouteTrottoir(); + } else { + if (w[LEFTSIDE] || w[RIGHTSIDE] || w[BASE]) { + if (c.surface() > 2 * Dimensions::minSurfaceSousBatiment) { + sousBatiments(); + } else { + etages(); + } + } else { + addChild(new TerrainTri(c)); + } + } } -void BatimentTri_::triangulation() { +void BatimentTri::triangulation() { Triangle th = c.offsetNormal(Dimensions::hauteurEtage * 2 + Dimensions::hauteurToit); addGPUTriangle(th, Couleurs::toit); for (int i = 0; i < 3; i++) addGPUQuad(Quad(c[LEFT+i], c[TOP+i], th[TOP+i], th[LEFT+i]), Couleurs::mur); } -void BatimentTri_::getBoundingBoxPoints() { +void BatimentTri::getBoundingBoxPoints() { addBBPoints(c, Dimensions::hauteurEtage * 2 + Dimensions::hauteurToit); } + +void BatimentTri::bordureRouteTrottoir() { + Triangle tinterieur = c.insetLTR(Dimensions::largeurRoute + Dimensions::largeurTrottoir); + Triangle tbatiments = tinterieur.offsetNormal(Dimensions::hauteurTrottoir); + + for (int i = 0; i < 4; i++) { + addChild(new RouteTrottoirQuad(Quad(c[LEFT+i],c[TOP+i],tinterieur[TOP+i],tinterieur[LEFT+i]))); + } + + bool anglesAcceptable = c.minAngle() > Angle::d2r(90-60) && c.maxAngle() < Angle::d2r(90+60); + + if (anglesAcceptable && proba(seed, 0, 0.95f)) { + addChild(new BatimentTri(tbatiments, true)); + } else { + addChild(new TerrainTri(tbatiments)); + } +} + +void BatimentTri::sousBatiments() { + Triangle t = c << c.minAngleCorner(); + TriBool tb = w << c.minAngleCorner(); + + // TODO : ajuster pour que la distance c[LEFT] -- left et c[LEFT] -- base soit similaire. + Vertex left = Segment(t[LEFT], t[TOP]).randomPos(seed, 0, 1.f/3.f, 2.f/3.f); + float dLeft = Segment(t[LEFT], left).length(); + float posBase = dLeft / Segment(t[LEFT], t[RIGHT]).length(); + if (posBase < 0.3f) posBase = 0.2f; + else if (posBase > 0.7f) posBase = 0.8f; + Vertex base = Segment(t[RIGHT], t[LEFT]).randomPos(seed, 1, posBase - 0.1f, posBase + 0.1f); + + bool small = t.surface() < 4 * Dimensions::minSurfaceSousBatiment; + + if (small && (tb[LEFTSIDE] || tb[RIGHTSIDE]) && proba(seed, 2, 0.3f)) { + addChild(new TerrainTri(Triangle(base, t[LEFT], left))); + addChild(new BatimentQuad(Quad(base, left, t[TOP], t[RIGHT]), true, QuadBool(true, w[LEFTSIDE], w[RIGHTSIDE], w[BASE]))); + } else if (small && (tb[LEFTSIDE] || tb[RIGHTSIDE] || tb[BASE]) && proba(seed, 2, 0.3f)) { + addChild(new BatimentTri(Triangle(base, t[LEFT], left), true, TriBool(w[BASE], w[LEFTSIDE], true))); + addChild(new TerrainQuad(Quad(base, left, t[TOP], t[RIGHT]))); + } else { + addChild(new BatimentTri(Triangle(base, t[LEFT], left), true, TriBool(w[BASE], w[LEFTSIDE], false))); + addChild(new BatimentQuad(Quad(base, left, t[TOP], t[RIGHT]), true, QuadBool(false, w[LEFTSIDE], w[RIGHTSIDE], w[BASE]))); + } +} + +void BatimentTri::etages() { + float randEtages = floatInRange(seed, 0, 0.f, 1.f); + int nbEtages = 1 + (int)(randEtages * randEtages * (Dimensions::maxEtages - 1)); + Triangle t = c; // c.insetNESW(30) + Triangle th; + for (int i = 0; i < nbEtages; i++) { + th = t.offsetNormal(floatInRange(seed, 1+i, Dimensions::hauteurEtage*0.9f, Dimensions::hauteurEtage*1.1f)); + addChild(new EtageTri(t, th, w, i, nbEtages)); + t = th; + } + addChild(new ToitTri(th, Dimensions::hauteurToit)); +} diff --git a/rules/batiment.hh b/rules/batiment.hh index 4988151..eda3928 100644 --- a/rules/batiment.hh +++ b/rules/batiment.hh @@ -20,11 +20,17 @@ public: BatimentQuad* isSubdivision(bool val); }; -class BatimentTri_ : public Chose { +class BatimentTri : public Chose { +private: Triangle c; + bool isSub; + TriBool w; + void bordureRouteTrottoir(); + void sousBatiments(); + void etages(); public: - BatimentTri_(Triangle _c); + BatimentTri(Triangle _c, bool _isSub = false, TriBool _w = TriBool(true, true, true)); virtual void split(); virtual void triangulation(); virtual void getBoundingBoxPoints(); diff --git a/rules/couleursDimensions.hh b/rules/couleursDimensions.hh index c7ac992..8479816 100644 --- a/rules/couleursDimensions.hh +++ b/rules/couleursDimensions.hh @@ -45,7 +45,7 @@ public: static const unsigned int hauteurTrottoir = 20; static const unsigned int hauteurMaxBatiment = hauteurTrottoir + hauteurEtage * 2 + hauteurToit; static const unsigned int minSurfaceSousBatiment = 100 * 100*100; // 100 m² - static const unsigned int minRayonPlace = 50 * 100; // 60 m + static const unsigned int minRayonPlace = 30 * 100; // 60 m static const unsigned int maxRayonPlace = 2 * minRayonPlace; // 60 m // Qualité diff --git a/rules/etage.cpp b/rules/etage.cpp index a6de9df..e77ce61 100644 --- a/rules/etage.cpp +++ b/rules/etage.cpp @@ -68,3 +68,43 @@ void EtageQuad::triangulation() { addGPUQuad(ch.offsetNormal(-30), Couleurs::plafond); addGPUQuad(c, Couleurs::plancher); } + +EtageTri::EtageTri(Triangle _c, Triangle _ch, TriBool _w, int _etage, int _nbEtages) : Chose(), c(_c), ch(_ch), w(_w), etage(_etage), nbEtages(_nbEtages) { + addEntropy(c); + addEntropy(ch); + for (int i = 0; i < 3; i++) + addEntropy(w[LEFTSIDE+i] ? 0 : 1); +} + +void EtageTri::getBoundingBoxPoints() { + addBBPoints(c); + addBBPoints(ch); +} + +void EtageTri::split() { + Triangle small = c.insetLTR(28); + Triangle smallh = ch.insetLTR(28); + + TriBool d(false,false,false); + + if(etage == 0) { + if(w[LEFTSIDE]) d[LEFTSIDE] = true; + else if(w[RIGHTSIDE]) d[RIGHTSIDE] = true; + else if(w[BASE]) d[BASE] = true; + } + + for (int i = 0; i < 3; i++) { + Quad q = Quad(c[TOP+i], small[TOP+i], small[LEFT+i], c[LEFT+i]); + Quad qh = Quad(ch[TOP+i], smallh[TOP+i], smallh[LEFT+i], ch[LEFT+i]); + addChild(new MurQuad(q, qh, w[LEFTSIDE+i]^d[LEFTSIDE+i],false,false,d[LEFTSIDE+i])); + } + + addChild(new PlancherPlafondTri(c, PlancherPlafondTri::PLANCHER)); + addChild(new PlancherPlafondTri(ch.offsetNormal(-10), PlancherPlafondTri::PLAFOND)); +} + +void EtageTri::triangulation() { + addGPUThreeQuads(c,ch, Couleurs::mur); + addGPUTriangle(ch.offsetNormal(-30), Couleurs::plafond); + addGPUTriangle(c, Couleurs::plancher); +} diff --git a/rules/etage.hh b/rules/etage.hh index f7f12ff..a26ced6 100644 --- a/rules/etage.hh +++ b/rules/etage.hh @@ -3,7 +3,6 @@ #include "all_includes.hh" - class EtageQuad : public Chose { private : Quad c; @@ -19,4 +18,19 @@ class EtageQuad : public Chose { virtual void getBoundingBoxPoints(); }; +class EtageTri : public Chose { + private : + Triangle c; + Triangle ch; + TriBool w; + int etage; + int nbEtages; + + public : + EtageTri(Triangle c, Triangle ch, TriBool _w, int _etage, int _nbEtages); + virtual void split(); + virtual void triangulation(); + virtual void getBoundingBoxPoints(); +}; + #endif diff --git a/rules/mur.cpp b/rules/mur.cpp index 24cba7f..dd27c7f 100644 --- a/rules/mur.cpp +++ b/rules/mur.cpp @@ -75,3 +75,19 @@ void PlancherPlafond::triangulation() { void PlancherPlafond::getBoundingBoxPoints() { addBBPoints(c); } + +PlancherPlafondTri::PlancherPlafondTri(Triangle _c, Type _type) : Chose(), c(_c), type(_type) { + addEntropy(c); + addEntropy((int)type); +} + +void PlancherPlafondTri::triangulation() { + unsigned int clr = Couleurs::plancher; + if (type == PLAFOND) + clr = Couleurs::plafond; + addGPUTriangle(c, clr); +} + +void PlancherPlafondTri::getBoundingBoxPoints() { + addBBPoints(c); +} diff --git a/rules/mur.hh b/rules/mur.hh index 27670b8..fe846bf 100644 --- a/rules/mur.hh +++ b/rules/mur.hh @@ -39,5 +39,21 @@ public: virtual void getBoundingBoxPoints(); }; +class PlancherPlafondTri: public Chose { +public: + enum Type { + PLANCHER, + PLAFOND + }; +private: + Triangle c; + Type type; + +public: + PlancherPlafondTri(Triangle _c, Type _type); + virtual void triangulation(); + virtual void getBoundingBoxPoints(); +}; + #endif diff --git a/rules/quartier.cpp b/rules/quartier.cpp index 2305286..716a82c 100644 --- a/rules/quartier.cpp +++ b/rules/quartier.cpp @@ -163,8 +163,8 @@ void QuartierTri::getBoundingBoxPoints() { } void QuartierTri::split() { - bool small = c.minLength() < 6000; - bool big = c.maxLength() >= 10000; + bool small = c.minLength() < 80 * 100; + bool big = c.maxLength() >= 150 * 100; float minAngle = c.minAngle(); float maxAngle = c.maxAngle(); bool equilateral = maxAngle < Angle::d2r(60+15) && minAngle > Angle::d2r(60-15); @@ -172,7 +172,7 @@ void QuartierTri::split() { bool angleAigu = minAngle < Angle::d2r(30); bool anglesAcceptable = !angleAigu && !angleObtus; if (!big && proba(seed, -1, 0.05f)) { - batiments(); // TODO : addChild(new BatimentTri_(c)); + addChild(new BatimentTri(c)); } else if (big && anglesAcceptable) { switch (hash2(seed, -2) % 3) { case 0: centre(); break; @@ -187,7 +187,7 @@ void QuartierTri::split() { } else if (!small) { trapeze(); } else { - batiments(); // TODO : addChild(new BatimentTri_(c)); + addChild(new BatimentTri(c)); } } @@ -228,24 +228,3 @@ void QuartierTri::trapeze() { addChild(new QuartierTri(Triangle(base, t[LEFT], left))); addChild(new QuartierQuad(Quad(base, left, t[TOP], t[RIGHT]))); } - -void QuartierTri::batiments() { - Triangle tinterieur = c.insetLTR(Dimensions::largeurRoute + Dimensions::largeurTrottoir); - Triangle tbatiments = tinterieur.offsetNormal(Dimensions::hauteurTrottoir); - - for (int i = 0; i < 3; i++) { - addChild(new RouteTrottoirQuad(Quad(c[LEFT+i],c[TOP+i],tinterieur[TOP+i],tinterieur[LEFT+i]))); - } - - bool small = tbatiments.minLength() < 3000; - bool big = tbatiments.maxLength() >= 5000; - bool anglesAcceptable = tbatiments.minAngle() > Angle::d2r(30) && tbatiments.maxAngle() < Angle::d2r(120); - - if (!big && proba(seed, 0, 0.05f)) { - addChild(new TerrainTri(tbatiments)); - } else if (small && anglesAcceptable) { - addChild(new BatimentTri_(tbatiments)); - } else { - addChild(new TerrainTri(tbatiments)); - } -} diff --git a/rules/quartier.hh b/rules/quartier.hh index e299093..eb57444 100644 --- a/rules/quartier.hh +++ b/rules/quartier.hh @@ -34,7 +34,6 @@ private: void centre(); void hauteur(); void trapeze(); - void batiments(); }; #endif diff --git a/rules/terrain.cpp b/rules/terrain.cpp index 35b34e6..0bfc7d2 100644 --- a/rules/terrain.cpp +++ b/rules/terrain.cpp @@ -37,10 +37,35 @@ void TerrainQuad::triangulation() { addGPUQuad(c, Couleurs::herbe); } -TerrainTri::TerrainTri(Triangle _c) : Chose(), c(_c) { +TerrainTri::TerrainTri(Triangle _c, bool _addTrees) : Chose(), c(_c), addTrees(_addTrees) { addEntropy(c); } +void TerrainTri::split() { + if (!addTrees) return; + + addChild(new TerrainTri(c, false)); + + Vertex p[10]; + int maxNArbres = std::min(10, (int)(c.surface() / (7.f*7.f*100.f*100.f))); + int pi = 0; + int nArbres = hash2(seed, -1) % (maxNArbres + 1); + for (int essai = 0; essai < nArbres * 2 && pi < nArbres; essai++) { + p[pi] = c.insetProportionnal(0.7f).randomPoint(seed, essai); + bool success = true; + for (int j = 0; j < pi; j++) { + if (Segment(p[j], p[pi]).length() < 3 * 100) { + success = false; + break; + } + } + if (success) pi++; + } + for (int i = 0; i < pi; i++) { + addChild(new Arbre(p[i], c)); + } +} + void TerrainTri::getBoundingBoxPoints() { addBBPoints(c); } diff --git a/rules/terrain.hh b/rules/terrain.hh index a845df2..f13f482 100644 --- a/rules/terrain.hh +++ b/rules/terrain.hh @@ -3,16 +3,6 @@ #include "all_includes.hh" -class TerrainTri : public Chose { - private : - Triangle c; - - public : - TerrainTri(Triangle _c); - virtual void triangulation(); - virtual void getBoundingBoxPoints(); -}; - class TerrainQuad : public Chose { private : Quad c; @@ -25,4 +15,16 @@ class TerrainQuad : public Chose { virtual void getBoundingBoxPoints(); }; +class TerrainTri : public Chose { + private : + Triangle c; + bool addTrees; + + public : + TerrainTri(Triangle _c, bool _addTrees = true); + virtual void split(); + virtual void triangulation(); + virtual void getBoundingBoxPoints(); +}; + #endif diff --git a/rules/toit.cpp b/rules/toit.cpp index 12a9d95..60d2f7b 100644 --- a/rules/toit.cpp +++ b/rules/toit.cpp @@ -12,6 +12,8 @@ void ToitQuad::getBoundingBoxPoints() { } void ToitQuad::triangulation() { + // TODO : si angles pas acceptables, plat(). + // TODO : toit plat : surélever. switch (hash2(seed, -1) % 5) { case 0: pointCentral(); break; case 1: quatrePoints(); break; @@ -97,6 +99,7 @@ void ToitTri::getBoundingBoxPoints() { } void ToitTri::triangulation() { + plat(); return; switch (hash2(seed, -1) % 5) { case 0: pointCentral(); break; case 1: troisPoints(); break; diff --git a/view.cpp b/view.cpp index d1445f9..26d45c2 100644 --- a/view.cpp +++ b/view.cpp @@ -300,6 +300,7 @@ void Camera::keyboard(const SDL_KeyboardEvent &eventKey) { up = true; break; case 'e' : + moveSensitivity = 1500; autoPilot = true; break; case 'z' : @@ -350,7 +351,6 @@ void Camera::animation(int elapsedTime) { float diff = ((float)(elapsedTime+1)/1000.f)*(float)moveSensitivity; if (autoPilot) { - moveSensitivity = 1500; float dx = floatInRange(frame/16, 42, -0.5, 0.5); float olddx = floatInRange(frame/16 - 1, 42, -0.5, 0.5); float mix = ((float)(frame % 16) / 16.f); @@ -359,7 +359,6 @@ void Camera::animation(int elapsedTime) { cameraCenter = cameraCenter + Vertex::fromSpherical(diff, yAngle, xAngle); cameraCenter.z = oldz; cameraCenter.z += std::min(20.f, std::max(-20.f, 1750 - cameraCenter.z)); - return; } if(up)