// LineStencil.cpp #include "stdafx.h" #include "LineStencil.h" #include "PixelBlock.h" void CLineStencil::Line(const CPoint& S, const CPoint& E, DWORD Colour) {Line((WORD)S.x,(WORD)S.y, (WORD)E.x,(WORD)E.y, Colour);} #pragma warning (disable: 4244) // conversion from 'int' to 'WORD', possible loss of data void CLineStencil::Line(WORD x0, WORD y0, WORD x1, WORD y1, DWORD Colour) { short dx, dy, xDir; if(y0>y1) { Swap(y0,y1); Swap(x0,x1); } SetPixel(x0,y0, Colour); // First and last Pixels always get Set: SetPixel(x1,y1, Colour); dx=x1-x0; dy=y1-y0; if(dx>=0) xDir=1; else { xDir=-1; dx=-dx; } /* This 'special case' version could be far faster if clipping is implemented. At the moment, it is still faster, but misses lines completely if they are not entirely within the PixelBlock! DWORD* ptr=GetPointer(x0,y0); if((ptr==0) || (x1>GetWidth()) || (y1>GetHeight())) return; // This is the only attempt at clipping in this routine! if(dx==0) { // vertical line while(dy--) {*ptr=Colour; ptr+=GetWidth();} return; } if(dy==0) { // horizontal line if(x0>x1) while(dx--) *ptr--=Colour; else while(dx--) *ptr++=Colour; return; } if(dx==dy) { // diagonal line. while(dy--) {*ptr=Colour; ptr+=GetWidth()+xDir;} return; } The following special cases are slow because they test every pixel is valid, but at least they draw everything you expect! */ if(dx==0) { // vertical line for(; dy--; ++y0) SetPixel(x0,y0,Colour); return; } if(dy==0) { // horizontal line for(; dx--; x0+=xDir) SetPixel(x0,y0,Colour); return; } if(dx==dy) { // diagonal line. for(; dy--; x0+=xDir, ++y0) SetPixel(x0,y0,Colour); return; } // line is not horizontal, diagonal, or vertical: use Wu Antialiasing: DWORD ErrorAcc=0; BYTE Transparency; if(dy>dx) { // y-major line DWORD ErrorAdj=((DWORD)dx<<16) / (DWORD)dy; if(xDir<0) { while(--dy) { ErrorAcc+=ErrorAdj; ++y0; x1=x0-(WORD)(ErrorAcc>>16); Transparency=(BYTE)(ErrorAcc>>8); BlendPixel(x1 , y0, Colour, Transparency); BlendPixel(x1-1, y0, Colour, ~Transparency); } }else{ while(--dy) { ErrorAcc+=ErrorAdj; ++y0; x1=x0+(WORD)(ErrorAcc>>16); Transparency=(BYTE)(ErrorAcc>>8); BlendPixel(x1 , y0, Colour, Transparency); BlendPixel(x1+xDir, y0, Colour, ~Transparency); } } }else{ // x-major line DWORD ErrorAdj=((DWORD)dy<<16) / (DWORD)dx; while(--dx) { ErrorAcc+=ErrorAdj; x0+=xDir; y1=y0+(WORD)(ErrorAcc>>16); Transparency=(BYTE)(ErrorAcc>>8); BlendPixel(x0, y1 , Colour, Transparency); BlendPixel(x0, y1+1, Colour, ~Transparency); } } } #pragma warning (default: 4244)