clray
diff src/scene.cc @ 35:7d77ded5f890
stopped using a heap to flatten the kdtree. added explicit left/right indices
author | John Tsiombikas <nuclear@member.fsf.org> |
---|---|
date | Thu, 26 Aug 2010 20:24:07 +0100 |
parents | 4cf4919c3812 |
children | 4dec8853bf75 |
line diff
1.1 --- a/src/scene.cc Tue Aug 24 05:47:04 2010 +0100 1.2 +++ b/src/scene.cc Thu Aug 26 20:24:07 2010 +0100 1.3 @@ -1,15 +1,18 @@ 1.4 +#include <stdlib.h> 1.5 #include <math.h> 1.6 #include <float.h> 1.7 #include <assert.h> 1.8 +#include <map> 1.9 #include "scene.h" 1.10 #include "ogl.h" 1.11 1.12 1.13 +static void flatten_kdtree(const KDNode *node, KDNodeGPU *kdbuf, int *count, std::map<const KDNode*, int> *flatmap); 1.14 +static void fix_child_links(const KDNode *node, KDNodeGPU *kdbuf, const std::map<const KDNode*, int> &flatmap); 1.15 static void draw_kdtree(const KDNode *node, int level = 0); 1.16 static bool build_kdtree(KDNode *kd, const Face *faces, int level = 0); 1.17 static float eval_cost(const Face *faces, const int *face_idx, int num_faces, const AABBox &aabb, int axis); 1.18 static void free_kdtree(KDNode *node); 1.19 -static void kdtree_gpu_flatten(KDNodeGPU *kdbuf, int idx, const KDNode *node); 1.20 static void print_item_counts(const KDNode *node, int level); 1.21 1.22 1.23 @@ -123,6 +126,11 @@ 1.24 return (int)matlib.size(); 1.25 } 1.26 1.27 +int Scene::get_num_kdnodes() const 1.28 +{ 1.29 + return kdtree_nodes(kdtree); 1.30 +} 1.31 + 1.32 Material *Scene::get_materials() 1.33 { 1.34 if(matlib.empty()) { 1.35 @@ -159,6 +167,27 @@ 1.36 return facebuf; 1.37 } 1.38 1.39 +static int find_node_index(const KDNode *node, const std::map<const KDNode*, int> &flatmap); 1.40 + 1.41 +static bool validate_flat_tree(const KDNode *node, const KDNodeGPU *kdbuf, int count, const std::map<const KDNode*, int> &flatmap) 1.42 +{ 1.43 + if(!node) return true; 1.44 + 1.45 + int idx = find_node_index(node, flatmap); 1.46 + int left_idx = find_node_index(node->left, flatmap); 1.47 + int right_idx = find_node_index(node->right, flatmap); 1.48 + 1.49 + if(kdbuf[idx].left != left_idx) { 1.50 + fprintf(stderr, "%d's left should be %d. it's: %d\n", idx, left_idx, kdbuf[idx].left); 1.51 + return false; 1.52 + } 1.53 + if(kdbuf[idx].right != right_idx) { 1.54 + fprintf(stderr, "%d's right should be %d. it's: %d\n", idx, right_idx, kdbuf[idx].right); 1.55 + return false; 1.56 + } 1.57 + return validate_flat_tree(node->left, kdbuf, count, flatmap) && validate_flat_tree(node->right, kdbuf, count, flatmap); 1.58 +} 1.59 + 1.60 const KDNodeGPU *Scene::get_kdtree_buffer() const 1.61 { 1.62 if(kdbuf) { 1.63 @@ -169,29 +198,72 @@ 1.64 ((Scene*)this)->build_kdtree(); 1.65 } 1.66 1.67 - int max_nodes = (int)pow(2, kdtree_depth(kdtree)) - 1; 1.68 - printf("allocating storage for the complete tree (%d)\n", max_nodes); 1.69 + /* we'll associate kdnodes with flattened array indices through this map as 1.70 + * we add them so that the second child-index pass, will be able to find 1.71 + * the children indices of each node. 1.72 + */ 1.73 + std::map<const KDNode*, int> flatmap; 1.74 + flatmap[0] = -1; 1.75 1.76 - kdbuf = new KDNodeGPU[max_nodes + 1]; 1.77 - kdtree_gpu_flatten(kdbuf, 1, kdtree); 1.78 + int num_nodes = get_num_kdnodes(); 1.79 + kdbuf = new KDNodeGPU[num_nodes]; 1.80 + 1.81 + int count = 0; 1.82 + 1.83 + // first arrange the kdnodes into an array (flatten) 1.84 + flatten_kdtree(kdtree, kdbuf, &count, &flatmap); 1.85 + 1.86 + // then fix all the left/right links to point to the correct nodes 1.87 + fix_child_links(kdtree, kdbuf, flatmap); 1.88 + 1.89 + assert(validate_flat_tree(kdtree, kdbuf, count, flatmap)); 1.90 + 1.91 return kdbuf; 1.92 } 1.93 1.94 -static int ipow(int x, int n) 1.95 +static void flatten_kdtree(const KDNode *node, KDNodeGPU *kdbuf, int *count, std::map<const KDNode*, int> *flatmap) 1.96 { 1.97 - assert(n >= 0); 1.98 + int idx = (*count)++; 1.99 1.100 - int res = 1; 1.101 - for(int i=0; i<n; i++) { 1.102 - res *= x; 1.103 + // copy the node 1.104 + kdbuf[idx].aabb = node->aabb; 1.105 + for(size_t i=0; i<node->face_idx.size(); i++) { 1.106 + kdbuf[idx].face_idx[i] = node->face_idx[i]; 1.107 } 1.108 - return res; 1.109 + kdbuf[idx].num_faces = node->face_idx.size(); 1.110 + 1.111 + // update the node* -> array-position mapping 1.112 + (*flatmap)[node] = idx; 1.113 + 1.114 + // recurse to the left/right (if we're not in a leaf node) 1.115 + if(node->left) { 1.116 + assert(node->right); 1.117 + 1.118 + flatten_kdtree(node->left, kdbuf, count, flatmap); 1.119 + flatten_kdtree(node->right, kdbuf, count, flatmap); 1.120 + } 1.121 } 1.122 1.123 -int Scene::get_kdtree_buffer_size() const 1.124 +static int find_node_index(const KDNode *node, const std::map<const KDNode*, int> &flatmap) 1.125 { 1.126 - // 2**depth - 1 nodes for the complete tree + 1 for the unused heap item 0. 1.127 - return ipow(2, kdtree_depth(kdtree)) * sizeof(KDNodeGPU); 1.128 + std::map<const KDNode*, int>::const_iterator it = flatmap.find(node); 1.129 + assert(it != flatmap.end()); 1.130 + return it->second; 1.131 +} 1.132 + 1.133 +static void fix_child_links(const KDNode *node, KDNodeGPU *kdbuf, const std::map<const KDNode*, int> &flatmap) 1.134 +{ 1.135 + if(!node) return; 1.136 + 1.137 + int idx = find_node_index(node, flatmap); 1.138 + 1.139 + kdbuf[idx].left = find_node_index(node->left, flatmap); 1.140 + if(!node->left && kdbuf[idx].left != -1) abort(); 1.141 + kdbuf[idx].right = find_node_index(node->right, flatmap); 1.142 + if(!node->right && kdbuf[idx].right != -1) abort(); 1.143 + 1.144 + fix_child_links(node->left, kdbuf, flatmap); 1.145 + fix_child_links(node->right, kdbuf, flatmap); 1.146 } 1.147 1.148 void Scene::draw_kdtree() const 1.149 @@ -442,33 +514,6 @@ 1.150 return kdtree_nodes(node->left) + kdtree_nodes(node->right) + 1; 1.151 } 1.152 1.153 -#define MAX_FACES (sizeof dest->face_idx / sizeof *dest->face_idx) 1.154 -static void kdtree_gpu_flatten(KDNodeGPU *kdbuf, int idx, const KDNode *node) 1.155 -{ 1.156 - KDNodeGPU *dest = kdbuf + idx; 1.157 - 1.158 - dest->aabb = node->aabb; 1.159 - dest->num_faces = 0; 1.160 - 1.161 - for(size_t i=0; i<node->face_idx.size(); i++) { 1.162 - if(dest->num_faces >= (int)MAX_FACES) { 1.163 - fprintf(stderr, "kdtree_gpu_flatten WARNING: more than %d faces in node, skipping!\n", (int)MAX_FACES); 1.164 - break; 1.165 - } 1.166 - dest->face_idx[dest->num_faces++] = node->face_idx[i]; 1.167 - } 1.168 - 1.169 - if(node->left) { 1.170 - assert(node->right); 1.171 - assert(!dest->num_faces); 1.172 - 1.173 - dest->num_faces = -1; 1.174 - 1.175 - kdtree_gpu_flatten(kdbuf, idx * 2, node->left); 1.176 - kdtree_gpu_flatten(kdbuf, idx * 2 + 1, node->right); 1.177 - } 1.178 -} 1.179 - 1.180 static void print_item_counts(const KDNode *node, int level) 1.181 { 1.182 if(!node) return;