/**
* $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 <gl/device.h> */
/* 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;y<shb->size;y+=16) {
for(x=0;x<shb->size;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(xres<fac) xres= fac;
if(yres<fac) yres= fac;
xs1-= (xres)/2;
ys1-= (yres)/2;
j= shb->jit[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<n;a++) {
for(b=0;b<n;b++) {
j= jitshad[tel++];
xs= xs1+ dy[0]*j[1] +dx[0]*j[0];
ys= ys1+ dy[1]*j[1] +dx[1]*j[0];
zs= zs1+ dy[2]*j[1] +dx[2]*j[0];
aantal+= readshadowbuf(shb,xs,ys,zs);
}
}
return 1.0- aantal/( (float)(n*n) );
}
/* 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<zs) aantal+= *fid;
fid++;
}
}
return 1.0-((float)aantal)/16.0;
*/