added CUSTOM_BLITTER define, no need for NGC specific rendering code inside core anymore

This commit is contained in:
ekeeke31 2012-02-05 19:37:20 +00:00
parent a45cf8861f
commit 38dcd29a66
9 changed files with 193 additions and 136 deletions

View File

@ -27,7 +27,7 @@ INCLUDES := source source/m68k source/z80 source/sound source/ntsc source/input_
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS = -O3 -fomit-frame-pointer --param large-function-growth=800 --param inline-unit-growth=200 -Wall -Winline -Wno-strict-aliasing $(MACHDEP) $(INCLUDE) -DUSE_16BPP_RENDERING -DALT_RENDERER -DNGC
CFLAGS = -O3 -fomit-frame-pointer --param large-function-growth=800 --param inline-unit-growth=200 -Wall -Winline -Wno-strict-aliasing $(MACHDEP) $(INCLUDE) -DUSE_16BPP_RENDERING -DALT_RENDERER
CXXFLAGS = $(CFLAGS)
LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map

View File

@ -27,7 +27,7 @@ INCLUDES := source source/m68k source/z80 source/sound source/ntsc source/input_
# options for code generation
#---------------------------------------------------------------------------------
CFLAGS = -O3 -fomit-frame-pointer --param large-function-growth=800 --param inline-unit-growth=200 -Wall -Winline -Wno-strict-aliasing $(MACHDEP) $(INCLUDE) -DUSE_16BPP_RENDERING -DALT_RENDERER -DNGC -DHW_RVL
CFLAGS = -O3 -fomit-frame-pointer --param large-function-growth=800 --param inline-unit-growth=200 -Wall -Winline -Wno-strict-aliasing $(MACHDEP) $(INCLUDE) -DUSE_16BPP_RENDERING -DALT_RENDERER -DHW_RVL
CXXFLAGS = $(CFLAGS)
LDFLAGS = $(MACHDEP) -Wl,-Map,$(notdir $@).map

View File

@ -1416,7 +1416,7 @@ void gx_video_Start(void)
}
/* When VSYNC is forced ON or AUTO with TV mode matching emulated video mode, emulation is synchronized with video hardware */
if ((config.vsync == 1) && (gc_pal == vdp_pal))
if (config.vsync && (gc_pal == vdp_pal))
{
/* VSYNC callback */
VIDEO_SetPreRetraceCallback(vi_callback);
@ -1741,3 +1741,147 @@ void gx_video_Shutdown(void)
VIDEO_Flush();
VIDEO_WaitVSync();
}
/* Custom NTSC blitters */
typedef unsigned short sms_ntsc_out_t;
typedef unsigned short md_ntsc_out_t;
void sms_ntsc_blit( sms_ntsc_t const* ntsc, SMS_NTSC_IN_T const* table, unsigned char* input,
int in_width, int vline)
{
int const chunk_count = in_width / sms_ntsc_in_chunk;
/* handle extra 0, 1, or 2 pixels by placing them at beginning of row */
int const in_extra = in_width - chunk_count * sms_ntsc_in_chunk;
unsigned const extra2 = (unsigned) -(in_extra >> 1 & 1); /* (unsigned) -1 = ~0 */
unsigned const extra1 = (unsigned) -(in_extra & 1) | extra2;
/* use palette entry 0 for unused pixels */
SMS_NTSC_IN_T border = table[0];
SMS_NTSC_BEGIN_ROW( ntsc, border,
(SMS_NTSC_ADJ_IN( table[input[0]] )) & extra2,
(SMS_NTSC_ADJ_IN( table[input[extra2 & 1]] )) & extra1 );
/* directly fill the RGB565 texture */
/* one tile is 32 byte = 4x4 pixels */
/* tiles are stored continuously in texture memory */
in_width = SMS_NTSC_OUT_WIDTH(in_width) / 4;
int offset = ((in_width * 32) * (vline / 4)) + ((vline & 3) * 8);
sms_ntsc_out_t* __restrict__ line_out = (sms_ntsc_out_t*)(texturemem + offset);
offset = 0;
int n;
input += in_extra;
for ( n = chunk_count; n; --n )
{
/* order of input and output pixels must not be altered */
SMS_NTSC_COLOR_IN( 0, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) );
SMS_NTSC_RGB_OUT( 0, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 1, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_COLOR_IN( 1, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) );
SMS_NTSC_RGB_OUT( 2, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 3, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_COLOR_IN( 2, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) );
SMS_NTSC_RGB_OUT( 4, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 5, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 6, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
}
/* finish final pixels */
SMS_NTSC_COLOR_IN( 0, ntsc, border );
SMS_NTSC_RGB_OUT( 0, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 1, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_COLOR_IN( 1, ntsc, border );
SMS_NTSC_RGB_OUT( 2, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 3, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_COLOR_IN( 2, ntsc, border );
SMS_NTSC_RGB_OUT( 4, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 5, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 6, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
}
void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned char* input,
int in_width, int vline)
{
int const chunk_count = in_width / md_ntsc_in_chunk - 1;
/* use palette entry 0 for unused pixels */
MD_NTSC_IN_T border = table[0];
MD_NTSC_BEGIN_ROW( ntsc, border,
MD_NTSC_ADJ_IN( table[*input++] ),
MD_NTSC_ADJ_IN( table[*input++] ),
MD_NTSC_ADJ_IN( table[*input++] ) );
/* directly fill the RGB565 texture */
/* one tile is 32 byte = 4x4 pixels */
/* tiles are stored continuously in texture memory */
in_width = MD_NTSC_OUT_WIDTH(in_width) >> 2;
int offset = ((in_width << 5) * (vline >> 2)) + ((vline & 3) * 8);
md_ntsc_out_t* __restrict__ line_out = (md_ntsc_out_t*)(texturemem + offset);
int n;
for ( n = chunk_count; n; --n )
{
/* order of input and output pixels must not be altered */
MD_NTSC_COLOR_IN( 0, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
MD_NTSC_RGB_OUT( 0, *line_out++ );
MD_NTSC_RGB_OUT( 1, *line_out++ );
MD_NTSC_COLOR_IN( 1, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
MD_NTSC_RGB_OUT( 2, *line_out++ );
MD_NTSC_RGB_OUT( 3, *line_out++ );
line_out += 12;
MD_NTSC_COLOR_IN( 2, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
MD_NTSC_RGB_OUT( 4, *line_out++ );
MD_NTSC_RGB_OUT( 5, *line_out++ );
MD_NTSC_COLOR_IN( 3, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
MD_NTSC_RGB_OUT( 6, *line_out++ );
MD_NTSC_RGB_OUT( 7, *line_out++ );
line_out += 12;
}
/* finish final pixels */
MD_NTSC_COLOR_IN( 0, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
MD_NTSC_RGB_OUT( 0, *line_out++ );
MD_NTSC_RGB_OUT( 1, *line_out++ );
MD_NTSC_COLOR_IN( 1, ntsc, border );
MD_NTSC_RGB_OUT( 2, *line_out++ );
MD_NTSC_RGB_OUT( 3, *line_out++ );
line_out += 12;
MD_NTSC_COLOR_IN( 2, ntsc, border );
MD_NTSC_RGB_OUT( 4, *line_out++ );
MD_NTSC_RGB_OUT( 5, *line_out++ );
MD_NTSC_COLOR_IN( 3, ntsc, border );
MD_NTSC_RGB_OUT( 6, *line_out++ );
MD_NTSC_RGB_OUT( 7, *line_out++ );
}

View File

@ -48,6 +48,22 @@
#define LIGHT_GREEN {0xa9,0xc7,0xc6,0xff}
#define WHITE {0xff,0xff,0xff,0xff}
/* Directly fill a RGB565 texture */
/* One tile is 32 byte = 4x4 pixels */
/* Tiles are stored continuously in texture memory */
#define CUSTOM_BLITTER(line, width, table, in) \
width >>= 2; \
u16 *out = (u16 *) (texturemem + (((width << 5) * (line >> 2)) + ((line & 3) << 3))); \
do \
{ \
*out++ = table[*in++]; \
*out++ = table[*in++]; \
*out++ = table[*in++]; \
*out++ = table[*in++]; \
out += 12; \
} \
while (--width);
/* image texture */
typedef struct
{

View File

@ -1,6 +1,6 @@
/* md_ntsc 0.1.2. http://www.slack.net/~ant/ */
/* Modified to work with Genesis Plus GX -- EkeEke*/
/* Modified for use with Genesis Plus GX -- EkeEke */
#include "shared.h"
#include "md_ntsc.h"
@ -85,6 +85,7 @@ void md_ntsc_init( md_ntsc_t* ntsc, md_ntsc_setup_t const* setup )
}
}
#ifndef CUSTOM_BLITTER
void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned char* input,
int in_width, int vline)
{
@ -98,16 +99,7 @@ void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned ch
MD_NTSC_ADJ_IN( table[*input++] ),
MD_NTSC_ADJ_IN( table[*input++] ) );
#ifdef NGC
/* directly fill the RGB565 texture */
/* one tile is 32 byte = 4x4 pixels */
/* tiles are stored continuously in texture memory */
in_width = MD_NTSC_OUT_WIDTH(in_width) >> 2;
int offset = ((in_width << 5) * (vline >> 2)) + ((vline & 3) * 8);
md_ntsc_out_t* restrict line_out = (md_ntsc_out_t*)(texturemem + offset);
#else
md_ntsc_out_t* restrict line_out = (md_ntsc_out_t*)(&bitmap.data[(vline * bitmap.pitch)]);
#endif
int n;
@ -122,10 +114,6 @@ void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned ch
MD_NTSC_RGB_OUT( 2, *line_out++ );
MD_NTSC_RGB_OUT( 3, *line_out++ );
#ifdef NGC
line_out += 12;
#endif
MD_NTSC_COLOR_IN( 2, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
MD_NTSC_RGB_OUT( 4, *line_out++ );
MD_NTSC_RGB_OUT( 5, *line_out++ );
@ -133,11 +121,7 @@ void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned ch
MD_NTSC_COLOR_IN( 3, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
MD_NTSC_RGB_OUT( 6, *line_out++ );
MD_NTSC_RGB_OUT( 7, *line_out++ );
#ifdef NGC
line_out += 12;
#endif
}
}
/* finish final pixels */
MD_NTSC_COLOR_IN( 0, ntsc, MD_NTSC_ADJ_IN( table[*input++] ) );
@ -148,10 +132,6 @@ void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned ch
MD_NTSC_RGB_OUT( 2, *line_out++ );
MD_NTSC_RGB_OUT( 3, *line_out++ );
#ifdef NGC
line_out += 12;
#endif
MD_NTSC_COLOR_IN( 2, ntsc, border );
MD_NTSC_RGB_OUT( 4, *line_out++ );
MD_NTSC_RGB_OUT( 5, *line_out++ );
@ -160,3 +140,4 @@ void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned ch
MD_NTSC_RGB_OUT( 6, *line_out++ );
MD_NTSC_RGB_OUT( 7, *line_out++ );
}
#endif

View File

@ -46,7 +46,7 @@ typedef struct md_ntsc_t md_ntsc_t;
void md_ntsc_init( md_ntsc_t* ntsc, md_ntsc_setup_t const* setup );
/* Filters one row of pixels. Input pixel format is set by MD_NTSC_IN_FORMAT
and output RGB depth is defined by MD_NTSC_RGB_OUT_. Both default to 16-bit RGB.
and output RGB depth is set by MD_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
In_row_width is the number of pixels to get to the next input row. */
void md_ntsc_blit( md_ntsc_t const* ntsc, MD_NTSC_IN_T const* table, unsigned char* input,
int in_width, int vline);

View File

@ -1,5 +1,7 @@
/* sms_ntsc 0.2.3. http://www.slack.net/~ant/ */
/* Modified for use with Genesis Plus GX -- EkeEke */
#include "shared.h"
#include "sms_ntsc.h"
@ -14,8 +16,6 @@ details. You should have received a copy of the GNU Lesser General Public
License along with this module; if not, write to the Free Software Foundation,
Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA */
/* Modified to work with Genesis Plus GX -- EkeEke */
sms_ntsc_setup_t const sms_ntsc_monochrome = { 0,-1, 0, 0,.2, 0, .2,-.2,-.2,-1, 0, 0 };
sms_ntsc_setup_t const sms_ntsc_composite = { 0, 0, 0, 0, 0, 0,.25, 0, 0, 0, 0, 0 };
sms_ntsc_setup_t const sms_ntsc_svideo = { 0, 0, 0, 0, 0, 0,.25, -1, -1, 0, 0, 0 };
@ -84,6 +84,7 @@ void sms_ntsc_init( sms_ntsc_t* ntsc, sms_ntsc_setup_t const* setup )
}
}
#ifndef CUSTOM_BLITTER
void sms_ntsc_blit( sms_ntsc_t const* ntsc, SMS_NTSC_IN_T const* table, unsigned char* input,
int in_width, int vline)
{
@ -101,17 +102,8 @@ void sms_ntsc_blit( sms_ntsc_t const* ntsc, SMS_NTSC_IN_T const* table, unsigned
(SMS_NTSC_ADJ_IN( table[input[0]] )) & extra2,
(SMS_NTSC_ADJ_IN( table[input[extra2 & 1]] )) & extra1 );
#ifdef NGC
/* directly fill the RGB565 texture */
/* one tile is 32 byte = 4x4 pixels */
/* tiles are stored continuously in texture memory */
in_width = SMS_NTSC_OUT_WIDTH(in_width) / 4;
int offset = ((in_width * 32) * (vline / 4)) + ((vline & 3) * 8);
sms_ntsc_out_t* restrict line_out = (sms_ntsc_out_t*)(texturemem + offset);
offset = 0;
#else
sms_ntsc_out_t* restrict line_out = (sms_ntsc_out_t*)(&bitmap.data[(vline * bitmap.pitch)]);
#endif
int n;
input += in_extra;
@ -119,76 +111,31 @@ void sms_ntsc_blit( sms_ntsc_t const* ntsc, SMS_NTSC_IN_T const* table, unsigned
{
/* order of input and output pixels must not be altered */
SMS_NTSC_COLOR_IN( 0, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) );
#ifdef NGC
SMS_NTSC_RGB_OUT( 0, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 1, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
#else
SMS_NTSC_RGB_OUT( 0, *line_out++ );
SMS_NTSC_RGB_OUT( 1, *line_out++ );
#endif
SMS_NTSC_COLOR_IN( 1, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) );
#ifdef NGC
SMS_NTSC_RGB_OUT( 2, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 3, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
#else
SMS_NTSC_RGB_OUT( 2, *line_out++ );
SMS_NTSC_RGB_OUT( 3, *line_out++ );
#endif
SMS_NTSC_COLOR_IN( 2, ntsc, SMS_NTSC_ADJ_IN( table[*input++] ) );
#ifdef NGC
SMS_NTSC_RGB_OUT( 4, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 5, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 6, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
#else
SMS_NTSC_RGB_OUT( 4, *line_out++ );
SMS_NTSC_RGB_OUT( 5, *line_out++ );
SMS_NTSC_RGB_OUT( 6, *line_out++ );
#endif
}
/* finish final pixels */
SMS_NTSC_COLOR_IN( 0, ntsc, border );
#ifdef NGC
SMS_NTSC_RGB_OUT( 0, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 1, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
#else
SMS_NTSC_RGB_OUT( 0, *line_out++ );
SMS_NTSC_RGB_OUT( 1, *line_out++ );
#endif
SMS_NTSC_COLOR_IN( 1, ntsc, border );
#ifdef NGC
SMS_NTSC_RGB_OUT( 2, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 3, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
#else
SMS_NTSC_RGB_OUT( 2, *line_out++ );
SMS_NTSC_RGB_OUT( 3, *line_out++ );
#endif
SMS_NTSC_COLOR_IN( 2, ntsc, border );
#ifdef NGC
SMS_NTSC_RGB_OUT( 4, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 5, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
SMS_NTSC_RGB_OUT( 6, line_out[offset++] );
if ((offset % 4) == 0) offset += 12;
#else
SMS_NTSC_RGB_OUT( 4, *line_out++ );
SMS_NTSC_RGB_OUT( 5, *line_out++ );
SMS_NTSC_RGB_OUT( 6, *line_out++ );
#endif
}
#endif

View File

@ -46,7 +46,7 @@ typedef struct sms_ntsc_t sms_ntsc_t;
void sms_ntsc_init( sms_ntsc_t* ntsc, sms_ntsc_setup_t const* setup );
/* Filters one row of pixels. Input pixel format is set by SMS_NTSC_IN_FORMAT
and output RGB depth is defined by SMS_NTSC_RGB_OUT_. Both default to 16-bit RGB.
and output RGB depth is set by SMS_NTSC_OUT_DEPTH. Both default to 16-bit RGB.
In_row_width is the number of pixels to get to the next input row. */
void sms_ntsc_blit( sms_ntsc_t const* ntsc, SMS_NTSC_IN_T const* table, unsigned char* input,
int in_width, int vline);

View File

@ -47,13 +47,23 @@
extern md_ntsc_t *md_ntsc;
extern sms_ntsc_t *sms_ntsc;
/* Output pixels type*/
#if defined(USE_8BPP_RENDERING)
#define PIXEL_OUT_T uint8
#elif defined(USE_32BPP_RENDERING)
#define PIXEL_OUT_T uint32
#else
#define PIXEL_OUT_T uint16
#endif
/* Pixel priority look-up tables information */
#define LUT_MAX (6)
#define LUT_SIZE (0x10000)
#ifdef ALIGN_LONG
/* Or change the names if you depend on these from elsewhere.. */
#undef READ_LONG
#undef WRITE_LONG
@ -452,7 +462,7 @@ INLINE void WRITE_LONG(void *address, uint32 data)
}
/* Pixel conversion macros */
/* Pixels conversion macro */
/* 4-bit color channels are either compressed to 2/3-bit or dithered to 5/6/8-bit equivalents */
/* 3:3:2 RGB */
#if defined(USE_8BPP_RENDERING)
@ -551,30 +561,10 @@ static uint32 bp_lut[0x10000];
/* Layer priority pixel look-up tables */
static uint8 lut[LUT_MAX][LUT_SIZE];
/* 8-bit pixel color mapping */
#if defined(USE_8BPP_RENDERING)
static uint8 pixel[0x100];
static uint8 pixel_lut[3][0x200];
static uint8 pixel_lut_m4[0x40];
/* 15-bit pixel color mapping */
#elif defined(USE_15BPP_RENDERING)
static uint16 pixel[0x100];
static uint16 pixel_lut[3][0x200];
static uint16 pixel_lut_m4[0x40];
/* 16-bit pixel color mapping */
#elif defined(USE_16BPP_RENDERING)
static uint16 pixel[0x100];
static uint16 pixel_lut[3][0x200];
static uint16 pixel_lut_m4[0x40];
/* 32-bit pixel color mapping */
#elif defined(USE_32BPP_RENDERING)
static uint32 pixel[0x100];
static uint32 pixel_lut[3][0x200];
static uint32 pixel_lut_m4[0x40];
#endif
/* Output pixel data look-up tables*/
static PIXEL_OUT_T pixel[0x100];
static PIXEL_OUT_T pixel_lut[3][0x200];
static PIXEL_OUT_T pixel_lut_m4[0x40];
/* Background & Sprite line buffers */
static uint8 linebuf[2][0x200];
@ -4145,31 +4135,10 @@ void remap_line(int line)
#endif
{
/* Convert VDP pixel data to output pixel format */
#ifdef NGC
/* Directly fill a RGB565 texture */
/* One tile is 32 byte = 4x4 pixels */
/* Tiles are stored continuously in texture memory */
width >>= 2;
uint16 *dst = (uint16 *) (texturemem + (((width << 5) * (line >> 2)) + ((line & 3) << 3)));
do
{
*dst++ = pixel[*src++];
*dst++ = pixel[*src++];
*dst++ = pixel[*src++];
*dst++ = pixel[*src++];
/* next tile */
dst += 12;
}
while (--width);
#ifdef CUSTOM_BLITTER
CUSTOM_BLITTER(line, width, pixel, src)
#else
#if defined(USE_8BPP_RENDERING)
uint8 *dst =((uint8 *)&bitmap.data[(line * bitmap.pitch)]);
#elif defined(USE_32BPP_RENDERING)
uint32 *dst =((uint32 *)&bitmap.data[(line * bitmap.pitch)]);
#else
uint16 *dst =((uint16 *)&bitmap.data[(line * bitmap.pitch)]);
#endif
PIXEL_OUT_T *dst =((PIXEL_OUT_T *)&bitmap.data[(line * bitmap.pitch)]);
do
{
*dst++ = pixel[*src++];