/** * $Id:$ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * The contents of this file may be used under the terms of either the GNU * General Public License Version 2 or later (the "GPL", see * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or * later (the "BL", see http://www.blender.org/BL/ ) which has to be * bought from the Blender Foundation to become active, in which case the * above mentioned GPL option does not apply. * * The Original Code is Copyright (C) 2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ /* *************************************** preproces.c nov/dec 1992 may 1999 - collect from meshes - countglobaldata() - makeGlobalElemArray() *************************************** */ #include "radio.h" int VecCompare(float *v1, float *v2, float limit) { if( fabs(v1[0]-v2[0])first; if((rp->f1 & RAD_NO_SPLIT)==0) { for(a=0; atype; a++) { if(a==0) vnc= (VeNoCo *)rn->v1; else if(a==1) vnc= (VeNoCo *)rn->v2; else if(a==2) vnc= (VeNoCo *)rn->v3; else vnc= (VeNoCo *)rn->v4; if(vnc->flag==0) { vnc->n= (float *)rp->norm; vnc->col= (float *)rp->ref; vnc->flag= 1; } else { /* mag vlak deze vertex gebruiken voor gouraud? */ vnc1= vnc; while(vnc1) { if(VecCompare(vnc1->n, rp->norm, 0.01)) { if(VecCompare(vnc1->col, rp->ref, 0.01)) { break; } } vnc= vnc1; vnc1= vnc1->next; } if(vnc1==0) { vnc1= mallocN(sizeof(VeNoCo), "splitconn"); vnc1->next= 0; vnc1->v= mallocVert(); vnc->next= vnc1; VECCOPY(vnc1->v, vnc->v); vnc1->n= (float *)rp->norm; vnc1->col= (float *)rp->ref; } if(a==0) rn->v1= (float *)vnc1; else if(a==1) rn->v2= (float *)vnc1; else if(a==2) rn->v3= (float *)vnc1; else rn->v4= (float *)vnc1; } } } rp= rp->next; } /* de vertexpointers van nodes aanpassen */ rp= RG.patchbase.first; while(rp) { rn= rp->first; rn->v1= ((VeNoCo *)(rn->v1))->v; rn->v2= ((VeNoCo *)(rn->v2))->v; rn->v3= ((VeNoCo *)(rn->v3))->v; if(rp->type==4) rn->v4= ((VeNoCo *)(rn->v4))->v; rp= rp->next; } /* het hele zaakje vrijgeven */ vnc= RG.verts; for(a=0; anext; while(vnc1) { next= vnc1->next; freeN(vnc1); vnc1= next; } vnc++; } freeN(RG.verts); RG.verts= 0; } int vergedge(const void *v1,const void *v2) { int *e1, *e2; e1= (int *)v1; e2= (int *)v2; if( e1[0] > e2[0] ) return 1; else if( e1[0] < e2[0] ) return -1; else if( e1[1] > e2[1] ) return 1; else if( e1[1] < e2[1] ) return -1; return 0; } void addedge(float *v1, float *v2, EdSort *es) { if( ((long)v1)<((long)v2) ) { es->v1= v1; es->v2= v2; } else { es->v2= v1; es->v1= v2; } } static void setedge(RNode *node, RNode *nb, int nr, int nrb) { switch(nr) { case 1: node->ed1= nb; break; case 2: node->ed2= nb; break; case 3: node->ed3= nb; break; case 4: node->ed4= nb; break; } switch(nrb) { case 1: nb->ed1= node; break; case 2: nb->ed2= node; break; case 3: nb->ed3= node; break; case 4: nb->ed4= node; break; } } void setedgepointers() { /* edge-array maken en sorteren */ /* paren edges staan bij elkaar: pointers invullen in nodes */ EdSort *es, *esblock; RPatch *rp; RNode *rn; int tot= 0; rp= RG.patchbase.first; while(rp) { tot+= rp->type; rp= rp->next; } if(tot==0) return; es=esblock= mallocN(tot*sizeof(EdSort), "setedgepointers"); rp= RG.patchbase.first; while(rp) { rn= rp->first; addedge(rn->v1, rn->v2, es); es->nr= 1; es->node= rn; es++; addedge(rn->v2, rn->v3, es); es->nr= 2; es->node= rn; es++; if(rp->type==3) { addedge(rn->v3, rn->v1, es); es->nr= 3; es->node= rn; es++; } else { addedge(rn->v3, rn->v4, es); es->nr= 3; es->node= rn; es++; addedge(rn->v4, rn->v1, es); es->nr= 4; es->node= rn; es++; } rp= rp->next; } qsort(esblock,tot,sizeof(EdSort),vergedge); es= esblock; while(tot>0) { if( es->v1== (es+1)->v1 ) { if( es->v2== (es+1)->v2 ) { setedge(es->node, (es+1)->node, es->nr, (es+1)->nr); tot--; es++; } } es++; tot--; } freeN(esblock); } void rad_collect_meshes() { extern Material defmaterial; Base *base; Object *ob; Mesh *me; MVert *mvert; MFace *mface; Material *ma; RPatch *rp; RNode *rn; VeNoCo *vnc, **nodevert; float *vd, *v1, *v2, *v3, *v4; int a, b, offs, index; if(G.obedit) { error("Unable to perform function in EditMode"); return; } set_radglobal(); freeAllRad(); start_fastmalloc("Radiosity"); /* count the number of verts */ RG.totvert= 0; RG.totface= 0; base= FIRSTBASE; while(base) { if(TESTBASE(base)) { if(base->object->type==OB_MESH) { base->flag |= OB_RADIO; me= base->object->data; RG.totvert+= me->totvert; } } base= base->next; } if(RG.totvert==0) { error("No vertices"); return; } vnc= RG.verts= callocN(RG.totvert*sizeof(VeNoCo), "readvideoscape1"); RG.min[0]= RG.min[1]= RG.min[2]= 1.0e20; RG.max[0]= RG.max[1]= RG.max[2]= -1.0e20; base= FIRSTBASE; while(base) { if(TESTBASE(base)) { if(base->object->type==OB_MESH) { me= base->object->data; mvert= me->mvert; for(a=0; atotvert; a++, mvert++) { vd= mallocVert(); VECCOPY(vd, mvert->co); Mat4MulVecfl(base->object->obmat, vd); vnc->v= vd; for(b=0; b<3; b++) { RG.min[b]= MIN2(RG.min[b], vd[b]); RG.max[b]= MAX2(RG.max[b], vd[b]); } vnc++; } } } base= base->next; } RG.cent[0]= (RG.min[0]+ RG.max[0])/2; RG.cent[1]= (RG.min[1]+ RG.max[1])/2; RG.cent[2]= (RG.min[2]+ RG.max[2])/2; RG.size[0]= (RG.max[0]- RG.min[0]); RG.size[1]= (RG.max[1]- RG.min[1]); RG.size[2]= (RG.max[2]- RG.min[2]); RG.maxsize= MAX3(RG.size[0],RG.size[1],RG.size[2]); /* make patches */ RG.totelem= 0; RG.totpatch= 0; RG.totlamp= 0; offs= 0; base= FIRSTBASE; while(base) { if(TESTBASE(base)) { if(base->object->type==OB_MESH) { ob= base->object; me= ob->data; mface= me->mface; index= -1; for(a=0; atotface; a++, mface++) { if(mface->v3) { rp= callocPatch(); addtail(&(RG.patchbase), rp); rp->from= ob; if(mface->v4) rp->type= 4; else rp->type= 3; rp->first= rn= callocNode(); if(mface->flag & ME_SMOOTH) rp->f1= RAD_NO_SPLIT; /* temporal: we store the venoco in the node */ rn->v1= (float *)(RG.verts+mface->v1+offs); v1= (RG.verts+mface->v1+offs)->v; rn->v2= (float *)(RG.verts+mface->v2+offs); v2= (RG.verts+mface->v2+offs)->v; rn->v3= (float *)(RG.verts+mface->v3+offs); v3= (RG.verts+mface->v3+offs)->v; if(mface->v4) { rn->v4= (float *)(RG.verts+mface->v4+offs); v4= (RG.verts+mface->v4+offs)->v; } rn->par= rp; rn->f= RAD_PATCH; /* deze node is Patch */ rn->type= rp->type; CalcNormFloat(v1, v2, v3, rp->norm); if(rn->type==4) rp->area= AreaQ3Dfl(v1, v2, v3, v4); else rp->area= AreaT3Dfl(v1, v2, v3); rn->area= rp->area; /* kleur en emit */ if(mface->mat_nr != index) { index= mface->mat_nr; ma= give_current_material(ob, index+1); if(ma==0) ma= &defmaterial; } rp->ref[0]= ma->r; rp->ref[1]= ma->g; rp->ref[2]= ma->b; if(ma->emit) RG.totlamp++; rp->emit[0]= rp->emit[1]= rp->emit[2]= ma->emit; rp->emit[0]*= rp->ref[0]; rp->emit[1]*= rp->ref[1]; rp->emit[2]*= rp->ref[2]; nodevert= (VeNoCo **)&(rn->v1); for(b=0; btype; b++) { rp->cent[0]+= (*nodevert)->v[0]; rp->cent[1]+= (*nodevert)->v[1]; rp->cent[2]+= (*nodevert)->v[2]; nodevert++; } rp->cent[0]/= (float)rp->type; rp->cent[1]/= (float)rp->type; rp->cent[2]/= (float)rp->type; RG.totelem++; RG.totpatch++; } } offs+= me->totvert; } } base= base->next; } splitconnected(); setedgepointers(); makeGlobalElemArray(); pseudoAmb(); rad_setlimits(); } void setparelem(RNode *rn, RPatch *par) { if(rn->down1) { setparelem(rn->down1, par); setparelem(rn->down2, par); } else { rn->par= par; } } void countelem(RNode *rn) { if(rn->down1) { countelem(rn->down1); countelem(rn->down2); } else RG.totelem++; } void countglobaldata() { /* telt aantal elements en patches*/ RPatch *rp; RG.totelem= RG.totpatch= 0; rp= RG.patchbase.first; while(rp) { RG.totpatch++; countelem(rp->first); rp= rp->next; } } void addelem(RNode ***el, RNode *rn, RPatch *rp) { if(rn->down1) { addelem(el, rn->down1, rp); addelem(el, rn->down2, rp); } else { rn->par= rp; **el= rn; (*el)++; } } void makeGlobalElemArray() { /* always called when # of elements change */ RPatch *rp; RNode **el; countglobaldata(); if(RG.elem) freeN(RG.elem); if(RG.totelem) { el= RG.elem= mallocN(sizeof(void *)*RG.totelem, "makeGlobalElemArray"); } else { RG.elem= 0; return; } /* recursief elements toevoegen */ rp= RG.patchbase.first; while(rp) { addelem(&el, rp->first, rp); rp= rp->next; } /* formfactor array */ if(RG.formfactors) freeN(RG.formfactors); if(RG.totelem) RG.formfactors= mallocN(sizeof(float)*RG.totelem, "formfactors"); else RG.formfactors= 0; } void splitpatch(RPatch *old) /* bij overflow gedurende shoot */ { RNode *rn; float **fpp; RPatch *rp; int a; rn= old->first; if(rn->down1==0) return; rn= rn->down1; old->unshot[0]/=2.0; old->unshot[1]/=2.0; old->unshot[2]/=2.0; setnodeflags(old->first, 2, 0); rp= mallocPatch(); *rp= *old; addhead(&RG.patchbase, rp); rp->first= rn; rp->area= rn->area; rp->cent[0]= rp->cent[1]= rp->cent[2]= 0.0; fpp= &(rn->v1); for(a=0; atype; a++) { rp->cent[0]+= (*fpp)[0]; rp->cent[1]+= (*fpp)[1]; rp->cent[2]+= (*fpp)[2]; fpp++; } rp->cent[0]/=(float)rp->type; rp->cent[1]/=(float)rp->type; rp->cent[2]/=(float)rp->type; setparelem(rn, rp); rn= old->first->down2; rp= mallocPatch(); *rp= *old; addhead(&RG.patchbase, rp); rp->first= rn; rp->area= rn->area; rp->cent[0]= rp->cent[1]= rp->cent[2]= 0.0; fpp= &(rn->v1); for(a=0; atype; a++) { rp->cent[0]+= (*fpp)[0]; rp->cent[1]+= (*fpp)[1]; rp->cent[2]+= (*fpp)[2]; fpp++; } rp->cent[0]/=(float)rp->type; rp->cent[1]/=(float)rp->type; rp->cent[2]/=(float)rp->type; setparelem(rn, rp); remlink(&RG.patchbase, old); freePatch(old); } void addpatch(RPatch *old, RNode *rn) { float **fpp; RPatch *rp; int a; if(rn->down1) { addpatch(old, rn->down1); addpatch(old, rn->down2); } else { rp= mallocPatch(); *rp= *old; addhead(&RG.patchbase, rp); rp->first= rn; rp->area= rn->area; rp->cent[0]= rp->cent[1]= rp->cent[2]= 0.0; fpp= &(rn->v1); for(a=0; atype; a++) { rp->cent[0]+= (*fpp)[0]; rp->cent[1]+= (*fpp)[1]; rp->cent[2]+= (*fpp)[2]; fpp++; } rp->cent[0]/=(float)rp->type; rp->cent[1]/=(float)rp->type; rp->cent[2]/=(float)rp->type; rn->par= rp; } } void converttopatches() { /* loopt patcheslijst af, als node gesubdivided: nieuwe patch */ RPatch *rp, *next; rp= RG.patchbase.first; while(rp) { next= rp->next; if(rp->first->down1) { addpatch(rp, rp->first); remlink(&RG.patchbase, rp); freePatch(rp); } rp= next; } } void subdiv_elements() { RNode **el, *rn; int a, toobig= 1; rad_init_energy(); /* eerst maxsize elements */ while(toobig) { toobig= 0; el= RG.elem; for(a=RG.totelem; a>0; a--, el++) { rn= *el; if( rn->totrad[0]==0.0 && rn->totrad[1]==0.0 && rn->totrad[2]==0.0) { if(rn->area>RG.elemmin) { subdivideNode(rn, 0); if(rn->down1 ) { toobig= 1; if(rn->down1->area>RG.elemmin) subdivideNode( rn->down1, 0); if(rn->down2->area>RG.elemmin) subdivideNode( rn->down2, 0); } } } } if(toobig) makeGlobalElemArray(); } el= RG.elem; for(a=RG.totelem; a>0; a--, el++) { rn= *el; if( rn->totrad[0]==0.0 && rn->totrad[1]==0.0 && rn->totrad[2]==0.0) { subdivideNode(rn, 0); if( rn->down1 ) { subdivideNode( rn->down1, 0); subdivideNode( rn->down2, 0); } } } makeGlobalElemArray(); } void subdividelamps() { RPatch *rp, *next; rp= RG.patchbase.first; while(rp) { next= rp->next; if(rp->emit[0]!=0.0 || rp->emit[1]!=0.0 || rp->emit[2]!=0.0) { subdivideNode( rp->first, 0); if(rp->first->down1) { subdivideNode(rp->first->down1, 0); subdivideNode(rp->first->down2, 0); } addpatch(rp, rp->first); remlink(&RG.patchbase, rp); freePatch(rp); } rp= next; } } void maxsizePatches() { RPatch *rp; int toobig= 1; while(toobig) { toobig= 0; rp= RG.patchbase.first; while(rp) { if(rp->area>RG.patchmax) { subdivideNode( rp->first, 0); if(rp->first->down1) toobig= 1; } rp= rp->next; } if(toobig) converttopatches(); } /* aantal lampen tellen */ rp= RG.patchbase.first; RG.totlamp= 0; while(rp) { if(rp->emit[0]!=0.0 || rp->emit[1]!=0.0 || rp->emit[2]!=0.0) { RG.totlamp++; } rp= rp->next; } makeGlobalElemArray(); }