Blob Blame Raw

#include <cassert>
#include <cstdlib>

#include <algorithm>
#include <map>

#include <GL/gl.h>
#include <GL/glext.h>

#include "mesh.h"


void Mesh::createbuf() const {
    if (ibuf && vbuf && elements) return;
    dirty();
    if (vertices.empty() || triangles.empty()) return;
    
    glGenBuffers(1, &vbuf);
    glBindBuffer(GL_ARRAY_BUFFER, vbuf);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertex)*vertices.size(), &vertices.front(), GL_STATIC_DRAW);
    glBindBuffer(GL_ARRAY_BUFFER, 0);

    glGenBuffers(1, &ibuf);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Triangle)*triangles.size(), &triangles.front(), GL_STATIC_DRAW);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    
    elements = triangles.size()*3u;
}

void Mesh::dirty() const {
    if (ibuf) { glDeleteBuffers(1, &ibuf); ibuf = 0; }
    if (vbuf) { glDeleteBuffers(1, &vbuf); vbuf = 0; }
    elements = 0;
}

void Mesh::clear() {
    dirty();
    triangles.clear();
    vertices.clear();
}

void Mesh::draw() const {
    createbuf();
    if (!elements) return;

    glBindBuffer(GL_ARRAY_BUFFER, vbuf);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf);
    glEnableClientState(GL_VERTEX_ARRAY);
    glEnableClientState(GL_NORMAL_ARRAY);

    glVertexPointer(3, GL_DOUBLE, sizeof(Vertex), 0);
    glNormalPointer(GL_DOUBLE, sizeof(Vertex), (void*)sizeof(Vector3));
    glDrawElements(GL_TRIANGLES, elements, GL_UNSIGNED_INT, 0);

    glDisableClientState(GL_VERTEX_ARRAY);
    glDisableClientState(GL_NORMAL_ARRAY);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    
    //glBegin(GL_TRIANGLES);
    //for(TriangleList::const_iterator i = triangles.begin(); i != triangles.end(); ++i) {
    //    for(int j = 0; j < 3; ++j) {
    //        glNormal3dv(vertices[ i->v[j] ].normal.c);
    //        glVertex3dv(vertices[ i->v[j] ].pos.c);
    //    }
    //}
    //glEnd();
}




LinkedMesh::Vertex LinkedMesh::average(const Vertex &a, const Vertex &b)
    { return Vertex((a.pos + b.pos)*0.5, (a.value + b.value)*0.5); }

Vector3 LinkedMesh::sphere_func(const Vertex &v, Real r, Real kr)
    { return v.pos.norm()*r*pow(1+kr, v.value); }
    
Vector3 LinkedMesh::z_func(const Vertex &v, Real r, Real kr)
    { return Vector3(v.pos.x, v.pos.y, v.pos.z + v.value*kr + r); }

Real LinkedMesh::random()
    { return real_random2(); }


void LinkedMesh::clear() {
    levels.clear();
    triangles.clear();
    edges.clear();
    vertices.clear();
}


void LinkedMesh::next_level(Real k) {
    Level level;
    if (!levels.empty()) {
        const Level &l = levels.back();
        level.k = l.k;
        level.vertex0 = l.vertex1;
        level.edge0 = l.edge1;
        level.triangle0 = l.triangle1;
    }
    
    level.k *= k;
    level.vertex1 = (int)vertices.size();
    level.edge1 = (int)edges.size();
    level.triangle1 = (int)triangles.size();
    
    assert(level.vertex0 <= level.vertex1);
    assert(level.edge0 <= level.edge1);
    assert(level.triangle0 <= level.triangle1);
    
    levels.push_back(level);
    check();
}


void LinkedMesh::check() const {
    if (levels.empty()) {
        assert(vertices.empty());
        assert(edges.empty());
        assert(triangles.empty());
    }
    
    for(int li = 0; li < (int)levels.size(); ++li) {
        const bool last_level = (li == (int)levels.size() - 1);
        const Level &l = levels[li];
        const Level pl = li ? levels[li - 1] : Level();
        const Level nl = last_level ? Level() : levels[li + 1];

        assert(l.k >= 0);
        assert(l.k <= pl.k);
        assert(l.vertex0 == pl.vertex1);
        assert(l.edge0 == pl.edge1);
        assert(l.triangle0 == pl.triangle1);

        assert(l.vertex0 >= 0);
        assert(l.edge0 >= 0);
        assert(l.triangle0 >= 0);

        assert(l.vertex1 <= (int)vertices.size());
        assert(l.edge1 <= (int)edges.size());
        assert(l.triangle1 <= (int)triangles.size());

        assert(l.vertex0 <= l.vertex1);
        assert(l.edge0 <= l.edge1);
        assert(l.triangle0 <= l.triangle1);
        
        if (last_level) {
            assert(l.vertex1 == (int)vertices.size());
            assert(l.edge1 == (int)edges.size());
            assert(l.triangle1 == (int)triangles.size());
        }
        
        for(int i = l.edge0; i < l.edge1; ++i) {
            const Edge &e = edges[i];
            if (last_level) {
                assert(e.e[0] == 0);
                assert(e.e[1] == 0);
                assert(e.v[1] == -1);
            } else {
                assert(e.e[0] != e.e[1]);
                assert(e.e[0] >= nl.edge0 && e.e[0] < nl.edge1);
                assert(e.e[1] >= nl.edge0 && e.e[1] < nl.edge1);
                assert(e.v[1] >= nl.vertex0 && e.v[1] < nl.vertex1);
            }
            assert(e.v[0] != e.v[1]);
            assert(e.v[0] >= 0 && e.v[0] < l.vertex1);
            assert(e.v[2] >= 0 && e.v[2] < l.vertex1);
        }

        for(int i = l.triangle0; i < l.triangle1; ++i) {
            const Triangle &t = triangles[i];
            for(int j = 0; j < 3; ++j) {
                int jj = (j+1)%3;
                assert(t.e[j] >= l.edge0 && t.e[j] < l.edge1);
                assert(edges[ t.e[j] ].v[ t.d[j] ? 0 : 2 ] == edges[ t.e[jj] ].v[ t.d[jj] ? 2 : 0 ]);
            }
        }
    }
}


void LinkedMesh::generate_level(Real k) {
    const Level level = levels.empty() ? Level() : levels.back();
    const Real kk = level.k * k;
    
    for(int i = level.triangle0; i < level.triangle1; ++i) {
        Triangle t = triangles[i];
        
        Edge ee[3];
        for(int j = 0; j < 3; ++j) {
            Edge &e = edges[t.e[j]];
            if (e.v[1] < 0) {
                Vertex v = average( vertices[e.v[0]], vertices[e.v[2]] );
                v.value += random()*kk;
                e.v[1] = (int)vertices.size();
                vertices.push_back(v);
                
                e.e[0] = (int)edges.size();
                e.e[1] = e.e[0] + 1;
                ee[j] = e;
                edges.push_back(Edge(ee[j].v[0], ee[j].v[1]));
                edges.push_back(Edge(ee[j].v[1], ee[j].v[2]));
            } else {
                ee[j] = e;
            }
            
            if (t.d[j]) {
                std::swap(ee[j].e[0], ee[j].e[1]);
                std::swap(ee[j].v[0], ee[j].v[2]);
            }
        }
        
        int ei = (int)edges.size();
        edges.push_back(Edge(ee[0].v[1], ee[2].v[1]));
        edges.push_back(Edge(ee[1].v[1], ee[0].v[1]));
        edges.push_back(Edge(ee[2].v[1], ee[1].v[1]));
        
        triangles.push_back(Triangle( ee[0].e[0], t.d[0], ei + 0, false, ee[2].e[1], t.d[2] ));
        triangles.push_back(Triangle( ee[1].e[0], t.d[1], ei + 1, false, ee[0].e[1], t.d[0] ));
        triangles.push_back(Triangle( ee[2].e[0], t.d[2], ei + 2, false, ee[1].e[1], t.d[1] ));

        triangles.push_back(Triangle( ei + 0, true, ei + 1, true, ei + 2, true ));
    }
    
    next_level(k);
}


void LinkedMesh::generate_levels(int count, Real k) {
    for(int i = 0; i < count; ++i)
        generate_level(k);
}


void LinkedMesh::smooth() {
    typedef std::pair<Real, Real> Sum;
    typedef std::vector<Sum> SumList;

    const Level &level = levels.back();
    SumList sum;
    sum.reserve(level.vertex1);
    for(int i = 0; i < level.vertex1; ++i)
        sum.push_back(Sum(1, vertices[i].value));
    for(int i = level.edge0; i < level.edge1; ++i) {
        const Edge &e = edges[i];
        Sum &s0 = sum[e.v[0]], &s1 = sum[e.v[2]];
        s0.first += 1;
        s1.first += 1;
        s0.second += vertices[e.v[2]].value;
        s1.second += vertices[e.v[1]].value;
    }
    for(int i = 0; i < level.vertex1; ++i) {
        const Sum &s = sum[i];
        vertices[i].value = s.second/s.first;
    }
}


void LinkedMesh::smooth(int count) {
    for(int i = 0; i < count; ++i)
        smooth();
}


void LinkedMesh::to_mesh(Mesh &mesh, VertexFunc func, Real r, Real kr, int level) const {
    if (levels.empty()) return;
    if (level < 0 || level >= (int)levels.size()) level = levels.size() - 1;
    const Level &l = levels[level];
    
    int v0 = (int)mesh.vertices.size();
    int v1 = v0 + l.vertex1;
    mesh.vertices.reserve(v1);
    for(int i = 0; i < l.vertex1; ++i)
        mesh.vertices.push_back(Mesh::Vertex( func(vertices[i], r, kr) ));
    
    mesh.triangles.reserve(mesh.triangles.size() + (l.triangle1 - l.triangle0));
    for(int i = l.triangle0; i < l.triangle1; ++i) {
        const Triangle &t = triangles[i];
        Mesh::Triangle tt;
        for(int j = 0; j < 3; ++j)
            tt.v[j] = v0 + edges[t.e[j]].v[ t.d[j] ? 2 : 0 ];
        Vector3 normal = (mesh.vertices[tt.v[1]].pos - mesh.vertices[tt.v[0]].pos).cross(
                          mesh.vertices[tt.v[2]].pos - mesh.vertices[tt.v[0]].pos ).norm();
        for(int j = 0; j < 3; ++j)
            mesh.vertices[tt.v[j]].normal += normal;
        mesh.triangles.push_back(tt);
    }

    for(int i = v0; i < v1; ++i)
        mesh.vertices[i].normal = mesh.vertices[i].normal.norm();
    
    mesh.dirty();
}


void LinkedMesh::triangle(Real k) {
    clear();
    for(int i = 0; i < 3; ++i) {
        Real a = 2*pi/3*i;
        vertices.push_back(Vertex( Vector3(cos(a), sin(a), 0), random()*k ));
        edges.push_back(Edge(i, (i+1)%3));
    }
    triangles.push_back(Triangle(0, false, 1, false, 2, false));
    next_level(k);
}

void LinkedMesh::tetrahedron(Real k) {
    clear();
    const Real r = 2*sqrt2/3;
    const Real z = -1/Real(3);

    vertices.push_back(Vertex( Vector3(0, 0, 1), random()*k ));
    for(int i = 0; i < 3; ++i) {
        Real a = 2*pi/3*i;
        vertices.push_back(Vertex( Vector3(cos(a)*r, sin(a)*r, z), random()*k ));
        edges.push_back(Edge(0, i+1));
        edges.push_back(Edge(i+1, (i+1)%3 + 1));
        triangles.push_back(Triangle(i*2, false, i*2+1, false, (i+1)%3*2, true));
    }
    triangles.push_back(Triangle(5, true, 3, true, 1, true));
    next_level(k);
}

void LinkedMesh::icosahedron(Real k) {
    clear();
    const Real kk = 4*sin(pi/5)*sin(pi/5) - 1;
    const Real r = 2*sqrt(kk)/(kk + 1);
    const Real z = 1 - r*sqrt(kk);

    // vertices
    vertices.push_back(Vertex( Vector3(0, 0,  1), random()*k ));
    for(int i = 0; i < 5; ++i) {
        Real a = 2*pi/5*i;
        vertices.push_back(Vertex( Vector3(cos(a)*r, sin(a)*r,  z), random()*k ));
    }
    for(int i = 0; i < 5; ++i) {
        Real a = 2*pi/5*i + pi/5;
        vertices.push_back(Vertex( Vector3(cos(a)*r, sin(a)*r, -z), random()*k ));
    }
    vertices.push_back(Vertex( Vector3(0, 0, -1), random()*k ));

    // edges
    for(int i = 0; i < 5; ++i) edges.push_back(Edge(0, i+1));
    for(int i = 0; i < 5; ++i) edges.push_back(Edge(i+1, (i+1)%5 + 1));
    for(int i = 0; i < 5; ++i) edges.push_back(Edge(i+1, i+6));
    for(int i = 0; i < 5; ++i) edges.push_back(Edge(i+6, (i+1)%5 + 1));
    for(int i = 0; i < 5; ++i) edges.push_back(Edge(i+6, (i+1)%5 + 6));
    for(int i = 0; i < 5; ++i) edges.push_back(Edge(11, i+6));
    
    // triangles
    for(int i = 0; i < 5; ++i) {
        int ii = (i+1)%5;
        triangles.push_back(Triangle(i, false, i+5, false, ii, true));
        triangles.push_back(Triangle(i+10, false, i+15, false, i+5, true));
        triangles.push_back(Triangle(i+20, false, ii+10, true, i+15, true));
        triangles.push_back(Triangle(i+25, true, ii+25, false, i+20, true));
    }
    
    next_level(k);
}