summaryrefslogtreecommitdiff
path: root/quadtree.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'quadtree.cpp')
-rw-r--r--quadtree.cpp159
1 files changed, 114 insertions, 45 deletions
diff --git a/quadtree.cpp b/quadtree.cpp
index 782837c..7fdf24f 100644
--- a/quadtree.cpp
+++ b/quadtree.cpp
@@ -19,6 +19,8 @@ Quadtree::Quadtree(int width, int height, float *heightmap, int levels) {
vbo_object = 0;
root = NULL;
heights = heightmap;
+ thread_done = thread_running = false;
+ thread_buffer = NULL;
create_nodes(levels);
}
@@ -310,6 +312,16 @@ Vector3 Quadtree::QuadNode::get_normal(int index) {
}
void Quadtree::update(float x, float z) {
+ if(!node_lock.try_lock()) {
+ return;
+ }
+
+ /*
+ * Lock won't be held until this function calls make_vbo(),
+ * which creates the update thread.
+ */
+ node_lock.unlock();
+
bool changed = false;
std::queue<QuadNode*> q;
@@ -406,24 +418,25 @@ unsigned int Quadtree::count_nodes() {
return count;
}
-void Quadtree::make_vbo() {
- nodes = count_nodes();
- if(vbo_object)
- glDeleteBuffers(1, &vbo_object);
- glGenBuffers(1, &vbo_object);
- glBindBuffer(GL_ARRAY_BUFFER, vbo_object);
- const size_t vertex_chunk_size = sizeof(float)*3*12;
+Quadtree::UpdateThread::UpdateThread(Quadtree *t, float *b) {
+ tree = t;
+ buffer = b;
+}
+
+void Quadtree::UpdateThread::operator()() {
+ tree->vbo_lock.lock();
+ tree->node_lock.lock();
+
+ unsigned int nodes = tree->nodes;
+ const size_t vertex_chunk_size = 3*12;
const size_t vertices_size = vertex_chunk_size*nodes;
const size_t normal_chunk_size = vertex_chunk_size;
const size_t normals_size = normal_chunk_size*nodes;
- const size_t tex_coord_chunk_size = sizeof(float)*2*12;
- const size_t tex_coords_size = tex_coord_chunk_size*nodes;
-
- glBufferData(GL_ARRAY_BUFFER, vertices_size + normals_size + tex_coords_size, NULL, GL_DYNAMIC_DRAW);
+ const size_t tex_coord_chunk_size = 2*12;
+ //const size_t tex_coords_size = tex_coord_chunk_size*nodes;
std::queue<Quadtree::QuadNode*> q;
- q.push(root);
- vertices = nodes*12;
+ q.push(tree->root);
unsigned int index = 0;
while(!q.empty()) {
Quadtree::QuadNode* node = q.front();
@@ -433,11 +446,6 @@ void Quadtree::make_vbo() {
q.push(node->children[j]);
continue;
}
- float v[3*12];
- float n[3*12];
- v[0] = node->vertex_array[0];
- v[1] = node->vertex_array[1];
- v[2] = node->vertex_array[2];
float tex_coords[4][3][2] = {
{{.5, .5}, {0, 0}, {0, 1}},
{{.5, .5}, {0, 1}, {1, 1}},
@@ -445,11 +453,17 @@ void Quadtree::make_vbo() {
{{.5, .5}, {1, 0}, {0, 0}}
};
for(int i = 0; i < 4; i++) {
+ float *v = buffer + vertex_chunk_size*index + 3*3*i;
for(int j = 0; j < 3; j++) {
- tex_coords[i][j][0] *= node->width;
- tex_coords[i][j][1] *= node->height;
+ float *tc = buffer + vertices_size + normals_size + tex_coord_chunk_size*index + 6*i + 2*j;
+ tc[0] = tex_coords[i][j][0]*node->width;
+ tc[1] = tex_coords[i][j][1]*node->height;
}
+ v[0] = node->vertex_array[0];
+ v[1] = node->vertex_array[1];
+ v[2] = node->vertex_array[2];
+
v[3] = node->vertex_array[i*3+3];
v[4] = node->vertex_array[i*3+4];
v[5] = node->vertex_array[i*3+5];
@@ -457,15 +471,16 @@ void Quadtree::make_vbo() {
v[6] = node->vertex_array[i == 3 ? 3 : (i*3+6)];
v[7] = node->vertex_array[i == 3 ? 4 : (i*3+7)];
v[8] = node->vertex_array[i == 3 ? 5 : (i*3+8)];
- glBufferSubData(GL_ARRAY_BUFFER, vertex_chunk_size*index + sizeof(float)*3*3*i, sizeof(float)*3*3, v);
}
+ float *n = buffer + vertices_size + normal_chunk_size*index;
+
/* interpolate normals per vertex between nodes */
- QuadNode *left = get_left(node);
- QuadNode *right = get_right(node);
- QuadNode *up = get_up(node);
- QuadNode *down = get_down(node);
+ QuadNode *left = tree->get_left(node);
+ QuadNode *right = tree->get_right(node);
+ QuadNode *up = tree->get_up(node);
+ QuadNode *down = tree->get_down(node);
// midpoint
{
@@ -488,10 +503,10 @@ void Quadtree::make_vbo() {
v += down->get_normal(2);
}
if(left && down) {
- QuadNode *n = get_left(down);
- if(n) {
- v += n->get_normal(0);
- v += n->get_normal(1);
+ QuadNode *temp = tree->get_left(down);
+ if(temp) {
+ v += temp->get_normal(0);
+ v += temp->get_normal(1);
}
}
v /= v.length();
@@ -512,10 +527,10 @@ void Quadtree::make_vbo() {
v += down->get_normal(0);
}
if(down && right) {
- QuadNode *n = get_down(right);
- if(n) {
- v += n->get_normal(1);
- v += n->get_normal(2);
+ QuadNode *temp = tree->get_down(right);
+ if(temp) {
+ v += temp->get_normal(1);
+ v += temp->get_normal(2);
}
}
v /= v.length();
@@ -536,10 +551,10 @@ void Quadtree::make_vbo() {
v += up->get_normal(3);
}
if(up && right) {
- QuadNode *n = get_right(up);
- if(n) {
- v += n->get_normal(2);
- v += n->get_normal(3);
+ QuadNode *temp = tree->get_right(up);
+ if(temp) {
+ v += temp->get_normal(2);
+ v += temp->get_normal(3);
}
}
v /= v.length();
@@ -560,10 +575,10 @@ void Quadtree::make_vbo() {
v += left->get_normal(1);
}
if(left && up) {
- QuadNode *n = get_left(up);
- if(n) {
- v += n->get_normal(0);
- v += n->get_normal(3);
+ QuadNode *temp = tree->get_left(up);
+ if(temp) {
+ v += temp->get_normal(0);
+ v += temp->get_normal(3);
}
}
v /= v.length();
@@ -572,11 +587,66 @@ void Quadtree::make_vbo() {
n[17] = n[23] = v.z;
}
- glBufferSubData(GL_ARRAY_BUFFER, vertices_size + normal_chunk_size*index, normal_chunk_size, n);
-
- glBufferSubData(GL_ARRAY_BUFFER, vertices_size + normals_size + tex_coord_chunk_size*index, tex_coord_chunk_size, tex_coords);
index++;
}
+
+ tree->thread_done = true;
+ tree->thread_running = false;
+
+ tree->node_lock.unlock();
+ tree->vbo_lock.unlock();
+}
+
+void Quadtree::make_vbo() {
+ if(thread_running || thread_done || thread_buffer)
+ return;
+
+ nodes = count_nodes();
+ glGenBuffers(1, &temp_vbo);
+ glBindBuffer(GL_ARRAY_BUFFER, temp_vbo);
+
+ const size_t vertex_chunk_size = sizeof(float)*3*12;
+ const size_t vertices_size = vertex_chunk_size*nodes;
+ const size_t normal_chunk_size = vertex_chunk_size;
+ const size_t normals_size = normal_chunk_size*nodes;
+ const size_t tex_coord_chunk_size = sizeof(float)*2*12;
+ const size_t tex_coords_size = tex_coord_chunk_size*nodes;
+
+ buf_size = sizeof(float)*(vertices_size + normals_size + tex_coords_size);
+
+ glBufferData(GL_ARRAY_BUFFER, sizeof(float)*(vertices_size + normals_size + tex_coords_size), NULL, GL_STATIC_DRAW);
+
+ thread_buffer = (float*)glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
+
+ thread_running = true;
+ boost::thread(UpdateThread(this, thread_buffer));
+}
+
+void Quadtree::update_vbo() {
+ if(!vbo_lock.try_lock()) {
+ return;
+ }
+
+ if(!thread_done || !thread_buffer || thread_running) {
+ vbo_lock.unlock();
+ return;
+ }
+
+ thread_done = false;
+
+ glBindBuffer(GL_ARRAY_BUFFER, temp_vbo);
+ glBufferData(GL_ARRAY_BUFFER, buf_size, thread_buffer, GL_STATIC_DRAW);
+
+ thread_buffer = NULL;
+
+ vertices = nodes*12;
+
+ if(vbo_object)
+ glDeleteBuffers(1, &vbo_object);
+ vbo_object = temp_vbo;
+ temp_vbo = 0;
+
+ vbo_lock.unlock();
}
Quadtree::QuadNode* Quadtree::find(float x, float y, int level) {
@@ -624,4 +694,3 @@ Quadtree::QuadNode *Quadtree::get_down(Quadtree::QuadNode *node) {
return NULL;
return n;
}
-