Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndre Susano Pinto <andresusanopinto@gmail.com>2009-07-12 02:13:01 +0400
committerAndre Susano Pinto <andresusanopinto@gmail.com>2009-07-12 02:13:01 +0400
commitd6aefa6abd6d99a0024e7d576a3766f72d115b7f (patch)
treeb66c365c7bd7f806ceb3c80c116b562fd9956d71 /source/blender/render/intern
parente56795b4fae00ca6d15d676843386c6fd34485bf (diff)
Added module bf_render_raytrace (source/blender/render/intern/raytrace)
to be able to use C++ at raytrace code C++ used in here is basicly C with templates and function overloads, to make it easier to reuse code between structures. For now BVH was converted in C++ and moved to this module
Diffstat (limited to 'source/blender/render/intern')
-rw-r--r--source/blender/render/intern/raytrace/bvh.h288
-rw-r--r--source/blender/render/intern/raytrace/rayobject_bvh.cpp470
-rw-r--r--source/blender/render/intern/source/rayobject_bvh.c474
3 files changed, 758 insertions, 474 deletions
diff --git a/source/blender/render/intern/raytrace/bvh.h b/source/blender/render/intern/raytrace/bvh.h
new file mode 100644
index 00000000000..d2da2690c49
--- /dev/null
+++ b/source/blender/render/intern/raytrace/bvh.h
@@ -0,0 +1,288 @@
+
+/* bvh tree generics */
+template<class Tree> static int bvh_intersect(Tree *obj, Isect *isec);
+
+template<class Tree> static void bvh_add(Tree *obj, RayObject *ob)
+{
+ rtbuild_add( obj->builder, ob );
+}
+
+template<class Tree> static void bvh_done(Tree *obj);
+
+template<class Tree>
+static void bvh_free(Tree *obj)
+{
+ if(obj->builder)
+ rtbuild_free(obj->builder);
+
+ if(obj->node_arena)
+ BLI_memarena_free(obj->node_arena);
+
+ MEM_freeN(obj);
+}
+
+template<class Tree>
+static void bvh_bb(Tree *obj, float *min, float *max)
+{
+ bvh_node_merge_bb(obj->root, min, max);
+}
+
+
+template<class Tree>
+static float bvh_cost(Tree *obj)
+{
+ assert(obj->cost >= 0.0);
+ return obj->cost;
+}
+
+
+
+/* bvh tree nodes generics */
+template<class Node> static inline int bvh_node_hit_test(Node *node, Isect *isec)
+{
+ return RE_rayobject_bb_intersect(isec, (const float*)node->bb) != FLT_MAX;
+}
+
+
+template<class Node>
+static void bvh_node_merge_bb(Node *node, float *min, float *max)
+{
+ if(RayObject_isAligned(node))
+ {
+ DO_MIN(node->bb , min);
+ DO_MAX(node->bb+3, max);
+ }
+ else
+ {
+ RE_rayobject_merge_bb( (RayObject*)node, min, max);
+ }
+}
+
+
+
+/*
+ * recursivly transverse a BVH looking for a rayhit using a local stack
+ */
+template<class Node> static inline void bvh_node_push_childs(Node *node, Isect *isec, Node **stack, int &stack_pos);
+
+template<class Node,int MAX_STACK_SIZE>
+static int bvh_node_stack_raycast(Node *root, Isect *isec)
+{
+ Node *stack[MAX_STACK_SIZE];
+ int hit = 0, stack_pos = 0;
+
+ stack[stack_pos++] = root;
+ while(stack_pos)
+ {
+ Node *node = stack[--stack_pos];
+ if(RayObject_isAligned(node))
+ {
+ if(bvh_node_hit_test(node,isec))
+ {
+ bvh_node_push_childs(node, isec, stack, stack_pos);
+ assert(stack_pos <= MAX_STACK_SIZE);
+ }
+ }
+ else
+ {
+ hit |= RE_rayobject_intersect( (RayObject*)node, isec);
+ if(hit && isec->mode == RE_RAY_SHADOW) return hit;
+ }
+ }
+ return hit;
+
+}
+
+/*
+ * recursively transverse a BVH looking for a rayhit using system stack
+ */
+/*
+template<class Node>
+static int bvh_node_raycast(Node *node, Isect *isec)
+{
+ int hit = 0;
+ if(bvh_test_node(node, isec))
+ {
+ if(isec->idot_axis[node->split_axis] > 0.0f)
+ {
+ int i;
+ for(i=0; i<BVH_NCHILDS; i++)
+ if(RayObject_isAligned(node->child[i]))
+ {
+ if(node->child[i] == 0) break;
+
+ hit |= bvh_node_raycast(node->child[i], isec);
+ if(hit && isec->mode == RE_RAY_SHADOW) return hit;
+ }
+ else
+ {
+ hit |= RE_rayobject_intersect( (RayObject*)node->child[i], isec);
+ if(hit && isec->mode == RE_RAY_SHADOW) return hit;
+ }
+ }
+ else
+ {
+ int i;
+ for(i=BVH_NCHILDS-1; i>=0; i--)
+ if(RayObject_isAligned(node->child[i]))
+ {
+ if(node->child[i])
+ {
+ hit |= dfs_raycast(node->child[i], isec);
+ if(hit && isec->mode == RE_RAY_SHADOW) return hit;
+ }
+ }
+ else
+ {
+ hit |= RE_rayobject_intersect( (RayObject*)node->child[i], isec);
+ if(hit && isec->mode == RE_RAY_SHADOW) return hit;
+ }
+ }
+ }
+ return hit;
+}
+*/
+
+/* bvh tree generics */
+template<class Tree> static int bvh_intersect(Tree *obj, Isect *isec);
+
+template<class Tree> static void bvh_add(Tree *obj, RayObject *ob)
+{
+ rtbuild_add( obj->builder, ob );
+}
+
+template<class Tree> static void bvh_done(Tree *obj);
+
+template<class Tree>
+static void bvh_free(Tree *obj)
+{
+ if(obj->builder)
+ rtbuild_free(obj->builder);
+
+ if(obj->node_arena)
+ BLI_memarena_free(obj->node_arena);
+
+ MEM_freeN(obj);
+}
+
+template<class Tree>
+static void bvh_bb(Tree *obj, float *min, float *max)
+{
+ bvh_node_merge_bb(obj->root, min, max);
+}
+
+
+template<class Tree>
+static float bvh_cost(Tree *obj)
+{
+ assert(obj->cost >= 0.0);
+ return obj->cost;
+}
+
+
+
+/* bvh tree nodes generics */
+template<class Node> static inline int bvh_node_hit_test(Node *node, Isect *isec)
+{
+ return RE_rayobject_bb_intersect(isec, (const float*)node->bb) != FLT_MAX;
+}
+
+
+template<class Node>
+static void bvh_node_merge_bb(Node *node, float *min, float *max)
+{
+ if(RayObject_isAligned(node))
+ {
+ DO_MIN(node->bb , min);
+ DO_MAX(node->bb+3, max);
+ }
+ else
+ {
+ RE_rayobject_merge_bb( (RayObject*)node, min, max);
+ }
+}
+
+
+
+/*
+ * recursivly transverse a BVH looking for a rayhit using a local stack
+ */
+template<class Node> static inline void bvh_node_push_childs(Node *node, Isect *isec, Node **stack, int &stack_pos);
+
+template<class Node,int MAX_STACK_SIZE>
+static int bvh_node_stack_raycast(Node *root, Isect *isec)
+{
+ Node *stack[MAX_STACK_SIZE];
+ int hit = 0, stack_pos = 0;
+
+ stack[stack_pos++] = root;
+ while(stack_pos)
+ {
+ Node *node = stack[--stack_pos];
+ if(RayObject_isAligned(node))
+ {
+ if(bvh_node_hit_test(node,isec))
+ {
+ bvh_node_push_childs(node, isec, stack, stack_pos);
+ assert(stack_pos <= MAX_STACK_SIZE);
+ }
+ }
+ else
+ {
+ hit |= RE_rayobject_intersect( (RayObject*)node, isec);
+ if(hit && isec->mode == RE_RAY_SHADOW) return hit;
+ }
+ }
+ return hit;
+
+}
+
+/*
+ * recursively transverse a BVH looking for a rayhit using system stack
+ */
+/*
+template<class Node>
+static int bvh_node_raycast(Node *node, Isect *isec)
+{
+ int hit = 0;
+ if(bvh_test_node(node, isec))
+ {
+ if(isec->idot_axis[node->split_axis] > 0.0f)
+ {
+ int i;
+ for(i=0; i<BVH_NCHILDS; i++)
+ if(RayObject_isAligned(node->child[i]))
+ {
+ if(node->child[i] == 0) break;
+
+ hit |= bvh_node_raycast(node->child[i], isec);
+ if(hit && isec->mode == RE_RAY_SHADOW) return hit;
+ }
+ else
+ {
+ hit |= RE_rayobject_intersect( (RayObject*)node->child[i], isec);
+ if(hit && isec->mode == RE_RAY_SHADOW) return hit;
+ }
+ }
+ else
+ {
+ int i;
+ for(i=BVH_NCHILDS-1; i>=0; i--)
+ if(RayObject_isAligned(node->child[i]))
+ {
+ if(node->child[i])
+ {
+ hit |= dfs_raycast(node->child[i], isec);
+ if(hit && isec->mode == RE_RAY_SHADOW) return hit;
+ }
+ }
+ else
+ {
+ hit |= RE_rayobject_intersect( (RayObject*)node->child[i], isec);
+ if(hit && isec->mode == RE_RAY_SHADOW) return hit;
+ }
+ }
+ }
+ return hit;
+}
+*/
diff --git a/source/blender/render/intern/raytrace/rayobject_bvh.cpp b/source/blender/render/intern/raytrace/rayobject_bvh.cpp
new file mode 100644
index 00000000000..7bf87e09181
--- /dev/null
+++ b/source/blender/render/intern/raytrace/rayobject_bvh.cpp
@@ -0,0 +1,470 @@
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+extern "C"
+{
+#include <assert.h>
+#include "MEM_guardedalloc.h"
+#include "BKE_utildefines.h"
+#include "BLI_arithb.h"
+#include "BLI_memarena.h"
+#include "RE_raytrace.h"
+#include "rayobject_rtbuild.h"
+#include "rayobject.h"
+};
+
+#include "bvh.h"
+
+#define BVH_NCHILDS 2
+#define RAY_BB_TEST_COST (0.2f)
+#define DFS_STACK_SIZE 64
+#define DYNAMIC_ALLOC
+
+//#define rtbuild_split rtbuild_mean_split_largest_axis /* objects mean split on the longest axis, childs BB are allowed to overlap */
+//#define rtbuild_split rtbuild_median_split_largest_axis /* space median split on the longest axis, childs BB are allowed to overlap */
+#define rtbuild_split rtbuild_heuristic_object_split /* split objects using heuristic */
+
+struct BVHNode
+{
+ BVHNode *child[BVH_NCHILDS];
+ float bb[6];
+ int split_axis;
+};
+
+struct BVHTree
+{
+ RayObject rayobj;
+
+ BVHNode *root;
+
+ MemArena *node_arena;
+
+ float cost;
+ RTBuilder *builder;
+};
+
+
+/*
+ * Push nodes (used on dfs)
+ */
+template<class Node>
+inline static void bvh_node_push_childs(Node *node, Isect *isec, Node **stack, int &stack_pos)
+{
+ //push nodes in reverse visit order
+ if(isec->idot_axis[node->split_axis] < 0.0f)
+ {
+ int i;
+ for(i=0; i<BVH_NCHILDS; i++)
+ if(node->child[i] == 0)
+ break;
+ else
+ stack[stack_pos++] = node->child[i];
+ }
+ else
+ {
+ int i;
+ for(i=BVH_NCHILDS-1; i>=0; i--)
+ if(node->child[i] != 0)
+ stack[stack_pos++] = node->child[i];
+ }
+}
+
+/*
+ * BVH done
+ */
+static BVHNode *bvh_new_node(BVHTree *tree, int nid)
+{
+ BVHNode *node = (BVHNode*)BLI_memarena_alloc(tree->node_arena, sizeof(BVHNode));
+ return node;
+}
+
+static int child_id(int pid, int nchild)
+{
+ //N child of node A = A * K + (2 - K) + N, (0 <= N < K)
+ return pid*BVH_NCHILDS+(2-BVH_NCHILDS)+nchild;
+}
+
+
+static BVHNode *bvh_rearrange(BVHTree *tree, RTBuilder *builder, int nid, float *cost)
+{
+ *cost = 0;
+ if(rtbuild_size(builder) == 0)
+ return 0;
+
+ if(rtbuild_size(builder) == 1)
+ {
+ RayObject *child = builder->begin[0];
+
+ if(RayObject_isRayFace(child))
+ {
+ int i;
+ BVHNode *parent = bvh_new_node(tree, nid);
+ parent->split_axis = 0;
+
+ INIT_MINMAX(parent->bb, parent->bb+3);
+
+ for(i=0; i<1; i++)
+ {
+ parent->child[i] = (BVHNode*)builder->begin[i];
+ bvh_node_merge_bb(parent->child[i], parent->bb, parent->bb+3);
+ }
+ for(; i<BVH_NCHILDS; i++)
+ parent->child[i] = 0;
+
+ *cost = RE_rayobject_cost(child)+RAY_BB_TEST_COST;
+ return parent;
+ }
+ else
+ {
+ assert(!RayObject_isAligned(child));
+ //Its a sub-raytrace structure, assume it has it own raycast
+ //methods and adding a Bounding Box arround is unnecessary
+
+ *cost = RE_rayobject_cost(child);
+ return (BVHNode*)child;
+ }
+ }
+ else
+ {
+ int i;
+ RTBuilder tmp;
+ BVHNode *parent = bvh_new_node(tree, nid);
+ int nc = rtbuild_split(builder, BVH_NCHILDS);
+
+
+ INIT_MINMAX(parent->bb, parent->bb+3);
+ parent->split_axis = builder->split_axis;
+ for(i=0; i<nc; i++)
+ {
+ float cbb[6];
+ float tcost;
+ parent->child[i] = bvh_rearrange( tree, rtbuild_get_child(builder, i, &tmp), child_id(nid,i), &tcost );
+
+ INIT_MINMAX(cbb, cbb+3);
+ bvh_node_merge_bb(parent->child[i], cbb, cbb+3);
+ DO_MIN(cbb, parent->bb);
+ DO_MAX(cbb+3, parent->bb+3);
+
+ *cost += tcost*bb_area(cbb, cbb+3);
+ }
+ for(; i<BVH_NCHILDS; i++)
+ parent->child[i] = 0;
+
+ *cost /= bb_area(parent->bb, parent->bb+3);
+ *cost += nc*RAY_BB_TEST_COST;
+ return parent;
+ }
+}
+
+template<>
+void bvh_done<BVHTree>(BVHTree *obj)
+{
+ int needed_nodes = (rtbuild_size(obj->builder)+1)*2;
+ if(needed_nodes > BLI_MEMARENA_STD_BUFSIZE)
+ needed_nodes = BLI_MEMARENA_STD_BUFSIZE;
+
+ obj->node_arena = BLI_memarena_new(needed_nodes);
+ BLI_memarena_use_malloc(obj->node_arena);
+
+
+ obj->root = bvh_rearrange( obj, obj->builder, 1, &obj->cost );
+
+ rtbuild_free( obj->builder );
+ obj->builder = NULL;
+}
+
+template<>
+int bvh_intersect<BVHTree>(BVHTree *obj, Isect* isec)
+{
+ if(RayObject_isAligned(obj->root))
+ return bvh_node_stack_raycast<BVHNode,64>(obj->root, isec);
+ else
+ return RE_rayobject_intersect( (RayObject*) obj->root, isec );
+}
+
+
+/* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */
+static RayObjectAPI bvh_api =
+{
+ (RE_rayobject_raycast_callback) ((int(*)(BVHTree*,Isect*)) &bvh_intersect<BVHTree>),
+ (RE_rayobject_add_callback) ((void(*)(BVHTree*,RayObject*)) &bvh_add<BVHTree>),
+ (RE_rayobject_done_callback) ((void(*)(BVHTree*)) &bvh_done<BVHTree>),
+ (RE_rayobject_free_callback) ((void(*)(BVHTree*)) &bvh_free<BVHTree>),
+ (RE_rayobject_merge_bb_callback)((void(*)(BVHTree*,float*,float*)) &bvh_bb<BVHTree>),
+ (RE_rayobject_cost_callback) ((float(*)(BVHTree*)) &bvh_cost<BVHTree>)
+};
+
+
+RayObject *RE_rayobject_bvh_create(int size)
+{
+ BVHTree *obj= (BVHTree*)MEM_callocN(sizeof(BVHTree), "BVHTree");
+ assert( RayObject_isAligned(obj) ); /* RayObject API assumes real data to be 4-byte aligned */
+
+ obj->rayobj.api = &bvh_api;
+ obj->root = NULL;
+
+ obj->node_arena = NULL;
+ obj->builder = rtbuild_create( size );
+
+ return RayObject_unalignRayAPI((RayObject*) obj);
+}
+/**
+ * $Id$
+ *
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ *
+ * The Original Code is Copyright (C) 2009 Blender Foundation.
+ * All rights reserved.
+ *
+ * The Original Code is: all of this file.
+ *
+ * Contributor(s): André Pinto.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+extern "C"
+{
+#include <assert.h>
+#include "MEM_guardedalloc.h"
+#include "BKE_utildefines.h"
+#include "BLI_arithb.h"
+#include "BLI_memarena.h"
+#include "RE_raytrace.h"
+#include "rayobject_rtbuild.h"
+#include "rayobject.h"
+};
+
+#include "bvh.h"
+
+#define BVH_NCHILDS 2
+#define RAY_BB_TEST_COST (0.2f)
+#define DFS_STACK_SIZE 64
+#define DYNAMIC_ALLOC
+
+//#define rtbuild_split rtbuild_mean_split_largest_axis /* objects mean split on the longest axis, childs BB are allowed to overlap */
+//#define rtbuild_split rtbuild_median_split_largest_axis /* space median split on the longest axis, childs BB are allowed to overlap */
+#define rtbuild_split rtbuild_heuristic_object_split /* split objects using heuristic */
+
+struct BVHNode
+{
+ BVHNode *child[BVH_NCHILDS];
+ float bb[6];
+ int split_axis;
+};
+
+struct BVHTree
+{
+ RayObject rayobj;
+
+ BVHNode *root;
+
+ MemArena *node_arena;
+
+ float cost;
+ RTBuilder *builder;
+};
+
+
+/*
+ * Push nodes (used on dfs)
+ */
+template<class Node>
+inline static void bvh_node_push_childs(Node *node, Isect *isec, Node **stack, int &stack_pos)
+{
+ //push nodes in reverse visit order
+ if(isec->idot_axis[node->split_axis] < 0.0f)
+ {
+ int i;
+ for(i=0; i<BVH_NCHILDS; i++)
+ if(node->child[i] == 0)
+ break;
+ else
+ stack[stack_pos++] = node->child[i];
+ }
+ else
+ {
+ int i;
+ for(i=BVH_NCHILDS-1; i>=0; i--)
+ if(node->child[i] != 0)
+ stack[stack_pos++] = node->child[i];
+ }
+}
+
+/*
+ * BVH done
+ */
+static BVHNode *bvh_new_node(BVHTree *tree, int nid)
+{
+ BVHNode *node = (BVHNode*)BLI_memarena_alloc(tree->node_arena, sizeof(BVHNode));
+ return node;
+}
+
+static int child_id(int pid, int nchild)
+{
+ //N child of node A = A * K + (2 - K) + N, (0 <= N < K)
+ return pid*BVH_NCHILDS+(2-BVH_NCHILDS)+nchild;
+}
+
+
+static BVHNode *bvh_rearrange(BVHTree *tree, RTBuilder *builder, int nid, float *cost)
+{
+ *cost = 0;
+ if(rtbuild_size(builder) == 0)
+ return 0;
+
+ if(rtbuild_size(builder) == 1)
+ {
+ RayObject *child = builder->begin[0];
+
+ if(RayObject_isRayFace(child))
+ {
+ int i;
+ BVHNode *parent = bvh_new_node(tree, nid);
+ parent->split_axis = 0;
+
+ INIT_MINMAX(parent->bb, parent->bb+3);
+
+ for(i=0; i<1; i++)
+ {
+ parent->child[i] = (BVHNode*)builder->begin[i];
+ bvh_node_merge_bb(parent->child[i], parent->bb, parent->bb+3);
+ }
+ for(; i<BVH_NCHILDS; i++)
+ parent->child[i] = 0;
+
+ *cost = RE_rayobject_cost(child)+RAY_BB_TEST_COST;
+ return parent;
+ }
+ else
+ {
+ assert(!RayObject_isAligned(child));
+ //Its a sub-raytrace structure, assume it has it own raycast
+ //methods and adding a Bounding Box arround is unnecessary
+
+ *cost = RE_rayobject_cost(child);
+ return (BVHNode*)child;
+ }
+ }
+ else
+ {
+ int i;
+ RTBuilder tmp;
+ BVHNode *parent = bvh_new_node(tree, nid);
+ int nc = rtbuild_split(builder, BVH_NCHILDS);
+
+
+ INIT_MINMAX(parent->bb, parent->bb+3);
+ parent->split_axis = builder->split_axis;
+ for(i=0; i<nc; i++)
+ {
+ float cbb[6];
+ float tcost;
+ parent->child[i] = bvh_rearrange( tree, rtbuild_get_child(builder, i, &tmp), child_id(nid,i), &tcost );
+
+ INIT_MINMAX(cbb, cbb+3);
+ bvh_node_merge_bb(parent->child[i], cbb, cbb+3);
+ DO_MIN(cbb, parent->bb);
+ DO_MAX(cbb+3, parent->bb+3);
+
+ *cost += tcost*bb_area(cbb, cbb+3);
+ }
+ for(; i<BVH_NCHILDS; i++)
+ parent->child[i] = 0;
+
+ *cost /= bb_area(parent->bb, parent->bb+3);
+ *cost += nc*RAY_BB_TEST_COST;
+ return parent;
+ }
+}
+
+template<>
+void bvh_done<BVHTree>(BVHTree *obj)
+{
+ int needed_nodes = (rtbuild_size(obj->builder)+1)*2;
+ if(needed_nodes > BLI_MEMARENA_STD_BUFSIZE)
+ needed_nodes = BLI_MEMARENA_STD_BUFSIZE;
+
+ obj->node_arena = BLI_memarena_new(needed_nodes);
+ BLI_memarena_use_malloc(obj->node_arena);
+
+
+ obj->root = bvh_rearrange( obj, obj->builder, 1, &obj->cost );
+
+ rtbuild_free( obj->builder );
+ obj->builder = NULL;
+}
+
+template<>
+int bvh_intersect<BVHTree>(BVHTree *obj, Isect* isec)
+{
+ if(RayObject_isAligned(obj->root))
+ return bvh_node_stack_raycast<BVHNode,64>(obj->root, isec);
+ else
+ return RE_rayobject_intersect( (RayObject*) obj->root, isec );
+}
+
+
+/* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */
+static RayObjectAPI bvh_api =
+{
+ (RE_rayobject_raycast_callback) ((int(*)(BVHTree*,Isect*)) &bvh_intersect<BVHTree>),
+ (RE_rayobject_add_callback) ((void(*)(BVHTree*,RayObject*)) &bvh_add<BVHTree>),
+ (RE_rayobject_done_callback) ((void(*)(BVHTree*)) &bvh_done<BVHTree>),
+ (RE_rayobject_free_callback) ((void(*)(BVHTree*)) &bvh_free<BVHTree>),
+ (RE_rayobject_merge_bb_callback)((void(*)(BVHTree*,float*,float*)) &bvh_bb<BVHTree>),
+ (RE_rayobject_cost_callback) ((float(*)(BVHTree*)) &bvh_cost<BVHTree>)
+};
+
+
+RayObject *RE_rayobject_bvh_create(int size)
+{
+ BVHTree *obj= (BVHTree*)MEM_callocN(sizeof(BVHTree), "BVHTree");
+ assert( RayObject_isAligned(obj) ); /* RayObject API assumes real data to be 4-byte aligned */
+
+ obj->rayobj.api = &bvh_api;
+ obj->root = NULL;
+
+ obj->node_arena = NULL;
+ obj->builder = rtbuild_create( size );
+
+ return RayObject_unalignRayAPI((RayObject*) obj);
+}
diff --git a/source/blender/render/intern/source/rayobject_bvh.c b/source/blender/render/intern/source/rayobject_bvh.c
deleted file mode 100644
index 181456c2b4d..00000000000
--- a/source/blender/render/intern/source/rayobject_bvh.c
+++ /dev/null
@@ -1,474 +0,0 @@
-/**
- * $Id$
- *
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
- *
- * The Original Code is Copyright (C) 2009 Blender Foundation.
- * All rights reserved.
- *
- * The Original Code is: all of this file.
- *
- * Contributor(s): André Pinto.
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-#include <assert.h>
-#include <stdio.h>
-#include <math.h>
-
-#include "MEM_guardedalloc.h"
-#include "BKE_utildefines.h"
-#include "BLI_arithb.h"
-#include "BLI_memarena.h"
-#include "RE_raytrace.h"
-#include "rayobject_rtbuild.h"
-#include "rayobject.h"
-
-#define RAY_BB_TEST_COST (0.2f)
-#define DFS_STACK_SIZE 64
-#define DYNAMIC_ALLOC
-
-//#define SPLIT_OVERLAP_MEAN_LONGEST_AXIS /* objects mean split on the longest axis, childs BB are allowed to overlap */
-//#define SPLIT_OVERLAP_MEDIAN_LONGEST_AXIS /* space median split on the longest axis, childs BB are allowed to overlap */
-#define SPLIT_OBJECTS_SAH /* split objects using heuristic */
-
-#define BVH_NCHILDS 2
-typedef struct BVHTree BVHTree;
-
-static int bvh_intersect(BVHTree *obj, Isect *isec);
-static int bvh_intersect_stack(BVHTree *obj, Isect *isec);
-static void bvh_add(BVHTree *o, RayObject *ob);
-static void bvh_done(BVHTree *o);
-static void bvh_free(BVHTree *o);
-static void bvh_bb(BVHTree *o, float *min, float *max);
-static float bvh_cost(BVHTree *o);
-
-static RayObjectAPI bvh_api =
-{
-#ifdef DFS_STACK_SIZE
- (RE_rayobject_raycast_callback) bvh_intersect_stack,
-#else
- (RE_rayobject_raycast_callback) bvh_intersect,
-#endif
- (RE_rayobject_add_callback) bvh_add,
- (RE_rayobject_done_callback) bvh_done,
- (RE_rayobject_free_callback) bvh_free,
- (RE_rayobject_merge_bb_callback)bvh_bb,
- (RE_rayobject_cost_callback) bvh_cost
-};
-
-typedef struct BVHNode BVHNode;
-struct BVHNode
-{
- BVHNode *child[BVH_NCHILDS];
-#ifdef DYNAMIC_ALLOC
- float bb[6];
-#else
- float *bb; //[6]; //[2][3];
-#endif
- int split_axis;
-};
-
-struct BVHTree
-{
- RayObject rayobj;
-
- BVHNode *root;
-
-#ifdef DYNAMIC_ALLOC
- MemArena *node_arena;
-#else
- BVHNode *node_alloc, *node_next;
- float *bb_alloc, *bb_next;
-#endif
- float cost;
- RTBuilder *builder;
-
-};
-
-
-RayObject *RE_rayobject_bvh_create(int size)
-{
- BVHTree *obj= (BVHTree*)MEM_callocN(sizeof(BVHTree), "BVHTree");
- assert( RayObject_isAligned(obj) ); /* RayObject API assumes real data to be 4-byte aligned */
-
- obj->rayobj.api = &bvh_api;
- obj->root = NULL;
-
-#ifdef DYNAMIC_ALLOC
- obj->node_arena = NULL;
-#else
- obj->node_alloc = obj->node_next = NULL;
- obj->bb_alloc = obj->bb_next = NULL;
-#endif
- obj->builder = rtbuild_create( size );
-
- return RayObject_unalignRayAPI((RayObject*) obj);
-}
-
-static void bvh_free(BVHTree *obj)
-{
- if(obj->builder)
- rtbuild_free(obj->builder);
-
-#ifdef DYNAMIC_ALLOC
- if(obj->node_arena)
- BLI_memarena_free(obj->node_arena);
-#else
- if(obj->node_alloc)
- MEM_freeN(obj->node_alloc);
-
- if(obj->bb_alloc)
- MEM_freeN(obj->bb_alloc);
-#endif
-
- MEM_freeN(obj);
-}
-
-
-static void bvh_merge_bb(BVHNode *node, float *min, float *max)
-{
- if(RayObject_isAligned(node))
- {
- DO_MIN(node->bb , min);
- DO_MAX(node->bb+3, max);
- }
- else
- {
- RE_rayobject_merge_bb( (RayObject*)node, min, max);
- }
-}
-
-static void bvh_bb(BVHTree *obj, float *min, float *max)
-{
- bvh_merge_bb(obj->root, min, max);
-}
-
-static float bvh_cost(BVHTree *obj)
-{
- assert(obj->cost >= 0.0);
- return obj->cost;
-}
-
-/*
- * Tree transverse
- */
-static int dfs_raycast_stack(BVHNode *root, Isect *isec)
-{
- BVHNode *stack[DFS_STACK_SIZE];
- int hit = 0, stack_pos = 0;
-#ifdef RT_USE_HINT
- BVHNode *last_processed_node = 0;
-#endif
-
- stack[stack_pos++] = root;
-
- while(stack_pos)
- {
- BVHNode *node = stack[--stack_pos];
- if(RayObject_isAligned(node))
- {
- if(RE_rayobject_bb_intersect(isec, (const float*)node->bb) != FLT_MAX)
- {
-#ifdef RT_USE_HINT
- last_processed_node = node;
-#endif
- //push nodes in reverse visit order
- if(isec->idot_axis[node->split_axis] < 0.0f)
- {
- int i;
- for(i=0; i<BVH_NCHILDS; i++)
- if(node->child[i] == 0) break;
- else
-#ifdef RT_USE_HINT
- if(node->child[i] != (BVHNode*)isec->hint)
-#endif
- stack[stack_pos++] = node->child[i];
- }
- else
- {
- int i;
- for(i=BVH_NCHILDS-1; i>=0; i--)
- if(node->child[i] != 0
-#ifdef RT_USE_HINT
- && node->child[i] != (BVHNode*)isec->hint
-#endif
- )
- stack[stack_pos++] = node->child[i];
- }
- assert(stack_pos <= DFS_STACK_SIZE);
- }
- }
- else
- {
- int ghit;
-#ifdef RT_USE_HINT
- RayTraceHint *b_hint = isec->hint;
- isec->hint = 0;
-#endif
- ghit = RE_rayobject_intersect( (RayObject*)node, isec);
-
-#ifdef RT_USE_HINT
- isec->hint = b_hint;
- if(ghit)
- isec->hit_hint = (RayTraceHint*)last_processed_node;
-#endif
- hit |= ghit;
- if(hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- }
- return hit;
-}
-
-static int bvh_intersect_stack(BVHTree *obj, Isect *isec)
-{
- if(RayObject_isAligned(obj->root))
- {
-#ifdef RT_USE_HINT
- if(isec->hint)
- {
- int hit;
- RE_RC_COUNT(isec->raycounter->raytrace_hint.test);
- hit = dfs_raycast_stack((BVHNode*) isec->hint, isec);
- if(hit)
- {
- RE_RC_COUNT(isec->raycounter->raytrace_hint.hit);
-
- if(isec->mode == RE_RAY_SHADOW) return hit;
- }
- else isec->hint = 0; //Clear HINT on non-hit?, that sounds good, but no tests where made
-
- return hit | dfs_raycast_stack(obj->root, isec);
- }
-#endif
- return dfs_raycast_stack(obj->root, isec);
- }
- else
- return RE_rayobject_intersect( (RayObject*)obj->root, isec);
-}
-
-static int dfs_raycast(BVHNode *node, Isect *isec)
-{
- int hit = 0;
- if(RE_rayobject_bb_intersect(isec, (const float*)node->bb) != FLT_MAX)
- {
- if(isec->idot_axis[node->split_axis] > 0.0f)
- {
- int i;
- for(i=0; i<BVH_NCHILDS; i++)
- if(RayObject_isAligned(node->child[i]))
- {
- if(node->child[i] == 0) break;
-
- hit |= dfs_raycast(node->child[i], isec);
- if(hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- else
- {
- hit |= RE_rayobject_intersect( (RayObject*)node->child[i], isec);
- if(hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- }
- else
- {
- int i;
- for(i=BVH_NCHILDS-1; i>=0; i--)
- if(RayObject_isAligned(node->child[i]))
- {
- if(node->child[i])
- {
- hit |= dfs_raycast(node->child[i], isec);
- if(hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- }
- else
- {
- hit |= RE_rayobject_intersect( (RayObject*)node->child[i], isec);
- if(hit && isec->mode == RE_RAY_SHADOW) return hit;
- }
- }
- }
- return hit;
-}
-
-static int bvh_intersect(BVHTree *obj, Isect *isec)
-{
- if(RayObject_isAligned(obj->root))
- return dfs_raycast(obj->root, isec);
- else
- return RE_rayobject_intersect( (RayObject*)obj->root, isec);
-}
-
-
-/*
- * Builds a BVH tree from builder object
- */
-static void bvh_add(BVHTree *obj, RayObject *ob)
-{
- rtbuild_add( obj->builder, ob );
-}
-
-static BVHNode *bvh_new_node(BVHTree *tree, int nid)
-{
-#ifdef DYNAMIC_ALLOC
- BVHNode *node = BLI_memarena_alloc(tree->node_arena, sizeof(BVHNode));
- return node;
-#else
- BVHNode *node = tree->node_alloc + nid - 1;
- assert(RayObject_isAligned(node));
- if(node+1 > tree->node_next)
- tree->node_next = node+1;
-
- node->bb = tree->bb_alloc + (nid - 1)*6;
- tree->bb_next += 6;
-
- return node;
-#endif
-}
-
-static int child_id(int pid, int nchild)
-{
- //N child of node A = A * K + (2 - K) + N, (0 <= N < K)
- return pid*BVH_NCHILDS+(2-BVH_NCHILDS)+nchild;
-}
-
-static BVHNode *bvh_rearrange(BVHTree *tree, RTBuilder *builder, int nid, float *cost)
-{
- *cost = 0;
- if(rtbuild_size(builder) == 0)
- return 0;
-
- if(rtbuild_size(builder) == 1)
- {
- RayObject *child = builder->begin[0];
-
- if(RayObject_isRayFace(child))
- {
- int i;
- BVHNode *parent = bvh_new_node(tree, nid);
- parent->split_axis = 0;
-
- INIT_MINMAX(parent->bb, parent->bb+3);
-
- for(i=0; i<1; i++)
- {
- parent->child[i] = (BVHNode*)builder->begin[i];
- bvh_merge_bb(parent->child[i], parent->bb, parent->bb+3);
- }
- for(; i<BVH_NCHILDS; i++)
- parent->child[i] = 0;
-
- *cost = RE_rayobject_cost(child)+RAY_BB_TEST_COST;
- return parent;
- }
- else
- {
- assert(!RayObject_isAligned(child));
- //Its a sub-raytrace structure, assume it has it own raycast
- //methods and adding a Bounding Box arround is unnecessary
-
- *cost = RE_rayobject_cost(child);
- return (BVHNode*)child;
- }
- }
- else
- {
- int i;
- RTBuilder tmp;
- BVHNode *parent = bvh_new_node(tree, nid);
- int nc;
-
-#ifdef SPLIT_OVERLAP_MEAN_LONGEST_AXIS
- nc = rtbuild_mean_split_largest_axis(builder, BVH_NCHILDS);
-#elif defined(SPLIT_OVERLAP_MEDIAN_LONGEST_AXIS)
- nc = rtbuild_median_split_largest_axis(builder, BVH_NCHILDS);
-#elif defined(SPLIT_OBJECTS_SAH)
- nc = rtbuild_heuristic_object_split(builder, BVH_NCHILDS);
-#else
- assert(0);
-#endif
-
- INIT_MINMAX(parent->bb, parent->bb+3);
- parent->split_axis = builder->split_axis;
- for(i=0; i<nc; i++)
- {
- float cbb[6];
- float tcost;
- parent->child[i] = bvh_rearrange( tree, rtbuild_get_child(builder, i, &tmp), child_id(nid,i), &tcost );
-
- INIT_MINMAX(cbb, cbb+3);
- bvh_merge_bb(parent->child[i], cbb, cbb+3);
- DO_MIN(cbb, parent->bb);
- DO_MAX(cbb+3, parent->bb+3);
-
- *cost += tcost*bb_area(cbb, cbb+3);
- }
- for(; i<BVH_NCHILDS; i++)
- parent->child[i] = 0;
-
- *cost /= bb_area(parent->bb, parent->bb+3);
- *cost += nc*RAY_BB_TEST_COST;
- return parent;
- }
-}
-
-/*
-static void bvh_info(BVHTree *obj)
-{
- printf("BVH: Used %d nodes\n", obj->node_next - obj->node_alloc);
-}
-*/
-
-static void bvh_done(BVHTree *obj)
-{
-
-#ifdef DYNAMIC_ALLOC
- int needed_nodes = (rtbuild_size(obj->builder)+1)*2;
- if(needed_nodes > BLI_MEMARENA_STD_BUFSIZE)
- needed_nodes = BLI_MEMARENA_STD_BUFSIZE;
-
- obj->node_arena = BLI_memarena_new(needed_nodes);
- BLI_memarena_use_malloc(obj->node_arena);
-
-#else
- int needed_nodes;
-
- //TODO exact calculate needed nodes
- needed_nodes = (rtbuild_size(obj->builder)+1)*2;
- assert(needed_nodes > 0);
-
- BVHNode *node = BLI_memarena_alloc(tree->node_arena, sizeof(BVHNode));
- return node;
- obj->node_alloc = (BVHNode*)MEM_mallocN( sizeof(BVHNode)*needed_nodes, "BVHTree.Nodes");
- obj->node_next = obj->node_alloc;
-
- obj->bb_alloc = (float*)MEM_mallocN( sizeof(float)*6*needed_nodes, "BVHTree.NodesBB");
- obj->bb_next = obj->bb_alloc;
-#endif
-
- obj->root = bvh_rearrange( obj, obj->builder, 1, &obj->cost );
-// obj->cost = 1.0;
-// obj->cost = logf( rtbuild_size( obj->builder ) );
-
-#ifndef DYNAMIC_ALLOC
- assert(obj->node_alloc+needed_nodes >= obj->node_next);
-#endif
-
- rtbuild_free( obj->builder );
- obj->builder = NULL;
-}
-