/** * $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 ***** */ /* shadbuf.c RENDER * * april 95 * */ #include "blender.h" #include "render.h" float jitshad[32][2]; short filt3[9]= { 1,2,1,2,4,2,1,2,1 }; long bias= 0x00500000; void lrectreadRectz(x1,y1,x2,y2,r1) /* leest deel uit rectz in r1 */ ulong x1,y1,x2,y2; char *r1; { ulong len4,*rz; if(x1>=R.rectx || x2>=R.rectx || y1>=R.recty || y2>=R.recty) return; if(x1>x2 || y1>y2) return; len4= 4*(x2- x1+1); rz= R.rectz+R.rectx*y1+x1; for(;y1<=y2;y1++) { memcpy(r1,rz,len4); rz+= R.rectx; r1+= len4; } } void initshadowbuf(lar, la, mat) struct LampRen *lar; struct Lamp *la; float mat[][4]; /* transf.matrix van lamp */ { struct ShadBuf *shb; float hoek, dist, temp, viewinv[4][4]; short v; /* if(la->spsi<16) return; */ /* geheugen reserveren */ shb= (struct ShadBuf *)callocN( sizeof(struct ShadBuf),"initshadbuf"); lar->shb= shb; if(shb==0) return; VECCOPY(shb->co, lar->co); /* percentage: min en max in de gaten houden */ shb->size= (la->bufsize*R.r.size)/100; if(shb->size<512) shb->size= 512; else if(shb->size > la->bufsize) shb->size= la->bufsize; shb->samp= la->samp; shb->soft= la->soft; shb->zbuf= (ulong *)mallocN( (shb->size*shb->size)/64,"initshadbuf2"); shb->cbuf= (char *)callocN( (shb->size*shb->size)/256,"initshadbuf3"); if(shb->zbuf==0 || shb->cbuf==0) { if(shb->zbuf) freeN(shb->zbuf); freeN(lar->shb); lar->shb= 0; return; } Mat4Ortho(mat); Mat4Invert(shb->winmat, mat); /* winmat is hier temp */ /* matrix: combinatie van inverse view en lampmat */ /* opnieuw berekenen: de ortho-render heeft geen correcte viewinv */ Mat4Invert(viewinv, R.viewmat); Mat4MulMat4(shb->persmat, viewinv, shb->winmat); /* projektie */ hoek= facos(lar->spotsi); temp= 0.5*shb->size*fcos(hoek)/fsin(hoek); shb->d= la->clipsta; shb->pixsize= (shb->d)/temp; shb->far= la->clipend; /* bias is percentage, 2x groter gemaakt ivm invalshoek correctie */ shb->bias= (0.02*la->bias)*0x7FFFFFFF; shb->bias= shb->bias*(100/R.r.size); } long sizeoflampbuf(shb) struct ShadBuf *shb; { long num,count=0; char *cp; cp= shb->cbuf; num= (shb->size*shb->size)/256; while(num--) count+= *(cp++); return 256*count; } void makeshadowbuf(LampRen *lar) { struct ShadBuf *shb= lar->shb; extern float panophi; void projectvert(); struct VlakRen *vlr; float temp, wsize, wd, dist; float winmat[4][4], vec[3]; ulong *rz,*rz1,verg,*ztile,verg1; long a,x,y,xof,yof,win,v,minx,miny,byt1,byt2; short temprx,tempry; char *rc,*rcline,*ctile,*zt; /* viewvars onthouden */ temprx= R.rectx; tempry= R.recty; R.rectx= R.recty= shb->size; initjit(shb->jit,shb->samp*shb->samp); /* matrices en window: in R.winmat komt transformatie van obsview naar lampview, inclusief lampwinmat */ wsize= shb->pixsize*(shb->size/2.0); i_window(-wsize, wsize, -wsize, wsize, shb->d, shb->far, winmat); Mat4SwapMat4(shb->winmat, R.winmat); Mat4MulMat4(R.winmat, shb->persmat, winmat); /* zbufferen */ if(R.rectz) freeN(R.rectz); R.rectz= (ulong *)mallocN(4*shb->size*shb->size,"makeshadbuf"); rcline= mallocN(256*4+4,"makeshadbuf2"); /* onthouden: panorama rot */ temp= panophi; panophi= 0.0; setzbufvlaggen(projectvert); panophi= temp; zbuffershad(lar); /* #include */ /* noborder();prefposition(0, R.rectx-1, 0, R.rectx-1); */ /* win= winopen("test"); RGBmode(); singlebuffer(); */ /* gconfig(); */ /* lrectwrite(0, 0, R.rectx-1, R.rectx-1, R.rectz); */ /* while(getbutton(LEFTMOUSE)); */ /* while(getbutton(LEFTMOUSE)==0); */ /* winclose(win); */ /* alle pixels 1 x ingevuld verwijderen (oneven) */ /* probleem hierbij kan geven dat er abrupte overgangen van zacht gebied * naar geen zacht gebied is: bijv als eronder een klein vlakje zit * DAAROM (voorlopig?) ER WEER UIT * a= shb->size*shb->size; rz= R.rectz; while(a--) { if(*rz & 1) *rz= 0x7FFFFFFF; rz++; } */ /* Z tiles aanmaken */ ztile= shb->zbuf; ctile= shb->cbuf; for(y=0;ysize;y+=16) { for(x=0;xsize;x+=16) { /* ligt rechthoek binnen spotbundel? */ a= shb->size/2; if(x< a) minx= x+15-a; else minx= x-a; if(y< a) miny= y+15-a; else miny= y-a; dist= fsqrt( (float)(minx*minx+miny*miny) ); if(dist>(float)(a+1)) { /* randjes willen wel 'ns mis gaan */ a= 256; verg= 0x80000000; /* 0x7FFFFFFF; */ rz1= (&verg)+1; } else { lrectreadRectz(x,y,MIN2(shb->size-1,x+15),MIN2(shb->size-1,y+15),rcline); rz1= (ulong *)rcline; verg= (*rz1 & 0xFFFFFF00); for(a=0;a<256;a++,rz1++) { if( (*rz1 & 0xFFFFFF00) !=verg) break; } } if(a==256) { /* compleet leeg vakje */ *ctile= 0; *ztile= *(rz1-1); } else { rc= rcline; rz1= (ulong *)rcline; verg= rc[0]; verg1= rc[1]; rc+=4; byt1= 1; byt2= 1; for(a=1;a<256;a++,rc+=4) { byt1&= (verg==rc[0]); byt2&= (verg1==rc[1]); if(byt1==0) break; } if(byt1 && byt2) { /* alleen byte opslaan */ *ctile= 1; *ztile= (ulong)mallocN(256+4,"tile1"); rz= (ulong *)*ztile; *rz= *rz1; zt= (char *)(rz+1); rc= rcline+2; for(a=0;a<256;a++,zt++,rc+=4) *zt= *rc; } else if(byt1) { /* short opslaan */ *ctile= 2; *ztile= (ulong)mallocN(2*256+4,"Tile2"); rz= (ulong *)*ztile; *rz= *rz1; zt= (char *)(rz+1); rc= rcline+1; for(a=0;a<256;a++,zt+=2,rc+=4) { zt[0]= rc[0]; zt[1]= rc[1]; } } else { /* triple opslaan */ *ctile= 3; *ztile= (ulong)mallocN(3*256,"Tile3"); zt= (char *)*ztile; rc= rcline; for(a=0;a<256;a++,zt+=3,rc+=4) { zt[0]= rc[0]; zt[1]= rc[1]; zt[2]= rc[2]; } } } ztile++; ctile++; } } freeN(rcline); freeN(R.rectz); R.rectz= 0; R.rectx= temprx; R.recty= tempry; Mat4SwapMat4(shb->winmat, R.winmat); /* printf("lampbuf %d\n", sizeoflampbuf(shb)); */ } short firstreadshadbuf(shb,xs,ys,nr) struct ShadBuf *shb; long xs,ys,nr; { /* return 1 als volledig gecomprimeerde shadbuftile && z==const */ static long zsamp; long ofs; register char *ct; if(xs<0 || ys<0) return 0; if(xs>=shb->size || ys>=shb->size) return 0; /* z berekenen */ ofs= (ys>>4)*(shb->size>>4) + (xs>>4); ct= shb->cbuf+ofs; if(*ct==0) { if(nr==0) { zsamp= *( (long *)(shb->zbuf+ofs) ); return 1; } else if(zsamp!= *( (long *)(shb->zbuf+ofs) )) return 0; return 1; } return 0; } float readshadowbuf(shb,xs,ys,zs) /* return 1.0 : volledig schaduw */ struct ShadBuf *shb; long xs,ys,zs; { float temp; long *rz,ofs,zsamp; register char *ct,*cz; /* simpleclip */ if(xs<0 || ys<0) return 1.0; if(xs>=shb->size || ys>=shb->size) return 1.0; /* z berekenen */ ofs= (ys>>4)*(shb->size>>4) + (xs>>4); ct= shb->cbuf+ofs; zsamp= *( (long *)(shb->zbuf+ofs) ); if(*ct==3) { ct= ((char *)zsamp)+3*16*(ys & 15)+3*(xs & 15); cz= (char *)&zsamp; cz[0]= ct[0]; cz[1]= ct[1]; cz[2]= ct[2]; } else if(*ct==2) { ct= ((char *)zsamp); zsamp= *(long *)ct; ct+= 4+2*16*(ys & 15)+2*(xs & 15); cz= (char *)&zsamp; cz[1]= ct[0]; cz[2]= ct[1]; } else if(*ct==1) { ct= ((char *)zsamp); zsamp= *(long *)ct; ct+= 4+16*(ys & 15)+(xs & 15); cz= (char *)&zsamp; cz[2]= ct[0]; } /* if(zsamp >= 0x7FFFFE00) return 0.0; */ /* geen schaduw als op oneindig wordt gesampeld*/ if(zsamp > zs) return 0.0; /* absoluut geen schaduw */ else if( zsamp < zs-bias) return 1.0 ; /* absoluut wel schaduw */ else { /* zacht gebied */ temp= ( (float)(zs- zsamp) )/(float)bias; return temp*temp; } } float testshadowbuf(struct ShadBuf *shb, float inp) /* return 1.0: geen schaduw */ { float fac, co[4], dx[3], dy[3], vec[3], aantal=0; float xs1,ys1, siz, *j, xres, yres; long xs,ys, zs; short a,num; if(inp <= 0.0) return 1.0; /* renderco en osaco roteren */ siz= 0.5*(float)shb->size; VECCOPY(co, R.co); co[3]= 1.0; Mat4MulVec4fl(shb->winmat, co); /* rationele hom co */ xs1= siz*(1.0+co[0]/co[3]); ys1= siz*(1.0+co[1]/co[3]); /* clip op z */ fac= (co[2]/co[3]); if(fac>=1.0) return 0.0; else if(fac<= -1.0) return 1.0; zs= ((float)0x7FFFFFFF)*fac; /* num*num samples nemen, gebied met fac vergroten */ num= shb->samp*shb->samp; fac= shb->soft; bias= (1.1-inp*inp)*shb->bias; if(num==1) return 1.0- readshadowbuf(shb,(long)xs1,(long)ys1,zs); co[0]= R.co[0]+O.dxco[0]; co[1]= R.co[1]+O.dxco[1]; co[2]= R.co[2]+O.dxco[2]; co[3]= 1.0; Mat4MulVec4fl(shb->winmat,co); /* rationele hom co */ dx[0]= xs1- siz*(1.0+co[0]/co[3]); dx[1]= ys1- siz*(1.0+co[1]/co[3]); co[0]= R.co[0]+O.dyco[0]; co[1]= R.co[1]+O.dyco[1]; co[2]= R.co[2]+O.dyco[2]; co[3]= 1.0; Mat4MulVec4fl(shb->winmat,co); /* rationele hom co */ dy[0]= xs1- siz*(1.0+co[0]/co[3]); dy[1]= ys1- siz*(1.0+co[1]/co[3]); xres= fac*( fabs(dx[0])+fabs(dy[0]) ); yres= fac*( fabs(dx[1])+fabs(dy[1]) ); if(xresjit[0]; if(xres<16.0 && yres<16.0) { if(firstreadshadbuf(shb, (long)xs1, (long)ys1, 0)) { if(firstreadshadbuf(shb, (long)(xs1+xres), (long)ys1, 1)) { if(firstreadshadbuf(shb, (long)xs1, (long)(ys1+yres), 1)) { if(firstreadshadbuf(shb, (long)(xs1+xres), (long)(ys1+yres), 1)) { return 1.0- readshadowbuf(shb,(long)xs1,(long)ys1,zs); } } } } } for(a=num;a>0;a--) { /* i.p.v. jit ook met random geprobeerd: lelijk! */ xs= xs1 + xres*j[0]; ys= ys1 + yres*j[1]; j+=2; aantal+= readshadowbuf(shb,xs,ys,zs); } return 1.0- aantal/( (float)(num) ); } float testshadowbufo(shb) struct ShadBuf *shb; { float fac,co[4],dx[3],dy[3],vec[3],aantal=0; float xs1,ys1,siz,*j,xres,yres; long xs,ys,zs,zs1; short a,b,n,tel=0; /* renderco en osaco roteren */ VECCOPY(co,R.co); co[3]= 1.0; Mat4MulVec4fl(shb->winmat,co); /* rationele hom co */ xs1= ((0.5*(float)shb->size)*(1.0+co[0]/co[3])); ys1= ((0.5*(float)shb->size)*(1.0+co[1]/co[3])); /* clip op z */ fac= (co[2]/co[3]); if(fac>=1.0) return 0.0; else if(fac<=0.0) return 1.0; zs1= 0x7FFFFFFF*fac; /* n*n samples nemen, gebied met fac vergroten */ n= shb->samp; fac= shb->soft; bias= shb->bias; if(n==1) return 1.0- readshadowbuf(shb,(long)xs1,(long)ys1,zs1); co[0]= R.co[0]+O.dxco[0]; co[1]= R.co[1]+O.dxco[1]; co[2]= R.co[2]+O.dxco[2]; co[3]= 1.0; Mat4MulVec4fl(shb->winmat,co); /* rationele hom co */ dx[0]= xs1-((0.5*(float)shb->size)*(1.0+co[0]/co[3])); dx[1]= ys1-((0.5*(float)shb->size)*(1.0+co[1]/co[3])); dx[2]= zs1 -0x7FFFFFFF*(co[2]/co[3]); co[0]= R.co[0]+O.dyco[0]; co[1]= R.co[1]+O.dyco[1]; co[2]= R.co[2]+O.dyco[2]; co[3]= 1.0; Mat4MulVec4fl(shb->winmat,co); /* rationele hom co */ dy[0]= xs1-((0.5*(float)shb->size)*(1.0+co[0]/co[3])); dy[1]= ys1-((0.5*(float)shb->size)*(1.0+co[1]/co[3])); dy[2]= zs1 -0x7FFFFFFF*(co[2]/co[3]); siz= ( fabs(dx[0])+fabs(dy[0]) )*( fabs(dx[1])+fabs(dy[1]) ); if( siz< fac) fac/= siz; fac/= 2.0; xs1-= (dx[0]+dy[0])*fac; ys1-= (dx[1]+dy[1])*fac; zs1-= (dx[2]+dy[2])*fac; fac*= 2.0; dx[0]*=fac; dx[1]*=fac; dx[2]*=fac; dy[0]*=fac; dy[1]*=fac; dy[2]*=fac; for(a=0;a=shb->size) { xstart= shb->size-3; xend= shb->size-1;} if(yend>=shb->size) { ystart= shb->size-3; yend= shb->size-1;} fid= filt3; for(ys=ystart;ys<=yend;ys++) { rz= shb->buf+ ys*shb->size+ xstart; for(xs= xstart;xs<=xend;xs++,rz++) { if( *rz+0x100000