GHOST: Fix uninitialized var
[blender.git] / source / blender / render / intern / raytrace / rayobject_instance.cpp
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  * The Original Code is Copyright (C) 2009 Blender Foundation.
19  * All rights reserved.
20  *
21  * The Original Code is: all of this file.
22  *
23  * Contributor(s): AndrĂ© Pinto.
24  *
25  * ***** END GPL LICENSE BLOCK *****
26  */
27
28 /** \file blender/render/intern/raytrace/rayobject_instance.cpp
29  *  \ingroup render
30  */
31
32
33 #include <assert.h>
34
35 #include "MEM_guardedalloc.h"
36
37 #include "BLI_math.h"
38 #include "BLI_utildefines.h"
39
40 #include "rayintersection.h"
41 #include "rayobject.h"
42
43 #define RE_COST_INSTANCE (1.0f)
44
45 static int  RE_rayobject_instance_intersect(RayObject *o, Isect *isec);
46 static void RE_rayobject_instance_free(RayObject *o);
47 static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max);
48 static float RE_rayobject_instance_cost(RayObject *o);
49
50 static void RE_rayobject_instance_hint_bb(RayObject *UNUSED(o), RayHint *UNUSED(hint),
51                                           float *UNUSED(min), float *UNUSED(max))
52 {}
53
54 static RayObjectAPI instance_api =
55 {
56         RE_rayobject_instance_intersect,
57         NULL, //static void RE_rayobject_instance_add(RayObject *o, RayObject *ob);
58         NULL, //static void RE_rayobject_instance_done(RayObject *o);
59         RE_rayobject_instance_free,
60         RE_rayobject_instance_bb,
61         RE_rayobject_instance_cost,
62         RE_rayobject_instance_hint_bb
63 };
64
65 typedef struct InstanceRayObject {
66         RayObject rayobj;
67         RayObject *target;
68
69         void *ob; //Object represented by this instance
70         void *target_ob; //Object represented by the inner RayObject, needed to handle self-intersection
71
72         float global2target[4][4];
73         float target2global[4][4];
74
75 } InstanceRayObject;
76
77
78 RayObject *RE_rayobject_instance_create(RayObject *target, float transform[4][4], void *ob, void *target_ob)
79 {
80         InstanceRayObject *obj = (InstanceRayObject *)MEM_callocN(sizeof(InstanceRayObject), "InstanceRayObject");
81         assert(RE_rayobject_isAligned(obj) );  /* RayObject API assumes real data to be 4-byte aligned */
82
83         obj->rayobj.api = &instance_api;
84         obj->target = target;
85         obj->ob = ob;
86         obj->target_ob = target_ob;
87
88         copy_m4_m4(obj->target2global, transform);
89         invert_m4_m4(obj->global2target, obj->target2global);
90
91         return RE_rayobject_unalignRayAPI((RayObject *) obj);
92 }
93
94 static int  RE_rayobject_instance_intersect(RayObject *o, Isect *isec)
95 {
96         InstanceRayObject *obj = (InstanceRayObject *)o;
97         float start[3], dir[3], idot_axis[3], dist;
98         int changed = 0, i, res;
99
100         // TODO - this is disabling self intersection on instances
101         if (isec->orig.ob == obj->ob && obj->ob) {
102                 changed = 1;
103                 isec->orig.ob = obj->target_ob;
104         }
105
106         // backup old values
107         copy_v3_v3(start, isec->start);
108         copy_v3_v3(dir, isec->dir);
109         copy_v3_v3(idot_axis, isec->idot_axis);
110         dist = isec->dist;
111
112         // transform to target coordinates system
113         mul_m4_v3(obj->global2target, isec->start);
114         mul_mat3_m4_v3(obj->global2target, isec->dir);
115         isec->dist *= normalize_v3(isec->dir);
116
117         // update idot_axis and bv_index
118         for (i = 0; i < 3; i++) {
119                 isec->idot_axis[i]        = 1.0f / isec->dir[i];
120
121                 isec->bv_index[2 * i]     = isec->idot_axis[i] < 0.0f ? 1 : 0;
122                 isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i];
123
124                 isec->bv_index[2 * i]     = i + 3 * isec->bv_index[2 * i];
125                 isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
126         }
127
128         // Pre-calculate orientation for watertight intersection checks.
129         isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
130
131         // raycast
132         res = RE_rayobject_intersect(obj->target, isec);
133
134         // map dist into original coordinate space
135         if (res == 0) {
136                 isec->dist = dist;
137         }
138         else {
139                 // note we don't just multiply dist, because of possible
140                 // non-uniform scaling in the transform matrix
141                 float vec[3];
142
143                 mul_v3_v3fl(vec, isec->dir, isec->dist);
144                 mul_mat3_m4_v3(obj->target2global, vec);
145
146                 isec->dist = len_v3(vec);
147                 isec->hit.ob = obj->ob;
148
149 #ifdef RT_USE_LAST_HIT
150                 // TODO support for last hit optimization in instances that can jump
151                 // directly to the last hit face.
152                 // For now it jumps directly to the last-hit instance root node.
153                 isec->last_hit = RE_rayobject_unalignRayAPI((RayObject *) obj);
154 #endif
155         }
156
157         // restore values
158         copy_v3_v3(isec->start, start);
159         copy_v3_v3(isec->dir, dir);
160         copy_v3_v3(isec->idot_axis, idot_axis);
161
162         if (changed)
163                 isec->orig.ob = obj->ob;
164
165         // restore bv_index
166         for (i = 0; i < 3; i++) {
167                 isec->bv_index[2 * i]     = isec->idot_axis[i] < 0.0f ? 1 : 0;
168                 isec->bv_index[2 * i + 1] = 1 - isec->bv_index[2 * i];
169
170                 isec->bv_index[2 * i]     = i + 3 * isec->bv_index[2 * i];
171                 isec->bv_index[2 * i + 1] = i + 3 * isec->bv_index[2 * i + 1];
172         }
173
174         // Pre-calculate orientation for watertight intersection checks.
175         isect_ray_tri_watertight_v3_precalc(&isec->isect_precalc, isec->dir);
176
177         return res;
178 }
179
180 static void RE_rayobject_instance_free(RayObject *o)
181 {
182         InstanceRayObject *obj = (InstanceRayObject *)o;
183         MEM_freeN(obj);
184 }
185
186 static float RE_rayobject_instance_cost(RayObject *o)
187 {
188         InstanceRayObject *obj = (InstanceRayObject *)o;
189         return RE_rayobject_cost(obj->target) + RE_COST_INSTANCE;
190 }
191
192 static void RE_rayobject_instance_bb(RayObject *o, float *min, float *max)
193 {
194         //TODO:
195         // *better bb.. calculated without rotations of bb
196         // *maybe cache that better-fitted-BB at the InstanceRayObject
197         InstanceRayObject *obj = (InstanceRayObject *)o;
198
199         float m[3], M[3], t[3];
200         int i, j;
201         INIT_MINMAX(m, M);
202         RE_rayobject_merge_bb(obj->target, m, M);
203
204         //There must be a faster way than rotating all the 8 vertexs of the BB
205         for (i = 0; i < 8; i++) {
206                 for (j = 0; j < 3; j++) t[j] = (i & (1 << j)) ? M[j] : m[j];
207                 mul_m4_v3(obj->target2global, t);
208                 DO_MINMAX(t, min, max);
209         }
210 }
211