//============================================================================ // softgl_trirast_smooth.cpp // - code based on refernce rasterizer //============================================================================ //---------------------------------------------------------------------------- // CLAMP TO PIXEL VALUE THAT IS "INSIDE" BIASED TOWARDS MIN (INCLUDES MIN) //---------------------------------------------------------------------------- static inline float FindMin(const float MinBound) { float CntrVal = ((float)((int)MinBound)) + 0.5f; return( (MinBound>CntrVal) ? CntrVal+1.0f : CntrVal ); } static inline float FindMax(const float MaxBound) { float CntrVal = ((float)((int)MaxBound)) + 0.5f; return( (MaxBound<=CntrVal) ? CntrVal-1.0f : CntrVal ); } //---------------------------------------------------------------------------- // Fill in interpolated values for one scanline span given the endpoint x boundaries // (A and B endpoints) and perform Z-buffer visibility. Actual scanline Y floating // point value should be cast to int before call (chop fraction). //---------------------------------------------------------------------------- static void RasterizeSpan(unsigned char *Color, float *Depth, const int W, const int H, int ScanlineY, float Ax, float Az, float Acolor[3], float Bx, float Bz, float Bcolor[3]) { // FIND STARTING AND ENDING PIXEL SAMPLE X VALUES (MIN BIASED) float MinX=FindMin(Ax), MaxX=FindMax(Bx); if (MinX>MaxX) return; // POSSIBLE EARLY TERMINATION // CALCULATED PROPER INTERPOLATED VALUES FOR STARTING VALUE float ABx=(Bx-Ax), ABz=(Bz-Az); float ABcolor[3] = {Bcolor[0] - Acolor[0], Bcolor[1] - Acolor[1], Bcolor[2] - Acolor[2]}; float t=(MinX-Ax)/ABx; float Z=Az+ABz*t; float dZ = ABz/ABx; float curColor[3] = {Acolor[0] + ABcolor[0]*t, Acolor[1] + ABcolor[1]*t, Acolor[2] + ABcolor[2]*t}; // CALCULATE RATES OF CHANGE OF INTERPOLATED VALUES W.R.T. CHANGES IN X-VALUE float dColor[3] = {ABcolor[0] / ABx, ABcolor[1] / ABx, ABcolor[2] / ABx}; // CALCULATE STARTING ADDRESS OF COLOR AND DEPTH BUFFERS FOR SCANLINE (reuse variables) int StartX=(int)MinX, EndX=(int)MaxX, i=ScanlineY*W+StartX; Color = &(Color[i*3]); Depth = &(Depth[i]); for (; StartX<=EndX; StartX++) { if (Z<(*Depth)) { Color[0]=(unsigned char)curColor[0]; Color[1]=(unsigned char)curColor[1]; Color[2]=(unsigned char)curColor[2]; (*Depth)=Z; } Color+=3; Depth++; Z+=dZ; curColor[0] += dColor[0]; curColor[1] += dColor[1]; curColor[2] += dColor[2]; } } //---------------------------------------------------------------------------- // Given 3D triangle ABC in screen space with clipped coordinates within the following // bounds: x in [0,W], y in [0,H], z in [0,1]. The origin for (x,y) is in the bottom // left corner of the pixel grid. z=0 is the near plane and z=1 is the far plane, // so lesser values are closer. The coordinates of the pixels are evenly spaced // in x and y 1 units apart starting at the bottom-left pixel with coords // (0.5,0.5). In other words, the pixel sample point is in the center of the // rectangular grid cell containing the pixel sample. The framebuffer has // dimensions width x height (WxH). The Color buffer is a 1D array (row-major // order) with 3 unsigned chars per pixel (24-bit color). The Depth buffer is // a 1D array (also row-major order) with a float value per pixel // For a pixel location (x,y) we can obtain // the Color and Depth array locations as: Color[(((int)y)*W+((int)x))*3] // (for the red value, green is offset +1, and blue is offset +2 and // Depth[((int)y)*W+((int)x)]. Fills the pixels contained in the triangle // with the global current color and the properly linearly interpolated depth // value (performs Z-buffer depth test before writing new pixel). // Pixel samples that lie inside the triangle edges are filled with // a bias towards the minimum values (samples that lie exactly on a triangle // edge are filled only for minimum x values along a horizontal span and for // minimum y values, samples lying on max values are not filled). //--------------------------------------------------------------------------- //============================================================================ // softgl_trirast_smooth.hpp //============================================================================ void RasterizeTriangle_SMOOTH(unsigned char *Color, float *Depth, const int W, const int H, float A[3], float B[3], float C[3], float Ca[3], float Cb[3], float Cc[3]) // PER-VERTEX RGB COLORS { float *a=A, *b=B, *c=C, *t; // TEMPORARY VERTEX SORTING PTRS float *ca = Ca, *cb = Cb, *cc = Cc, *ct; // SORT VERTICES BY Y VALUES #define SWAP(a,b,t) t=a,a=b,b=t if (b[1]dACx) // IF BC IS ON THE LEFT { // geometry t=bcStartDY/BCy; // FRACTION ALONG BC FOR STARTING SCANLINE ltX=b[0]+BCx*t; // LEFT STARTING VALUES ltZ=b[2]+BCz*t; ltDX=dBCx; // LEFT RATES OF CHANGE ltDZ=BCz/BCy; // colors ltR=cb[0]+BCr*t; // LEFT RED STARTING VALUES ltG=cb[1]+BCg*t; // LEFT BLUE STARTING VALUES ltB=cb[2]+BCb*t; // LEFT GREEN STARTING VALUES ltDR=dBCr; // LEFT COLOR RATES OF CHANGE ltDG=dBCg; ltDB=dBCb; // geometry t=acStartDY/ACy; // FRACTION ALONG AC FOR STARTING SCANLINE rtX=a[0]+ACx*t; // RIGHT STARTING VALUES rtZ=a[2]+ACz*t; rtDX=dACx; // RIGHT RATES OF CHANGE rtDZ=ACz/ACy; // colors rtR=ca[0]+ACr*t; // RIGHT RED STARTING VALUES rtG=ca[1]+ACg*t; // RIGHT GREEN STARTING VALUES rtB=ca[2]+ACb*t; // RIGHT BLUE STARTING VALUES rtDR=dACr; // RIGHT COLOR RATES OF CHANGE rtDG=dACg; rtDB=dACb; } else // ELSE AC IS ON THE LEFT { // geometry t=acStartDY/ACy; // FRACTION ALONG AC FOR STARTING SCANLINE ltX=a[0]+ACx*t; // LEFT STARTING VALUES ltZ=a[2]+ACz*t; ltDX=dACx; // LEFT RATES OF CHANGE ltDZ=ACz/ACy; // colors ltR=ca[0]+ACr*t; // LEFT RED STARTING VALUES ltG=ca[1]+ACg*t; // LEFT BLUE STARTING VALUES ltB=ca[2]+ACb*t; // LEFT GREEN STARTING VALUES ltDR=dACr; // LEFT COLOR RATES OF CHANGE ltDG=dACg; ltDB=dACb; // geometry t=bcStartDY/BCy; // FRACTION ALONG AB FOR STARTING SCANLINE rtX=b[0]+BCx*t; // RIGHT STARTING VALUES rtZ=b[2]+BCz*t; rtDX=dBCx; // RIGHT RATES OF CHANGE rtDZ=BCz/BCy; // colors rtR=cb[0]+BCr*t; // RIGHT RED STARTING VALUES rtG=cb[1]+BCg*t; // RIGHT GREEN STARTING VALUES rtB=cb[2]+BCb*t; // RIGHT BLUE STARTING VALUES rtDR=dBCr; // RIGHT COLOR RATES OF CHANGE rtDG=dBCg; rtDB=dBCb; } for (; bStartY<=bEndY; bStartY++) // INCREMENTALLY COMPUTE LT,RT VALUES FOR EACH SCANLINE { float ltColor[3] = {ltR, ltG, ltB}; float rtColor[3] = {rtR, rtG, rtB}; RasterizeSpan(Color,Depth,W,H,(int)bStartY,ltX,ltZ,ltColor, rtX,rtZ,rtColor); ltX+=ltDX; ltZ+=ltDZ; ltR+=ltDR; ltG+=ltDG; ltB+=ltDB; rtX+=rtDX; rtZ+=rtDZ; rtR+=rtDR; rtG+=rtDG; rtB+=rtDB; } } }