1 | /*****************************************************************************/ |
2 | /* */ |
3 | /* vic2sprite.c */ |
4 | /* */ |
5 | /* VICII sprite format 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 | |
40 | /* sp65 */ |
41 | #include "attr.h" |
42 | #include "error.h" |
43 | #include "vic2sprite.h" |
44 | |
45 | |
46 | |
47 | /*****************************************************************************/ |
48 | /* Data */ |
49 | /*****************************************************************************/ |
50 | |
51 | |
52 | |
53 | /* Sprite mode */ |
54 | enum Mode { |
55 | smAuto, |
56 | smHighRes, |
57 | smMultiColor |
58 | }; |
59 | |
60 | /* Size of a sprite */ |
61 | #define WIDTH_HR 24U |
62 | #define WIDTH_MC 12U |
63 | #define HEIGHT 21U |
64 | |
65 | |
66 | |
67 | /*****************************************************************************/ |
68 | /* Code */ |
69 | /*****************************************************************************/ |
70 | |
71 | |
72 | |
73 | static enum Mode GetMode (const Collection* A) |
74 | /* Return the sprite mode from the attribute collection A */ |
75 | { |
76 | /* Check for a mode attribute */ |
77 | const char* Mode = GetAttrVal (A, "mode" ); |
78 | if (Mode) { |
79 | if (strcmp (Mode, "highres" ) == 0) { |
80 | return smHighRes; |
81 | } else if (strcmp (Mode, "multicolor" ) == 0) { |
82 | return smMultiColor; |
83 | } else { |
84 | Error ("Invalid value for attribute 'mode'" ); |
85 | } |
86 | } |
87 | |
88 | return smAuto; |
89 | } |
90 | |
91 | |
92 | |
93 | StrBuf* GenVic2Sprite (const Bitmap* B, const Collection* A) |
94 | /* Generate binary output in VICII sprite format for the bitmap B. The output |
95 | ** is stored in a string buffer (which is actually a dynamic char array) and |
96 | ** returned. |
97 | */ |
98 | { |
99 | enum Mode M; |
100 | StrBuf* D; |
101 | unsigned X, Y; |
102 | |
103 | |
104 | /* Output the image properties */ |
105 | Print (stdout, 1, "Image is %ux%u with %u colors%s\n" , |
106 | GetBitmapWidth (B), GetBitmapHeight (B), GetBitmapColors (B), |
107 | BitmapIsIndexed (B)? " (indexed)" : "" ); |
108 | |
109 | /* Get the sprite mode */ |
110 | M = GetMode (A); |
111 | |
112 | /* Check the height of the bitmap */ |
113 | if (GetBitmapHeight (B) != HEIGHT) { |
114 | Error ("Invalid bitmap height (%u) for conversion to vic2 sprite" , |
115 | GetBitmapHeight (B)); |
116 | } |
117 | |
118 | /* If the mode wasn't given, determine it from the image properties */ |
119 | if (M == smAuto) { |
120 | switch (GetBitmapWidth (B)) { |
121 | case WIDTH_HR: |
122 | M = smHighRes; |
123 | break; |
124 | case WIDTH_MC: |
125 | M = smMultiColor; |
126 | break; |
127 | default: |
128 | Error ("Cannot determine mode from image properties" ); |
129 | } |
130 | } |
131 | |
132 | /* Now check if mode and the image properties match */ |
133 | if (M == smMultiColor) { |
134 | if (GetBitmapWidth (B) != WIDTH_MC || GetBitmapColors (B) > 4) { |
135 | Error ("Invalid image properties for multicolor sprite" ); |
136 | } |
137 | } else { |
138 | if (GetBitmapWidth (B) != WIDTH_HR || GetBitmapColors (B) > 2) { |
139 | Error ("Invalid image properties for highres sprite" ); |
140 | } |
141 | } |
142 | |
143 | /* Create the output buffer and resize it to the required size. */ |
144 | D = NewStrBuf (); |
145 | SB_Realloc (D, 63); |
146 | |
147 | /* Convert the image */ |
148 | for (Y = 0; Y < HEIGHT; ++Y) { |
149 | unsigned char V = 0; |
150 | if (M == smHighRes) { |
151 | for (X = 0; X < WIDTH_HR; ++X) { |
152 | |
153 | /* Fetch next bit into byte buffer */ |
154 | V = (V << 1) | (GetPixel (B, X, Y).Index & 0x01); |
155 | |
156 | /* Store full bytes into the output buffer */ |
157 | if ((X & 0x07) == 0x07) { |
158 | SB_AppendChar (D, V); |
159 | V = 0; |
160 | } |
161 | } |
162 | } else { |
163 | for (X = 0; X < WIDTH_MC; ++X) { |
164 | |
165 | /* Fetch next bit into byte buffer */ |
166 | V = (V << 2) | (GetPixel (B, X, Y).Index & 0x03); |
167 | |
168 | /* Store full bytes into the output buffer */ |
169 | if ((X & 0x03) == 0x03) { |
170 | SB_AppendChar (D, V); |
171 | V = 0; |
172 | } |
173 | } |
174 | } |
175 | } |
176 | |
177 | /* Return the converted bitmap */ |
178 | return D; |
179 | } |
180 | |