Reverted incorrect merge (missing files)
[blender.git] / source / blender / radiosity / intern / source / radpreprocess.c
1         /* *************************************** 
2  *
3  * ***** BEGIN GPL 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.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software Foundation,
17  * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18  *
19  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
20  * All rights reserved.
21  *
22  * The Original Code is: all of this file.
23  *
24  * Contributor(s): none yet.
25  *
26  * ***** END GPL LICENSE BLOCK *****
27
28
29
30     preproces.c nov/dec 1992
31                                 may 1999
32         
33         - collect from meshes
34         - countglobaldata()
35         - makeGlobalElemArray()
36         
37    $Id$
38
39   *************************************** */
40
41 #include <stdlib.h>
42 #include <stdio.h>
43 #include <string.h>
44 #include <math.h>
45
46 #include "MEM_guardedalloc.h"
47
48 #include "BLI_blenlib.h"
49 #include "BLI_arithb.h"
50
51 #include "DNA_mesh_types.h"
52 #include "DNA_meshdata_types.h"
53 #include "DNA_object_types.h"
54 #include "DNA_scene_types.h"
55 #include "DNA_view3d_types.h"
56
57 #include "BKE_customdata.h"
58 #include "BKE_global.h"
59 #include "BKE_main.h"
60 #include "BKE_material.h"
61 #include "BKE_mesh.h"
62 #include "BKE_object.h" /* during_script() */
63 #include "BKE_utildefines.h"
64
65 #include "radio.h"
66
67 #include "BLO_sys_types.h" // for intptr_t support
68
69 void setparelem(RNode *rn, RPatch *par);
70
71 void splitconnected()
72 {
73         /* Since input meshes can have faces with sharing vertices, the geometry is being tested here.
74          * Using normals and colors, faces are split separately. we do this by storing for each
75          * vertex a normal and a color
76          */
77         RPatch *rp;
78         RNode *rn;
79         VeNoCo *vnc, *next, *vnc1;
80         int a;
81         
82         /* test if we need a split */
83         
84         rp= RG.patchbase.first;
85         while(rp) {
86                 rn= rp->first;
87                 if((rp->f1 & RAD_NO_SPLIT)==0) {
88                         for(a=0; a<rp->type; a++) {
89
90                                 if(a==0) vnc= (VeNoCo *)rn->v1;
91                                 else if(a==1) vnc= (VeNoCo *)rn->v2;
92                                 else if(a==2) vnc= (VeNoCo *)rn->v3;
93                                 else vnc= (VeNoCo *)rn->v4;
94
95                                 if(vnc->flag==0) {
96                                         vnc->n= (float *)rp->norm;
97                                         vnc->col= (float *)rp->ref;
98                                         vnc->flag= 1;
99                                 }
100                                 else {  /* is face from this vertex allowed for gouraud? */
101                                         vnc1= vnc;
102                                         while(vnc1) {
103                                                 if(VecCompare(vnc1->n, rp->norm, 0.01f)) {
104                                                         if(VecCompare(vnc1->col, rp->ref, 0.01f)) {
105                                                                 break;
106                                                         }
107                                                 }
108                                                 vnc= vnc1;
109                                                 vnc1= vnc1->next;
110                                         }
111                                         if(vnc1==0) {
112                                                 vnc1= MEM_mallocN(sizeof(VeNoCo), "splitconn");
113                                                 vnc1->next= 0;
114                                                 vnc1->v= mallocVert();
115                                                 vnc->next= vnc1;
116                                                 VECCOPY(vnc1->v, vnc->v);
117                                                 vnc1->n= (float *)rp->norm;
118                                                 vnc1->col= (float *)rp->ref;
119                                         }
120                                         if(a==0) rn->v1= (float *)vnc1;
121                                         else if(a==1) rn->v2= (float *)vnc1;
122                                         else if(a==2) rn->v3= (float *)vnc1;
123                                         else rn->v4= (float *)vnc1;
124                                 }
125                         }
126                 }
127                 rp= rp->next;
128         }
129                 /* adapt vertexpointers from nodes */
130         
131         rp= RG.patchbase.first;
132         while(rp) {
133                 rn= rp->first;
134                 rn->v1= ((VeNoCo *)(rn->v1))->v;
135                 rn->v2= ((VeNoCo *)(rn->v2))->v;
136                 rn->v3= ((VeNoCo *)(rn->v3))->v;
137                 if(rp->type==4) rn->v4= ((VeNoCo *)(rn->v4))->v;
138
139                 rp= rp->next;
140         }
141         
142         
143         /* free all */
144         vnc= RG.verts;
145         for(a=0; a<RG.totvert; a++) {
146                 vnc1= vnc->next;
147                 while(vnc1) {
148                         next= vnc1->next;
149                         MEM_freeN(vnc1);
150                         vnc1= next;
151                 }
152                 vnc++;
153         }
154         MEM_freeN(RG.verts);
155         RG.verts= 0;
156 }
157
158 int vergedge(const void *v1,const void *v2)
159 {
160         int *e1, *e2;
161         
162         e1= (int *)v1;
163         e2= (int *)v2;
164
165         if( e1[0] > e2[0] ) return 1;
166         else if( e1[0] < e2[0] ) return -1;
167         else if( e1[1] > e2[1] ) return 1;
168         else if( e1[1] < e2[1] ) return -1;
169
170         return 0;
171 }
172
173
174 void addedge(float *v1, float *v2, EdSort *es)
175 {
176         if( ((intptr_t)v1)<((intptr_t)v2) ) {
177                 es->v1= v1;
178                 es->v2= v2;
179         }
180         else {
181                 es->v2= v1;
182                 es->v1= v2;
183         }
184 }
185
186 static void setedge(RNode *node, RNode *nb, int nr, int nrb)
187 {
188         switch(nr) {
189                 case 1:
190                         node->ed1= nb;
191                         break;
192                 case 2:
193                         node->ed2= nb;
194                         break;
195                 case 3:
196                         node->ed3= nb;
197                         break;
198                 case 4:
199                         node->ed4= nb;
200                         break;
201         }
202         switch(nrb) {
203                 case 1:
204                         nb->ed1= node;
205                         break;
206                 case 2:
207                         nb->ed2= node;
208                         break;
209                 case 3:
210                         nb->ed3= node;
211                         break;
212                 case 4:
213                         nb->ed4= node;
214                         break;
215         }
216 }
217
218 void setedgepointers()
219 {
220         /* make edge-array and sort it */
221         /* pairs of edges are put together: fill in pointers in nodes */
222         EdSort *es, *esblock;
223         RPatch *rp;
224         RNode *rn;
225         int tot= 0;
226         
227         rp= RG.patchbase.first;
228         while(rp) {
229                 tot+= rp->type;
230                 rp= rp->next;
231         }
232         
233         if(tot==0) return;
234         
235         es=esblock= MEM_mallocN(tot*sizeof(EdSort), "setedgepointers");
236         rp= RG.patchbase.first;
237         while(rp) {
238                 rn= rp->first;
239                 addedge(rn->v1, rn->v2, es);
240                 es->nr= 1;
241                 es->node= rn;
242                 es++;           
243                 addedge(rn->v2, rn->v3, es);
244                 es->nr= 2;
245                 es->node= rn;
246                 es++;           
247                 if(rp->type==3) {
248                         addedge(rn->v3, rn->v1, es);
249                         es->nr= 3;
250                         es->node= rn;
251                         es++;
252                 }
253                 else {
254                         addedge(rn->v3, rn->v4, es);
255                         es->nr= 3;
256                         es->node= rn;
257                         es++;                                   
258                         addedge(rn->v4, rn->v1, es);
259                         es->nr= 4;
260                         es->node= rn;
261                         es++;
262                 }
263                 rp= rp->next;
264         }
265         
266         qsort(esblock,tot,sizeof(EdSort),vergedge);
267
268         es= esblock;
269         while(tot>0) {
270                 if( es->v1== (es+1)->v1 ) {
271                         if( es->v2== (es+1)->v2 ) {
272                                 setedge(es->node, (es+1)->node, es->nr, (es+1)->nr);
273                                 tot--;
274                                 es++;
275                         }
276                 }
277                 es++;
278                 tot--;
279         }
280
281         MEM_freeN(esblock);
282 }
283
284 static int materialIndex(Material *ma)
285 {
286         int i = 0;
287         for(i=0;i< RG.totmat; i++)
288         {
289                 if (RG.matar[i] == ma) {
290                         return i;
291                 }
292         }
293         return -1;
294 }
295
296 void rad_collect_meshes(Scene *scene, View3D *v3d)
297 {
298         extern Material defmaterial;
299         Base *base;
300         Object *ob;
301         Mesh *me;
302         MVert *mvert;
303         MFace *mface;
304         MTFace *tf, *tface;
305         Material *ma = NULL, *noma= NULL;
306         RPatch *rp;
307         RNode *rn;
308         VeNoCo *vnc, **nodevert;
309         float *vd, *v1, *v2, *v3, *v4 = NULL;
310         int a, b, offs, index, mfdatatot;
311         
312         if (v3d==NULL) {
313                 printf("Error, trying to collect radiosity meshes with no 3d view\n");
314                 return;
315         }
316         
317         set_radglobal(scene);
318
319         freeAllRad(scene);
320
321         start_fastmalloc("Radiosity");
322                                         
323         /* count the number of verts */
324         RG.totvert= 0;
325         RG.totface= 0;
326         base= (scene->base.first);
327         while(base) {
328                 if(((base)->flag & SELECT) && ((base)->lay & v3d->lay) ) {
329                         if(base->object->type==OB_MESH) {
330                                 base->flag |= OB_RADIO;
331                                 me= base->object->data;
332                                 RG.totvert+= me->totvert;
333                         }
334                 }
335                 base= base->next;
336         }
337         if(RG.totvert==0) {
338                 if (!during_script()); //XXX error("No vertices");
339                 return;
340         }
341         vnc= RG.verts= MEM_callocN(RG.totvert*sizeof(VeNoCo), "radioverts");
342
343         RG.min[0]= RG.min[1]= RG.min[2]= 1.0e20f;
344         RG.max[0]= RG.max[1]= RG.max[2]= -1.0e20f;
345
346         mfdatatot= 0;
347         
348         /* min-max and material array */
349         base= (scene->base.first);
350         while(base) {
351                 if( ((base)->flag & SELECT) && ((base)->lay & v3d->lay) ) {
352                         if(base->object->type==OB_MESH) {
353                                 me= base->object->data;
354                                 mvert= me->mvert;
355                                 for(a=0; a<me->totvert; a++, mvert++) {
356                                         vd= mallocVert();
357                                         VECCOPY(vd, mvert->co);
358                                         /* Should make MTC its own module... */
359                                         Mat4MulVecfl(base->object->obmat, vd);
360                                         
361                                         vnc->v= vd;
362                                         for(b=0; b<3; b++) {
363                                                 RG.min[b]= MIN2(RG.min[b], vd[b]);
364                                                 RG.max[b]= MAX2(RG.max[b], vd[b]);
365                                         }
366                                         vnc++;
367                                 }
368                                 
369                                 if(base->object->totcol==0) {
370                                         if(RG.totmat<MAXMAT) {
371                                                 if(noma==NULL) {
372                                                         noma= add_material("RadioMat");
373                                                         RG.matar[RG.totmat]= noma;
374                                                         RG.totmat++;
375                                                 }
376                                         }
377                                 }
378                                 else {
379                                         for(a=0; a<base->object->totcol; a++) {
380                                                 if(RG.totmat >= MAXMAT) break;
381
382                                                 ma = give_current_material(base->object, a+1);
383
384                                                 if (materialIndex(ma)!=-1) break;
385
386                                                 RG.matar[RG.totmat]= ma;
387                                                 RG.totmat++;
388                                         }
389                                 }
390
391                                 mfdatatot += me->totface;
392                         }
393                 }
394                 base= base->next;
395         }
396
397         RG.cent[0]= (RG.min[0]+ RG.max[0])/2;
398         RG.cent[1]= (RG.min[1]+ RG.max[1])/2;
399         RG.cent[2]= (RG.min[2]+ RG.max[2])/2;
400         RG.size[0]= (RG.max[0]- RG.min[0]);
401         RG.size[1]= (RG.max[1]- RG.min[1]);
402         RG.size[2]= (RG.max[2]- RG.min[2]);
403         RG.maxsize= MAX3(RG.size[0],RG.size[1],RG.size[2]);
404
405         RG.mfdata= MEM_callocN(sizeof(CustomData), "radiomfdata");
406         RG.mfdatanodes= MEM_mallocN(sizeof(RNode*)*mfdatatot, "radiomfdatanodes");
407         RG.mfdatatot= mfdatatot;
408
409         /* make patches */
410
411         RG.totelem= 0;
412         RG.totpatch= 0;
413         RG.totlamp= 0;
414         offs= 0;
415         
416         base= (scene->base.first);
417         while(base) {
418                 if( ((base)->flag & SELECT) && ((base)->lay & v3d->lay) )  {
419                         if(base->object->type==OB_MESH) {
420                                 ob= base->object;
421                                 me= ob->data;
422                                 mface= me->mface;
423                                 tface= me->mtface;
424                                 
425                                 index= -1;
426
427                                 CustomData_merge(&me->fdata, RG.mfdata, CD_MASK_DERIVEDMESH,
428                                         CD_DEFAULT, mfdatatot);
429                                 
430                                 for(a=0; a<me->totface; a++, mface++) {
431                                         tf= tface? tface+a: NULL;
432                                         
433                                         if (tf && (tf->mode & TF_INVISIBLE))
434                                                 continue;
435
436                                         rp= callocPatch();
437                                         BLI_addtail(&(RG.patchbase), rp);
438                                         rp->from= ob;
439                                         
440                                         if(mface->v4) rp->type= 4;
441                                         else rp->type= 3;
442                                         
443                                         rp->first= rn= callocNode();
444                                         
445                                         if(mface->flag & ME_SMOOTH) rp->f1= RAD_NO_SPLIT;
446                                         
447                                         /* temporal: we store the venoco in the node */
448                                         rn->v1= (float *)(RG.verts+mface->v1+offs);
449                                         v1= (RG.verts+mface->v1+offs)->v;
450                                         rn->v2= (float *)(RG.verts+mface->v2+offs);
451                                         v2= (RG.verts+mface->v2+offs)->v;
452                                         rn->v3= (float *)(RG.verts+mface->v3+offs);
453                                         v3= (RG.verts+mface->v3+offs)->v;
454
455                                         if(mface->v4) {
456                                                 rn->v4= (float *)(RG.verts+mface->v4+offs);
457                                                 v4= (RG.verts+mface->v4+offs)->v;
458                                         }                       
459                                         rn->par= rp;
460                                         rn->f= RAD_PATCH;       /* this node is a Patch */
461                                         rn->type= rp->type;
462
463                                         if(rn->type==4) {
464                                                 rp->area= AreaQ3Dfl(v1, v2, v3, v4);
465                                                 CalcNormFloat4(v1, v2, v3, v4, rp->norm);
466                                         }
467                                         else {
468                                                 rp->area= AreaT3Dfl(v1, v2, v3);
469                                                 CalcNormFloat(v1, v2, v3, rp->norm);
470                                         }
471
472                                         rn->area= rp->area;
473
474                                         /* color and emit */
475                                         if(mface->mat_nr != index) {
476                                                 index= mface->mat_nr;
477                                                 ma= give_current_material(ob, index+1);
478                                                 if(ma==0) ma= &defmaterial;
479                                         }
480                                         rp->ref[0]= ma->r;
481                                         rp->ref[1]= ma->g;
482                                         rp->ref[2]= ma->b;
483
484                                         if(ma->emit) RG.totlamp++;
485
486                                         rp->emit[0]= rp->emit[1]= rp->emit[2]= ma->emit;
487                                         rp->emit[0]*= rp->ref[0];
488                                         rp->emit[1]*= rp->ref[1];
489                                         rp->emit[2]*= rp->ref[2];
490
491 // uncommented, this is not satisfying, but i leave it in code for now (ton)                                            
492 //                                              if(ma->translucency!=0.0) rn->f |= RAD_TWOSIDED;
493
494                                         nodevert= (VeNoCo **)&(rn->v1);
495                                         for(b=0; b<rp->type; b++) {
496                                                 rp->cent[0]+= (*nodevert)->v[0];
497                                                 rp->cent[1]+= (*nodevert)->v[1];
498                                                 rp->cent[2]+= (*nodevert)->v[2];
499                                                 nodevert++;
500                                         }
501                                         rp->cent[0]/= (float)rp->type;
502                                         rp->cent[1]/= (float)rp->type;
503                                         rp->cent[2]/= (float)rp->type;
504                                         
505                                         /* for reconstruction materials */
506                                         rp->matindex= materialIndex(ma);
507                                         if(rp->matindex==-1) rp->matindex= 1;
508
509                                         /* these RNode's are stored now for later use in rad_addmesh
510                                            they should not get deleted before that */
511                                         rn->orig= RG.totelem;
512                                         RG.mfdatanodes[RG.totelem]= rn;
513
514                                         CustomData_copy_data(&me->fdata, RG.mfdata, a, RG.totelem, 1);
515                                         
516                                         RG.totelem++;
517                                         RG.totpatch++;
518                                 }
519
520                                 offs+= me->totvert;
521                         }
522                 }
523                 base= base->next;
524         }
525         
526         splitconnected();
527         setedgepointers();
528
529         makeGlobalElemArray();
530         pseudoAmb();
531         rad_setlimits(scene);
532 }
533
534 void setparelem(RNode *rn, RPatch *par)
535 {
536         
537         if(rn->down1) {
538                 setparelem(rn->down1, par);
539                 setparelem(rn->down2, par);
540         }
541         else {
542                 rn->par= par;
543         }
544 }
545
546 void countelem(RNode *rn)
547 {
548
549         if(rn->down1) {
550                 countelem(rn->down1);
551                 countelem(rn->down2);
552         }
553         else RG.totelem++;
554 }
555
556 void countglobaldata()
557 {
558         /* counts elements and patches*/
559         RPatch *rp;
560
561         RG.totelem= RG.totpatch= 0;
562
563         rp= RG.patchbase.first;
564         while(rp) {
565                 RG.totpatch++;
566                 countelem(rp->first);
567                 rp= rp->next;
568         }
569 }
570
571 void addelem(RNode ***el, RNode *rn, RPatch *rp)
572 {
573         if(rn->down1) {
574                 addelem(el, rn->down1, rp);
575                 addelem(el, rn->down2, rp);
576         }
577         else {
578                 rn->par= rp;
579                 **el= rn;
580                 (*el)++;
581         }
582 }
583
584 void makeGlobalElemArray()
585 {
586         /* always called when # of elements change */
587         RPatch *rp;
588         RNode **el;
589
590         countglobaldata();
591
592         if(RG.elem) MEM_freeN(RG.elem);
593         if(RG.totelem) {
594                 el= RG.elem= MEM_mallocN(sizeof(void *)*RG.totelem, "makeGlobalElemArray");
595         }
596         else {
597                 RG.elem= 0;
598                 return;
599         }
600
601         /* recursive adding elements */
602         rp= RG.patchbase.first;
603         while(rp) {
604                 addelem(&el, rp->first, rp);
605                 rp= rp->next;
606         }
607
608         /* formfactor array */
609         if(RG.formfactors) MEM_freeN(RG.formfactors);
610         if(RG.totelem)
611                 RG.formfactors= MEM_mallocN(sizeof(float)*RG.totelem, "formfactors");
612         else
613                 RG.formfactors= 0;
614 }
615
616 void splitpatch(RPatch *old)            /* in case of overflow during shoot */
617 {
618         RNode *rn;
619         float **fpp;
620         RPatch *rp;
621         int a;
622         
623         rn= old->first;
624         if(rn->down1==0) return;
625         rn= rn->down1;
626
627         old->unshot[0]/=2.0;
628         old->unshot[1]/=2.0;
629         old->unshot[2]/=2.0;
630         setnodeflags(old->first, 2, 0);
631
632         rp= mallocPatch();
633         *rp= *old;
634         BLI_addhead(&RG.patchbase, rp);
635         rp->first= rn;
636         rp->area= rn->area;
637         rp->cent[0]= rp->cent[1]= rp->cent[2]= 0.0;
638         fpp= &(rn->v1);
639         for(a=0; a<rp->type; a++) {
640                 rp->cent[0]+= (*fpp)[0];
641                 rp->cent[1]+= (*fpp)[1];
642                 rp->cent[2]+= (*fpp)[2];
643                 fpp++;
644         }
645         rp->cent[0]/=(float)rp->type;
646         rp->cent[1]/=(float)rp->type;
647         rp->cent[2]/=(float)rp->type;
648                 
649         setparelem(rn, rp);
650
651         rn= old->first->down2;
652
653         rp= mallocPatch();
654         *rp= *old;
655         BLI_addhead(&RG.patchbase, rp);
656         rp->first= rn;
657         rp->area= rn->area;
658         rp->cent[0]= rp->cent[1]= rp->cent[2]= 0.0;
659         fpp= &(rn->v1);
660         for(a=0; a<rp->type; a++) {
661                 rp->cent[0]+= (*fpp)[0];
662                 rp->cent[1]+= (*fpp)[1];
663                 rp->cent[2]+= (*fpp)[2];
664                 fpp++;
665         }
666         rp->cent[0]/=(float)rp->type;
667         rp->cent[1]/=(float)rp->type;
668         rp->cent[2]/=(float)rp->type;
669         
670         setparelem(rn, rp);
671
672         BLI_remlink(&RG.patchbase, old);
673         freePatch(old);
674 }
675
676
677 void addpatch(RPatch *old, RNode *rn)
678 {
679         float **fpp;
680         RPatch *rp;
681         int a;
682         
683         if(rn->down1) {
684                 addpatch(old, rn->down1);
685                 addpatch(old, rn->down2);
686         }
687         else {
688                 rp= mallocPatch();
689                 *rp= *old;
690                 BLI_addhead(&RG.patchbase, rp);
691                 rp->first= rn;
692                 
693                 rp->area= rn->area;
694                 rp->cent[0]= rp->cent[1]= rp->cent[2]= 0.0;
695                 fpp= &(rn->v1);
696                 for(a=0; a<rp->type; a++) {
697                         rp->cent[0]+= (*fpp)[0];
698                         rp->cent[1]+= (*fpp)[1];
699                         rp->cent[2]+= (*fpp)[2];
700                         fpp++;
701                 }
702                 rp->cent[0]/=(float)rp->type;
703                 rp->cent[1]/=(float)rp->type;
704                 rp->cent[2]/=(float)rp->type;
705                 
706                 rn->par= rp;
707         }
708 }
709
710 void converttopatches()
711 {
712         /* chacks patches list, if node subdivided: new patch */
713         RPatch *rp, *next;
714         
715         rp= RG.patchbase.first;
716         while(rp) {
717                 next= rp->next;
718                 if(rp->first->down1) {
719                         addpatch(rp, rp->first);
720                         BLI_remlink(&RG.patchbase, rp);
721                         freePatch(rp);
722                 }
723                 rp= next;
724         }
725         
726 }
727
728 void subdiv_elements()
729 {
730         RNode **el, *rn;
731         int a, toobig= 1;
732
733         rad_init_energy();
734         
735         /* first maxsize elements */
736         
737         while(toobig) {
738                 toobig= 0;
739                 
740                 el= RG.elem;
741                 for(a=RG.totelem; a>0; a--, el++) {
742                         rn= *el;
743                         if( rn->totrad[0]==0.0 && rn->totrad[1]==0.0 && rn->totrad[2]==0.0) {
744                                 if(rn->area>RG.elemmin) {
745                                         subdivideNode(rn, 0);
746                                         if(rn->down1 ) {
747                                                 toobig= 1;
748                                                 if(rn->down1->area>RG.elemmin)
749                                                         subdivideNode( rn->down1, 0);
750                                                 if(rn->down2->area>RG.elemmin)
751                                                         subdivideNode( rn->down2, 0);
752                                         }
753                                 }
754                         }
755                 }
756                 if(toobig) makeGlobalElemArray();
757         }
758
759         el= RG.elem;
760         for(a=RG.totelem; a>0; a--, el++) {
761                 rn= *el;
762                 if( rn->totrad[0]==0.0 && rn->totrad[1]==0.0 && rn->totrad[2]==0.0) {
763                         subdivideNode(rn, 0);
764                         if( rn->down1 ) {
765                                 subdivideNode( rn->down1, 0);
766                                 subdivideNode( rn->down2, 0);
767                         }
768                 }
769         }
770         makeGlobalElemArray();
771 }
772
773 void subdividelamps()
774 {
775         RPatch *rp, *next;
776         
777         rp= RG.patchbase.first;
778         while(rp) {
779                 next= rp->next;
780                 if(rp->emit[0]!=0.0 || rp->emit[1]!=0.0 || rp->emit[2]!=0.0) {
781                         subdivideNode( rp->first, 0);
782                         if(rp->first->down1) {
783                                 subdivideNode(rp->first->down1, 0);
784                                 subdivideNode(rp->first->down2, 0);
785                         }
786                         
787                         addpatch(rp, rp->first);
788                         BLI_remlink(&RG.patchbase, rp);
789                         freePatch(rp);
790                 }
791                 rp= next;
792         }
793         
794 }
795
796 void maxsizePatches()
797 {
798         RPatch *rp;
799         int toobig= 1;
800         
801         while(toobig) {
802                 toobig= 0;
803                 rp= RG.patchbase.first;
804                 while(rp) {
805                         if(rp->area>RG.patchmax) {
806                                 subdivideNode( rp->first, 0);
807                                 if(rp->first->down1) toobig= 1;
808                         }
809                         rp= rp->next;
810                 }
811                 
812                 if(toobig) converttopatches();
813         }
814         
815         /* count lamps */
816         rp= RG.patchbase.first;
817         RG.totlamp= 0;
818         while(rp) {
819                 if(rp->emit[0]!=0.0 || rp->emit[1]!=0.0 || rp->emit[2]!=0.0) {
820                         RG.totlamp++;
821                 }
822                 rp= rp->next;
823         }
824         makeGlobalElemArray();
825 }
826
827
828