diff --git a/main.cpp b/main.cpp index af1a05a..567e1a4 100644 --- a/main.cpp +++ b/main.cpp @@ -16,12 +16,13 @@ void recursiveSubdivide(Chose* c) { int main() { // Générer une tile de base - int size = 50; + int size = 20000; Vertex ne(size, size, 0); Vertex se(size, 0, 0); Vertex sw(0, 0, 0); Vertex nw(0, size, 0); Chose* c = new QuadRoutes(ne,se,sw,nw); + // c->subdivide(); recursiveSubdivide(c); new View(c); diff --git a/rules/batiment.cpp b/rules/batiment.cpp index 24231e5..7e2dc7e 100644 --- a/rules/batiment.cpp +++ b/rules/batiment.cpp @@ -17,12 +17,13 @@ bool Batiment::subdivide() { void Batiment::triangulation() { triangles.reserve(12); - int h = hashInRange(seed,0,4,8); + int h = hashInRange(seed,0,minHeight,maxHeight); + int htoit = hashInRange(seed,0,minHeight/2,maxHeight/2); Vertex neh = ne + Vertex(0,0,h); Vertex seh = se + Vertex(0,0,h); Vertex nwh = nw + Vertex(0,0,h); Vertex swh = sw + Vertex(0,0,h); - Vertex toit = (neh + seh + nwh + swh) / 4 + Vertex(0,0,h/2); + Vertex toit = (neh + seh + nwh + swh) / 4 + Vertex(0,0,htoit); // 4 Murs addTriangle(new Triangle(neh,seh,ne,0xf1,0xe3,0xad)); addTriangle(new Triangle(seh,se,ne,0xf1,0xe3,0xad)); // ne-se-seh-neh diff --git a/rules/batiment.hh b/rules/batiment.hh index dfbcc4b..5a9560b 100644 --- a/rules/batiment.hh +++ b/rules/batiment.hh @@ -10,6 +10,9 @@ public: Vertex se; Vertex sw; Vertex nw; +public: + static const int minHeight = 400; + static const int maxHeight = 800; public: Batiment(Vertex ne, Vertex se, Vertex sw, Vertex nw); int width(); diff --git a/rules/carrefour.cpp b/rules/carrefour.cpp index 9d074c9..a284e91 100644 --- a/rules/carrefour.cpp +++ b/rules/carrefour.cpp @@ -20,6 +20,6 @@ std::ostream& operator<<(std::ostream& os, const Carrefour& c) { void Carrefour::triangulation() { triangles.reserve(2); - addTriangle(new Triangle(ne, nw, sw, 0x80, 0x80, 0x80)); - addTriangle(new Triangle(sw, se, ne, 0x80, 0x80, 0x80)); + addTriangle(new Triangle(ne, nw, sw, 0x36, 0x36, 0x36)); + addTriangle(new Triangle(sw, se, ne, 0x36, 0x36, 0x36)); } diff --git a/rules/quadroutes.cpp b/rules/quadroutes.cpp index 72562ad..9d49fcb 100644 --- a/rules/quadroutes.cpp +++ b/rules/quadroutes.cpp @@ -11,25 +11,44 @@ int QuadRoutes::height() { return std::abs(this->ne.y - this->sw.y); } bool QuadRoutes::subdivide() { children.reserve(9); - int minchildsize = 4; - int lx = std::floor(std::min((nw-ne).norm(), (sw-se).norm())); - // constraint: lx - maxdelta*2 ≥ minchildsize - // constraint: maxdelta ≤ lx/4 - int maxdelta = std::min(lx/4, (lx-minchildsize)/2); - float xpos = (lx/2.f + hashInRange(seed, 0, -maxdelta, maxdelta)) / (float)lx; // xpos \in 0..1 - Vertex n = nw * xpos + ne * (1-xpos); + + // TODO : faire ces calculs sur des Vertex2d. - int splitXMin = this->sw.x + std::max(4, this->width()*1/4); - int splitXMax = this->ne.x - std::max(4, this->width()*1/4); - int splitYMin = this->sw.y + std::max(4, this->height()*1/4); - int splitYMax = this->ne.y - std::max(4, this->height()*1/4); - Vertex split( - hashInRange(this->seed, 0, splitXMin, splitXMax), - hashInRange(this->seed, 1, splitYMin, splitYMax), - 0 // TODO - ); - // TODO : addChild(…); - addChild(new Carrefour(split + Vertex(1,1,0), split + Vertex(1,-1,0), split + Vertex(-1,-1,0), split + Vertex(-1,1,0))); + int slen = (se-sw).norm(); + int nlen = (ne-nw).norm(); + int minsnlen = std::min(slen,nlen); + // constraint: min(slen, nlen) - maxdelta*2 ≥ minchildsize + // constraint: maxdelta ≤ min(slen,nlen)/4 + int xmaxdelta = std::min(minsnlen/4, (minsnlen-minchildsize)/2); + float sxpos = slen/2 + hashInRange(seed, 0, -xmaxdelta, xmaxdelta); + float nxpos = nlen/2 + hashInRange(seed, 0, -xmaxdelta, xmaxdelta); + Vertex s = (sw * sxpos / slen) + (se * (slen - nxpos) / slen); + Vertex n = (nw * nxpos / nlen) + (ne * (nlen - nxpos) / nlen); + + int wlen = (nw-sw).norm(); + int elen = (ne-se).norm(); + int minwelen = std::min(wlen,elen); + // constraint: min(wlen, elen) - maxdelta*2 ≥ minchildsize + // constraint: maxdelta ≤ min(wlen,elen)/4 + int ymaxdelta = std::min(minwelen/4, (minwelen-minchildsize)/2); + float wypos = wlen/2 + hashInRange(seed, 0, -ymaxdelta, ymaxdelta); + float eypos = elen/2 + hashInRange(seed, 0, -ymaxdelta, ymaxdelta); + Vertex w = (nw * wypos / wlen) + (sw * (wlen - wypos) / wlen); + Vertex e = (ne * eypos / elen) + (se * (elen - eypos) / elen); + + Vertex split = intersection(s,n,w,e); + + // TODO : Pour offset les points des extrémités de la route w--split : + // Vertex offset = vecteur perpendiculaire w--split, de longueur hrw. + // Projeter `offset` sur split--n, et ajouter le résultat à split. + // Projeter `offset` sur w--nw, et ajouter le résultat à w. + + // Projeter u sur v : (u scalaire v) / v.norm(). + // scalaire(u,v) = u.norm() * v.norm() * cos(angle(u,v)) + // Donc projeter u sur v : u.norm() * cos(angle(u,v)) + // TODO : comment calculer l'angle(u,v) ? + + addChild(new Carrefour(split + Vertex(hrw,hrw,0), split + Vertex(hrw,-hrw,0), split + Vertex(-hrw,-hrw,0), split + Vertex(-hrw,hrw,0))); // routes au NESW du carrefour // TODO : la plupart des zéros en z sont faux… Vertex roadEndN(split.x, this->ne.y, 0); @@ -37,10 +56,10 @@ bool QuadRoutes::subdivide() { Vertex roadEndS(split.x, this->sw.y, 0); Vertex roadEndW(this->sw.x, split.y, 0); // TODO : addChild(…); - Route* rn = new Route(roadEndN + Vertex(+1,0,0), split + Vertex(+1,+1,0), split + Vertex(-1,+1,0), roadEndN + Vertex(-1,0,0)); // N - Route* re = new Route(roadEndE + Vertex(0,+1,0), roadEndE + Vertex(0,-1,0), split + Vertex(+1,-1,0), split + Vertex(+1,+1,0)); // E - Route* rs = new Route(split + Vertex(+1,-1,0), roadEndS + Vertex(+1,0,0), roadEndS + Vertex(-1,0,0), split + Vertex(-1,-1,0)); // S - Route* rw = new Route(split + Vertex(-1,+1,0), split + Vertex(-1,-1,0), roadEndW + Vertex(0,-1,0), roadEndW + Vertex(0,+1,0)); // W + Route* rn = new Route(roadEndN + Vertex(+hrw,0,0), split + Vertex(+hrw,+hrw,0), split + Vertex(-hrw,+hrw,0), roadEndN + Vertex(-hrw,0,0)); // N + Route* re = new Route(roadEndE + Vertex(0,+hrw,0), roadEndE + Vertex(0,-hrw,0), split + Vertex(+hrw,-hrw,0), split + Vertex(+hrw,+hrw,0)); // E + Route* rs = new Route(split + Vertex(+hrw,-hrw,0), roadEndS + Vertex(+hrw,0,0), roadEndS + Vertex(-hrw,0,0), split + Vertex(-hrw,-hrw,0)); // S + Route* rw = new Route(split + Vertex(-hrw,+hrw,0), split + Vertex(-hrw,-hrw,0), roadEndW + Vertex(0,-hrw,0), roadEndW + Vertex(0,+hrw,0)); // W addChild(rn); addChild(re); addChild(rs); @@ -63,7 +82,7 @@ void QuadRoutes::triangulation() { Chose* QuadRoutes::sub(Vertex ne, Vertex sw) { Segment rect = Segment(ne,sw); - if (rect.width() < 10 || rect.height() < 10) { + if (rect.width() < minQuadSize || rect.height() < minQuadSize) { return new Batiment(ne, Vertex(ne.x, sw.y, 0), sw, Vertex(sw.x, ne.y, 0)); } else { return new QuadRoutes(ne, Vertex(ne.x, sw.y, 0), sw, Vertex(sw.x, ne.y, 0)); diff --git a/rules/quadroutes.hh b/rules/quadroutes.hh index 50b5528..ef00cea 100644 --- a/rules/quadroutes.hh +++ b/rules/quadroutes.hh @@ -10,17 +10,20 @@ public: Vertex se; Vertex sw; Vertex nw; +public: + static const int hrw = 250; // half road width : 2,50m. + static const int minchildsize = 1000; + static const int minQuadSize = 2500; public: QuadRoutes(Vertex ne, Vertex se, Vertex sw, Vertex nw); int width(); int height(); virtual bool subdivide(); virtual void triangulation(); -private: - Chose* sub(Vertex ne, Vertex sw); -public: friend std::ostream& operator<<(std::ostream& os, const QuadRoutes& r); friend std::ostream& operator<<(std::ostream& os, const QuadRoutes* r); +private: + Chose* sub(Vertex ne, Vertex sw); }; diff --git a/rules/route.cpp b/rules/route.cpp index 69b7ba0..50e75b8 100644 --- a/rules/route.cpp +++ b/rules/route.cpp @@ -21,6 +21,6 @@ std::ostream& operator<<(std::ostream& os, const Route& r) { void Route::triangulation() { triangles.reserve(2); - addTriangle(new Triangle(ne, nw, sw, 0x6c, 0x6c, 0x6c)); - addTriangle(new Triangle(sw, se, ne, 0x6c, 0x6c, 0x6c)); + addTriangle(new Triangle(ne, nw, sw, 0x36, 0x36, 0x36)); + addTriangle(new Triangle(sw, se, ne, 0x36, 0x36, 0x36)); } diff --git a/triangle.cpp b/triangle.cpp index ce37394..92df43f 100644 --- a/triangle.cpp +++ b/triangle.cpp @@ -14,25 +14,8 @@ std::ostream& operator<<(std::ostream& os, const Triangle& t) { } Vertexf Triangle::normalVector(Vertex v1, Vertex v2, Vertex v3) { - int ax = v1.x - v2.x; - int ay = v1.y - v2.y; - int az = v1.z - v2.z; - int bx = v2.x - v3.x; - int by = v2.y - v3.y; - int bz = v2.z - v3.z; - - Vertexf normal; - - float x = (float)((ay * bz) - (az * by)); - float y = (float)((az * bx) - (ax * bz)); - float z = (float)((ax * by) - (ay * bx)); - float length = sqrt(x*x + y*y + z*z); - - normal.x = x/length; - normal.y = y/length; - normal.z = z/length; - - return normal; + Vertexf normal = (v1 - v2)*(v2 - v3); + return normal / normal.norm(); } void Triangle::display() { @@ -41,16 +24,16 @@ void Triangle::display() { // glBegin(GL_LINES); // glColor3ub(255,255,0); // Vertex v = (v1 + v2 + v3) / 3; - // glVertex3d(v.x*10,v.y*10,v.z*10); - // glVertex3d(v.x*10+normal.x*50,v.y*10+normal.y*50,v.z*10+normal.z*50); + // glVertex3d(v.x,v.y,v.z); + // glVertex3d(v.x+normal.x*50,v.y+normal.y*50,v.z+normal.z*50); // glEnd( ); // glEnable(GL_LIGHTING); View::setColor(r,g,b); glNormal3d(normal.x,normal.y,normal.z); - glBegin(GL_TRIANGLES); - glVertex3d(v1.x*10,v1.y*10,v1.z*10); - glVertex3d(v2.x*10,v2.y*10,v2.z*10); - glVertex3d(v3.x*10,v3.y*10,v3.z*10); - glEnd(); + // glBegin(GL_TRIANGLES); + glVertex3d(v1.x,v1.y,v1.z); + glVertex3d(v2.x,v2.y,v2.z); + glVertex3d(v3.x,v3.y,v3.z); + // glEnd(); } diff --git a/vertex.cpp b/vertex.cpp index fe8907d..612fd70 100644 --- a/vertex.cpp +++ b/vertex.cpp @@ -6,6 +6,25 @@ Vertex::Vertex(int x, int y, int z): x(x), y(y), z(z) {} float Vertex::norm() { return std::sqrt(x*x + y*y + z*z); } +// TODO : this is 2D only, use Vertex2d. +Vertex intersection(Vertex a, Vertex b, Vertex c, Vertex d) { + // Note : si les deux lignes sont parallèles, on risque fort + // d'avoir une division par zéro. + // http://en.wikipedia.org/wiki/Line-line_intersection + long long x1 = a.x; long long y1 = a.y; + long long x2 = b.x; long long y2 = b.y; + long long x3 = c.x; long long y3 = c.y; + long long x4 = d.x; long long y4 = d.y; + long long denominator = ((x1-x2)*(y3-y4) - (y1-y2)*(x3-x4)); + return Vertex( + ((x1*y2-y1*x2)*(x3-x4) - (x1-x2)*(x3*y4-y3*x4)) / denominator, + ((x1*y2-y1*x2)*(y3-y4) - (y1-y2)*(x3*y4-y3*x4)) / denominator, + 0 + ); +} + +Vertex::operator Vertexf() { return Vertexf(x,y,z); } + std::ostream& operator<<(std::ostream& os, const Vertex& v) { return os << "(" << v.x << "," << v.y << "," << v.z << ")"; } @@ -34,10 +53,22 @@ Vertex operator*(const Vertex& v, const int n) { return Vertex(v.x * n, v.y * n, v.z * n); } +Vertex operator*(const Vertex& u, const Vertex& v) { + return Vertex( + (u.y * v.z) - (u.z * v.y), + (u.z * v.x) - (u.x * v.z), + (u.x * v.y) - (u.y * v.x) + ); +} + Vertex operator/(const Vertex& v, const int n) { return Vertex(v.x / n, v.y / n, v.z / n); } +Vertex operator/(const Vertex& v, const float f) { + return Vertex(v.x / f, v.y / f, v.z / f); +} + Vertex Vertex::fromSpherical(float r, float xAngle, float yAngle) { // http://electron9.phys.utk.edu/vectors/3dcoordinates.htm return Vertex( @@ -56,6 +87,8 @@ Vertexf::Vertexf(float x, float y, float z): x(x), y(y), z(z) {} float Vertexf::norm() { return std::sqrt(x*x + y*y + z*z); } +Vertexf::operator Vertex() { return Vertex(x,y,z); } + std::ostream& operator<<(std::ostream& os, const Vertexf& v) { return os << "(" << v.x << "," << v.y << "," << v.z << ")"; } @@ -84,10 +117,22 @@ Vertexf operator*(const Vertexf& v, const int n) { return Vertexf(v.x * n, v.y * n, v.z * n); } +Vertexf operator*(const Vertexf& u, const Vertexf& v) { + return Vertexf( + (u.y * v.z) - (u.z * v.y), + (u.z * v.x) - (u.x * v.z), + (u.x * v.y) - (u.y * v.x) + ); +} + Vertexf operator/(const Vertexf& v, const int n) { return Vertexf(v.x / n, v.y / n, v.z / n); } +Vertexf operator/(const Vertexf& v, const float f) { + return Vertexf(v.x / f, v.y / f, v.z / f); +} + Vertexf Vertexf::fromSpherical(float r, float xAngle, float yAngle) { // http://electron9.phys.utk.edu/vectors/3dcoordinates.htm return Vertexf( diff --git a/vertex.hh b/vertex.hh index de84186..a27d536 100644 --- a/vertex.hh +++ b/vertex.hh @@ -15,14 +15,18 @@ class Vertex { Vertex(int x, int y, int z); float norm(); static Vertex fromSpherical(float r, float xAngle, float yAngle); + friend Vertex intersection(Vertex a, Vertex b, Vertex c, Vertex d); // Intersection entre (a,b) et (c,d). public: + operator Vertexf(); friend std::ostream& operator<<(std::ostream& os, const Vertex& v); friend Vertex operator+(const Vertex& u, const Vertex& v); friend Vertex operator-(const Vertex& u, const Vertex& v); friend Vertex operator-(const Vertex& v); friend Vertex operator*(const Vertex& v, const int n); + friend Vertex operator*(const Vertex& u, const Vertex& v); friend Vertex operator/(const Vertex& v, const int n); + friend Vertex operator/(const Vertex& v, const float f); friend Vertex operator+(const Vertex& u, const Vertexf& v); friend Vertex operator-(const Vertex& u, const Vertexf& v); }; @@ -40,12 +44,15 @@ class Vertexf { static Vertexf fromSpherical(float r, float xAngle, float yAngle); public: + operator Vertex(); friend std::ostream& operator<<(std::ostream& os, const Vertexf& v); friend Vertexf operator+(const Vertexf& u, const Vertexf& v); friend Vertexf operator-(const Vertexf& u, const Vertexf& v); friend Vertexf operator-(const Vertexf& v); friend Vertexf operator*(const Vertexf& v, const int n); + friend Vertexf operator*(const Vertexf& u, const Vertexf& v); friend Vertexf operator/(const Vertexf& v, const int n); + friend Vertexf operator/(const Vertexf& v, const float f); friend Vertexf operator+(const Vertexf& u, const Vertex& v); friend Vertexf operator-(const Vertexf& u, const Vertex& v); }; diff --git a/view.cpp b/view.cpp index 6ac8716..cc6d02d 100644 --- a/view.cpp +++ b/view.cpp @@ -1,6 +1,6 @@ #include "all_includes.hh" -View::View(Chose* root) : root(root), camera(Camera(Vertexf(420,468,151),230,108,40,0.6)) { +View::View(Chose* root) : root(root), camera(Camera(Vertexf(1000,1000,2000),45,100,1000,0.6)) { initWindow(); mainLoop(); } @@ -21,7 +21,7 @@ void View::initWindow() { SDL_SetVideoMode(windowWidth, windowHeight, 32, SDL_OPENGL); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); - gluPerspective(70,(double)windowWidth/windowHeight,1,10000); + gluPerspective(70,(double)windowWidth/windowHeight,1,100000); // back frustum : 1km glEnable(GL_DEPTH_TEST); glewInit(); @@ -40,7 +40,7 @@ void View::initWindow() { } void View::setLight() { - float Light1Pos[4] = {0.5f, 1.0f, 1.0f, 0.0f}; + float Light1Pos[4] = {-0.5f, -1.0f, 1.0f, 0.0f}; float Light1Dif[4] = {1.0f, 1.0f, 1.0f, 1.0f}; float Light1Spec[4] = {0.0f, 0.0f, 0.0f, 1.0f}; float Light1Amb[4] = {0.2f, 0.2f, 0.2f, 1.0f}; @@ -88,7 +88,9 @@ void View::renderScene(int lastTime, int currentTime) { setLight(); //displayAxes(); + glBegin(GL_TRIANGLES); root->display(); + glEnd(); glFlush(); SDL_GL_SwapBuffers(); @@ -189,8 +191,18 @@ void Camera::keyboard(const SDL_KeyboardEvent &eventKey) { case 'q': exit(0); break; + case 's': + if (eventKey.type != SDL_KEYDOWN) break; + moveDist = std::min(50000,std::max(moveDist+1, moveDist*10/9)); + break; + case 'x': + if (eventKey.type != SDL_KEYDOWN) break; + moveDist = std::max(10, moveDist*9/10); + break; case 'p': // _Print _Position + if (eventKey.type != SDL_KEYDOWN) break; std::cout << *this << std::endl; + break; default: break; }