t3dlib7.cpp
资源名称:Source.rar [点击查看]
上传用户:husern
上传日期:2018-01-20
资源大小:42486k
文件大小:512k
源码类别:
游戏
开发平台:
Visual C++
- // 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 < min_clip_x) || (x0 > max_clip_x) ||
- (x1 < min_clip_x) || (x1 > max_clip_x) ||
- (x2 < min_clip_x) || (x2 > 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 < min_clip_x)
- {
- // compute x overlap
- dx = min_clip_x - xstart;
- // slide interpolants over
- ui+=dx*du;
- vi+=dx*dv;
- // set x to left clip edge
- xstart = min_clip_x;
- } // end if
- // test for x clipping RHS
- if (xend > max_clip_x)
- xend = 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
- /////////////////////////////////////////////////////////////////////////////
- void Draw_Top_Tri2_16(float x1, float y1,
- float x2, float y2,
- float x3, float y3,
- int color,
- UCHAR *_dest_buffer, int mempitch)
- {
- // this function draws a triangle that has a flat top
- float dx_right, // the dx/dy ratio of the right edge of line
- dx_left, // the dx/dy ratio of the left edge of line
- xs,xe, // the starting and ending points of the edges
- height, // the height of the triangle
- temp_x, // used during sorting as temps
- temp_y,
- right, // used by clipping
- left;
- int iy1,iy3,loop_y; // integers for y looping
- // cast dest buffer to ushort
- USHORT *dest_buffer = (USHORT *)_dest_buffer;
- // destination address of next scanline
- USHORT *dest_addr = NULL;
- // recompute mempitch in 16-bit words
- mempitch = (mempitch >> 1);
- // test order of x1 and x2
- if (x2 < x1)
- {
- SWAP(x1,x2,temp_x);
- } // end if swap
- // compute delta's
- height = y3 - y1;
- dx_left = (x3-x1) / height;
- dx_right = (x3-x2) / height;
- // set starting points
- xs = x1;
- xe = x2;
- #if (RASTERIZER_MODE==RASTERIZER_ACCURATE)
- // perform y clipping
- if (y1 < min_clip_y)
- {
- // compute new xs and ys
- xs = xs+dx_left*(-y1+min_clip_y);
- xe = xe+dx_right*(-y1+min_clip_y);
- // reset y1
- y1 = min_clip_y;
- // make sure top left fill convention is observed
- iy1 = y1;
- } // end if top is off screen
- else
- {
- // make sure top left fill convention is observed
- iy1 = ceil(y1);
- // bump xs and xe appropriately
- xs = xs+dx_left*(iy1-y1);
- xe = xe+dx_right*(iy1-y1);
- } // end else
- if (y3 > max_clip_y)
- {
- // clip y
- y3 = max_clip_y;
- // make sure top left fill convention is observed
- iy3 = y3-1;
- } // end if
- else
- {
- // make sure top left fill convention is observed
- iy3 = ceil(y3)-1;
- } // end else
- #endif
- #if ( (RASTERIZER_MODE==RASTERIZER_FAST) || (RASTERIZER_MODE==RASTERIZER_FASTEST) )
- // perform y clipping
- if (y1 < min_clip_y)
- {
- // compute new xs and ys
- xs = xs+dx_left*(-y1+min_clip_y);
- xe = xe+dx_right*(-y1+min_clip_y);
- // reset y1
- y1 = min_clip_y;
- } // end if top is off screen
- if (y3 > max_clip_y)
- y3 = max_clip_y;
- // make sure top left fill convention is observed
- iy1 = ceil(y1);
- iy3 = ceil(y3)-1;
- #endif
- //Write_Error("nTri-Top: xs=%f, xe=%f, y1=%f, y3=%f, iy1=%d, iy3=%d", xs,xe,y1,y3,iy1,iy3);
- // compute starting address in video memory
- dest_addr = dest_buffer + iy1*mempitch;
- // test if x clipping is needed
- if (x1 >= min_clip_x && x1 <= max_clip_x &&
- x2 >= min_clip_x && x2 <= max_clip_x &&
- x3 >= min_clip_x && x3 <= max_clip_x)
- {
- // draw the triangle
- for (loop_y=iy1; loop_y <= iy3; loop_y++, dest_addr+=mempitch)
- {
- //Write_Error("nxs=%f, xe=%f", xs,xe);
- // draw the line
- Mem_Set_WORD(dest_addr+(unsigned int)(xs),color,(unsigned int)((int)xe-(int)xs+1));
- // adjust starting point and ending point
- xs+=dx_left;
- xe+=dx_right;
- } // end for
- } // end if no x clipping needed
- else
- {
- // clip x axis with slower version
- // draw the triangle
- for (loop_y=iy1; loop_y <= iy3; loop_y++, dest_addr+=mempitch)
- {
- // do x clip
- left = xs;
- right = xe;
- // adjust starting point and ending point
- xs+=dx_left;
- xe+=dx_right;
- // clip line
- if (left < min_clip_x)
- {
- left = min_clip_x;
- if (right < min_clip_x)
- continue;
- }
- if (right > max_clip_x)
- {
- right = max_clip_x;
- if (left > max_clip_x)
- continue;
- }
- //Write_Error("nleft=%f, right=%f", left,right);
- // draw the line
- Mem_Set_WORD(dest_addr+(unsigned int)(left),color,(unsigned int)((int)right-(int)left+1));
- } // end for
- } // end else x clipping needed
- } // end Draw_Top_Tri2_16
- /////////////////////////////////////////////////////////////////////////////
- void Draw_Bottom_Tri2_16(float x1, float y1,
- float x2, float y2,
- float x3, float y3,
- int color,
- UCHAR *_dest_buffer, int mempitch)
- {
- // this function draws a triangle that has a flat bottom
- float dx_right, // the dx/dy ratio of the right edge of line
- dx_left, // the dx/dy ratio of the left edge of line
- xs,xe, // the starting and ending points of the edges
- height, // the height of the triangle
- temp_x, // used during sorting as temps
- temp_y,
- right, // used by clipping
- left;
- int iy1,iy3,loop_y;
- // cast dest buffer to ushort
- USHORT *dest_buffer = (USHORT *)_dest_buffer;
- // destination address of next scanline
- USHORT *dest_addr = NULL;
- // recompute mempitch in 16-bit words
- mempitch = (mempitch >> 1);
- // test order of x1 and x2
- if (x3 < x2)
- {
- SWAP(x2,x3,temp_x);
- } // end if swap
- // compute delta's
- height = y3 - y1;
- dx_left = (x2-x1)/height;
- dx_right = (x3-x1)/height;
- // set starting points
- xs = x1;
- xe = x1;
- #if (RASTERIZER_MODE==RASTERIZER_ACCURATE)
- // perform y clipping
- if (y1 < min_clip_y)
- {
- // compute new xs and ys
- xs = xs+dx_left*(-y1+min_clip_y);
- xe = xe+dx_right*(-y1+min_clip_y);
- // reset y1
- y1 = min_clip_y;
- // make sure top left fill convention is observed
- iy1 = y1;
- } // end if top is off screen
- else
- {
- // make sure top left fill convention is observed
- iy1 = ceil(y1);
- // bump xs and xe appropriately
- xs = xs+dx_left*(iy1-y1);
- xe = xe+dx_right*(iy1-y1);
- } // end else
- if (y3 > max_clip_y)
- {
- // clip y
- y3 = max_clip_y;
- // make sure top left fill convention is observed
- iy3 = y3-1;
- } // end if
- else
- {
- // make sure top left fill convention is observed
- iy3 = ceil(y3)-1;
- } // end else
- #endif
- #if ( (RASTERIZER_MODE==RASTERIZER_FAST) || (RASTERIZER_MODE==RASTERIZER_FASTEST) )
- // perform y clipping
- if (y1 < min_clip_y)
- {
- // compute new xs and ys
- xs = xs+dx_left*(-y1+min_clip_y);
- xe = xe+dx_right*(-y1+min_clip_y);
- // reset y1
- y1 = min_clip_y;
- } // end if top is off screen
- if (y3 > max_clip_y)
- y3 = max_clip_y;
- // make sure top left fill convention is observed
- iy1 = ceil(y1);
- iy3 = ceil(y3)-1;
- #endif
- //Write_Error("nTri-Bottom: xs=%f, xe=%f, y1=%f, y3=%f, iy1=%d, iy3=%d", xs,xe,y1,y3,iy1,iy3);
- // compute starting address in video memory
- dest_addr = dest_buffer + iy1*mempitch;
- // test if x clipping is needed
- if (x1 >= min_clip_x && x1 <= max_clip_x &&
- x2 >= min_clip_x && x2 <= max_clip_x &&
- x3 >= min_clip_x && x3 <= max_clip_x)
- {
- // draw the triangle
- for (loop_y = iy1; loop_y <= iy3; loop_y++, dest_addr+=mempitch)
- {
- //Write_Error("nxs=%f, xe=%f", xs,xe);
- // draw the line
- Mem_Set_WORD(dest_addr+(unsigned int)(xs),color,(unsigned int)((int)xe-(int)xs+1));
- // adjust starting point and ending point
- xs+=dx_left;
- xe+=dx_right;
- } // end for
- } // end if no x clipping needed
- else
- {
- // clip x axis with slower version
- // draw the triangle
- for (loop_y = iy1; loop_y <= iy3; loop_y++,dest_addr+=mempitch)
- {
- // do x clip
- left = xs;
- right = xe;
- // adjust starting point and ending point
- xs+=dx_left;
- xe+=dx_right;
- // clip line
- if (left < min_clip_x)
- {
- left = min_clip_x;
- if (right < min_clip_x)
- continue;
- }
- if (right > max_clip_x)
- {
- right = max_clip_x;
- if (left > max_clip_x)
- continue;
- }
- //Write_Error("nleft=%f, right=%f", left,right);
- // draw the line
- Mem_Set_WORD(dest_addr+(unsigned int)(left),color,(unsigned int)((int)right-(int)left+1));
- } // end for
- } // end else x clipping needed
- } // end Draw_Bottom_Tri2_16
- ///////////////////////////////////////////////////////////////////////////////
- void Draw_Triangle_2D2_16(float x1,float y1,
- float x2,float y2,
- float x3,float y3,
- int color,
- UCHAR *dest_buffer, int mempitch)
- {
- // this function draws a triangle on the destination buffer
- // it decomposes all triangles into a pair of flat top, flat bottom
- float temp_x, // used for sorting
- temp_y,
- new_x;
- #ifdef DEBUG_ON
- // track rendering stats
- debug_polys_rendered_per_frame++;
- #endif
- // test for h lines and v lines
- if ((FCMP(x1,x2) && FCMP(x2,x3)) || (FCMP(y1,y2) && FCMP(y2,y3)))
- return;
- // sort p1,p2,p3 in ascending y order
- if (y2 < y1)
- {
- SWAP(x1,x2,temp_x);
- SWAP(y1,y2,temp_y);
- } // end if
- // now we know that p1 and p2 are in order
- if (y3 < y1)
- {
- SWAP(x1,x3,temp_x);
- SWAP(y1,y3,temp_y);
- } // end if
- // finally test y3 against y2
- if (y3 < y2)
- {
- SWAP(x2,x3,temp_x);
- SWAP(y2,y3,temp_y);
- } // end if
- // do trivial rejection tests for clipping
- if ( y3 < min_clip_y || y1 > max_clip_y ||
- (x1 < min_clip_x && x2 < min_clip_x && x3 < min_clip_x) ||
- (x1 > max_clip_x && x2 > max_clip_x && x3 > max_clip_x) )
- return;
- // test if top of triangle is flat
- if (FCMP(y1,y2))
- {
- Draw_Top_Tri2_16(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
- } // end if
- else
- if (FCMP(y2,y3))
- {
- Draw_Bottom_Tri2_16(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
- } // end if bottom is flat
- else
- {
- // general triangle that's needs to be broken up along long edge
- new_x = x1 + (y2-y1)*(x3-x1)/(y3-y1);
- // draw each sub-triangle
- Draw_Bottom_Tri2_16(x1,y1,new_x,y2,x2,y2,color, dest_buffer, mempitch);
- Draw_Top_Tri2_16(x2,y2,new_x,y2,x3,y3,color, dest_buffer, mempitch);
- } // end else
- } // end Draw_Triangle_2D2_16
- ///////////////////////////////////////////////////////////////////////////////
- void Draw_Top_Tri2(float x1,float y1,
- float x2,float y2,
- float x3,float y3,
- int color,
- UCHAR *dest_buffer, int mempitch)
- {
- // this function draws a triangle that has a flat top
- float dx_right, // the dx/dy ratio of the right edge of line
- dx_left, // the dx/dy ratio of the left edge of line
- xs,xe, // the starting and ending points of the edges
- height, // the height of the triangle
- temp_x, // used during sorting as temps
- temp_y,
- right, // used by clipping
- left;
- int iy1,iy3,loop_y; // integers for y loops
- // destination address of next scanline
- UCHAR *dest_addr = NULL;
- // test order of x1 and x2
- if (x2 < x1)
- {
- SWAP(x1,x2,temp_x);
- } // end if swap
- // compute delta's
- height = y3-y1;
- dx_left = (x3-x1)/height;
- dx_right = (x3-x2)/height;
- // set starting points
- xs = x1;
- xe = x2;
- #if (RASTERIZER_MODE==RASTERIZER_ACCURATE)
- // perform y clipping
- if (y1 < min_clip_y)
- {
- // compute new xs and ys
- xs = xs+dx_left*(-y1+min_clip_y);
- xe = xe+dx_right*(-y1+min_clip_y);
- // reset y1
- y1 = min_clip_y;
- // make sure top left fill convention is observed
- iy1 = y1;
- } // end if top is off screen
- else
- {
- // make sure top left fill convention is observed
- iy1 = ceil(y1);
- // bump xs and xe appropriately
- xs = xs+dx_left*(iy1-y1);
- xe = xe+dx_right*(iy1-y1);
- } // end else
- if (y3 > max_clip_y)
- {
- // clip y
- y3 = max_clip_y;
- // make sure top left fill convention is observed
- iy3 = y3-1;
- } // end if
- else
- {
- // make sure top left fill convention is observed
- iy3 = ceil(y3)-1;
- } // end else
- #endif
- #if ( (RASTERIZER_MODE==RASTERIZER_FAST) || (RASTERIZER_MODE==RASTERIZER_FASTEST) )
- // perform y clipping
- if (y1 < min_clip_y)
- {
- // compute new xs and ys
- xs = xs+dx_left*(-y1+min_clip_y);
- xe = xe+dx_right*(-y1+min_clip_y);
- // reset y1
- y1 = min_clip_y;
- } // end if top is off screen
- if (y3 > max_clip_y)
- y3 = max_clip_y;
- // make sure top left fill convention is observed
- iy1 = ceil(y1);
- iy3 = ceil(y3)-1;
- #endif
- // compute starting address in video memory
- dest_addr = dest_buffer+iy1*mempitch;
- // test if x clipping is needed
- if (x1>=min_clip_x && x1<=max_clip_x &&
- x2>=min_clip_x && x2<=max_clip_x &&
- x3>=min_clip_x && x3<=max_clip_x)
- {
- // draw the triangle
- for (loop_y=iy1; loop_y<=iy3; loop_y++,dest_addr+=mempitch)
- {
- // draw the line
- memset((UCHAR *)dest_addr+(unsigned int)xs, color,(unsigned int)((int)xe-(int)xs+1));
- // adjust starting point and ending point
- xs+=dx_left;
- xe+=dx_right;
- } // end for
- } // end if no x clipping needed
- else
- {
- // clip x axis with slower version
- // draw the triangle
- for (temp_y=iy1; temp_y<=iy3; temp_y++,dest_addr+=mempitch)
- {
- // do x clip
- left = xs;
- right = xe;
- // adjust starting point and ending point
- xs+=dx_left;
- xe+=dx_right;
- // clip line
- if (left < min_clip_x)
- {
- left = min_clip_x;
- if (right < min_clip_x)
- continue;
- }
- if (right > max_clip_x)
- {
- right = max_clip_x;
- if (left > max_clip_x)
- continue;
- }
- // draw the line
- memset((UCHAR *)dest_addr+(unsigned int)left, color,(unsigned int)((int)right-(int)left+1));
- } // end for
- } // end else x clipping needed
- } // end Draw_Top_Tri2
- /////////////////////////////////////////////////////////////////////////////
- void Draw_Bottom_Tri2(float x1,float y1,
- float x2,float y2,
- float x3,float y3,
- int color,
- UCHAR *dest_buffer, int mempitch)
- {
- // this function draws a triangle that has a flat bottom
- float dx_right, // the dx/dy ratio of the right edge of line
- dx_left, // the dx/dy ratio of the left edge of line
- xs,xe, // the starting and ending points of the edges
- height, // the height of the triangle
- temp_x, // used during sorting as temps
- temp_y,
- right, // used by clipping
- left;
- int iy1,iy3,loop_y; // integers for y loops
- // destination address of next scanline
- UCHAR *dest_addr;
- // test order of x1 and x2
- if (x3 < x2)
- {
- SWAP(x2,x3,temp_x);
- } // end if swap
- // compute delta's
- height = y3-y1;
- dx_left = (x2-x1)/height;
- dx_right = (x3-x1)/height;
- // set starting points
- xs = x1;
- xe = x1;
- #if (RASTERIZER_MODE==RASTERIZER_ACCURATE)
- // perform y clipping
- if (y1 < min_clip_y)
- {
- // compute new xs and ys
- xs = xs+dx_left*(-y1+min_clip_y);
- xe = xe+dx_right*(-y1+min_clip_y);
- // reset y1
- y1 = min_clip_y;
- // make sure top left fill convention is observed
- iy1 = y1;
- } // end if top is off screen
- else
- {
- // make sure top left fill convention is observed
- iy1 = ceil(y1);
- // bump xs and xe appropriately
- xs = xs+dx_left*(iy1-y1);
- xe = xe+dx_right*(iy1-y1);
- } // end else
- if (y3 > max_clip_y)
- {
- // clip y
- y3 = max_clip_y;
- // make sure top left fill convention is observed
- iy3 = y3-1;
- } // end if
- else
- {
- // make sure top left fill convention is observed
- iy3 = ceil(y3)-1;
- } // end else
- #endif
- #if ( (RASTERIZER_MODE==RASTERIZER_FAST) || (RASTERIZER_MODE==RASTERIZER_FASTEST) )
- // perform y clipping
- if (y1 < min_clip_y)
- {
- // compute new xs and ys
- xs = xs+dx_left*(-y1+min_clip_y);
- xe = xe+dx_right*(-y1+min_clip_y);
- // reset y1
- y1 = min_clip_y;
- } // end if top is off screen
- if (y3 > max_clip_y)
- y3 = max_clip_y;
- // make sure top left fill convention is observed
- iy1 = ceil(y1);
- iy3 = ceil(y3)-1;
- #endif
- // compute starting address in video memory
- dest_addr = dest_buffer+iy1*mempitch;
- // test if x clipping is needed
- if (x1 >= min_clip_x && x1 <= max_clip_x &&
- x2 >= min_clip_x && x2 <= max_clip_x &&
- x3 >= min_clip_x && x3 <= max_clip_x)
- {
- // draw the triangle
- for (loop_y = iy1; loop_y <= iy3; loop_y++,dest_addr+=mempitch)
- {
- // fill the line
- memset((UCHAR *)dest_addr+(unsigned int)xs, color,(unsigned int)((int)xe-(int)xs+1));
- // adjust starting point and ending point
- xs+=dx_left;
- xe+=dx_right;
- } // end for
- } // end if no x clipping needed
- else
- {
- // clip x axis with slower version
- // draw the triangle
- for (loop_y = iy1; loop_y <= iy3; loop_y++,dest_addr+=mempitch)
- {
- // do x clip
- left = xs;
- right = xe;
- // adjust starting point and ending point
- xs+=dx_left;
- xe+=dx_right;
- // clip line
- if (left < min_clip_x)
- {
- left = min_clip_x;
- if (right < min_clip_x)
- continue;
- }
- if (right > max_clip_x)
- {
- right = max_clip_x;
- if (left > max_clip_x)
- continue;
- }
- // fill the line
- memset((UCHAR *)dest_addr+(unsigned int)left, color,(unsigned int)((int)right-(int)left+1));
- } // end for
- } // end else x clipping needed
- } // end Draw_Bottom_Tri2
- ///////////////////////////////////////////////////////////////////////////////
- void Draw_Triangle_2D2(float x1,float y1,
- float x2,float y2,
- float x3,float y3,
- int color,
- UCHAR *dest_buffer, int mempitch)
- {
- // this function draws a triangle on the destination buffer
- // it decomposes all triangles into a pair of flat top, flat bottom
- float temp_x, // used for sorting
- temp_y,
- new_x;
- #ifdef DEBUG_ON
- // track rendering stats
- debug_polys_rendered_per_frame++;
- #endif
- // test for h lines and v lines
- if ((FCMP(x1,x2) && FCMP(x2,x3)) || (FCMP(y1,y2) && FCMP(y2,y3)))
- return;
- // sort p1,p2,p3 in ascending y order
- if (y2 < y1)
- {
- SWAP(x1,x2,temp_x);
- SWAP(y1,y2,temp_y);
- } // end if
- // now we know that p1 and p2 are in order
- if (y3 < y1)
- {
- SWAP(x1,x3,temp_x);
- SWAP(y1,y3,temp_y);
- } // end if
- // finally test y3 against y2
- if (y3 < y2)
- {
- SWAP(x2,x3,temp_x);
- SWAP(y2,y3,temp_y);
- } // end if
- // do trivial rejection tests for clipping
- if ( y3 < min_clip_y || y1 > max_clip_y ||
- (x1 < min_clip_x && x2 < min_clip_x && x3<min_clip_x) ||
- (x1 > max_clip_x && x2 > max_clip_x && x3>max_clip_x) )
- return;
- // test if top of triangle is flat
- if (FCMP(y1,y2))
- {
- Draw_Top_Tri2(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
- } // end if
- else
- if (FCMP(y2,y3))
- {
- Draw_Bottom_Tri2(x1,y1,x2,y2,x3,y3,color, dest_buffer, mempitch);
- } // end if bottom is flat
- else
- {
- // general triangle that's needs to be broken up along long edge
- new_x = x1 + (y2-y1)*(x3-x1)/(y3-y1);
- // draw each sub-triangle
- Draw_Bottom_Tri2(x1,y1,new_x,y2,x2,y2,color, dest_buffer, mempitch);
- Draw_Top_Tri2(x2,y2,new_x,y2,x3,y3,color, dest_buffer, mempitch);
- } // end else
- } // end Draw_Triangle_2D2
- ////////////////////////////////////////////////////////////////////////////
- int Load_Bitmap_File2(BITMAP_FILE_PTR bitmap, char *filename)
- {
- // simply checks the file extension and calls the appropriate loader
- // .bmp or .pcx of course there must be a file extension!
- char _filename[256]; // temp string
- // copy string and upcase it
- strcpy(_filename, filename);
- _strupr(_filename);
- // check for bmp
- if (strstr(_filename, ".BMP"))
- return(Load_Bitmap_File(bitmap, _filename));
- else // pcx?
- if (strstr(_filename, ".PCX"))
- return(Load_Bitmap_PCX_File(bitmap, _filename));
- else // serious trouble
- return(0);
- } // end Load_Bitmap_File2
- ////////////////////////////////////////////////////////////////////////////
- int Load_Bitmap_PCX_File(BITMAP_FILE_PTR bitmap, char *filename)
- {
- // this function loads a PCX file into the bitmap file structure. The function
- // has three main parts: 1. load the PCX header, 2. load the image data and
- // decompress it and 3. load the palette data
- FILE *fp; // the file pointer used to open the PCX file
- PCX_HEADER pcx_header; // pcx file header
- int num_bytes, // number of bytes in current RLE run
- index, // loop variable
- count, // the total number of bytes decompressed
- width, // width of image in pixels
- height, // height of image in pixels
- bits_per_pixel, // bits per pixel
- bytes_per_pixel;
- UCHAR data; // the current pixel data
- // open the file, test if it exists
- if ((fp = fopen(filename,"rb"))==NULL)
- {
- return(0);
- } // end if couldn't find file
- // load the header
- for (index=0; index < sizeof(PCX_HEADER); index++)
- {
- ((UCHAR *)&pcx_header)[index] = (UCHAR)getc(fp);
- } // end for index
- // compute statistics
- width = (pcx_header.xmax - pcx_header.xmin) + 1;
- height = (pcx_header.ymax - pcx_header.ymin) + 1;
- // allocate memory
- bitmap->buffer = (UCHAR *)malloc( width*height );
- // compute bit stuff, not needed since it's ALWAYS 8-bit
- bits_per_pixel = pcx_header.bits_per_pixel;
- bytes_per_pixel = bits_per_pixel / 8;
- // loop while width*height bytes haven't been decompressed
- for (count = 0; count < width * height; )
- {
- // get the first piece of data
- data = (UCHAR)getc(fp);
- // is this a RLE run?
- if (data >= 192 && data <= 255)
- {
- // compute number of bytes in run
- num_bytes = data-192;
- // get the actual data for the run
- data = (UCHAR)getc(fp);
- // replicate data in buffer num_bytes times
- while(num_bytes-- > 0)
- {
- bitmap->buffer[count++] = data;
- } // end while
- } // end if rle
- else
- {
- // actual data, just copy it into buffer at next location
- bitmap->buffer[count++] = data;
- } // end else not rle
- } // end for
- // move to end of file then back up 768 bytes i.e. to begining of palette
- fseek(fp,-768L,SEEK_END);
- // load the PCX pallete into the VGA color registers
- for (index=0; index < 256; index++)
- {
- // get the red component
- bitmap->palette[index].peRed = (unsigned char)getc(fp);
- // get the green component
- bitmap->palette[index].peGreen = (unsigned char)getc(fp);
- // get the blue component
- bitmap->palette[index].peBlue = (unsigned char)getc(fp);
- // always set the flags word to this
- bitmap->palette[index].peFlags = PC_NOCOLLAPSE;
- } // end for index
- // time to close the file
- fclose(fp);
- // now fill in bitmap BMP header fields with translated information from
- // pcx file, sneaky, but has to be done...
- bitmap->bitmapinfoheader.biBitCount = bits_per_pixel;
- bitmap->bitmapinfoheader.biSizeImage = width*height*bytes_per_pixel;
- bitmap->bitmapinfoheader.biWidth = width;
- bitmap->bitmapinfoheader.biHeight = height;
- bitmap->bitmapinfoheader.biClrUsed = 256;
- bitmap->bitmapinfoheader.biClrImportant = 256;
- #if 1
- // write the file info out
- printf("nfilename:%s nsize=%d nwidth=%d nheight=%d nbitsperpixel=%d ncolors=%d nimpcolors=%d",
- filename,
- bitmap->bitmapinfoheader.biSizeImage,
- bitmap->bitmapinfoheader.biWidth,
- bitmap->bitmapinfoheader.biHeight,
- bitmap->bitmapinfoheader.biBitCount,
- bitmap->bitmapinfoheader.biClrUsed,
- bitmap->bitmapinfoheader.biClrImportant);
- #endif
- // success
- return(1);
- } // end Load_Bitmap_PCX_File
- //////////////////////////////////////////////////////////
- int Compute_OBJECT4DV2_Poly_Normals(OBJECT4DV2_PTR obj)
- {
- // the normal of a polygon is commonly needed in a number
- // of functions, however, to store a normal turns out to
- // be counterproductive in most cases since the transformation
- // to rotate the normal ends up taking as long as computing the
- // normal -- HOWEVER, if the normal must have unit length, then
- // pre-computing the length of the normal, and then in real-time
- // dividing by this save a length computation, so we get the
- // best of both worlds... thus, this function computes the length
- // of a polygon's normal, but care must be taken, so that we compute
- // the length based on the EXACT same two vectors that all other
- // functions will use when computing the normal
- // in most cases the functions of interest are the lighting functions
- // if we can pre-compute the normal length
- // for all these functions then that will save at least:
- // num_polys_per_frame * (time to compute length of vector)
- // the way we have written the engine, in all cases the normals
- // during lighting are computed as u = v0->v1, and v = v1->v2
- // so as long as we follow that convention we are fine.
- // also, since the new OBJECT4DV2 format supports multiple frames
- // we must perform these calculations for EACH frame of the animation
- // since although the poly indices don't change, the vertice positions
- // do and thus, so do the normals!!!
- // is this object valid
- if (!obj)
- return(0);
- // iterate thru the poly list of the object and compute normals
- // each polygon
- for (int poly=0; poly < obj->num_polys; poly++)
- {
- // extract vertex indices into master list, rember the polygons are
- // NOT self contained, but based on the vertex list stored in the object
- // itself
- int vindex_0 = obj->plist[poly].vert[0];
- int vindex_1 = obj->plist[poly].vert[1];
- int vindex_2 = obj->plist[poly].vert[2];
- // we need to compute the normal of this polygon face, and recall
- // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
- VECTOR4D u, v, n;
- // build u, v
- VECTOR4D_Build(&obj->vlist_local[ vindex_0 ].v, &obj->vlist_local[ vindex_1 ].v, &u);
- VECTOR4D_Build(&obj->vlist_local[ vindex_0 ].v, &obj->vlist_local[ vindex_2 ].v, &v);
- // compute cross product
- VECTOR4D_Cross(&u, &v, &n);
- // compute length of normal accurately and store in poly nlength
- // +- epsilon later to fix over/underflows
- obj->plist[poly].nlength = VECTOR4D_Length(&n);
- } // end for poly
- // return success
- return(1);
- } // end Compute_OBJECT4DV2_Poly_Normals
- ///////////////////////////////////////////////////////////////////////////////
- int Compute_OBJECT4DV2_Vertex_Normals(OBJECT4DV2_PTR obj)
- {
- // the vertex normals of each polygon are commonly needed in a number
- // functions, most importantly lighting calculations for gouraud shading
- // however, we only need to compute the vertex normals for polygons that are
- // gouraud shader, so for every vertex we must determine the polygons that
- // share the vertex then compute the average normal, to determine if a polygon
- // contributes we look at the shading flags for the polygon
- // is this object valid
- if (!obj)
- return(0);
- // algorithm: we are going to scan the polygon list and for every polygon
- // that needs normals we are going to "accumulate" the surface normal into all
- // vertices that the polygon touches, and increment a counter to track how many
- // polys contribute to vertex, then when the scan is done the counts will be used
- // to average the accumulated values, so instead of an O(n^2) algorithm, we get a O(c*n)
- // this tracks the polygon indices that touch a particular vertex
- // the array is used to count the number of contributors to the vertex
- // so at the end of the process we can divide each "accumulated" normal
- // and average
- int polys_touch_vertex[OBJECT4DV2_MAX_VERTICES];
- memset((void *)polys_touch_vertex, 0, sizeof(int)*OBJECT4DV2_MAX_VERTICES);
- // iterate thru the poly list of the object, compute its normal, then add
- // each vertice that composes it to the "touching" vertex array
- // while accumulating the normal in the vertex normal array
- for (int poly=0; poly < obj->num_polys; poly++)
- {
- Write_Error("nprocessing poly %d", poly);
- // test if this polygon needs vertex normals
- if (obj->plist[poly].attr & POLY4DV2_ATTR_SHADE_MODE_GOURAUD)
- {
- // extract vertex indices into master list, rember the polygons are
- // NOT self contained, but based on the vertex list stored in the object
- // itself
- int vindex_0 = obj->plist[poly].vert[0];
- int vindex_1 = obj->plist[poly].vert[1];
- int vindex_2 = obj->plist[poly].vert[2];
- Write_Error("nTouches vertices: %d, %d, %d", vindex_0, vindex_1, vindex_2);
- // we need to compute the normal of this polygon face, and recall
- // that the vertices are in cw order, u=p0->p1, v=p0->p2, n=uxv
- VECTOR4D u, v, n;
- // build u, v
- VECTOR4D_Build(&obj->vlist_local[ vindex_0 ].v, &obj->vlist_local[ vindex_1 ].v, &u);
- VECTOR4D_Build(&obj->vlist_local[ vindex_0 ].v, &obj->vlist_local[ vindex_2 ].v, &v);
- // compute cross product
- VECTOR4D_Cross(&u, &v, &n);
- // update vertex array to flag this polygon as a contributor
- polys_touch_vertex[vindex_0]++;
- polys_touch_vertex[vindex_1]++;
- polys_touch_vertex[vindex_2]++;
- Write_Error("nPoly touch array v[%d] = %d, v[%d] = %d, v[%d] = %d", vindex_0, polys_touch_vertex[vindex_0],
- vindex_1, polys_touch_vertex[vindex_1],
- vindex_2, polys_touch_vertex[vindex_2]);
- // now accumulate the normal into the vertex normal itself
- // note, we do NOT normalize at this point since we want the length of the normal
- // to weight on the average, and since the length is in fact the area of the parallelogram
- // constructed by uxv, so we are taking the "influence" of the area into consideration
- VECTOR4D_Add(&obj->vlist_local[vindex_0].n, &n, &obj->vlist_local[vindex_0].n);
- VECTOR4D_Add(&obj->vlist_local[vindex_1].n, &n, &obj->vlist_local[vindex_1].n);
- VECTOR4D_Add(&obj->vlist_local[vindex_2].n, &n, &obj->vlist_local[vindex_2].n);
- } // end for poly
- } // end if needs vertex normals
- // now we are almost done, we have accumulated all the vertex normals, but need to average them
- for (int vertex = 0; vertex < obj->num_vertices; vertex++)
- {
- // if this vertex has any contributors then it must need averaging, OR we could check
- // the shading hints flags, they should be one to one
- Write_Error("nProcessing vertex: %d, attr: %d, contributors: %d", vertex,
- obj->vlist_local[vertex].attr,
- polys_touch_vertex[vertex]);
- // test if this vertex has a normal and needs averaging
- if (polys_touch_vertex[vertex] >= 1)
- {
- obj->vlist_local[vertex].nx/=polys_touch_vertex[vertex];
- obj->vlist_local[vertex].ny/=polys_touch_vertex[vertex];
- obj->vlist_local[vertex].nz/=polys_touch_vertex[vertex];
- // now normalize the normal
- VECTOR4D_Normalize(&obj->vlist_local[vertex].n);
- Write_Error("nAvg Vertex normal: [%f, %f, %f]", obj->vlist_local[vertex].nx,
- obj->vlist_local[vertex].ny,
- obj->vlist_local[vertex].nz);
- } // end if
- } // end for
- // return success
- return(1);
- } // end Compute_OBJECT4DV2_Vertex_Normals
- ///////////////////////////////////////////////////////////////////////////////////////////////
- void Draw_Gouraud_Triangle16(POLYF4DV2_PTR face, // ptr to face
- UCHAR *_dest_buffer, // pointer to video buffer
- int mem_pitch) // bytes per line, 320, 640 etc.
- {
- // this function draws a gouraud shaded polygon, based on the affine texture mapper, instead
- // of interpolating the texture coordinates, we simply interpolate the (R,G,B) values across
- // the polygons, I simply needed at another interpolant, I have mapped u->red, v->green, w->blue
- 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,w,
- du,dv,dw,
- xi,yi, // the current interpolated x,y
- ui,vi,wi, // 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,
- dwdyl,
- wl,
- dudyr,
- ur,
- dvdyr,
- vr,
- dwdyr,
- wr;
- int x0,y0,tu0,tv0,tw0, // cached vertices
- x1,y1,tu1,tv1,tw1,
- x2,y2,tu2,tv2,tw2;
- int r_base0, g_base0, b_base0,
- r_base1, g_base1, b_base1,
- r_base2, g_base2, b_base2;
- 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
- // adjust memory pitch to words, divide by 2
- mem_pitch >>=1;
- // first trivial clipping rejection tests
- if (((face->tvlist[0].y < min_clip_y) &&
- (face->tvlist[1].y < min_clip_y) &&
- (face->tvlist[2].y < min_clip_y)) ||
- ((face->tvlist[0].y > max_clip_y) &&
- (face->tvlist[1].y > max_clip_y) &&
- (face->tvlist[2].y > max_clip_y)) ||
- ((face->tvlist[0].x < min_clip_x) &&
- (face->tvlist[1].x < min_clip_x) &&
- (face->tvlist[2].x < min_clip_x)) ||
- ((face->tvlist[0].x > max_clip_x) &&
- (face->tvlist[1].x > max_clip_x) &&
- (face->tvlist[2].x > 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
- // assume 5.6.5 format -- sorry!
- // we can't afford a function call in the inner loops, so we must write
- // two hard coded versions, if we want support for both 5.6.5, and 5.5.5
- _RGB565FROM16BIT(face->lit_color[v0], &r_base0, &g_base0, &b_base0);
- _RGB565FROM16BIT(face->lit_color[v1], &r_base1, &g_base1, &b_base1);
- _RGB565FROM16BIT(face->lit_color[v2], &r_base2, &g_base2, &b_base2);
- // scale to 8 bit
- r_base0 <<= 3;
- g_base0 <<= 2;
- b_base0 <<= 3;
- // scale to 8 bit
- r_base1 <<= 3;
- g_base1 <<= 2;
- b_base1 <<= 3;
- // scale to 8 bit
- r_base2 <<= 3;
- g_base2 <<= 2;
- b_base2 <<= 3;
- // 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 = r_base0;
- tv0 = g_base0;
- tw0 = b_base0;
- x1 = (int)(face->tvlist[v1].x+0.5);
- y1 = (int)(face->tvlist[v1].y+0.5);
- tu1 = r_base1;
- tv1 = g_base1;
- tw1 = b_base1;
- x2 = (int)(face->tvlist[v2].x+0.5);
- y2 = (int)(face->tvlist[v2].y+0.5);
- tu2 = r_base2;
- tv2 = g_base2;
- tw2 = b_base2;
- // 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;
- dwdyl = ((tw2 - tw0) << FIXP16_SHIFT)/dy;
- dxdyr = ((x2 - x1) << FIXP16_SHIFT)/dy;
- dudyr = ((tu2 - tu1) << FIXP16_SHIFT)/dy;
- dvdyr = ((tv2 - tv1) << FIXP16_SHIFT)/dy;
- dwdyr = ((tw2 - tw1) << FIXP16_SHIFT)/dy;
- // test for y clipping
- if (y0 < min_clip_y)
- {
- // compute overclip
- dy = (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);
- wl = dwdyl*dy + (tw0 << 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);
- wr = dwdyr*dy + (tw1 << FIXP16_SHIFT);
- // compute new starting y
- ystart = 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);
- wl = (tw0 << FIXP16_SHIFT);
- ur = (tu1 << FIXP16_SHIFT);
- vr = (tv1 << FIXP16_SHIFT);
- wr = (tw1 << 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;
- dwdyl = ((tw1 - tw0) << FIXP16_SHIFT)/dy;
- dxdyr = ((x2 - x0) << FIXP16_SHIFT)/dy;
- dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dy;
- dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dy;
- dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dy;
- // test for y clipping
- if (y0 < min_clip_y)
- {
- // compute overclip
- dy = (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);
- wl = dwdyl*dy + (tw0 << 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);
- wr = dwdyr*dy + (tw0 << FIXP16_SHIFT);
- // compute new starting y
- ystart = 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);
- wl = (tw0 << FIXP16_SHIFT);
- ur = (tu0 << FIXP16_SHIFT);
- vr = (tv0 << FIXP16_SHIFT);
- wr = (tw0 << FIXP16_SHIFT);
- // set starting y
- ystart = y0;
- } // end else
- } // end else flat bottom
- // test for bottom clip, always
- if ((yend = y2) > max_clip_y)
- yend = max_clip_y;
- // test for horizontal clipping
- if ((x0 < min_clip_x) || (x0 > max_clip_x) ||
- (x1 < min_clip_x) || (x1 > max_clip_x) ||
- (x2 < min_clip_x) || (x2 > 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,w interpolants
- ui = ul + FIXP16_ROUND_UP;
- vi = vl + FIXP16_ROUND_UP;
- wi = wl + FIXP16_ROUND_UP;
- // compute u,v interpolants
- if ((dx = (xend - xstart))>0)
- {
- du = (ur - ul)/dx;
- dv = (vr - vl)/dx;
- dw = (wr - wl)/dx;
- } // end if
- else
- {
- du = (ur - ul);
- dv = (vr - vl);
- dw = (wr - wl);
- } // end else
- ///////////////////////////////////////////////////////////////////////
- // test for x clipping, LHS
- if (xstart < min_clip_x)
- {
- // compute x overlap
- dx = min_clip_x - xstart;
- // slide interpolants over
- ui+=dx*du;
- vi+=dx*dv;
- wi+=dx*dw;
- // reset vars
- xstart = min_clip_x;
- } // end if
- // test for x clipping RHS
- if (xend > max_clip_x)
- xend = max_clip_x;
- ///////////////////////////////////////////////////////////////////////
- // draw span
- for (xi=xstart; xi<=xend; xi++)
- {
- // write textel assume 5.6.5
- screen_ptr[xi] = ((ui >> (FIXP16_SHIFT+3)) << 11) + ((vi >> (FIXP16_SHIFT+2)) << 5) + (wi >> (FIXP16_SHIFT+3));
- // interpolate u,v
- ui+=du;
- vi+=dv;
- wi+=dw;
- } // end for xi
- // interpolate u,v,w,x along right and left edge
- xl+=dxdyl;
- ul+=dudyl;
- vl+=dvdyl;
- wl+=dwdyl;
- xr+=dxdyr;
- ur+=dudyr;
- vr+=dvdyr;
- wr+=dwdyr;
- // 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,w interpolants
- ui = ul + FIXP16_ROUND_UP;
- vi = vl + FIXP16_ROUND_UP;
- wi = wl + FIXP16_ROUND_UP;
- // compute u,v interpolants
- if ((dx = (xend - xstart))>0)
- {
- du = (ur - ul)/dx;
- dv = (vr - vl)/dx;
- dw = (wr - wl)/dx;
- } // end if
- else
- {
- du = (ur - ul);
- dv = (vr - vl);
- dw = (wr - wl);
- } // end else
- // draw span
- for (xi=xstart; xi<=xend; xi++)
- {
- // write textel 5.6.5
- screen_ptr[xi] = ((ui >> (FIXP16_SHIFT+3)) << 11) + ((vi >> (FIXP16_SHIFT+2)) << 5) + (wi >> (FIXP16_SHIFT+3));
- // interpolate u,v
- ui+=du;
- vi+=dv;
- wi+=dw;
- } // end for xi
- // interpolate u,v,w,x along right and left edge
- xl+=dxdyl;
- ul+=dudyl;
- vl+=dvdyl;
- wl+=dwdyl;
- xr+=dxdyr;
- ur+=dudyr;
- vr+=dvdyr;
- wr+=dwdyr;
- // 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) > max_clip_y)
- yend = max_clip_y;
- // pre-test y clipping status
- if (y1 < 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;
- dwdyl = ((tw2 - tw1) << 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;
- dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dyr;
- // compute overclip
- dyr = (min_clip_y - y0);
- dyl = (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);
- wl = dwdyl*dyl + (tw1 << 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);
- wr = dwdyr*dyr + (tw0 << FIXP16_SHIFT);
- // compute new starting y
- ystart = 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(dwdyl,dwdyr,temp);
- SWAP(xl,xr,temp);
- SWAP(ul,ur,temp);
- SWAP(vl,vr,temp);
- SWAP(wl,wr,temp);
- SWAP(x1,x2,temp);
- SWAP(y1,y2,temp);
- SWAP(tu1,tu2,temp);
- SWAP(tv1,tv2,temp);
- SWAP(tw1,tw2,temp);
- // set interpolation restart
- irestart = INTERP_RHS;
- } // end if
- } // end if
- else
- if (y0 < 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;
- dwdyl = ((tw1 - tw0) << 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;
- dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dyr;
- // compute overclip
- dy = (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);
- wl = dwdyl*dy + (tw0 << 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);
- wr = dwdyr*dy + (tw0 << FIXP16_SHIFT);
- // compute new starting y
- ystart = 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(dwdyl,dwdyr,temp);
- SWAP(xl,xr,temp);
- SWAP(ul,ur,temp);
- SWAP(vl,vr,temp);
- SWAP(wl,wr,temp);
- SWAP(x1,x2,temp);
- SWAP(y1,y2,temp);
- SWAP(tu1,tu2,temp);
- SWAP(tv1,tv2,temp);
- SWAP(tw1,tw2,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;
- dwdyl = ((tw1 - tw0) << 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;
- dwdyr = ((tw2 - tw0) << 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);
- wl = (tw0 << FIXP16_SHIFT);
- ur = (tu0 << FIXP16_SHIFT);
- vr = (tv0 << FIXP16_SHIFT);
- wr = (tw0 << 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(dwdyl,dwdyr,temp);
- SWAP(xl,xr,temp);
- SWAP(ul,ur,temp);
- SWAP(vl,vr,temp);
- SWAP(wl,wr,temp);
- SWAP(x1,x2,temp);
- SWAP(y1,y2,temp);
- SWAP(tu1,tu2,temp);
- SWAP(tv1,tv2,temp);
- SWAP(tw1,tw2,temp);
- // set interpolation restart
- irestart = INTERP_RHS;
- } // end if
- } // end else
- // test for horizontal clipping
- if ((x0 < min_clip_x) || (x0 > max_clip_x) ||
- (x1 < min_clip_x) || (x1 > max_clip_x) ||
- (x2 < min_clip_x) || (x2 > 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,w interpolants
- ui = ul + FIXP16_ROUND_UP;
- vi = vl + FIXP16_ROUND_UP;
- wi = wl + FIXP16_ROUND_UP;
- // compute u,v interpolants
- if ((dx = (xend - xstart))>0)
- {
- du = (ur - ul)/dx;
- dv = (vr - vl)/dx;
- dw = (wr - wl)/dx;
- } // end if
- else
- {
- du = (ur - ul);
- dv = (vr - vl);
- dw = (wr - wl);
- } // end else
- ///////////////////////////////////////////////////////////////////////
- // test for x clipping, LHS
- if (xstart < min_clip_x)
- {
- // compute x overlap
- dx = min_clip_x - xstart;
- // slide interpolants over
- ui+=dx*du;
- vi+=dx*dv;
- wi+=dx*dw;
- // set x to left clip edge
- xstart = min_clip_x;
- } // end if
- // test for x clipping RHS
- if (xend > max_clip_x)
- xend = max_clip_x;
- ///////////////////////////////////////////////////////////////////////
- // draw span
- for (xi=xstart; xi<=xend; xi++)
- {
- // write textel assume 5.6.5
- screen_ptr[xi] = ((ui >> (FIXP16_SHIFT+3)) << 11) + ((vi >> (FIXP16_SHIFT+2)) << 5) + (wi >> (FIXP16_SHIFT+3));
- // interpolate u,v
- ui+=du;
- vi+=dv;
- wi+=dw;
- } // end for xi
- // interpolate u,v,w,x along right and left edge
- xl+=dxdyl;
- ul+=dudyl;
- vl+=dvdyl;
- wl+=dwdyl;
- xr+=dxdyr;
- ur+=dudyr;
- vr+=dvdyr;
- wr+=dwdyr;
- // 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;
- dwdyl = ((tw2 - tw1) << FIXP16_SHIFT)/dyl;
- // set starting values
- xl = (x1 << FIXP16_SHIFT);
- ul = (tu1 << FIXP16_SHIFT);
- vl = (tv1 << FIXP16_SHIFT);
- wl = (tw1 << FIXP16_SHIFT);
- // interpolate down on LHS to even up
- xl+=dxdyl;
- ul+=dudyl;
- vl+=dvdyl;
- wl+=dwdyl;
- } // 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;
- dwdyr = ((tw1 - tw2) << FIXP16_SHIFT)/dyr;
- // set starting values
- xr = (x2 << FIXP16_SHIFT);
- ur = (tu2 << FIXP16_SHIFT);
- vr = (tv2 << FIXP16_SHIFT);
- wr = (tw2 << FIXP16_SHIFT);
- // interpolate down on RHS to even up
- xr+=dxdyr;
- ur+=dudyr;
- vr+=dvdyr;
- wr+=dwdyr;
- } // 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,w interpolants
- ui = ul + FIXP16_ROUND_UP;
- vi = vl + FIXP16_ROUND_UP;
- wi = wl + FIXP16_ROUND_UP;
- // compute u,v interpolants
- if ((dx = (xend - xstart))>0)
- {
- du = (ur - ul)/dx;
- dv = (vr - vl)/dx;
- dw = (wr - wl)/dx;
- } // end if
- else
- {
- du = (ur - ul);
- dv = (vr - vl);
- dw = (wr - wl);
- } // end else
- // draw span
- for (xi=xstart; xi<=xend; xi++)
- {
- // write textel assume 5.6.5
- screen_ptr[xi] = ((ui >> (FIXP16_SHIFT+3)) << 11) + ((vi >> (FIXP16_SHIFT+2)) << 5) + (wi >> (FIXP16_SHIFT+3));
- // interpolate u,v
- ui+=du;
- vi+=dv;
- wi+=dw;
- } // end for xi
- // interpolate u,v,w,x along right and left edge
- xl+=dxdyl;
- ul+=dudyl;
- vl+=dvdyl;
- wl+=dwdyl;
- xr+=dxdyr;
- ur+=dudyr;
- vr+=dvdyr;
- wr+=dwdyr;
- // 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;
- dwdyl = ((tw2 - tw1) << FIXP16_SHIFT)/dyl;
- // set starting values
- xl = (x1 << FIXP16_SHIFT);
- ul = (tu1 << FIXP16_SHIFT);
- vl = (tv1 << FIXP16_SHIFT);
- wl = (tw1 << FIXP16_SHIFT);
- // interpolate down on LHS to even up
- xl+=dxdyl;
- ul+=dudyl;
- vl+=dvdyl;
- wl+=dwdyl;
- } // 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;
- dwdyr = ((tw1 - tw2) << FIXP16_SHIFT)/dyr;
- // set starting values
- xr = (x2 << FIXP16_SHIFT);
- ur = (tu2 << FIXP16_SHIFT);
- vr = (tv2 << FIXP16_SHIFT);
- wr = (tw2 << FIXP16_SHIFT);
- // interpolate down on RHS to even up
- xr+=dxdyr;
- ur+=dudyr;
- vr+=dvdyr;
- wr+=dwdyr;
- } // end else
- } // end if
- } // end for y
- } // end else
- } // end if
- } // end Draw_Gouraud_Triangle16
- ///////////////////////////////////////////////////////////////////////////////
- void Draw_Gouraud_Triangle(POLYF4DV2_PTR face, // ptr to face
- UCHAR *dest_buffer, // pointer to video buffer
- int mem_pitch) // bytes per line, 320, 640 etc.
- {
- // this function draws a gouraud shaded polygon, based on the affine texture mapper, instead
- // of interpolating the texture coordinates, we simply interpolate the (R,G,B) values across
- // the polygons, I simply needed at another interpolant, I have mapped u->red, v->green, w->blue
- // note that this is the 8-bit version, and I have decided to throw caution at the wind and see
- // what happens if we do a full RGB interpolation and then at the last minute use the color lookup
- // to find the appropriate color
- 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,w,
- du,dv,dw,
- xi,yi, // the current interpolated x,y
- ui,vi,wi, // 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,
- dwdyl,
- wl,
- dudyr,
- ur,
- dvdyr,
- vr,
- dwdyr,
- wr;
- int x0,y0,tu0,tv0,tw0, // cached vertices
- x1,y1,tu1,tv1,tw1,
- x2,y2,tu2,tv2,tw2;
- int r_base0, g_base0, b_base0,
- r_base1, g_base1, b_base1,
- r_base2, g_base2, b_base2;
- UCHAR *screen_ptr = NULL,
- *screen_line = NULL,
- *textmap = NULL;
- #ifdef DEBUG_ON
- // track rendering stats
- debug_polys_rendered_per_frame++;
- #endif
- // first trivial clipping rejection tests
- if (((face->tvlist[0].y < min_clip_y) &&
- (face->tvlist[1].y < min_clip_y) &&
- (face->tvlist[2].y < min_clip_y)) ||
- ((face->tvlist[0].y > max_clip_y) &&
- (face->tvlist[1].y > max_clip_y) &&
- (face->tvlist[2].y > max_clip_y)) ||
- ((face->tvlist[0].x < min_clip_x) &&
- (face->tvlist[1].x < min_clip_x) &&
- (face->tvlist[2].x < min_clip_x)) ||
- ((face->tvlist[0].x > max_clip_x) &&
- (face->tvlist[1].x > max_clip_x) &&
- (face->tvlist[2].x > 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
- // assume 5.6.5 format -- sorry!
- // we can't afford a function call in the inner loops, so we must write
- // two hard coded versions, if we want support for both 5.6.5, and 5.5.5
- // notice that eventhough we will rasterize in 8-bit, the incoming data
- // is still in RGB format
- _RGB565FROM16BIT(face->lit_color[v0], &r_base0, &g_base0, &b_base0);
- _RGB565FROM16BIT(face->lit_color[v1], &r_base1, &g_base1, &b_base1);
- _RGB565FROM16BIT(face->lit_color[v2], &r_base2, &g_base2, &b_base2);
- // scale to 8 bit
- r_base0 <<= 3;
- g_base0 <<= 2;
- b_base0 <<= 3;
- // scale to 8 bit
- r_base1 <<= 3;
- g_base1 <<= 2;
- b_base1 <<= 3;
- // scale to 8 bit
- r_base2 <<= 3;
- g_base2 <<= 2;
- b_base2 <<= 3;
- // 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 = r_base0;
- tv0 = g_base0;
- tw0 = b_base0;
- x1 = (int)(face->tvlist[v1].x+0.5);
- y1 = (int)(face->tvlist[v1].y+0.5);
- tu1 = r_base1;
- tv1 = g_base1;
- tw1 = b_base1;
- x2 = (int)(face->tvlist[v2].x+0.5);
- y2 = (int)(face->tvlist[v2].y+0.5);
- tu2 = r_base2;
- tv2 = g_base2;
- tw2 = b_base2;
- // 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;
- dwdyl = ((tw2 - tw0) << FIXP16_SHIFT)/dy;
- dxdyr = ((x2 - x1) << FIXP16_SHIFT)/dy;
- dudyr = ((tu2 - tu1) << FIXP16_SHIFT)/dy;
- dvdyr = ((tv2 - tv1) << FIXP16_SHIFT)/dy;
- dwdyr = ((tw2 - tw1) << FIXP16_SHIFT)/dy;
- // test for y clipping
- if (y0 < min_clip_y)
- {
- // compute overclip
- dy = (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);
- wl = dwdyl*dy + (tw0 << 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);
- wr = dwdyr*dy + (tw1 << FIXP16_SHIFT);
- // compute new starting y
- ystart = 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);
- wl = (tw0 << FIXP16_SHIFT);
- ur = (tu1 << FIXP16_SHIFT);
- vr = (tv1 << FIXP16_SHIFT);
- wr = (tw1 << 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;
- dwdyl = ((tw1 - tw0) << FIXP16_SHIFT)/dy;
- dxdyr = ((x2 - x0) << FIXP16_SHIFT)/dy;
- dudyr = ((tu2 - tu0) << FIXP16_SHIFT)/dy;
- dvdyr = ((tv2 - tv0) << FIXP16_SHIFT)/dy;
- dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dy;
- // test for y clipping
- if (y0 < min_clip_y)
- {
- // compute overclip
- dy = (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);
- wl = dwdyl*dy + (tw0 << 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);
- wr = dwdyr*dy + (tw0 << FIXP16_SHIFT);
- // compute new starting y
- ystart = 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);
- wl = (tw0 << FIXP16_SHIFT);
- ur = (tu0 << FIXP16_SHIFT);
- vr = (tv0 << FIXP16_SHIFT);
- wr = (tw0 << FIXP16_SHIFT);
- // set starting y
- ystart = y0;
- } // end else
- } // end else flat bottom
- // test for bottom clip, always
- if ((yend = y2) > max_clip_y)
- yend = max_clip_y;
- // test for horizontal clipping
- if ((x0 < min_clip_x) || (x0 > max_clip_x) ||
- (x1 < min_clip_x) || (x1 > max_clip_x) ||
- (x2 < min_clip_x) || (x2 > 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,w interpolants
- ui = ul + FIXP16_ROUND_UP;
- vi = vl + FIXP16_ROUND_UP;
- wi = wl + FIXP16_ROUND_UP;
- // compute u,v interpolants
- if ((dx = (xend - xstart))>0)
- {
- du = (ur - ul)/dx;
- dv = (vr - vl)/dx;
- dw = (wr - wl)/dx;
- } // end if
- else
- {
- du = (ur - ul);
- dv = (vr - vl);
- dw = (wr - wl);
- } // end else
- ///////////////////////////////////////////////////////////////////////
- // test for x clipping, LHS
- if (xstart < min_clip_x)
- {
- // compute x overlap
- dx = min_clip_x - xstart;
- // slide interpolants over
- ui+=dx*du;
- vi+=dx*dv;
- wi+=dx*dw;
- // reset vars
- xstart = min_clip_x;
- } // end if
- // test for x clipping RHS
- if (xend > max_clip_x)
- xend = max_clip_x;
- ///////////////////////////////////////////////////////////////////////
- // draw span
- for (xi=xstart; xi<=xend; xi++)
- {
- // write textel assume 5.6.5
- screen_ptr[xi] = rgblookup[( ((ui >> (FIXP16_SHIFT+3)) << 11) +
- ((vi >> (FIXP16_SHIFT+2)) << 5) +
- (wi >> (FIXP16_SHIFT+3)) ) ];
- // interpolate u,v
- ui+=du;
- vi+=dv;
- wi+=dw;
- } // end for xi
- // interpolate u,v,w,x along right and left edge
- xl+=dxdyl;
- ul+=dudyl;
- vl+=dvdyl;
- wl+=dwdyl;
- xr+=dxdyr;
- ur+=dudyr;
- vr+=dvdyr;
- wr+=dwdyr;
- // 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,w interpolants
- ui = ul + FIXP16_ROUND_UP;
- vi = vl + FIXP16_ROUND_UP;
- wi = wl + FIXP16_ROUND_UP;
- // compute u,v interpolants
- if ((dx = (xend - xstart))>0)
- {
- du = (ur - ul)/dx;
- dv = (vr - vl)/dx;
- dw = (wr - wl)/dx;
- } // end if
- else
- {
- du = (ur - ul);
- dv = (vr - vl);
- dw = (wr - wl);
- } // end else
- // draw span
- for (xi=xstart; xi<=xend; xi++)
- {
- // write textel 5.6.5
- screen_ptr[xi] = rgblookup[( ((ui >> (FIXP16_SHIFT+3)) << 11) +
- ((vi >> (FIXP16_SHIFT+2)) << 5) +
- (wi >> (FIXP16_SHIFT+3)) ) ];
- // interpolate u,v
- ui+=du;
- vi+=dv;
- wi+=dw;
- } // end for xi
- // interpolate u,v,w,x along right and left edge
- xl+=dxdyl;
- ul+=dudyl;
- vl+=dvdyl;
- wl+=dwdyl;
- xr+=dxdyr;
- ur+=dudyr;
- vr+=dvdyr;
- wr+=dwdyr;
- // 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) > max_clip_y)
- yend = max_clip_y;
- // pre-test y clipping status
- if (y1 < 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;
- dwdyl = ((tw2 - tw1) << 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;
- dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dyr;
- // compute overclip
- dyr = (min_clip_y - y0);
- dyl = (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);
- wl = dwdyl*dyl + (tw1 << 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);
- wr = dwdyr*dyr + (tw0 << FIXP16_SHIFT);
- // compute new starting y
- ystart = 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(dwdyl,dwdyr,temp);
- SWAP(xl,xr,temp);
- SWAP(ul,ur,temp);
- SWAP(vl,vr,temp);
- SWAP(wl,wr,temp);
- SWAP(x1,x2,temp);
- SWAP(y1,y2,temp);
- SWAP(tu1,tu2,temp);
- SWAP(tv1,tv2,temp);
- SWAP(tw1,tw2,temp);
- // set interpolation restart
- irestart = INTERP_RHS;
- } // end if
- } // end if
- else
- if (y0 < 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;
- dwdyl = ((tw1 - tw0) << 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;
- dwdyr = ((tw2 - tw0) << FIXP16_SHIFT)/dyr;
- // compute overclip
- dy = (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);
- wl = dwdyl*dy + (tw0 << 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);
- wr = dwdyr*dy + (tw0 << FIXP16_SHIFT);
- // compute new starting y
- ystart = 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(dwdyl,dwdyr,temp);
- SWAP(xl,xr,temp);
- SWAP(ul,ur,temp);
- SWAP(vl,vr,temp);
- SWAP(wl,wr,temp);
- SWAP(x1,x2,temp);
- SWAP(y1,y2,temp);
- SWAP(tu1,tu2,temp);
- SWAP(tv1,tv2,temp);
- SWAP(tw1,tw2,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;
- dwdyl = ((tw1 - tw0) << 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;
- dwdyr = ((tw2 - tw0) << 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);
- wl = (tw0 << FIXP16_SHIFT);
- ur = (tu0 << FIXP16_SHIFT);
- vr = (tv0 << FIXP16_SHIFT);
- wr = (tw0 << 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(dwdyl,dwdyr,temp);
- SWAP(xl,xr,temp);
- SWAP(ul,ur,temp);
- SWAP(vl,vr,temp);
- SWAP(wl,wr,temp);
- SWAP(x1,x2,temp);
- SWAP(y1,y2,temp);
- SWAP(tu1,tu2,temp);
- SWAP(tv1,tv2,temp);
- SWAP(tw1,tw2,temp);
- // set interpolation restart
- irestart = INTERP_RHS;
- } // end if
- } // end else
- // test for horizontal clipping
- if ((x0 < min_clip_x) || (x0 > max_clip_x) ||
- (x1 < min_clip_x) || (x1 > max_clip_x) ||
- (x2 < min_clip_x) || (x2 > 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,w interpolants
- ui = ul + FIXP16_ROUND_UP;
- vi = vl + FIXP16_ROUND_UP;
- wi = wl + FIXP16_ROUND_UP;
- // compute u,v interpolants
- if ((dx = (xend - xstart))>0)
- {
- du = (ur - ul)/dx;
- dv = (vr - vl)/dx;
- dw = (wr - wl)/dx;
- } // end if
- else
- {
- du = (ur - ul);
- dv = (vr - vl);
- dw = (wr - wl);
- } // end else
- ///////////////////////////////////////////////////////////////////////
- // test for x clipping, LHS
- if (xstart < min_clip_x)
- {
- // compute x overlap
- dx = min_clip_x - xstart;
- // slide interpolants over
- ui+=dx*du;
- vi+=dx*dv;
- wi+=dx*dw;
- // set x to left clip edge
- xstart = min_clip_x;
- } // end if
- // test for x clipping RHS
- if (xend > max_clip_x)
- xend = max_clip_x;
- ///////////////////////////////////////////////////////////////////////
- // draw span
- for (xi=xstart; xi<=xend; xi++)
- {
- // write textel assume 5.6.5
- screen_ptr[xi] = rgblookup[( ((ui >> (FIXP16_SHIFT+3)) << 11) +
- ((vi >> (FIXP16_SHIFT+2)) << 5) +
- (wi >> (FIXP16_SHIFT+3)) ) ];
- // interpolate u,v
- ui+=du;
- vi+=dv;
- wi+=dw;
- } // end for xi
- // interpolate u,v,w,x along right and left edge
- xl+=dxdyl;
- ul+=dudyl;
- vl+=dvdyl;
- wl+=dwdyl;
- xr+=dxdyr;
- ur+=dudyr;
- vr+=dvdyr;
- wr+=dwdyr;
- // 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;
- dwdyl = ((tw2 - tw1) << FIXP16_SHIFT)/dyl;
- // set starting values
- xl = (x1 << FIXP16_SHIFT);
- ul = (tu1 << FIXP16_SHIFT);
- vl = (tv1 << FIXP16_SHIFT);
- wl = (tw1 << FIXP16_SHIFT);
- // interpolate down on LHS to even up
- xl+=dxdyl;
- ul+=dudyl;
- vl+=dvdyl;
- wl+=dwdyl;
- } // 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;
- dwdyr = ((tw1 - tw2) << FIXP16_SHIFT)/dyr;
- // set starting values
- xr = (x2 << FIXP16_SHIFT);
- ur = (tu2 << FIXP16_SHIFT);
- vr = (tv2 << FIXP16_SHIFT);
- wr = (tw2 << FIXP16_SHIFT);
- // interpolate down on RHS to even up
- xr+=dxdyr;
- ur+=dudyr;
- vr+=dvdyr;
- wr+=dwdyr;
- } // 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,w interpolants
- ui = ul + FIXP16_ROUND_UP;
- vi = vl + FIXP16_ROUND_UP;
- wi = wl + FIXP16_ROUND_UP;
- // compute u,v interpolants
- if ((dx = (xend - xstart))>0)
- {
- du = (ur - ul)/dx;
- dv = (vr - vl)/dx;
- dw = (wr - wl)/dx;
- } // end if
- else
- {
- du = (ur - ul);
- dv = (vr - vl);
- dw = (wr - wl);
- } // end else
- // draw span
- for (xi=xstart; xi<=xend; xi++)
- {
- // write textel assume 5.6.5
- screen_ptr[xi] = rgblookup[( ((ui >> (FIXP16_SHIFT+3)) << 11) +
- ((vi >> (FIXP16_SHIFT+2)) << 5) +
- (wi >> (FIXP16_SHIFT+3)) ) ];
- // interpolate u,v
- ui+=du;
- vi+=dv;
- wi+=dw;
- } // end for xi
- // interpolate u,v,w,x along right and left edge
- xl+=dxdyl;
- ul+=dudyl;
- vl+=dvdyl;
- wl+=dwdyl;
- xr+=dxdyr;
- ur+=dudyr;
- vr+=dvdyr;
- wr+=dwdyr;
- // 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;
- dwdyl = ((tw2 - tw1) << FIXP16_SHIFT)/dyl;
- // set starting values
- xl = (x1 << FIXP16_SHIFT);
- ul = (tu1 << FIXP16_SHIFT);
- vl = (tv1 << FIXP16_SHIFT);
- wl = (tw1 << FIXP16_SHIFT);
- // interpolate down on LHS to even up
- xl+=dxdyl;
- ul+=dudyl;
- vl+=dvdyl;
- wl+=dwdyl;
- } // 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;
- dwdyr = ((tw1 - tw2) << FIXP16_SHIFT)/dyr;
- // set starting values
- xr = (x2 << FIXP16_SHIFT);
- ur = (tu2 << FIXP16_SHIFT);
- vr = (tv2 << FIXP16_SHIFT);
- wr = (tw2 << FIXP16_SHIFT);
- // interpolate down on RHS to even up
- xr+=dxdyr;
- ur+=dudyr;
- vr+=dvdyr;
- wr+=dwdyr;
- } // end else
- } // end if
- } // end for y
- } // end else
- } // end if
- } // end Draw_Gouraud_Triangle
- ///////////////////////////////////////////////////////////////////////////////
- int RGB_12_8_Lighting_Table_Builder(LPPALETTEENTRY src_palette, // source palette
- UCHAR rgblookup[4096][256]) // lookup table
- {
- // this function creates a lighting table used for 8-bit lighting inside the
- // texture mapping function, what we need is a table that for every possible
- // light color and textel color outputs the textel index that is the closest
- // match for the given color modulation, however, that would be 256*65536 = 16.7 megs!
- // a little excessive, thus, we will scale the incoming light value down to 4.4.4
- // format, or only 16 different intensities per channel, or a total of 12 bits,
- // now we will only need 256*2^12 = 1meg which is reasonable for the speed gain
- // additionally, the table is going to be 2d, where the row is the intensity
- // and the column is the color, this format is more effective since tables are
- // stored in row-major form, and since we are shading flat shaded polys with
- // texture, we know the texture color will change during the calculations,
- // but not the light color, thus, the cache coherence will be excellent if we access
- // elements in the form rgblookup[RGBcolor.12bit][textel index.8bit]
- // finally, it's up to the caller to send in the rgblookup pre-allocated
- // here it goes...
- // first check the pointers
- if (!src_palette || !rgblookup)
- return(-1);
- // there are 4096 RGB values we need to compute, assuming that we are in RGB: 4.4.4 format
- for (int rgbindex = 0; rgbindex < 4096; rgbindex++)
- {
- // for each RGB color 0..4095 we need to multiple by each palette entry 0..255
- // and then scan for the closest match, lots of loops!!!!
- for (int color_index = 0; color_index < 256; color_index++)
- {
- int curr_index = -1; // current color index of best match
- long curr_error = INT_MAX; // distance in color space to nearest match or "error"
- // extract r,g,b from rgbindex, assuming an encoding of 4.4.4
- int r = (rgbindex >> 8);
- int g = ((rgbindex >> 4) & 0x0f);
- int b = (rgbindex & 0x0f);
- // now the final target is this r,g,b value which is simulating the light source
- // multiplied by the textel color, that IS our target...
- // modulate values together, make sure results stay in 0..255, so divide results
- // by 15 since the r,g,b values were normalized to 15 rather than 1.0
- r = (int)(( (float)r * (float)src_palette[color_index].peRed) / 15);
- g = (int)(( (float)g * (float)src_palette[color_index].peGreen) / 15);
- b = (int)(( (float)b * (float)src_palette[color_index].peBlue) / 15);
- // now scan palette to find this color
- for (int color_scan = 0; color_scan < 256; color_scan++)
- {
- // compute distance to color from target
- long delta_red = abs(src_palette[color_scan].peRed - r);
- long delta_green = abs(src_palette[color_scan].peGreen - g);
- long delta_blue = abs(src_palette[color_scan].peBlue - b);
- long error = (delta_red*delta_red) + (delta_green*delta_green) + (delta_blue*delta_blue);
- // is this color a better match?
- if (error < curr_error)
- {
- curr_index = color_scan;
- curr_error = error;
- } // end if
- } // end for color_scan
- // best match has been found, enter it into table
- rgblookup[rgbindex][color_index] = curr_index;
- } // end for color_index
- } // end for rgbindex
- // return success
- return(1);
- } // end RGB_12_8_Lighting_Table_Builder
- ///////////////////////////////////////////////////////////////////////////////
- // OBSOLETE and TEST FUNCTIONS ////////////////////////////////////////////////
- ///////////////////////////////////////////////////////////////////////////////
- void Draw_RENDERLIST4DV1_Solid2_16(RENDERLIST4DV1_PTR rend_list,
- UCHAR *video_buffer, int lpitch)
- {
- // this function "executes" the render list or in other words
- // draws all the faces in the list in wire frame 16bit mode
- // note there is no need to sort wire frame polygons, but
- // later we will need to, so hidden surfaces stay hidden
- // also, we leave it to the function to determine the bitdepth
- // and call the correct rasterizer
- // at this point, all we have is a list of polygons and it's time
- // to draw them
- for (int poly=0; poly < rend_list->num_polys; poly++)
- {
- // render this polygon if and only if it's not clipped, not culled,
- // active, and visible, note however the concecpt of "backface" is
- // irrelevant in a wire frame engine though
- if (!(rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_ACTIVE) ||
- (rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_CLIPPED ) ||
- (rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_BACKFACE) )
- continue; // move onto next poly
- // draw the triangle
- Draw_Triangle_2D2_16(rend_list->poly_ptrs[poly]->tvlist[0].x, rend_list->poly_ptrs[poly]->tvlist[0].y,
- rend_list->poly_ptrs[poly]->tvlist[1].x, rend_list->poly_ptrs[poly]->tvlist[1].y,
- rend_list->poly_ptrs[poly]->tvlist[2].x, rend_list->poly_ptrs[poly]->tvlist[2].y,
- rend_list->poly_ptrs[poly]->color, video_buffer, lpitch);
- } // end for poly
- } // end Draw_RENDERLIST4DV1_Solid2_16
- //////////////////////////////////////////////////////////////////////////////////////
- void Draw_OBJECT4DV1_Solid2(OBJECT4DV1_PTR obj,
- UCHAR *video_buffer, int lpitch)
- {
- // this function renders an object to the screen in solid,
- // 8 bit mode, it has no regard at all about hidden surface removal,
- // etc. the function only exists as an easy way to render an object
- // without converting it into polygons, the function assumes all
- // coordinates are screen coordinates, but will perform 2D clipping
- // iterate thru the poly list of the object and simply draw
- // each polygon
- for (int poly=0; poly < obj->num_polys; poly++)
- {
- // render this polygon if and only if it's not clipped, not culled,
- // active, and visible, note however the concecpt of "backface" is
- // irrelevant in a wire frame engine though
- if (!(obj->plist[poly].state & POLY4DV1_STATE_ACTIVE) ||
- (obj->plist[poly].state & POLY4DV1_STATE_CLIPPED ) ||
- (obj->plist[poly].state & POLY4DV1_STATE_BACKFACE) )
- continue; // move onto next poly
- // extract vertex indices into master list, rember the polygons are
- // NOT self contained, but based on the vertex list stored in the object
- // itself
- int vindex_0 = obj->plist[poly].vert[0];
- int vindex_1 = obj->plist[poly].vert[1];
- int vindex_2 = obj->plist[poly].vert[2];
- // draw the triangle
- Draw_Triangle_2D2(obj->vlist_trans[ vindex_0 ].x, obj->vlist_trans[ vindex_0 ].y,
- obj->vlist_trans[ vindex_1 ].x, obj->vlist_trans[ vindex_1 ].y,
- obj->vlist_trans[ vindex_2 ].x, obj->vlist_trans[ vindex_2 ].y,
- obj->plist[poly].color, video_buffer, lpitch);
- } // end for poly
- } // end Draw_OBJECT4DV1_Solid2
- ///////////////////////////////////////////////////////////////
- void Draw_RENDERLIST4DV1_Solid2(RENDERLIST4DV1_PTR rend_list,
- UCHAR *video_buffer, int lpitch)
- {
- // this function "executes" the render list or in other words
- // draws all the faces in the list in wire frame 8bit mode
- // note there is no need to sort wire frame polygons, but
- // later we will need to, so hidden surfaces stay hidden
- // also, we leave it to the function to determine the bitdepth
- // and call the correct rasterizer
- // at this point, all we have is a list of polygons and it's time
- // to draw them
- for (int poly=0; poly < rend_list->num_polys; poly++)
- {
- // render this polygon if and only if it's not clipped, not culled,
- // active, and visible, note however the concecpt of "backface" is
- // irrelevant in a wire frame engine though
- if (!(rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_ACTIVE) ||
- (rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_CLIPPED ) ||
- (rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_BACKFACE) )
- continue; // move onto next poly
- // draw the triangle
- Draw_Triangle_2D2(rend_list->poly_ptrs[poly]->tvlist[0].x, rend_list->poly_ptrs[poly]->tvlist[0].y,
- rend_list->poly_ptrs[poly]->tvlist[1].x, rend_list->poly_ptrs[poly]->tvlist[1].y,
- rend_list->poly_ptrs[poly]->tvlist[2].x, rend_list->poly_ptrs[poly]->tvlist[2].y,
- rend_list->poly_ptrs[poly]->color, video_buffer, lpitch);
- } // end for poly
- } // end Draw_RENDERLIST4DV1_Solid2
- /////////////////////////////////////////////////////////////
- void Draw_OBJECT4DV1_Solid2_16(OBJECT4DV1_PTR obj,
- UCHAR *video_buffer, int lpitch)
- {
- // this function renders an object to the screen in wireframe,
- // 16 bit mode, it has no regard at all about hidden surface removal,
- // etc. the function only exists as an easy way to render an object
- // without converting it into polygons, the function assumes all
- // coordinates are screen coordinates, but will perform 2D clipping
- // iterate thru the poly list of the object and simply draw
- // each polygon
- for (int poly=0; poly < obj->num_polys; poly++)
- {
- // render this polygon if and only if it's not clipped, not culled,
- // active, and visible, note however the concecpt of "backface" is
- // irrelevant in a wire frame engine though
- if (!(obj->plist[poly].state & POLY4DV1_STATE_ACTIVE) ||
- (obj->plist[poly].state & POLY4DV1_STATE_CLIPPED ) ||
- (obj->plist[poly].state & POLY4DV1_STATE_BACKFACE) )
- continue; // move onto next poly
- // extract vertex indices into master list, rember the polygons are
- // NOT self contained, but based on the vertex list stored in the object
- // itself
- int vindex_0 = obj->plist[poly].vert[0];
- int vindex_1 = obj->plist[poly].vert[1];
- int vindex_2 = obj->plist[poly].vert[2];
- // draw the triangle
- Draw_Triangle_2D2_16(obj->vlist_trans[ vindex_0 ].x, obj->vlist_trans[ vindex_0 ].y,
- obj->vlist_trans[ vindex_1 ].x, obj->vlist_trans[ vindex_1 ].y,
- obj->vlist_trans[ vindex_2 ].x, obj->vlist_trans[ vindex_2 ].y,
- obj->plist[poly].color, video_buffer, lpitch);
- } // end for poly
- } // end Draw_OBJECT4DV1_Solid2_16
- ///////////////////////////////////////////////////////////////////////////
- void Draw_RENDERLIST4DV2_Textured(RENDERLIST4DV2_PTR rend_list,
- UCHAR *video_buffer,
- int lpitch,
- BITMAP_IMAGE_PTR texture)
- {
- // TEST FUNCTION ONLY!!!
- POLYF4DV2 face; // temp face used to render polygon
- // at this point, all we have is a list of polygons and it's time
- // to draw them
- for (int poly=0; poly < rend_list->num_polys; poly++)
- {
- // render this polygon if and only if it's not clipped, not culled,
- // active, and visible, note however the concecpt of "backface" is
- // irrelevant in a wire frame engine though
- if (!(rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_ACTIVE) ||
- (rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_CLIPPED ) ||
- (rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_BACKFACE) )
- continue; // move onto next poly
- // set the vertices
- face.tvlist[0].x = (int)rend_list->poly_ptrs[poly]->tvlist[0].x;
- face.tvlist[0].y = (int)rend_list->poly_ptrs[poly]->tvlist[0].y;
- face.tvlist[0].u0 = 0;
- face.tvlist[0].v0 = 0;
- face.tvlist[1].x = (int)rend_list->poly_ptrs[poly]->tvlist[1].x;
- face.tvlist[1].y = (int)rend_list->poly_ptrs[poly]->tvlist[1].y;
- face.tvlist[1].u0 = 0;
- face.tvlist[1].v0 = 63;
- face.tvlist[2].x = (int)rend_list->poly_ptrs[poly]->tvlist[2].x;
- face.tvlist[2].y = (int)rend_list->poly_ptrs[poly]->tvlist[2].y;
- face.tvlist[2].u0 = 63;
- face.tvlist[2].v0 = 63;
- // assign the texture
- face.texture = texture;
- // draw the textured triangle
- Draw_Textured_Triangle(&face, video_buffer, lpitch);
- } // end for poly
- } // end Draw_RENDERLIST4DV2_Textured
- ///////////////////////////////////////////////////////////////////////////
- void Draw_RENDERLIST4DV2_Textured16(RENDERLIST4DV2_PTR rend_list,
- UCHAR *video_buffer,
- int lpitch,
- BITMAP_IMAGE_PTR texture)
- {
- // TEST FUNCTION ONLY!!!!
- POLYF4DV2 face; // temp face used to render polygon
- // at this point, all we have is a list of polygons and it's time
- // to draw them
- for (int poly=0; poly < rend_list->num_polys; poly++)
- {
- // render this polygon if and only if it's not clipped, not culled,
- // active, and visible, note however the concecpt of "backface" is
- // irrelevant in a wire frame engine though
- if (!(rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_ACTIVE) ||
- (rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_CLIPPED ) ||
- (rend_list->poly_ptrs[poly]->state & POLY4DV2_STATE_BACKFACE) )
- continue; // move onto next poly
- // set the vertices
- face.tvlist[0].x = (int)rend_list->poly_ptrs[poly]->tvlist[0].x;
- face.tvlist[0].y = (int)rend_list->poly_ptrs[poly]->tvlist[0].y;
- face.tvlist[0].u0 = 0;
- face.tvlist[0].v0 = 0;
- face.tvlist[1].x = (int)rend_list->poly_ptrs[poly]->tvlist[1].x;
- face.tvlist[1].y = (int)rend_list->poly_ptrs[poly]->tvlist[1].y;
- face.tvlist[1].u0 = 0;
- face.tvlist[1].v0 = 63;
- face.tvlist[2].x = (int)rend_list->poly_ptrs[poly]->tvlist[2].x;
- face.tvlist[2].y = (int)rend_list->poly_ptrs[poly]->tvlist[2].y;
- face.tvlist[2].u0 = 63;
- face.tvlist[2].v0 = 63;
- // assign the texture
- face.texture = texture;
- // draw the textured triangle
- Draw_Textured_Triangle16(&face, video_buffer, lpitch);
- } // end for poly
- } // end Draw_RENDERLIST4DV2_Textured16
- /////////////////////////////////////////////////////////////////////////
- void Draw_OBJECT4DV1_Textured(OBJECT4DV1_PTR obj,
- UCHAR *video_buffer, int lpitch)
- {
- // TEST FUNCTION ONLY!!!
- // iterate thru the poly list of the object and simply draw
- // each polygon
- for (int poly=0; poly < obj->num_polys; poly++)
- {
- // render this polygon if and only if it's not clipped, not culled,
- // active, and visible, note however the concecpt of "backface" is
- // irrelevant in a wire frame engine though
- if (!(obj->plist[poly].state & POLY4DV1_STATE_ACTIVE) ||
- (obj->plist[poly].state & POLY4DV1_STATE_CLIPPED ) ||
- (obj->plist[poly].state & POLY4DV1_STATE_BACKFACE) )
- continue; // move onto next poly
- // extract vertex indices into master list, rember the polygons are
- // NOT self contained, but based on the vertex list stored in the object
- // itself
- int vindex_0 = obj->plist[poly].vert[0];
- int vindex_1 = obj->plist[poly].vert[1];
- int vindex_2 = obj->plist[poly].vert[2];
- // draw the triangle
- Draw_Triangle_2D(obj->vlist_trans[ vindex_0 ].x, obj->vlist_trans[ vindex_0 ].y,
- obj->vlist_trans[ vindex_1 ].x, obj->vlist_trans[ vindex_1 ].y,
- obj->vlist_trans[ vindex_2 ].x, obj->vlist_trans[ vindex_2 ].y,
- obj->plist[poly].color, video_buffer, lpitch);
- } // end for poly
- } // end Draw_OBJECT4DV1_Textured
- ///////////////////////////////////////////////////////////////
- void Draw_RENDERLIST4DV1_Textured(RENDERLIST4DV1_PTR rend_list,
- UCHAR *video_buffer,
- int lpitch,
- BITMAP_IMAGE_PTR texture)
- {
- // TEST FUNCTION
- POLYF4DV2 face; // temp face used to render polygon
- // at this point, all we have is a list of polygons and it's time
- // to draw them
- for (int poly=0; poly < rend_list->num_polys; poly++)
- {
- // render this polygon if and only if it's not clipped, not culled,
- // active, and visible, note however the concecpt of "backface" is
- // irrelevant in a wire frame engine though
- if (!(rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_ACTIVE) ||
- (rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_CLIPPED ) ||
- (rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_BACKFACE) )
- continue; // move onto next poly
- // set the vertices
- face.tvlist[0].x = (int)rend_list->poly_ptrs[poly]->tvlist[0].x;
- face.tvlist[0].y = (int)rend_list->poly_ptrs[poly]->tvlist[0].y;
- face.tvlist[0].u0 = 0;
- face.tvlist[0].v0 = 0;
- face.tvlist[1].x = (int)rend_list->poly_ptrs[poly]->tvlist[1].x;
- face.tvlist[1].y = (int)rend_list->poly_ptrs[poly]->tvlist[1].y;
- face.tvlist[1].u0 = 0;
- face.tvlist[1].v0 = 63;
- face.tvlist[2].x = (int)rend_list->poly_ptrs[poly]->tvlist[2].x;
- face.tvlist[2].y = (int)rend_list->poly_ptrs[poly]->tvlist[2].y;
- face.tvlist[2].u0 = 63;
- face.tvlist[2].v0 = 63;
- // assign the texture
- face.texture = texture;
- // draw the textured triangle
- Draw_Textured_Triangle(&face, video_buffer, lpitch);
- } // end for poly
- } // end Draw_RENDERLIST4DV1_Textured
- ///////////////////////////////////////////////////////////////
- void Draw_RENDERLIST4DV1_Textured16(RENDERLIST4DV1_PTR rend_list,
- UCHAR *video_buffer,
- int lpitch,
- BITMAP_IMAGE_PTR texture)
- {
- // TEST FUNCTION
- POLYF4DV2 face; // temp face used to render polygon
- // at this point, all we have is a list of polygons and it's time
- // to draw them
- for (int poly=0; poly < rend_list->num_polys; poly++)
- {
- // render this polygon if and only if it's not clipped, not culled,
- // active, and visible, note however the concecpt of "backface" is
- // irrelevant in a wire frame engine though
- if (!(rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_ACTIVE) ||
- (rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_CLIPPED ) ||
- (rend_list->poly_ptrs[poly]->state & POLY4DV1_STATE_BACKFACE) )
- continue; // move onto next poly
- // set the vertices
- face.tvlist[0].x = (int)rend_list->poly_ptrs[poly]->tvlist[0].x;
- face.tvlist[0].y = (int)rend_list->poly_ptrs[poly]->tvlist[0].y;
- face.tvlist[0].u0 = 0;
- face.tvlist[0].v0 = 0;
- face.tvlist[1].x = (int)rend_list->poly_ptrs[poly]->tvlist[1].x;
- face.tvlist[1].y = (int)rend_list->poly_ptrs[poly]->tvlist[1].y;
- face.tvlist[1].u0 = 0;
- face.tvlist[1].v0 = 63;
- face.tvlist[2].x = (int)rend_list->poly_ptrs[poly]->tvlist[2].x;
- face.tvlist[2].y = (int)rend_list->poly_ptrs[poly]->tvlist[2].y;
- face.tvlist[2].u0 = 63;
- face.tvlist[2].v0 = 63;
- // assign the texture
- face.texture = texture;
- // draw the textured triangle
- Draw_Textured_Triangle16(&face, video_buffer, lpitch);
- } // end for poly
- } // end Draw_RENDERLIST4DV1_Textured16