#include "miniP.h"
// set the global error handler for the mini library
void setminierrorhandler(void (*handler)(char *file,int line,int fatal))
{}//minierrorhandler=handler;}
namespace mini {
// set fine tuning parameters
void setparams(float minr,
float maxd,
float ginf,
float bsaf,
int maxc)
{
if (minr<1.0f || maxd<=0.0f || ginf<0.0f || bsaf<0.0f || maxc<0) ERRORMSG();
minres=minr;
maxd2=maxd;
gradinf=ginf;
bsafety=bsaf;
maxcull=maxc;
}
// scale the height field
void scalemap(short int *image,int size)
{
int i,j,
mi,mj;
float pi,pj,
ri,rj;
for (i=0; i<S; i++)
for (j=0; j<S; j++)
if (size==S) y[i][j]=image[(S-1-j)*S+i];
else
{
if (i<S-1)
{
pi=(float)i/(S-1)*(size-1);
mi=ftrc(pi);
ri=pi-mi;
}
else
{
mi=size-2;
ri=1.0f;
}
if (j>0)
{
pj=(float)(S-1-j)/(S-1)*(size-1);
mj=ftrc(pj);
rj=pj-mj;
}
else
{
mj=size-2;
rj=1.0f;
}
y[i][j]=ftrc((1.0f-rj)*((1.0f-ri)*image[mj*size+mi]+
ri*image[mj*size+mi+1])+
rj*((1.0f-ri)*image[(mj+1)*size+mi]+
ri*image[(mj+1)*size+mi+1])+0.5f);
}
}
// calculate the height differences
void calcDH()
{
int i,j,s,
m,n;
DH=y[S];
for (i=0; i<S; i++) DH[i]=0;
for (s=S-1; s>1; s/=2)
for (i=s/2; i<S; i+=s)
for (j=s/2; j<S; j+=s)
for (m=-s/2; m<=s/2; m++)
for (n=-s/2; n<=s/2; n++)
DH[s]=max((unsigned short int)DH[s],abs(y[i+m][j+n]-y[i][j]));
}
// store a d2-value
void store(float fc,int i,int j,int s2)
{
if (fc>1.0f) ERRORMSG();
if (fc>dcpr(i,j,s2))
{
bc[i-s2][j]=cpr(fc)%256;
bc[i][j-s2]=cpr(fc)/256;
while (dcpr(i,j,s2)<fc)
if (++bc[i-s2][j]==0)
if (++bc[i][j-s2]==0)
{
bc[i-s2][j]=bc[i][j-s2]=255;
break;
}
}
}
// propagate a local d2-value to the next higher level
void propagate(int i,int j,int s,int i0,int j0)
{
float l1,l2;
if (i0<0 || i0>=S || j0<0 || j0>=S) return;
l1=2.0f*s*D*minres;
l2=l1-fsqrt(fsqr(X(i)-X(i0))+fsqr(Z(j)-Z(j0)));
if (l2<=0.0f) ERRORMSG();
store(dcpr(i,j,s/2)*l1/l2/2.0f,i0,j0,s);
}
// calculate d2-value
inline float d2value(const float a,const float b,const float m)
{return(fmax(fabs(a+b-2.0f*m)-gradinf*fabs(a-b),0.0f));}
// calculate the d2-values
void calcD2()
{
int i,j,s,s2;
float fc;
for (i=0; i<S-1; i++)
for (j=0; j<S-1; j++) bc[i][j]=0;
// propagate the d2-values up the tree
for (s=2; s<S; s*=2)
{
s2=s/2;
for (i=s2; i<S; i+=s)
for (j=s2; j<S; j+=s)
{
// calculate the local d2-value
fc=d2value(Y(i-s2,j-s2),Y(i+s2,j-s2),Y(i,j-s2));
fc=fmax(fc,d2value(Y(i-s2,j+s2),Y(i+s2,j+s2),Y(i,j+s2)));
fc=fmax(fc,d2value(Y(i-s2,j-s2),Y(i-s2,j+s2),Y(i-s2,j)));
fc=fmax(fc,d2value(Y(i+s2,j-s2),Y(i+s2,j+s2),Y(i+s2,j)));
if ((i/s+j/s)%2==0) fc=fmax(fc,d2value(Y(i-s2,j-s2),Y(i+s2,j+s2),Y(i,j)));
else fc=fmax(fc,d2value(Y(i-s2,j+s2),Y(i+s2,j-s2),Y(i,j)));
store(fmin(fc/s/D/maxd2,1.0f),i,j,s2);
// propagate the local d2-value
if (s<S-1) switch ((i/s)%2+2*((j/s)%2))
{
case 0: propagate(i,j,s,i+s2,j+s2);
propagate(i,j,s,i-s-s2,j+s2);
propagate(i,j,s,i+s2,j-s-s2);
break;
case 1: propagate(i,j,s,i-s2,j+s2);
propagate(i,j,s,i-s2,j-s-s2);
propagate(i,j,s,i+s+s2,j+s2);
break;
case 2: propagate(i,j,s,i+s2,j-s2);
propagate(i,j,s,i+s2,j+s+s2);
propagate(i,j,s,i-s-s2,j-s2);
break;
case 3: propagate(i,j,s,i-s2,j-s2);
propagate(i,j,s,i+s+s2,j-s2);
propagate(i,j,s,i-s2,j+s+s2);
break;
}
}
}
}
inline float blendE(const int bc,const float v0,const float v1,const float v2)
{return((bc==255)?v0:(2*bc*v0+(255-bc)*(v1+v2))/510.0f);}
inline float blendM(const int bc,const float v0,const float v1,const float v2)
{return((bc==0)?-MAXFLOAT:blendE(bc,v0,v1,v2));}
int maxbc(const int w,int i,int j,const int s2)
{
int s;
if (bc2[w]==NULL) return(255);
if (S2[w]<S)
{
if ((s=(S-1)/(S2[w]-1))>s2) return(0);
i/=s;
j/=s;
}
else
{
s=(S2[w]-1)/(S-1);
i*=s;
j*=s;
}
return(bc2[w][i][j]);
}
inline float blendD(const int i,const int j,const float y1,const float y2)
{return(blendE(bc[i][j],y[i][j],y1,y2));}
inline float blendV(const int i,const int j,const int s2,const float y1,const float y2)
{return(blendM(min((i>0)?bc[i-s2][j]:maxbc(0,S-1-s2,j,s2),
(i<S-1)?bc[i+s2][j]:maxbc(1,s2,j,s2)),y[i][j],y1,y2));}
inline float blendH(const int i,const int j,const int s2,const float y1,const float y2)
{return(blendM(min((j>0)?bc[i][j-s2]:maxbc(2,i,S-1-s2,s2),
(j<S-1)?bc[i][j+s2]:maxbc(3,i,s2,s2)),y[i][j],y1,y2));}
// geomorph the triangulation
void drawmap(const int i,const int j,const int s,
const float e1,const float e2,const float e3,const float e4)
{
int s2,s4;
float dx,dy,dz;
float l,d;
float m0,m1,m2,m3,m4;
int bc1,bc2,bc3,bc4;
s2=s/2;
s4=s/4;
if (CULLING && s>(S>>maxcull)) // view frustum culling
{
dx=X(i)-EX;
dy=Y(i,j)-EY;
dz=Z(j)-EZ;
l=DX*dx+DY*dy+DZ*dz;
d=k1*s2+k2*(unsigned short int)DH[s];
if (l<NEARP-d || l>FARP+d) return;
if (!ORTHO)
{
if (nx1*dx+ny1*dy+nz1*dz>k11*s2+k12*(unsigned short int)DH[s]) return;
if (nx2*dx+ny2*dy+nz2*dz>k21*s2+k22*(unsigned short int)DH[s]) return;
if (nx3*dx+ny3*dy+nz3*dz>k31*s2+k32*(unsigned short int)DH[s]) return;
if (nx4*dx+ny4*dy+nz4*dz>k41*s2+k42*(unsigned short int)DH[s]) return;
}
else
{
if (fabs(RX*dx+RY*dy+RZ*dz)>k11*s2+k12*(unsigned short int)DH[s]+k31) return;
if (fabs(UX*dx+UY*dy+UZ*dz)>k21*s2+k22*(unsigned short int)DH[s]+k32) return;
}
}
// blend the center vertex
if (((i+j)/s)%2==1) m0=blendD(i,j,e1,e3);
else m0=blendD(i,j,e2,e4);
// blend the edge vertices
m1=blendV(i+s2,j,s2,e4,e1);
m2=blendH(i,j+s2,s2,e1,e2);
m3=blendV(i-s2,j,s2,e2,e3);
m4=blendH(i,j-s2,s2,e3,e4);
// subdivision factors
if (s4>0)
{
bc1=bc[i+s4][j+s4];
bc2=bc[i-s4][j+s4];
bc3=bc[i-s4][j-s4];
bc4=bc[i+s4][j-s4];
}
else bc1=bc2=bc3=bc4=0;
// first triangle fan quarter
if (bc1!=0)
{
if (m1==-MAXFLOAT) m1=(e4+e1)/2.0f;
if (m2==-MAXFLOAT) m2=(e1+e2)/2.0f;
drawmap(i+s4,j+s4,s2,e1,m2,m0,m1);
}
else
{
miniOGL::beginfan();
fanvertex(i,m0,j);
if (bc4!=0)
{
if (m1==-MAXFLOAT) m1=(e4+e1)/2.0f;
fanvertex(i+s2,m1,j);
}
else if (m1!=-MAXFLOAT) fanvertex(i+s2,m1,j);