]> git.sur5r.net Git - cc65/blob - src/sp65/geosbitmap.c
Merge remote-tracking branch 'upstream/master' into a5200
[cc65] / src / sp65 / geosbitmap.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                               geosbitmap.c                                */
4 /*                                                                           */
5 /*   GEOS compacted bitmap backend for the sp65 sprite and bitmap utility    */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 2012,      Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 /* common */
37 #include "attrib.h"
38 #include "print.h"
39 #include "xmalloc.h"
40
41 /* sp65 */
42 #include "attr.h"
43 #include "error.h"
44 #include "geosbitmap.h"
45
46
47
48 /*****************************************************************************/
49 /*                                   Data                                    */
50 /*****************************************************************************/
51
52
53
54 #define UNIQUE_MAX       91U            /* Maximum number of unique bytes */
55 #define REPEAT_MAX      127U            /* Maximum number of repeated bytes */
56
57
58
59 /* Structure used for RLE compression */
60 struct RLE {
61     unsigned char*      Buf;            /* Pointer to pixel buffer */
62     unsigned            Remaining;      /* Remaining bytes in buffer */
63     unsigned char       LastVal;        /* Last value seen */
64     unsigned            Count;          /* Number of occurrences for LastVal */
65     StrBuf*             D;              /* Buffer for compressed data */
66     StrBuf              UniqueData;     /* Temp buffer for unique data */
67 };
68
69
70
71 /*****************************************************************************/
72 /*                                   Code                                    */
73 /*****************************************************************************/
74
75
76
77 static void StoreByte (struct RLE* RLE)
78 /* Store a unique byte or a run of repeated bytes. If count is zero, the
79  * function will flush the internal buffers, so that all data is in RLE->D.
80  */
81 {
82
83
84     if (RLE->Count == 1 || RLE->Count == 2) {
85         /* A run of two identical bytes is treated as two unique bytes, since
86          * this will usually merge with the following run.
87          */
88         SB_AppendChar (&RLE->UniqueData, RLE->LastVal);
89         if (RLE->Count == 2) {
90             SB_AppendChar (&RLE->UniqueData, RLE->LastVal);
91         }
92
93         /* Clear the repeat counter */
94         RLE->Count = 0;
95
96     } else {
97
98         /* Run of repeated bytes. First flush the temp buffer for unique
99          * bytes.
100          */
101         const char* Buf = SB_GetConstBuf (&RLE->UniqueData);
102         unsigned Count  = SB_GetLen (&RLE->UniqueData);
103         while (Count) {
104
105             /* Determine the count for this sequence */
106             unsigned Chunk = Count;
107             if (Chunk > UNIQUE_MAX) {
108                 Chunk = UNIQUE_MAX;
109             }
110
111             /* Output the unique op */
112             SB_AppendChar (RLE->D, 0x80 + (unsigned char) Chunk);
113             SB_AppendBuf (RLE->D, Buf, Chunk);
114
115             /* Bump the counters */
116             Buf += Chunk;
117             Count -= Chunk;
118         }
119
120         /* Clear the unique byte buffer */
121         SB_Clear (&RLE->UniqueData);
122
123         /* Now output the repeat sequence */
124         while (RLE->Count) {
125
126             /* Determine the count for this sequence */
127             unsigned Chunk = RLE->Count;
128             if (Chunk > REPEAT_MAX) {
129                 Chunk = REPEAT_MAX;
130             }
131             /* Output the repeat op */
132             SB_AppendChar (RLE->D, (unsigned char) Chunk);
133             SB_AppendChar (RLE->D, RLE->LastVal);
134
135             /* Bump the counters */
136             RLE->Count -= Chunk;
137         }
138     }
139 }
140
141
142
143 StrBuf* GenGeosBitmap (const Bitmap* B, const Collection* A attribute ((unused)))
144 /* Generate binary output in GEOS compacted bitmap format for the bitmap B.
145  * The output is stored in a string buffer (which is actually a dynamic char
146  * array) and returned.
147  */
148 {
149     unsigned        LineWidth;
150     unsigned char*  Buf;
151     unsigned char*  BP;
152     StrBuf*         D;
153     unsigned        X, Y;
154     struct RLE      RLE;
155
156
157     /* Output the image properties */
158     Print (stdout, 1, "Image is %ux%u with %u colors%s\n",
159            GetBitmapWidth (B), GetBitmapHeight (B), GetBitmapColors (B),
160            BitmapIsIndexed (B)? " (indexed)" : "");
161
162     /* Check the bitmap properties */
163     if (!BitmapIsIndexed (B) || GetBitmapColors (B) > 2) {
164         Error ("Bitmaps converted to GEOS compacted bitmap must be "
165                "indexed with two colors");
166     }
167
168     /* Calculate the width of one line in bytes */
169     LineWidth = (GetBitmapWidth (B) + 7U) / 8U;
170
171     /* Allocate a buffer for the raw image */
172     Buf = xmalloc (LineWidth * GetBitmapHeight (B));
173
174     /* Convert the bitmap into a raw image */
175     BP = Buf;
176     for (Y = 0; Y < GetBitmapHeight (B); ++Y) {
177         for (X = 0; X < GetBitmapWidth (B); ) {
178             unsigned char V = 0;
179             int Bits = 8;
180             if ((unsigned)Bits > GetBitmapWidth (B) - X) {
181                 Bits = (GetBitmapWidth (B) - X);
182             }
183             while (--Bits >= 0) {
184                 V |= (GetPixel (B, X++, Y).Index & 0x01) << Bits;
185             }
186             *BP++ = V;
187         }
188     }
189
190     /* Create the output buffer and resize it to something reasonable */
191     D = NewStrBuf ();
192     SB_Realloc (D, 64);
193
194     /* Compact the image. We're currently using only REPEAT and UNIQUE opcodes.
195      * BIGCOUNT is rather difficult to apply.
196      */
197     RLE.Buf        = Buf;
198     RLE.Remaining  = LineWidth * GetBitmapHeight (B) - 1;
199     RLE.LastVal    = *RLE.Buf++;
200     RLE.Count      = 1;
201     RLE.D          = D;
202     RLE.UniqueData = EmptyStrBuf;
203     while (RLE.Remaining--) {
204         /* */
205         if (RLE.LastVal == *RLE.Buf) {
206             ++RLE.Buf;
207             ++RLE.Count;
208         } else {
209             StoreByte (&RLE);
210             RLE.LastVal = *RLE.Buf++;
211             RLE.Count = 1;
212         }
213     }
214
215     /* If something remains, store it */
216     if (RLE.Count) {
217         StoreByte (&RLE);
218     }
219
220     /* Flush the unique byte buffer */
221     StoreByte (&RLE);
222
223     /* Release the unique byte buffer */
224     SB_Done (&RLE.UniqueData);
225
226     /* Free the raw image buffer */
227     xfree (Buf);
228
229     /* Return the converted bitmap */
230     return D;
231 }