brender-v1.1.2/ZB/INNERP.H
2022-05-04 18:14:23 -07:00

478 lines
12 KiB
C

/* $Id: innerp.h 1.4 1995/03/01 15:49:34 sam Exp $ */
/* Perspective texture mapped triangle renderer */
#define SHIFT 1
/* Macros for moving left, right, up and down in texture */
#if SIZE==256 && defined __WATCOMC__
#define incv(a) inch(a)
#define incu(a) incl(a)
#define decv(a) dech(a)
#define decu(a) decl(a)
#else
#define incv(a) (a+SIZE & SIZE*SIZE-1);
#define incu(a) ((a+1 & SIZE-1) | (a & ~(SIZE-1)));
#define decv(a) (a-SIZE & SIZE*SIZE-1);
#define decu(a) ((a-1 & SIZE-1) | (a & ~(SIZE-1)));
#endif
void BR_ASM_CALL
FNAME(struct temp_vertex *_a,struct temp_vertex *_b,struct temp_vertex *_c)
{
struct temp_vertex_fixed *a = (void *)_a;
struct temp_vertex_fixed *b = (void *)_b;
struct temp_vertex_fixed *c = (void *)_c;
/* v[0] and v[1] contain the (fractional) screen coordinates */
/* And comp[C_W] contain the 3-space z-value */
/* (v[0]-width/2)*comp[C_W] gives the 3-space x-values */
/* Similarly for y */
float sxa,sxb,sxc,sya,syb,syc;
float WbWc,WcWa,WaWb;
float bvcx,bvcy,bvcz,cvax,cvay,cvaz,avbx,avby,avbz;
float dUx,dUy,dUz,dVx,dVy,dVz,nx,ny;
float fW;
float au,av,bu,bv,cu,cv;
unsigned int iU,iV;
int idUx,idUy,idVx,idVy,idWx,idWy;
#if FIX
br_fixed_ls
#else
float
#endif
dp1,dp2,g_divisor;
/* We need two sets of iterators: */
/* One for following scan lines */
/* Another for following the start of scan lines */
int udW_nocarry;
int vdW_nocarry;
int dU_nocarry,dV_nocarry,dW_nocarry;
int udom,vdom;
int offset;
int u_base,v_base;
int carry,grad;
float tmpf;
int tmpi,tmp1,tmp2,tmp3;
int range;
/* Optimal sort of 3 elements? */
if (a->v[1]>b->v[1]) {
if (b->v[1]>c->v[1]) {
swap(struct temp_vertex_fixed *,a,c);
} else {
if (a->v[1]>c->v[1]) {
swap(struct temp_vertex_fixed *,a,b);
swap(struct temp_vertex_fixed *,b,c);
} else {
swap(struct temp_vertex_fixed *,a,b);
}
}
} else {
if (b->v[1]>c->v[1]) {
if (a->v[1]>c->v[1]) {
swap(struct temp_vertex_fixed *,b,c);
swap(struct temp_vertex_fixed *,a,b);
} else {
swap(struct temp_vertex_fixed *,b,c);
}
}
}
if (PerspCheat) {
range = a->v[0]-b->v[0];
if ((tmpi = a->v[0]-c->v[0])>range) range = tmpi;
if ((tmpi = b->v[0]-c->v[0])>range) range = tmpi;
if ((tmpi = b->v[0]-a->v[0])>range) range = tmpi;
if ((tmpi = c->v[0]-a->v[0])>range) range = tmpi;
if ((tmpi = c->v[0]-b->v[0])>range) range = tmpi;
if ((tmpi = c->v[1]-a->v[1])>range) range = tmpi;
range /= 0x10000;
tmp1 = a->comp[C_W];
tmp2 = b->comp[C_W];
tmp3 = c->comp[C_W];
if (tmp1>tmp2) swap(int,tmp1,tmp2);
if (tmp2>tmp3) swap(int,tmp2,tmp3);
if (tmp1>tmp2) tmp1 = tmp2;
if (tmp3<0) return;
while ((tmp1 | tmp3) & 0xffff0000) {
tmp1 /= 2;
tmp3 /= 2;
}
if ((tmp3-tmp1)*range<cutoff*tmp1) {
#if SIZE==256 && LIGHT
TriangleRenderPIZ2TI(_a,_b,_c);
#elif SIZE==256 && !LIGHT
TriangleRenderPIZ2T(_a,_b,_c);
#elif LIGHT
TriangleRenderPIZ2TIA(_a,_b,_c);
#elif !LIGHT
TriangleRenderPIZ2TA(_a,_b,_c);
#endif
return;
}
}
sxa = sar16(a->v[0]-fw.vp_width);
sxb = sar16(b->v[0]-fw.vp_width);
sxc = sar16(c->v[0]-fw.vp_width);
sya = sar16(a->v[1]-fw.vp_height);
syb = sar16(b->v[1]-fw.vp_height);
syc = sar16(c->v[1]-fw.vp_height);
if (sya==syc) return;
/* The compiler hopefully has the sense to substitute multiplications here */
u_base = a->comp[C_U];
if (b->comp[C_U]<u_base) u_base = b->comp[C_U];
if (c->comp[C_U]<u_base) u_base = c->comp[C_U];
v_base = a->comp[C_V];
if (b->comp[C_V]<v_base) v_base = b->comp[C_V];
if (c->comp[C_V]<v_base) v_base = c->comp[C_V];
u_base &= 0xffff0000;
v_base &= 0xffff0000;
au = (float)(a->comp[C_U]-u_base)/0x10000;
bu = (float)(b->comp[C_U]-u_base)/0x10000;
cu = (float)(c->comp[C_U]-u_base)/0x10000;
av = (float)(a->comp[C_V]-v_base)/0x10000;
bv = (float)(b->comp[C_V]-v_base)/0x10000;
cv = (float)(c->comp[C_V]-v_base)/0x10000;
u_base /= 0x10000;
v_base /= 0x10000;
WbWc = (float)b->comp[C_W]*(float)c->comp[C_W];
WcWa = (float)c->comp[C_W]*(float)a->comp[C_W];
WaWb = (float)a->comp[C_W]*(float)b->comp[C_W];
/* Compute cross products a x b using snapped integer coordinates */
bvcx = WbWc*(syb-syc);
bvcy = WbWc*(sxc-sxb);
bvcz = WbWc*(sxb*syc-syb*sxc);
cvax = WcWa*(syc-sya);
cvay = WcWa*(sxa-sxc);
cvaz = WcWa*(sxc*sya-syc*sxa);
avbx = WaWb*(sya-syb);
avby = WaWb*(sxb-sxa);
avbz = WaWb*(sxa*syb-sya*sxb);
/* The u coordinate for the texel mapped to the screen at x,y */
/* are given by u = int(U(x,y)/V(x,y)) */
dUx = bvcx*au+cvax*bu+avbx*cu;
dUy = bvcy*au+cvay*bu+avby*cu;
dUz = bvcz*au+cvaz*bu+avbz*cu;
dVx = bvcx*av+cvax*bv+avbx*cv;
dVy = bvcy*av+cvay*bv+avby*cv;
dVz = bvcz*av+cvaz*bv+avbz*cv;
nx = bvcx+cvax+avbx;
ny = bvcy+cvay+avby;
fW = nx*sxa+ny*sya+bvcz+cvaz+avbz;
if (fW<0) {
fW = -fW;
dUx = -dUx, dUy = -dUy;
dVx = -dVx, dVy = -dVy;
nx = -nx, ny = -ny;
}
/* Now put U,V and various deltas into integers */
/* As u = int(U/V) we can multiply U and V by any factor we choose. */
/* We choose the factor to make U and V representible by large */
/* integers for greater accuracy. */
tmpf = fabs(au)+fabs(bu)+fabs(cu)+fabs(av)+fabs(bv)+fabs(cv);
tmpf = (float)(1 << 30)/(tmpf*fW);
idUx = dUx*tmpf;
idUy = dUy*tmpf;
idVx = dVx*tmpf;
idVy = dVy*tmpf;
tsl.dWx = idWx = nx*tmpf;
idWy = ny*tmpf;
tmpf *= fW;
iU = au*tmpf;
iV = av*tmpf;
tsl.iW = tmpf;
if (!tsl.iW) return;
zb.top.x = sxb-sxa;
zb.top.y = syb-sya;
zb.bot.x = sxc-sxb;
zb.bot.y = syc-syb;
zb.main.x = sxc-sxa;
zb.main.y = syc-sya;
#if FIX
g_divisor = zb.top.x*zb.main.y-zb.main.x*zb.top.y;
if (!g_divisor) return;
#else
g_divisor = zb.top.x*zb.main.y-zb.main.x*zb.top.y;
if (!g_divisor) return;
#endif
/* Calculate deltas along triangle edges */
zb.main.grad = zb.main.x*_reciprocal[zb.main.y];
zb.main.d_f = zb.main.grad << 16;
grad = sar16(zb.main.grad);
zb.main.d_i = grad+zb.row_width;
dU_nocarry = grad*idUx+idUy;
dV_nocarry = grad*idVx+idVy;
dW_nocarry = grad*idWx+idWy;
zb.top.grad = zb.top.y ? zb.top.x*_reciprocal[zb.top.y] : 0;
zb.top.d_f = zb.top.grad << 16;
zb.top.d_i = sar16(zb.top.grad)+zb.row_width;
/* Shift right by half a pixel */
zb.main.f = zb.top.f = 0x80000000;
udom = au;
vdom = av;
udW_nocarry = udom*dW_nocarry-dU_nocarry;
tsl.udW = udom*idWx-idUx;
vdW_nocarry = vdom*dW_nocarry-dV_nocarry;
tsl.vdW = vdom*idWx-idVx;
/* Eu and Ev are the 'Bresenham style' error terms */
tsl.Eu = iU-udom*tsl.iW;
tsl.Ev = iV-vdom*tsl.iW;
tsl.source = ((vdom+v_base) & SIZE-1) * SIZE | (udom+u_base) & SIZE-1;
offset = sar16(a->v[X])+sar16(a->v[Y])*zb.row_width-(g_divisor<0);
tsl.start = tsl.end = zb.colour_buffer+offset;
tsl.zstart = (char *)zb.depth_buffer+(offset << 1);
zb.top.count = syb-sya;
zb.bot.f = 0x80000000;
zb.bot.grad = zb.bot.y ? zb.bot.x*_reciprocal[zb.bot.y] : 0;
zb.bot.d_f = zb.bot.grad << 16;
zb.bot.d_i = sar16(zb.bot.grad)+zb.row_width;
zb.bot.count = syc-syb;
#if FIX
#define PARAM_SETUP(param,p) {\
dp1 = b->p-a->p;\
dp2 = c->p-a->p;\
param.grad_x = SafeFixedMac2Div(dp1,zb.main.y,-dp2,zb.top.y,g_divisor);\
param.grad_y = SafeFixedMac2Div(dp2,zb.top.x,-dp1,zb.main.x,g_divisor);\
param.current = a->p+(g_divisor >=0 ? param.grad_x/2 : -param.grad_x/2);\
param.d_nocarry = BrFixedToInt(zb.main.grad)*param.grad_x+param.grad_y;\
param.d_carry = param.d_nocarry+param.grad_x;\
}
#else
#define PARAM_SETUP(param,p) {\
dp1 = BrFixedToFloat(b->p-a->p);\
dp2 = BrFixedToFloat(c->p-a->p);\
param.grad_x = BrFloatToFixed((dp1*zb.main.y-dp2*zb.top.y)/g_divisor);\
param.grad_y = BrFloatToFixed((dp2*zb.top.x-dp1*zb.main.x)/g_divisor);\
param.current = a->p+param.grad_x/2;\
param.d_nocarry = BrFixedToInt(zb.main.grad)*param.grad_x+param.grad_y;\
param.d_carry = param.d_nocarry+param.grad_x;\
}
#endif
#if LIGHT
PARAM_SETUP(zb.pi,comp[C_I]);
#endif
PARAM_SETUP(zb.pz,v[Z]);
#if SHIFT
/* shift by 1/2 pixel */
if (g_divisor>=0) {
tsl.iW += tsl.dWx/2;
tsl.Eu += -tsl.udW/2;
tsl.Ev += -tsl.vdW/2;
} else {
tsl.iW -= tsl.dWx/2;
tsl.Eu -= -tsl.udW/2;
tsl.Ev -= -tsl.vdW/2;
}
if ((signed)tsl.iW<0) return;
while (tsl.Eu>=(signed)tsl.iW) {
tsl.Eu -= tsl.iW; tsl.source = incu(tsl.source); tsl.udW += tsl.dWx;
udW_nocarry += dW_nocarry;
}
while (tsl.Eu<0) {
tsl.Eu += tsl.iW; tsl.source = decu(tsl.source); tsl.udW -= tsl.dWx;
udW_nocarry -= dW_nocarry;
}
while (tsl.Ev>=(signed)tsl.iW) {
tsl.Ev -= tsl.iW; tsl.source = incv(tsl.source); tsl.vdW += tsl.dWx;
vdW_nocarry += dW_nocarry;
}
while (tsl.Ev<0) {
tsl.Ev += tsl.iW; tsl.source = decv(tsl.source); tsl.vdW -= tsl.dWx;
vdW_nocarry -= dW_nocarry;
}
#endif
while (zb.top.count--) {
/* Start of second innermost loop */
#if SIZE==256 && LIGHT
ScanLinePIZ2TIP256();
#elif SIZE==256 && !LIGHT
ScanLinePIZ2TP256();
#elif SIZE==64 && LIGHT
ScanLinePIZ2TIP64();
#elif SIZE==64 && !LIGHT
ScanLinePIZ2TP64();
#elif SIZE==1024 && !LIGHT
ScanLinePIZ2TP1024();
#elif SIZE==1024 && LIGHT
ScanLinePIZ2TIP1024();
#endif
zb.top.f += zb.top.d_f;
carry = (unsigned)zb.top.f < (unsigned)zb.top.d_f;
tsl.end += zb.top.d_i+carry;
zb.main.f += zb.main.d_f;
carry = (unsigned)zb.main.f < (unsigned)zb.main.d_f;
tsl.iW += dW_nocarry;
tsl.Eu += -udW_nocarry;
tsl.Ev += -vdW_nocarry;
tsl.start += zb.main.d_i+carry;
tsl.zstart += zb.main.d_i+carry << 1;
#if LIGHT
zb.pi.current += zb.pi.d_nocarry;
#endif
zb.pz.current += zb.pz.d_nocarry;
if (carry) {
tsl.iW +=idWx;
tsl.Eu += -tsl.udW;
tsl.Ev += -tsl.vdW;
#if LIGHT
zb.pi.current += zb.pi.grad_x;
#endif
zb.pz.current += zb.pz.grad_x;
}
/* The core perspective calculations along the main edge */
if ((signed)tsl.iW<0) return;
while (tsl.Eu>=(signed)tsl.iW) {
tsl.Eu -= tsl.iW; tsl.source = incu(tsl.source); tsl.udW += tsl.dWx;
udW_nocarry += dW_nocarry;
}
while (tsl.Eu<0) {
tsl.Eu += tsl.iW; tsl.source = decu(tsl.source); tsl.udW -= tsl.dWx;
udW_nocarry -= dW_nocarry;
}
while (tsl.Ev>=(signed)tsl.iW) {
tsl.Ev -= tsl.iW; tsl.source = incv(tsl.source); tsl.vdW += tsl.dWx;
vdW_nocarry += dW_nocarry;
}
while (tsl.Ev<0) {
tsl.Ev += tsl.iW; tsl.source = decv(tsl.source); tsl.vdW -= tsl.dWx;
vdW_nocarry -= dW_nocarry;
}
/* End of second innermost loop */
}
tsl.end = zb.colour_buffer+sar16(b->v[X])+sar16(b->v[Y])*zb.row_width
-(g_divisor<0);
while (zb.bot.count--) {
/* Start of second innermost loop */
#if SIZE==256 && LIGHT
ScanLinePIZ2TIP256();
#elif SIZE==256 && !LIGHT
ScanLinePIZ2TP256();
#elif SIZE==64 && LIGHT
ScanLinePIZ2TIP64();
#elif SIZE==64 && !LIGHT
ScanLinePIZ2TP64();
#elif SIZE==1024 && !LIGHT
ScanLinePIZ2TP1024();
#elif SIZE==1024 && LIGHT
ScanLinePIZ2TIP1024();
#endif
zb.bot.f += zb.bot.d_f;
carry = (unsigned)zb.bot.f < (unsigned)zb.bot.d_f;
tsl.end += zb.bot.d_i+carry;
zb.main.f += zb.main.d_f;
carry = (unsigned)zb.main.f < (unsigned)zb.main.d_f;
tsl.iW += dW_nocarry;
tsl.Eu += -udW_nocarry;
tsl.Ev += -vdW_nocarry;
tsl.start += zb.main.d_i+carry;
tsl.zstart += zb.main.d_i+carry << 1;
#if LIGHT
zb.pi.current += zb.pi.d_nocarry;
#endif
zb.pz.current += zb.pz.d_nocarry;
if (carry) {
tsl.iW +=idWx;
tsl.Eu += -tsl.udW;
tsl.Ev += -tsl.vdW;
#if LIGHT
zb.pi.current += zb.pi.grad_x;
#endif
zb.pz.current += zb.pz.grad_x;
}
if ((signed)tsl.iW<0) return;
while (tsl.Eu>=(signed)tsl.iW) {
tsl.Eu -= tsl.iW; tsl.source = incu(tsl.source); tsl.udW += tsl.dWx;
udW_nocarry += dW_nocarry;
}
while (tsl.Eu<0) {
tsl.Eu += tsl.iW; tsl.source = decu(tsl.source); tsl.udW -= tsl.dWx;
udW_nocarry -= dW_nocarry;
}
while (tsl.Ev>=(signed)tsl.iW) {
tsl.Ev -= tsl.iW; tsl.source = incv(tsl.source); tsl.vdW += tsl.dWx;
vdW_nocarry += dW_nocarry;
}
while (tsl.Ev<0) {
tsl.Ev += tsl.iW; tsl.source = decv(tsl.source); tsl.vdW -= tsl.dWx;
vdW_nocarry -= dW_nocarry;
}
/* End of second innermost loop */
}
}
#undef decu
#undef decv
#undef incu
#undef incv