Renamed exported functions from render to have the RE_ prefix
[blender-staging.git] / source / blender / render / intern / source / rayobject.c
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., 59 Temple Place - Suite 330, Boston, MA  02111-1307, 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 #include <assert.h>
30
31 #include "BKE_utildefines.h"
32
33 #include "RE_raytrace.h"
34 #include "render_types.h"
35 #include "rayobject.h"
36
37 /* only for self-intersecting test with current render face (where ray left) */
38 static int intersection2(VlakRen *face, float r0, float r1, float r2, float rx1, float ry1, float rz1)
39 {
40         float co1[3], co2[3], co3[3], co4[3];
41         float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22;
42         float m0, m1, m2, divdet, det, det1;
43         float u1, v, u2;
44
45         VECCOPY(co1, face->v1->co);
46         VECCOPY(co2, face->v2->co);
47         if(face->v4)
48         {
49                 VECCOPY(co3, face->v4->co);
50                 VECCOPY(co4, face->v3->co);
51         }
52         else
53         {
54                 VECCOPY(co3, face->v3->co);
55         }
56
57         t00= co3[0]-co1[0];
58         t01= co3[1]-co1[1];
59         t02= co3[2]-co1[2];
60         t10= co3[0]-co2[0];
61         t11= co3[1]-co2[1];
62         t12= co3[2]-co2[2];
63         
64         x0= t11*r2-t12*r1;
65         x1= t12*r0-t10*r2;
66         x2= t10*r1-t11*r0;
67
68         divdet= t00*x0+t01*x1+t02*x2;
69
70         m0= rx1-co3[0];
71         m1= ry1-co3[1];
72         m2= rz1-co3[2];
73         det1= m0*x0+m1*x1+m2*x2;
74         
75         if(divdet!=0.0f) {
76                 u1= det1/divdet;
77
78                 if(u1<ISECT_EPSILON) {
79                         det= t00*(m1*r2-m2*r1);
80                         det+= t01*(m2*r0-m0*r2);
81                         det+= t02*(m0*r1-m1*r0);
82                         v= det/divdet;
83
84                         if(v<ISECT_EPSILON && (u1 + v) > -(1.0f+ISECT_EPSILON)) {
85                                 return 1;
86                         }
87                 }
88         }
89
90         if(face->v4) {
91
92                 t20= co3[0]-co4[0];
93                 t21= co3[1]-co4[1];
94                 t22= co3[2]-co4[2];
95
96                 divdet= t20*x0+t21*x1+t22*x2;
97                 if(divdet!=0.0f) {
98                         u2= det1/divdet;
99                 
100                         if(u2<ISECT_EPSILON) {
101                                 det= t20*(m1*r2-m2*r1);
102                                 det+= t21*(m2*r0-m0*r2);
103                                 det+= t22*(m0*r1-m1*r0);
104                                 v= det/divdet;
105         
106                                 if(v<ISECT_EPSILON && (u2 + v) >= -(1.0f+ISECT_EPSILON)) {
107                                         return 2;
108                                 }
109                         }
110                 }
111         }
112         return 0;
113 }
114
115
116 /* ray - triangle or quad intersection */
117 /* this function shall only modify Isect if it detects an hit */
118 static int intersect_rayface(RayFace *face, Isect *is)
119 {
120         float co1[3],co2[3],co3[3],co4[3];
121         float x0,x1,x2,t00,t01,t02,t10,t11,t12,t20,t21,t22,r0,r1,r2;
122         float m0, m1, m2, divdet, det1;
123         float labda, u, v;
124         short ok=0;
125         
126         if(is->orig.ob == face->ob && is->orig.face == face->face)
127                 return 0;
128
129         /* disabled until i got real & fast cylinder checking, this code doesnt work proper for faster strands */
130         //      if(is->mode==RE_RAY_SHADOW && is->vlr->flag & R_STRAND) 
131         //              return intersection_strand(is);
132         
133
134         VECCOPY(co1, face->v1);
135         VECCOPY(co2, face->v2);
136         if(face->v4)
137         {
138                 VECCOPY(co3, face->v4);
139                 VECCOPY(co4, face->v3);
140         }
141         else
142         {
143                 VECCOPY(co3, face->v3);
144         }
145
146         t00= co3[0]-co1[0];
147         t01= co3[1]-co1[1];
148         t02= co3[2]-co1[2];
149         t10= co3[0]-co2[0];
150         t11= co3[1]-co2[1];
151         t12= co3[2]-co2[2];
152         
153         r0= is->vec[0];
154         r1= is->vec[1];
155         r2= is->vec[2];
156         
157         x0= t12*r1-t11*r2;
158         x1= t10*r2-t12*r0;
159         x2= t11*r0-t10*r1;
160
161         divdet= t00*x0+t01*x1+t02*x2;
162
163         m0= is->start[0]-co3[0];
164         m1= is->start[1]-co3[1];
165         m2= is->start[2]-co3[2];
166         det1= m0*x0+m1*x1+m2*x2;
167         
168         if(divdet!=0.0f) {
169
170                 divdet= 1.0f/divdet;
171                 u= det1*divdet;
172                 if(u<ISECT_EPSILON && u>-(1.0f+ISECT_EPSILON)) {
173                         float cros0, cros1, cros2;
174                         
175                         cros0= m1*t02-m2*t01;
176                         cros1= m2*t00-m0*t02;
177                         cros2= m0*t01-m1*t00;
178                         v= divdet*(cros0*r0 + cros1*r1 + cros2*r2);
179
180                         if(v<ISECT_EPSILON && (u + v) > -(1.0f+ISECT_EPSILON)) {
181                                 labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12);
182
183                                 if(labda>-ISECT_EPSILON && labda<1.0f+ISECT_EPSILON) {
184                                         ok= 1;
185                                 }
186                         }
187                 }
188         }
189
190         if(ok==0 && face->v4) {
191
192                 t20= co3[0]-co4[0];
193                 t21= co3[1]-co4[1];
194                 t22= co3[2]-co4[2];
195
196                 divdet= t20*x0+t21*x1+t22*x2;
197                 if(divdet!=0.0f) {
198                         divdet= 1.0f/divdet;
199                         u = det1*divdet;
200                         
201                         if(u<ISECT_EPSILON && u>-(1.0f+ISECT_EPSILON)) {
202                                 float cros0, cros1, cros2;
203                                 cros0= m1*t22-m2*t21;
204                                 cros1= m2*t20-m0*t22;
205                                 cros2= m0*t21-m1*t20;
206                                 v= divdet*(cros0*r0 + cros1*r1 + cros2*r2);
207         
208                                 if(v<ISECT_EPSILON && (u + v) >-(1.0f+ISECT_EPSILON)) {
209                                         labda= divdet*(cros0*t10 + cros1*t11 + cros2*t12);
210                                         
211                                         if(labda>-ISECT_EPSILON && labda<1.0f+ISECT_EPSILON) {
212                                                 ok= 2;
213                                         }
214                                 }
215                         }
216                 }
217         }
218
219         if(ok) {
220         
221                 /* when a shadow ray leaves a face, it can be little outside the edges of it, causing
222                 intersection to be detected in its neighbour face */
223                 if(is->skip & RE_SKIP_VLR_NEIGHBOUR)
224                 {
225                         if(labda < 0.1f && is->orig.ob == face->ob)
226                         {
227                                 VlakRen * a = is->orig.face;
228                                 VlakRen * b = face->face;
229
230                                 /* so there's a shared edge or vertex, let's intersect ray with face
231                                 itself, if that's true we can safely return 1, otherwise we assume
232                                 the intersection is invalid, 0 */
233                                 if(a->v1==b->v1 || a->v2==b->v1 || a->v3==b->v1 || a->v4==b->v1
234                                 || a->v1==b->v2 || a->v2==b->v2 || a->v3==b->v2 || a->v4==b->v2
235                                 || a->v1==b->v3 || a->v2==b->v3 || a->v3==b->v3 || a->v4==b->v3
236                                 || a->v1==b->v4 || a->v2==b->v4 || a->v3==b->v4 || (a->v4 && a->v4==b->v4))
237                                 if(!intersection2((VlakRen*)b, -r0, -r1, -r2, is->start[0], is->start[1], is->start[2]))
238                                 {
239                                         return 0;
240                                 }
241                         }
242                 }
243 #if 0
244                 else if(labda < ISECT_EPSILON)
245                 {
246                         /* too close to origin */
247                         return 0;
248                 }
249 #endif
250
251 /*
252                 TODO
253                 if(is->mode!=RE_RAY_SHADOW) {
254                         / * for mirror & tra-shadow: large faces can be filled in too often, this prevents
255                            a face being detected too soon... * /
256                         if(is->labda > is->ddalabda) {
257                                 return 0;
258                         }
259                 }
260 */              
261                 is->isect= ok;  // wich half of the quad
262                 is->labda= labda;
263                 is->u= u; is->v= v;
264
265                 is->hit.ob   = face->ob;
266                 is->hit.face = face->face;
267                 return 1;
268         }
269
270         return 0;
271 }
272
273 int RE_rayobject_raycast(RayObject *r, Isect *i)
274 {
275         if(i->mode==RE_RAY_SHADOW && i->last_hit && RE_rayobject_intersect(i->last_hit, i))
276                 return 1;
277
278         return RE_rayobject_intersect(r, i);
279 }
280
281 int RE_rayobject_intersect(RayObject *r, Isect *i)
282 {
283         assert(i->mode==RE_RAY_SHADOW);
284         if(RayObject_isFace(r))
285         {
286                 return intersect_rayface( (RayFace*) r, i);
287         }
288         else
289         {
290                 //TODO should be done somewhere else
291 //              float len = Normalize( i->vec );
292                 int hit;
293                 i->vec[0] *= i->labda;
294                 i->vec[1] *= i->labda;
295                 i->vec[2] *= i->labda;
296                 i->labda = 1.0f; //RE_RAYTRACE_MAXDIST; //len;
297                 
298                 r = RayObject_align( r );
299
300                 hit = r->api->raycast( r, i );
301 //              i->labda /= len;
302                 
303                 return hit;
304         }
305 }
306
307 void RE_rayobject_add(RayObject *r, RayObject *o)
308 {
309         r = RayObject_align( r );
310         return r->api->add( r, o );
311 }
312
313 void RE_rayobject_done(RayObject *r)
314 {
315         r = RayObject_align( r );
316         r->api->done( r );
317 }
318
319 void RE_rayobject_free(RayObject *r)
320 {
321         r = RayObject_align( r );
322         r->api->free( r );
323 }
324
325 void RE_rayobject_merge_bb(RayObject *r, float *min, float *max)
326 {
327         if(RayObject_isFace(r))
328         {
329                 RayFace *face = (RayFace*)r;
330                 DO_MINMAX( face->v1, min, max );
331                 DO_MINMAX( face->v2, min, max );
332                 DO_MINMAX( face->v3, min, max );
333                 if(face->v4) DO_MINMAX( face->v4, min, max );
334         }
335         else
336         {
337                 r = RayObject_align( r );
338                 r->api->bb( r, min, max );
339         }
340 }
341