svn merge -r 13357:13382 https://svn.blender.org/svnroot/bf-blender/trunk/blender
[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 void findshoot_rr(Render *re, VlakRen **shoot_p, RadFace **shootrf_p)
88 {
89         RadFace *rf, *shootrf, **radface;
90         ObjectRen *obr;
91         VlakRen *vlr=NULL, *shoot;
92         float energy;
93         int a;
94         
95         shoot= NULL;
96         shootrf= NULL;
97         maxenergy= 0.0;
98         
99         for(obr=re->objecttable.first; obr; obr=obr->next) {
100                 for(a=0; a<obr->totvlak; a++) {
101                         if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak; else vlr++;
102                         if((radface=RE_vlakren_get_radface(obr, vlr, 0))) {
103                                 rf= *radface;
104                                 rf->flag &= ~RAD_SHOOT;
105                                 
106                                 energy= rf->unshot[0]*rf->area;
107                                 energy+= rf->unshot[1]*rf->area;
108                                 energy+= rf->unshot[2]*rf->area;
109
110                                 if(energy>maxenergy) {
111                                         shoot= vlr;
112                                         shootrf= rf;
113                                         maxenergy= energy;
114                                 }
115                         }
116                 }
117         }
118
119         if(shootrf) {
120                 maxenergy/= RG.totenergy;
121                 if(maxenergy<RG.convergence) {
122                         *shoot_p= NULL;
123                         *shootrf_p= NULL;
124                 }
125                 shootrf->flag |= RAD_SHOOT;
126         }
127
128         *shoot_p= shoot;
129         *shootrf_p= shootrf;
130 }
131
132 static void backface_test_rr(Render *re, VlakRen *shoot, RadFace *shootrf)
133 {
134         ObjectRen *obr;
135         VlakRen *vlr=NULL;
136         RadFace *rf, **radface;
137         float tvec[3];
138         int a;
139         
140         /* backface testing */
141         for(obr=re->objecttable.first; obr; obr=obr->next) {
142                 for(a=0; a<obr->totvlak; a++) {
143                         if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak; else vlr++;
144                         if(vlr != shoot && (radface=RE_vlakren_get_radface(obr, vlr, 0))) {
145                                 rf= *radface;
146                                 VecSubf(tvec, shootrf->cent, rf->cent);
147                                 
148                                 if(tvec[0]*rf->norm[0]+ tvec[1]*rf->norm[1]+ tvec[2]*rf->norm[2] < 0.0)
149                                         rf->flag |= RAD_BACKFACE;
150                         }
151                 }
152         }
153 }
154
155 static void clear_backface_test_rr(Render *re)
156 {
157         ObjectRen *obr;
158         VlakRen *vlr=NULL;
159         RadFace *rf, **radface;
160         int a;
161         
162         /* backface flag clear */
163         for(obr=re->objecttable.first; obr; obr=obr->next) {
164                 for(a=0; a<obr->totvlak; a++) {
165                         if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak; else vlr++;
166                         
167                         if((radface=RE_vlakren_get_radface(obr, vlr, 0))) {
168                                 rf= *radface;
169                                 rf->flag &= ~RAD_BACKFACE;
170                         }
171                 }
172         }
173 }
174
175 extern RadView hemitop, hemiside; // radfactors.c
176
177 /* hemi-zbuffering, delivers formfactors array */
178 static void makeformfactors_rr(Render *re, VlakRen *shoot, RadFace *shootrf)
179 {
180         ObjectRen *obr;
181         VlakRen *vlr=NULL;
182         RadFace *rf, **radface;
183         float len, vec[3], up[3], side[3], tar[5][3], *fp;
184         int a;
185
186         memset(RG.formfactors, 0, sizeof(float)*RG.totelem);
187
188         /* set up hemiview */
189         /* first: upvector for hemitop, we use diagonal hemicubes to prevent aliasing */
190         
191         VecSubf(vec, shoot->v1->co, shootrf->cent);
192         Crossf(up, shootrf->norm, vec);
193         len= Normalize(up);
194         
195         VECCOPY(hemitop.up, up);
196         VECCOPY(hemiside.up, shootrf->norm);
197
198         Crossf(side, shootrf->norm, up);
199
200         /* five targets */
201         VecAddf(tar[0], shootrf->cent, shootrf->norm);
202         VecAddf(tar[1], shootrf->cent, up);
203         VecSubf(tar[2], shootrf->cent, up);
204         VecAddf(tar[3], shootrf->cent, side);
205         VecSubf(tar[4], shootrf->cent, side);
206
207         /* camera */
208         VECCOPY(hemiside.cam, shootrf->cent);
209         VECCOPY(hemitop.cam, shootrf->cent);
210
211         /* do it! */
212         VECCOPY(hemitop.tar, tar[0]);
213         hemizbuf(&hemitop);
214
215         for(a=1; a<5; a++) {
216                 VECCOPY(hemiside.tar, tar[a]);
217                 hemizbuf(&hemiside);
218         }
219
220         /* convert factors to real radiosity */
221         fp= RG.formfactors;
222
223         for(obr=re->objecttable.first; obr; obr=obr->next) {
224                 for(a=0; a<obr->totvlak; a++) {
225                         if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak; else vlr++;
226                         
227                         if((radface=RE_vlakren_get_radface(obr, vlr, 0))) {
228                                 rf= *radface;
229                                 if(*fp!=0.0 && rf->area!=0.0) {
230                                         *fp *= shootrf->area/rf->area;
231                                         if(*fp>1.0) *fp= 1.0001;
232                                 }
233                                 fp++;
234                         }
235                 }
236         }
237 }
238
239 /* based at RG.formfactors array, distribute shoot energy over other faces */
240 static void applyformfactors_rr(Render *re, VlakRen *shoot, RadFace *shootrf)
241 {
242         ObjectRen *obr;
243         VlakRen *vlr=NULL;
244         RadFace *rf, **radface;
245         float *fp, *ref, unr, ung, unb, r, g, b;
246         int a;
247
248         unr= shootrf->unshot[0];
249         ung= shootrf->unshot[1];
250         unb= shootrf->unshot[2];
251
252         fp= RG.formfactors;
253         
254         for(obr=re->objecttable.first; obr; obr=obr->next) {
255                 for(a=0; a<obr->totvlak; a++) {
256                         if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak; else vlr++;
257                         
258                         if((radface=RE_vlakren_get_radface(obr, vlr, 0))) {
259                                 rf= *radface;
260                                 if(*fp!= 0.0) {
261                                         
262                                         ref= &(vlr->mat->r);
263                                         
264                                         r= (*fp)*unr*ref[0];
265                                         g= (*fp)*ung*ref[1];
266                                         b= (*fp)*unb*ref[2];
267                                         
268                                         // if(rf->flag & RAD_BACKFACE) {
269                                         
270                                         rf->totrad[0]+= r;
271                                         rf->totrad[1]+= g;
272                                         rf->totrad[2]+= b;
273                                         
274                                         rf->unshot[0]+= r;
275                                         rf->unshot[1]+= g;
276                                         rf->unshot[2]+= b;
277                                 }
278                                 fp++;
279                         }
280                 }
281         }
282         /* shoot energy has been shot */
283         shootrf->unshot[0]= shootrf->unshot[1]= shootrf->unshot[2]= 0.0;
284 }
285
286
287 /* main loop for itterations */
288 static void progressiverad_rr(Render *re)
289 {
290         VlakRen *shoot;
291         RadFace *shootrf;
292         float unshot[3];
293         int it= 0;
294         
295         findshoot_rr(re, &shoot, &shootrf);
296         while( shoot ) {
297                 
298                 /* backfaces receive no energy, but are zbuffered... */
299                 backface_test_rr(re, shoot, shootrf);
300                 
301                 /* ...unless it's two sided */
302                 if(shootrf->flag & RAD_TWOSIDED) {
303                         VECCOPY(unshot, shootrf->unshot);
304                         VecMulf(shootrf->norm, -1.0);
305                         makeformfactors_rr(re, shoot, shootrf);
306                         applyformfactors_rr(re, shoot, shootrf);
307                         VecMulf(shootrf->norm, -1.0);
308                         VECCOPY(shootrf->unshot, unshot);
309                 }
310
311                 /* hemi-zbuffers */
312                 makeformfactors_rr(re, shoot, shootrf);
313                 /* based at RG.formfactors array, distribute shoot energy over other faces */
314                 applyformfactors_rr(re, shoot, shootrf);
315                 
316                 it++;
317                 re->timecursor(it);
318                 
319                 clear_backface_test_rr(re);
320                 
321                 if(re->test_break()) break;
322                 if(RG.maxiter && RG.maxiter<=it) break;
323                 
324                 findshoot_rr(re, &shoot, &shootrf);
325         }
326         printf(" Unshot energy:%f\n", 1000.0*maxenergy);
327         
328         re->timecursor((G.scene->r.cfra));
329 }
330
331 static RadFace *radfaces=NULL;
332
333 static void initradfaces(Render *re)    
334 {
335         ObjectRen *obr;
336         VlakRen *vlr= NULL;
337         RadFace *rf, **radface;
338         int a, b;
339         
340         /* globals */
341         RG.totenergy= 0.0;
342         RG.totpatch= 0;         // we count initial emittors here
343         RG.totelem= 0;          // total # faces are put here (so we can use radfactors.c calls)
344         /* size is needed for hemicube clipping */
345         RG.min[0]= RG.min[1]= RG.min[2]= 1.0e20;
346         RG.max[0]= RG.max[1]= RG.max[2]= -1.0e20;
347         
348         /* count first for fast malloc */
349         for(obr=re->objecttable.first; obr; obr=obr->next) {
350                 for(a=0; a<obr->totvlak; a++) {
351                         if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak; else vlr++;
352                         
353                         if(vlr->mat->mode & MA_RADIO) {
354                                 if(vlr->mat->emit > 0.0) {
355                                         RG.totpatch++;
356                                 }
357                                 RG.totelem++;
358                         }
359                 }
360         }
361                 
362 printf(" Rad elems: %d emittors %d\n", RG.totelem, RG.totpatch);        
363         if(RG.totelem==0 || RG.totpatch==0) return;
364
365         /* make/init radfaces */
366         rf=radfaces= MEM_callocN(RG.totelem*sizeof(RadFace), "radfaces");
367         for(obr=re->objecttable.first; obr; obr=obr->next) {
368                 for(a=0; a<obr->totvlak; a++) {
369                         if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak; else vlr++;
370                         
371                         if(vlr->mat->mode & MA_RADIO) {
372                                 
373                                 /* during render, vlr->n gets flipped/corrected, we cannot have that */
374                                 if(vlr->v4) CalcNormFloat4(vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4->co, rf->norm);
375                                 else CalcNormFloat(vlr->v1->co, vlr->v2->co, vlr->v3->co, rf->norm);
376                                 
377                                 rf->totrad[0]= vlr->mat->emit*vlr->mat->r;
378                                 rf->totrad[1]= vlr->mat->emit*vlr->mat->g;
379                                 rf->totrad[2]= vlr->mat->emit*vlr->mat->b;
380                                 VECCOPY(rf->unshot, rf->totrad);
381                                 
382                                 if(vlr->v4) {
383                                         rf->area= AreaQ3Dfl(vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4->co);
384                                         CalcCent4f(rf->cent, vlr->v1->co, vlr->v2->co, vlr->v3->co, vlr->v4->co);
385                                 }
386                                 else {
387                                         rf->area= AreaT3Dfl(vlr->v1->co, vlr->v2->co, vlr->v3->co);
388                                         CalcCent3f(rf->cent, vlr->v1->co, vlr->v2->co, vlr->v3->co);
389                                 }
390                                 
391                                 RG.totenergy+= rf->unshot[0]*rf->area;
392                                 RG.totenergy+= rf->unshot[1]*rf->area;
393                                 RG.totenergy+= rf->unshot[2]*rf->area;
394                                 
395                                 for(b=0; b<3; b++) {
396                                         RG.min[b]= MIN2(RG.min[b], rf->cent[b]);
397                                         RG.max[b]= MAX2(RG.max[b], rf->cent[b]);
398                                 }
399
400         // uncommented; this isnt satisfying, but i leave it in the code for now (ton)                  
401         //                      if(vlr->mat->translucency!=0.0) rf->flag |= RAD_TWOSIDED;
402                                 
403                                 radface=RE_vlakren_get_radface(obr, vlr, 1);
404                                 *radface= rf++;
405                         }
406                 }
407         }
408         RG.size[0]= (RG.max[0]- RG.min[0]);
409         RG.size[1]= (RG.max[1]- RG.min[1]);
410         RG.size[2]= (RG.max[2]- RG.min[2]);
411         RG.maxsize= MAX3(RG.size[0],RG.size[1],RG.size[2]);
412
413         /* formfactor array */
414         if(RG.formfactors) MEM_freeN(RG.formfactors);
415         if(RG.totelem)
416                 RG.formfactors= MEM_mallocN(sizeof(float)*RG.totelem, "formfactors");
417         else
418                 RG.formfactors= NULL;
419         
420 }
421
422 static void vecaddfac(float *vec, float *v1, float *v2, float fac)
423 {
424         vec[0]= v1[0] + fac*v2[0];
425         vec[1]= v1[1] + fac*v2[1];
426         vec[2]= v1[2] + fac*v2[2];
427
428 }
429
430 /* unused now, doesnt work..., find it in cvs of nov 2005 or older */
431 /* static void filter_rad_values(void) */
432
433
434 static void make_vertex_rad_values(Render *re)
435 {
436         ObjectRen *obr;
437         VertRen *v1=NULL;
438         VlakRen *vlr=NULL;
439         RadFace *rf, **radface;
440         float *col;
441         int a;
442
443         RG.igamma= 1.0/RG.gamma;
444         RG.radfactor= RG.radfac*pow(64*64, RG.igamma)/128.0; /* compatible with radio-tool */
445
446         /* accumulate vertexcolors */
447         for(obr=re->objecttable.first; obr; obr=obr->next) {
448                 for(a=0; a<obr->totvlak; a++) {
449                         if((a & 255)==0) vlr= obr->vlaknodes[a>>8].vlak; else vlr++;
450                         
451                         if((radface=RE_vlakren_get_radface(obr, vlr, 0))) {
452                                 rf= *radface;
453                                 
454                                 /* apply correction */
455                                 rf->totrad[0]= RG.radfactor*pow( rf->totrad[0], RG.igamma);
456                                 rf->totrad[1]= RG.radfactor*pow( rf->totrad[1], RG.igamma);
457                                 rf->totrad[2]= RG.radfactor*pow( rf->totrad[2], RG.igamma);
458                                 
459                                 /* correct rf->rad values for color */
460                                 if(vlr->mat->r > 0.0) rf->totrad[0]/= vlr->mat->r;
461                                 if(vlr->mat->g > 0.0) rf->totrad[1]/= vlr->mat->g;
462                                 if(vlr->mat->b > 0.0) rf->totrad[2]/= vlr->mat->b;
463                                 
464                                 col= RE_vertren_get_rad(obr, vlr->v1, 1);
465                                 vecaddfac(col, col, rf->totrad, rf->area); 
466                                 col[3]+= rf->area;
467                                 
468                                 col= RE_vertren_get_rad(obr, vlr->v2, 1);
469                                 vecaddfac(col, col, rf->totrad, rf->area); 
470                                 col[3]+= rf->area;
471                                 
472                                 col= RE_vertren_get_rad(obr, vlr->v3, 1);
473                                 vecaddfac(col, col, rf->totrad, rf->area); 
474                                 col[3]+= rf->area;
475
476                                 if(vlr->v4) {
477                                         col= RE_vertren_get_rad(obr, vlr->v4, 1);
478                                         vecaddfac(col, col, rf->totrad, rf->area); 
479                                         col[3]+= rf->area;
480                                 }
481                         }
482                 }
483         
484                 /* make vertex colors */
485                 for(a=0; a<obr->totvert; a++) {
486                         if((a & 255)==0) v1= RE_findOrAddVert(obr, a); else v1++;
487                         
488                         col= RE_vertren_get_rad(obr, v1, 0);
489                         if(col && col[3]>0.0) {
490                                 col[0]/= col[3];
491                                 col[1]/= col[3];
492                                 col[2]/= col[3];
493                         }
494                 }
495         }
496 }
497
498 /* main call, extern */
499 void do_radio_render(Render *re)
500 {
501         if(G.scene->radio==NULL) add_radio();
502         freeAllRad();   /* just in case radio-tool is still used */
503         
504         set_radglobal(); /* init the RG struct */
505         RG.re= re;              /* only used by hemizbuf(), prevents polluting radio code all over */
506         
507         initradfaces(re);        /* add radface structs to render faces */
508         if(RG.totenergy>0.0) {
509
510                 initradiosity();        /* LUT's */
511                 inithemiwindows();      /* views, need RG.maxsize for clipping */
512         
513                 progressiverad_rr(re); /* main radio loop */
514                 
515                 make_vertex_rad_values(re); /* convert face energy to vertex ones */
516
517         }
518         
519         freeAllRad();   /* luts, hemis, sets vars at zero */
520 }
521
522 /* free call, after rendering, extern */
523 void end_radio_render(void)
524 {
525         if(radfaces) MEM_freeN(radfaces);
526         radfaces= NULL;
527 }
528