Final merge of HEAD (bf-blender) into the orange branch.
[blender.git] / source / blender / radiosity / intern / source / radrender.c
1 /* ***************************************
2  *
3  * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * as published by the Free Software Foundation; either version 2
8  * of the License, or (at your option) any later version. The Blender
9  * Foundation also sells licenses for use in proprietary software under
10  * the Blender License.  See http://www.blender.org/BL/ for information
11  * about this.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software Foundation,
20  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21  *
22  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
23  * All rights reserved.
24  *
25  * The Original Code is: all of this file.
26  *
27  * Contributor(s): none yet.
28  *
29  * ***** END GPL/BL DUAL LICENSE BLOCK *****
30  */
31  
32 /* radrender.c, aug 2003
33  *
34  * Most of the code here is copied from radiosity code, to optimize for renderfaces.
35  * Shared function calls mostly reside in radfactors.c
36  * No adaptive subdivision takes place
37  *
38  * - do_radio_render();  main call, extern
39  *   - initradfaces(); add radface structs in render faces, init radio globals
40  *   - 
41  *   - initradiosity(); LUTs
42  *   - inithemiwindows();
43  *   - progressiverad(); main itteration loop
44  *     - hemi zbuffers
45  *     - calc rad factors
46  * 
47  *   - closehemiwindows();
48  *   - freeAllRad();
49  *   - make vertex colors
50  *
51  * - during render, materials use totrad as ambient replacement
52  * - free radfaces
53  */
54
55 #include <stdlib.h>
56 #include <string.h>
57 #include <math.h>
58
59 #include "MEM_guardedalloc.h"
60
61 #include "BLI_blenlib.h"
62 #include "BLI_arithb.h"
63 #include "BLI_rand.h"
64
65 #include "BKE_utildefines.h"
66 #include "BKE_global.h"
67 #include "BKE_main.h"
68
69 #include "BIF_screen.h"
70
71 #include "radio.h"
72
73 /* the radiosity module uses internal includes from render! */
74 #include "renderpipeline.h" 
75 #include "render_types.h" 
76 #include "renderdatabase.h" 
77
78 #ifdef HAVE_CONFIG_H
79 #include <config.h>
80 #endif
81
82 /* only needed now for a print, if its useful move to RG */
83 static float maxenergy; 
84
85 /* find the face with maximum energy to become shooter */
86 /* nb: _rr means rad-render version of existing radio call */
87 static VlakRen *findshoot_rr(Render *re)
88 {
89         RadFace *rf;
90         VlakRen *vlr=NULL, *shoot;
91         float energy;
92         int a;
93         
94         shoot= NULL;
95         maxenergy= 0.0;
96         
97         for(a=0; a<re->totvlak; a++) {
98                 if((a & 255)==0) vlr= re->blovl[a>>8]; else vlr++;
99                 if(vlr->radface) {
100                         rf= vlr->radface;
101                         rf->flag &= ~RAD_SHOOT;
102                         
103                         energy= rf->unshot[0]*rf->area;
104                         energy+= rf->unshot[1]*rf->area;
105                         energy+= rf->unshot[2]*rf->area;
106
107                         if(energy>maxenergy) {
108                                 shoot= vlr;
109                                 maxenergy= energy;
110                         }
111                 }
112         }
113
114         if(shoot) {
115                 maxenergy/= RG.totenergy;
116                 if(maxenergy<RG.convergence) return NULL;
117                 shoot->radface->flag |= RAD_SHOOT;
118         }
119
120         return shoot;
121 }
122
123 static void backface_test_rr(Render *re, VlakRen *shoot)
124 {
125         VlakRen *vlr=NULL;
126         RadFace *rf;
127         float tvec[3];
128         int a;
129         
130         /* backface testing */
131         for(a=0; a<re->totvlak; a++) {
132                 if((a & 255)==0) vlr= re->blovl[a>>8]; else vlr++;
133                 if(vlr->radface) {
134                         if(vlr!=shoot) {
135                                 rf= vlr->radface;
136                                 VecSubf(tvec, shoot->radface->cent, rf->cent);
137                                 
138                                 if( tvec[0]*rf->norm[0]+ tvec[1]*rf->norm[1]+ tvec[2]*rf->norm[2] < 0.0) {              
139                                         rf->flag |= RAD_BACKFACE;
140                                 }
141                         }
142                 }
143         }
144 }
145
146 static void clear_backface_test_rr(Render *re)
147 {
148         VlakRen *vlr=NULL;
149         RadFace *rf;
150         int a;
151         
152         /* backface flag clear */
153         for(a=0; a<re->totvlak; a++) {
154                 if((a & 255)==0) vlr= re->blovl[a>>8]; else vlr++;
155                 
156                 if(vlr->radface) {
157                         rf= vlr->radface;
158                         rf->flag &= ~RAD_BACKFACE;
159                 }
160         }
161 }
162
163 extern RadView hemitop, hemiside; // radfactors.c
164
165 /* hemi-zbuffering, delivers formfactors array */
166 static void makeformfactors_rr(Render *re, VlakRen *shoot)
167 {
168         VlakRen *vlr=NULL;
169         RadFace *rf;
170         float len, vec[3], up[3], side[3], tar[5][3], *fp;
171         int a;
172
173         memset(RG.formfactors, 0, sizeof(float)*RG.totelem);
174
175         /* set up hemiview */
176         /* first: upvector for hemitop, we use diagonal hemicubes to prevent aliasing */
177         
178         VecSubf(vec, shoot->v1->co, shoot->radface->cent);
179         Crossf(up, shoot->radface->norm, vec);
180         len= Normalise(up);
181         
182         VECCOPY(hemitop.up, up);
183         VECCOPY(hemiside.up, shoot->radface->norm);
184
185         Crossf(side, shoot->radface->norm, up);
186
187         /* five targets */
188         VecAddf(tar[0], shoot->radface->cent, shoot->radface->norm);
189         VecAddf(tar[1], shoot->radface->cent, up);
190         VecSubf(tar[2], shoot->radface->cent, up);
191         VecAddf(tar[3], shoot->radface->cent, side);
192         VecSubf(tar[4], shoot->radface->cent, side);
193
194         /* camera */
195         VECCOPY(hemiside.cam, shoot->radface->cent);
196         VECCOPY(hemitop.cam, shoot->radface->cent);
197
198         /* do it! */
199         VECCOPY(hemitop.tar, tar[0]);
200         hemizbuf(&hemitop);
201
202         for(a=1; a<5; a++) {
203                 VECCOPY(hemiside.tar, tar[a]);
204                 hemizbuf(&hemiside);
205         }
206
207         /* convert factors to real radiosity */
208         fp= RG.formfactors;
209
210         for(a=0; a<re->totvlak; a++) {
211                 if((a & 255)==0) vlr= re->blovl[a>>8]; else vlr++;
212                 
213                 if(vlr->radface) {
214                         rf= vlr->radface;
215                         if(*fp!=0.0 && rf->area!=0.0) {
216                                 *fp *= shoot->radface->area/rf->area;
217                                 if(*fp>1.0) *fp= 1.0001;
218                         }
219                         fp++;
220                 }
221         }
222 }
223
224 /* based at RG.formfactors array, distribute shoot energy over other faces */
225 static void applyformfactors_rr(Render *re, VlakRen *shoot)
226 {
227         VlakRen *vlr=NULL;
228         RadFace *rf;
229         float *fp, *ref, unr, ung, unb, r, g, b;
230         int a;
231
232         unr= shoot->radface->unshot[0];
233         ung= shoot->radface->unshot[1];
234         unb= shoot->radface->unshot[2];
235
236         fp= RG.formfactors;
237         
238         for(a=0; a<re->totvlak; a++) {
239                 if((a & 255)==0) vlr= re->blovl[a>>8]; else vlr++;
240                 
241                 if(vlr->radface) {
242                         rf= vlr->radface;
243                         if(*fp!= 0.0) {
244                                 
245                                 ref= &(vlr->mat->r);
246                                 
247                                 r= (*fp)*unr*ref[0];
248                                 g= (*fp)*ung*ref[1];
249                                 b= (*fp)*unb*ref[2];
250                                 
251                                 // if(rf->flag & RAD_BACKFACE) {
252                                 
253                                 rf->totrad[0]+= r;
254                                 rf->totrad[1]+= g;
255                                 rf->totrad[2]+= b;
256                                 
257                                 rf->unshot[0]+= r;
258                                 rf->unshot[1]+= g;
259                                 rf->unshot[2]+= b;
260                         }
261                         fp++;
262                 }
263         }
264         /* shoot energy has been shot */
265         shoot->radface->unshot[0]= shoot->radface->unshot[1]= shoot->radface->unshot[2]= 0.0;
266 }
267
268
269 /* main loop for itterations */
270 static void progressiverad_rr(Render *re)
271 {
272         VlakRen *shoot;
273         float unshot[3];
274         int it= 0;
275         
276         shoot= findshoot_rr(re);
277         while( shoot ) {
278                 
279                 /* backfaces receive no energy, but are zbuffered... */
280                 backface_test_rr(re, shoot);
281                 
282                 /* ...unless it's two sided */
283                 if(shoot->radface->flag & RAD_TWOSIDED) {
284                         VECCOPY(unshot, shoot->radface->unshot);
285                         VecMulf(shoot->radface->norm, -1.0);
286                         makeformfactors_rr(re, shoot);
287                         applyformfactors_rr(re, shoot);
288                         VecMulf(shoot->radface->norm, -1.0);
289                         VECCOPY(shoot->radface->unshot, unshot);
290                 }
291
292                 /* hemi-zbuffers */
293                 makeformfactors_rr(re, shoot);
294                 /* based at RG.formfactors array, distribute shoot energy over other faces */
295                 applyformfactors_rr(re, shoot);
296                 
297                 it++;
298                 re->timecursor(it);
299                 
300                 clear_backface_test_rr(re);
301                 
302                 if(blender_test_break()) break;
303                 if(RG.maxiter && RG.maxiter<=it) break;
304                 
305                 shoot= findshoot_rr(re);
306         }
307         printf(" Unshot energy:%f\n", 1000.0*maxenergy);
308         
309         re->timecursor((G.scene->r.cfra));
310 }
311
312 static RadFace *radfaces=NULL;
313
314 static void initradfaces(Render *re)    
315 {
316         VlakRen *vlr= NULL;
317         RadFace *rf;
318         int a, b;
319         
320         /* globals */
321         RG.totenergy= 0.0;
322         RG.totpatch= 0;         // we count initial emittors here
323         RG.totelem= 0;          // total # faces are put here (so we can use radfactors.c calls)
324         /* size is needed for hemicube clipping */
325         RG.min[0]= RG.min[1]= RG.min[2]= 1.0e20;
326         RG.max[0]= RG.max[1]= RG.max[2]= -1.0e20;
327         
328         /* count first for fast malloc */
329         for(a=0; a<re->totvlak; a++) {
330                 if((a & 255)==0) vlr= re->blovl[a>>8]; else vlr++;
331                 
332                 if(vlr->mat->mode & MA_RADIO) {
333                         if(vlr->mat->emit > 0.0) {
334                                 RG.totpatch++;
335                         }
336                         RG.totelem++;
337                 }
338         }
339         
340 printf(" Rad elems: %d emittors %d\n", RG.totelem, RG.totpatch);        
341         if(RG.totelem==0 || RG.totpatch==0) return;
342
343         /* make/init radfaces */
344         rf=radfaces= MEM_callocN(RG.totelem*sizeof(RadFace), "radfaces");
345         for(a=0; a<re->totvlak; a++) {
346                 if((a & 255)==0) vlr= re->blovl[a>>8]; else vlr++;
347                 
348                 if(vlr->mat->mode & MA_RADIO) {
349                         
350                         /* during render, vlr->n gets flipped/corrected, we cannot have that */
351                         if(vlr->v4) CalcNormFloat4(vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4->co, rf->norm);
352                         else CalcNormFloat(vlr->v1->co, vlr->v2->co, vlr->v3->co, rf->norm);
353                         
354                         rf->totrad[0]= vlr->mat->emit*vlr->mat->r;
355                         rf->totrad[1]= vlr->mat->emit*vlr->mat->g;
356                         rf->totrad[2]= vlr->mat->emit*vlr->mat->b;
357                         VECCOPY(rf->unshot, rf->totrad);
358                         
359                         if(vlr->v4) {
360                                 rf->area= AreaQ3Dfl(vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4->co);
361                                 CalcCent4f(rf->cent, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4->co);
362                         }
363                         else {
364                                 rf->area= AreaT3Dfl(vlr->v1->co, vlr->v2->co, vlr->v3->co);
365                                 CalcCent3f(rf->cent, vlr->v1->co, vlr->v2->co, vlr->v3->co);
366                         }
367                         
368                         RG.totenergy+= rf->unshot[0]*rf->area;
369                         RG.totenergy+= rf->unshot[1]*rf->area;
370                         RG.totenergy+= rf->unshot[2]*rf->area;
371                         
372                         for(b=0; b<3; b++) {
373                                 RG.min[b]= MIN2(RG.min[b], rf->cent[b]);
374                                 RG.max[b]= MAX2(RG.max[b], rf->cent[b]);
375                         }
376
377 // uncommented; this isnt satisfying, but i leave it in the code for now (ton)                  
378 //                      if(vlr->mat->translucency!=0.0) rf->flag |= RAD_TWOSIDED;
379                         
380                         vlr->radface= rf++;
381                 }
382         }
383         RG.size[0]= (RG.max[0]- RG.min[0]);
384         RG.size[1]= (RG.max[1]- RG.min[1]);
385         RG.size[2]= (RG.max[2]- RG.min[2]);
386         RG.maxsize= MAX3(RG.size[0],RG.size[1],RG.size[2]);
387
388         /* formfactor array */
389         if(RG.formfactors) MEM_freeN(RG.formfactors);
390         if(RG.totelem)
391                 RG.formfactors= MEM_mallocN(sizeof(float)*RG.totelem, "formfactors");
392         else
393                 RG.formfactors= NULL;
394         
395 }
396
397 static void vecaddfac(float *vec, float *v1, float *v2, float fac)
398 {
399         vec[0]= v1[0] + fac*v2[0];
400         vec[1]= v1[1] + fac*v2[1];
401         vec[2]= v1[2] + fac*v2[2];
402
403 }
404
405 /* unused now, doesnt work..., find it in cvs of nov 2005 or older */
406 /* static void filter_rad_values(void) */
407
408
409 static void make_vertex_rad_values(Render *re)
410 {
411         VertRen *v1=NULL;
412         VlakRen *vlr=NULL;
413         RadFace *rf;
414         float *col;
415         int a;
416
417         RG.igamma= 1.0/RG.gamma;
418         RG.radfactor= RG.radfac*pow(64*64, RG.igamma)/128.0; /* compatible with radio-tool */
419
420         /* accumulate vertexcolors */
421         for(a=0; a<re->totvlak; a++) {
422                 if((a & 255)==0) vlr= re->blovl[a>>8]; else vlr++;
423                 
424                 if(vlr->radface) {
425                         rf= vlr->radface;
426                         
427                         /* apply correction */
428                         rf->totrad[0]= RG.radfactor*pow( rf->totrad[0], RG.igamma);
429                         rf->totrad[1]= RG.radfactor*pow( rf->totrad[1], RG.igamma);
430                         rf->totrad[2]= RG.radfactor*pow( rf->totrad[2], RG.igamma);
431                         
432                         /* correct rf->rad values for color */
433                         if(vlr->mat->r > 0.0) rf->totrad[0]/= vlr->mat->r;
434                         if(vlr->mat->g > 0.0) rf->totrad[1]/= vlr->mat->g;
435                         if(vlr->mat->b > 0.0) rf->totrad[2]/= vlr->mat->b;
436                         
437                         col= RE_vertren_get_rad(re, vlr->v1, 1);
438                         vecaddfac(col, col, rf->totrad, rf->area); 
439                         col[3]+= rf->area;
440                         
441                         col= RE_vertren_get_rad(re, vlr->v2, 1);
442                         vecaddfac(col, col, rf->totrad, rf->area); 
443                         col[3]+= rf->area;
444                         
445                         col= RE_vertren_get_rad(re, vlr->v3, 1);
446                         vecaddfac(col, col, rf->totrad, rf->area); 
447                         col[3]+= rf->area;
448
449                         if(vlr->v4) {
450                                 col= RE_vertren_get_rad(re, vlr->v4, 1);
451                                 vecaddfac(col, col, rf->totrad, rf->area); 
452                                 col[3]+= rf->area;
453                         }
454                 }
455         }
456         
457         /* make vertex colors */
458         for(a=0; a<re->totvert; a++) {
459                 if((a & 255)==0) v1= RE_findOrAddVert(re, a); else v1++;
460                 col= RE_vertren_get_rad(re, v1, 0);
461                 if(col[3]>0.0) {
462                         col[0]/= col[3];
463                         col[1]/= col[3];
464                         col[2]/= col[3];
465                 }
466         }
467
468 }
469
470 /* main call, extern */
471 void do_radio_render(Render *re)
472 {
473         if(G.scene->radio==NULL) add_radio();
474         freeAllRad();   /* just in case radio-tool is still used */
475         
476         set_radglobal(); /* init the RG struct */
477         RG.re= re;              /* only used by hemizbuf(), prevents polluting radio code all over */
478         
479         initradfaces(re);        /* add radface structs to render faces */
480         if(RG.totenergy>0.0) {
481
482                 initradiosity();        /* LUT's */
483                 inithemiwindows();      /* views, need RG.maxsize for clipping */
484         
485                 progressiverad_rr(re); /* main radio loop */
486                 
487                 make_vertex_rad_values(re); /* convert face energy to vertex ones */
488
489         }
490         
491         freeAllRad();   /* luts, hemis, sets vars at zero */
492 }
493
494 /* free call, after rendering, extern */
495 void end_radio_render(void)
496 {
497         if(radfaces) MEM_freeN(radfaces);
498         radfaces= NULL;
499 }
500