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