doxygen: prevent GPL license block from being parsed as doxygen comment.
[blender.git] / source / blender / render / intern / raytrace / rayobject_svbvh.cpp
1 /*
2  * $Id$
3  *
4  * ***** BEGIN GPL LICENSE BLOCK *****
5  *
6  * This program is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU General Public License
8  * as published by the Free Software Foundation; either version 2
9  * of the License, or (at your option) any later version. 
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software Foundation,
18  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19  *
20  * The Original Code is Copyright (C) 2009 Blender Foundation.
21  * All rights reserved.
22  *
23  * The Original Code is: all of this file.
24  *
25  * Contributor(s): AndrĂ© Pinto.
26  *
27  * ***** END GPL LICENSE BLOCK *****
28  */
29
30 #include "MEM_guardedalloc.h"
31
32 #include "BLI_utildefines.h"
33
34 #include "vbvh.h"
35 #include "svbvh.h"
36 #include "reorganize.h"
37
38 #ifdef __SSE__
39
40 #define DFS_STACK_SIZE  256
41
42 struct SVBVHTree
43 {
44         RayObject rayobj;
45
46         SVBVHNode *root;
47         MemArena *node_arena;
48
49         float cost;
50         RTBuilder *builder;
51 };
52
53 /*
54  * Cost to test N childs
55  */
56 struct PackCost
57 {
58         float operator()(int n)
59         {
60                 return (n / 4) + ((n % 4) > 2 ? 1 : n%4);
61         }
62 };
63
64
65 template<>
66 void bvh_done<SVBVHTree>(SVBVHTree *obj)
67 {
68         rtbuild_done(obj->builder, &obj->rayobj.control);
69         
70         //TODO find a away to exactly calculate the needed memory
71         MemArena *arena1 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "svbvh arena");
72                                            BLI_memarena_use_malloc(arena1);
73
74         MemArena *arena2 = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, "svbvh arena2");
75                                            BLI_memarena_use_malloc(arena2);
76                                            BLI_memarena_use_align(arena2, 16);
77
78         //Build and optimize the tree
79         if(0)
80         {
81                 VBVHNode *root = BuildBinaryVBVH<VBVHNode>(arena1, &obj->rayobj.control).transform(obj->builder);
82
83                 if(RE_rayobjectcontrol_test_break(&obj->rayobj.control))
84                 {
85                         BLI_memarena_free(arena1);
86                         BLI_memarena_free(arena2);
87                         return;
88                 }
89                 
90                 reorganize(root);
91                 remove_useless(root, &root);
92                 bvh_refit(root);
93
94                 pushup(root);
95                 pushdown(root);
96                 pushup_simd<VBVHNode,4>(root);
97
98                 obj->root = Reorganize_SVBVH<VBVHNode>(arena2).transform(root);
99         }
100         else
101         {
102                 //Finds the optimal packing of this tree using a given cost model
103                 //TODO this uses quite a lot of memory, find ways to reduce memory usage during building
104                 OVBVHNode *root = BuildBinaryVBVH<OVBVHNode>(arena1,&obj->rayobj.control).transform(obj->builder);                      
105
106                 if(RE_rayobjectcontrol_test_break(&obj->rayobj.control))
107                 {
108                         BLI_memarena_free(arena1);
109                         BLI_memarena_free(arena2);
110                         return;
111                 }
112
113                 VBVH_optimalPackSIMD<OVBVHNode,PackCost>(PackCost()).transform(root);
114                 obj->root = Reorganize_SVBVH<OVBVHNode>(arena2).transform(root);
115         }
116         
117         //Free data
118         BLI_memarena_free(arena1);
119         
120         obj->node_arena = arena2;
121         obj->cost = 1.0;
122
123         rtbuild_free( obj->builder );
124         obj->builder = NULL;
125 }
126
127 template<int StackSize>
128 int intersect(SVBVHTree *obj, Isect* isec)
129 {
130         //TODO renable hint support
131         if(RE_rayobject_isAligned(obj->root)) {
132                 if(isec->mode == RE_RAY_SHADOW)
133                         return svbvh_node_stack_raycast<StackSize,true>(obj->root, isec);
134                 else
135                         return svbvh_node_stack_raycast<StackSize,false>(obj->root, isec);
136         }
137         else
138                 return RE_rayobject_intersect( (RayObject*) obj->root, isec );
139 }
140
141 template<class Tree>
142 void bvh_hint_bb(Tree *tree, LCTSHint *hint, float *min, float *max)
143 {
144         //TODO renable hint support
145         {
146                 hint->size = 0;
147                 hint->stack[hint->size++] = (RayObject*)tree->root;
148         }
149 }
150 /* the cast to pointer function is needed to workarround gcc bug: http://gcc.gnu.org/bugzilla/show_bug.cgi?id=11407 */
151 template<class Tree, int STACK_SIZE>
152 RayObjectAPI make_api()
153 {
154         static RayObjectAPI api = 
155         {
156                 (RE_rayobject_raycast_callback) ((int(*)(Tree*,Isect*)) &intersect<STACK_SIZE>),
157                 (RE_rayobject_add_callback)     ((void(*)(Tree*,RayObject*)) &bvh_add<Tree>),
158                 (RE_rayobject_done_callback)    ((void(*)(Tree*))       &bvh_done<Tree>),
159                 (RE_rayobject_free_callback)    ((void(*)(Tree*))       &bvh_free<Tree>),
160                 (RE_rayobject_merge_bb_callback)((void(*)(Tree*,float*,float*)) &bvh_bb<Tree>),
161                 (RE_rayobject_cost_callback)    ((float(*)(Tree*))      &bvh_cost<Tree>),
162                 (RE_rayobject_hint_bb_callback) ((void(*)(Tree*,LCTSHint*,float*,float*)) &bvh_hint_bb<Tree>)
163         };
164         
165         return api;
166 }
167
168 template<class Tree>
169 RayObjectAPI* bvh_get_api(int maxstacksize)
170 {
171         static RayObjectAPI bvh_api256 = make_api<Tree,1024>();
172         
173         if(maxstacksize <= 1024) return &bvh_api256;
174         assert(maxstacksize <= 256);
175         return 0;
176 }
177
178 RayObject *RE_rayobject_svbvh_create(int size)
179 {
180         return bvh_create_tree<SVBVHTree,DFS_STACK_SIZE>(size);
181 }
182
183 #else
184
185 RayObject *RE_rayobject_svbvh_create(int size)
186 {
187         puts("WARNING: SSE disabled at compile time\n");
188         return NULL;
189 }
190
191 #endif