1 /*         ______   ___    ___
2  *        /\  _  \ /\_ \  /\_ \
3  *        \ \ \L\ \\//\ \ \//\ \      __     __   _ __   ___
4  *         \ \  __ \ \ \ \  \ \ \   /'__`\ /'_ `\/\`'__\/ __`\
5  *          \ \ \/\ \ \_\ \_ \_\ \_/\  __//\ \L\ \ \ \//\ \L\ \
6  *           \ \_\ \_\/\____\/\____\ \____\ \____ \ \_\\ \____/
7  *            \/_/\/_/\/____/\/____/\/____/\/___L\ \/_/ \/___/
8  *                                           /\____/
9  *                                           \_/__/
10  *
11  *      RLE sprite generation routines.
12  *
13  *      By Shawn Hargreaves.
14  *
15  *      See readme.txt for copyright information.
16  */
17 
18 
19 #include <string.h>
20 
21 #include "allegro.h"
22 #include "allegro/internal/aintern.h"
23 
24 
25 
26 /* get_rle_sprite:
27  *  Creates a run length encoded sprite based on the specified bitmap.
28  *  The returned sprite is likely to be a lot smaller than the original
29  *  bitmap, and can be drawn to the screen with draw_rle_sprite().
30  *
31  *  The compression is done individually for each line of the image.
32  *  Format is a series of command bytes, 1-127 marks a run of that many
33  *  solid pixels, negative numbers mark a gap of -n pixels, and 0 marks
34  *  the end of a line (since zero can't occur anywhere else in the data,
35  *  this can be used to find the start of a specified line when clipping).
36  *  For truecolor RLE sprites, the data and command bytes are both in the
37  *  same format (16 or 32 bits, 24 bpp data is padded to 32 bit aligment),
38  *  and the mask color (bright pink) is used as the EOL marker.
39  */
get_rle_sprite(BITMAP * bitmap)40 RLE_SPRITE *get_rle_sprite(BITMAP *bitmap)
41 {
42    int depth;
43    RLE_SPRITE *s;
44    int x, y;
45    int run;
46    int pix;
47    int c;
48    ASSERT(bitmap);
49 
50    depth = bitmap_color_depth(bitmap);
51 
52    #define WRITE_TO_SPRITE8(x) {                                             \
53       _grow_scratch_mem(c+1);                                                \
54       p = (signed char *)_scratch_mem;                                       \
55       p[c] = x;                                                              \
56       c++;                                                                   \
57    }
58 
59    #define WRITE_TO_SPRITE16(x) {                                            \
60       _grow_scratch_mem((c+1)*sizeof(int16_t));                              \
61       p = (int16_t *)_scratch_mem;                                           \
62       p[c] = x;                                                              \
63       c++;                                                                   \
64    }
65 
66    #define WRITE_TO_SPRITE32(x) {                                            \
67       _grow_scratch_mem((c+1)*sizeof(int32_t));                              \
68       p = (int32_t *)_scratch_mem;                                           \
69       p[c] = x;                                                              \
70       c++;                                                                   \
71    }
72 
73    /* helper for building an RLE run */
74    #define DO_RLE(bits)                                                      \
75    {                                                                         \
76       for (y=0; y<bitmap->h; y++) {                                          \
77 	 run = -1;                                                           \
78 	 for (x=0; x<bitmap->w; x++) {                                       \
79 	    pix = getpixel(bitmap, x, y) & 0xFFFFFF;                         \
80 	    if (pix != bitmap->vtable->mask_color) {                         \
81 	       if ((run >= 0) && (p[run] > 0) && (p[run] < 127))             \
82 		  p[run]++;                                                  \
83 	       else {                                                        \
84 		  run = c;                                                   \
85 		  WRITE_TO_SPRITE##bits(1);                                  \
86 	       }                                                             \
87 	       WRITE_TO_SPRITE##bits(getpixel(bitmap, x, y));                \
88 	    }                                                                \
89 	    else {                                                           \
90 	       if ((run >= 0) && (p[run] < 0) && (p[run] > -128))            \
91 		  p[run]--;                                                  \
92 	       else {                                                        \
93 		  run = c;                                                   \
94 		  WRITE_TO_SPRITE##bits(-1);                                 \
95 	       }                                                             \
96 	    }                                                                \
97 	 }                                                                   \
98 	 WRITE_TO_SPRITE##bits(bitmap->vtable->mask_color);                  \
99       }                                                                      \
100    }
101 
102    c = 0;
103 
104    switch (depth) {
105 
106       #ifdef ALLEGRO_COLOR8
107 
108 	 case 8:
109 	    {
110 	       signed char *p = (signed char *)_scratch_mem;
111 	       DO_RLE(8);
112 	    }
113 	    break;
114 
115       #endif
116 
117       #ifdef ALLEGRO_COLOR16
118 
119 	 case 15:
120 	 case 16:
121 	    {
122 	       signed short *p = (signed short *)_scratch_mem;
123 	       DO_RLE(16);
124 	       c *= sizeof(short);
125 	    }
126 	    break;
127 
128       #endif
129 
130       #if (defined ALLEGRO_COLOR24) || (defined ALLEGRO_COLOR32)
131 
132 	 case 24:
133 	 case 32:
134 	    {
135 	       int32_t *p = (int32_t *)_scratch_mem;
136 	       DO_RLE(32);
137 	       c *= sizeof(int32_t);
138 	    }
139 	    break;
140 
141       #endif
142    }
143 
144    s = _AL_MALLOC(sizeof(RLE_SPRITE) + c);
145 
146    if (s) {
147       s->w = bitmap->w;
148       s->h = bitmap->h;
149       s->color_depth = depth;
150       s->size = c;
151       memcpy(s->dat, _scratch_mem, c);
152    }
153 
154    return s;
155 }
156 
157 
158 
159 /* destroy_rle_sprite:
160  *  Destroys an RLE sprite structure returned by get_rle_sprite().
161  */
destroy_rle_sprite(RLE_SPRITE * sprite)162 void destroy_rle_sprite(RLE_SPRITE *sprite)
163 {
164    if (sprite)
165       _AL_FREE(sprite);
166 }
167 
168 
169