#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);
}