Blender  V2.59
rayobject_svbvh.cpp
Go to the documentation of this file.
00001 /*
00002  * $Id: rayobject_svbvh.cpp 35477 2011-03-11 22:27:06Z blendix $
00003  *
00004  * ***** BEGIN GPL LICENSE BLOCK *****
00005  *
00006  * This program is free software; you can redistribute it and/or
00007  * modify it under the terms of the GNU General Public License
00008  * as published by the Free Software Foundation; either version 2
00009  * of the License, or (at your option) any later version. 
00010  *
00011  * This program is distributed in the hope that it will be useful,
00012  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00014  * GNU General Public License for more details.
00015  *
00016  * You should have received a copy of the GNU General Public License
00017  * along with this program; if not, write to the Free Software Foundation,
00018  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00019  *
00020  * The Original Code is Copyright (C) 2009 Blender Foundation.
00021  * All rights reserved.
00022  *
00023  * The Original Code is: all of this file.
00024  *
00025  * Contributor(s): André Pinto.
00026  *
00027  * ***** END GPL LICENSE BLOCK *****
00028  */
00029 
00035 #include "MEM_guardedalloc.h"
00036 
00037 #include "BLI_utildefines.h"
00038 
00039 #include "vbvh.h"
00040 #include "svbvh.h"
00041 #include "reorganize.h"
00042 
00043 #ifdef __SSE__
00044 
00045 #define DFS_STACK_SIZE  256
00046 
00047 struct SVBVHTree
00048 {
00049         RayObject rayobj;
00050 
00051         SVBVHNode *root;
00052         MemArena *node_arena;
00053 
00054         float cost;
00055         RTBuilder *builder;
00056 };
00057 
00058 /*
00059  * Cost to test N childs
00060  */
00061 struct PackCost
00062 {
00063         float operator()(int n)
00064         {
00065                 return (n / 4) + ((n % 4) > 2 ? 1 : n%4);
00066         }
00067 };
00068 
00069 
00070 template<>
00071 void bvh_done<SVBVHTree>(SVBVHTree *obj)
00072 {
00073         rtbuild_done(obj->builder, &obj->rayobj.control);
00074         
00075         //TODO find a away to exactly calculate the needed memory
00076         MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "svbvh arena");
00077                                            BLI_memarena_use_malloc(arena1);
00078 
00079         MemArena *arena2 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "svbvh arena2");
00080                                            BLI_memarena_use_malloc(arena2);
00081                                            BLI_memarena_use_align(arena2, 16);
00082 
00083         //Build and optimize the tree
00084         if(0)
00085         {
00086                 VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder);
00087 
00088                 if(RE_rayobjectcontrol_test_break(&obj->rayobj.control))
00089                 {
00090                         BLI_memarena_free(arena1);
00091                         BLI_memarena_free(arena2);
00092                         return;
00093                 }
00094                 
00095                 reorganize(root);
00096                 remove_useless(root, &root);
00097                 bvh_refit(root);
00098 
00099                 pushup(root);
00100                 pushdown(root);
00101                 pushup_simd<VBVHNode,4>(root);
00102 
00103                 obj->root = Reorganize_SVBVH<VBVHNode>(arena2).transform(root);
00104         }
00105         else
00106         {
00107                 //Finds the optimal packing of this tree using a given cost model
00108                 //TODO this uses quite a lot of memory, find ways to reduce memory usage during building
00109                 OVBVHNode *root = BuildBinaryVBVH<OVBVHNode>(arena1,&obj->rayobj.control).transform(obj->builder);                      
00110 
00111                 if(RE_rayobjectcontrol_test_break(&obj->rayobj.control))
00112                 {
00113                         BLI_memarena_free(arena1);
00114                         BLI_memarena_free(arena2);
00115                         return;
00116                 }
00117 
00118                 if(root) {
00119                         VBVH_optimalPackSIMD<OVBVHNode,PackCost>(PackCost()).transform(root);
00120                         obj->root = Reorganize_SVBVH<OVBVHNode>(arena2).transform(root);
00121                 }
00122                 else
00123                         obj->root = NULL;
00124         }
00125         
00126         //Free data
00127         BLI_memarena_free(arena1);
00128         
00129         obj->node_arena = arena2;
00130         obj->cost = 1.0;
00131 
00132         rtbuild_free( obj->builder );
00133         obj->builder = NULL;
00134 }
00135 
00136 template<int StackSize>
00137 int intersect(SVBVHTree *obj, Isect* isec)
00138 {
00139         //TODO renable hint support
00140         if(RE_rayobject_isAligned(obj->root)) {
00141                 if(isec->mode == RE_RAY_SHADOW)
00142                         return svbvh_node_stack_raycast<StackSize,true>(obj->root, isec);
00143                 else
00144                         return svbvh_node_stack_raycast<StackSize,false>(obj->root, isec);
00145         }
00146         else
00147                 return RE_rayobject_intersect( (RayObject*) obj->root, isec );
00148 }
00149 
00150 template<class Tree>
00151 void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *min, float *max)
00152 {
00153         //TODO renable hint support
00154         {
00155                 hint->size = 0;
00156                 hint->stack[hint->size++] = (RayObject*)tree->root;
00157         }
00158 }
00159 /* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */
00160 template<class Tree, int STACK_SIZE>
00161 RayObjectAPI make_api()
00162 {
00163         static RayObjectAPI api = 
00164         {
00165                 (RE_rayobject_raycast_callback) ((int(*)(Tree*,Isect*)) &intersect<STACK_SIZE>),
00166                 (RE_rayobject_add_callback)     ((void(*)(Tree*,RayObject*)) &bvh_add<Tree>),
00167                 (RE_rayobject_done_callback)    ((void(*)(Tree*))       &bvh_done<Tree>),
00168                 (RE_rayobject_free_callback)    ((void(*)(Tree*))       &bvh_free<Tree>),
00169                 (RE_rayobject_merge_bb_callback)((void(*)(Tree*,float*,float*)) &bvh_bb<Tree>),
00170                 (RE_rayobject_cost_callback)    ((float(*)(Tree*))      &bvh_cost<Tree>),
00171                 (RE_rayobject_hint_bb_callback) ((void(*)(Tree*,LCTSHint*,float*,float*)) &bvh_hint_bb<Tree>)
00172         };
00173         
00174         return api;
00175 }
00176 
00177 template<class Tree>
00178 RayObjectAPI* bvh_get_api(int maxstacksize)
00179 {
00180         static RayObjectAPI bvh_api256 = make_api<Tree,1024>();
00181         
00182         if(maxstacksize <= 1024) return &bvh_api256;
00183         assert(maxstacksize <= 256);
00184         return 0;
00185 }
00186 
00187 RayObject *RE_rayobject_svbvh_create(int size)
00188 {
00189         return bvh_create_tree<SVBVHTree,DFS_STACK_SIZE>(size);
00190 }
00191 
00192 #else
00193 
00194 RayObject *RE_rayobject_svbvh_create(int size)
00195 {
00196         puts("WARNING: SSE disabled at compile time\n");
00197         return NULL;
00198 }
00199 
00200 #endif