2.5: globals cleanup
[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(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         if(G.obedit) {
318                 if (!during_script()); //XXX  error("Unable to perform function in EditMode");
319                 return;
320         }
321
322         set_radglobal();
323
324         freeAllRad();
325
326         start_fastmalloc("Radiosity");
327                                         
328         /* count the number of verts */
329         RG.totvert= 0;
330         RG.totface= 0;
331         base= (G.scene->base.first);
332         while(base) {
333                 if(((base)->flag & SELECT) && ((base)->lay & v3d->lay) ) {
334                         if(base->object->type==OB_MESH) {
335                                 base->flag |= OB_RADIO;
336                                 me= base->object->data;
337                                 RG.totvert+= me->totvert;
338                         }
339                 }
340                 base= base->next;
341         }
342         if(RG.totvert==0) {
343                 if (!during_script()); //XXX error("No vertices");
344                 return;
345         }
346         vnc= RG.verts= MEM_callocN(RG.totvert*sizeof(VeNoCo), "radioverts");
347
348         RG.min[0]= RG.min[1]= RG.min[2]= 1.0e20f;
349         RG.max[0]= RG.max[1]= RG.max[2]= -1.0e20f;
350
351         mfdatatot= 0;
352         
353         /* min-max and material array */
354         base= (G.scene->base.first);
355         while(base) {
356                 if( ((base)->flag & SELECT) && ((base)->lay & v3d->lay) ) {
357                         if(base->object->type==OB_MESH) {
358                                 me= base->object->data;
359                                 mvert= me->mvert;
360                                 for(a=0; a<me->totvert; a++, mvert++) {
361                                         vd= mallocVert();
362                                         VECCOPY(vd, mvert->co);
363                                         /* Should make MTC its own module... */
364                                         Mat4MulVecfl(base->object->obmat, vd);
365                                         
366                                         vnc->v= vd;
367                                         for(b=0; b<3; b++) {
368                                                 RG.min[b]= MIN2(RG.min[b], vd[b]);
369                                                 RG.max[b]= MAX2(RG.max[b], vd[b]);
370                                         }
371                                         vnc++;
372                                 }
373                                 
374                                 if(base->object->totcol==0) {
375                                         if(RG.totmat<MAXMAT) {
376                                                 if(noma==NULL) {
377                                                         noma= add_material("RadioMat");
378                                                         RG.matar[RG.totmat]= noma;
379                                                         RG.totmat++;
380                                                 }
381                                         }
382                                 }
383                                 else {
384                                         for(a=0; a<base->object->totcol; a++) {
385                                                 if(RG.totmat >= MAXMAT) break;
386
387                                                 ma = give_current_material(base->object, a+1);
388
389                                                 if (materialIndex(ma)!=-1) break;
390
391                                                 RG.matar[RG.totmat]= ma;
392                                                 RG.totmat++;
393                                         }
394                                 }
395
396                                 mfdatatot += me->totface;
397                         }
398                 }
399                 base= base->next;
400         }
401
402         RG.cent[0]= (RG.min[0]+ RG.max[0])/2;
403         RG.cent[1]= (RG.min[1]+ RG.max[1])/2;
404         RG.cent[2]= (RG.min[2]+ RG.max[2])/2;
405         RG.size[0]= (RG.max[0]- RG.min[0]);
406         RG.size[1]= (RG.max[1]- RG.min[1]);
407         RG.size[2]= (RG.max[2]- RG.min[2]);
408         RG.maxsize= MAX3(RG.size[0],RG.size[1],RG.size[2]);
409
410         RG.mfdata= MEM_callocN(sizeof(CustomData), "radiomfdata");
411         RG.mfdatanodes= MEM_mallocN(sizeof(RNode*)*mfdatatot, "radiomfdatanodes");
412         RG.mfdatatot= mfdatatot;
413
414         /* make patches */
415
416         RG.totelem= 0;
417         RG.totpatch= 0;
418         RG.totlamp= 0;
419         offs= 0;
420         
421         base= (G.scene->base.first);
422         while(base) {
423                 if( ((base)->flag & SELECT) && ((base)->lay & v3d->lay) )  {
424                         if(base->object->type==OB_MESH) {
425                                 ob= base->object;
426                                 me= ob->data;
427                                 mface= me->mface;
428                                 tface= me->mtface;
429                                 
430                                 index= -1;
431
432                                 CustomData_merge(&me->fdata, RG.mfdata, CD_MASK_DERIVEDMESH,
433                                         CD_DEFAULT, mfdatatot);
434                                 
435                                 for(a=0; a<me->totface; a++, mface++) {
436                                         tf= tface? tface+a: NULL;
437                                         
438                                         if (tf && (tf->mode & TF_INVISIBLE))
439                                                 continue;
440
441                                         rp= callocPatch();
442                                         BLI_addtail(&(RG.patchbase), rp);
443                                         rp->from= ob;
444                                         
445                                         if(mface->v4) rp->type= 4;
446                                         else rp->type= 3;
447                                         
448                                         rp->first= rn= callocNode();
449                                         
450                                         if(mface->flag & ME_SMOOTH) rp->f1= RAD_NO_SPLIT;
451                                         
452                                         /* temporal: we store the venoco in the node */
453                                         rn->v1= (float *)(RG.verts+mface->v1+offs);
454                                         v1= (RG.verts+mface->v1+offs)->v;
455                                         rn->v2= (float *)(RG.verts+mface->v2+offs);
456                                         v2= (RG.verts+mface->v2+offs)->v;
457                                         rn->v3= (float *)(RG.verts+mface->v3+offs);
458                                         v3= (RG.verts+mface->v3+offs)->v;
459
460                                         if(mface->v4) {
461                                                 rn->v4= (float *)(RG.verts+mface->v4+offs);
462                                                 v4= (RG.verts+mface->v4+offs)->v;
463                                         }                       
464                                         rn->par= rp;
465                                         rn->f= RAD_PATCH;       /* this node is a Patch */
466                                         rn->type= rp->type;
467
468                                         if(rn->type==4) {
469                                                 rp->area= AreaQ3Dfl(v1, v2, v3, v4);
470                                                 CalcNormFloat4(v1, v2, v3, v4, rp->norm);
471                                         }
472                                         else {
473                                                 rp->area= AreaT3Dfl(v1, v2, v3);
474                                                 CalcNormFloat(v1, v2, v3, rp->norm);
475                                         }
476
477                                         rn->area= rp->area;
478
479                                         /* color and emit */
480                                         if(mface->mat_nr != index) {
481                                                 index= mface->mat_nr;
482                                                 ma= give_current_material(ob, index+1);
483                                                 if(ma==0) ma= &defmaterial;
484                                         }
485                                         rp->ref[0]= ma->r;
486                                         rp->ref[1]= ma->g;
487                                         rp->ref[2]= ma->b;
488
489                                         if(ma->emit) RG.totlamp++;
490
491                                         rp->emit[0]= rp->emit[1]= rp->emit[2]= ma->emit;
492                                         rp->emit[0]*= rp->ref[0];
493                                         rp->emit[1]*= rp->ref[1];
494                                         rp->emit[2]*= rp->ref[2];
495
496 // uncommented, this is not satisfying, but i leave it in code for now (ton)                                            
497 //                                              if(ma->translucency!=0.0) rn->f |= RAD_TWOSIDED;
498
499                                         nodevert= (VeNoCo **)&(rn->v1);
500                                         for(b=0; b<rp->type; b++) {
501                                                 rp->cent[0]+= (*nodevert)->v[0];
502                                                 rp->cent[1]+= (*nodevert)->v[1];
503                                                 rp->cent[2]+= (*nodevert)->v[2];
504                                                 nodevert++;
505                                         }
506                                         rp->cent[0]/= (float)rp->type;
507                                         rp->cent[1]/= (float)rp->type;
508                                         rp->cent[2]/= (float)rp->type;
509                                         
510                                         /* for reconstruction materials */
511                                         rp->matindex= materialIndex(ma);
512                                         if(rp->matindex==-1) rp->matindex= 1;
513
514                                         /* these RNode's are stored now for later use in rad_addmesh
515                                            they should not get deleted before that */
516                                         rn->orig= RG.totelem;
517                                         RG.mfdatanodes[RG.totelem]= rn;
518
519                                         CustomData_copy_data(&me->fdata, RG.mfdata, a, RG.totelem, 1);
520                                         
521                                         RG.totelem++;
522                                         RG.totpatch++;
523                                 }
524
525                                 offs+= me->totvert;
526                         }
527                 }
528                 base= base->next;
529         }
530         
531         splitconnected();
532         setedgepointers();
533
534         makeGlobalElemArray();
535         pseudoAmb();
536         rad_setlimits();
537 }
538
539 void setparelem(RNode *rn, RPatch *par)
540 {
541         
542         if(rn->down1) {
543                 setparelem(rn->down1, par);
544                 setparelem(rn->down2, par);
545         }
546         else {
547                 rn->par= par;
548         }
549 }
550
551 void countelem(RNode *rn)
552 {
553
554         if(rn->down1) {
555                 countelem(rn->down1);
556                 countelem(rn->down2);
557         }
558         else RG.totelem++;
559 }
560
561 void countglobaldata()
562 {
563         /* counts elements and patches*/
564         RPatch *rp;
565
566         RG.totelem= RG.totpatch= 0;
567
568         rp= RG.patchbase.first;
569         while(rp) {
570                 RG.totpatch++;
571                 countelem(rp->first);
572                 rp= rp->next;
573         }
574 }
575
576 void addelem(RNode ***el, RNode *rn, RPatch *rp)
577 {
578         if(rn->down1) {
579                 addelem(el, rn->down1, rp);
580                 addelem(el, rn->down2, rp);
581         }
582         else {
583                 rn->par= rp;
584                 **el= rn;
585                 (*el)++;
586         }
587 }
588
589 void makeGlobalElemArray()
590 {
591         /* always called when # of elements change */
592         RPatch *rp;
593         RNode **el;
594
595         countglobaldata();
596
597         if(RG.elem) MEM_freeN(RG.elem);
598         if(RG.totelem) {
599                 el= RG.elem= MEM_mallocN(sizeof(void *)*RG.totelem, "makeGlobalElemArray");
600         }
601         else {
602                 RG.elem= 0;
603                 return;
604         }
605
606         /* recursive adding elements */
607         rp= RG.patchbase.first;
608         while(rp) {
609                 addelem(&el, rp->first, rp);
610                 rp= rp->next;
611         }
612
613         /* formfactor array */
614         if(RG.formfactors) MEM_freeN(RG.formfactors);
615         if(RG.totelem)
616                 RG.formfactors= MEM_mallocN(sizeof(float)*RG.totelem, "formfactors");
617         else
618                 RG.formfactors= 0;
619 }
620
621 void splitpatch(RPatch *old)            /* in case of overflow during shoot */
622 {
623         RNode *rn;
624         float **fpp;
625         RPatch *rp;
626         int a;
627         
628         rn= old->first;
629         if(rn->down1==0) return;
630         rn= rn->down1;
631
632         old->unshot[0]/=2.0;
633         old->unshot[1]/=2.0;
634         old->unshot[2]/=2.0;
635         setnodeflags(old->first, 2, 0);
636
637         rp= mallocPatch();
638         *rp= *old;
639         BLI_addhead(&RG.patchbase, rp);
640         rp->first= rn;
641         rp->area= rn->area;
642         rp->cent[0]= rp->cent[1]= rp->cent[2]= 0.0;
643         fpp= &(rn->v1);
644         for(a=0; a<rp->type; a++) {
645                 rp->cent[0]+= (*fpp)[0];
646                 rp->cent[1]+= (*fpp)[1];
647                 rp->cent[2]+= (*fpp)[2];
648                 fpp++;
649         }
650         rp->cent[0]/=(float)rp->type;
651         rp->cent[1]/=(float)rp->type;
652         rp->cent[2]/=(float)rp->type;
653                 
654         setparelem(rn, rp);
655
656         rn= old->first->down2;
657
658         rp= mallocPatch();
659         *rp= *old;
660         BLI_addhead(&RG.patchbase, rp);
661         rp->first= rn;
662         rp->area= rn->area;
663         rp->cent[0]= rp->cent[1]= rp->cent[2]= 0.0;
664         fpp= &(rn->v1);
665         for(a=0; a<rp->type; a++) {
666                 rp->cent[0]+= (*fpp)[0];
667                 rp->cent[1]+= (*fpp)[1];
668                 rp->cent[2]+= (*fpp)[2];
669                 fpp++;
670         }
671         rp->cent[0]/=(float)rp->type;
672         rp->cent[1]/=(float)rp->type;
673         rp->cent[2]/=(float)rp->type;
674         
675         setparelem(rn, rp);
676
677         BLI_remlink(&RG.patchbase, old);
678         freePatch(old);
679 }
680
681
682 void addpatch(RPatch *old, RNode *rn)
683 {
684         float **fpp;
685         RPatch *rp;
686         int a;
687         
688         if(rn->down1) {
689                 addpatch(old, rn->down1);
690                 addpatch(old, rn->down2);
691         }
692         else {
693                 rp= mallocPatch();
694                 *rp= *old;
695                 BLI_addhead(&RG.patchbase, rp);
696                 rp->first= rn;
697                 
698                 rp->area= rn->area;
699                 rp->cent[0]= rp->cent[1]= rp->cent[2]= 0.0;
700                 fpp= &(rn->v1);
701                 for(a=0; a<rp->type; a++) {
702                         rp->cent[0]+= (*fpp)[0];
703                         rp->cent[1]+= (*fpp)[1];
704                         rp->cent[2]+= (*fpp)[2];
705                         fpp++;
706                 }
707                 rp->cent[0]/=(float)rp->type;
708                 rp->cent[1]/=(float)rp->type;
709                 rp->cent[2]/=(float)rp->type;
710                 
711                 rn->par= rp;
712         }
713 }
714
715 void converttopatches()
716 {
717         /* chacks patches list, if node subdivided: new patch */
718         RPatch *rp, *next;
719         
720         rp= RG.patchbase.first;
721         while(rp) {
722                 next= rp->next;
723                 if(rp->first->down1) {
724                         addpatch(rp, rp->first);
725                         BLI_remlink(&RG.patchbase, rp);
726                         freePatch(rp);
727                 }
728                 rp= next;
729         }
730         
731 }
732
733 void subdiv_elements()
734 {
735         RNode **el, *rn;
736         int a, toobig= 1;
737
738         rad_init_energy();
739         
740         /* first maxsize elements */
741         
742         while(toobig) {
743                 toobig= 0;
744                 
745                 el= RG.elem;
746                 for(a=RG.totelem; a>0; a--, el++) {
747                         rn= *el;
748                         if( rn->totrad[0]==0.0 && rn->totrad[1]==0.0 && rn->totrad[2]==0.0) {
749                                 if(rn->area>RG.elemmin) {
750                                         subdivideNode(rn, 0);
751                                         if(rn->down1 ) {
752                                                 toobig= 1;
753                                                 if(rn->down1->area>RG.elemmin)
754                                                         subdivideNode( rn->down1, 0);
755                                                 if(rn->down2->area>RG.elemmin)
756                                                         subdivideNode( rn->down2, 0);
757                                         }
758                                 }
759                         }
760                 }
761                 if(toobig) makeGlobalElemArray();
762         }
763
764         el= RG.elem;
765         for(a=RG.totelem; a>0; a--, el++) {
766                 rn= *el;
767                 if( rn->totrad[0]==0.0 && rn->totrad[1]==0.0 && rn->totrad[2]==0.0) {
768                         subdivideNode(rn, 0);
769                         if( rn->down1 ) {
770                                 subdivideNode( rn->down1, 0);
771                                 subdivideNode( rn->down2, 0);
772                         }
773                 }
774         }
775         makeGlobalElemArray();
776 }
777
778 void subdividelamps()
779 {
780         RPatch *rp, *next;
781         
782         rp= RG.patchbase.first;
783         while(rp) {
784                 next= rp->next;
785                 if(rp->emit[0]!=0.0 || rp->emit[1]!=0.0 || rp->emit[2]!=0.0) {
786                         subdivideNode( rp->first, 0);
787                         if(rp->first->down1) {
788                                 subdivideNode(rp->first->down1, 0);
789                                 subdivideNode(rp->first->down2, 0);
790                         }
791                         
792                         addpatch(rp, rp->first);
793                         BLI_remlink(&RG.patchbase, rp);
794                         freePatch(rp);
795                 }
796                 rp= next;
797         }
798         
799 }
800
801 void maxsizePatches()
802 {
803         RPatch *rp;
804         int toobig= 1;
805         
806         while(toobig) {
807                 toobig= 0;
808                 rp= RG.patchbase.first;
809                 while(rp) {
810                         if(rp->area>RG.patchmax) {
811                                 subdivideNode( rp->first, 0);
812                                 if(rp->first->down1) toobig= 1;
813                         }
814                         rp= rp->next;
815                 }
816                 
817                 if(toobig) converttopatches();
818         }
819         
820         /* count lamps */
821         rp= RG.patchbase.first;
822         RG.totlamp= 0;
823         while(rp) {
824                 if(rp->emit[0]!=0.0 || rp->emit[1]!=0.0 || rp->emit[2]!=0.0) {
825                         RG.totlamp++;
826                 }
827                 rp= rp->next;
828         }
829         makeGlobalElemArray();
830 }
831
832
833