Re: [AD] offscreen sub bitmaps revisited

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


On Sat, Jun 26, 2010 at 1:04 PM, Matthew Leverton <meffer@xxxxxxxxxx> wrote:
> On Sat, Jun 26, 2010 at 7:52 AM, Elias Pschernig
>> You can apply the patch as is I'd say, will be more
>> motivation to fix things properly.
>>
Applied the attached patch.

Drawing from and to out-of-bounds memory sub-bitmaps should work now.
Tested with ex_subbitmap on regular, scaled, and flipped bitmaps.

I'm assuming it doesn't work with transformations on memory bitmaps.

OpenGL is buggy when blitting from an out-of-bounds source sub bitmap.

Haven't tested D3D.

--
Matthew Leverton
Index: src/bitmap.c
===================================================================
--- src/bitmap.c	(revision 13401)
+++ src/bitmap.c	(working copy)
@@ -616,34 +616,12 @@
 {
    ALLEGRO_BITMAP *bitmap;
 
-   /* Clip */
-   if (x < 0) {
-      w += x;
-      if (w < 0) w = 0;
-      x = 0;
-   }
-   if (y < 0) {
-      h += y;
-      if (h < 0) h = 0;
-      y = 0;
-   }
-   if (x+w > parent->w) {
-      w = parent->w - x;
-   }
-   if (y+h > parent->h) {
-      h = parent->h - y;
-   }
-
    if (parent->parent) {
       x += parent->xofs;
       y += parent->yofs;
       parent = parent->parent;
    }
 
-   /* Note:
-    * Drivers are guaranteed that the parent is not a subbitmap itself
-    * and that the passed rectangle lies fully within the parent.
-    */
    if (parent->display && parent->display->vt &&
          parent->display->vt->create_sub_bitmap)
    {
Index: src/memblit.c
===================================================================
--- src/memblit.c	(revision 13401)
+++ src/memblit.c	(working copy)
@@ -166,8 +166,108 @@
 #define SRC_NOT_MODIFIED \
    src_mode == ALLEGRO_ONE && src_alpha == ALLEGRO_ONE && \
    tint.r == 1.0f && tint.g == 1.0f && tint.b == 1.0f && tint.a == 1.0f
+   
+/* sub-bitmaps may originate and extend off its parents boundaries in any
+ * direction. The HANDLE_SUB_BITMAPS macro takes post-clipped coordinates
+ * for both the source and destination bitmaps and further restricts them
+ * as necessary. The wr and hr parameters are the ratio of source
+ * width & height to destination width & height _before_ clipping.
+ *
+ * First the left (top) coordinates are moved inward. Then the right
+ * (bottom) coordinates are moved inward. The changes are applied 
+ * simultaneously to the complementary bitmap with scaling taken into
+ * consideration.
+ *
+ * The coordinates are modified, and the sub-bitmaps are set to the
+ * parent bitmaps. If nothing needs to be drawn, the macro exits the 
+ * function.
+ */   
+#define HANDLE_SUB_BITMAPS(src, sx, sy, sw, sh, dest, dx, dy, dw, dh, wr, hr) \
+                                                                         \
+   if (dest->parent) {                                                   \
+      dx += dest->xofs;                                                  \
+      if (dx < 0) {                                                      \
+         int scaled_width = dx * wr;                                     \
+         sw += scaled_width;                                             \
+         sx -= scaled_width;                                             \
+         dw += dx;                                                       \
+         dx = 0;                                                         \
+      }                                                                  \
+      else if (dx >= dest->parent->w) {                                  \
+         return;                                                         \
+      }                                                                  \
+                                                                         \
+      dy += dest->yofs;                                                  \
+      if (dy < 0) {                                                      \
+         int scaled_height = dy * hr;                                    \
+         sh += scaled_height;                                            \
+         sy -= scaled_height;                                            \
+         dh += dy;                                                       \
+         dy = 0;                                                         \
+      }                                                                  \
+      else if (dy >= dest->parent->h) {                                  \
+         return;                                                         \
+      }                                                                  \
+                                                                         \
+      dest = dest->parent;                                               \
+                                                                         \
+      if (dx + dw > dest->w) {                                           \
+         sw -= (dx + dw - dest->w) * wr;                                 \
+         dw = dest->w - dx;                                              \
+      }                                                                  \
+                                                                         \
+      if (dy + dh > dest->h) {                                           \
+         sh -= (dy + dh - dest->h) * hr;                                 \
+         dh = dest->h - dy;                                              \
+      }                                                                  \
+                                                                         \
+      if (dw <= 0 || dh <= 0) {                                          \
+         return;                                                         \
+      }                                                                  \
+   }                                                                     \
+                                                                         \
+   if (src->parent) {                                                    \
+      sx += src->xofs;                                                   \
+      if (sx < 0) {                                                      \
+         int scaled_width = sx / wr;                                     \
+         dw += scaled_width;                                             \
+         dx -= scaled_width;                                             \
+         sw += sx;                                                       \
+         sx = 0;                                                         \
+      }                                                                  \
+      else if (sx >= src->parent->w) {                                   \
+         return;                                                         \
+      }                                                                  \
+                                                                         \
+      sy += src->yofs;                                                   \
+      if (sy < 0) {                                                      \
+         int scaled_height = sy / hr;                                    \
+         dh += scaled_height;                                            \
+         dy -= scaled_height;                                            \
+         sh += sy;                                                       \
+         sy = 0;                                                         \
+      }                                                                  \
+      else if (sy >= src->parent->h) {                                   \
+         return;                                                         \
+      }                                                                  \
+                                                                         \
+      src = src->parent;                                                 \
+                                                                         \
+      if (sx + sw > src->w) {                                            \
+         dw -= (sx + sw - src->w) / wr;                                  \
+         sw = src->w - sx;                                               \
+      }                                                                  \
+                                                                         \
+      if (sy + sh > src->h) {                                            \
+         dh -= (sy + sh - src->h) / hr;                                  \
+         sh = src->h - sy;                                               \
+      }                                                                  \
+                                                                         \
+      if (sw <= 0 || sh <= 0) {                                          \
+         return;                                                         \
+      }                                                                  \
+   }
 
-
 void _al_draw_bitmap_region_memory(ALLEGRO_BITMAP *bitmap,
    ALLEGRO_COLOR tint,
    int sx, int sy, int sw, int sh,
@@ -182,6 +282,7 @@
    int xinc, yinc;
    int yd;
    int sxd;
+   int dw, dh;
    
    if(!is_identity(al_get_current_transform()))
    {
@@ -228,19 +329,11 @@
       return;
    }
 
-   /* Handle sub bitmaps */
-   if (dest->parent) {
-      dx += dest->xofs;
-      dy += dest->yofs;
-      dest = dest->parent;
-   }
+	 dw = sw;
+	 dh = sh;
+	 
+	 HANDLE_SUB_BITMAPS(bitmap, sx, sy, sw, sh, dest, dx, dy, dw, dh, 1.0f, 1.0f)
 
-   if (bitmap->parent) {
-      sx += bitmap->xofs;
-      sy += bitmap->yofs;
-      bitmap = bitmap->parent;
-   }
-
 #ifdef ALLEGRO_GP2XWIZ
    if (src_mode == ALLEGRO_ALPHA &&
 	 dst_mode == ALLEGRO_INVERSE_ALPHA &&
@@ -431,19 +524,8 @@
    if (dw == 0 || dh == 0)
       return;
 
-   /* Handle sub bitmaps */
-   if (dest->parent) {
-      dx += dest->xofs;
-      dy += dest->yofs;
-      dest = dest->parent;
-   }
+   HANDLE_SUB_BITMAPS(src, sx, sy, sw, sh, dest, dx, dy, dw, dh, sxinc, syinc) 
 
-   if (src->parent) {
-      sx += src->xofs;
-      sy += src->yofs;
-      src = src->parent;
-   }
-
    if (!(src_region = al_lock_bitmap(src, ALLEGRO_PIXEL_FORMAT_ANY, ALLEGRO_LOCK_READONLY))) {
       return;
    }
@@ -1256,6 +1338,7 @@
    ALLEGRO_BITMAP *dest = al_get_target_bitmap();
    int x;
    int y;
+   int dw, dh;
 
    ASSERT(_al_pixel_format_is_real(bitmap->format));
    ASSERT(_al_pixel_format_is_real(dest->format));
@@ -1283,19 +1366,11 @@
       sh -= inc;
    }
 
-   /* Handle sub bitmaps */
-   if (dest->parent) {
-      dx += dest->xofs;
-      dy += dest->yofs;
-      dest = dest->parent;
-   }
+   dw = sw;
+   dh = sh;
+   
+   HANDLE_SUB_BITMAPS(bitmap, sx, sy, sw, sh, dest, dx, dy, dw, dh, 1.0f, 1.0f)
 
-   if (bitmap->parent) {
-      sx += bitmap->xofs;
-      sy += bitmap->yofs;
-      bitmap = bitmap->parent;
-   }
-
    /* Fast paths for no flipping */
    if (!(flags & ALLEGRO_FLIP_HORIZONTAL) &&
          !(flags & ALLEGRO_FLIP_VERTICAL)) {
@@ -1419,19 +1494,8 @@
    if (dw == 0 || dh == 0)
       return;
 
-   /* Handle sub bitmaps */
-   if (dest->parent) {
-      dx += dest->xofs;
-      dy += dest->yofs;
-      dest = dest->parent;
-   }
+   HANDLE_SUB_BITMAPS(src, sx, sy, sw, sh, dest, dx, dy, dw, dh, sxinc, syinc)
 
-   if (src->parent) {
-      sx += src->xofs;
-      sy += src->yofs;
-      src = src->parent;
-   }
-
    if (src->format == dest->format) {
       if (!(src_region = al_lock_bitmap(src, ALLEGRO_PIXEL_FORMAT_ANY,
             ALLEGRO_LOCK_READONLY))) {
Index: docs/src/refman/graphics.txt
===================================================================
--- docs/src/refman/graphics.txt	(revision 13401)
+++ docs/src/refman/graphics.txt	(working copy)
@@ -301,8 +301,7 @@
 pre-existing (parent) bitmap, but possibly with a different size and
 clipping settings.
 
-If the sub-bitmap does not lie completely inside the parent bitmap, then
-it is automatically clipped so that it does.
+The sub-bitmap may originate off or extend past the parent bitmap.
 
 See the discussion in [al_get_backbuffer] about using sub-bitmaps of
 the backbuffer.
Index: examples/ex_subbitmap.c
===================================================================
--- examples/ex_subbitmap.c	(revision 13401)
+++ examples/ex_subbitmap.c	(working copy)
@@ -50,8 +50,8 @@
 int dst_y2 = DST_HEIGHT-1;
 
 Mode mode = PLAIN_BLIT;
+int draw_flags = 0;
 
-
 int main(void)
 {
    ALLEGRO_BITMAP *src_subbmp[2] = {NULL, NULL};
@@ -147,16 +147,20 @@
          al_set_target_bitmap(dst_subbmp[1]);
          switch (mode) {
             case PLAIN_BLIT:
-               al_draw_bitmap(src_subbmp[1], 0, 0, 0);
+            {
+               al_draw_bitmap(src_subbmp[1], 0, 0, draw_flags);
                break;
+            }
             case SCALED_BLIT:
+            {
                al_draw_scaled_bitmap(src_subbmp[1],
                   0, 0, al_get_bitmap_width(src_subbmp[1]),
                   al_get_bitmap_height(src_subbmp[1]),
                   0, 0, al_get_bitmap_width(dst_subbmp[1]),
                   al_get_bitmap_height(dst_subbmp[1]),
-                  0);
+                  draw_flags);
                break;
+            }
          }
 
          #define SWAP_GREATER(f1, f2) { \
@@ -222,6 +226,14 @@
             mode = SCALED_BLIT;
             redraw = true;
          }
+         else if (event.keyboard.unichar == 'h') {
+            draw_flags ^= ALLEGRO_FLIP_HORIZONTAL;
+            redraw = true;
+         }
+         else if (event.keyboard.unichar == 'v') {
+            draw_flags ^= ALLEGRO_FLIP_VERTICAL;
+            redraw = true;
+         }
       }
       else if (event.type == ALLEGRO_EVENT_MOUSE_BUTTON_DOWN &&
             event.mouse.button == 1) {


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