2014年11月1日星期六(DEMO9-3模型纹理读取)
这一节理论很简单,无非就是纹理坐标通过插值和采样两种方式组成的。这节新加的内容就是对模型中的纹理进行了处理。
void ddraw_math::Draw_Textured_TriangleFS16( POLYF4DV2_PTR face, UCHAR * _dest_buffer, int mem_pitch ) // bytes per line, 320, 640 etc.
{
// this function draws a textured triangle in 16-bit mode with flat shading
UCHAR logbase2ofx[513] =
{
0,0,1,1,2,2,2,2,3,3,3,3,3,3,3,3, 4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,
5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5, 5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6, 6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7, 7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8, 8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,
};
int v0=0,
v1=1,
v2=2,
temp=0,
tri_type = TRI_TYPE_NONE,
irestart = INTERP_LHS;
int dx,dy,dyl,dyr, // general deltas
u,v,
du,dv,
xi,yi, // the current interpolated x,y
ui,vi, // the current interpolated u,v
index_x,index_y, // looping vars
x,y, // hold general x,y
xstart,
xend,
ystart,
yrestart,
yend,
xl,
dxdyl,
xr,
dxdyr,
dudyl,
ul,
dvdyl,
vl,
dudyr,
ur,
dvdyr,
vr;
USHORT r_base, g_base, b_base,
r_textel, g_textel, b_textel, textel;
int x0,y0,tu0,tv0, // cached vertices
x1,y1,tu1,tv1,
x2,y2,tu2,tv2;
USHORT *screen_ptr = NULL,
*screen_line = NULL,
*textmap = NULL,
*dest_buffer = (USHORT *)_dest_buffer;
#ifdef DEBUG_ON
// track rendering stats
debug_polys_rendered_per_frame++;
#endif
// extract texture map
textmap = (USHORT *)face->texture->buffer;
// extract base 2 of texture width
int texture_shift2 = logbase2ofx[face->texture->width];
// adjust memory pitch to words, divide by 2
mem_pitch >>=1;
// first trivial clipping rejection tests
if (((face->tvlist[0].y < m_min_clip_y) &&
(face->tvlist[1].y < m_min_clip_y) &&
(face->tvlist[2].y < m_min_clip_y)) ||
((face->tvlist[0].y > m_max_clip_y) &&
(face->tvlist[1].y > m_max_clip_y) &&
(face->tvlist[2].y > m_max_clip_y)) ||
((face->tvlist[0].x < m_min_clip_x) &&
(face->tvlist[1].x < m_min_clip_x) &&
(face->tvlist[2].x < m_min_clip_x)) ||
((face->tvlist[0].x > m_max_clip_x) &&
(face->tvlist[1].x > m_max_clip_x) &&
(face->tvlist[2].x > m_max_clip_x)))
return;
// degenerate triangle
if ( ((face->tvlist[0].x==face->tvlist[1].x) && (face->tvlist[1].x==face->tvlist[2].x)) ||
((face->tvlist[0].y==face->tvlist[1].y) && (face->tvlist[1].y==face->tvlist[2].y)))
return;
// sort vertices
if (face->tvlist[v1].y < face->tvlist[v0].y)
{SWAP(v0,v1,temp);}
if (face->tvlist[v2].y < face->tvlist[v0].y)
{SWAP(v0,v2,temp);}
if (face->tvlist[v2].y < face->tvlist[v1].y)
{SWAP(v1,v2,temp);}
// now test for trivial flat sided cases
if (face->tvlist[v0].y==face->tvlist[v1].y)
{
// set triangle type
tri_type = TRI_TYPE_FLAT_TOP;
// sort vertices left to right
if (face->tvlist[v1].x < face->tvlist[v0].x)
{SWAP(v0,v1,temp);}
} // end if
else
// now test for trivial flat sided cases
if (face->tvlist[v1].y==face->tvlist[v2].y)
{
// set triangle type
tri_type = TRI_TYPE_FLAT_BOTTOM;
// sort vertices left to right
if (face->tvlist[v2].x < face->tvlist[v1].x)
{SWAP(v1,v2,temp);}
} // end if
else
{
// must be a general triangle
tri_type = TRI_TYPE_GENERAL;
} // end else
// extract base color of lit poly, so we can modulate texture a bit
// for lighting
_RGB565FROM16BIT(face->lit_color[0], &r_base, &g_base, &b_base);
// extract vertices for processing, now that we have order
x0 = (int)(face->tvlist[v0].x+0.5);
y0 = (int)(face->tvlist[v0].y+0.5);
tu0 = (int)(face->tvlist[v0].u0);
tv0 = (int)(face->tvlist[v0].v0);
x1 = (int)(face->tvlist[v1].x+0.5);
y1 = (int)(face->tvlist[v1].y+0.5);
tu1 = (int)(face->tvlist[v1].u0);
tv1 = (int)(face->tvlist[v1].v0);
x2 = (int)(face->tvlist[v2].x+0.5);
y2 = (int)(face->tvlist[v2].y+0.5);
tu2 = (int)(face->tvlist[v2].u0);
tv2 = (int)(face->tvlist[v2].v0);
// set interpolation restart value
yrestart = y1;
// what kind of triangle
if (tri_type & TRI_TYPE_FLAT_MASK)
{
if (tri_type == TRI_TYPE_FLAT_TOP)
{
// compute all deltas
dy = (y2 - y0);
dxdyl = ((x2 - x0) << FIXP16_SHIFT)/dy;
dudyl = ((tu2 - tu0) << FIXP16_SHIFT)/dy;
dvdyl = ((tv2 - tv0) << FIXP16_SHIFT)/dy;
dxdyr = ((x2 - x1) << FIXP16_SHIFT)/dy;
dudyr = ((tu2 - tu1) << FIXP16_SHIFT)/dy;
dvdyr = ((tv2 - tv1) << FIXP16_SHIFT)/dy;
// test for y clipping
if (y0 < m_min_clip_y)
{
// compute overclip
dy = (m_min_clip_y - y0);
// computer new LHS starting values
xl = dxdyl*dy + (x0 << FIXP16_SHIFT);
ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
// compute new RHS starting values
xr = dxdyr*dy + (x1 << FIXP16_SHIFT);
ur = dudyr*dy + (tu1 << FIXP16_SHIFT);
vr = dvdyr*dy + (tv1 << FIXP16_SHIFT);
// compute new starting y
ystart = m_min_clip_y;
} // end if
else
{
// no clipping
// set starting values
xl = (x0 << FIXP16_SHIFT);
xr = (x1 << FIXP16_SHIFT);
ul = (tu0 << FIXP16_SHIFT);
vl = (tv0 << FIXP16_SHIFT);
ur = (tu1 << FIXP16_SHIFT);
vr = (tv1 << FIXP16_SHIFT);
// set starting y
ystart = y0;
} // end else
} // end if flat top
else
{
// must be flat bottom
// compute all deltas
dy = (y1 - y0);
dxdyl = ((x1 - x0) << FIXP16_SHIFT)/dy;
dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dy;
dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dy;
dxdyr = ((x2 - x0) << FIXP16_SHIFT)/dy;
dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dy;
dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dy;
// test for y clipping
if (y0 < m_min_clip_y)
{
// compute overclip
dy = (m_min_clip_y - y0);
// computer new LHS starting values
xl = dxdyl*dy + (x0 << FIXP16_SHIFT);
ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
// compute new RHS starting values
xr = dxdyr*dy + (x0 << FIXP16_SHIFT);
ur = dudyr*dy + (tu0 << FIXP16_SHIFT);
vr = dvdyr*dy + (tv0 << FIXP16_SHIFT);
// compute new starting y
ystart = m_min_clip_y;
} // end if
else
{
// no clipping
// set starting values
xl = (x0 << FIXP16_SHIFT);
xr = (x0 << FIXP16_SHIFT);
ul = (tu0 << FIXP16_SHIFT);
vl = (tv0 << FIXP16_SHIFT);
ur = (tu0 << FIXP16_SHIFT);
vr = (tv0 << FIXP16_SHIFT);
// set starting y
ystart = y0;
} // end else
} // end else flat bottom
// test for bottom clip, always
if ((yend = y2) > m_max_clip_y)
yend = m_max_clip_y;
// test for horizontal clipping
if ((x0 < m_min_clip_x) || (x0 > m_max_clip_x) ||
(x1 < m_min_clip_x) || (x1 > m_max_clip_x) ||
(x2 < m_min_clip_x) || (x2 > m_max_clip_x))
{
// clip version
// point screen ptr to starting line
screen_ptr = dest_buffer + (ystart * mem_pitch);
for (yi = ystart; yi<=yend; yi++)
{
// compute span endpoints
xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
xend = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
// compute starting points for u,v interpolants
ui = ul + FIXP16_ROUND_UP;
vi = vl + FIXP16_ROUND_UP;
// compute u,v interpolants
if ((dx = (xend - xstart))>0)
{
du = (ur - ul)/dx;
dv = (vr - vl)/dx;
} // end if
else
{
du = (ur - ul);
dv = (vr - vl);
} // end else
///
// test for x clipping, LHS
if (xstart < m_min_clip_x)
{
// compute x overlap
dx = m_min_clip_x - xstart;
// slide interpolants over
ui+=dx*du;
vi+=dx*dv;
// reset vars
xstart = m_min_clip_x;
} // end if
// test for x clipping RHS
if (xend > m_max_clip_x)
xend = m_max_clip_x;
///
// draw span
for (xi=xstart; xi<=xend; xi++)
{
// write textel
// get textel first
textel = textmap[(ui >> FIXP16_SHIFT) + ((vi >> FIXP16_SHIFT) << texture_shift2)];
// extract rgb components
r_textel = ((textel >> 11) );
g_textel = ((textel >> 5) & 0x3f);
b_textel = (textel & 0x1f);
// modulate textel with lit background color
r_textel*=r_base;
g_textel*=g_base;
b_textel*=b_base;
// finally write pixel, note that we did the math such that the results are r*32, g*64, b*32
// hence we need to divide the results by 32,64,32 respetively, BUT since we need to shift
// the results to fit into the destination 5.6.5 word, we can take advantage of the shifts
// and they all cancel out for the most part, but we will need logical anding, we will do
// it later when we optimize more...
screen_ptr[xi] = ((b_textel >> 5) + ((g_textel >> 6) << 5) + ((r_textel >> 5) << 11));
// interpolate u,v
ui+=du;
vi+=dv;
} // end for xi
// interpolate u,v,x along right and left edge
xl+=dxdyl;
ul+=dudyl;
vl+=dvdyl;
xr+=dxdyr;
ur+=dudyr;
vr+=dvdyr;
// advance screen ptr
screen_ptr+=mem_pitch;
} // end for y
} // end if clip
else
{
// non-clip version
// point screen ptr to starting line
screen_ptr = dest_buffer + (ystart * mem_pitch);
for (yi = ystart; yi<=yend; yi++)
{
// compute span endpoints
xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
xend = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
// compute starting points for u,v interpolants
ui = ul + FIXP16_ROUND_UP;
vi = vl + FIXP16_ROUND_UP;
// compute u,v interpolants
if ((dx = (xend - xstart))>0)
{
du = (ur - ul)/dx;
dv = (vr - vl)/dx;
} // end if
else
{
du = (ur - ul);
dv = (vr - vl);
} // end else
// draw span
for (xi=xstart; xi<=xend; xi++)
{
// write textel
// get textel first
textel = textmap[(ui >> FIXP16_SHIFT) + ((vi >> FIXP16_SHIFT) << texture_shift2)];
// extract rgb components
r_textel = ((textel >> 11) );
g_textel = ((textel >> 5) & 0x3f);
b_textel = (textel & 0x1f);
// modulate textel with lit background color
r_textel*=r_base;
g_textel*=g_base;
b_textel*=b_base;
// finally write pixel, note that we did the math such that the results are r*32, g*64, b*32
// hence we need to divide the results by 32,64,32 respetively, BUT since we need to shift
// the results to fit into the destination 5.6.5 word, we can take advantage of the shifts
// and they all cancel out for the most part, but we will need logical anding, we will do
// it later when we optimize more...
screen_ptr[xi] = ((b_textel >> 5) + ((g_textel >> 6) << 5) + ((r_textel >> 5) << 11));
// interpolate u,v
ui+=du;
vi+=dv;
} // end for xi
// interpolate u,v,x along right and left edge
xl+=dxdyl;
ul+=dudyl;
vl+=dvdyl;
xr+=dxdyr;
ur+=dudyr;
vr+=dvdyr;
// advance screen ptr
screen_ptr+=mem_pitch;
} // end for y
} // end if non-clipped
} // end if
else
if (tri_type==TRI_TYPE_GENERAL)
{
// first test for bottom clip, always
if ((yend = y2) > m_max_clip_y)
yend = m_max_clip_y;
// pre-test y clipping status
if (y1 < m_min_clip_y)
{
// compute all deltas
// LHS
dyl = (y2 - y1);
dxdyl = ((x2 - x1) << FIXP16_SHIFT)/dyl;
dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;
dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;
// RHS
dyr = (y2 - y0);
dxdyr = ((x2 - x0) << FIXP16_SHIFT)/dyr;
dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;
dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;
// compute overclip
dyr = (m_min_clip_y - y0);
dyl = (m_min_clip_y - y1);
// computer new LHS starting values
xl = dxdyl*dyl + (x1 << FIXP16_SHIFT);
ul = dudyl*dyl + (tu1 << FIXP16_SHIFT);
vl = dvdyl*dyl + (tv1 << FIXP16_SHIFT);
// compute new RHS starting values
xr = dxdyr*dyr + (x0 << FIXP16_SHIFT);
ur = dudyr*dyr + (tu0 << FIXP16_SHIFT);
vr = dvdyr*dyr + (tv0 << FIXP16_SHIFT);
// compute new starting y
ystart = m_min_clip_y;
// test if we need swap to keep rendering left to right
if (dxdyr > dxdyl)
{
SWAP(dxdyl,dxdyr,temp);
SWAP(dudyl,dudyr,temp);
SWAP(dvdyl,dvdyr,temp);
SWAP(xl,xr,temp);
SWAP(ul,ur,temp);
SWAP(vl,vr,temp);
SWAP(x1,x2,temp);
SWAP(y1,y2,temp);
SWAP(tu1,tu2,temp);
SWAP(tv1,tv2,temp);
// set interpolation restart
irestart = INTERP_RHS;
} // end if
} // end if
else
if (y0 < m_min_clip_y)
{
// compute all deltas
// LHS
dyl = (y1 - y0);
dxdyl = ((x1 - x0) << FIXP16_SHIFT)/dyl;
dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dyl;
dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dyl;
// RHS
dyr = (y2 - y0);
dxdyr = ((x2 - x0) << FIXP16_SHIFT)/dyr;
dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;
dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;
// compute overclip
dy = (m_min_clip_y - y0);
// computer new LHS starting values
xl = dxdyl*dy + (x0 << FIXP16_SHIFT);
ul = dudyl*dy + (tu0 << FIXP16_SHIFT);
vl = dvdyl*dy + (tv0 << FIXP16_SHIFT);
// compute new RHS starting values
xr = dxdyr*dy + (x0 << FIXP16_SHIFT);
ur = dudyr*dy + (tu0 << FIXP16_SHIFT);
vr = dvdyr*dy + (tv0 << FIXP16_SHIFT);
// compute new starting y
ystart = m_min_clip_y;
// test if we need swap to keep rendering left to right
if (dxdyr < dxdyl)
{
SWAP(dxdyl,dxdyr,temp);
SWAP(dudyl,dudyr,temp);
SWAP(dvdyl,dvdyr,temp);
SWAP(xl,xr,temp);
SWAP(ul,ur,temp);
SWAP(vl,vr,temp);
SWAP(x1,x2,temp);
SWAP(y1,y2,temp);
SWAP(tu1,tu2,temp);
SWAP(tv1,tv2,temp);
// set interpolation restart
irestart = INTERP_RHS;
} // end if
} // end if
else
{
// no initial y clipping
// compute all deltas
// LHS
dyl = (y1 - y0);
dxdyl = ((x1 - x0) << FIXP16_SHIFT)/dyl;
dudyl = ((tu1 - tu0) << FIXP16_SHIFT)/dyl;
dvdyl = ((tv1 - tv0) << FIXP16_SHIFT)/dyl;
// RHS
dyr = (y2 - y0);
dxdyr = ((x2 - x0) << FIXP16_SHIFT)/dyr;
dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dyr;
dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dyr;
// no clipping y
// set starting values
xl = (x0 << FIXP16_SHIFT);
xr = (x0 << FIXP16_SHIFT);
ul = (tu0 << FIXP16_SHIFT);
vl = (tv0 << FIXP16_SHIFT);
ur = (tu0 << FIXP16_SHIFT);
vr = (tv0 << FIXP16_SHIFT);
// set starting y
ystart = y0;
// test if we need swap to keep rendering left to right
if (dxdyr < dxdyl)
{
SWAP(dxdyl,dxdyr,temp);
SWAP(dudyl,dudyr,temp);
SWAP(dvdyl,dvdyr,temp);
SWAP(xl,xr,temp);
SWAP(ul,ur,temp);
SWAP(vl,vr,temp);
SWAP(x1,x2,temp);
SWAP(y1,y2,temp);
SWAP(tu1,tu2,temp);
SWAP(tv1,tv2,temp);
// set interpolation restart
irestart = INTERP_RHS;
} // end if
} // end else
// test for horizontal clipping
if ((x0 < m_min_clip_x) || (x0 > m_max_clip_x) ||
(x1 < m_min_clip_x) || (x1 > m_max_clip_x) ||
(x2 < m_min_clip_x) || (x2 > m_max_clip_x))
{
// clip version
// x clipping
// point screen ptr to starting line
screen_ptr = dest_buffer + (ystart * mem_pitch);
for (yi = ystart; yi<=yend; yi++)
{
// compute span endpoints
xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
xend = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
// compute starting points for u,v interpolants
ui = ul + FIXP16_ROUND_UP;
vi = vl + FIXP16_ROUND_UP;
// compute u,v interpolants
if ((dx = (xend - xstart))>0)
{
du = (ur - ul)/dx;
dv = (vr - vl)/dx;
} // end if
else
{
du = (ur - ul);
dv = (vr - vl);
} // end else
///
// test for x clipping, LHS
if (xstart < m_min_clip_x)
{
// compute x overlap
dx = m_min_clip_x - xstart;
// slide interpolants over
ui+=dx*du;
vi+=dx*dv;
// set x to left clip edge
xstart = m_min_clip_x;
} // end if
// test for x clipping RHS
if (xend > m_max_clip_x)
xend = m_max_clip_x;
///
// draw span
for (xi=xstart; xi<=xend; xi++)
{
// write textel
//screen_ptr[xi] = textmap[(ui >> FIXP16_SHIFT) + ((vi >> FIXP16_SHIFT) << texture_shift2)];
// get textel first
textel = textmap[(ui >> FIXP16_SHIFT) + ((vi >> FIXP16_SHIFT) << texture_shift2)];
// extract rgb components
r_textel = ((textel >> 11) );
g_textel = ((textel >> 5) & 0x3f);
b_textel = (textel & 0x1f);
// modulate textel with lit background color
r_textel*=r_base;
g_textel*=g_base;
b_textel*=b_base;
// finally write pixel, note that we did the math such that the results are r*32, g*64, b*32
// hence we need to divide the results by 32,64,32 respetively, BUT since we need to shift
// the results to fit into the destination 5.6.5 word, we can take advantage of the shifts
// and they all cancel out for the most part, but we will need logical anding, we will do
// it later when we optimize more...
screen_ptr[xi] = ((b_textel >> 5) + ((g_textel >> 6) << 5) + ((r_textel >> 5) << 11));
// interpolate u,v
ui+=du;
vi+=dv;
} // end for xi
// interpolate u,v,x along right and left edge
xl+=dxdyl;
ul+=dudyl;
vl+=dvdyl;
xr+=dxdyr;
ur+=dudyr;
vr+=dvdyr;
// advance screen ptr
screen_ptr+=mem_pitch;
// test for yi hitting second region, if so change interpolant
if (yi==yrestart)
{
// test interpolation side change flag
if (irestart == INTERP_LHS)
{
// LHS
dyl = (y2 - y1);
dxdyl = ((x2 - x1) << FIXP16_SHIFT)/dyl;
dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;
dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;
// set starting values
xl = (x1 << FIXP16_SHIFT);
ul = (tu1 << FIXP16_SHIFT);
vl = (tv1 << FIXP16_SHIFT);
// interpolate down on LHS to even up
xl+=dxdyl;
ul+=dudyl;
vl+=dvdyl;
} // end if
else
{
// RHS
dyr = (y1 - y2);
dxdyr = ((x1 - x2) << FIXP16_SHIFT)/dyr;
dudyr = ((tu1 - tu2) << FIXP16_SHIFT)/dyr;
dvdyr = ((tv1 - tv2) << FIXP16_SHIFT)/dyr;
// set starting values
xr = (x2 << FIXP16_SHIFT);
ur = (tu2 << FIXP16_SHIFT);
vr = (tv2 << FIXP16_SHIFT);
// interpolate down on RHS to even up
xr+=dxdyr;
ur+=dudyr;
vr+=dvdyr;
} // end else
} // end if
} // end for y
} // end if
else
{
// no x clipping
// point screen ptr to starting line
screen_ptr = dest_buffer + (ystart * mem_pitch);
for (yi = ystart; yi<=yend; yi++)
{
// compute span endpoints
xstart = ((xl + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
xend = ((xr + FIXP16_ROUND_UP) >> FIXP16_SHIFT);
// compute starting points for u,v interpolants
ui = ul + FIXP16_ROUND_UP;
vi = vl + FIXP16_ROUND_UP;
// compute u,v interpolants
if ((dx = (xend - xstart))>0)
{
du = (ur - ul)/dx;
dv = (vr - vl)/dx;
} // end if
else
{
du = (ur - ul);
dv = (vr - vl);
} // end else
// draw span
for (xi=xstart; xi<=xend; xi++)
{
// write textel
// get textel first
textel = textmap[(ui >> FIXP16_SHIFT) + ((vi >> FIXP16_SHIFT) << texture_shift2)];
// extract rgb components
r_textel = ((textel >> 11) );
g_textel = ((textel >> 5) & 0x3f);
b_textel = (textel & 0x1f);
// modulate textel with lit background color
r_textel*=r_base;
g_textel*=g_base;
b_textel*=b_base;
// finally write pixel, note that we did the math such that the results are r*32, g*64, b*32
// hence we need to divide the results by 32,64,32 respetively, BUT since we need to shift
// the results to fit into the destination 5.6.5 word, we can take advantage of the shifts
// and they all cancel out for the most part, but we will need logical anding, we will do
// it later when we optimize more...
screen_ptr[xi] = ((b_textel >> 5) + ((g_textel >> 6) << 5) + ((r_textel >> 5) << 11));
// interpolate u,v
ui+=du;
vi+=dv;
} // end for xi
// interpolate u,v,x along right and left edge
xl+=dxdyl;
ul+=dudyl;
vl+=dvdyl;
xr+=dxdyr;
ur+=dudyr;
vr+=dvdyr;
// advance screen ptr
screen_ptr+=mem_pitch;
// test for yi hitting second region, if so change interpolant
if (yi==yrestart)
{
// test interpolation side change flag
if (irestart == INTERP_LHS)
{
// LHS
dyl = (y2 - y1);
dxdyl = ((x2 - x1) << FIXP16_SHIFT)/dyl;
dudyl = ((tu2 - tu1) << FIXP16_SHIFT)/dyl;
dvdyl = ((tv2 - tv1) << FIXP16_SHIFT)/dyl;
// set starting values
xl = (x1 << FIXP16_SHIFT);
ul = (tu1 << FIXP16_SHIFT);
vl = (tv1 << FIXP16_SHIFT);
// interpolate down on LHS to even up
xl+=dxdyl;
ul+=dudyl;
vl+=dvdyl;
} // end if
else
{
// RHS
dyr = (y1 - y2);
dxdyr = ((x1 - x2) << FIXP16_SHIFT)/dyr;
dudyr = ((tu1 - tu2) << FIXP16_SHIFT)/dyr;
dvdyr = ((tv1 - tv2) << FIXP16_SHIFT)/dyr;
// set starting values
xr = (x2 << FIXP16_SHIFT);
ur = (tu2 << FIXP16_SHIFT);
vr = (tv2 << FIXP16_SHIFT);
// interpolate down on RHS to even up
xr+=dxdyr;
ur+=dudyr;
vr+=dvdyr;
} // end else
} // end if
} // end for y
} // end else
} // end if
} // end Draw_Textured_TriangleFS16