/** * $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 * * Version: $Id: shadbuf.c,v 1.2 2000/09/21 13:46:23 nzc Exp $ */ #include "blender.h" #include "render.h" #include "initrender.h" #include "zbuf.h" #include "matrixops.h" #include "shadbuf.h" float jitshad[32][2]; short filt3[9]= { 1,2,1,2,4,2,1,2,1 }; static int bias= 0x00500000; void lrectreadRectz(x1,y1,x2,y2,r1) /* leest deel uit rectz in r1 */ int x1,y1,x2,y2; char *r1; { uint 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(LampRen *lar, Lamp *la, float mat[][4]) { struct ShadBuf *shb; float hoek, temp, viewinv[4][4]; /* 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->shadhalostep= la->shadhalostep; shb->zbuf= (ulong *)mallocN( sizeof(ulong)*(shb->size*shb->size)/256, "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; } MTC_Mat4Ortho(mat); MTC_Mat4Invert(shb->winmat, mat); /* winmat is hier temp */ /* matrix: combinatie van inverse view en lampmat */ /* opnieuw berekenen: de ortho-render heeft geen correcte viewinv */ MTC_Mat4Invert(viewinv, R.viewmat); MTC_Mat4MulMat4(shb->viewmat, viewinv, shb->winmat); /* projektie */ hoek= safacos(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); } int sizeoflampbuf(shb) struct ShadBuf *shb; { int 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(); float temp, wsize, dist; int *rz, *rz1, verg, verg1; ulong *ztile; int a, x, y, minx, miny, byt1, byt2; short temprx,tempry, square; char *rc, *rcline, *ctile, *zt; /* viewvars onthouden */ temprx= R.rectx; tempry= R.recty; R.rectx= R.recty= shb->size; initjit(shb->jit[0], 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, shb->winmat); MTC_Mat4MulMat4(shb->persmat, shb->viewmat, shb->winmat); /* temp, will be restored */ Mat4SwapMat4(shb->persmat, R.winmat); /* zbufferen */ if(R.rectz) freeN(R.rectz); R.rectz= (uint *)mallocN(sizeof(int)*shb->size*shb->size,"makeshadbuf"); rcline= mallocN(256*4+sizeof(int),"makeshadbuf2"); /* onthouden: panorama rot */ temp= panophi; panophi= 0.0; setzbufvlaggen(projectvert); panophi= temp; zbuffershad(lar); /* 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 ER WEER UIT * ook vanwege shadowhalo! * a= shb->size*shb->size; rz= R.rectz; while(a--) { if(*rz & 1) *rz= 0x7FFFFFFF; rz++; } */ square= lar->mode & LA_SQUARE; /* Z tiles aanmaken: dit systeem is 24 bits!!! */ ztile= shb->zbuf; ctile= shb->cbuf; for(y=0; ysize; y+=16) { if(y< shb->size/2) miny= y+15-shb->size/2; else miny= y-shb->size/2; 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; dist= fsqrt( (float)(minx*minx+miny*miny) ); if(square==0 && dist>(float)(a+12)) { /* 12, tested with a onlyshadow lamp */ a= 256; verg= 0; /* 0x80000000; */ /* 0x7FFFFFFF; */ rz1= (&verg)+1; } else { lrectreadRectz(x, y, MIN2(shb->size-1,x+15), MIN2(shb->size-1,y+15), rcline); rz1= (int *)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 { /* ACOMP enz. zijn defined L/B endian */ rc= rcline; rz1= (int *)rcline; verg= rc[ACOMP]; verg1= rc[BCOMP]; rc+= 4; byt1= 1; byt2= 1; for(a=1;a<256;a++,rc+=4) { byt1 &= (verg==rc[ACOMP]); byt2 &= (verg1==rc[BCOMP]); if(byt1==0) break; } if(byt1 && byt2) { /* alleen byte opslaan */ *ctile= 1; *ztile= (ulong)mallocN(256+4, "tile1"); rz= (int *)*ztile; *rz= *rz1; zt= (char *)(rz+1); rc= rcline; for(a=0; a<256; a++, zt++, rc+=4) *zt= rc[GCOMP]; } else if(byt1) { /* short opslaan */ *ctile= 2; *ztile= (ulong)mallocN(2*256+4,"Tile2"); rz= (int *)*ztile; *rz= *rz1; zt= (char *)(rz+1); rc= rcline; for(a=0; a<256; a++, zt+=2, rc+=4) { zt[0]= rc[BCOMP]; zt[1]= rc[GCOMP]; } } 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[ACOMP]; zt[1]= rc[BCOMP]; zt[2]= rc[GCOMP]; } } } ztile++; ctile++; } } freeN(rcline); freeN(R.rectz); R.rectz= 0; R.rectx= temprx; R.recty= tempry; Mat4SwapMat4(shb->persmat, R.winmat); /* printf("lampbuf %d\n", sizeoflampbuf(shb)); */ } int firstreadshadbuf(struct ShadBuf *shb, int xs, int ys, int nr) { /* return 1 als volledig gecomprimeerde shadbuftile && z==const */ static int *rz; int ofs; char *ct; /* always test borders of shadowbuffer */ if(xs<0) xs= 0; else if(xs>=shb->size) xs= shb->size-1; if(ys<0) ys= 0; else if(ys>=shb->size) ys= shb->size-1; /* z berekenen */ ofs= (ys>>4)*(shb->size>>4) + (xs>>4); ct= shb->cbuf+ofs; if(*ct==0) { if(nr==0) { rz= *( (int **)(shb->zbuf+ofs) ); return 1; } else if(rz!= *( (int **)(shb->zbuf+ofs) )) return 0; return 1; } return 0; } float readshadowbuf(struct ShadBuf *shb, int xs, int ys, int zs) /* return 1.0 : volledig licht */ { float temp; int *rz, ofs; int zsamp; char *ct, *cz; /* simpleclip */ /* if(xs<0 || ys<0) return 1.0; */ /* if(xs>=shb->size || ys>=shb->size) return 1.0; */ /* always test borders of shadowbuffer */ if(xs<0) xs= 0; else if(xs>=shb->size) xs= shb->size-1; if(ys<0) ys= 0; else if(ys>=shb->size) ys= shb->size-1; /* z berekenen */ ofs= (ys>>4)*(shb->size>>4) + (xs>>4); ct= shb->cbuf+ofs; rz= *( (int **)(shb->zbuf+ofs) ); if(*ct==3) { ct= ((char *)rz)+3*16*(ys & 15)+3*(xs & 15); cz= (char *)&zsamp; cz[ACOMP]= ct[0]; cz[BCOMP]= ct[1]; cz[GCOMP]= ct[2]; } else if(*ct==2) { ct= ((char *)rz); ct+= 4+2*16*(ys & 15)+2*(xs & 15); zsamp= *rz; cz= (char *)&zsamp; cz[BCOMP]= ct[0]; cz[GCOMP]= ct[1]; } else if(*ct==1) { ct= ((char *)rz); ct+= 4+16*(ys & 15)+(xs & 15); zsamp= *rz; cz= (char *)&zsamp; cz[GCOMP]= ct[0]; } else { zsamp= (int) rz; } /* if(zsamp >= 0x7FFFFE00) return 1.0; */ /* geen schaduw als op oneindig wordt gesampeld*/ if(zsamp > zs) return 1.0; /* absoluut geen schaduw */ else if( zsamp < zs-bias) return 0.0 ; /* absoluut wel schaduw */ else { /* zacht gebied */ temp= ( (float)(zs- zsamp) )/(float)bias; return 1.0 - temp*temp; } } float testshadowbuf(struct ShadBuf *shb, float inp) /* return 1.0: geen schaduw */ { float fac, co[4], dx[3], dy[3], aantal=0; float xs1,ys1, siz, *j, xres, yres; int 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->persmat, 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 readshadowbuf(shb,(int)xs1, (int)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->persmat,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->persmat,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, (int)xs1, (int)ys1, 0)) { if(firstreadshadbuf(shb, (int)(xs1+xres), (int)ys1, 1)) { if(firstreadshadbuf(shb, (int)xs1, (int)(ys1+yres), 1)) { if(firstreadshadbuf(shb, (int)(xs1+xres), (int)(ys1+yres), 1)) { return readshadowbuf(shb,(int)xs1, (int)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 aantal/( (float)(num) ); } /* different function... sampling behind clipend can be LIGHT, bias is negative! */ /* return: light */ float readshadowbuf_halo(struct ShadBuf *shb, int xs, int ys, int zs) { float temp; int *rz, ofs; int zbias, zsamp; char *ct, *cz; /* simpleclip */ if(xs<0 || ys<0) return 0.0; if(xs>=shb->size || ys>=shb->size) return 0.0; /* z berekenen */ ofs= (ys>>4)*(shb->size>>4) + (xs>>4); ct= shb->cbuf+ofs; rz= *( (int **)(shb->zbuf+ofs) ); if(*ct==3) { ct= ((char *)rz)+3*16*(ys & 15)+3*(xs & 15); cz= (char *)&zsamp; zsamp= 0; cz[ACOMP]= ct[0]; cz[BCOMP]= ct[1]; cz[GCOMP]= ct[2]; } else if(*ct==2) { ct= ((char *)rz); ct+= 4+2*16*(ys & 15)+2*(xs & 15); zsamp= *rz; cz= (char *)&zsamp; cz[BCOMP]= ct[0]; cz[GCOMP]= ct[1]; } else if(*ct==1) { ct= ((char *)rz); ct+= 4+16*(ys & 15)+(xs & 15); zsamp= *rz; cz= (char *)&zsamp; cz[GCOMP]= ct[0]; } else { zsamp= (int) rz; } /* geen schaduw als op oneindig wordt gesampeld*/ if(zsamp >= 0x7FFFFE00) return 1.0; if(zsamp > zs) return 1.0; /* absoluut geen schaduw */ else { /* bias is negative, so the (zs-bias) can be beyond 0x7fffffff */ zbias= 0x7fffffff - zs; if(zbias > -bias) { if( zsamp < zs-bias) return 0.0 ; /* absoluut wel schaduw */ } else return 0.0 ; /* absoluut wel schaduw */ } /* zacht gebied */ temp= ( (float)(zs- zsamp) )/(float)bias; return 1.0 - temp*temp; } float shadow_halo(LampRen *lar, float *p1, float *p2) { /* p1 p2 already are rotated in spot-space */ ShadBuf *shb= lar->shb; float co[4], siz; float labda, labdao, labdax, labday, ldx, ldy; float zf, xf1, yf1, zf1, xf2, yf2, zf2; float count, lightcount; int x, y, z, xs1, ys1; int dx = 0, dy = 0; siz= 0.5*(float)shb->size; /* negative! The other side is more important */ bias= -shb->bias; co[0]= p1[0]; co[1]= p1[1]; co[2]= p1[2]/lar->sh_zfac; co[3]= 1.0; Mat4MulVec4fl(shb->winmat, co); /* rationele hom co */ xf1= siz*(1.0+co[0]/co[3]); yf1= siz*(1.0+co[1]/co[3]); zf1= (co[2]/co[3]); co[0]= p2[0]; co[1]= p2[1]; co[2]= p2[2]/lar->sh_zfac; co[3]= 1.0; Mat4MulVec4fl(shb->winmat, co); /* rationele hom co */ xf2= siz*(1.0+co[0]/co[3]); yf2= siz*(1.0+co[1]/co[3]); zf2= (co[2]/co[3]); /* de 2dda */ xs1= (int)xf1; ys1= (int)yf1; if(xf1 != xf2) { if(xf2-xf1 > 0.0) { labdax= (xf1-xs1-1.0)/(xf1-xf2); ldx= -shb->shadhalostep/(xf1-xf2); dx= shb->shadhalostep; } else { labdax= (xf1-xs1)/(xf1-xf2); ldx= shb->shadhalostep/(xf1-xf2); dx= -shb->shadhalostep; } } else { labdax= 1.0; ldx= 0.0; } if(yf1 != yf2) { if(yf2-yf1 > 0.0) { labday= (yf1-ys1-1.0)/(yf1-yf2); ldy= -shb->shadhalostep/(yf1-yf2); dy= shb->shadhalostep; } else { labday= (yf1-ys1)/(yf1-yf2); ldy= shb->shadhalostep/(yf1-yf2); dy= -shb->shadhalostep; } } else { labday= 1.0; ldy= 0.0; } x= xs1; y= ys1; labda= count= lightcount= 0.0; /* printf("start %x %x \n", (int)(0x7FFFFFFF*zf1), (int)(0x7FFFFFFF*zf2)); */ while(TRUE) { labdao= labda; if(labdax==labday) { labdax+= ldx; x+= dx; labday+= ldy; y+= dy; } else { if(labdax=1.0) break; zf= zf1 + labda*(zf2-zf1); count+= 1.0; if(zf<= 0.0) lightcount += 1.0; /* close to the spot */ else { /* make sure, behind the clipend we extend halolines. */ if(zf>=1.0) z= 0x7FFFF000; else z= (int)(0x7FFFF000*zf); lightcount+= readshadowbuf_halo(shb, x, y, z); } } if(count!=0.0) return (lightcount/count); return 0.0; } /* sampelen met filter xstart= xs-1; ystart= ys-1; if(xstart<0) xstart= 0; if(ystart<0) ystart= 0; xend= xstart+2; yend= ystart+2; if(xend>=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