comparison src/lib64gfx.c @ 812:1e5cf1144f36

Move library source under src/ subdirectory.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 16 May 2014 03:22:39 +0300
parents lib64gfx.c@aebc2f8b2c2d
children c8beac5313c3
comparison
equal deleted inserted replaced
811:aebc2f8b2c2d 812:1e5cf1144f36
1 /*
2 * Functions for reading and converting various restricted
3 * C64/etc and/or indexed/paletted graphics formats.
4 * Programmed and designed by Matti 'ccr' Hamalainen
5 * (C) Copyright 2012 Tecnic Software productions (TNSP)
6 *
7 * Please read file 'COPYING' for information on license and distribution.
8 */
9 #include "lib64gfx.h"
10
11 #define BUF_SIZE_INITIAL (16*1024)
12 #define BUF_SIZE_GROW (4*1024)
13
14
15 char * dmC64GetImageTypeString(char *buf, const size_t len, const int type)
16 {
17 snprintf(buf, len,
18 "%s%s%s",
19 (type & D64_FMT_FLI) ? "FLI " : "",
20 (type & D64_FMT_MC) ? "MCol" : "HiRes",
21 (type & D64_FMT_ILACE) ? " Ilace" : ""
22 );
23
24 return buf;
25 }
26
27
28 // Based on Pepto's palette, stolen from VICE
29 DMColor dmC64Palette[C64_NCOLORS] =
30 {
31 { 0x00, 0x00, 0x00, 0xff },
32 { 0xFF, 0xFF, 0xFF, 0xff },
33 { 0x68, 0x37, 0x2B, 0xff },
34 { 0x70, 0xA4, 0xB2, 0xff },
35 { 0x6F, 0x3D, 0x86, 0xff },
36 { 0x58, 0x8D, 0x43, 0xff },
37 { 0x35, 0x28, 0x79, 0xff },
38 { 0xB8, 0xC7, 0x6F, 0xff },
39 { 0x6F, 0x4F, 0x25, 0xff },
40 { 0x43, 0x39, 0x00, 0xff },
41 { 0x9A, 0x67, 0x59, 0xff },
42 { 0x44, 0x44, 0x44, 0xff },
43 { 0x6C, 0x6C, 0x6C, 0xff },
44 { 0x9A, 0xD2, 0x84, 0xff },
45 { 0x6C, 0x5E, 0xB5, 0xff },
46 { 0x95, 0x95, 0x95, 0xff },
47 };
48
49
50 const size_t dmC64DefaultSizes[DT_LAST] =
51 {
52 C64_SCR_COLOR_SIZE,
53 C64_SCR_BITMAP_SIZE,
54 C64_SCR_SCREEN_SIZE,
55 1,
56 C64_SCR_EXTRADATA,
57 };
58
59
60 #define DM_GET_ADDR_LO(addr) ((addr) & 0xff)
61 #define DM_GET_ADDR_HI(addr) (((addr) >> 8) & 0xff)
62
63
64 static BOOL dmCompareAddr16(const Uint8 *buf, const size_t offs, const Uint16 addr)
65 {
66 return buf[offs] == DM_GET_ADDR_LO(addr) &&
67 buf[offs + 1] == DM_GET_ADDR_HI(addr);
68 }
69
70
71 int dmC64ConvertCSData(DMImage *img,
72 int xoffs, int yoffs, const Uint8 *buf,
73 int width, int height, BOOL multicolor, int *colors)
74 {
75 int yc, widthpx = width * 8;
76 Uint8 *dp;
77
78 if (img == NULL)
79 return DMERR_NULLPTR;
80
81 if (xoffs < 0 || yoffs < 0 ||
82 xoffs > img->width - widthpx ||
83 yoffs > img->height - height)
84 return DMERR_INVALID_ARGS;
85
86 dp = img->data + (yoffs * img->pitch) + xoffs;
87
88 if (multicolor)
89 {
90 for (yc = 0; yc < height; yc++)
91 {
92 const int offs = yc * width;
93 int xc;
94 Uint8 *d = dp;
95
96 for (xc = 0; xc < widthpx / 2; xc++)
97 {
98 const int b = buf[offs + (xc / 4)];
99 const int v = 6 - ((xc * 2) & 6);
100 const Uint8 c = colors[(b >> v) & 3];
101
102 *d++ = c;
103 *d++ = c;
104 }
105
106 dp += img->pitch;
107 }
108 }
109 else
110 {
111 for (yc = 0; yc < height; yc++)
112 {
113 const int offs = yc * width;
114 int xc;
115 Uint8 *d = dp;
116
117 for (xc = 0; xc < widthpx; xc++)
118 {
119 const int b = buf[offs + (xc / 8)];
120 const int v = 7 - (xc & 7);
121 const Uint8 c = colors[(b >> v) & 1];
122
123 *d++ = c;
124 }
125
126 dp += img->pitch;
127 }
128 }
129
130 return DMERR_OK;
131 }
132
133
134 static int fmtProbeDrazPaint20Packed(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
135 {
136 const char *ident = (const char *) buf + 2;
137
138 if (len > 22 &&
139 dmCompareAddr16(buf, 0, fmt->addr) &&
140 strncmp(ident, "DRAZPAINT ", 10) == 0 &&
141 ident[11] == '.' && (
142 (ident[10] == '1' && ident[12] == '4') ||
143 (ident[10] == '2' && ident[12] == '0')
144 ))
145 return DM_PROBE_SCORE_MAX;
146
147 return DM_PROBE_SCORE_FALSE;
148 }
149
150
151 static int dmDecodeGenericRLE(Uint8 **mem, Uint8 **pdstEnd, const Uint8 *src, const Uint8 *srcEnd, const Uint8 rleMarker)
152 {
153 Uint8 *dst, *dstEnd;
154
155 if ((*mem = dmMalloc(C64_RAM_SIZE)) == NULL)
156 return DMERR_MALLOC;
157
158 dst = *mem;
159 dstEnd = *mem + C64_RAM_SIZE;
160
161 while (src <= srcEnd && dst <= dstEnd)
162 {
163 int c = *src++;
164 if (c == rleMarker && src + 2 <= srcEnd)
165 {
166 int cnt = *src++;
167 c = *src++;
168 while (cnt-- && dst <= dstEnd)
169 *dst++ = c;
170 }
171 else
172 *dst++ = c;
173 }
174
175 *pdstEnd = dst;
176
177 return DMERR_OK;
178 }
179
180
181 static int fmtDecodeDrazPaintPacked(DMC64Image *img, const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
182 {
183 int res;
184 Uint8 *mem = NULL, *dstEnd;
185
186 if ((res = dmDecodeGenericRLE(&mem, &dstEnd, buf + 0x0e, buf + len, *(buf + 0x0d))) != DMERR_OK)
187 goto out;
188
189 res = dmC64DecodeGenericBMP(img, mem, dstEnd - mem + 1, fmt);
190
191 out:
192 dmFree(mem);
193 return res;
194 }
195
196
197 static int fmtProbeDrazLace10Packed(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
198 {
199 const char *ident = (const char *) buf + 2;
200 if (len > 22 &&
201 dmCompareAddr16(buf, 0, fmt->addr) &&
202 strncmp(ident, "DRAZLACE! 1.0", 13) == 0)
203 return DM_PROBE_SCORE_MAX;
204
205 return DM_PROBE_SCORE_FALSE;
206 }
207
208
209 static BOOL fmtDrazLaceSetLaceType(DMC64Image *img, const struct _DMC64EncDecOp *op, const Uint8 *buf, const size_t len)
210 {
211 (void) len;
212
213 img->laceType = buf[op->offs] ? D64_ILACE_RES : D64_ILACE_COLOR;
214 img->laceBank1 = img->laceBank2 = 0;
215 return TRUE;
216 }
217
218
219 #define AMICA_DM_PROBE_SIZE 2048
220 static int fmtProbeAmicaPaintPacked(const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
221 {
222 size_t i, n;
223 if (len < AMICA_DM_PROBE_SIZE || !dmCompareAddr16(buf, 0, fmt->addr))
224 return DM_PROBE_SCORE_FALSE;
225
226 // Interpaint Hi-Res gives a false positive
227 if (len == 9002)
228 return DM_PROBE_SCORE_FALSE;
229
230 for (n = 0, i = 2; i < len; i++)
231 if (buf[i] == 0xC2) n++;
232
233 if (n > 50)
234 return DM_PROBE_SCORE_GOOD;
235 if (n > 25)
236 return DM_PROBE_SCORE_AVG;
237 if (n > 10)
238 return DM_PROBE_SCORE_MAYBE;
239 return DM_PROBE_SCORE_FALSE;
240 }
241
242
243 static int fmtDecodeAmicaPaintPacked(DMC64Image *img, const Uint8 *buf, const size_t len, const DMC64ImageFormat *fmt)
244 {
245 int res;
246 Uint8 *mem = NULL, *dstEnd;
247
248 if ((res = dmDecodeGenericRLE(&mem, &dstEnd, buf, buf + len, 0xC2)) != DMERR_OK)
249 goto out;
250
251 res = dmC64DecodeGenericBMP(img, mem, dstEnd - mem + 1, fmt);
252
253 out:
254 dmFree(mem);
255 return res;
256 }
257
258
259 static BOOL fmtTruePaintSetLaceType(DMC64Image *img, const struct _DMC64EncDecOp *op, const Uint8 *buf, const size_t len)
260 {
261 (void) op;
262 (void) buf;
263 (void) len;
264 img->laceType = D64_ILACE_RES;
265 img->laceBank1 = 0;
266 img->laceBank2 = 1;
267 return TRUE;
268 }
269
270
271 static BOOL fmtSetFLIType(DMC64Image *img, const struct _DMC64EncDecOp *op, const Uint8 *buf, const size_t len)
272 {
273 (void) buf;
274 (void) len;
275 img->fliType = op->bank;
276 return TRUE;
277 }
278
279
280 const DMC64ImageFormat dmC64ImageFormats[] =
281 {
282 {
283 D64_FMT_MC, "d2p", "DrazPaint 2.0 (packed)", 0x5800, -1,
284 fmtProbeDrazPaint20Packed, fmtDecodeDrazPaintPacked,
285 NULL, NULL, NULL,
286 4,
287 {
288 { DT_COLOR_RAM, 0x0000, 0, 0, NULL, NULL },
289 { DT_BITMAP, 0x0800, 0, 0, NULL, NULL },
290 { DT_SCREEN_RAM, 0x0400, 0, 0, NULL, NULL },
291 { DT_BGCOLOR, 0x2740, 0, 0, NULL, NULL },
292 }
293 },
294
295 {
296 D64_FMT_MC | D64_FMT_ILACE, "dlp", "DrazLace 1.0 (packed)", 0x5800, -1,
297 fmtProbeDrazLace10Packed, fmtDecodeDrazPaintPacked,
298 NULL, NULL, NULL,
299 6,
300 {
301 { DT_COLOR_RAM, 0x0000, 0, 0, NULL, NULL },
302 { DT_BITMAP, 0x0800, 0, 0, NULL, NULL },
303 { DT_SCREEN_RAM, 0x0400, 0, 0, NULL, NULL },
304 { DT_BGCOLOR, 0x2740, 0, 0, NULL, NULL },
305 { DT_BITMAP, 0x2800, 1, 0, NULL, NULL },
306 { DT_DEC_FUNCTION, 0x2742, 0, 1, fmtDrazLaceSetLaceType, NULL },
307 }
308 },
309
310 {
311 D64_FMT_MC, "drp", "DrazPaint (unpacked)", 0x5800, 10051,
312 NULL, NULL,
313 NULL, NULL, NULL,
314 4,
315 {
316 { DT_COLOR_RAM, 0x0000, 0, 0, NULL, NULL },
317 { DT_BITMAP, 0x0800, 0, 0, NULL, NULL },
318 { DT_SCREEN_RAM, 0x0400, 0, 0, NULL, NULL },
319 { DT_BGCOLOR, 0x2740, 0, 0, NULL, NULL },
320 }
321 },
322
323 {
324 D64_FMT_MC | D64_FMT_ILACE, "drl", "DrazLace 1.0 (unpacked)", 0x5800, 18242,
325 NULL, NULL,
326 NULL, NULL, NULL,
327 6,
328 {
329 { DT_COLOR_RAM, 0x0000, 0, 0, NULL, NULL },
330 { DT_BITMAP, 0x0800, 0, 0, NULL, NULL },
331 { DT_SCREEN_RAM, 0x0400, 0, 0, NULL, NULL },
332 { DT_BGCOLOR, 0x2740, 0, 0, NULL, NULL },
333 { DT_BITMAP, 0x2800, 1, 0, NULL, NULL },
334 { DT_DEC_FUNCTION, 0x2742, 0, 1, fmtDrazLaceSetLaceType, NULL },
335 }
336 },
337
338 {
339 D64_FMT_MC | D64_FMT_ILACE, "mci", "Truepaint (unpacked)", 0x9c00, 19434,
340 NULL, NULL,
341 NULL, NULL, NULL,
342 6,
343 {
344 { DT_SCREEN_RAM, 0x0000, 0, 0, NULL, NULL },
345 { DT_BGCOLOR, 0x03e8, 0, 0, NULL, NULL },
346 { DT_BITMAP, 0x0400, 0, 0, NULL, NULL },
347 { DT_BITMAP, 0x2400, 1, 0, NULL, NULL },
348 { DT_SCREEN_RAM, 0x4400, 1, 0, NULL, NULL },
349 { DT_COLOR_RAM, 0x4800, 0, 0, NULL, NULL },
350 { DT_DEC_FUNCTION, 0x0000, 0, 0, fmtTruePaintSetLaceType, NULL },
351 }
352 },
353
354 {
355 D64_FMT_MC, "kla", "Koala Paint (unpacked)", 0x6000, 10003,
356 NULL, NULL,
357 NULL, NULL, NULL,
358 4,
359 {
360 { DT_BITMAP, 0x0000, 0, 0, NULL, NULL },
361 { DT_SCREEN_RAM, 0x1f40, 0, 0, NULL, NULL },
362 { DT_COLOR_RAM, 0x2328, 0, 0, NULL, NULL },
363 { DT_BGCOLOR, 0x2710, 0, 0, NULL, NULL },
364 }
365 },
366
367 {
368 D64_FMT_MC, "ocp", "Advanced Art Studio (unpacked)", 0x2000, 10018,
369 NULL, NULL,
370 NULL, NULL, NULL,
371 4,
372 {
373 { DT_BITMAP, 0x0000, 0, 0, NULL, NULL },
374 { DT_SCREEN_RAM, 0x1f40, 0, 0, NULL, NULL },
375 { DT_COLOR_RAM, 0x2338, 0, 0, NULL, NULL },
376 { DT_BGCOLOR, 0x2329, 0, 0, NULL, NULL },
377 }
378 },
379
380 {
381 D64_FMT_MC, "ami", "Amica Paint (packed)", 0x4000, -1,
382 fmtProbeAmicaPaintPacked, fmtDecodeAmicaPaintPacked,
383 NULL, NULL, NULL,
384 4,
385 {
386 { DT_COLOR_RAM, 0x2328, 0, 0, NULL, NULL },
387 { DT_BITMAP, 0x0000, 0, 0, NULL, NULL },
388 { DT_SCREEN_RAM, 0x1f40, 0, 0, NULL, NULL },
389 { DT_BGCOLOR, 0x2710, 0, 0, NULL, NULL },
390 }
391 },
392
393 {
394 D64_FMT_MC, "rpm", "Run Paint (unpacked)", 0x6000, 10006,
395 NULL, NULL,
396 NULL, NULL, NULL,
397 4,
398 {
399 { DT_COLOR_RAM, 0x2328, 0, 0, NULL, NULL },
400 { DT_BITMAP, 0x0000, 0, 0, NULL, NULL },
401 { DT_SCREEN_RAM, 0x1f40, 0, 0, NULL, NULL },
402 { DT_BGCOLOR, 0x2710, 0, 0, NULL, NULL },
403 }
404 },
405
406 {
407 D64_FMT_HIRES, "art", "Art Studio (unpacked)", 0x2000, 9009,
408 NULL, NULL,
409 NULL, NULL, NULL,
410 2,
411 {
412 { DT_BITMAP, 0x0000, 0, 0, NULL, NULL },
413 { DT_SCREEN_RAM, 0x1f40, 0, 0, NULL, NULL },
414 }
415 },
416
417 {
418 D64_FMT_HIRES, "iph", "Interpaint (unpacked)", 0x4000, 9002,
419 NULL, NULL,
420 NULL, NULL, NULL,
421 2,
422 {
423 { DT_BITMAP, 0x0000, 0, 0, NULL, NULL },
424 { DT_SCREEN_RAM, 0x1f40, 0, 0, NULL, NULL },
425 }
426 },
427
428 {
429 D64_FMT_HIRES, "dd", "Doodle (unpacked)", 0x1c00, 9218,
430 NULL, NULL,
431 NULL, NULL, NULL,
432 2,
433 {
434 { DT_SCREEN_RAM, 0x0000, 0, 0, NULL, NULL },
435 { DT_BITMAP, 0x0400, 0, 0, NULL, NULL },
436 }
437 },
438
439 {
440 D64_FMT_MC | D64_FMT_FLI, "bml", "Blackmail FLI (unpacked)", 0x3b00, 17474,
441 NULL, NULL,
442 NULL, NULL, NULL,
443 11,
444 {
445 { DT_COLOR_RAM, 0x0100, 0, 0, NULL, NULL },
446
447 { DT_SCREEN_RAM, 0x0500, 0, 0, NULL, NULL },
448 { DT_SCREEN_RAM, 0x0900, 1, 0, NULL, NULL },
449 { DT_SCREEN_RAM, 0x0d00, 2, 0, NULL, NULL },
450 { DT_SCREEN_RAM, 0x1100, 3, 0, NULL, NULL },
451
452 { DT_SCREEN_RAM, 0x1500, 4, 0, NULL, NULL },
453 { DT_SCREEN_RAM, 0x1900, 5, 0, NULL, NULL },
454 { DT_SCREEN_RAM, 0x1d00, 6, 0, NULL, NULL },
455 { DT_SCREEN_RAM, 0x2100, 7, 0, NULL, NULL },
456
457 { DT_BITMAP, 0x2500, 0, 0, NULL, NULL },
458 { DT_DEC_FUNCTION, 0x0000, D64_FLI_8BANK, 0, fmtSetFLIType, NULL },
459 }
460 },
461
462 {
463 D64_FMT_MC | D64_FMT_FLI, "fli", "FLI Designer (unpacked)", 0x3c00, 17409,
464 NULL, NULL,
465 NULL, NULL, NULL,
466 11,
467 {
468 { DT_COLOR_RAM, 0x0000, 0, 0, NULL, NULL },
469 { DT_SCREEN_RAM, 0x0400, 0, 0, NULL, NULL },
470 { DT_SCREEN_RAM, 0x0800, 1, 0, NULL, NULL },
471 { DT_SCREEN_RAM, 0x0c00, 2, 0, NULL, NULL },
472 { DT_SCREEN_RAM, 0x1000, 3, 0, NULL, NULL },
473 { DT_SCREEN_RAM, 0x1400, 4, 0, NULL, NULL },
474 { DT_SCREEN_RAM, 0x1800, 5, 0, NULL, NULL },
475 { DT_SCREEN_RAM, 0x1c00, 6, 0, NULL, NULL },
476 { DT_SCREEN_RAM, 0x2000, 7, 0, NULL, NULL },
477 { DT_BITMAP, 0x2400, 0, 0, NULL, NULL },
478 { DT_DEC_FUNCTION, 0x0000, D64_FLI_8BANK, 0, fmtSetFLIType, NULL },
479 }
480 },
481
482 };
483
484 const int ndmC64ImageFormats = sizeof(dmC64ImageFormats) / sizeof(dmC64ImageFormats[0]);
485
486
487 // Perform probing of the given data buffer, trying to determine
488 // if it contains a supported "C64" image format. Returns the
489 // "probe score", see libgfx.h for list of values. If a match
490 // is found, pointer to format description is set to *pfmt.
491 int dmC64ProbeBMP(const Uint8 *buf, const size_t len, const DMC64ImageFormat **pfmt)
492 {
493 int i, scoreMax = DM_PROBE_SCORE_FALSE, scoreIndex = -1;
494
495 for (i = 0; i < ndmC64ImageFormats; i++)
496 {
497 const DMC64ImageFormat *fmt = &dmC64ImageFormats[i];
498 int score = DM_PROBE_SCORE_FALSE;
499 if (fmt->probe == NULL && fmt->size > 0 && fmt->addr > 0)
500 {
501 // Generic probe just checks matching size and load address
502 if (len == fmt->size && dmCompareAddr16(buf, 0, fmt->addr))
503 score = DM_PROBE_SCORE_GOOD;
504 }
505 else
506 score = fmt->probe(buf, len, fmt);
507
508 if (score > scoreMax)
509 {
510 scoreMax = score;
511 scoreIndex = i;
512 }
513 }
514
515 if (scoreIndex >= 0)
516 {
517 *pfmt = &dmC64ImageFormats[scoreIndex];
518 return scoreMax;
519 }
520 else
521 return DM_PROBE_SCORE_FALSE;
522 }
523
524
525 static int dmC64SanityCheckEncDecOp(const int i, const DMC64EncDecOp *op)
526 {
527 if (op->bank < 0 || op->bank >= C64_SCR_MAX_BANK)
528 {
529 dmError("Invalid bank %d definition in generic encode/decode operator %d @ #%d.\n",
530 op->bank, op->type, i);
531 return DMERR_INTERNAL;
532 }
533
534 if (op->type < 0 || op->type >= DT_LAST)
535 {
536 dmError("Invalid encode/decode operator type %d @ #%d.\n",
537 op->type, i);
538 return DMERR_INTERNAL;
539 }
540
541 return DMERR_OK;
542 }
543
544
545 int dmC64DecodeGenericBMP(DMC64Image *img, const Uint8 *buf,
546 const size_t len, const DMC64ImageFormat *fmt)
547 {
548 int i;
549
550 if (buf == NULL || img == NULL || fmt == NULL)
551 return DMERR_NULLPTR;
552
553 // Clear the image structure
554 memset(img, 0, sizeof(*img));
555 img->type = fmt->type;
556
557 // Perform decoding
558 for (i = 0; i < fmt->nencdecOps; i++)
559 {
560 const DMC64EncDecOp *op = &fmt->encdecOps[i];
561 const Uint8 *src;
562 size_t size;
563 int res;
564
565 // Check operation validity
566 if ((res = dmC64SanityCheckEncDecOp(i, op)) != DMERR_OK)
567 return res;
568
569 // Check size
570 size = (op->size == 0) ? dmC64DefaultSizes[op->type] : op->size;
571
572 // Do we need to reallocate some more space?
573 if (op->offs + size > len)
574 {
575 dmError("Decode out of bounds, op #%d type=%d, offs=%d ($%04x), "
576 "bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
577 i, op->type, op->offs, op->offs, op->bank, size, size, len, len);
578 return DMERR_INVALID_DATA;
579 }
580
581 src = buf + op->offs;
582
583 // Perform operation
584 switch (op->type)
585 {
586 case DT_COLOR_RAM: memcpy(img->color[op->bank], src, size); break;
587 case DT_BITMAP: memcpy(img->bitmap[op->bank], src, size); break;
588 case DT_SCREEN_RAM: memcpy(img->screen[op->bank], src, size); break;
589 case DT_BGCOLOR: img->bgcolor = *src; break;
590 case DT_EXTRADATA: memcpy(img->extradata, src, size); break;
591 case DT_DEC_FUNCTION:
592 if (op->decfunction == NULL)
593 {
594 dmError("Decode op is a function, but function ptr is NULL: "
595 "op #%d, offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
596 i, op->offs, op->offs, op->bank, size, size, len, len);
597 return DMERR_INTERNAL;
598 }
599 if (!op->decfunction(img, op, buf, len))
600 {
601 dmError("Decode op custom function failed: op #%d, "
602 "offs=%d ($%04x), bank=%d, size=%d ($%04x) @ %d ($%04x)\n",
603 i, op->offs, op->offs, op->bank, size, size, len, len);
604 return DMERR_INTERNAL;
605 }
606 break;
607 }
608 }
609
610 return DMERR_OK;
611 }
612
613
614 int dmC64EncodeGenericBMP(Uint8 **pbuf, size_t *plen, const DMC64Image *img, const DMC64ImageFormat *fmt)
615 {
616 int i, res = DMERR_OK;
617 Uint8 *buf;
618 size_t allocated;
619
620 if (pbuf == NULL || plen == NULL || img == NULL || fmt == NULL)
621 return DMERR_NULLPTR;
622
623 // Allocate the output buffer
624 *plen = 0;
625 if (fmt->size > 0)
626 *plen = allocated = fmt->size;
627 else
628 allocated = 8 * 1024;
629
630 if ((buf = dmMalloc(allocated)) == NULL)
631 {
632 dmError("Could not allocate %d bytes of memory for C64 image encoding buffer.\n",
633 allocated);
634 res = DMERR_MALLOC;
635 goto error;
636 }
637
638 // Perform encoding
639 for (i = 0; i < fmt->nencdecOps; i++)
640 {
641 const DMC64EncDecOp *op = &fmt->encdecOps[i];
642 Uint8 *dst = 2 + buf + op->offs;
643 size_t size;
644
645 // Check operation validity
646 if ((res = dmC64SanityCheckEncDecOp(i, op)) != DMERR_OK)
647 goto error;
648
649 // Check size
650 size = (op->size == 0) ? dmC64DefaultSizes[op->type] : op->size;
651
652 // Do we need to reallocate some more space?
653 if (2 + op->offs + size > allocated)
654 {
655 if ((buf = dmRealloc(buf, allocated)) == NULL)
656 {
657 size_t diff = allocated - (op->offs + size + 2),
658 grow = (diff / (BUF_SIZE_GROW - 1)) * BUF_SIZE_GROW;
659 allocated = allocated + grow;
660 dmError("Could not re-allocate %d bytes of memory for C64 image encoding buffer.\n",
661 allocated);
662 res = DMERR_MALLOC;
663 goto error;
664 }
665 }
666
667 if (fmt->size == 0 && op->offs + size + 2 > *plen)
668 *plen = op->offs + size + 2;
669
670 // Perform operation
671 switch (op->type)
672 {
673 case DT_COLOR_RAM: memcpy(dst, img->color[op->bank], size); break;
674 case DT_BITMAP: memcpy(dst, img->bitmap[op->bank], size); break;
675 case DT_SCREEN_RAM: memcpy(dst, img->screen[op->bank], size); break;
676 case DT_BGCOLOR: *dst = img->bgcolor; break;
677 case DT_EXTRADATA: memcpy(dst, img->extradata, size); break;
678 case DT_ENC_FUNCTION:
679 break;
680 }
681 }
682
683 buf[0] = DM_GET_ADDR_LO(fmt->addr);
684 buf[1] = DM_GET_ADDR_HI(fmt->addr);
685
686 *pbuf = buf;
687 return DMERR_OK;
688
689 error:
690 dmFree(buf);
691 *pbuf = NULL;
692 *plen = 0;
693 return res;
694 }
695
696
697 static inline Uint8 dmC64GetMCColor(const DMC64Image *img, const int bits, const int cbank, const int vbank, const int scroffs)
698 {
699 switch (bits)
700 {
701 case 0: return img->bgcolor; break;
702 case 1: return img->screen[vbank][scroffs] >> 4; break;
703 case 2: return img->screen[vbank][scroffs] & 15; break;
704 default: return img->color[cbank][scroffs] & 15; break;
705 }
706 }
707
708
709 // Convert a generic "C64" format bitmap in DMC64Image struct to
710 // a indexed/paletted bitmap image.
711 int dmC64ConvertGenericBMP2Image(DMImage *dst, const DMC64Image *src, const BOOL doubleMC)
712 {
713 Uint8 *dp = dst->data;
714 int yc;
715
716 // Sanity check arguments
717 if (dst == NULL || src == NULL)
718 return DMERR_NULLPTR;
719
720 if (dst->width < 8)
721 return DMERR_INVALID_ARGS;
722
723 // Perform generic conversion
724 for (yc = 0; yc < dst->height; yc++)
725 {
726 Uint8 *d = dp;
727 const int y = yc / 8, yb = yc & 7;
728 const int scroffsy = y * C64_SCR_CH_WIDTH;
729 const int bmoffsy = y * C64_SCR_WIDTH;
730 int xc;
731
732 if ((src->type & D64_FMT_MC) == D64_FMT_HIRES)
733 {
734 // Hi-res bitmap
735 for (xc = 0; xc < dst->width; xc++)
736 {
737 const int x = xc / 8;
738 const int scroffs = scroffsy + x;
739 const int bmoffs = bmoffsy + (x * 8) + yb;
740 const int v = 7 - (xc & 7);
741
742 if ((src->bitmap[0][bmoffs] >> v) & 1)
743 *d++ = src->screen[0][scroffs] >> 4;
744 else
745 *d++ = src->screen[0][scroffs] & 15;
746 }
747 }
748 else
749 {
750 // Multicolor variants
751 const int
752 wdivisor = doubleMC ? 2 : 1,
753 divisor = doubleMC ? 4 : 8;
754
755 for (xc = 0; xc < dst->width / wdivisor; xc++)
756 {
757 const int x = xc / divisor;
758 const int scroffs = scroffsy + x;
759 const int bmoffs = bmoffsy + (x * 8) + yb;
760 const int v = 6 - ((xc * 2) & 6);
761 Uint8 c;
762
763 if (src->type & D64_FMT_FLI)
764 {
765 int vbank = 0;
766 switch (src->fliType)
767 {
768 case D64_FLI_2BANK:
769 vbank = yb / 4;
770 break;
771 case D64_FLI_4BANK:
772 vbank = yb / 2;
773 break;
774 case D64_FLI_8BANK:
775 vbank = yb;
776 break;
777 }
778 c = dmC64GetMCColor(src, (src->bitmap[0][bmoffs] >> v) & 3, 0, vbank, scroffs);
779 *d++ = c;
780 if (doubleMC)
781 *d++ = c;
782 }
783 else
784 if (src->type & D64_FMT_ILACE)
785 {
786 *d++ = dmC64GetMCColor(src, (src->bitmap[0][bmoffs] >> v) & 3, 0, src->laceBank1, scroffs);
787 if (doubleMC)
788 *d++ = dmC64GetMCColor(src, (src->bitmap[1][bmoffs] >> v) & 3, 0, src->laceBank2, scroffs);
789 }
790 else
791 {
792 c = dmC64GetMCColor(src, (src->bitmap[0][bmoffs] >> v) & 3, 0, 0, scroffs);
793 *d++ = c;
794 if (doubleMC)
795 *d++ = c;
796 }
797 }
798 }
799 dp += dst->pitch;
800 }
801
802 return DMERR_OK;
803 }
804
805
806 int dmC64ConvertBMP2Image(DMImage **pdst, const DMC64Image *src, const DMC64ImageFormat *fmt, const BOOL doubleMC)
807 {
808 int width, res;
809 DMImage *dst;
810
811 if (pdst == NULL || src == NULL)
812 return DMERR_NULLPTR;
813
814 // Calculate output image width
815 if ((src->type & D64_FMT_MC) && !doubleMC)
816 width = C64_SCR_WIDTH / 2;
817 else
818 width = C64_SCR_WIDTH;
819
820 // Allocate image structure
821 if ((*pdst = dst = dmImageAlloc(width, C64_SCR_HEIGHT)) == NULL)
822 return DMERR_MALLOC;
823
824 // Set palette
825 dst->pal = (DMColor *) &dmC64Palette;
826 dst->ncolors = C64_NCOLORS;
827 dst->constpal = TRUE;
828
829 // Convert
830 if (fmt->convertFrom != NULL)
831 res = fmt->convertFrom(dst, src, doubleMC);
832 else
833 res = dmC64ConvertGenericBMP2Image(dst, src, doubleMC);
834
835 return res;
836 }
837
838
839 int dmC64DecodeBMP(DMC64Image *img, const Uint8 *buf, const size_t len,
840 const size_t probeOffs, const size_t loadOffs,
841 const DMC64ImageFormat **fmt, const DMC64ImageFormat *forced)
842 {
843 // Check for forced format
844 if (forced != NULL)
845 *fmt = forced;
846 else
847 {
848 // Nope, perform a generic probe
849 if (probeOffs >= len)
850 return -200;
851
852 if (dmC64ProbeBMP(buf + probeOffs, len - probeOffs, fmt) == DM_PROBE_SCORE_FALSE)
853 return -201;
854 }
855
856 if (loadOffs >= len)
857 return -203;
858
859 // Decode the bitmap to memory layout
860 if ((*fmt)->decode != NULL)
861 return (*fmt)->decode(img, buf + loadOffs, len - loadOffs, *fmt);
862 else
863 return dmC64DecodeGenericBMP(img, buf + loadOffs, len - loadOffs, *fmt);
864 }