bitblt.c

changeset 47
bfc6aaa089b0
parent 43
b80cb5a4282a
child 48
3d0be1c1c1b2
     1.1 --- a/bitblt.c	Sun Aug 25 13:22:42 2002 +0000
     1.2 +++ b/bitblt.c	Mon Aug 26 05:43:49 2002 +0000
     1.3 @@ -1,3 +1,4 @@
     1.4 +#include <assert.h>
     1.5  #include <stdio.h>
     1.6  #include <stdlib.h>
     1.7  #include <string.h>
     1.8 @@ -45,6 +46,17 @@
     1.9    0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
    1.10  };
    1.11  
    1.12 +
    1.13 +void reverse_bits (u8 *p, int byte_count)
    1.14 +{
    1.15 +  while (byte_count--)
    1.16 +    {
    1.17 +      (*p) = bit_reverse_byte [*p];
    1.18 +      p++;
    1.19 +    }
    1.20 +}
    1.21 +
    1.22 +
    1.23  static word_type bit_reverse_word (word_type d)
    1.24  {
    1.25    return (bit_reverse_byte [d >> 24] |
    1.26 @@ -54,8 +66,8 @@
    1.27  }
    1.28  
    1.29  
    1.30 -static u32 *temp_buffer;
    1.31 -static u32 temp_buffer_size;
    1.32 +static word_type *temp_buffer;
    1.33 +static word_type temp_buffer_size;
    1.34  
    1.35  static void realloc_temp_buffer (u32 size)
    1.36  {
    1.37 @@ -71,15 +83,41 @@
    1.38  }
    1.39  
    1.40  
    1.41 -static inline word_type pixel_mask (x)
    1.42 +static inline word_type pixel_mask (int x)
    1.43  {
    1.44 -#ifdef LSB_LEFT
    1.45 -  return (1 << x);
    1.46 +#if defined (MIXED_ENDIAN)  /* disgusting hack for mixed-endian */
    1.47 +  word_type m;
    1.48 +  m = 0x80 >> (x & 7);
    1.49 +  m <<= (x & 24);
    1.50 +  return (m);
    1.51 +#elif defined (LSB_RIGHT)
    1.52 +  return (1U << ((BITS_PER_WORD - 1) - x));
    1.53  #else
    1.54 -  return (1 << ((BITS_PER_WORD - 1) - x));
    1.55 +  return (1U << x);
    1.56  #endif
    1.57  };
    1.58  
    1.59 +
    1.60 +/* mask for range of bits left..right, inclusive */
    1.61 +static inline word_type pixel_range_mask (int left, int right)
    1.62 +{
    1.63 +  word_type m1, m2, val;
    1.64 +
    1.65 +  /* $$$ one of these cases is wrong! */
    1.66 +#if defined (LSB_RIGHT)
    1.67 +  m1 = (~ 0U) >> left;
    1.68 +  m2 = (~ 0U) << (BITS_PER_WORD - 1 - right);
    1.69 +#else
    1.70 +  m1 = (~ 0U) << left;
    1.71 +  m2 = (~ 0U) >> (BITS_PER_WORD - 1 - right);
    1.72 +#endif
    1.73 +  val = m1 & m2;
    1.74 +
    1.75 +  printf ("left %d, right %d, mask %08x\n", left, right, val);
    1.76 +  return (val);
    1.77 +};
    1.78 +
    1.79 +
    1.80  Bitmap *create_bitmap (Rect *rect)
    1.81  {
    1.82    Bitmap *bitmap;
    1.83 @@ -112,32 +150,40 @@
    1.84  boolean get_pixel (Bitmap *bitmap, Point coord)
    1.85  {
    1.86    word_type *p;
    1.87 +  int w,b;
    1.88 +
    1.89    if ((coord.x < bitmap->rect.min.x) ||
    1.90        (coord.x >= bitmap->rect.max.x) ||
    1.91        (coord.y < bitmap->rect.min.y) ||
    1.92        (coord.y >= bitmap->rect.max.y))
    1.93      return (0);
    1.94 -  p = bitmap->bits +
    1.95 -    (coord.y - bitmap->rect.min.y) * bitmap->row_words +
    1.96 -    (coord.x - bitmap->rect.min.x) / BITS_PER_WORD;
    1.97 -  return ((*p & pixel_mask (coord.x & (BITS_PER_WORD - 1))) != 0);
    1.98 +  coord.y -= bitmap->rect.min.y;
    1.99 +  coord.x -= bitmap->rect.min.x;
   1.100 +  w = coord.x / BITS_PER_WORD;
   1.101 +  b = coord.x & (BITS_PER_WORD - 1);
   1.102 +  p = bitmap->bits + coord.y * bitmap->row_words + w;
   1.103 +  return (((*p) & pixel_mask (b)) != 0);
   1.104  }
   1.105  
   1.106  void set_pixel (Bitmap *bitmap, Point coord, boolean value)
   1.107  {
   1.108    word_type *p;
   1.109 +  int w,b;
   1.110 +
   1.111    if ((coord.x < bitmap->rect.min.x) ||
   1.112        (coord.x >= bitmap->rect.max.x) ||
   1.113        (coord.y < bitmap->rect.min.y) ||
   1.114        (coord.y >= bitmap->rect.max.y))
   1.115      return;
   1.116 -  p = bitmap->bits +
   1.117 -    (coord.y - bitmap->rect.min.y) * bitmap->row_words +
   1.118 -    (coord.x - bitmap->rect.min.x) / BITS_PER_WORD;
   1.119 +  coord.y -= bitmap->rect.min.y;
   1.120 +  coord.x -= bitmap->rect.min.x;
   1.121 +  w = coord.x / BITS_PER_WORD;
   1.122 +  b = coord.x & (BITS_PER_WORD - 1);
   1.123 +  p = bitmap->bits + coord.y * bitmap->row_words + w;
   1.124    if (value)
   1.125 -    *p |= pixel_mask (coord.x & (BITS_PER_WORD - 1));
   1.126 +    (*p) |= pixel_mask (b);
   1.127    else
   1.128 -    *p &= ~pixel_mask (coord.x & (BITS_PER_WORD - 1));
   1.129 +    (*p) &= ~pixel_mask (b);
   1.130  }
   1.131  
   1.132  
   1.133 @@ -174,36 +220,104 @@
   1.134  }
   1.135  
   1.136  
   1.137 -#if 0
   1.138  static void blt_background (Bitmap *dest_bitmap,
   1.139 -			    Rect *dest_rect)
   1.140 +			    Rect dest_rect)
   1.141  {
   1.142 -  s32 y;
   1.143 +  u32 y;
   1.144    word_type *rp;
   1.145 +  u32 left_bit, left_word;
   1.146 +  u32 right_bit, right_word;
   1.147 +  word_type left_mask, right_mask;
   1.148 +  s32 word_count;
   1.149  
   1.150    /* This function requires a non-null dest rect */
   1.151 -  assert (dest_rect->min.x < dest_rect->max.x);
   1.152 -  assert (dest_rect->min.y < dest_rect->max.y);
   1.153 +  assert (dest_rect.min.x < dest_rect.max.x);
   1.154 +  assert (dest_rect.min.y < dest_rect.max.y);
   1.155   
   1.156    /* and that the rows of the dest rect lie entirely within the dest bitmap */
   1.157 -  assert (dest_rect->min.y >= dest_bitmap->rect->min.y);
   1.158 -  assert (dest_rect->max.y <= dest_bitmap->rect->max.y);
   1.159 +  assert (dest_rect.min.y >= dest_bitmap->rect.min.y);
   1.160 +  assert (dest_rect.max.y <= dest_bitmap->rect.max.y);
   1.161  
   1.162    /* clip the x axis of the dest_rect to the bounds of the dest bitmap */
   1.163 -  if (dest_rect->min.x < dest_bitmap->rect.min.x)
   1.164 -    dest_rect->min.x = dest_bitmap->rect.min.x;
   1.165 -  if (dest_rect->max.x > dest_bitmap->rect.max.x)
   1.166 -    dest_rect->max.x = dest_bitmap->rect.max.x;
   1.167 +  if (dest_rect.min.x < dest_bitmap->rect.min.x)
   1.168 +    dest_rect.min.x = dest_bitmap->rect.min.x;
   1.169 +  if (dest_rect.max.x > dest_bitmap->rect.max.x)
   1.170 +    dest_rect.max.x = dest_bitmap->rect.max.x;
   1.171 +
   1.172 +  rp = dest_bitmap->bits +
   1.173 +    (dest_rect.min.y - dest_bitmap->rect.min.y) * dest_bitmap->row_words +
   1.174 +    (dest_rect.min.x - dest_bitmap->rect.min.x) / BITS_PER_WORD;
   1.175 +
   1.176 +  left_bit = dest_rect.min.x % BITS_PER_WORD;
   1.177 +  left_word = dest_rect.min.x / BITS_PER_WORD;
   1.178 +
   1.179 +  right_bit = (dest_rect.max.x - 1) % BITS_PER_WORD;
   1.180 +  right_word = (dest_rect.max.x - 1) / BITS_PER_WORD;
   1.181 +
   1.182 +  word_count = right_word + 1 - left_word;
   1.183 +
   1.184 +  /* special case if entire horizontal range fits in a single word */
   1.185 +  if (word_count == 1)
   1.186 +    {
   1.187 +      left_mask = 0;
   1.188 +      right_mask = ~ pixel_range_mask (left_bit, right_bit);
   1.189 +      word_count = 0;
   1.190 +    }
   1.191 +  else
   1.192 +    {
   1.193 +      if (left_bit)
   1.194 +	{
   1.195 +	  left_mask = ~ pixel_range_mask (left_bit, BITS_PER_WORD - 1);
   1.196 +	  word_count--;
   1.197 +	}
   1.198  
   1.199 -  rp = ???;
   1.200 -  for (y = 0; y < rect_height (dest_rect); y++)
   1.201 +      if (right_bit != (BITS_PER_WORD - 1))
   1.202 +	{
   1.203 +	  right_mask = ~ pixel_range_mask (0, right_bit);
   1.204 +	  word_count--;
   1.205 +	}
   1.206 +    }
   1.207 +
   1.208 +  for (y = 0; y < rect_height (& dest_rect); y++)
   1.209      {
   1.210 -  ???;
   1.211 +      word_type *wp = rp;
   1.212 +
   1.213 +      /* partial word at left, if any */
   1.214 +      if (left_mask)
   1.215 +	*(wp++) &= left_mask;
   1.216 +
   1.217 +      /* use Duff's Device for the full words */
   1.218 +      if (word_count)
   1.219 +	{
   1.220 +	  s32 i = word_count;
   1.221 +	  switch (i % 8)
   1.222 +	    {
   1.223 +	      while (i > 0)
   1.224 +		{
   1.225 +		  *(wp++) = 0;
   1.226 +		case 7: *(wp++) = 0;
   1.227 +		case 6: *(wp++) = 0;
   1.228 +		case 5: *(wp++) = 0;
   1.229 +		case 4: *(wp++) = 0;
   1.230 +		case 3: *(wp++) = 0;
   1.231 +		case 2: *(wp++) = 0;
   1.232 +		case 1: *(wp++) = 0;
   1.233 +		case 0: i -= 8;
   1.234 +		}
   1.235 +	    }
   1.236 +	}
   1.237 +
   1.238 +      /* partial word at right, if any */
   1.239 +      if (right_mask)
   1.240 +	*wp &= right_mask;
   1.241 +
   1.242 +      /* advance to next row */
   1.243        rp += dest_bitmap->row_words;
   1.244      }
   1.245  }
   1.246  
   1.247  
   1.248 +#if 0
   1.249  static void blt (Bitmap *src_bitmap,
   1.250  		 Rect *src_rect,
   1.251  		 Bitmap *dest_bitmap,
   1.252 @@ -253,6 +367,32 @@
   1.253  }
   1.254  
   1.255  
   1.256 +/*
   1.257 + * The destination rectangle is first clipped to the dest bitmap, and
   1.258 + * the source rectangle is adjusted in the corresponding manner.
   1.259 + * What's left is divided into five sections, any of which may be
   1.260 + * null.  The portion that actually corresponds to the intersection of
   1.261 + * the source rectangle and the source bitmpa is the "middle".  The
   1.262 + * other four sections will use the background color as the source
   1.263 + * operand.
   1.264 + *
   1.265 + *          
   1.266 + *   y0 ->  -------------------------------------------------
   1.267 + *          |                     top                       |
   1.268 + *          |                                               |
   1.269 + *   y1 ->  -------------------------------------------------
   1.270 + *          |   left        |    middle     |    right      |
   1.271 + *          |               |               |               |
   1.272 + *   y2 ->  -------------------------------------------------
   1.273 + *          |                     bottom                    |
   1.274 + *          |                                               |
   1.275 + *   y3 ->  -------------------------------------------------
   1.276 + *
   1.277 + *          ^               ^               ^               ^
   1.278 + *          |               |               |               |
   1.279 + *         x0              x1              x2              x3
   1.280 + *
   1.281 + * */
   1.282  Bitmap *bitblt (Bitmap *src_bitmap,
   1.283  		Rect   *src_rect,
   1.284  		Bitmap *dest_bitmap,
   1.285 @@ -265,6 +405,10 @@
   1.286    u32 drw, drh;    /* dest rect width, height - gets adjusted */
   1.287    Point src_point, dest_point;
   1.288  
   1.289 +  /* dest coordinates: */
   1.290 +  u32 x0, x1, x2, x3;
   1.291 +  u32 y0, y1, y2, y3;
   1.292 +
   1.293    {
   1.294      sr = * src_rect;
   1.295  
   1.296 @@ -274,7 +418,8 @@
   1.297      if ((srw < 0) || (srh < 0))
   1.298        goto done;  /* the source rect is empty! */
   1.299  
   1.300 -    dr.min = * dest_min;
   1.301 +    dr.min.x = dest_min->x;
   1.302 +    dr.min.y = dest_min->y;
   1.303      dr.max.x = dr.min.x + srw;
   1.304      dr.max.y = dr.min.y + srh;
   1.305    }
   1.306 @@ -291,7 +436,6 @@
   1.307      goto done;  /* the dest rect isn't even in the dest bitmap! */
   1.308  
   1.309    /* crop dest rect to dest bitmap */
   1.310 -
   1.311    delta = dest_bitmap->rect.min.x - dr.min.x;
   1.312    if (delta > 0)
   1.313      {
   1.314 @@ -323,17 +467,36 @@
   1.315    drw = rect_width (& dr);
   1.316    drh = rect_height (& dh);
   1.317  
   1.318 +  x0 = dr.min.x;
   1.319 +  y0 = dr.min.y;
   1.320 +  x3 = dr.max.x;
   1.321 +  y3 = dr.max.y;
   1.322 +
   1.323 +#if 0
   1.324    /* if the source rect min y is >= the source bitmap max y,
   1.325       we transfer background color to the entire dest rect */
   1.326    if (sr.min.y >= src->rect.max.y)
   1.327      {
   1.328 -      blt_background (dest_bitmap, & dr);
   1.329 +      blt_background (dest_bitmap, dr);
   1.330        goto done;
   1.331      }
   1.332 +#endif
   1.333 +
   1.334 +  /* top */
   1.335 +  if (y0 != y1)
   1.336 +    {
   1.337 +      dr2.min.x = x0;
   1.338 +      dr2.max.x = x3;
   1.339 +      dr2.min.y = y0;
   1.340 +      dr2.max.y = y1;
   1.341 +      blt_background (dest_bitmap, & dr2);
   1.342 +    }
   1.343  
   1.344 -  /* if the source rect min y is less than the source bitmap min y,
   1.345 -     we need to transfer some backgound color to the top part of the dest
   1.346 -     rect */
   1.347 +  /*
   1.348 +   * top:  if the source rect min y is less than the source bitmap min y,
   1.349 +   * we need to transfer some backgound color to the top part of the dest
   1.350 +   * rect
   1.351 +   */
   1.352    if (sr.min.y < src->rect.min.y)
   1.353      {
   1.354        Rect dr2;
   1.355 @@ -359,13 +522,43 @@
   1.356  	goto done;
   1.357      }
   1.358  
   1.359 -  /* now blt the available rows of the source rect */
   1.360 +  if (y1 != y2)
   1.361 +    {
   1.362 +      /* left */
   1.363 +      if (x0 != x1)
   1.364 +	{
   1.365 +	  dr2.min.x = x1;
   1.366 +	  dr2.max.x = x1;
   1.367 +	  dr2.min.y = y1;
   1.368 +	  dr2.max.y = y2
   1.369 +	  blt_background (dest_bitmap, & dr2);
   1.370 +	}
   1.371 +
   1.372 +      /* middle */
   1.373 +      if (x1 != x2)
   1.374 +	{
   1.375 +	  /* ??? */
   1.376 +	}
   1.377  
   1.378 -  /* now transfer the background color to any remaining rows of the
   1.379 -     dest rect */
   1.380 -  if (??? )
   1.381 +      /* right */
   1.382 +      if (x2 != x3)
   1.383 +	{
   1.384 +	  dr2.min.x = x2;
   1.385 +	  dr2.max.x = x3;
   1.386 +	  dr2.min.y = y1;
   1.387 +	  dr2.max.y = y2
   1.388 +	  blt_background (dest_bitmap, & dr2);
   1.389 +	}
   1.390 +    }
   1.391 +
   1.392 +  /* bottom */
   1.393 +  if (y2 != y3)
   1.394      {
   1.395 -      blt_background (dest_bitmap, & dr);
   1.396 +      dr2.min.x = x0;
   1.397 +      dr2.max.x = x3;
   1.398 +      dr2.min.y = y2;
   1.399 +      dr2.max.y = y3;
   1.400 +      blt_background (dest_bitmap, & dr2);
   1.401      }
   1.402  
   1.403   done:
   1.404 @@ -390,25 +583,49 @@
   1.405  	return (NULL);
   1.406      }
   1.407  
   1.408 -  for (src_point.y = src_rect->min.y;
   1.409 -       src_point.y < src_rect->max.y;
   1.410 -       src_point.y++)
   1.411 +  if (tfn == TF_SRC)
   1.412      {
   1.413 -      dest_point.y = dest_min->y + src_point.y - src_rect->min.y;
   1.414 -
   1.415 -      for (src_point.x = src_rect->min.x;
   1.416 -	   src_point.x < src_rect->max.x;
   1.417 -	   src_point.x++)
   1.418 +      for (src_point.y = src_rect->min.y;
   1.419 +	   src_point.y < src_rect->max.y;
   1.420 +	   src_point.y++)
   1.421  	{
   1.422 -	  boolean a, b, c;
   1.423 +	  dest_point.y = dest_min->y + src_point.y - src_rect->min.y;
   1.424 +	  
   1.425 +	  for (src_point.x = src_rect->min.x;
   1.426 +	       src_point.x < src_rect->max.x;
   1.427 +	       src_point.x++)
   1.428 +	    {
   1.429 +	      boolean a;
   1.430  
   1.431 -	  dest_point.x = dest_min->x + src_point.x - src_rect->min.x;
   1.432 +	      dest_point.x = dest_min->x + src_point.x - src_rect->min.x;
   1.433  
   1.434 -	  a = get_pixel (src_bitmap, src_point);
   1.435 -	  b = get_pixel (dest_bitmap, dest_point);
   1.436 -	  c = (tfn & (1 << (a * 2 + b))) != 0;
   1.437 +	      a = get_pixel (src_bitmap, src_point);
   1.438 +	      set_pixel (dest_bitmap, dest_point, a);
   1.439 +	    }
   1.440 +	}
   1.441 +    }
   1.442 +  else
   1.443 +    {
   1.444 +      for (src_point.y = src_rect->min.y;
   1.445 +	   src_point.y < src_rect->max.y;
   1.446 +	   src_point.y++)
   1.447 +	{
   1.448 +	  dest_point.y = dest_min->y + src_point.y - src_rect->min.y;
   1.449 +	  
   1.450 +	  for (src_point.x = src_rect->min.x;
   1.451 +	       src_point.x < src_rect->max.x;
   1.452 +	       src_point.x++)
   1.453 +	    {
   1.454 +	      boolean a, b, c;
   1.455  
   1.456 -	  set_pixel (dest_bitmap, dest_point, c);
   1.457 +	      dest_point.x = dest_min->x + src_point.x - src_rect->min.x;
   1.458 +
   1.459 +	      a = get_pixel (src_bitmap, src_point);
   1.460 +	      b = get_pixel (dest_bitmap, dest_point);
   1.461 +	      c = (tfn & (1 << (a * 2 + b))) != 0;
   1.462 +
   1.463 +	      set_pixel (dest_bitmap, dest_point, c);
   1.464 +	    }
   1.465  	}
   1.466      }
   1.467    return (dest_bitmap);