At initialization! Remember in the code snippet I put out for you says that ideally, you should get the bitmask once - and that would preferrably be at initialization.
You could check the memblock for color (if memory serves me, DX uses Transparent-black for transparency checks).
Here's some code I've put together way back when (early 2001 or so) that *may* be of some help to you...
NOTE: Long code listing(s) but may help you. Not sure just how relevant they are to today's DX9 stuff, but should at least be a starting point... (i hope)...
types ending in:
_PTR = pointer type (*)
_REF = reference type (&)
_CONST = const
and IMAGE_PTR was taken from:
struct IMAGE_INFO {
DWORD Width;
DWORD Height;
PIXELFMT Format;
};
// Raw-Image Data: Length of Buffer (in bytes) = (Info.Height * RealWidth * Info.Format) / 16
struct IMAGE {
IMAGE_INFO Info;
DWORD RealWidth;
VOIDPTR PixelData;
};
(you can take it from there)
GraphicFunctions.h
#ifndef OTI_GRAPHICFUNCTIONS_H__
#define OTI_GRAPHICFUNCTIONS_H__
#if defined( __cplusplus ) && !defined( GN_COMMENT_BLOCK_ONLY )
extern "C" {
#endif // __cplusplus
DWORD MakeColor( RGBQUAD_CONST_PTR clr, PIXELFMT fmt );
VOID RipColor( DWORD_CONST clr, PIXELFMT fmt, RGBQUAD_PTR dest );
VOID BlendColors( RGBQUAD_CONST_PTR src, RGBQUAD_CONST_PTR dst, RGBQUAD_PTR result, FLOAT pct );
// Image Manipulation...
DWORD PlotPixel( POINT_CONST pt, RGBQUAD_CONST_PTR clr, IMAGE_PTR img );
DWORD DrawHorizontalLine( INT start_x, INT end_x, INT y_line, RGBQUAD_CONST_PTR clr, IMAGE_PTR img );
DWORD DrawVerticalLine( INT start_y, INT end_y, INT x_line, RGBQUAD_CONST_PTR clr, IMAGE_PTR img );
DWORD DrawLine( POINT_REF pt_beg, POINT_REF pt_end, RGBQUAD_CONST_PTR clr, IMAGE_PTR img );
DWORD DrawRectangle( POINT_REF topleft, POINT_REF botrt, RGBQUAD_CONST_PTR clr, IMAGE_PTR img );
DWORD DrailledRectangle( POINT_REF topleft, POINT_REF botrt, RGBQUAD_CONST_PTR clr, IMAGE_PTR img );
BOOL LineClipper( POINT_REF pt_beg, POINT_REF pt_end, RECT_CONST clip_rect );
DWORD BlendLine( POINT_REF pt_beg, POINT_REF pt_end, RGBQUAD_CONST_PTR clr_beg, RGBQUAD_CONST_PTR clr_end, IMAGE_PTR img );
#if defined( __cplusplus ) && !defined( GN_COMMENT_BLOCK_ONLY )
}
#endif // __cplusplus
GraphicsFunctions.cpp
#include "GraphicsLibrary.h"
VOID BlendColors( RGBQUAD_CONST_PTR src, RGBQUAD_CONST_PTR dst, RGBQUAD_PTR result, FLOAT pct )
{
FLOAT start_pct = 1.00f - pct;
if (NULL != result)
{
result->alpha = (ULONG) ((src->alpha * start_pct) + (dst->alpha * pct));
result->red = (ULONG) ((src->red * start_pct) + (dst->red * pct));
result->green = (ULONG) ((src->green * start_pct) + (dst->green * pct));
result->blue = (ULONG) ((src->blue * start_pct) + (dst->blue * pct));
}
}
DWORD MakeColor( RGBQUAD_CONST_PTR clr, PIXELFMT fmt )
{
DWORD result = 0;
switch(fmt)
{
case FMT_X8R8G8B8: result = _RGB32BIT( clr->red, clr->green, clr->blue ); break;
case FMT_A8R8G8B8: result = _ARGB32BIT( clr->alpha, clr->red, clr->green, clr->blue ); break;
case FMT_A1R5G5B5: result = _ARGB16BIT( clr->alpha, clr->red, clr->green, clr->blue ); break;
case FMT_X1R5G5B5: result = _RGB15BIT( clr->red, clr->green, clr->blue ); break;
case FMT_R5G6B5: result = _RGB16BIT( clr->red, clr->green, clr->blue ); break;
default:
{
TRACE(TEXT("Unsupported Pixel Format!\n"));
break;
}
}
if ((fmt >> 4) & 3) result |= (result << 16);
return result;
}
VOID RipColor( DWORD_CONST clr, PIXELFMT fmt, RGBQUAD_PTR dest )
{
if (NULL != dest)
{
switch(fmt)
{
case FMT_X8R8G8B8: _RGB32BITRIP( clr, dest->red, dest->green, dest->blue ); break;
case FMT_A8R8G8B8: _ARGB32BITRIP( clr, dest->alpha, dest->red, dest->green, dest->blue ); break;
case FMT_A1R5G5B5: _ARGB16BITRIP( clr, dest->alpha, dest->red, dest->green, dest->blue ); break;
case FMT_X1R5G5B5: _RGB15BITRIP( clr, dest->red, dest->green, dest->blue ); break;
case FMT_R5G6B5: _RGB16BITRIP( clr, dest->red, dest->green, dest->blue ); break;
default:
{
TRACE(TEXT("Unsupported Pixel Format!\n"));
break;
}
}
}
}
DWORD PlotPixel( POINT_CONST pt, RGBQUAD_CONST_PTR clr, IMAGE_PTR img )
{
DWORD result = FAIL;
DWORD color = 0;
DWORD pos = 0;
DWORD_PTR dst32 = NULL;
WORD_PTR dst16 = NULL;
INT dstpitch = 0;
INT dstoffset = 0;
INT dstbpp = 0;
// Do we have valid pointers...?
if ((NULL == img) || (NULL == clr)) { return FAIL; }
if ((pt.x < 0) || (pt.x >= img->Info.Width)) { return SUCCESS; }
if ((pt.y < 0) || (pt.y >= img->Info.Height)) { return SUCCESS; }
// Convert the color value... NOTE: This
// should be done AFTER clipping and other
// validations that result in the actual
// plotting of the pixel...
color = MakeColor( clr, img->Info.Format );
// Are we dealing with 16 or 32 bit color image...?
dstbpp = (img->Info.Format >> 4);
// img->RealWidth gives us our Pitch in BYTES, not as
// the number of Color-Points within the image; so, we
// convert it here...
dstpitch = (img->RealWidth / dstbpp);
pos = (pt.y * dstpitch) + pt.x;
if (dstbpp & 3)
{
// We're using 16-bit Color Format...
dst16 = (WORD_PTR) img->PixelData;
dst16[pos] = color;
}
else
{
// We're using 32-bit Color Format...
dst32 = (DWORD_PTR) img->PixelData;
dst32[pos] = color;
}
return SUCCESS;
}
DWORD DrawHorizontalLine( INT start_x, INT end_x, INT y_line, RGBQUAD_CONST_PTR clr, IMAGE_PTR img )
{
DWORD color = 0;
DWORD pos = 0;
DWORD_PTR dst32 = NULL;
WORD_PTR dst16 = NULL;
INT dstpitch = 0;
INT dstoffset = 0;
INT dstbpp = 0;
INT count = 0;
// Make sure we start on the left and move to the right...
if (start_x > end_x)
{
count = start_x;
start_x = end_x;
end_x = count;
}
// Do we have valid pointers...?
if ((NULL == img) || (NULL == clr)) { return FAIL; }
// Is our line on the screen... If not, return success...!
if ((y_line < 0) || (y_line >= img->Info.Height)) { return SUCCESS; }
if (start_x >= img->Info.Width) { return SUCCESS; }
if (end_x < 0) { return SUCCESS; }
// Basic Clipping...
if (start_x < 0) { start_x = 0; }
if (end_x >= img->Info.Width) { end_x = img->Info.Width - 1; }
// How many pixels to draw...
count = (end_x - start_x);
// Now to determine Color-Formatting...
color = MakeColor( clr, img->Info.Format );
// Are we dealing with 16 or 32 bit color image...?
dstbpp = (img->Info.Format >> 4);
// img->RealWidth gives us our Pitch in BYTES, not as
// the number of Color-Points within the image; so, we
// convert it here...
dstpitch = (img->RealWidth / dstbpp);
// This is our offset into the image buffer where we
// begin our line drawing...
pos = (y_line * dstpitch) + start_x;
if (dstbpp & 3)
{
// We're using 16-bit Color Format...
dst16 = (WORD_PTR) img->PixelData;
dst16 += pos;
MemSet16Bit( dst16, (WORD) color, count );
}
else
{
// We're using 32-bit Color Format...
dst32 = (DWORD_PTR) img->PixelData;
dst32 += pos;
MemSet32Bit( dst32, (DWORD) color, count );
}
return SUCCESS;
}
DWORD DrawVerticalLine( INT start_y, INT end_y, INT x_line, RGBQUAD_CONST_PTR clr, IMAGE_PTR img )
{
DWORD color = 0;
DWORD pos = 0;
DWORD_PTR dst32 = NULL;
WORD_PTR dst16 = NULL;
INT dstpitch = 0;
INT dstoffset = 0;
INT dstbpp = 0;
INT count = 0;
// Make sure we start on the left and move to the right...
if (start_y > end_y)
{
count = start_y;
start_y = end_y;
end_y = count;
}
// Do we have valid pointers...?
if ((NULL == img) || (NULL == clr)) { return FAIL; }
// Is our line on the screen... If not, return success...!
if ((x_line < 0) || (x_line >= img->Info.Width)) { return SUCCESS; }
if (start_y >= img->Info.Height) { return SUCCESS; }
if (end_y < 0) { return SUCCESS; }
// Basic Clipping...
if (start_y < 0) { start_y = 0; }
if (end_y >= img->Info.Height) { end_y = img->Info.Height - 1; }
// How many pixels to draw...
count = (end_y - start_y);
// Now to determine Color-Formatting...
color = MakeColor( clr, img->Info.Format );
// Are we dealing with 16 or 32 bit color image...?
dstbpp = (img->Info.Format >> 4);
// img->RealWidth gives us our Pitch in BYTES, not as
// the number of Color-Points within the image; so, we
// convert it here...
dstpitch = (img->RealWidth / dstbpp);
// This is our offset into the image buffer where we
// begin our line drawing...
pos = (start_y * dstpitch) + x_line;
if (dstbpp & 3)
{
// We're using 16-bit Color Format...
dst16 = (WORD_PTR) img->PixelData;
dst16 += pos;
while (count-- > 0)
{
VALUE_OF(dst16) = (WORD) color;
dst16 += dstpitch;
}
}
else
{
// We're using 32-bit Color Format...
dst32 = (DWORD_PTR) img->PixelData;
dst32 += pos;
while (count-- > 0)
{
VALUE_OF(dst32) = (DWORD) color;
dst32 += dstpitch;
}
}
return SUCCESS;
}
DWORD DrawLine( POINT_REF pt_beg, POINT_REF pt_end, RGBQUAD_CONST_PTR clr, IMAGE_PTR img )
{
DWORD color = 0;
DWORD pos = 0;
DWORD_PTR dst32 = NULL;
WORD_PTR dst16 = NULL;
INT dstpitch = 0;
INT dstoffset = 0;
INT dstbpp = 0;
RECT clipper;
// Do we have valid pointers...?
if ((NULL == img) || (NULL == clr)) { return FAIL; }
else if (pt_beg.y == pt_end.y) { return DrawHorizontalLine( pt_beg.x, pt_end.x, pt_beg.y, clr, img ); }
else if (pt_beg.x == pt_end.x) { return DrawVerticalLine( pt_beg.y, pt_end.y, pt_beg.x, clr, img ); }
else
{
//***********************************
// Some odd-ball slope of a line...
//***********************************
//
// Create a Clipping Rectangle...
clipper.top = 0; clipper.left = 0;
clipper.bottom = img->Info.Height - 1;
clipper.right = img->Info.Width - 1;
//***********************************
// Clip the Line to the Clipping
// Rectangle. This does two things:
// 1) Returns TRUE if the line is
// visible; otherwise FALSE.
// 2) Changes the Beginning and End
// Points of the line so that
// only the visible portion of
// the line will be drawn...
//***********************************
if (TRUE == LineClipper( pt_beg, pt_end, clipper ))
{
INT long_dist, short_dist;
INT inc_xh, inc_xl, inc_yh, inc_yl;
INT inc_ah, inc_al;
INT dist_x = (pt_end.x - pt_beg.x);
INT dist_y = (pt_end.y - pt_beg.y);
INT disc, add_disc_h, add_disc_l;
INT loop;
// Now to determine Color-Formatting...
color = MakeColor( clr, img->Info.Format );
// Are we dealing with 16 or 32 bit color image...?
dstbpp = (img->Info.Format >> 4);
// img->RealWidth gives us our Pitch in BYTES, not as
// the number of Color-Points within the image; so, we
// convert it here...
dstpitch = (img->RealWidth / dstbpp);
// This is our offset into the image buffer where we
// begin our line drawing...
pos = (pt_beg.y * dstpitch) + pt_beg.x;
// Regardless of color format, let's
// setup the start of both buffers.
// We'll use the correct one in the
// plotting loop below...
dst16 = (WORD_PTR) img->PixelData;
dst32 = (DWORD_PTR) img->PixelData;
dst16 += pos;
dst32 += pos;
// Adjustments along the X-Axis...
if (dist_x < 0) { dist_x = -dist_x; inc_xh = -1; inc_xl = -1; }
else { inc_xh = 1; inc_xl = 1; }
// Adjustments along the Y-Axis...
if (dist_y < 0) { dist_y = -dist_y; inc_yh = -dstpitch; inc_yl = -dstpitch; }
else { inc_yh = dstpitch; inc_yl = dstpitch; }
if (dist_x > dist_y) { long_dist = dist_x; short_dist = dist_y; inc_yl = 0; }
else { long_dist = dist_y; short_dist = dist_x; inc_xl = 0; }
//***********************************
// Note: Can't use bit-shifting here
// since the values may be negative.
disc = ((2 * short_dist) - long_dist);
add_disc_l = (2 * short_dist);
add_disc_h = (add_disc_l - (2 * long_dist));
inc_al = inc_xl + inc_yl;
inc_ah = inc_xh + inc_yh;
for (loop = 0; loop <= long_dist; loop++)
{
// Working with 16 or 32 bit colors...?
if (dstbpp & 3)
{
VALUE_OF(dst16) = (WORD) color;
if (disc >= 0) { dst16 += inc_ah; disc += add_disc_h; }
else { dst16 += inc_al; disc += add_disc_l; }
}
else
{
VALUE_OF(dst32) = (DWORD) color;
if (disc >= 0) { dst32 += inc_ah; disc += add_disc_h; }
else { dst32 += inc_al; disc += add_disc_l; }
}
}
}
}
return SUCCESS;
}
DWORD DrawRectangle( POINT_REF topleft, POINT_REF botrt, RGBQUAD_CONST_PTR clr, IMAGE_PTR img )
{
if ((NULL == clr) || ( NULL == img)) return FAIL;
DrawHorizontalLine( topleft.x, botrt.x, topleft.y, clr, img );
DrawHorizontalLine( topleft.x, botrt.x, botrt.y, clr, img );
DrawVerticalLine( topleft.y, botrt.y, topleft.x, clr, img );
DrawVerticalLine( topleft.y, botrt.y, botrt.x, clr, img );
return SUCCESS;
}
DWORD DrawFilledRectangle( POINT_REF topleft, POINT_REF botrt, RGBQUAD_CONST_PTR clr, IMAGE_PTR img )
{
INT top, bottom, x;
if ((NULL == clr) || ( NULL == img)) return FAIL;
top = min(topleft.y, botrt.y);
bottom = max(topleft.y, botrt.y);
for (x = top; x < bottom; x++)
DrawHorizontalLine( topleft.x, botrt.x, x, clr, img );
return SUCCESS;
}
BOOL LineClipper( POINT_REF pt_beg, POINT_REF pt_end, RECT_CONST clip_rect )
{
// Codes for basic directions...
#define CLIP_CODE_C 0x0000
#define CLIP_CODE_N 0x0008
#define CLIP_CODE_S 0x0004
#define CLIP_CODE_E 0x0002
#define CLIP_CODE_W 0x0001
// Sum of two codes above...
#define CLIP_CODE_NE 0x000A
#define CLIP_CODE_SE 0x0006
#define CLIP_CODE_NW 0x0009
#define CLIP_CODE_SW 0x0005
INT beg_code = 0, end_code = 0;
BOOL result = FALSE; // Default to not-visible...
POINT tmp_beg, tmp_end;
//**********************************************
// Which regions do the end-points reside in...
//**********************************************
// Start-Point: North or South?
if (pt_beg.y < clip_rect.top)
beg_code |= CLIP_CODE_N;
else if (pt_beg.y >= clip_rect.bottom)
beg_code |= CLIP_CODE_S;
// Start-Point: East or West?
if (pt_beg.x < clip_rect.left)
beg_code |= CLIP_CODE_W;
else if (pt_beg.x >= clip_rect.right)
beg_code |= CLIP_CODE_E;
// End-Point: North or South?
if (pt_end.y < clip_rect.top)
end_code |= CLIP_CODE_N;
else if (pt_end.y >= clip_rect.bottom)
end_code |= CLIP_CODE_S;
// End-Point: East or West?
if (pt_end.x < clip_rect.left)
end_code |= CLIP_CODE_W;
else if (pt_end.x >= clip_rect.right)
end_code |= CLIP_CODE_E;
// This works because if any two bits are
// the same in beg_code and end_code, then
// we know that pt_beg and pt_end are both
// outside the clipping rectangle in the
// same primary direction (N,S,E,W).
if ((beg_code & end_code) > 0)
return FALSE;
// If the line is entirely within the
// clipping rectangle, then we're done.
if ((beg_code == 0) && (end_code == 0))
return TRUE;
// Figure out where the first point is
// and make the appropriate changes to
// clip it into visibility...
switch (beg_code)
{
case CLIP_CODE_C:
// Point is visible, nothing to do...
break;
case CLIP_CODE_N:
// Point is outside of the clipping
// rectangle - to the North...
tmp_beg.y = clip_rect.top;
tmp_beg.x = pt_beg.x + 0.5 + (clip_rect.top - pt_beg.y) *
(pt_end.x - pt_beg.x) / (pt_end.y - pt_beg.y);
break;
case CLIP_CODE_S:
// Point is outside of the clipping
// rectangle - to the South...
tmp_beg.y = clip_rect.bottom;
tmp_beg.x = pt_beg.x + 0.5 + (clip_rect.bottom - pt_beg.y) *
(pt_end.x - pt_beg.x) / (pt_end.y - pt_beg.y);
break;
case CLIP_CODE_W:
// Point is outside of the clipping
// rectangle - to the West...
tmp_beg.x = clip_rect.left;
tmp_beg.y = pt_beg.y + 0.5 + (clip_rect.left - pt_beg.x) *
(pt_end.y - pt_beg.y) / (pt_end.x - pt_beg.x);
break;
case CLIP_CODE_E:
// Point is outside of the clipping
// rectangle - to the East...
tmp_beg.x = clip_rect.right;
tmp_beg.y = pt_beg.y + 0.5 + (clip_rect.right - pt_beg.x) *
(pt_end.y - pt_beg.y) / (pt_end.x - pt_beg.x);
break;
case CLIP_CODE_NE:
// Point is outside of the clipping
// rectangle - to the North East...
//
// May have to compute 2-intersections...
//
// North-Line Intersection...
tmp_beg.y = clip_rect.top;
tmp_beg.x = pt_beg.x + 0.5 + (clip_rect.top - pt_beg.y) *
(pt_end.x - pt_beg.x) / (pt_end.y - pt_beg.y);
// Validate our point: if it's invalid,
// then we have to compute the second...
if ((tmp_beg.x < clip_rect.left) || (tmp_beg.x > clip_rect.right))
{
// East-Line Intersection...
tmp_beg.x = clip_rect.right;
tmp_beg.y = pt_beg.y + 0.5 + (clip_rect.right - pt_beg.x) *
(pt_end.y - pt_beg.y) / (pt_end.x - pt_beg.x);
}
break;
case CLIP_CODE_SE:
// Point is outside of the clipping
// rectangle - to the South East...
//
// May have to compute 2-intersections...
//
// South-Line Intersection...
tmp_beg.y = clip_rect.bottom;
tmp_beg.x = pt_beg.x + 0.5 + (clip_rect.bottom - pt_beg.y) *
(pt_end.x - pt_beg.x) / (pt_end.y - pt_beg.y);
// Validate our point: if it's invalid,
// then we have to compute the second...
if ((tmp_beg.x < clip_rect.left) || (tmp_beg.x > clip_rect.right))
{
// East-Line Intersection...
tmp_beg.x = clip_rect.right;
tmp_beg.y = pt_beg.y + 0.5 + (clip_rect.right - pt_beg.x) *
(pt_end.y - pt_beg.y) / (pt_end.x - pt_beg.x);
}
break;
case CLIP_CODE_NW:
// Point is outside of the clipping
// rectangle - to the North West...
//
// May have to compute 2-intersections...
//
// North-Line Intersection...
tmp_beg.y = clip_rect.top;
tmp_beg.x = pt_beg.x + 0.5 + (clip_rect.top - pt_beg.y) *
(pt_end.x - pt_beg.x) / (pt_end.y - pt_beg.y);
// Validate our point: if it's invalid,
// then we have to compute the second...
if ((tmp_beg.x < clip_rect.left) || (tmp_beg.x > clip_rect.right))
{
// West-Line Intersection...
tmp_beg.x = clip_rect.left;
tmp_beg.y = pt_beg.y + 0.5 + (clip_rect.left - pt_beg.x) *
(pt_end.y - pt_beg.y) / (pt_end.x - pt_beg.x);
}
break;
case CLIP_CODE_SW:
// Point is outside of the clipping
// rectangle - to the North West...
//
// May have to compute 2-intersections...
//
// North-Line Intersection...
tmp_beg.y = clip_rect.bottom;
tmp_beg.x = pt_beg.x + 0.5 + (clip_rect.bottom - pt_beg.y) *
(pt_end.x - pt_beg.x) / (pt_end.y - pt_beg.y);
// Validate our point: if it's invalid,
// then we have to compute the second...
if ((tmp_beg.x < clip_rect.left) || (tmp_beg.x > clip_rect.right))
{
// West-Line Intersection...
tmp_beg.x = clip_rect.left;
tmp_beg.y = pt_beg.y + 0.5 + (clip_rect.left - pt_beg.x) *
(pt_end.y - pt_beg.y) / (pt_end.x - pt_beg.x);
}
break;
default:
break;
} // end-of switch(beg_code)...
// Figure out where the first point is
// and make the appropriate changes to
// clip it into visibility...
switch (end_code)
{
case CLIP_CODE_C:
// Point is visible, nothing to do...
break;
case CLIP_CODE_N:
// Point is outside of the clipping
// rectangle - to the North...
tmp_end.y = clip_rect.top;
tmp_end.x = pt_end.x + 0.5 + (clip_rect.top - pt_end.y) *
(pt_beg.x - pt_end.x) / (pt_beg.y - pt_end.y);
break;
case CLIP_CODE_S:
// Point is outside of the clipping
// rectangle - to the South...
tmp_end.y = clip_rect.bottom;
tmp_end.x = pt_end.x + 0.5 + (clip_rect.bottom - pt_end.y) *
(pt_beg.x - pt_end.x) / (pt_beg.y - pt_end.y);
break;
case CLIP_CODE_W:
// Point is outside of the clipping
// rectangle - to the West...
tmp_end.x = clip_rect.left;
tmp_end.y = pt_end.y + 0.5 + (clip_rect.left - pt_end.x) *
(pt_beg.y - pt_end.y) / (pt_beg.x - pt_end.x);
break;
case CLIP_CODE_E:
// Point is outside of the clipping
// rectangle - to the East...
tmp_end.x = clip_rect.right;
tmp_end.y = pt_end.y + 0.5 + (clip_rect.right - pt_end.x) *
(pt_beg.y - pt_end.y) / (pt_beg.x - pt_end.x);
break;
case CLIP_CODE_NE:
// Point is outside of the clipping
// rectangle - to the North East...
//
// May have to compute 2-intersections...
//
// North-Line Intersection...
tmp_end.y = clip_rect.top;
tmp_end.x = pt_end.x + 0.5 + (clip_rect.top - pt_end.y) *
(pt_beg.x - pt_end.x) / (pt_beg.y - pt_end.y);
// Validate our point: if it's invalid,
// then we have to compute the second...
if ((tmp_end.x < clip_rect.left) || (tmp_end.x > clip_rect.right))
{
// East-Line Intersection...
tmp_end.x = clip_rect.right;
tmp_end.y = pt_end.y + 0.5 + (clip_rect.right - pt_end.x) *
(pt_beg.y - pt_end.y) / (pt_beg.x - pt_end.x);
}
break;
case CLIP_CODE_SE:
// Point is outside of the clipping
// rectangle - to the South East...
//
// May have to compute 2-intersections...
//
// South-Line Intersection...
tmp_end.y = clip_rect.bottom;
tmp_end.x = pt_end.x + 0.5 + (clip_rect.bottom - pt_end.y) *
(pt_beg.x - pt_end.x) / (pt_beg.y - pt_end.y);
// Validate our point: if it's invalid,
// then we have to compute the second...
if ((tmp_end.x < clip_rect.left) || (tmp_end.x > clip_rect.right))
{
// East-Line Intersection...
tmp_end.x = clip_rect.right;
tmp_end.y = pt_end.y + 0.5 + (clip_rect.right - pt_end.x) *
(pt_beg.y - pt_end.y) / (pt_beg.x - pt_end.x);
}
break;
case CLIP_CODE_NW:
// Point is outside of the clipping
// rectangle - to the North West...
//
// May have to compute 2-intersections...
//
// North-Line Intersection...
tmp_end.y = clip_rect.top;
tmp_end.x = pt_end.x + 0.5 + (clip_rect.top - pt_end.y) *
(pt_beg.x - pt_end.x) / (pt_beg.y - pt_end.y);
// Validate our point: if it's invalid,
// then we have to compute the second...
if ((tmp_end.x < clip_rect.left) || (tmp_end.x > clip_rect.right))
{
// West-Line Intersection...
tmp_end.x = clip_rect.left;
tmp_end.y = pt_end.y + 0.5 + (clip_rect.left - pt_end.x) *
(pt_beg.y - pt_end.y) / (pt_beg.x - pt_end.x);
}
break;
case CLIP_CODE_SW:
// Point is outside of the clipping
// rectangle - to the North West...
//
// May have to compute 2-intersections...
//
// North-Line Intersection...
tmp_end.y = clip_rect.bottom;
tmp_end.x = pt_end.x + 0.5 + (clip_rect.bottom - pt_end.y) *
(pt_beg.x - pt_end.x) / (pt_beg.y - pt_end.y);
// Validate our point: if it's invalid,
// then we have to compute the second...
if ((tmp_end.x < clip_rect.left) || (tmp_end.x > clip_rect.right))
{
// West-Line Intersection...
tmp_end.x = clip_rect.left;
tmp_end.y = pt_end.y + 0.5 + (clip_rect.left - pt_end.x) *
(pt_beg.y - pt_end.y) / (pt_beg.x - pt_end.x);
}
break;
default:
break;
} // end-of switch(end_code)...
// Final round of Bounds Checking.
if ((tmp_beg.x < clip_rect.left) || (tmp_beg.x > clip_rect.right) ||
(tmp_beg.y < clip_rect.top) || (tmp_beg.y > clip_rect.bottom) ||
(tmp_end.x < clip_rect.left) || (tmp_end.x > clip_rect.right) ||
(tmp_end.y < clip_rect.top) || (tmp_end.y > clip_rect.bottom) )
return FALSE;
// Add done now... Time to finish up!
// Update the new line-points for the
// visible line to be drawn...
pt_beg = tmp_beg;
pt_end = tmp_end;
return TRUE;
}
DWORD BlendLine( POINT_REF pt_beg, POINT_REF pt_end, RGBQUAD_CONST_PTR clr_beg, RGBQUAD_CONST_PTR clr_end, IMAGE_PTR img )
{
DWORD color = 0;
DWORD pos = 0;
DWORD_PTR dst32 = NULL;
WORD_PTR dst16 = NULL;
INT dstpitch = 0;
INT dstoffset = 0;
INT dstbpp = 0;
RECT clipper;
FLOAT pct_step = 0.0f, pct = 0.0f;
RGBQUAD clr;
memset( ADDRESS_OF(clr), 0, sizeof(RGBQUAD) );
// Do we have valid pointers...?
if ((NULL == img) || (NULL == clr_beg) || (NULL == clr_end)) { return FAIL; }
//***********************************
// We really don't care about the
// Slope of the line because we have
// to calculate and plot every pixel
// as opposed to calling either:
// DrawHorizontalLine() or
// DrawVerticalLine()
//***********************************
// Create a Clipping Rectangle...
clipper.top = 0; clipper.left = 0;
clipper.bottom = img->Info.Height - 1;
clipper.right = img->Info.Width - 1;
//***********************************
// Clip the Line to the Clipping
// Rectangle. This does two things:
// 1) Returns TRUE if the line is
// visible; otherwise FALSE.
// 2) Changes the Beginning and End
// Points of the line so that
// only the visible portion of
// the line will be drawn...
//***********************************
if (TRUE == LineClipper( pt_beg, pt_end, clipper ))
{
INT long_dist, short_dist;
INT inc_xh, inc_xl, inc_yh, inc_yl;
INT inc_ah, inc_al;
INT dist_x = (pt_end.x - pt_beg.x);
INT dist_y = (pt_end.y - pt_beg.y);
INT disc, add_disc_h, add_disc_l;
INT loop;
// Are we dealing with 16 or 32 bit color image...?
dstbpp = (img->Info.Format >> 4);
// img->RealWidth gives us our Pitch in BYTES, not as
// the number of Color-Points within the image; so, we
// convert it here...
dstpitch = (img->RealWidth / dstbpp);
// This is our offset into the image buffer where we
// begin our line drawing...
pos = (pt_beg.y * dstpitch) + pt_beg.x;
// Regardless of color format, let's
// setup the start of both buffers.
// We'll use the correct one in the
// plotting loop below...
dst16 = (WORD_PTR) img->PixelData;
dst32 = (DWORD_PTR) img->PixelData;
dst16 += pos;
dst32 += pos;
// Adjustments along the X-Axis...
if (dist_x < 0) { dist_x = -dist_x; inc_xh = -1; inc_xl = -1; }
else { inc_xh = 1; inc_xl = 1; }
// Adjustments along the Y-Axis...
if (dist_y < 0) { dist_y = -dist_y; inc_yh = -dstpitch; inc_yl = -dstpitch; }
else { inc_yh = dstpitch; inc_yl = dstpitch; }
if (dist_x > dist_y) { long_dist = dist_x; short_dist = dist_y; inc_yl = 0; }
else { long_dist = dist_y; short_dist = dist_x; inc_xl = 0; }
//***********************************
// Note: Can't use bit-shifting here
// since the values may be negative.
disc = ((2 * short_dist) - long_dist);
add_disc_l = (2 * short_dist);
add_disc_h = (add_disc_l - (2 * long_dist));
inc_al = inc_xl + inc_yl;
inc_ah = inc_xh + inc_yh;
pct_step = (1.0f / long_dist);
for (loop = 0; loop <= long_dist; loop++)
{
// Calculate the blending percentage...
pct = (pct_step * loop);
// Now to determine Color-Formatting...
BlendColors( clr_beg, clr_end, ADDRESS_OF(clr), pct );
color = MakeColor( ADDRESS_OF(clr), img->Info.Format );
// Working with 16 or 32 bit colors...?
if (dstbpp & 3)
{
VALUE_OF(dst16) = (WORD) color;
if (disc >= 0) { dst16 += inc_ah; disc += add_disc_h; }
else { dst16 += inc_al; disc += add_disc_l; }
}
else
{
VALUE_OF(dst32) = (DWORD) color;
if (disc >= 0) { dst32 += inc_ah; disc += add_disc_h; }
else { dst32 += inc_al; disc += add_disc_l; }
}
}
}
return SUCCESS;
}
Misc. macro definitions
#define ADDRESS_OF(val) (&val)
#define VALUE_OF(ptr) (*ptr)
#define UNUSED_VARIABLE(var) (var)
#define UNUSED_PARAMETER(prm) UNUSED_VARIABLE(prm)
#define UNUSED(var) UNUSED_VARIABLE(var)
#if !defined(SAFE_ADDREF)
# define SAFE_ADDREF(p) { if(NULL != (p)) { (p)->AddRef(); } }
#endif
#if !defined(SAFE_RELEASE)
# define SAFE_RELEASE(p) { if(NULL != (p)) { (p)->Release(); (p)=NULL; } }
#endif
#if !defined(ASSIGN_UNKNOWN)
# define ASSIGN_UNKNOWN(l,r) { SAFE_ADDREF((r)); SAFE_RELEASE((l)); (l) = (r); }
#endif
#if !defined(SAFE_FREE)
# define SAFE_FREE(p) { if(NULL != (p)) { free((void*)(p)); (p)=NULL; } }
#endif
#if !defined(SAFE_DELETE)
# define SAFE_DELETE(p) { if(NULL != (p)) { delete (p); (p)=NULL; } }
#endif
#if !defined(SAFE_DELETE_ARRAY)
# define SAFE_DELETE_ARRAY(p) { if(NULL != (p)) { delete [] (p); (p)=NULL; } }
#endif
#if !defined(SAFE_DELETE_LIST)
# define SAFE_DELETE_LIST(list, cnt) \
{ \
if (NULL != (list)) \
{ \
for (int x=0; x<(cnt); x++) \
{ \
SAFE_DELETE(list[x]); \
} \
SAFE_DELETE_ARRAY(list); \
} \
}
#endif // SAFE_DELETE_LIST...
// Color Making macros for each supported format...
#define _RGB15BIT(r,g,b) (WORD) ((b>>3) + ((g>>3) << 5) + ((r>>3) << 10)) // FMT_X1R5G6B5
#define _RGB16BIT(r,g,b) (WORD) ((b>>3) + ((g>>2) << 5) + ((r>>3) << 11)) // FMT_R5G6B5
#define _RGB32BIT(r,g,b) _ARGB32BIT( 0x00, r, g, b ) // FMT_X8R8G8B8
#define _ARGB16BIT(a,r,g,b) (WORD) ((b>>3) + ((g>>3) << 5) + ((r>>3) << 10) + ((a) ? 0x8000 : 0x0000)) // FMT_A1R5G5B5
#define _ARGB32BIT(a,r,g,b) (DWORD)((b) + ((g) << 8) + ((r) << 16) + ((a) << 24)) // FMT_A8R8G8B8
// Color Ripping macros for each supported format...
#define _RGB15BITRIP(clr,r,g,b) \
{ ((b) = (BYTE) ((clr) << 3)); \
((g) = (BYTE) (((clr) >> 5) << 3)); \
((r) = (BYTE) (((clr) >> 10) << 3)); }
#define _RGB16BITRIP(clr,r,g,b) \
{ ((b) = (BYTE) ((clr) << 3)); \
((g) = (BYTE) (((clr) >> 5) << 2)); \
((r) = (BYTE) (((clr) >> 11) << 3)); }
#define _RGB32BITRIP(clr,r,g,b) \
{ ((b) = (BYTE) ((clr) & 0xFF)); \
((g) = (BYTE) (((clr) >> 8) & 0xFF)); \
((r) = (BYTE) (((clr) >> 16) & 0xFF)); }
#define _ARGB16BITRIP(clr,a,r,g,b) \
{ ((b) = (BYTE) ((clr) << 3)); \
((g) = (BYTE) (((clr) >> 5) << 3)); \
((r) = (BYTE) (((clr) >> 11) << 3)); \
((a) = (BYTE) (((clr) & 0x8000) ? 0xFF : 0x00 )); }
#define _ARGB32BITRIP(clr,a,r,g,b) \
{ ((b) = (BYTE) ((clr) & 0xFF)); \
((g) = (BYTE) (((clr) >> 8) & 0xFF)); \
((r) = (BYTE) (((clr) >> 16) & 0xFF)); \
((a) = (BYTE) (((clr) >> 24) & 0xFF)); }
You probably won't be able to compile any of this code right off, but at least you can see *how* i have done things in the past. I still use alot of this code as a reference point - although, admittedly, I don't do to many things that way anymore since I'm trying to migrate away from 2D and into 3D - it appears that alot of stuff changes, but with 2D basics, 3D is making more sense to me (somewhat).
Anyway, what I was getting at with my response to pixel format being D3D_X8R8G8G8 before would be better understood with the macros/functions used to RipColor/MakeColor etc... Format matters and you have 3-bytes per pixel which seemed to me to be incorrect for the XRGB format - but then again, this code is nearly 10-years old, so what do I know... lol
Anyway, I hope this stuff helps you, you'll have to follow the code as I've removed most of the comments for brevity... (Not to brief though, is it?)
I'll be here for any further questions that you (or anyone for that matter) may have. I'll help if I can...
JTK