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: Sat, 05 May 2007 08:55:23 -0600
On Thu, 2007-04-26 at 15:40 -0600, I wrote:
> ... Everything appears to work just as the
> original, except I'm not able to test Mode-X right now ...
I had a chance to test things out in Mode-X. Here is what I found:
I found it impossible to enter Mode-X unless Allegro is compiled with
assembly. I tried under real DOS and Linux console. If that's the case,
then the C version of the Mode-X stretchers will never be called.
However:
Neither mine nor the original C versions of the Mode-X stretchers worked
properly at all, when forced into use. Under DOS they fill with a solid
color and under Linux they segfault.
The only version that I was able to get to work properly was the
assembly version under DOS. Under Linux the assembly version gave
incorrect colors and sizes.
I'm attaching a patch that fixes the inaccuracy of the current
stretch_blit implementation. It shouldn't break anything that works
currently. The fact that the C Mode-X stretchers don't work shouldn't
matter, as they don't appear to be used (and they were broken to begin
with).
--- cstretch.c 2007-04-26 06:00:46.000000000 -0600
+++ /home/trent/allegro-4.2.1/src/c/cstretch.c 2007-05-04 17:32:42.000000000 -0600
@@ -20,35 +20,53 @@
-/* Information for stretching line (saved state of Bresenham line algorithm). */
-static struct
-{
- int i1, i2;
- int dd, dw;
- int sinc;
+/* Information for stretching line */
+static struct {
+ int xcstart; /* x counter start */
+ int sxinc; /* amount to increment src x every time */
+ int xcdec; /* amount to deccrement counter by, increase sptr when this reaches 0 */
+ int xcinc; /* amount to increment counter by when it reaches 0 */
+ int linesize; /* size of a whole row of pixels */
} _al_stretch;
-/*
- * Line stretchers.
- */
-#define DECLARE_STRETCHER(type, size, set, get) \
-int dd = _al_stretch.dd; \
-type *s = (type*) sptr; \
-uintptr_t d = dptr; \
-uintptr_t dend = d + _al_stretch.dw; \
-ASSERT(s); \
-ASSERT(d); \
-for (; d < dend; d += (size), s = (type *) \
- ((unsigned char*)s + _al_stretch.sinc)) { \
- set(d, get(s)); \
- if (dd >= 0) { \
- s = (type *) ((unsigned char*)s + (size)); \
- dd += _al_stretch.i2; \
- } \
- else \
- dd += _al_stretch.i1; \
-}
+
+/* Stretcher macros */
+#define DECLARE_STRETCHER(type, size, put, get) \
+ int xc = _al_stretch.xcstart; \
+ uintptr_t dend = dptr + _al_stretch.linesize; \
+ ASSERT(dptr); \
+ ASSERT(sptr); \
+ for (; dptr < dend; dptr += size, sptr += _al_stretch.sxinc) { \
+ put(dptr, get((type*)sptr)); \
+ if (xc <= 0) { \
+ sptr += size; \
+ xc += _al_stretch.xcinc; \
+ } \
+ else \
+ xc -= _al_stretch.xcdec; \
+ }
+
+
+
+#define DECLARE_MASKED_STRETCHER(type, size, put, get, mask) \
+ int xc = _al_stretch.xcstart; \
+ uintptr_t dend = dptr + _al_stretch.linesize; \
+ ASSERT(dptr); \
+ ASSERT(sptr); \
+ for (; dptr < dend; dptr += size, sptr += _al_stretch.sxinc) { \
+ int color = get((type*)sptr); \
+ if (color != mask) \
+ put(dptr, get((type*)sptr)); \
+ if (xc <= 0) { \
+ sptr += size; \
+ xc += _al_stretch.xcinc; \
+ } \
+ else \
+ xc -= _al_stretch.xcdec; \
+ }
+
+
#ifdef GFX_HAS_VGA
/*
@@ -57,180 +75,158 @@
static void stretch_linex(uintptr_t dptr, unsigned char *sptr)
{
int plane;
- int dw = _al_stretch.dw;
- int first_dd = _al_stretch.dd;
+ int first_xc = _al_stretch.xcstart;
+ int dw = _al_stretch.linesize;
ASSERT(dptr);
ASSERT(sptr);
for (plane = 0; plane < 4; plane++) {
- int dd = first_dd;
+ int xc = first_xc;
unsigned char *s = sptr;
uintptr_t d = dptr / 4;
uintptr_t dend = (dptr + dw) / 4;
outportw(0x3C4, (0x100 << (dptr & 3)) | 2);
- for (; d < dend; d++, s += 4 * _al_stretch.sinc) {
+
+ for (; d < dend; d++, s += 4 * _al_stretch.sxinc) {
bmp_write8(d, *s);
- if (dd >= 0) s++, dd += _al_stretch.i2;
- else dd += _al_stretch.i1;
- if (dd >= 0) s++, dd += _al_stretch.i2;
- else dd += _al_stretch.i1;
- if (dd >= 0) s++, dd += _al_stretch.i2;
- else dd += _al_stretch.i1;
- if (dd >= 0) s++, dd += _al_stretch.i2;
- else dd += _al_stretch.i1;
+ if (xc <= 0) s++, xc += _al_stretch.xcinc;
+ else xc -= _al_stretch.xcdec;
+ if (xc <= 0) s++, xc += _al_stretch.xcinc;
+ else xc -= _al_stretch.xcdec;
+ if (xc <= 0) s++, xc += _al_stretch.xcinc;
+ else xc -= _al_stretch.xcdec;
+ if (xc <= 0) s++, xc += _al_stretch.xcinc;
+ else xc -= _al_stretch.xcdec;
}
/* Move to the beginning of next plane. */
- if (first_dd >= 0)
- sptr++, first_dd += _al_stretch.i2;
+ if (first_xc <= 0) {
+ sptr++;
+ first_xc += _al_stretch.xcinc;
+ }
else
- first_dd += _al_stretch.i1;
+ first_xc -= _al_stretch.xcdec;
+
dptr++;
- sptr += _al_stretch.sinc;
+ sptr += _al_stretch.sxinc;
dw--;
}
}
-#endif
-#ifdef ALLEGRO_COLOR8
-static void stretch_line8(uintptr_t dptr, unsigned char *sptr)
-{
- DECLARE_STRETCHER(unsigned char, 1, bmp_write8, *);
-}
-#endif
-
-#ifdef ALLEGRO_COLOR16
-static void stretch_line15(uintptr_t dptr, unsigned char *sptr)
-{
- DECLARE_STRETCHER(unsigned short, sizeof(unsigned short), bmp_write15, *);
-}
-
-static void stretch_line16(uintptr_t dptr, unsigned char *sptr)
-{
- DECLARE_STRETCHER(unsigned short, sizeof(unsigned short), bmp_write16, *);
-}
-#endif
-
-#ifdef ALLEGRO_COLOR24
-
-static void stretch_line24(uintptr_t dptr, unsigned char *sptr)
-{
- DECLARE_STRETCHER(unsigned char, 3, bmp_write24, READ3BYTES);
-}
-#endif
-
-#ifdef ALLEGRO_COLOR32
-static void stretch_line32(uintptr_t dptr, unsigned char *sptr)
-{
- DECLARE_STRETCHER(uint32_t, sizeof(uint32_t), bmp_write32, *);
-}
-#endif
-
-
-
-/*
- * Masked line stretchers.
- */
-#define DECLARE_MASKED_STRETCHER(type, size, set, get, mask) \
-int dd = _al_stretch.dd; \
-type *s = (type*) sptr; \
-uintptr_t d = dptr; \
-uintptr_t dend = d + _al_stretch.dw; \
-ASSERT(s); \
-ASSERT(d); \
-for (; d < dend; d += (size), s = (type*) \
- ((unsigned char*)s + _al_stretch.sinc)) { \
- unsigned long color = get(s); \
- if (color != (mask)) \
- set(d, color); \
- if (dd >= 0) { \
- s = (type *) ((unsigned char*)s + (size)); \
- dd += _al_stretch.i2; \
- } \
- else \
- dd += _al_stretch.i1; \
-}
-
-#ifdef GFX_HAS_VGA
/*
* Mode-X masked line stretcher.
*/
static void stretch_masked_linex(uintptr_t dptr, unsigned char *sptr)
{
int plane;
- int dw = _al_stretch.dw;
- int first_dd = _al_stretch.dd;
+ int dw = _al_stretch.linesize;
+ int first_xc = _al_stretch.xcstart;
ASSERT(dptr);
ASSERT(sptr);
for (plane = 0; plane < 4; plane++) {
- int dd = first_dd;
+ int xc = first_xc;
unsigned char *s = sptr;
uintptr_t d = dptr / 4;
uintptr_t dend = (dptr + dw) / 4;
outportw(0x3C4, (0x100 << (dptr & 3)) | 2);
- for (; d < dend; d++, s += 4 * _al_stretch.sinc) {
+
+ for (; d < dend; d++, s += 4 * _al_stretch.sxinc) {
unsigned long color = *s;
if (color != 0)
bmp_write8(d, color);
- if (dd >= 0) s++, dd += _al_stretch.i2;
- else dd += _al_stretch.i1;
- if (dd >= 0) s++, dd += _al_stretch.i2;
- else dd += _al_stretch.i1;
- if (dd >= 0) s++, dd += _al_stretch.i2;
- else dd += _al_stretch.i1;
- if (dd >= 0) s++, dd += _al_stretch.i2;
- else dd += _al_stretch.i1;
+ if (xc <= 0) s++, xc += _al_stretch.xcinc;
+ else xc -= _al_stretch.xcdec;
+ if (xc <= 0) s++, xc += _al_stretch.xcinc;
+ else xc -= _al_stretch.xcdec;
+ if (xc <= 0) s++, xc += _al_stretch.xcinc;
+ else xc -= _al_stretch.xcdec;
+ if (xc <= 0) s++, xc += _al_stretch.xcinc;
+ else xc -= _al_stretch.xcdec;
}
/* Move to the beginning of next plane. */
- if (first_dd >= 0)
- sptr++, first_dd += _al_stretch.i2;
+ if (first_xc <= 0) {
+ sptr++;
+ first_xc += _al_stretch.xcinc;
+ }
else
- first_dd += _al_stretch.i1;
+ first_xc -= _al_stretch.xcdec;
+
dptr++;
- sptr += _al_stretch.sinc;
+ sptr += _al_stretch.sxinc;
dw--;
}
}
#endif
+
+
#ifdef ALLEGRO_COLOR8
+static void stretch_line8(uintptr_t dptr, unsigned char *sptr)
+{
+ DECLARE_STRETCHER(unsigned char, 1, bmp_write8, *);
+}
+
static void stretch_masked_line8(uintptr_t dptr, unsigned char *sptr)
{
DECLARE_MASKED_STRETCHER(unsigned char, 1, bmp_write8, *, 0);
}
#endif
+
+
#ifdef ALLEGRO_COLOR16
-static void stretch_masked_line15(uintptr_t dptr, unsigned char *sptr)
+static void stretch_line15(uintptr_t dptr, unsigned char* sptr)
+{
+ DECLARE_STRETCHER(unsigned short, 2, bmp_write15, *);
+}
+
+static void stretch_line16(uintptr_t dptr, unsigned char* sptr)
{
- DECLARE_MASKED_STRETCHER(unsigned short, sizeof(unsigned short),
- bmp_write15, *, MASK_COLOR_15);
+ DECLARE_STRETCHER(unsigned short, 2, bmp_write16, *);
}
-static void stretch_masked_line16(uintptr_t dptr, unsigned char *sptr)
+static void stretch_masked_line15(uintptr_t dptr, unsigned char* sptr)
{
- DECLARE_MASKED_STRETCHER(unsigned short, sizeof(unsigned short),
- bmp_write16, *, MASK_COLOR_16);
+ DECLARE_MASKED_STRETCHER(unsigned short, 2, bmp_write15, *, MASK_COLOR_15);
+}
+
+static void stretch_masked_line16(uintptr_t dptr, unsigned char* sptr)
+{
+ DECLARE_MASKED_STRETCHER(unsigned short, 2, bmp_write16, *, MASK_COLOR_16);
}
#endif
+
+
#ifdef ALLEGRO_COLOR24
-static void stretch_masked_line24(uintptr_t dptr, unsigned char *sptr)
+static void stretch_line24(uintptr_t dptr, unsigned char* sptr)
+{
+ DECLARE_STRETCHER(unsigned char, 3, bmp_write24, READ3BYTES);
+}
+
+static void stretch_masked_line24(uintptr_t dptr, unsigned char* sptr)
{
DECLARE_MASKED_STRETCHER(unsigned char, 3, bmp_write24, READ3BYTES, MASK_COLOR_24);
}
#endif
+
+
#ifdef ALLEGRO_COLOR32
-static void stretch_masked_line32(uintptr_t dptr, unsigned char *sptr)
+static void stretch_line32(uintptr_t dptr, unsigned char* sptr)
{
- DECLARE_MASKED_STRETCHER(uint32_t, sizeof(uint32_t), bmp_write32, *, MASK_COLOR_32);
+ DECLARE_STRETCHER(uint32_t, 4, bmp_write32, *);
+}
+
+static void stretch_masked_line32(uintptr_t dptr, unsigned char* sptr)
+{
+ DECLARE_MASKED_STRETCHER(uint32_t, 4, bmp_write32, *, MASK_COLOR_32);
}
#endif
@@ -240,17 +236,21 @@
* Stretch blit work-horse.
*/
static void _al_stretch_blit(BITMAP *src, BITMAP *dst,
- int sx, int sy, int sw, int sh,
- int dx, int dy, int dw, int dh,
- int masked)
-{
- int x, y, fixup;
- int i1, i2, dd;
- int xinc, yinc;
- int dxbeg, dxend;
+ int sx, int sy, int sw, int sh, int dx, int dy, int dw, int dh,
+ int masked)
+{
+ int y; /* current dst y */
+ int yc; /* y counter */
+ int sxofs, dxofs; /* start offsets */
+ int syinc; /* amount to increment src y each time */
+ int ycdec; /* amount to deccrement counter by, increase sy when this reaches 0 */
+ int ycinc; /* amount to increment counter by when it reaches 0 */
+ int size = 0; /* pixel size */
+ int dxbeg, dxend; /* clipping information */
int dybeg, dyend;
- int sxofs, dxofs;
- void (*stretch_line)(uintptr_t dptr, unsigned char *sptr);
+ int i;
+
+ void (*stretch_line)(uintptr_t, unsigned char*) = 0;
ASSERT(src);
ASSERT(dst);
@@ -264,115 +264,42 @@
if ((sw <= 0) || (sh <= 0) || (dw <= 0) || (dh <= 0))
return;
- if (dst->clip) {
- dybeg = ((dy > dst->ct) ? dy : dst->ct);
- dyend = (((dy + dh) < dst->cb) ? (dy + dh) : dst->cb);
- if (dybeg >= dyend)
- return;
-
- dxbeg = ((dx > dst->cl) ? dx : dst->cl);
- dxend = (((dx + dw) < dst->cr) ? (dx + dw) : dst->cr);
- if (dxbeg >= dxend)
- return;
- }
- else {
- dxbeg = dx;
- dxend = dx + dw;
- dybeg = dy;
- dyend = dy + dh;
- }
-
- /* Bresenham algorithm uses difference between points, not number of points. */
- sw--;
- sh--;
- dw--;
- dh--;
-
- /* How much to add to src-coordinates, when moving to the next dst-coordinate. */
- if (dw == 0)
- xinc = 0;
- else {
- xinc = sw / dw;
- sw %= dw;
- }
-
- if (dh == 0)
- yinc = 0;
- else {
- yinc = sh / dh;
- sh %= dh;
- }
-
- /* Walk in x direction until dxbeg and save Bresenham state there. */
- i2 = (dd = (i1 = 2 * sw) - dw) - dw;
- for (x = dx, y = sx; x < dxbeg; x++, y += xinc) {
- if (dd >= 0)
- y++, dd += i2;
- else
- dd += i1;
- }
-
- /* Save Bresenham algorithm state with offset fixups. */
- switch (bitmap_color_depth(dst)) {
- case 15:
- case 16:
- fixup = sizeof(uint16_t);
- break;
- case 24:
- fixup = 3;
- break;
- case 32:
- fixup = sizeof(uint32_t);
- break;
- default:
- fixup = 1;
- break;
- }
- sxofs = y * fixup;
- dxofs = x * fixup;
-
- _al_stretch.i1 = i1;
- _al_stretch.i2 = i2;
- _al_stretch.dd = dd;
- _al_stretch.dw = (dxend - dxbeg) * fixup;
- _al_stretch.sinc = xinc * fixup;
-
- /* Find out which stretcher should be used. */
+ /* Find out which stretcher should be used */
if (masked) {
switch (bitmap_color_depth(dst)) {
#ifdef ALLEGRO_COLOR8
case 8:
if (is_linear_bitmap(dst))
stretch_line = stretch_masked_line8;
- else {
#ifdef GFX_HAS_VGA
+ else
stretch_line = stretch_masked_linex;
-#else
- return;
#endif
- }
+ size = 1;
break;
#endif
#ifdef ALLEGRO_COLOR16
case 15:
stretch_line = stretch_masked_line15;
+ size = 2;
break;
case 16:
stretch_line = stretch_masked_line16;
+ size = 2;
break;
#endif
#ifdef ALLEGRO_COLOR24
case 24:
stretch_line = stretch_masked_line24;
+ size = 3;
break;
#endif
#ifdef ALLEGRO_COLOR32
case 32:
stretch_line = stretch_masked_line32;
+ size = 4;
break;
#endif
- default:
- return;
}
}
else {
@@ -381,58 +308,107 @@
case 8:
if (is_linear_bitmap(dst))
stretch_line = stretch_line8;
- else {
#ifdef GFX_HAS_VGA
+ else
stretch_line = stretch_linex;
-#else
- return;
#endif
- }
+ size = 1;
break;
#endif
#ifdef ALLEGRO_COLOR16
case 15:
stretch_line = stretch_line15;
+ size = 2;
break;
case 16:
stretch_line = stretch_line16;
+ size = 2;
break;
#endif
#ifdef ALLEGRO_COLOR24
case 24:
stretch_line = stretch_line24;
+ size = 3;
break;
#endif
#ifdef ALLEGRO_COLOR32
case 32:
stretch_line = stretch_line32;
+ size = 4;
break;
#endif
- default:
- return;
}
}
ASSERT(stretch_line);
- /* Walk in y direction until we reach first non-clipped line. */
- i2 = (dd = (i1 = 2 * sh) - dh) - dh;
- for (x = dy, y = sy; x < dybeg; x++, y += yinc) {
- if (dd >= 0)
- y++, dd += i2;
+ if (dst->clip) {
+ dybeg = ((dy > dst->ct) ? dy : dst->ct);
+ dyend = (((dy + dh) < dst->cb) ? (dy + dh) : dst->cb);
+ if (dybeg >= dyend)
+ return;
+
+ dxbeg = ((dx > dst->cl) ? dx : dst->cl);
+ dxend = (((dx + dw) < dst->cr) ? (dx + dw) : dst->cr);
+ if (dxbeg >= dxend)
+ return;
+ }
+ else {
+ dxbeg = dx;
+ dxend = dx + dw;
+ dybeg = dy;
+ dyend = dy + dh;
+ }
+
+ syinc = sh / dh;
+ ycdec = sh - (syinc*dh);
+ ycinc = dh - ycdec;
+ yc = ycinc;
+ sxofs = sx * size;
+ dxofs = dx * size;
+
+ _al_stretch.sxinc = sw / dw * size;
+ _al_stretch.xcdec = sw - ((sw/dw)*dw);
+ _al_stretch.xcinc = dw - _al_stretch.xcdec;
+ _al_stretch.linesize = (dxend-dxbeg)*size;
+
+ /* get start state (clip) */
+ _al_stretch.xcstart = _al_stretch.xcinc;
+ for (i = 0; i < dxbeg-dx; i++, sxofs += _al_stretch.sxinc) {
+ if (_al_stretch.xcstart <= 0) {
+ _al_stretch.xcstart += _al_stretch.xcinc;
+ sxofs += size;
+ }
else
- dd += i1;
+ _al_stretch.xcstart -= _al_stretch.xcdec;
}
- /* Stretch all non-clipped lines. */
+ dxofs += i * size;
+
+ /* skip clipped lines */
+ for (y = dy; y < dybeg; y++, sy += syinc) {
+ if (yc <= 0) {
+ sy++;
+ yc += ycinc;
+ }
+ else
+ yc -= ycdec;
+ }
+
+ /* Stretch it */
+
bmp_select(dst);
- for (; x < dyend; x++, y += yinc) {
- (*stretch_line)(bmp_write_line(dst, x) + dxofs, src->line[y] + sxofs);
- if (dd >= 0)
- y++, dd += i2;
+
+ for (; y < dyend; y++, sy += syinc) {
+ (*stretch_line)(bmp_write_line(dst, y) + dxofs, src->line[sy] + sxofs);
+ if (yc <= 0) {
+ sy++;
+ yc += ycinc;
+ }
else
- dd += i1;
+ yc -= ycdec;
}
+
bmp_unwrite_line(dst);
}