summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SConstruct2
-rw-r--r--main.cpp14
-rw-r--r--quadtree.cpp159
-rw-r--r--quadtree.h17
-rw-r--r--scene.cpp1
5 files changed, 135 insertions, 58 deletions
diff --git a/SConstruct b/SConstruct
index 1e7d2e3..ee8efa8 100644
--- a/SConstruct
+++ b/SConstruct
@@ -8,7 +8,7 @@ AddOption('--release', action = 'store_true')
AddOption('--profiling', action = 'store_true')
env.Append(CPPPATH = ['.'])
-env.Append(LIBS = ['GL', 'GLU'])
+env.Append(LIBS = ['GL', 'GLU', 'boost_thread'])
env.ParseConfig('sdl-config --cflags --libs')
env.ParseConfig('pkg-config --cflags --libs SDL_image')
env.ParseConfig('pkg-config --cflags --libs ftgl')
diff --git a/main.cpp b/main.cpp
index 5f089e8..eee70dd 100644
--- a/main.cpp
+++ b/main.cpp
@@ -76,24 +76,14 @@ int main(int argc, char **argv) {
bool gravity = true;
SDL_WarpMouse(video::width/2, video::height/2);
unsigned int last_time = SDL_GetTicks();
- unsigned int last_update = SDL_GetTicks();
- /*boost::timer t;
- double last_time = 0;*/
Vector3 selected;
Quadtree::QuadNode *node;
Quadtree::QuadNode *last_node = NULL;
scene.update();
while(running) {
unsigned int time = SDL_GetTicks();
- //double time = t.elapsed();
- //t.restart();
unsigned int steps = time - last_time + 1;
- //double steps = (time - last_time) * 1000;
last_time = time;
- /*if(time - last_update > 5000) {
- scene.update();
- last_update = time;
- }*/
bool do_select = 0;
int sx, sy;
while(SDL_PollEvent(&event)) {
@@ -297,8 +287,8 @@ int main(int argc, char **argv) {
float height = font->LineHeight();
glColor3f(1, 1, 1);
glTranslatef(0, video::height-height, 0);
- font->Render((boost::format("%dx%d %d levels %d nodes tree creation time: %f steps: %d")
- % scene.qt->width % scene.qt->height % scene.qt->levels % scene.qt->nodes % scene.qt->init_time % steps).str().c_str());
+ font->Render((boost::format("%dx%d %d levels %d nodes tree creation time: %f steps: %d update: %d")
+ % scene.qt->width % scene.qt->height % scene.qt->levels % scene.qt->nodes % scene.qt->init_time % steps % scene.qt->thread_running).str().c_str());
//glTranslatef(0, height, 0);
//font->Render((boost::format("selected: %x") % selected).str().c_str());
glTranslatef(0, -height, 0);
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;
}
-
diff --git a/quadtree.h b/quadtree.h
index 951a98e..b927dee 100644
--- a/quadtree.h
+++ b/quadtree.h
@@ -3,8 +3,18 @@
#include "vector.h"
+#include <boost/thread.hpp>
+
class Quadtree {
public:
+
+ struct UpdateThread {
+ Quadtree *tree;
+ float *buffer;
+ UpdateThread(Quadtree *t, float *b);
+ void operator()();
+ };
+
struct QuadNode {
Quadtree *tree;
QuadNode *parent;
@@ -29,9 +39,15 @@ class Quadtree {
};
float *heights;
+ float *thread_buffer;
+ size_t buf_size;
+ bool thread_done, thread_running;
+ boost::mutex vbo_lock;
+ boost::mutex node_lock;
int width, height, levels;
float init_time;
QuadNode *root;
+ unsigned int temp_vbo;
unsigned int vbo_object;
unsigned int nodes;
unsigned int vertices;
@@ -43,6 +59,7 @@ class Quadtree {
void create_nodes(int levels);
unsigned int count_nodes();
void make_vbo();
+ void update_vbo();
QuadNode *find(float x, float y, int level = -1);
QuadNode *get_left(QuadNode *node);
QuadNode *get_right(QuadNode *node);
diff --git a/scene.cpp b/scene.cpp
index 4b96595..5bbd1b2 100644
--- a/scene.cpp
+++ b/scene.cpp
@@ -92,4 +92,5 @@ bool Scene::select(int x, int y, float& px, float& py, float& pz) {
void Scene::update() {
qt->update(pos.x, pos.z);
+ qt->update_vbo();
}