Re: [AD] stretch_blit bug |
[ Thread Index |
Date Index
| More lists.liballeg.org/allegro-developers Archives
]
- To: Coordination of admins/developers of the game programming library Allegro <alleg-developers@xxxxxxxxxx>
- Subject: Re: [AD] stretch_blit bug
- From: Trent Gamblin <trent@xxxxxxxxxx>
- Date: Wed, 25 Apr 2007 10:44:47 -0600
Attached is an improved version of Elias' stretching routines, with a
benchmark program. It's not as fast as stretch_blit, but it's more
accurate and can blit between bitmaps of different color depths.
On Sun, 2007-04-22 at 09:30 -0600, Trent Gamblin wrote:
> I've attached the version of this code that I'm using that does high and
> truecolor modes. I didn't implement 8 bit but it should be easy. I've
> separated it into four functions to handle all the cases of whether the
> bitmaps are memory or video. It was significantly slower as one
> function.
#include <allegro.h>
#include <stdio.h>
#ifdef __linux__
#include <sys/time.h>
#else
#include <allegro.h>
#include <winalleg.h>
#endif
long currentTimeMillis()
{
#ifdef __linux__
struct timeval tv;
gettimeofday(&tv, 0);
return (tv.tv_sec * 1000) + (tv.tv_usec / 1000);
#else
return timeGetTime();
#endif
}
unsigned char* memory_get_address(BITMAP* bmp, int y)
{
return bmp->line[y];
}
unsigned char* video_get_read_address(BITMAP* bmp, int y)
{
return (unsigned char*)bmp_read_line(bmp, y);
}
unsigned char* video_get_write_address(BITMAP* bmp, int y)
{
return (unsigned char*)bmp_write_line(bmp, y);
}
inline int memory_get15_or_16(unsigned char* addr)
{
return *((short *)addr);
}
inline int memory_get24(unsigned char* addr)
{
return *addr | (*(addr+1) << 8) | (*(addr+2) << 16);
}
inline int memory_get32(unsigned char* addr)
{
return *((int *)addr);
}
inline void memory_put15_or_16(unsigned char* addr, int color)
{
*((short *)addr) = color;
}
inline void memory_put24(unsigned char* addr, int color)
{
*addr = color & 0xff;
*(addr+1) = (color >> 8) & 0xff;
*(addr+2) = (color >> 16) & 0xff;
}
inline void memory_put32(unsigned char* addr, int color)
{
*((int *)addr) = color;
}
inline int video_get15_or_16(unsigned char* addr)
{
return bmp_read16((long)addr);
}
inline int video_get24(unsigned char* addr)
{
return bmp_read24((long)addr);
}
inline int video_get32(unsigned char* addr)
{
return bmp_read32((long)addr);
}
inline void video_put15_or_16(unsigned char* addr, int color)
{
bmp_write16((long)addr, color);
}
inline void video_put24(unsigned char* addr, int color)
{
bmp_write24((long)addr, color);
}
inline void video_put32(unsigned char* addr, int color)
{
bmp_write32((long)addr, color);
}
void my_stretch_vv(BITMAP *source, BITMAP *destination,
int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh)
{
int x, y; // current destination pixel
int xc, yc; // counters
int xx; // current source x
int ss, ds; // pixel sizes
unsigned char* sa, *da; // source and destination addresses
unsigned char* (*get_source_address)(BITMAP* bmp, int y);
unsigned char* (*get_destination_address)(BITMAP*, int y);
void (*put)(unsigned char* addr, int color);
int (*get)(unsigned char* addr);
get_source_address = video_get_read_address;
get_destination_address = video_get_write_address;
switch (bitmap_color_depth(source)) {
case 15:
case 16:
get = video_get15_or_16;
ss = 2;
break;
case 24:
get = video_get24;
ss = 3;
break;
case 32:
get = video_get32;
ss = 4;
break;
}
switch (bitmap_color_depth(destination)) {
case 15:
case 16:
put = video_put15_or_16;
ds = 2;
break;
case 24:
put = video_put24;
ds = 3;
break;
case 32:
put = video_put32;
ds = 4;
break;
}
yc = sh/2;
for (y = dy; y < dy + dh; y++) {
int n;
bmp_select(source);
sa = get_source_address(source, sy) + (sx * ss);
bmp_select(destination);
da = get_destination_address(destination, y) + (dx * ds);
xc = sw/2;
for (x = dx; x < dx + dw; x++) {
int color;
bmp_select(source);
color = get(sa);
bmp_select(destination);
put(da, color);
da += ds;
xc += sw;
while (xc > dw) {
sa += ss;
xc -= dw;
}
}
yc += sh;
while (yc > dh) {
sy++;
yc -= dh;
}
bmp_unwrite_line(source);
bmp_unwrite_line(destination);
}
}
void my_stretch_vm(BITMAP *source, BITMAP *destination,
int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh)
{
int x, y; // current destination pixel
int xc, yc; // counters
int xx; // current source x
int ss, ds; // pixel sizes
unsigned char* sa, *da; // source and destination addresses
unsigned char* (*get_source_address)(BITMAP* bmp, int y);
unsigned char* (*get_destination_address)(BITMAP*, int y);
void (*put)(unsigned char* addr, int color);
int (*get)(unsigned char* addr);
get_source_address = video_get_read_address;
get_destination_address = memory_get_address;
switch (bitmap_color_depth(source)) {
case 15:
case 16:
get = video_get15_or_16;
ss = 2;
break;
case 24:
get = video_get24;
ss = 3;
break;
case 32:
get = video_get32;
ss = 4;
break;
}
switch (bitmap_color_depth(destination)) {
case 15:
case 16:
put = memory_put15_or_16;
ds = 2;
break;
case 24:
put = memory_put24;
ds = 3;
break;
case 32:
put = memory_put32;
ds = 4;
break;
}
yc = sh/2;
bmp_select(source);
for (y = dy; y < dy + dh; y++) {
int n;
sa = get_source_address(source, sy) + (sx * ss);
da = get_destination_address(destination, y) + (dx * ds);
xc = sw/2;
for (x = dx; x < dx + dw; x++) {
put(da, get(sa));
da += ds;
xc += sw;
while (xc > dw) {
sa += ss;
xc -= dw;
}
}
yc += sh/2;
while (yc > dh) {
sy++;
yc -= dh;
}
}
bmp_unwrite_line(source);
}
void my_stretch_mv(BITMAP *source, BITMAP *destination,
int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh)
{
int x, y; // current destination pixel
int xc, yc; // counters
int xx; // current source x
int ss, ds; // pixel sizes
unsigned char* sa, *da; // source and destination addresses
unsigned char* (*get_source_address)(BITMAP* bmp, int y);
unsigned char* (*get_destination_address)(BITMAP*, int y);
void (*put)(unsigned char* addr, int color);
int (*get)(unsigned char* addr);
get_source_address = memory_get_address;
get_destination_address = video_get_write_address;
switch (bitmap_color_depth(source)) {
case 15:
case 16:
get = memory_get15_or_16;
ss = 2;
break;
case 24:
get = memory_get24;
ss = 3;
break;
case 32:
get = memory_get32;
ss = 4;
break;
}
switch (bitmap_color_depth(destination)) {
case 15:
case 16:
put = video_put15_or_16;
ds = 2;
break;
case 24:
put = video_put24;
ds = 3;
break;
case 32:
put = video_put32;
ds = 4;
break;
}
yc = sh/2;
bmp_select(destination);
for (y = dy; y < dy + dh; y++) {
sa = get_source_address(source, sy) + (sx * ss);
da = get_destination_address(destination, y) + (dx * ds);
xc = sw/2;
for (x = dx; x < dx + dw; x++) {
put(da, get(sa));
da += ds;
xc += sw;
while (xc > dw) {
sa += ss;
xc -= dw;
}
}
yc += sh;
while (yc > dh) {
sy++;
yc -= dh;
}
}
bmp_unwrite_line(destination);
}
void my_stretch_mm(BITMAP *source, BITMAP *destination,
int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh)
{
int x, y; // current destination pixel
int xc, yc; // counters
int xx; // current source x
int ss, ds; // pixel sizes
unsigned char* sa, *da; // source and destination addresses
unsigned char* (*get_source_address)(BITMAP* bmp, int y);
unsigned char* (*get_destination_address)(BITMAP*, int y);
void (*put)(unsigned char* addr, int color);
int (*get)(unsigned char* addr);
get_source_address = get_destination_address = memory_get_address;
switch (bitmap_color_depth(source)) {
case 15:
case 16:
get = memory_get15_or_16;
ss = 2;
break;
case 24:
get = memory_get24;
ss = 3;
break;
case 32:
get = memory_get32;
ss = 4;
break;
}
switch (bitmap_color_depth(destination)) {
case 15:
case 16:
put = memory_put15_or_16;
ds = 2;
break;
case 24:
put = memory_put24;
ds = 3;
break;
case 32:
put = memory_put32;
ds = 4;
break;
}
yc = sh/2;
for (y = dy; y < dy + dh; y++) {
int n;
sa = get_source_address(source, sy) + (sx * ss);
da = get_destination_address(destination, y) + (dx * ds);
xc = sw/2;
for (x = dx; x < dx + dw; x++) {
put(da, get(sa));
da += ds;
xc += sw;
while (xc > dw) {
sa += ss;
xc -= dw;
}
}
yc += sh;
while (yc > dh) {
sy++;
yc -= dh;
}
}
}
void my_stretch(BITMAP *source, BITMAP *destination,
int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh)
{
if (is_video_bitmap(source) && is_video_bitmap(destination)) {
my_stretch_vv(source, destination, sx, sy, sw, sh, dx, dy, dw, dh);
}
else if (is_video_bitmap(source)) {
my_stretch_vm(source, destination, sx, sy, sw, sh, dx, dy, dw, dh);
}
else if (is_video_bitmap(destination)) {
my_stretch_mv(source, destination, sx, sy, sw, sh, dx, dy, dw, dh);
}
else {
my_stretch_mm(source, destination, sx, sy, sw, sh, dx, dy, dw, dh);
}
}
int main()
{
const int count = 2500;
const int w = 200;
const int h = 200;
BITMAP* buffer, *sprite;
long start, end;
int i;
allegro_init();
install_keyboard();
set_color_depth(24);
set_gfx_mode(GFX_AUTODETECT_WINDOWED, 640, 480, 0, 0);
buffer = create_bitmap(640, 480);
sprite = load_bitmap("test.pcx", 0);
if (!buffer || !sprite) return 1;
start = currentTimeMillis();
for (i = 0; i < count; i++) {
int x = rand() % 640;
int y = rand() % 480;
x = MAX(0, MIN(640-w, x));
y = MAX(0, MIN(480-h, y));
stretch_blit(sprite, buffer, 0, 0, sprite->w, sprite->h,
x, y, w, h);
}
end = currentTimeMillis();
printf("mm stretch_blit took %d millis\n", end - start);
start = currentTimeMillis();
for (i = 0; i < count; i++) {
int x = rand() % 640;
int y = rand() % 480;
x = MAX(0, MIN(640-w, x));
y = MAX(0, MIN(480-h, y));
my_stretch(sprite, buffer, 0, 0, sprite->w, sprite->h,
x, y, w, h);
}
end = currentTimeMillis();
printf("mm my_stretch took %d millis\n", end - start);
start = currentTimeMillis();
for (i = 0; i < count; i++) {
int x = rand() % 640;
int y = rand() % 480;
x = MAX(0, MIN(640-w, x));
y = MAX(0, MIN(480-h, y));
stretch_blit(sprite, screen, 0, 0, sprite->w, sprite->h,
x, y, w, h);
}
end = currentTimeMillis();
printf("mv stretch_blit took %d millis\n", end - start);
start = currentTimeMillis();
for (i = 0; i < count; i++) {
int x = rand() % 640;
int y = rand() % 480;
x = MAX(0, MIN(640-w, x));
y = MAX(0, MIN(480-h, y));
my_stretch(sprite, screen, 0, 0, sprite->w, sprite->h,
x, y, w, h);
}
end = currentTimeMillis();
printf("mv my_stretch took %d millis\n", end - start);
start = currentTimeMillis();
for (i = 0; i < count; i++) {
int x = rand() % 640;
int y = rand() % 480;
x = MAX(0, MIN(640-w, x));
y = MAX(0, MIN(480-h, y));
stretch_blit(screen, buffer, 0, 0, sprite->w, sprite->h,
x, y, w, h);
}
end = currentTimeMillis();
printf("vm stretch_blit took %d millis\n", end - start);
start = currentTimeMillis();
for (i = 0; i < count; i++) {
int x = rand() % 640;
int y = rand() % 480;
x = MAX(0, MIN(640-w, x));
y = MAX(0, MIN(480-h, y));
my_stretch(screen, buffer, 0, 0, sprite->w, sprite->h,
x, y, w, h);
}
end = currentTimeMillis();
printf("vm my_stretch took %d millis\n", end - start);
start = currentTimeMillis();
for (i = 0; i < count; i++) {
int x = rand() % 640;
int y = rand() % 480;
x = MAX(0, MIN(640-w, x));
y = MAX(0, MIN(480-h, y));
stretch_blit(screen, screen, 0, 0, sprite->w, sprite->h,
x, y, w, h);
}
end = currentTimeMillis();
printf("vv stretch_blit took %d millis\n", end - start);
start = currentTimeMillis();
for (i = 0; i < count; i++) {
int x = rand() % 640;
int y = rand() % 480;
x = MAX(0, MIN(640-w, x));
y = MAX(0, MIN(480-h, y));
my_stretch(screen, screen, 0, 0, sprite->w, sprite->h,
x, y, w, h);
}
end = currentTimeMillis();
printf("vv my_stretch took %d millis\n", end - start);
}