Re: [AD] stretch_blit bug

[ Thread Index | Date Index | More lists.liballeg.org/allegro-developers Archives ]


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.

On Sat, 2007-04-21 at 16:34 +0200, Elias Pschernig wrote:
> Ok, as I don't understand the Bresenham version used in cstretch.c
> (which makes it hard to fix..), I tried writing up a simple
> re-implementation of a stretch blit.
> 
> I'm not sure what bmp_select, bmp_write_line, bmp_write8 and
> bmp_unwrite_line really do, I just tried to match their use with the
> current implementation.
> 
> my_stretch8 is about 10% faster than the current stretch_blit (when
> stretch a bitmap from 333x333 to 1000x1000), likely once wired in there
> would be extra per-call overhead, so I'd say it has about the same
> performance. But it's *much* simpler, and doesn't show that bug.
> 
> I'm going to try and replace cstretch.c with this one, but needs
> clipping and color depths (i won't care about "mode X") and masking, so
> it will take some time.
> 
> void my_stretch8(BITMAP *source, BITMAP *destination,
>     int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh)
> {
>     int x, y;
>     fixed fx, fy; /* fractional source position */
>     fixed xi, yi; /* x and y increment */
>     uintptr_t dptr;
> 
>     xi = itofix(sw) / dw;
>     yi = itofix(sh) / dh;
> 
>     fy = itofix(sy) + yi / 2;
>     fx = itofix(sx) + xi / 2;
> 
>     bmp_select(destination);
> 
>     for (y = dy; y < dy + dh; y++) {
>         unsigned char *sptr = source->line[fixtoi(fy)];
>         unsigned char *sptr2;
>         fixed fx_backup = fx;
>         dptr = bmp_write_line(destination, y) + dx;
>         for (x = dx; x < dx + dw; x++) {
>             sptr2 = sptr + fixtoi(fx);
>             bmp_write8(dptr++, *sptr2);
>             fx += xi;
>         }
>         fx = fx_backup;
>         fy += yi;
>     }
>     bmp_unwrite_line(destination);
> }
> 
> -- 
> Elias Pschernig

static inline void memory_putpixel15_or_16(BITMAP* bmp, int x, int y, int color)
{
	((short *)bmp->line[y])[x] = color;
}

static inline void memory_putpixel24(BITMAP* bmp, int x, int y, int color)
{
	putpixel(bmp, x, y, color);
}

static inline void memory_putpixel32(BITMAP* bmp, int x, int y, int color)
{
	((int32_t *)bmp->line[y])[x] = (int32_t)color;
}

static inline int memory_getpixel15_or_16(BITMAP *bmp, int x, int y)
{
	return ((short *)bmp->line[y])[x];
}

static inline int memory_getpixel24(BITMAP* bmp, int x, int y)
{
	return getpixel(bmp, x, y);
}

static inline int memory_getpixel32(BITMAP* bmp, int x, int y)
{
	return ((int *)bmp->line[y])[x];
}

static inline void video_putpixel15_or_16(uintptr_t addr, int x, int color)
{
	bmp_write16(addr+x*2, color);
}

static inline void video_putpixel24(uintptr_t addr, int x, int color)
{
	bmp_write24(addr+x*3, color);
}

static inline void video_putpixel32(uintptr_t addr, int x, int color)
{
	bmp_write32(addr+x*4, color);
}

static inline int video_getpixel15_or_16(uintptr_t addr, int x)
{
	return bmp_read16(addr+x*2);
}

static inline int video_getpixel24(uintptr_t addr, int x)
{
	return bmp_read24(addr+x*3);
}

static inline int video_getpixel32(uintptr_t addr, int x)
{
	return bmp_read32(addr+x*4);
}

static 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;
    float fx, fy; /* fractional source position */
    float xi, yi; /* x and y increment */

    void (*put)(uintptr_t addr, int x, int color);
    int (*get)(uintptr_t addr, int x);

    switch (bitmap_color_depth(source)) {
	    case 15:
	    case 16:
		get = video_getpixel15_or_16;
		break;
	    case 24:
		get = video_getpixel24;
		break;
	    case 32:
		get = video_getpixel32;
		break;
    }
    switch (bitmap_color_depth(destination)) {
	    case 15:
	    case 16:
		put = video_putpixel15_or_16;
		break;
	    case 24:
		put = video_putpixel24;
		break;
	    case 32:
		put = video_putpixel32;
		break;
    }

    xi = (float)sw / dw;
    yi = (float)sh / dh;

    fy = (float)sy + yi / 2;
    fx = (float)sx + xi / 2;

    for (y = dy; y < dy + dh; y++) {
        float fx_backup = fx;
	uintptr_t saddr = bmp_write_line(source, (int)fy);
	uintptr_t daddr = bmp_write_line(destination, y);
        for (x = dx; x < dx + dw; x++) {
	    int color;
	    bmp_select(source);
	    color = get(saddr, (int)fx);
	    bmp_select(destination);
	    put(daddr, x, color);
            fx += xi;
        }
	bmp_unwrite_line(source);
	bmp_unwrite_line(destination);
        fx = fx_backup;
        fy += yi;
    }
}

static 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;
    float fx, fy; /* fractional source position */
    float xi, yi; /* x and y increment */

    void (*put)(BITMAP* bmp, int x, int y, int color);
    int (*get)(uintptr_t addr, int x);

    switch (bitmap_color_depth(source)) {
	    case 15:
	    case 16:
		get = video_getpixel15_or_16;
		break;
	    case 24:
		get = video_getpixel24;
		break;
	    case 32:
		get = video_getpixel32;
		break;
    }
    switch (bitmap_color_depth(destination)) {
	    case 15:
	    case 16:
		put = memory_putpixel15_or_16;
		break;
	    case 24:
		put = memory_putpixel24;
		break;
	    case 32:
		put = memory_putpixel32;
		break;
    }

    xi = (float)sw / dw;
    yi = (float)sh / dh;

    fy = (float)sy + yi / 2;
    fx = (float)sx + xi / 2;

    for (y = dy; y < dy + dh; y++) {
        float fx_backup = fx;
	bmp_select(source);
	uintptr_t saddr = bmp_write_line(source, (int)fy);
        for (x = dx; x < dx + dw; x++) {
	    int color;
	    color = get(saddr, (int)fx);
	    put(destination, x, y, color);
            fx += xi;
        }
	bmp_unwrite_line(source);
        fx = fx_backup;
        fy += yi;
    }
}

static 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;
    float fx, fy; /* fractional source position */
    float xi, yi; /* x and y increment */

    void (*put)(uintptr_t addr, int x, int color);
    int (*get)(BITMAP* bmp, int x, int y);

    switch (bitmap_color_depth(source)) {
	    case 15:
	    case 16:
		get = memory_getpixel15_or_16;
		break;
	    case 24:
		get = memory_getpixel24;
		break;
	    case 32:
		get = memory_getpixel32;
		break;
    }
    switch (bitmap_color_depth(destination)) {
	    case 15:
	    case 16:
		put = video_putpixel15_or_16;
		break;
	    case 24:
		put = video_putpixel24;
		break;
	    case 32:
		put = video_putpixel32;
		break;
    }

    xi = (float)sw / dw;
    yi = (float)sh / dh;

    fy = (float)sy + yi / 2;
    fx = (float)sx + xi / 2;

    for (y = dy; y < dy + dh; y++) {
        float fx_backup = fx;
	bmp_select(destination);
	uintptr_t daddr = bmp_write_line(destination, y);
        for (x = dx; x < dx + dw; x++) {
	    int color;
	    color = get(source, (int)fx, (int)fy);
	    put(daddr, x, color);
            fx += xi;
        }
	bmp_unwrite_line(destination);
        fx = fx_backup;
        fy += yi;
    }
}

static 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;
    float fx, fy; /* fractional source position */
    float xi, yi; /* x and y increment */

    void (*put)(BITMAP* bmp, int x, int y, int color);
    int (*get)(BITMAP* bmp, int x, int y);

    switch (bitmap_color_depth(source)) {
	    case 15:
	    case 16:
		get = memory_getpixel15_or_16;
		break;
	    case 24:
		get = memory_getpixel24;
		break;
	    case 32:
		get = memory_getpixel32;
		break;
    }
    switch (bitmap_color_depth(destination)) {
	    case 15:
	    case 16:
		put = memory_putpixel15_or_16;
		break;
	    case 24:
		put = memory_putpixel24;
		break;
	    case 32:
		put = memory_putpixel32;
		break;
    }

    xi = (float)sw / dw;
    yi = (float)sh / dh;

    fy = (float)sy + yi / 2;
    fx = (float)sx + xi / 2;

    for (y = dy; y < dy + dh; y++) {
        float fx_backup = fx;
        for (x = dx; x < dx + dw; x++) {
	    int color;
	    color = get(source, (int)fx, (int)fy);
	    put(destination, x, y, color);
            fx += xi;
        }
        fx = fx_backup;
        fy += yi;
    }
}

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);
	}
}



Mail converted by MHonArc 2.6.19+ http://listengine.tuxfamily.org/