1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489 |
- ///////////////////////////////////////////////////////////////////////////////
- // CDraw32 Class Implementation
- //
- // Basic drawing routines for 32-bit buffer
- ///////////////////////////////////////////////////////////////////////////////
- #include "../server/exe_headers.h"
- #include "cm_local.h"
- #include "cm_draw.h"
- ///////////// statics for CDraw32 //////////////////////////////////
- // Used by all drawing routines as the "current" drawing context
- CPixel32* CDraw32::buffer = NULL; // pointer to 32-bit deep pixel buffer
- long CDraw32::buf_width=0; // width of buffer in pixels
- long CDraw32::buf_height=0; // height of buffer in pixels
- long CDraw32::stride = 0; // stride in pixels
- long CDraw32::clip_min_x=0; // clip bounds
- long CDraw32::clip_min_y=0; // clip bounds
- long CDraw32::clip_max_x=0; // clip bounds
- long CDraw32::clip_max_y=0; // clip bounds
- long* CDraw32::row_off = NULL; // Table for quick Y calculations
- CDraw32::CDraw32()
- //USE: constructor
- {
- }
- CDraw32::~CDraw32()
- //USE: Destructor
- {
- }
- int imgKernel[5][5] =
- {
- {-1,-1,-1,-1, 0},
- {-1,-1,-1, 0, 1},
- {-1,-1, 0, 1, 1},
- {-1, 0, 1, 1, 1},
- { 0, 1, 1, 1, 1}
- };
- const int KWIDTH = 2;
- void CDraw32::Emboss(long dstX, long dstY, long width, long height,
- CPixel32* clrImage, long clrX, long clrY, long clrStride)
- {
- CPixel32 *dst;
- CPixel32 *clr;
- int x,y,i,j;
- int dstNextLine;
- int clrNextLine;
- assert(buffer != NULL);
- BlitClip(dstX, dstY, width, height, clrX, clrY);
- if (width < 1 || height < 1)
- return;
- dst = &buffer[PIXPOS(dstX,dstY,stride)];
- clr = &clrImage[PIXPOS(clrX,clrY,clrStride)];
- dstNextLine = (stride - width);
- clrNextLine = (clrStride - width);
- for (y = 0; y < height; y++)
- {
- for (x = 0; x < width; x++)
- {
- int accum = 0;
- for (j = -KWIDTH; j<=KWIDTH; j++)
- for (i = -KWIDTH; i<=KWIDTH; i++)
- {
- int xk = CLAMP(x + i, clrX, clrX+width-1);
- int yk = CLAMP(y + j, clrY, clrY+height-1);
- accum += clrImage[PIXPOS(xk,yk,clrStride)].a * imgKernel[j+KWIDTH][i+KWIDTH];
- }
- *dst = LIGHT_PIX(*clr, accum);
- dst->a = 255;
- ++dst;
- ++clr;
- }
- dst += dstNextLine;
- clr += clrNextLine;
- }
- }
- bool CDraw32::SetBufferSize(long width,long height,long stride_len)
- //USE: setup for a particular size drawing buffer
- // (do not re-setup if buffer size has not changed)
- //IN: width,height - size of buffer
- // stride_len - distance to next line
- //OUT: true if everything goes OK, otherwise false
- {
- long i;
- assert(width!=0);
- assert(height!=0);
- assert(stride_len!=0);
- if (buf_width != width || buf_height != height ||
- stride_len != stride)
- { // need to re-create row_off table
- buf_width = width;
- buf_height = height;
- stride = stride_len;
- if (row_off)
- delete [] row_off;
- // row offsets used for quick pixel address calcs
- row_off = new long[height];
- assert(row_off != NULL);
- if (row_off == NULL)
- return false;
- // table for quick pixel lookups
- for (i=0; i<height; i++)
- row_off[i] = i * stride;
- }
- // set default clip bounds
- SetClip(0, 0, width-1, height-1);
- return true;
- }
- void CDraw32::ClearLines(CPixel32 color,long start,long end)
- //USE: clear screen buffer to color provided for lines
- //IN: color - 32-bit color value
- // start through end - line numbers
- //OUT: none
- {
- CPixel32 *dest;
- int line,i,next_line;
- assert(buffer!=NULL);
- assert(start>=0);
- assert(end<buf_height);
- dest = &buffer[row_off[start]];
- next_line = stride - buf_width;
- line = end - start + 1;
- while (line-- != 0)
- { // very simple-minded fill loop
- i = buf_width;
- while (i--)
- *dest++ = color;
- dest += next_line;
- }
- }
- void CDraw32::SetAlphaLines(byte alpha,long start,long end)
- //USE: set the alpha value only
- //IN: alpha - 8-bit alpha value
- // start through end - line numbers
- //OUT: none
- {
- CPixel32 *dest;
- int line,i,next_line;
- assert(buffer!=NULL);
- assert(start>=0);
- assert(end<buf_height);
- dest = &buffer[row_off[start]];
- next_line = stride - buf_width;
- line = end - start + 1;
- while (line-- != 0)
- { // very simple-minded fill loop
- i = buf_width;
- while (i--)
- {
- dest->a = alpha;
- ++dest;
- }
- dest += next_line;
- }
- }
- #define LEFT 1 // code bits
- #define RIGHT 2
- #define TOP 4
- #define BOTTOM 8
- static long code(long x,long y)
- //USE: determines where a point is in relation to a bounding box
- //IN: x,y - coordinate pair
- //OUT: clipping code compaired to global clip context
- {
- long c;
- c = 0;
- if (x < CDraw32::clip_min_x) c |= LEFT;
- if (x > CDraw32::clip_max_x) c |= RIGHT;
- if (y < CDraw32::clip_min_y) c |= BOTTOM;
- if (y > CDraw32::clip_max_y) c |= TOP;
- return c;
- }
- bool CDraw32::ClipLine(long& x1, long& y1, long& x2, long& y2)
- //USE: clip a line from (x1,y1) to (x2,y2) to clip bounds
- //IN: (x1,y1)-(x2,y2) line
- //OUT: return true if something left to draw, otherwise false
- {
- long c1,c2,c,x,y,f;
- x = x1;
- y = y1;
- c1 = code(x1,y1); // find where first pt. is
- c2 = code(x2,y2); // find where second pt. is
- if ((c1 & c2) == 0)
- { // the line may be visible
- while (c1 | c2)
- { // where there is 2D clipping to be done
- if (c1 & c2)
- {
- return false; // if both on same side, quit
- }
- c = c1;
- if (c==0)
- {
- c = c2; // pick a point
- }
- if (c & TOP)
- {
- f = ((clip_max_y-y1) << 15)/(y2-y1);
- x = x1 + (((x2-x1)*f + 16384) >> 15);
- y = clip_max_y;
- }
- else if (c & BOTTOM)
- {
- f = ((clip_min_y-y1) << 15)/(y2-y1);
- x = x1 + (((x2-x1)*f + 16384) >> 15);
- y = clip_min_y;
- }
- else if (c & LEFT)
- {
- f = ((clip_min_x-x1) << 15)/(x2-x1);
- y = y1 + (((y2-y1)*f + 16384) >> 15);
- x = clip_min_x;
- }
- else if (c & RIGHT)
- {
- f = ((clip_max_x-x1) << 15)/(x2-x1);
- y = y1 + (((y2-y1)*f + 16384) >> 15);
- x = clip_max_x;
- }
- if (c==c1)
- {
- x1=x; y1=y; c1=code(x1,y1);
- }
- else
- {
- x2=x; y2=y; c2=code(x2,y2);
- }
- } // while still needs clipping
- }
- else
- { // line not visible
- return false;
- }
- return true;
- }
- void CDraw32::DrawLineNC(long x1, long y1, long x2, long y2, CPixel32 color)
- //USE: draw a line from (x1,y1) to (x2,y2) in color (no clip)
- //IN: (x1,y1) - starting coordinate
- // (x2,y2) - ending coordinate
- // color - 32-bit color value
- //OUT: none
- {
- long d, ax, ay, sx, sy, dx, dy;
- CPixel32* dest;
- assert(buffer != NULL);
- dx = x2-x1;
- ax = ABS(dx) << 1;
- sx = SIGN(dx);
- dy = y2-y1;
- ay = ABS(dy) << 1;
- sy = SIGN(dy);
- if (255 == color.a)
- {
- if (dy == 0)
- { // horz line
- if (dx >= 0)
- {
- dest = &buffer[row_off[y1] + x1];
- int i = dx+1;
- while (i--)
- *dest++ = color;
- }
- else
- {
- dest = &buffer[row_off[y1] + x1 + dx];
- int i = -dx+1;
- while (i--)
- *dest++ = color;
- }
- return;
- }
- if (dx == 0)
- { // vert line
- if (dy >= 0)
- {
- dest = &buffer[row_off[y1] + x1];
- dy++;
- }
- else
- {
- dest = &buffer[row_off[y2] + x1];
- dy = -dy + 1;
- }
- while (dy-- != 0)
- {
- *dest = color;
- dest += stride;
- }
- return;
- }
- }
- // bressenham's algorithm
- if (ax > ay)
- {
- d = ay - (ax >> 1);
- while(x1 != x2)
- {
- PutPixAlphaNC(x1,y1,color);
- if (d >= 0)
- {
- y1 += sy;
- d -= ax;
- }
- x1 += sx;
- d += ay;
- }
- }
- else
- {
- d = ax - (ay >> 1);
- while(y1 != y2)
- {
- PutPixAlphaNC(x1,y1,color);
- if (d >= 0)
- {
- x1 += sx;
- d -= ay;
- }
- y1 += sy;
- d += ax;
- }
- }
- PutPixAlphaNC(x1,y1,color);
- }
- void CDraw32::DrawLineAveNC(long x1, long y1, long x2, long y2, CPixel32 color)
- //USE: draw a translucent line from (x1,y1) to (x2,y2) in color (no clip)
- //IN: (x1,y1) - starting coordinate
- // (x2,y2) - ending coordinate
- // color - 32-bit color value
- //OUT: none
- {
- long d, ax, ay, sx, sy, dx, dy;
- CPixel32* dest;
- assert(buffer != NULL);
- dx = x2-x1;
- ax = ABS(dx) << 1;
- sx = SIGN(dx);
- dy = y2-y1;
- ay = ABS(dy) << 1;
- sy = SIGN(dy);
- if (dy == 0)
- { // horz line
- if (dx >= 0)
- {
- dest = &buffer[row_off[y1] + x1];
- int i = dx+1;
- while (i--)
- *dest++ = AVE_PIX(*dest, color);
- }
- else
- {
- dest = &buffer[row_off[y1] + x1 + dx];
- int i = -dx+1;
- while (i--)
- *dest++ = AVE_PIX(*dest, color);
- }
- return;
- }
- if (dx == 0)
- { // vert line
- if (dy >= 0)
- {
- dest = &buffer[row_off[y1] + x1];
- dy++;
- }
- else
- {
- dest = &buffer[row_off[y2] + x1];
- dy = -dy + 1;
- }
- while (dy-- != 0)
- {
- *dest = AVE_PIX(*dest, color);
- dest += stride;
- }
- return;
- }
- // bressenham's algorithm
- if (ax > ay)
- {
- d = ay - (ax >> 1);
- while(x1 != x2)
- {
- PutPixAveNC(x1,y1,color);
- if (d >= 0)
- {
- y1 += sy;
- d -= ax;
- }
- x1 += sx;
- d += ay;
- }
- }
- else
- {
- d = ax - (ay >> 1);
- while(y1 != y2)
- {
- PutPixAveNC(x1,y1,color);
- if (d >= 0)
- {
- x1 += sx;
- d -= ay;
- }
- y1 += sy;
- d += ax;
- }
- }
- PutPixAveNC(x1,y1,color);
- }
- void CDraw32::DrawLineAANC(long x0, long y0, long x1, long y1, CPixel32 color)
- // Wu antialiased line drawer.
- //USE: Function to draw an antialiased line from (x0,y0) to (x1,y1), using an
- // antialiasing approach published by Xiaolin Wu in the July 1991 issue of
- // Computer Graphics (SIGGRAPH proceedings).
- //
- //IN: (x0,y0),(x1,y1) = line to draw
- // color = 32-bit color
- //OUT: none
- {
- assert(buffer != NULL);
- // Make sure the line runs top to bottom
- if (y0 > y1)
- {
- SWAP(y0,y1);
- SWAP(x0,x1);
- }
- long DeltaX = x1 - x0;
- long DeltaY = y1 - y0;
- long XDir;
- // Draw the initial pixel, which is always exactly intersected by
- // the line and so needs no Alpha
- PutPixAlphaNC(x0, y0, color);
- if (DeltaX >= 0)
- {
- XDir = 1;
- }
- else
- {
- XDir = -1;
- DeltaX = -DeltaX; // make DeltaX positive
- }
- // Special-case horizontal, vertical, and diagonal lines, which
- // require no Alpha because they go right through the center of
- // every pixel
- if (DeltaY == 0)
- { // Horizontal line
- while (DeltaX-- != 0)
- {
- x0 += XDir;
- PutPixAlphaNC(x0, y0, color);
- }
- return;
- }
- if (DeltaX == 0)
- { // Vertical line
- do
- {
- y0++;
- PutPixAlphaNC(x0, y0, color);
- }
- while (--DeltaY != 0);
- return;
- }
- if (DeltaX == DeltaY)
- { // Diagonal line
- do
- {
- x0 += XDir;
- y0++;
- PutPixAlphaNC(x0, y0, color);
- }
- while (--DeltaY != 0);
- return;
- }
- // Line is not horizontal, diagonal, or vertical
- unsigned short ErrorAcc = 0; // initialize the line error accumulator to 0
- // # of bits by which to shift ErrorAcc to get intensity level
- const unsigned long IntensityShift = 16 - 8;
-
- // Is this an X-major or Y-major line?
- if (DeltaY > DeltaX)
- {
- // Y-major line; calculate 16-bit fixed-point fractional part of a
- // pixel that X advances each time Y advances 1 pixel, truncating the
- // result so that we won't overrun the endpoint along the X axis
- unsigned short ErrorAdj = unsigned short
- (((unsigned long) DeltaX << 16) / (unsigned long) DeltaY);
- // Draw all pixels other than the first and last
- while (--DeltaY)
- {
- unsigned short ErrorAccTemp = ErrorAcc; // remember currrent accumulated error
- ErrorAcc += ErrorAdj; // calculate error for next pixel
- if (ErrorAcc <= ErrorAccTemp)
- { // The error accumulator turned over, so advance the X coord
- x0 += XDir;
- }
- y0++; // Y-major, so always advance Y
- // The IntensityBits most significant bits of ErrorAcc give us the
- // intensity Alpha for this pixel, and the complement of the
- // Alpha for the paired pixel
- unsigned long Alpha = ErrorAcc >> IntensityShift;
- unsigned long InvAlpha = 256-Alpha;
- PutPixAlphaNC(x0, y0,
- ALPHA_PIX(GetPix(x0, y0), color, Alpha, InvAlpha));
- PutPixAlphaNC(x0+XDir, y0,
- ALPHA_PIX(GetPix(x0+XDir, y0), color, InvAlpha, Alpha));
- }
- // Draw the final pixel, which is always exactly intersected by the line
- // and so needs no Alpha
- PutPixAlphaNC(x1, y1, color);
- return;
- }
- // It's an X-major line; calculate 16-bit fixed-point fractional part of a
- // pixel that Y advances each time X advances 1 pixel, truncating the
- // result to avoid overrunning the endpoint along the X axis
- unsigned short ErrorAdj = unsigned short
- (((unsigned long) DeltaY << 16) / (unsigned long) DeltaX);
- // Draw all pixels other than the first and last
- while (--DeltaX)
- {
- unsigned short ErrorAccTemp = ErrorAcc; // remember currrent accumulated error
- ErrorAcc += ErrorAdj; // calculate error for next pixel
- if (ErrorAcc <= ErrorAccTemp)
- { // The error accumulator turned over, so advance the Y coord
- y0++;
- }
- x0 += XDir; // X-major, so always advance X
- // The IntensityBits most significant bits of ErrorAcc give us the
- // intensity Alpha for this pixel, and the complement of the
- // Alpha for the paired pixel
- unsigned long Alpha = ErrorAcc >> IntensityShift;
- unsigned long InvAlpha = 256-Alpha;
- PutPixAlphaNC(x0, y0,
- ALPHA_PIX(GetPix(x0, y0), color, Alpha, InvAlpha));
- PutPixAlphaNC(x0, y0+1,
- ALPHA_PIX(GetPix(x0, y0+1), color, InvAlpha, Alpha));
- }
- // Draw the final pixel, which is always exactly intersected by the line
- // and so needs no Alpha
- PutPixAlphaNC(x1, y1, color);
- }
- void CDraw32::DrawRectNC(long ulx, long uly, long width, long height, CPixel32 color)
- //USE: draw rectangle in solid color, no clipping
- //IN: (ulx,uly) - coordinates of upper-left corner of rect
- // width, height - dimensions of rectangle
- // color - color value
- //OUT: none
- {
- assert(buffer != NULL);
- assert(ulx>=0);
- assert(uly>=0);
- assert(ulx+width<buf_width);
- assert(uly+height<buf_height);
- if (height < 1 || width < 1)
- return;
- while (height-- != 0)
- {
- DrawLineNC(ulx, uly, ulx+width-1, uly, color);
- uly++;
- }
- }
- void CDraw32::DrawRect(long ulx, long uly, long width, long height, CPixel32 color)
- //USE: draw rectangle in solid color
- //IN: (ulx,uly) - coordinates of upper-left corner of rect
- // width, height - dimensions of rectangle
- // color - color value
- //OUT: none
- {
- assert(buffer != NULL);
- if (height < 1 || width < 1)
- return;
- while (height-- != 0)
- {
- DrawLine(ulx, uly, ulx+width-1, uly, color);
- uly++;
- }
- }
- void CDraw32::DrawRectAve(long ulx, long uly, long width, long height, CPixel32 color)
- //USE: draw rectangle in solid color, translucent
- //IN: (ulx,uly) - coordinates of upper-left corner of rect
- // width, height - dimensions of rectangle
- // color - color value
- //OUT: none
- {
- assert(buffer != NULL);
- if (height < 1 || width < 1)
- return;
- while (height-- != 0)
- {
- DrawLineAve(ulx, uly, ulx+width-1, uly, color);
- uly++;
- }
- }
- void CDraw32::DrawBoxNC(long ulx, long uly, long width, long height, CPixel32 color)
- //USE: Draw an empty box, no clipping
- //IN: (ulx,uly) - coordinates of upper-left corner of box
- // width, height - dimensions of box
- // color - color value
- //OUT: none
- {
- assert(buffer != NULL);
- if (height < 1 || width < 1)
- return;
- DrawLineNC(ulx, uly, ulx+width-1, uly, color);
- DrawLineNC(ulx, uly+height-1, ulx+width-1, uly+height-1, color);
- DrawLineNC(ulx, uly, ulx, uly+height-1, color);
- DrawLineNC(ulx+width-1, uly, ulx+width-1, uly+height-1, color);
- }
- void CDraw32::DrawBox(long ulx, long uly, long width, long height, CPixel32 color)
- //USE: Draw an empty box
- //IN: (ulx,uly) - coordinates of upper-left corner of rect
- // width, height - dimensions of rectangle
- // color - color value
- //OUT: none
- {
- assert(buffer != NULL);
- if (height < 1 || width < 1)
- return;
- DrawLine(ulx, uly, ulx+width-1, uly, color);
- DrawLine(ulx, uly+height-1, ulx+width-1, uly+height-1, color);
- DrawLine(ulx, uly, ulx, uly+height-1, color);
- DrawLine(ulx+width-1, uly, ulx+width-1, uly+height-1, color);
- }
- void CDraw32::DrawBoxAve(long ulx, long uly, long width, long height, CPixel32 color)
- //USE: Draw an empty box, translucent
- //IN: (ulx,uly) - coordinates of upper-left corner of rect
- // width, height - dimensions of rectangle
- // color - color value
- //OUT: none
- {
- assert(buffer!=NULL);
- if (height < 1 || width < 1)
- return;
- DrawLineAve(ulx, uly, ulx+width-1, uly, color);
- DrawLineAve(ulx, uly+height-1, ulx+width-1, uly+height-1, color);
- DrawLineAve(ulx, uly, ulx, uly+height-1, color);
- DrawLineAve(ulx+width-1, uly, ulx+width-1, uly+height-1, color);
- }
- void CDraw32::DrawCircle(long xc, long yc, long r, CPixel32 edge, CPixel32 fill)
- //USE: Draw a simple circle in current color with Bresenham's
- // circle algorithm.
- // See PROCEDURAL ELEMENTS FOR COMPUTER GRAPHICS
- // David F. Rogers Pg. 48.
- //
- //IN: xc,yc - center
- // r - radius
- // edge - edge color
- // fill - fill color
- //
- //OUT: NONE (a circle drawn in the off-screen buffer)
- {
- long x,y;
- long limit,di,delta;
- long last_x,last_y;
- assert(buffer != NULL);
- if (r < 1)
- return;
- // draw fill
- if (fill.a != 0)
- {
- x = 0; last_x = x;
- y = r; last_y = y;
- di = 2*(1-r);
- limit = 0;
- do
- {
- if (y >= limit)
- {
- if (di < 0)
- {
- delta = 2*di + 2*y - 1;
- if (delta <= 0)
- { // move horizontal
- last_x = x;
- x++;
- di += (2*x + 1);
- }
- else
- { // move diagonal
- last_x = x;
- x++;
- y--;
- di += (2*x - 2*y + 2);
- }
- }
- else
- {
- if (di > 0)
- {
- delta = 2*di - 2*x -1;
- if (delta <= 0)
- { // move diagonal
- last_x = x;
- x++;
- y--;
- di += (2*x - 2*y + 2);
- }
- else
- { // move vertical
- y--;
- di += (1 - 2*y);
- }
- }
- else /* di = 0 */
- { // move diagonal
- last_x = x;
- x++;
- y--;
- di += (2*x - 2*y + 2);
- }
- }
- }
- if (y != last_y)
- { // circle fill
- DrawLine(xc-last_x,yc+last_y,xc+last_x,yc+last_y,fill);
- if (last_y > limit)
- {
- DrawLine(xc-last_x,yc-last_y,xc+last_x,yc-last_y,fill);
- }
- last_y = y;
- }
- } while (y >= limit);
- }
- // draw edge
- if (edge.a != 0)
- {
- x = 0;
- y = r;
- limit = 0;
- di = 2*(1-r);
- do
- {
- // circle edge
- PutPix(xc+x, yc+y, edge);
- PutPix(xc-x, yc+y, edge);
- if (y > limit)
- {
- PutPix(xc+x, yc-y, edge);
- PutPix(xc-x, yc-y, edge);
- }
- if (y >= limit)
- {
- if (di < 0)
- {
- delta = 2*di + 2*y - 1;
- if (delta <= 0)
- { // move horizontal
- x++;
- di += (2*x + 1);
- }
- else
- { // move diagonal
- x++;
- y--;
- di += (2*x - 2*y + 2);
- }
- }
- else
- {
- if (di > 0)
- {
- delta = 2*di - 2*x -1;
- if (delta <= 0)
- { // move diagonal
- x++;
- y--;
- di += (2*x - 2*y + 2);
- }
- else
- { // move vertical
- y--;
- di += (1 - 2*y);
- }
- }
- else /* di = 0 */
- { // move diagonal
- x++;
- y--;
- di += (2*x - 2*y + 2);
- }
- }
- }
- } while (y >= limit);
- }
- } // DrawCircle
- void CDraw32::DrawCircleAve(long xc, long yc, long r, CPixel32 edge, CPixel32 fill)
- //USE: Draw a simple circle in current color with Bresenham's
- // circle algorithm.
- // a circle with fill and edge colors averaged with dest (-1 = no color)
- // See PROCEDURAL ELEMENTS FOR COMPUTER GRAPHICS
- // David F. Rogers Pg. 48.
- //
- //IN: xc,yc - center
- // r - radius
- // edge - edge color
- // fill - fill color
- //
- //OUT: none (a circle on in the off-screen buffer)
- {
- long x,y;
- long limit,di,delta;
- long last_x,last_y;
- long f;
- assert(buffer != NULL);
- if (r < 1)
- return;
- // draw fill
- if (fill.a != 0)
- {
- x = 0; last_x = x;
- y = r; last_y = y;
- di = 2*(1-r);
- limit = 0;
- do
- {
- if (y >= limit)
- {
- if (di < 0)
- {
- delta = 2*di + 2*y - 1;
- if (delta <= 0)
- { // move horizontal
- last_x = x;
- x++;
- di += (2*x + 1);
- }
- else
- { // move diagonal
- last_x = x;
- x++;
- y--;
- di += (2*x - 2*y + 2);
- }
- }
- else
- {
- if (di > 0)
- {
- delta = 2*di - 2*x -1;
- if (delta <= 0)
- { // move diagonal
- last_x = x;
- x++;
- y--;
- di += (2*x - 2*y + 2);
- }
- else
- { // move vertical
- y--;
- di += (1 - 2*y);
- }
- }
- else /* di = 0 */
- { // move diagonal
- last_x = x;
- x++;
- y--;
- di += (2*x - 2*y + 2);
- }
- }
- }
- if (y != last_y)
- { // circle fill
- for (f=xc-last_x; f<=xc+last_x; f++)
- PutPixAve(f, yc+last_y, fill);
- if (last_y > limit)
- {
- for (f=xc-last_x; f<=xc+last_x; f++)
- PutPixAve(f, yc-last_y, fill);
- }
- last_y = y;
- }
- } while (y >= limit);
- }
- // draw edge
- if (edge.a != 0)
- {
- x = 0;
- y = r;
- limit = 0;
- di = 2*(1-r);
- do
- {
- // circle edge
- PutPixAve(xc+x, yc+y, edge);
- PutPixAve(xc-x, yc+y, edge);
- if (y > limit)
- {
- PutPixAve(xc+x, yc-y, edge);
- PutPixAve(xc-x, yc-y, edge);
- }
- if (y >= limit)
- {
- if (di < 0)
- {
- delta = 2*di + 2*y - 1;
- if (delta <= 0)
- { // move horizontal
- x++;
- di += (2*x + 1);
- }
- else
- { // move diagonal
- x++;
- y--;
- di += (2*x - 2*y + 2);
- }
- }
- else
- {
- if (di > 0)
- {
- delta = 2*di - 2*x -1;
- if (delta <= 0)
- { // move diagonal
- x++;
- y--;
- di += (2*x - 2*y + 2);
- }
- else
- { // move vertical
- y--;
- di += (1 - 2*y);
- }
- }
- else /* di = 0 */
- { // move diagonal
- x++;
- y--;
- di += (2*x - 2*y + 2);
- }
- }
- }
- } while (y >= limit);
- }
- } // DrawCircleAve
- ////////////////////////////////////////////////////////////////////////////
- //Concave Polygon Scan Conversion
- ////////////////////////////////////////////////////////////////////////////
- // concave: scan convert nvert-sided concave non-simple polygon
- // with vertices at (point[i].x, point[i].y) for i in
- // [0..nvert-1] within the window win by
- // calling spanproc for each visible span of pixels.
- //
- // Polygon can be clockwise or counterclockwise.
- //
- // Algorithm does uniform point sampling at pixel centers.
- // Inside-outside test done by even-odd rule: a point is
- // considered inside if an emanating ray intersects the polygon
- // an odd number of times.
- //
- // spanproc should fill in pixels from xl to xr inclusive on scanline y,
- //
- // e.g:
- // spanproc(short y, short xl, short xr)
- // {
- // short x;
- // for (x=xl; x<=xr; x++)
- // pixel_write(x, y, pixelvalue);
- // }
- typedef struct
- { // a polygon edge
- // these are fixed point long ints for some accuracy & speed
- long x; // x coordinate of edge's intersection with current scanline
- long dx; // change in x with respect to y
- long i; // edge number: edge i goes from pt[i] to
- // pt[i+1]
- } POLYEDGE;
- #define INT_SHIFT 13
- // global for speed
- static long n; // number of vertices
- static POINT *pt; // vertices
- static long nact; // number of active edges
- static POLYEDGE active[256]; // active edge list:edges crossing scanline y
- static long ind[256]; // list of vertex indices, sorted by
- // pt[ind[j]].y
- static void del_edge(long i)
- // remove edge i from active list
- {
- int j;
- for (j = 0; j < nact && active[j].i != i; j++)
- ;
- // edge not in active list; happens at cliprect->top
- if (j >= nact)
- {
- return;
- }
- nact--;
- memcpy(&active[j], &active[j + 1], (nact - j) * sizeof(active[0]));
- }
- static void ins_edge(long i, long y)
- // append edge i to end of active list
- {
- int j;
- long dx;
- POINT *p;
- POINT *q;
- j = i < n - 1 ? i + 1 : 0;
- if (pt[i].y < pt[j].y)
- {
- p = &pt[i];
- q = &pt[j];
- }
- else
- {
- p = &pt[j];
- q = &pt[i];
- }
- // initialize x position at intersection of edge with scanline y
- if ((q->y - p->y) != 0)
- {
- dx = (((long)q->x - (long)p->x) * (long)(1<<INT_SHIFT));
- dx /= (((long)q->y - (long)p->y));
- }
- else
- {
- // horizontal line
- dx = 0;
- }
- active[nact].dx = dx;
- active[nact].x = (dx * (long)(y - p->y)) + ((long)p->x << INT_SHIFT);
- active[nact].i = i;
- nact++;
- }
- // comparison routines for shellsort
- int compare_ind(long *u, long *v)
- {
- return (pt[*u].y <= pt[*v].y ? -1 : 1);
- }
- int compare_active(POLYEDGE *u, POLYEDGE *v)
- {
- return (u->x <= v->x ? -1 : 1);
- }
- void shell_sort(void *vec, long n, long siz,
- int (*compare)(void*,void*))
- // USE: shell sort aka heap sort. Best sort algorithm for almost sorted list.
- {
- byte *a;
- byte v[128]; // temp object
- long i,j,h;
- a = (byte *)vec;
- // choose size of "heap"
- for (h = 1; h <= n/9; h = 3*h+1)
- ;
- // divide and conq.
- for ( ; h > 0; h /= 3)
- {
- for (i = h; i < n; i++)
- {
- // v = a[i];
- memcpy(v,(a+i*siz),siz);
- j = i;
- // j >= h && a[j-h] > v
- while ((j >= h) && compare((void*)(a+(j-h)*siz),(void*)v) > 0)
- {
- // a[j] = a[j-h]
- memcpy((a+j*siz),(a+(j-h)*siz),siz);
- j -= h;
- }
- // a[j] = v;
- memcpy((a+j*siz),v,siz);
- }
- }
- }
- void CDraw32::DrawPolygon(long nvert, POINT *point, CPixel32 edge, CPixel32 fill)
- //USE: Scan convert a polygon
- //IN: nvert: Number of vertices
- // point: Vertices of polygon
- // edge: edge color
- // fill: fill color
- //OUT: none
- {
- long k,
- y0,
- y1,
- y,
- i,
- j,
- xl,
- xr;
- assert(buffer != NULL);
- n = nvert;
- if (n <= 0)
- { // nothing to do
- return;
- }
- pt = point;
- if (fill.a != 0)
- { // draw fill
- // create y-sorted array of indices ind[k] into vertex list
- for (k = 0; k < n; k++)
- {
- ind[k] = k;
- }
- // sort ind by pt[ind[k]].y
- shell_sort(ind, n, sizeof(long), (int (*)(void*,void*)) compare_ind);
- nact = 0; // start with empty active list
- k = 0; // ind[k] is next vertex to process
- // ymin of polygon
- y0 = MAX(clip_min_y-1, pt[ind[0]].y);
- // ymax of polygon
- y1 = MIN(clip_max_y+1, pt[ind[n-1]].y);
- // step through scanlines
- for (y = y0; y < y1; y++)
- {
- // Check vertices between previous scanline
- // and current one, if any
- for (; (k < n) && (pt[ind[k]].y <= y); k++)
- {
- i = ind[k];
- // insert or delete edges before and after vertex i
- // (i-1 to i, and i to i+1)
- // from active list if they cross scanline y
- j = i > 0 ? i - 1 : n - 1; // vertex previous to i
- if (pt[j].y < y)
- {
- // old edge, remove from active list
- del_edge(j);
- }
- else
- {
- if (pt[j].y > y)
- {
- // new edge, add to active list
- ins_edge(j, y);
- }
- }
- j = i < n - 1 ? i + 1 : 0; // vertex next after i
- if (pt[j].y < y)
- {
- // old edge, remove from active list
- del_edge(i);
- }
- else
- {
- if (pt[j].y > y)
- {
- // new edge, add to active list
- ins_edge(i, y);
- }
- }
- }
- // sort active edge list by active[j].x
- shell_sort(active, nact, sizeof(POLYEDGE), (int (*)(void*,void*))compare_active);
- // draw horizontal segments for scanline y
- for (j = 0; j < nact; j += 2)
- { // draw horizontal segments
- // span 'tween j & j+1 is inside, span tween
- // j+1 & j+2 is outside
- // left end of span
- // convert back from fixed point - round down
- xl = (long) (active[j].x >> INT_SHIFT);
- if (xl < clip_min_x-1)
- {
- xl = clip_min_x-1;
- }
- // right end of span
- // convert back from fixed point - round down
- xr = (long) (active[j + 1].x >> INT_SHIFT);
- if (xr > clip_max_x)
- {
- xr = clip_max_x;
- }
- if (xl < xr)
- {
- // draw pixels in span
- DrawLine(xl+1,y,xr,y,fill);
- }
- // increment edge coords
- active[j].x += active[j].dx;
- active[j + 1].x += active[j + 1].dx;
- }
- }
- // sort active edge list by active[j].x
- shell_sort(active, nact, sizeof(POLYEDGE), (int (*)(void*,void*))compare_active);
- // draw horizontal segments for scanline y
- for (j = 0; j < nact; j += 2)
- { // draw horizontal segments
- // span 'tween j & j+1 is inside, span tween
- // j+1 & j+2 is outside
- // left end of span
- // convert back from fixed point - round down
- xl = (long) (active[j].x >> INT_SHIFT);
- if (xl < clip_min_x-1)
- {
- xl = clip_min_x-1;
- }
- // right end of span
- // convert back from fixed point - round up
- xr = (long) (active[j + 1].x >> INT_SHIFT);
- if (xr > clip_max_x)
- {
- xr = clip_max_x;
- }
- if (xl < xr)
- {
- // draw pixels in span
- DrawLine(xl+1,y,xr,y,fill);
- }
- // increment edge coords
- active[j].x += active[j].dx;
- active[j + 1].x += active[j + 1].dx;
- }
- }
- if (edge.a != 0)
- { // draw edges
- for (k = 0; k < n-1; k++)
- {
- DrawLineAA(pt[k].x,pt[k].y,pt[k+1].x,pt[k+1].y,edge);
- }
- DrawLineAA(pt[n-1].x,pt[n-1].y,pt[0].x,pt[0].y,edge);
- }
- return;
- }
- void CDraw32::Blit(long dstX, long dstY, long width, long height,
- CPixel32* srcImage, long srcX, long srcY, long srcStride)
- //USE: simple blit
- //IN: dstX, dstY - upper left corner of where image will land in buffer
- // width, height - width and height of image
- // srcImage - src image buffer
- // srcX, srcY - upper left corner in src image
- // srcStride - number of pixels per line in src image
- //OUT: none
- {
- CPixel32 *dst;
- CPixel32 *src;
- int x,y;
- assert(buffer != NULL);
- BlitClip(dstX, dstY, width, height, srcX, srcY);
- if (width < 1 || height < 1)
- return;
- dst = &buffer[PIXPOS(dstX,dstY,stride)];
- src = &srcImage[PIXPOS(srcX,srcY,srcStride)];
- for (y = 0; y < height; y++)
- {
- for (x = 0; x < width; x++)
- {
- // *dst++ = *src++;
- byte alpha = src->a;
- byte dst_alpha = dst->a;
- *dst = ALPHA_PIX(*src, *dst, alpha, 256-alpha);
- dst->a = dst_alpha;
- ++dst;
- ++src;
- }
- dst += (stride - width);
- src += (srcStride - width);
- }
- }
- void CDraw32::BlitClip(long& dstX, long& dstY,
- long& width, long& height,
- long& srcX, long& srcY)
- //USE: simple blit clip
- //IN: dstX, dstY - upper left corner of where image will land in buffer
- // width, height - width and height of image
- // srcX, srcY - upper left corner in src image
- //OUT: none
- {
- // clip to our buffer size
- if (dstX < clip_min_x)
- {
- int dif = (clip_min_x - dstX);
- dstX += dif;
- srcX += dif;
- width -= dif;
- }
- if (dstY < clip_min_y)
- {
- int dif = (clip_min_y - dstY);
- dstY += dif;
- srcY += dif;
- height -= dif;
- }
- if (dstX+width-1 > clip_max_x)
- {
- width -= (dstX+width-1 - clip_max_x);
- }
- if (dstY+height-1 > clip_max_y)
- {
- height -= (dstY+height-1 - clip_max_y);
- }
- }
- void CDraw32::BlitColor(long dstX, long dstY, long width, long height,
- CPixel32* srcImage, long srcX, long srcY, long srcStride, CPixel32 color)
- //USE: blit using image alpha as mask
- //IN: dstX, dstY - upper left corner of where image will land in buffer
- // width, height - width and height of image
- // srcImage - src image buffer
- // srcX, srcY - upper left corner in src image
- // srcStride - number of pixels per line in src image
- // color - color to apply to srcImage
- //OUT: none
- {
- CPixel32 *dst;
- CPixel32 *src;
- int x,y;
- int dstNextLine;
- int srcNextLine;
- assert(buffer != NULL);
- BlitClip(dstX, dstY, width, height, srcX, srcY);
- if (width < 1 || height < 1)
- return;
- dst = &buffer[PIXPOS(dstX,dstY,stride)];
- src = &srcImage[PIXPOS(srcX,srcY,srcStride)];
- dstNextLine = (stride - width);
- srcNextLine = (srcStride - width);
- for (y = 0; y < height; y++)
- {
- for (x = 0; x < width; x++)
- {
- byte alpha = src->a;
- *dst = ALPHA_PIX(color, *dst, alpha, 256-alpha);
- ++dst;
- ++src;
- }
- dst += dstNextLine;
- src += srcNextLine;
- }
- }
|