rev |
line source |
nuclear@0
|
1 #include <stdio.h>
|
nuclear@0
|
2 #include <stdlib.h>
|
nuclear@1
|
3 #include <string.h>
|
nuclear@2
|
4 #include <errno.h>
|
nuclear@1
|
5 #include <arpa/inet.h>
|
nuclear@0
|
6 #include "image.h"
|
nuclear@0
|
7
|
nuclear@1
|
8 /* hammer dump format (input)
|
nuclear@1
|
9 * byte order: little endian
|
nuclear@1
|
10 *
|
nuclear@1
|
11 * 4 bytes: palette changes per scanline (cps)
|
nuclear@1
|
12 * 256 * cps * 2 bytes: [ idx | r | g | b ]
|
nuclear@1
|
13 * 320 * 256 bytes: linear HAM pixels
|
nuclear@1
|
14 */
|
nuclear@1
|
15
|
nuclear@1
|
16 /* interleaved ham format (output)
|
nuclear@1
|
17 * byte order: big endian
|
nuclear@1
|
18 *
|
nuclear@1
|
19 * 4 bytes: magic: "HAAM"
|
nuclear@1
|
20 * 2 bytes: width
|
nuclear@1
|
21 * 2 bytes: height
|
nuclear@1
|
22 * 1 byte: number of bitplanes
|
nuclear@1
|
23 * 1 byte: padding
|
nuclear@1
|
24 * 2 bytes: number of palette change descriptors (nchg)
|
nuclear@1
|
25 * 16 * 2 bytes: initial palette [ x | r | g | b ]
|
nuclear@1
|
26 * nchg * 4 bytes: [ scanline ] [ idx | r | g | b ]
|
nuclear@1
|
27 * width * height / 8 * bitplanes bytes: pixels interleaved scanlines
|
nuclear@1
|
28 * [ row0 bpl0 ] ... [ row0 bplN ] [ row1 bpl0 ] ... [ row1 bplN ] ...
|
nuclear@1
|
29 */
|
nuclear@1
|
30
|
nuclear@0
|
31 struct ham_image *load_hammer(const char *fname);
|
nuclear@0
|
32 int save_ham(struct ham_image *img, const char *fname);
|
nuclear@1
|
33 void free_image(struct ham_image *img);
|
nuclear@0
|
34
|
nuclear@0
|
35 int main(int argc, char **argv)
|
nuclear@0
|
36 {
|
nuclear@1
|
37 int i;
|
nuclear@1
|
38 struct ham_image *img;
|
nuclear@1
|
39 char *name, *dot;
|
nuclear@1
|
40
|
nuclear@1
|
41 for(i=1; i<argc; i++) {
|
nuclear@1
|
42 if(!(img = load_hammer(argv[i]))) {
|
nuclear@1
|
43 fprintf(stderr, "failed to load hammer dump: %s\n", argv[i]);
|
nuclear@1
|
44 continue;
|
nuclear@1
|
45 }
|
nuclear@1
|
46
|
nuclear@1
|
47 if(!(name = malloc(strlen(argv[i] + 8)))) {
|
nuclear@1
|
48 perror("failed to allocate output name buffer");
|
nuclear@1
|
49 abort();
|
nuclear@1
|
50 }
|
nuclear@1
|
51 strcpy(name, argv[i]);
|
nuclear@1
|
52
|
nuclear@1
|
53 if((dot = strrchr(name, '.'))) {
|
nuclear@1
|
54 *dot = 0;
|
nuclear@1
|
55 }
|
nuclear@1
|
56 strcat(name, ".ham");
|
nuclear@1
|
57
|
nuclear@2
|
58 if(save_ham(img, name) == -1) {
|
nuclear@1
|
59 fprintf(stderr, "failed to save ham image: %s\n", name);
|
nuclear@1
|
60 free_image(img);
|
nuclear@1
|
61 continue;
|
nuclear@1
|
62 }
|
nuclear@1
|
63 }
|
nuclear@1
|
64 return 0;
|
nuclear@0
|
65 }
|
nuclear@1
|
66
|
nuclear@2
|
67 static uint16_t nops(uint16_t x) { return x; }
|
nuclear@2
|
68 static uint16_t swaps(uint16_t x) { return (x >> 8) | (x << 8); }
|
nuclear@2
|
69
|
nuclear@1
|
70 struct ham_image *load_hammer(const char *fname)
|
nuclear@1
|
71 {
|
nuclear@2
|
72 int i, x, y, pstart, numpix = 320 * 256;
|
nuclear@2
|
73 FILE *fp = 0;
|
nuclear@2
|
74 uint32_t cps, npalent;
|
nuclear@2
|
75 struct ham_image *img = 0;
|
nuclear@2
|
76 struct palchange *tail = 0;
|
nuclear@2
|
77 unsigned char *inpixels = 0;
|
nuclear@2
|
78 unsigned char *srcptr, *destptr;
|
nuclear@2
|
79 uint16_t endtest = 0xaabb;
|
nuclear@2
|
80 uint16_t (*letohs)(uint16_t);
|
nuclear@2
|
81
|
nuclear@2
|
82 letohs = (*(unsigned char*)&endtest == 0xaa) ? swaps : nops;
|
nuclear@2
|
83
|
nuclear@2
|
84 if(!(fp = fopen(fname, "rb"))) {
|
nuclear@2
|
85 fprintf(stderr, "failed to open %s: %s\n", fname, strerror(errno));
|
nuclear@2
|
86 return 0;
|
nuclear@2
|
87 }
|
nuclear@2
|
88
|
nuclear@2
|
89 if(!(img = malloc(sizeof *img))) {
|
nuclear@2
|
90 perror("failed to allocate image");
|
nuclear@2
|
91 goto err;
|
nuclear@2
|
92 }
|
nuclear@2
|
93 img->width = 320;
|
nuclear@2
|
94 img->height = 256;
|
nuclear@2
|
95 img->nbitplanes = 6;
|
nuclear@2
|
96 img->chglist = 0;
|
nuclear@2
|
97
|
nuclear@2
|
98 if(!(img->pixels = malloc(img->width * img->height / 8 * img->nbitplanes))) {
|
nuclear@2
|
99 perror("failed to allocate pixels");
|
nuclear@2
|
100 goto err;
|
nuclear@2
|
101 }
|
nuclear@2
|
102
|
nuclear@2
|
103 if(fread(&cps, 4, 1, fp) < 1) goto err;
|
nuclear@2
|
104 cps = letohs(cps);
|
nuclear@2
|
105 if(cps <= 0 || cps > 16) {
|
nuclear@2
|
106 fprintf(stderr, "invalid changes-per-line value: %u\n", (unsigned int)cps);
|
nuclear@2
|
107 goto err;
|
nuclear@2
|
108 }
|
nuclear@2
|
109
|
nuclear@2
|
110 /* read palette changes and palette */
|
nuclear@2
|
111
|
nuclear@2
|
112 npalent = cps * 256;
|
nuclear@2
|
113 pstart = npalent - 16;
|
nuclear@2
|
114
|
nuclear@2
|
115 for(i=0; i<npalent; i++) {
|
nuclear@2
|
116 uint16_t palent;
|
nuclear@2
|
117 struct palchange *chg;
|
nuclear@2
|
118
|
nuclear@2
|
119 if(fread(&palent, 2, 1, fp) < 1) {
|
nuclear@2
|
120 perror("unexpected end of file");
|
nuclear@2
|
121 goto err;
|
nuclear@2
|
122 }
|
nuclear@2
|
123 palent = letohs(palent);
|
nuclear@2
|
124
|
nuclear@2
|
125 if(!(chg = malloc(sizeof *chg))) {
|
nuclear@2
|
126 perror("failed to allocate palchange node");
|
nuclear@2
|
127 goto err;
|
nuclear@2
|
128 }
|
nuclear@2
|
129 chg->line = i / cps;
|
nuclear@2
|
130 chg->entry = palent;
|
nuclear@2
|
131 chg->next = 0;
|
nuclear@2
|
132 if(tail) {
|
nuclear@2
|
133 tail->next = chg;
|
nuclear@2
|
134 tail = chg;
|
nuclear@2
|
135 } else {
|
nuclear@2
|
136 img->chglist = tail = chg;
|
nuclear@2
|
137 }
|
nuclear@2
|
138
|
nuclear@2
|
139 if(i >= pstart) {
|
nuclear@2
|
140 img->palette[i - pstart] = palent & 0xfff;
|
nuclear@2
|
141 }
|
nuclear@2
|
142 }
|
nuclear@2
|
143
|
nuclear@2
|
144 /* read pixels */
|
nuclear@2
|
145 if(!(inpixels = malloc(numpix))) {
|
nuclear@2
|
146 perror("failed to allocate pixel buffer");
|
nuclear@2
|
147 goto err;
|
nuclear@2
|
148 }
|
nuclear@2
|
149 if(fread(inpixels, 1, numpix, fp) < numpix) {
|
nuclear@2
|
150 perror("unexpected end of file while reading pixels");
|
nuclear@2
|
151 goto err;
|
nuclear@2
|
152 }
|
nuclear@2
|
153
|
nuclear@2
|
154 for(i=0; i<img->nbitplanes; i++) {
|
nuclear@2
|
155 srcptr = inpixels;
|
nuclear@2
|
156 destptr = img->pixels + i * img->width / 8;
|
nuclear@2
|
157 for(y=0; y<img->height; y++) {
|
nuclear@2
|
158 unsigned char pixval = 0;
|
nuclear@2
|
159 for(x=0; x<img->width; x++) {
|
nuclear@2
|
160 pixval = (pixval << 1) | ((*srcptr++ >> i) & 1);
|
nuclear@2
|
161 if((x & 7) == 7) {
|
nuclear@2
|
162 *destptr++ = pixval;
|
nuclear@2
|
163 pixval = 0;
|
nuclear@2
|
164 }
|
nuclear@2
|
165 }
|
nuclear@2
|
166 destptr += img->width / 8 * (img->nbitplanes - 1);
|
nuclear@2
|
167 }
|
nuclear@2
|
168 }
|
nuclear@2
|
169
|
nuclear@3
|
170 free(inpixels);
|
nuclear@3
|
171 fclose(fp);
|
nuclear@2
|
172 return img;
|
nuclear@2
|
173
|
nuclear@2
|
174 err:
|
nuclear@2
|
175 free(inpixels);
|
nuclear@2
|
176 if(img) {
|
nuclear@2
|
177 while(img->chglist) {
|
nuclear@2
|
178 void *tmp = img->chglist;
|
nuclear@2
|
179 img->chglist = img->chglist->next;
|
nuclear@2
|
180 free(tmp);
|
nuclear@2
|
181 }
|
nuclear@2
|
182 free(img->pixels);
|
nuclear@2
|
183 free(img);
|
nuclear@2
|
184 }
|
nuclear@2
|
185 if(fp) fclose(fp);
|
nuclear@2
|
186 return 0;
|
nuclear@1
|
187 }
|
nuclear@1
|
188
|
nuclear@1
|
189 int save_ham(struct ham_image *img, const char *fname)
|
nuclear@1
|
190 {
|
nuclear@2
|
191 int i, num;
|
nuclear@2
|
192 unsigned char c, *pptr;
|
nuclear@1
|
193 uint16_t val;
|
nuclear@1
|
194 FILE *fp;
|
nuclear@2
|
195 struct palchange *chg;
|
nuclear@1
|
196
|
nuclear@1
|
197 if(!(fp = fopen(fname, "wb"))) {
|
nuclear@1
|
198 fprintf(stderr, "failed to open %s for writing: %s\n", fname, strerror(errno));
|
nuclear@1
|
199 return -1;
|
nuclear@1
|
200 }
|
nuclear@1
|
201 fprintf(fp, "HAAM");
|
nuclear@1
|
202
|
nuclear@1
|
203 val = htons(img->width);
|
nuclear@2
|
204 fwrite(&val, 2, 1, fp);
|
nuclear@1
|
205 val = htons(img->height);
|
nuclear@2
|
206 fwrite(&val, 2, 1, fp);
|
nuclear@2
|
207 c = img->nbitplanes;
|
nuclear@2
|
208 fwrite(&c, 1, 1, fp);
|
nuclear@2
|
209 fwrite(&c, 1, 1, fp); /* padding */
|
nuclear@2
|
210
|
nuclear@2
|
211 num = 0;
|
nuclear@2
|
212 chg = img->chglist;
|
nuclear@2
|
213 while(chg) {
|
nuclear@2
|
214 ++num;
|
nuclear@2
|
215 chg = chg->next;
|
nuclear@2
|
216 }
|
nuclear@2
|
217 num = htons(num);
|
nuclear@2
|
218 fwrite(&num, 2, 1, fp);
|
nuclear@2
|
219
|
nuclear@3
|
220 for(i=0; i<16; i++) {
|
nuclear@3
|
221 val = htons(img->palette[i]);
|
nuclear@3
|
222 fwrite(&val, 2, 1, fp);
|
nuclear@3
|
223 }
|
nuclear@3
|
224
|
nuclear@2
|
225 chg = img->chglist;
|
nuclear@2
|
226 while(chg) {
|
nuclear@2
|
227 val = htons(chg->line);
|
nuclear@2
|
228 fwrite(&val, 2, 1, fp);
|
nuclear@2
|
229 val = htons(chg->entry);
|
nuclear@2
|
230 fwrite(&val, 2, 1, fp);
|
nuclear@2
|
231 chg = chg->next;
|
nuclear@2
|
232 }
|
nuclear@2
|
233
|
nuclear@2
|
234 pptr = img->pixels;
|
nuclear@2
|
235 num = img->width * img->height / 8 * img->nbitplanes;
|
nuclear@2
|
236 for(i=0; i<num; i++) {
|
nuclear@2
|
237 val = htons(*pptr);
|
nuclear@2
|
238 ++pptr;
|
nuclear@2
|
239
|
nuclear@2
|
240 fwrite(&val, 2, 1, fp);
|
nuclear@2
|
241 }
|
nuclear@2
|
242 fclose(fp);
|
nuclear@2
|
243 return 0;
|
nuclear@1
|
244 }
|
nuclear@1
|
245
|
nuclear@1
|
246 void free_image(struct ham_image *img)
|
nuclear@1
|
247 {
|
nuclear@1
|
248 if(img) {
|
nuclear@1
|
249 free(img->pixels);
|
nuclear@1
|
250 while(img->chglist) {
|
nuclear@1
|
251 void *tmp = img->chglist;
|
nuclear@1
|
252 img->chglist = img->chglist->next;
|
nuclear@1
|
253 free(tmp);
|
nuclear@1
|
254 }
|
nuclear@1
|
255 free(img);
|
nuclear@1
|
256 }
|
nuclear@1
|
257 }
|