Blame projects/asteroid/mesh.cpp

223ac6
223ac6
#include <cassert></cassert>
223ac6
#include <cstdlib></cstdlib>
223ac6
223ac6
#include <algorithm></algorithm>
223ac6
#include <map></map>
223ac6
223ac6
#include <gl gl.h=""></gl>
223ac6
#include <gl glext.h=""></gl>
223ac6
223ac6
#include "mesh.h"
223ac6
223ac6
223ac6
void Mesh::createbuf() const {
223ac6
    if (ibuf && vbuf && elements) return;
223ac6
    dirty();
223ac6
    if (vertices.empty() || triangles.empty()) return;
223ac6
    
223ac6
    glGenBuffers(1, &vbuf);
223ac6
    glBindBuffer(GL_ARRAY_BUFFER, vbuf);
223ac6
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*vertices.size(), &vertices.front(), GL_STATIC_DRAW);
223ac6
    glBindBuffer(GL_ARRAY_BUFFER, 0);
223ac6
223ac6
    glGenBuffers(1, &ibuf);
223ac6
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf);
223ac6
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Triangle)*triangles.size(), &triangles.front(), GL_STATIC_DRAW);
223ac6
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
223ac6
    
223ac6
    elements = triangles.size()*3u;
223ac6
}
223ac6
223ac6
void Mesh::dirty() const {
223ac6
    if (ibuf) { glDeleteBuffers(1, &ibuf); ibuf = 0; }
223ac6
    if (vbuf) { glDeleteBuffers(1, &vbuf); vbuf = 0; }
223ac6
    elements = 0;
223ac6
}
223ac6
223ac6
void Mesh::clear() {
223ac6
    dirty();
223ac6
    triangles.clear();
223ac6
    vertices.clear();
223ac6
}
223ac6
223ac6
void Mesh::draw() const {
223ac6
    createbuf();
223ac6
    if (!elements) return;
223ac6
223ac6
    glBindBuffer(GL_ARRAY_BUFFER, vbuf);
223ac6
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf);
223ac6
    glEnableClientState(GL_VERTEX_ARRAY);
223ac6
    glEnableClientState(GL_NORMAL_ARRAY);
223ac6
223ac6
    glVertexPointer(3, GL_DOUBLE, sizeof(Vertex), 0);
223ac6
    glNormalPointer(GL_DOUBLE, sizeof(Vertex), (void*)sizeof(Vector3));
223ac6
    glDrawElements(GL_TRIANGLES, elements, GL_UNSIGNED_INT, 0);
223ac6
223ac6
    glDisableClientState(GL_VERTEX_ARRAY);
223ac6
    glDisableClientState(GL_NORMAL_ARRAY);
223ac6
    glBindBuffer(GL_ARRAY_BUFFER, 0);
223ac6
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
223ac6
    
223ac6
    //glBegin(GL_TRIANGLES);
223ac6
    //for(TriangleList::const_iterator i = triangles.begin(); i != triangles.end(); ++i) {
223ac6
    //    for(int j = 0; j < 3; ++j) {
223ac6
    //        glNormal3dv(vertices[ i->v[j] ].normal.c);
223ac6
    //        glVertex3dv(vertices[ i->v[j] ].pos.c);
223ac6
    //    }
223ac6
    //}
223ac6
    //glEnd();
223ac6
}
223ac6
223ac6
223ac6
223ac6
223ac6
LinkedMesh::Vertex LinkedMesh::average(const Vertex &a, const Vertex &b)
223ac6
    { return Vertex((a.pos + b.pos)*0.5, (a.value + b.value)*0.5); }
223ac6
223ac6
Vector3 LinkedMesh::sphere_func(const Vertex &v, Real r, Real kr)
223ac6
    { return v.pos.norm()*r*pow(1+kr, v.value); }
223ac6
    
223ac6
Vector3 LinkedMesh::z_func(const Vertex &v, Real r, Real kr)
223ac6
    { return Vector3(v.pos.x, v.pos.y, v.pos.z + v.value*kr + r); }
223ac6
223ac6
Real LinkedMesh::random()
223ac6
    { return real_random2(); }
223ac6
223ac6
223ac6
void LinkedMesh::clear() {
223ac6
    levels.clear();
223ac6
    triangles.clear();
223ac6
    edges.clear();
223ac6
    vertices.clear();
223ac6
}
223ac6
223ac6
223ac6
void LinkedMesh::next_level(Real k) {
223ac6
    Level level;
223ac6
    if (!levels.empty()) {
223ac6
        const Level &l = levels.back();
223ac6
        level.k = l.k;
223ac6
        level.vertex0 = l.vertex1;
223ac6
        level.edge0 = l.edge1;
223ac6
        level.triangle0 = l.triangle1;
223ac6
    }
223ac6
    
223ac6
    level.k *= k;
223ac6
    level.vertex1 = (int)vertices.size();
223ac6
    level.edge1 = (int)edges.size();
223ac6
    level.triangle1 = (int)triangles.size();
223ac6
    
223ac6
    assert(level.vertex0 <= level.vertex1);
223ac6
    assert(level.edge0 <= level.edge1);
223ac6
    assert(level.triangle0 <= level.triangle1);
223ac6
    
223ac6
    levels.push_back(level);
223ac6
    check();
223ac6
}
223ac6
223ac6
223ac6
void LinkedMesh::check() const {
223ac6
    if (levels.empty()) {
223ac6
        assert(vertices.empty());
223ac6
        assert(edges.empty());
223ac6
        assert(triangles.empty());
223ac6
    }
223ac6
    
223ac6
    for(int li = 0; li < (int)levels.size(); ++li) {
223ac6
        const bool last_level = (li == (int)levels.size() - 1);
223ac6
        const Level &l = levels[li];
223ac6
        const Level pl = li ? levels[li - 1] : Level();
223ac6
        const Level nl = last_level ? Level() : levels[li + 1];
223ac6
223ac6
        assert(l.k >= 0);
223ac6
        assert(l.k <= pl.k);
223ac6
        assert(l.vertex0 == pl.vertex1);
223ac6
        assert(l.edge0 == pl.edge1);
223ac6
        assert(l.triangle0 == pl.triangle1);
223ac6
223ac6
        assert(l.vertex0 >= 0);
223ac6
        assert(l.edge0 >= 0);
223ac6
        assert(l.triangle0 >= 0);
223ac6
223ac6
        assert(l.vertex1 <= (int)vertices.size());
223ac6
        assert(l.edge1 <= (int)edges.size());
223ac6
        assert(l.triangle1 <= (int)triangles.size());
223ac6
223ac6
        assert(l.vertex0 <= l.vertex1);
223ac6
        assert(l.edge0 <= l.edge1);
223ac6
        assert(l.triangle0 <= l.triangle1);
223ac6
        
223ac6
        if (last_level) {
223ac6
            assert(l.vertex1 == (int)vertices.size());
223ac6
            assert(l.edge1 == (int)edges.size());
223ac6
            assert(l.triangle1 == (int)triangles.size());
223ac6
        }
223ac6
        
223ac6
        for(int i = l.edge0; i < l.edge1; ++i) {
223ac6
            const Edge &e = edges[i];
223ac6
            if (last_level) {
223ac6
                assert(e.e[0] == 0);
223ac6
                assert(e.e[1] == 0);
223ac6
                assert(e.v[1] == -1);
223ac6
            } else {
223ac6
                assert(e.e[0] != e.e[1]);
223ac6
                assert(e.e[0] >= nl.edge0 && e.e[0] < nl.edge1);
223ac6
                assert(e.e[1] >= nl.edge0 && e.e[1] < nl.edge1);
223ac6
                assert(e.v[1] >= nl.vertex0 && e.v[1] < nl.vertex1);
223ac6
            }
223ac6
            assert(e.v[0] != e.v[1]);
223ac6
            assert(e.v[0] >= 0 && e.v[0] < l.vertex1);
223ac6
            assert(e.v[2] >= 0 && e.v[2] < l.vertex1);
223ac6
        }
223ac6
223ac6
        for(int i = l.triangle0; i < l.triangle1; ++i) {
223ac6
            const Triangle &t = triangles[i];
223ac6
            for(int j = 0; j < 3; ++j) {
223ac6
                int jj = (j+1)%3;
223ac6
                assert(t.e[j] >= l.edge0 && t.e[j] < l.edge1);
223ac6
                assert(edges[ t.e[j] ].v[ t.d[j] ? 0 : 2 ] == edges[ t.e[jj] ].v[ t.d[jj] ? 2 : 0 ]);
223ac6
            }
223ac6
        }
223ac6
    }
223ac6
}
223ac6
223ac6
223ac6
void LinkedMesh::generate_level(Real k) {
223ac6
    const Level level = levels.empty() ? Level() : levels.back();
223ac6
    const Real kk = level.k * k;
223ac6
    
223ac6
    for(int i = level.triangle0; i < level.triangle1; ++i) {
223ac6
        Triangle t = triangles[i];
223ac6
        
223ac6
        Edge ee[3];
223ac6
        for(int j = 0; j < 3; ++j) {
223ac6
            Edge &e = edges[t.e[j]];
223ac6
            if (e.v[1] < 0) {
223ac6
                Vertex v = average( vertices[e.v[0]], vertices[e.v[2]] );
223ac6
                v.value += random()*kk;
223ac6
                e.v[1] = (int)vertices.size();
223ac6
                vertices.push_back(v);
223ac6
                
223ac6
                e.e[0] = (int)edges.size();
223ac6
                e.e[1] = e.e[0] + 1;
223ac6
                ee[j] = e;
223ac6
                edges.push_back(Edge(ee[j].v[0], ee[j].v[1]));
223ac6
                edges.push_back(Edge(ee[j].v[1], ee[j].v[2]));
223ac6
            } else {
223ac6
                ee[j] = e;
223ac6
            }
223ac6
            
223ac6
            if (t.d[j]) {
223ac6
                std::swap(ee[j].e[0], ee[j].e[1]);
223ac6
                std::swap(ee[j].v[0], ee[j].v[2]);
223ac6
            }
223ac6
        }
223ac6
        
223ac6
        int ei = (int)edges.size();
223ac6
        edges.push_back(Edge(ee[0].v[1], ee[2].v[1]));
223ac6
        edges.push_back(Edge(ee[1].v[1], ee[0].v[1]));
223ac6
        edges.push_back(Edge(ee[2].v[1], ee[1].v[1]));
223ac6
        
223ac6
        triangles.push_back(Triangle( ee[0].e[0], t.d[0], ei + 0, false, ee[2].e[1], t.d[2] ));
223ac6
        triangles.push_back(Triangle( ee[1].e[0], t.d[1], ei + 1, false, ee[0].e[1], t.d[0] ));
223ac6
        triangles.push_back(Triangle( ee[2].e[0], t.d[2], ei + 2, false, ee[1].e[1], t.d[1] ));
223ac6
223ac6
        triangles.push_back(Triangle( ei + 0, true, ei + 1, true, ei + 2, true ));
223ac6
    }
223ac6
    
223ac6
    next_level(k);
223ac6
}
223ac6
223ac6
223ac6
void LinkedMesh::generate_levels(int count, Real k) {
223ac6
    for(int i = 0; i < count; ++i)
223ac6
        generate_level(k);
223ac6
}
223ac6
223ac6
223ac6
void LinkedMesh::smooth() {
223ac6
    typedef std::pair<real, real=""> Sum;</real,>
223ac6
    typedef std::vector<sum> SumList;</sum>
223ac6
223ac6
    const Level &level = levels.back();
223ac6
    SumList sum;
223ac6
    sum.reserve(level.vertex1);
223ac6
    for(int i = 0; i < level.vertex1; ++i)
223ac6
        sum.push_back(Sum(1, vertices[i].value));
223ac6
    for(int i = level.edge0; i < level.edge1; ++i) {
223ac6
        const Edge &e = edges[i];
223ac6
        Sum &s0 = sum[e.v[0]], &s1 = sum[e.v[2]];
223ac6
        s0.first += 1;
223ac6
        s1.first += 1;
223ac6
        s0.second += vertices[e.v[2]].value;
223ac6
        s1.second += vertices[e.v[1]].value;
223ac6
    }
223ac6
    for(int i = 0; i < level.vertex1; ++i) {
223ac6
        const Sum &s = sum[i];
223ac6
        vertices[i].value = s.second/s.first;
223ac6
    }
223ac6
}
223ac6
223ac6
223ac6
void LinkedMesh::smooth(int count) {
223ac6
    for(int i = 0; i < count; ++i)
223ac6
        smooth();
223ac6
}
223ac6
223ac6
223ac6
void LinkedMesh::to_mesh(Mesh &mesh, VertexFunc func, Real r, Real kr, int level) const {
223ac6
    if (levels.empty()) return;
223ac6
    if (level < 0 || level >= (int)levels.size()) level = levels.size() - 1;
223ac6
    const Level &l = levels[level];
223ac6
    
223ac6
    int v0 = (int)mesh.vertices.size();
223ac6
    int v1 = v0 + l.vertex1;
223ac6
    mesh.vertices.reserve(v1);
223ac6
    for(int i = 0; i < l.vertex1; ++i)
223ac6
        mesh.vertices.push_back(Mesh::Vertex( func(vertices[i], r, kr) ));
223ac6
    
223ac6
    mesh.triangles.reserve(mesh.triangles.size() + (l.triangle1 - l.triangle0));
223ac6
    for(int i = l.triangle0; i < l.triangle1; ++i) {
223ac6
        const Triangle &t = triangles[i];
223ac6
        Mesh::Triangle tt;
223ac6
        for(int j = 0; j < 3; ++j)
223ac6
            tt.v[j] = v0 + edges[t.e[j]].v[ t.d[j] ? 2 : 0 ];
223ac6
        Vector3 normal = (mesh.vertices[tt.v[1]].pos - mesh.vertices[tt.v[0]].pos).cross(
223ac6
                          mesh.vertices[tt.v[2]].pos - mesh.vertices[tt.v[0]].pos ).norm();
223ac6
        for(int j = 0; j < 3; ++j)
223ac6
            mesh.vertices[tt.v[j]].normal += normal;
223ac6
        mesh.triangles.push_back(tt);
223ac6
    }
223ac6
223ac6
    for(int i = v0; i < v1; ++i)
223ac6
        mesh.vertices[i].normal = mesh.vertices[i].normal.norm();
223ac6
    
223ac6
    mesh.dirty();
223ac6
}
223ac6
223ac6
223ac6
void LinkedMesh::triangle(Real k) {
223ac6
    clear();
223ac6
    for(int i = 0; i < 3; ++i) {
223ac6
        Real a = 2*pi/3*i;
223ac6
        vertices.push_back(Vertex( Vector3(cos(a), sin(a), 0), random()*k ));
223ac6
        edges.push_back(Edge(i, (i+1)%3));
223ac6
    }
223ac6
    triangles.push_back(Triangle(0, false, 1, false, 2, false));
223ac6
    next_level(k);
223ac6
}
223ac6
223ac6
void LinkedMesh::tetrahedron(Real k) {
223ac6
    clear();
223ac6
    const Real r = 2*sqrt2/3;
223ac6
    const Real z = -1/Real(3);
223ac6
223ac6
    vertices.push_back(Vertex( Vector3(0, 0, 1), random()*k ));
223ac6
    for(int i = 0; i < 3; ++i) {
223ac6
        Real a = 2*pi/3*i;
223ac6
        vertices.push_back(Vertex( Vector3(cos(a)*r, sin(a)*r, z), random()*k ));
223ac6
        edges.push_back(Edge(0, i+1));
223ac6
        edges.push_back(Edge(i+1, (i+1)%3 + 1));
223ac6
        triangles.push_back(Triangle(i*2, false, i*2+1, false, (i+1)%3*2, true));
223ac6
    }
223ac6
    triangles.push_back(Triangle(5, true, 3, true, 1, true));
223ac6
    next_level(k);
223ac6
}
223ac6
223ac6
void LinkedMesh::icosahedron(Real k) {
223ac6
    clear();
223ac6
    const Real kk = 4*sin(pi/5)*sin(pi/5) - 1;
223ac6
    const Real r = 2*sqrt(kk)/(kk + 1);
223ac6
    const Real z = 1 - r*sqrt(kk);
223ac6
223ac6
    // vertices
223ac6
    vertices.push_back(Vertex( Vector3(0, 0,  1), random()*k ));
223ac6
    for(int i = 0; i < 5; ++i) {
223ac6
        Real a = 2*pi/5*i;
223ac6
        vertices.push_back(Vertex( Vector3(cos(a)*r, sin(a)*r,  z), random()*k ));
223ac6
    }
223ac6
    for(int i = 0; i < 5; ++i) {
223ac6
        Real a = 2*pi/5*i + pi/5;
223ac6
        vertices.push_back(Vertex( Vector3(cos(a)*r, sin(a)*r, -z), random()*k ));
223ac6
    }
223ac6
    vertices.push_back(Vertex( Vector3(0, 0, -1), random()*k ));
223ac6
223ac6
    // edges
223ac6
    for(int i = 0; i < 5; ++i) edges.push_back(Edge(0, i+1));
223ac6
    for(int i = 0; i < 5; ++i) edges.push_back(Edge(i+1, (i+1)%5 + 1));
223ac6
    for(int i = 0; i < 5; ++i) edges.push_back(Edge(i+1, i+6));
223ac6
    for(int i = 0; i < 5; ++i) edges.push_back(Edge(i+6, (i+1)%5 + 1));
223ac6
    for(int i = 0; i < 5; ++i) edges.push_back(Edge(i+6, (i+1)%5 + 6));
223ac6
    for(int i = 0; i < 5; ++i) edges.push_back(Edge(11, i+6));
223ac6
    
223ac6
    // triangles
223ac6
    for(int i = 0; i < 5; ++i) {
223ac6
        int ii = (i+1)%5;
223ac6
        triangles.push_back(Triangle(i, false, i+5, false, ii, true));
223ac6
        triangles.push_back(Triangle(i+10, false, i+15, false, i+5, true));
223ac6
        triangles.push_back(Triangle(i+20, false, ii+10, true, i+15, true));
223ac6
        triangles.push_back(Triangle(i+25, true, ii+25, false, i+20, true));
223ac6
    }
223ac6
    
223ac6
    next_level(k);
223ac6
}