bitblt.c

Tue, 22 Jan 2002 09:42:42 +0000

author
eric
date
Tue, 22 Jan 2002 09:42:42 +0000
changeset 43
b80cb5a4282a
parent 42
9c85a4cd88a3
child 47
bfc6aaa089b0
permissions
-rw-r--r--

*** empty log message ***

     1 #include <stdio.h>
     2 #include <stdlib.h>
     3 #include <string.h>
     5 #include "type.h"
     6 #include "bitblt.h"
     9 #define DIV_ROUND_UP(count,pow2) (((count) - 1) / (pow2) + 1)
    12 static const u8 bit_reverse_byte [0x100] =
    13 {
    14   0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0,
    15   0x10, 0x90, 0x50, 0xd0, 0x30, 0xb0, 0x70, 0xf0,
    16   0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
    17   0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8,
    18   0x04, 0x84, 0x44, 0xc4, 0x24, 0xa4, 0x64, 0xe4,
    19   0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
    20   0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec,
    21   0x1c, 0x9c, 0x5c, 0xdc, 0x3c, 0xbc, 0x7c, 0xfc,
    22   0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
    23   0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2,
    24   0x0a, 0x8a, 0x4a, 0xca, 0x2a, 0xaa, 0x6a, 0xea,
    25   0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
    26   0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6,
    27   0x16, 0x96, 0x56, 0xd6, 0x36, 0xb6, 0x76, 0xf6,
    28   0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
    29   0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe,
    30   0x01, 0x81, 0x41, 0xc1, 0x21, 0xa1, 0x61, 0xe1,
    31   0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
    32   0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9,
    33   0x19, 0x99, 0x59, 0xd9, 0x39, 0xb9, 0x79, 0xf9,
    34   0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
    35   0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5,
    36   0x0d, 0x8d, 0x4d, 0xcd, 0x2d, 0xad, 0x6d, 0xed,
    37   0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
    38   0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3,
    39   0x13, 0x93, 0x53, 0xd3, 0x33, 0xb3, 0x73, 0xf3,
    40   0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
    41   0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb,
    42   0x07, 0x87, 0x47, 0xc7, 0x27, 0xa7, 0x67, 0xe7,
    43   0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
    44   0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef,
    45   0x1f, 0x9f, 0x5f, 0xdf, 0x3f, 0xbf, 0x7f, 0xff
    46 };
    48 static word_type bit_reverse_word (word_type d)
    49 {
    50   return (bit_reverse_byte [d >> 24] |
    51 	  (bit_reverse_byte [(d >> 16) & 0xff] << 8) |
    52 	  (bit_reverse_byte [(d >> 8) & 0xff] << 16) |
    53 	  (bit_reverse_byte [d & 0xff] << 24));
    54 }
    57 static u32 *temp_buffer;
    58 static u32 temp_buffer_size;
    60 static void realloc_temp_buffer (u32 size)
    61 {
    62   if (size <= temp_buffer_size)
    63     return;
    64   temp_buffer = realloc (temp_buffer, size);
    65   if (! temp_buffer)
    66     {
    67       fprintf (stderr, "realloc failed in bitblt library\n");
    68       exit (2);
    69     }
    70   temp_buffer_size = size;
    71 }
    74 static inline word_type pixel_mask (x)
    75 {
    76 #ifdef LSB_LEFT
    77   return (1 << x);
    78 #else
    79   return (1 << ((BITS_PER_WORD - 1) - x));
    80 #endif
    81 };
    83 Bitmap *create_bitmap (Rect *rect)
    84 {
    85   Bitmap *bitmap;
    86   u32 width = rect_width (rect);
    87   u32 height = rect_height (rect);
    89   if ((width <= 0) || (height <= 0))
    90     return (NULL);
    92   bitmap = calloc (1, sizeof (Bitmap));
    93   if (! bitmap)
    94     return (NULL);
    95   bitmap->rect = * rect;
    96   bitmap->row_words = DIV_ROUND_UP (width, BITS_PER_WORD);
    97   bitmap->bits = calloc (1, height * bitmap->row_words * sizeof (word_type));
    98   if (! bitmap->bits)
    99     {
   100       free (bitmap);
   101       return (NULL);
   102     }
   103   return (bitmap);
   104 }
   106 void free_bitmap (Bitmap *bitmap)
   107 {
   108   free (bitmap->bits);
   109   free (bitmap);
   110 }
   112 boolean get_pixel (Bitmap *bitmap, Point coord)
   113 {
   114   word_type *p;
   115   if ((coord.x < bitmap->rect.min.x) ||
   116       (coord.x >= bitmap->rect.max.x) ||
   117       (coord.y < bitmap->rect.min.y) ||
   118       (coord.y >= bitmap->rect.max.y))
   119     return (0);
   120   p = bitmap->bits +
   121     (coord.y - bitmap->rect.min.y) * bitmap->row_words +
   122     (coord.x - bitmap->rect.min.x) / BITS_PER_WORD;
   123   return ((*p & pixel_mask (coord.x & (BITS_PER_WORD - 1))) != 0);
   124 }
   126 void set_pixel (Bitmap *bitmap, Point coord, boolean value)
   127 {
   128   word_type *p;
   129   if ((coord.x < bitmap->rect.min.x) ||
   130       (coord.x >= bitmap->rect.max.x) ||
   131       (coord.y < bitmap->rect.min.y) ||
   132       (coord.y >= bitmap->rect.max.y))
   133     return;
   134   p = bitmap->bits +
   135     (coord.y - bitmap->rect.min.y) * bitmap->row_words +
   136     (coord.x - bitmap->rect.min.x) / BITS_PER_WORD;
   137   if (value)
   138     *p |= pixel_mask (coord.x & (BITS_PER_WORD - 1));
   139   else
   140     *p &= ~pixel_mask (coord.x & (BITS_PER_WORD - 1));
   141 }
   144 /* modifies rect1 to be the intersection of rect1 and rect2;
   145    returns true if intersection is non-null */
   146 static boolean clip_rect (Rect *rect1, Rect *rect2)
   147 {
   148   if (rect1->min.y > rect2->max.y)
   149     goto empty;
   150   if (rect1->min.y < rect2->min.y)
   151     {
   152       if (rect1->max.y < rect2->max.y)
   153 	goto empty;
   154       rect1->min.y = rect2->min.y;
   155     }
   156   if (rect1->max.y > rect2->max.y)
   157     rect1->max.y = rect2->max.y;
   159   if (rect1->min.x > rect2->max.x)
   160     goto empty;
   161   if (rect1->min.x < rect2->min.x)
   162     {
   163       if (rect1->max.x < rect2->max.x)
   164 	goto empty;
   165       rect1->min.x = rect2->min.x;
   166     }
   167   if (rect1->max.x > rect2->max.x)
   168     rect1->max.x = rect2->max.x;
   170  empty:
   171   rect1->min.x = rect1->min.y =
   172     rect1->max.x = rect1->max.y = 0;
   173   return (0);
   174 }
   177 #if 0
   178 static void blt_background (Bitmap *dest_bitmap,
   179 			    Rect *dest_rect)
   180 {
   181   s32 y;
   182   word_type *rp;
   184   /* This function requires a non-null dest rect */
   185   assert (dest_rect->min.x < dest_rect->max.x);
   186   assert (dest_rect->min.y < dest_rect->max.y);
   188   /* and that the rows of the dest rect lie entirely within the dest bitmap */
   189   assert (dest_rect->min.y >= dest_bitmap->rect->min.y);
   190   assert (dest_rect->max.y <= dest_bitmap->rect->max.y);
   192   /* clip the x axis of the dest_rect to the bounds of the dest bitmap */
   193   if (dest_rect->min.x < dest_bitmap->rect.min.x)
   194     dest_rect->min.x = dest_bitmap->rect.min.x;
   195   if (dest_rect->max.x > dest_bitmap->rect.max.x)
   196     dest_rect->max.x = dest_bitmap->rect.max.x;
   198   rp = ???;
   199   for (y = 0; y < rect_height (dest_rect); y++)
   200     {
   201   ???;
   202       rp += dest_bitmap->row_words;
   203     }
   204 }
   207 static void blt (Bitmap *src_bitmap,
   208 		 Rect *src_rect,
   209 		 Bitmap *dest_bitmap,
   210 		 Rect *dest_rect)
   211 {
   212   s32 y;
   213   word_type *rp;
   215   /* This function requires a non-null src rect */
   216   assert (dest_rect->min.x < dest_rect->max.x);
   217   assert (dest_rect->min.y < dest_rect->max.y);
   219   /* and a non-null dest rect */
   220   assert (dest_rect->min.x < dest_rect->max.x);
   221   assert (dest_rect->min.y < dest_rect->max.y);
   223   /* and that the widths and heights of the rects match */
   224   assert (rect_width (src_rect) == rect_width (dest_rect));
   225   assert (rect_height (src_rect) == rect_height (dest_rect));
   227   /* and that the rows of the src rect lie entirely within the src bitmap */
   228   assert (dest_rect->min.y >= dest_bitmap->rect->min.y);
   229   assert (dest_rect->max.y <= dest_bitmap->rect->max.y);
   231   /* and that the rows of the dest rect lie entirely within the dest bitmap */
   232   assert (dest_rect->min.y >= dest_bitmap->rect->min.y);
   233   assert (dest_rect->max.y <= dest_bitmap->rect->max.y);
   235   /* clip the x axis of the dest_rect to the bounds of the dest bitmap,
   236      and adjust the src_rect to match */
   237   if (dest_rect->min.x < dest_bitmap->rect.min.x)
   238     {
   239       src_rect->min.x += ???;
   240       dest_rect->min.x = dest_bitmap->rect.min.x;
   241     }
   242   if (dest_rect->max.x > dest_bitmap->rect.max.x)
   243     {
   244       dest_rect->max.x = dest_bitmap->rect.max.x;
   245     }
   247   rp = ???;
   248   for (y = 0; y < rect_height (dest_rect); y++)
   249     {
   250   ???;
   251       rp += dest_bitmap->row_words;
   252     }
   253 }
   256 Bitmap *bitblt (Bitmap *src_bitmap,
   257 		Rect   *src_rect,
   258 		Bitmap *dest_bitmap,
   259 		Point  *dest_min,
   260 		int tfn,
   261 		int background)
   262 {
   263   Rect sr, dr;     /* src and dest rects, clipped to visible portion of
   264 		      dest rect */
   265   u32 drw, drh;    /* dest rect width, height - gets adjusted */
   266   Point src_point, dest_point;
   268   {
   269     sr = * src_rect;
   271     u32 srw = rect_width (& sr);
   272     u32 srh = rect_height (& sr);
   274     if ((srw < 0) || (srh < 0))
   275       goto done;  /* the source rect is empty! */
   277     dr.min = * dest_min;
   278     dr.max.x = dr.min.x + srw;
   279     dr.max.y = dr.min.y + srh;
   280   }
   282   if (! dest_bitmap)
   283     {
   284       dest_bitmap = create_bitmap (& dr);
   285       if (! dest_bitmap)
   286 	return (NULL);
   287     }
   289   if ((dr.min.x >= dest_bitmap->rect.max.x) ||
   290       (dr.min.y >= dest_bitmap->rect.max.y))
   291     goto done;  /* the dest rect isn't even in the dest bitmap! */
   293   /* crop dest rect to dest bitmap */
   295   delta = dest_bitmap->rect.min.x - dr.min.x;
   296   if (delta > 0)
   297     {
   298       sr.min.x += delta;
   299       dr.min.x += delta;
   300     }
   302   delta = dest_bitmap->rect.min.y - dr.min.y;
   303   if (delta > 0)
   304     {
   305       sr.min.y += delta;
   306       dr.min.y += delta;
   307     }
   309   delta = dr.max.x - dest_bitmap->rect.max.x;
   310   if (delta > 0)
   311     {
   312       sr.max.x -= delta;
   313       dr.max.x -= delta;
   314     }
   316   delta = dr.max.y - dest_bitmap->rect.max.y;
   317   if (delta > 0)
   318     {
   319       sr.max.x -= delta;
   320       dr.max.x -= delta;
   321     }
   323   drw = rect_width (& dr);
   324   drh = rect_height (& dh);
   326   /* if the source rect min y is >= the source bitmap max y,
   327      we transfer background color to the entire dest rect */
   328   if (sr.min.y >= src->rect.max.y)
   329     {
   330       blt_background (dest_bitmap, & dr);
   331       goto done;
   332     }
   334   /* if the source rect min y is less than the source bitmap min y,
   335      we need to transfer some backgound color to the top part of the dest
   336      rect */
   337   if (sr.min.y < src->rect.min.y)
   338     {
   339       Rect dr2;
   340       uint32 bg_height;
   342       bg_height = src->rect.min.y - sr.min.y;
   343       if (bg_height > sh)
   344 	bg_height = sh;
   346       dr2 = dr;
   347       dr2.max.y = dr2.min.y + bg_height;
   349       blt_background (dest_bitmap, & dr2);
   351       /* now reduce the rect height by the number of lines of background
   352 	 color */
   353       sr.min.y += bg_height;
   354       dr.min.y += bg_height;
   355       sh -= bg_height;
   356       dh -= bg_height;
   358       if (sr.min.y == sr.max.y)
   359 	goto done;
   360     }
   362   /* now blt the available rows of the source rect */
   364   /* now transfer the background color to any remaining rows of the
   365      dest rect */
   366   if (??? )
   367     {
   368       blt_background (dest_bitmap, & dr);
   369     }
   371  done:
   372   return (dest_bitmap);
   373 }
   374 #else
   375 Bitmap *bitblt (Bitmap *src_bitmap,
   376 		Rect   *src_rect,
   377 		Bitmap *dest_bitmap,
   378 		Point  *dest_min,
   379 		int tfn,
   380 		int background)
   381 {
   382   Point src_point, dest_point;
   384   if (! dest_bitmap)
   385     {
   386       Rect dest_rect = {{ 0, 0 }, { dest_min->x + rect_width (src_rect),
   387 				    dest_min->y + rect_height (src_rect) }};
   388       dest_bitmap = create_bitmap (& dest_rect);
   389       if (! dest_bitmap)
   390 	return (NULL);
   391     }
   393   for (src_point.y = src_rect->min.y;
   394        src_point.y < src_rect->max.y;
   395        src_point.y++)
   396     {
   397       dest_point.y = dest_min->y + src_point.y - src_rect->min.y;
   399       for (src_point.x = src_rect->min.x;
   400 	   src_point.x < src_rect->max.x;
   401 	   src_point.x++)
   402 	{
   403 	  boolean a, b, c;
   405 	  dest_point.x = dest_min->x + src_point.x - src_rect->min.x;
   407 	  a = get_pixel (src_bitmap, src_point);
   408 	  b = get_pixel (dest_bitmap, dest_point);
   409 	  c = (tfn & (1 << (a * 2 + b))) != 0;
   411 	  set_pixel (dest_bitmap, dest_point, c);
   412 	}
   413     }
   414   return (dest_bitmap);
   415 }
   416 #endif
   419 /* in-place transformations */
   420 void flip_h (Bitmap *src)
   421 {
   422   word_type *rp;  /* row pointer */
   423   word_type *p1;  /* work src ptr */
   424   word_type *p2;  /* work dest ptr */
   425   s32 y;
   426   int shift1, shift2;
   428   realloc_temp_buffer ((src->row_words + 1) * sizeof (word_type));
   430   rp = src->bits;
   431   if ((rect_width (& src->rect) & 7) == 0)
   432     {
   433       for (y = src->rect.min.y; y < src->rect.max.y; y++)
   434 	{
   435 	  memcpy (temp_buffer, rp, src->row_words * sizeof (word_type));
   436 	  p1 = temp_buffer + src->row_words;
   437 	  p2 = rp;
   439 	  while (p1 >= temp_buffer)
   440 	    *(p2++) = bit_reverse_word (*(p1--));
   442 	  rp += src->row_words;
   443 	}
   444       return;
   445     }
   447   temp_buffer [0] = 0;
   448   shift1 = rect_width (& src->rect) & (BITS_PER_WORD - 1);
   449   shift2 = BITS_PER_WORD - shift1;
   451   for (y = src->rect.min.y; y < src->rect.max.y; y++)
   452     {
   453       word_type d1, d2;
   455       memcpy (temp_buffer + 1, rp, src->row_words * sizeof (word_type));
   456       p1 = temp_buffer + src->row_words;
   457       p2 = rp;
   459       d2 = *(p1--);
   461       while (p1 >= temp_buffer)
   462 	{
   463 	  d1 = *(p1--);
   464 	  *(p2++) = bit_reverse_word ((d1 << shift1) | (d2 >> shift2));
   465 	  d2 = d1;
   466 	}      
   468       rp += src->row_words;
   469     }
   470 }
   472 void flip_v (Bitmap *src)
   473 {
   474   word_type *p1, *p2;
   476   realloc_temp_buffer (src->row_words * sizeof (word_type));
   478   p1 = src->bits;
   479   p2 = src->bits + src->row_words * (rect_height (& src->rect) - 1);
   480   while (p1 < p2)
   481     {
   482       memcpy (temp_buffer, p1, src->row_words * sizeof (word_type));
   483       memcpy (p1, p2, src->row_words * sizeof (word_type));
   484       memcpy (p2, temp_buffer, src->row_words * sizeof (word_type));
   485       p1 += src->row_words;
   486       p2 -= src->row_words;
   487     }
   488 }
   490 void rot_180 (Bitmap *src)  /* combination of flip_h and flip_v */
   491 {
   492   flip_h (src);
   493   flip_v (src);
   494 }
   496 /* "in-place" transformations - will allocate new memory and free old */
   497 void transpose (Bitmap *src)
   498 {
   499   u32 new_row_words = DIV_ROUND_UP (rect_height (& src->rect), 32);
   500   word_type *new_bits;
   502   new_bits = calloc (1, new_row_words * rect_width (& src->rect) * sizeof (word_type));
   504   /* $$$ more code needed here */
   505 }
   507 void rot_90 (Bitmap *src)   /* transpose + flip_h */
   508 {
   509   transpose (src);
   510   flip_h (src);
   511 }
   513 void rot_270 (Bitmap *src)  /* transpose + flip_v */
   514 {
   515   transpose (src);
   516   flip_v (src);
   517 }