comparison tools/lib64gfx.c @ 931:2270d7f3af77

Refactor the DMC64Image handling to be more dynamic, and start work on allowing non 320/160 x 200 formats, and charmode based formats. There is still work to be done, and some problems to sort out.
author Matti Hamalainen <ccr@tnsp.org>
date Wed, 25 Feb 2015 19:37:59 +0200
parents db495f421242
children 6320bf08e302
comparison
equal deleted inserted replaced
930:efbad8817b79 931:2270d7f3af77
8 */ 8 */
9 #include "lib64gfx.h" 9 #include "lib64gfx.h"
10 10
11 #define BUF_SIZE_INITIAL (16*1024) 11 #define BUF_SIZE_INITIAL (16*1024)
12 #define BUF_SIZE_GROW (4*1024) 12 #define BUF_SIZE_GROW (4*1024)
13
14
15 DMC64Image * dmC64ImageAlloc(int width, int height, int ch_width, int ch_height)
16 {
17 int i;
18 DMC64Image *img = dmMalloc0(sizeof(DMC64Image));
19
20 if (img == NULL)
21 return NULL;
22
23 img->width = width;
24 img->height = height;
25 img->ch_width = ch_width;
26 img->ch_height = ch_height;
27
28 for (i = 0; i < C64_SCR_MAX_BANK; i++)
29 {
30 if ((img->color[i] = dmMalloc0(ch_width * ch_height)) == NULL)
31 goto err;
32
33 if ((img->bitmap[i] = dmMalloc0(ch_width * ch_height * 8)) == NULL)
34 goto err;
35
36 if ((img->screen[i] = dmMalloc0(ch_width * ch_height)) == NULL)
37 goto err;
38
39 if ((img->charmem[i] = dmMalloc0(C64_MAX_CHARS * C64_CHR_SIZE)) == NULL)
40 goto err;
41 }
42
43 return img;
44
45 err:
46 dmC64ImageFree(img);
47 return NULL;
48 }
49
50
51 void dmC64ImageFree(DMC64Image *img)
52 {
53 if (img != NULL)
54 {
55 int i;
56 for (i = 0; i < C64_SCR_MAX_BANK; i++)
57 {
58 dmFree(img->color[i]);
59 dmFree(img->bitmap[i]);
60 dmFree(img->screen[i]);
61 }
62 memset(img, 0, sizeof(DMC64Image));
63 dmFree(img);
64 }
65 }
13 66
14 67
15 char * dmC64GetImageTypeString(char *buf, const size_t len, const int type) 68 char * dmC64GetImageTypeString(char *buf, const size_t len, const int type)
16 { 69 {
17 *buf = 0; 70 *buf = 0;
517 { DT_COLOR_RAM, 0x2400, 0, 0, NULL, NULL }, 570 { DT_COLOR_RAM, 0x2400, 0, 0, NULL, NULL },
518 { DT_COLOR_SET, 0x00 , 0, DC_BGCOL, NULL, NULL }, 571 { DT_COLOR_SET, 0x00 , 0, DC_BGCOL, NULL, NULL },
519 } 572 }
520 }, 573 },
521 574
522 #define XX2_WIDTH_CH 40 575 #define XX2_WIDTH_CH 40
523 #define XX2_HEIGHT_CH 10 576 #define XX2_HEIGHT_CH 10
524 577 #define XX2_SIZE (XX2_WIDTH_CH * XX2_HEIGHT_CH)
525 #define XX2_SIZE (XX2_WIDTH_CH * XX2_HEIGHT_CH) 578 #define XX2_BSIZE (XX2_SIZE * 8)
526 #define XX2_BSIZE (XX2_SIZE * 8) 579
527
528 #if 0
529 { 580 {
530 D64_FMT_MC, "xx2", "Unknown $2000 format (unpacked)", 0x2000, 4002, 581 D64_FMT_MC, "xx2", "Unknown $2000 format (unpacked)", 0x2000, 4002,
531 XX2_WIDTH_CH * 4, XX2_HEIGHT_CH * 8, 582 XX2_WIDTH_CH * 4, XX2_HEIGHT_CH * 8,
532 XX2_WIDTH_CH , XX2_HEIGHT_CH, 583 XX2_WIDTH_CH , XX2_HEIGHT_CH,
533 NULL, NULL, 584 NULL, NULL,
540 591
541 { DT_COLOR_SET, 11 , 0, DC_BGCOL, NULL, NULL }, 592 { DT_COLOR_SET, 11 , 0, DC_BGCOL, NULL, NULL },
542 } 593 }
543 }, 594 },
544 595
545 #else 596 #if 0
546 597 {
547 { 598 D64_FMT_MC | D64_FMT_CHAR, "xx3", "??? (unpacked)", 0x2000, 0,
548 D64_FMT_MC | D64_FMT_CHAR, "xx2", "Unknown $2000 char format (unpacked)", 0x2000, 4002, 599 XX3_WIDTH_CH * 4, XX3_HEIGHT_CH * 8,
549 XX2_WIDTH_CH * 4, XX2_HEIGHT_CH * 8, 600 XX3_WIDTH_CH , XX3_HEIGHT_CH,
550 XX2_WIDTH_CH , XX2_HEIGHT_CH,
551 NULL, NULL, 601 NULL, NULL,
552 NULL, NULL, NULL, 602 NULL, NULL, NULL,
553 4, 603 4,
554 { 604 {
555 { DT_CHAR_DATA, 0x0000, 0, XX2_BSIZE, NULL, NULL }, 605 { DT_CHAR_DATA, 0x0000, 0, XX3_BSIZE, NULL, NULL },
556 { DT_COLOR_RAM, XX2_BSIZE + XX2_SIZE , 0, XX2_SIZE, NULL, NULL }, 606 { DT_COLOR_RAM, XX3_BSIZE + XX3_SIZE , 0, XX3_SIZE, NULL, NULL },
557 607
558 { DT_CHAR_CONFIG, D64_CHCFG_LINEAR, 0, XX2_SIZE, NULL, NULL }, 608 { DT_CHAR_CONFIG, D64_CHCFG_LINEAR, 0, XX3_SIZE, NULL, NULL },
559 { DT_COLOR_SET, 1 , 0, DC_BGCOL, NULL, NULL }, 609 { DT_COLOR_SET, 1 , 0, DC_BGCOL, NULL, NULL },
560 { DT_COLOR_SET, 3 , 0, DC_D022, NULL, NULL }, 610 { DT_COLOR_SET, 3 , 0, DC_D022, NULL, NULL },
561 { DT_COLOR_SET, 4 , 0, DC_D023, NULL, NULL }, 611 { DT_COLOR_SET, 4 , 0, DC_D023, NULL, NULL },
562 } 612 }
563 }, 613 },
623 673
624 return DMERR_OK; 674 return DMERR_OK;
625 } 675 }
626 676
627 677
628 static int dmC64GetOpSize(const DMC64EncDecOp *op, const DMC64ImageFormat *fmt) 678 static BOOL dmC64GetOpSize(const DMC64EncDecOp *op, const DMC64ImageFormat *fmt, size_t *size)
629 { 679 {
680 BOOL check;
681 switch (op->type)
682 {
683 case DT_SCREEN_RAM:
684 case DT_COLOR_RAM:
685 *size = fmt->ch_height * fmt->ch_width;
686 check = TRUE;
687 break;
688
689 case DT_BITMAP:
690 *size = fmt->ch_height * fmt->ch_width * 8;
691 check = TRUE;
692 break;
693
694 case DT_EXTRADATA:
695 *size = C64_SCR_EXTRADATA;
696 check = TRUE;
697 break;
698
699 case DT_CHAR_DATA:
700 *size = C64_MAX_CHARS * C64_CHR_SIZE;
701 check = TRUE;
702 break;
703
704 case DT_COLOR_REG:
705 *size = 1;
706 check = FALSE;
707 break;
708
709 default:
710 *size = 0;
711 check = FALSE;
712 }
713
630 if (op->size != 0) 714 if (op->size != 0)
631 return op->size; 715 {
632 716 if (check && op->size > *size)
633 switch (op->type) 717 return FALSE;
634 { 718
635 case DT_SCREEN_RAM: 719 *size = op->size;
636 return C64_SCREEN_SIZE; 720 }
637 721
638 case DT_COLOR_RAM: 722 return TRUE;
639 return C64_COLOR_SIZE;
640
641 case DT_BITMAP:
642 return C64_BITMAP_SIZE;
643
644 case DT_EXTRADATA:
645 return C64_SCR_EXTRADATA;
646
647 case DT_CHAR_DATA:
648 return C64_MAX_CHARS * C64_CHR_HEIGHT * C64_CHR_WIDTH;
649
650 case DT_COLOR_REG:
651 return 1;
652
653 default:
654 return 0;
655 }
656 } 723 }
657 724
658 725
659 int dmC64DecodeGenericBMP(DMC64Image *img, const Uint8 *buf, 726 int dmC64DecodeGenericBMP(DMC64Image *img, const Uint8 *buf,
660 const size_t len, const DMC64ImageFormat *fmt) 727 const size_t len, const DMC64ImageFormat *fmt)
669 dmError("Invalid number of enc/dec ops in format. Internal error.\n"); 736 dmError("Invalid number of enc/dec ops in format. Internal error.\n");
670 return DMERR_INTERNAL; 737 return DMERR_INTERNAL;
671 } 738 }
672 739
673 // Clear the image structure, set basics 740 // Clear the image structure, set basics
674 memset(img, 0, sizeof(*img)); 741 img->type = fmt->type;
675 img->type = fmt->type; 742 img->width = fmt->width;
743 img->height = fmt->height;
744 img->ch_width = fmt->ch_width;
745 img->ch_height = fmt->ch_height;
676 746
677 // Perform decoding 747 // Perform decoding
678 for (i = 0; i < fmt->nencdecOps; i++) 748 for (i = 0; i < fmt->nencdecOps; i++)
679 { 749 {
680 const DMC64EncDecOp *op = &fmt->encdecOps[i]; 750 const DMC64EncDecOp *op = &fmt->encdecOps[i];
685 // Check operation validity 755 // Check operation validity
686 if ((res = dmC64SanityCheckEncDecOp(i, op)) != DMERR_OK) 756 if ((res = dmC64SanityCheckEncDecOp(i, op)) != DMERR_OK)
687 return res; 757 return res;
688 758
689 // Check size 759 // Check size
690 size = dmC64GetOpSize(op, fmt); 760 if (!dmC64GetOpSize(op, fmt, &size))
761 {
762 dmError("Decode op SIZE out of bounds, op #%d type=%d, offs=%d ($%04x), "
763 "bank=%d, size=%d ($%04x) vs. allocated %d ($%04x)\n",
764 i, op->type, op->offs, op->offs, op->bank, size, size, op->size, op->size);
765 return DMERR_INVALID_DATA;
766 }
691 767
692 // Do we need to reallocate some more space? 768 // Do we need to reallocate some more space?
693 if (op->offs + size > len) 769 if (op->offs + size > len)
694 { 770 {
695 dmError("Decode out of bounds, op #%d type=%d, offs=%d ($%04x), " 771 dmError("Decode out of bounds, op #%d type=%d, offs=%d ($%04x), "
704 switch (op->type) 780 switch (op->type)
705 { 781 {
706 case DT_COLOR_RAM: memcpy(img->color[op->bank], src, size); break; 782 case DT_COLOR_RAM: memcpy(img->color[op->bank], src, size); break;
707 case DT_BITMAP: memcpy(img->bitmap[op->bank], src, size); break; 783 case DT_BITMAP: memcpy(img->bitmap[op->bank], src, size); break;
708 case DT_SCREEN_RAM: memcpy(img->screen[op->bank], src, size); break; 784 case DT_SCREEN_RAM: memcpy(img->screen[op->bank], src, size); break;
785 case DT_CHAR_DATA: memcpy(img->charmem[op->bank], src, size); break;
709 case DT_EXTRADATA: memcpy(img->extradata, src, size); break; 786 case DT_EXTRADATA: memcpy(img->extradata, src, size); break;
710 case DT_CHAR_DATA: memcpy(img->charmem, src, size); break;
711 787
712 case DT_COLOR_REG: 788 case DT_COLOR_REG:
713 switch (op->size) 789 switch (op->size)
714 { 790 {
715 case DC_D020: img->d020 = *src; break; 791 case DC_D020: img->d020 = *src; break;
749 case D64_CHCFG_SCREEN: 825 case D64_CHCFG_SCREEN:
750 break; 826 break;
751 827
752 case D64_CHCFG_LINEAR: 828 case D64_CHCFG_LINEAR:
753 { 829 {
754 size_t bank, offs; 830 int bank, offs;
755 for (bank = 0; bank < C64_SCR_MAX_BANK; bank++) 831 for (bank = 0; bank < C64_SCR_MAX_BANK; bank++)
756 for (offs = 0; offs < C64_SCR_SCREEN_SIZE; offs++) 832 for (offs = 0; offs < fmt->ch_height * fmt->ch_width; offs++)
757 img->screen[bank][offs] = offs & 0xff; 833 img->screen[bank][offs] = offs & 0xff;
758 } 834 }
759 break; 835 break;
760 836
761 default: 837 default:
829 // Check operation validity 905 // Check operation validity
830 if ((res = dmC64SanityCheckEncDecOp(i, op)) != DMERR_OK) 906 if ((res = dmC64SanityCheckEncDecOp(i, op)) != DMERR_OK)
831 goto error; 907 goto error;
832 908
833 // Check size 909 // Check size
834 size = dmC64GetOpSize(op, fmt); 910 if (!dmC64GetOpSize(op, fmt, &size))
911 {
912 dmError("Decode op SIZE out of bounds, op #%d type=%d, offs=%d ($%04x), "
913 "bank=%d, size=%d ($%04x) vs. allocated %d ($%04x)\n",
914 i, op->type, op->offs, op->offs, op->bank, size, size, op->size, op->size);
915 return DMERR_INVALID_DATA;
916 }
835 917
836 // Do we need to reallocate some more space? 918 // Do we need to reallocate some more space?
837 if (2 + op->offs + size > allocated) 919 if (2 + op->offs + size > allocated)
838 { 920 {
839 size_t diff = allocated - (op->offs + size + 2), 921 size_t diff = allocated - (op->offs + size + 2),
856 switch (op->type) 938 switch (op->type)
857 { 939 {
858 case DT_COLOR_RAM: memcpy(dst, img->color[op->bank], size); break; 940 case DT_COLOR_RAM: memcpy(dst, img->color[op->bank], size); break;
859 case DT_BITMAP: memcpy(dst, img->bitmap[op->bank], size); break; 941 case DT_BITMAP: memcpy(dst, img->bitmap[op->bank], size); break;
860 case DT_SCREEN_RAM: memcpy(dst, img->screen[op->bank], size); break; 942 case DT_SCREEN_RAM: memcpy(dst, img->screen[op->bank], size); break;
943 case DT_CHAR_DATA: memcpy(dst, img->charmem[op->bank], size); break;
861 case DT_EXTRADATA: memcpy(dst, img->extradata, size); break; 944 case DT_EXTRADATA: memcpy(dst, img->extradata, size); break;
862 case DT_CHAR_DATA: memcpy(dst, img->charmem, size); break;
863 945
864 case DT_COLOR_REG: 946 case DT_COLOR_REG:
865 switch (op->size) 947 switch (op->size)
866 { 948 {
867 case DC_D020: *dst = img->d020; break; 949 case DC_D020: *dst = img->d020; break;
936 1018
937 // Sanity check arguments 1019 // Sanity check arguments
938 if (dst == NULL || src == NULL) 1020 if (dst == NULL || src == NULL)
939 return DMERR_NULLPTR; 1021 return DMERR_NULLPTR;
940 1022
941 if (dst->width < 8) 1023 if (dst->width < src->width || dst->height < src->height)
942 return DMERR_INVALID_ARGS; 1024 return DMERR_INVALID_DATA;
943 1025
944 if (src->type & D64_FMT_CHAR) 1026 memset(dst->data, 0, dst->size);
945 for (yc = 0; yc < dst->height; yc++) 1027
1028 // Perform conversion
1029 for (yc = 0; yc < src->height; yc++)
946 { 1030 {
947 Uint8 *d = dp; 1031 Uint8 *d = dp;
948 const int y = yc / 8, yb = yc & 7; 1032 const int y = yc / 8, yb = yc & 7;
949 const int scroffsy = y * C64_SCR_CH_WIDTH; 1033 const int scroffsy = y * src->ch_width;
950 int xc; 1034 int xc;
951 1035
952 if ((src->type & D64_FMT_MC) == D64_FMT_HIRES) 1036 if (src->type & D64_FMT_CHAR)
953 { 1037 {
1038 // Charmode conversion
1039 if ((src->type & D64_FMT_MC) == D64_FMT_HIRES)
954 // Hi-res charmap 1040 // Hi-res charmap
955 for (xc = 0; xc < dst->width; xc++) 1041 for (xc = 0; xc < src->width; xc++)
956 { 1042 {
957 const int x = xc / 8; 1043 const int x = xc / 8;
958 const int scroffs = scroffsy + x; 1044 const int scroffs = scroffsy + x;
959 const int chr = src->screen[0][scroffs]; 1045 const int chr = src->screen[0][scroffs];
960 const int v = 7 - (xc & 7); 1046 const int v = 7 - (xc & 7);
961 1047
962 if ((src->charmem[chr][yb] >> v) & 1) 1048 if ((src->charmem[0][chr * C64_CHR_SIZE + yb] >> v) & 1)
963 *d++ = src->color[0][scroffs]; 1049 *d++ = src->color[0][scroffs];
964 else 1050 else
965 *d++ = src->bgcolor; 1051 *d++ = src->bgcolor;
966 } 1052 }
967 } 1053 else
968 else
969 {
970 // Multicolor variants 1054 // Multicolor variants
971 for (xc = 0; xc < dst->width / wdivisor; xc++) 1055 for (xc = 0; xc < src->width / wdivisor; xc++)
972 { 1056 {
973 const int x = xc / 4; 1057 const int x = xc / 4;
974 const int scroffs = scroffsy + x; 1058 const int scroffs = scroffsy + x;
975 const int chr = src->screen[0][scroffs]; 1059 const int chr = src->screen[0][scroffs];
976 const int v = 6 - ((xc * 2) & 6); 1060 const int v = 6 - ((xc * 2) & 6);
977 Uint8 c; 1061 Uint8 c;
978 1062
979 switch ((src->charmem[chr][yb] >> v) & 3) 1063 switch ((src->charmem[0][chr * C64_CHR_SIZE + yb] >> v) & 3)
980 { 1064 {
981 case 0: c = src->bgcolor; break; 1065 case 0: c = src->bgcolor; break;
982 case 1: c = src->d022; break; 1066 case 1: c = src->d022; break;
983 case 2: c = src->d023; break; 1067 case 2: c = src->d023; break;
984 case 3: c = src->color[0][scroffs]; 1068 case 3: c = src->color[0][scroffs];
987 *d++ = c; 1071 *d++ = c;
988 if (doubleMC) 1072 if (doubleMC)
989 *d++ = c; 1073 *d++ = c;
990 } 1074 }
991 } 1075 }
992 dp += dst->pitch; 1076 else
993 } 1077 {
994 else 1078 // Perform generic BITMAP conversion
995 // Perform generic BITMAP conversion 1079 const int bmoffsy = y * src->width;
996 for (yc = 0; yc < dst->height; yc++) 1080
997 { 1081 if ((src->type & D64_FMT_MC) == D64_FMT_HIRES)
998 Uint8 *d = dp;
999 const int y = yc / 8, yb = yc & 7;
1000 const int scroffsy = y * C64_SCR_CH_WIDTH;
1001 const int bmoffsy = y * C64_SCR_WIDTH;
1002 int xc;
1003
1004 if ((src->type & D64_FMT_MC) == D64_FMT_HIRES)
1005 {
1006 // Hi-res bitmap 1082 // Hi-res bitmap
1007 for (xc = 0; xc < dst->width; xc++) 1083 for (xc = 0; xc < src->width; xc++)
1008 { 1084 {
1009 const int x = xc / 8; 1085 const int x = xc / 8;
1010 const int scroffs = scroffsy + x; 1086 const int scroffs = scroffsy + x;
1011 const int bmoffs = bmoffsy + (x * 8) + yb; 1087 const int bmoffs = bmoffsy + (x * 8) + yb;
1012 const int v = 7 - (xc & 7); 1088 const int v = 7 - (xc & 7);
1014 if ((src->bitmap[0][bmoffs] >> v) & 1) 1090 if ((src->bitmap[0][bmoffs] >> v) & 1)
1015 *d++ = src->screen[0][scroffs] >> 4; 1091 *d++ = src->screen[0][scroffs] >> 4;
1016 else 1092 else
1017 *d++ = src->screen[0][scroffs] & 15; 1093 *d++ = src->screen[0][scroffs] & 15;
1018 } 1094 }
1019 } 1095 else
1020 else 1096 // Multicolor bitmap and variants
1021 { 1097 for (xc = 0; xc < src->width / wdivisor; xc++)
1022 // Multicolor variants
1023 for (xc = 0; xc < dst->width / wdivisor; xc++)
1024 { 1098 {
1025 const int x = xc / 4; 1099 const int x = xc / 4;
1026 const int scroffs = scroffsy + x; 1100 const int scroffs = scroffsy + x;
1027 const int bmoffs = bmoffsy + (x * 8) + yb; 1101 const int bmoffs = bmoffsy + (x * 8) + yb;
1028 const int v = 6 - ((xc * 2) & 6); 1102 const int v = 6 - ((xc * 2) & 6);
1102 1176
1103 return res; 1177 return res;
1104 } 1178 }
1105 1179
1106 1180
1107 int dmC64DecodeBMP(DMC64Image *img, const Uint8 *buf, const size_t len, 1181 int dmC64DecodeBMP(DMC64Image **img, const Uint8 *buf, const size_t len,
1108 const size_t probeOffs, const size_t loadOffs, 1182 const size_t probeOffs, const size_t loadOffs,
1109 const DMC64ImageFormat **fmt, const DMC64ImageFormat *forced) 1183 const DMC64ImageFormat **fmt, const DMC64ImageFormat *forced)
1110 { 1184 {
1185 if (img == NULL)
1186 return DMERR_NULLPTR;
1187
1111 // Check for forced format 1188 // Check for forced format
1112 if (forced != NULL) 1189 if (forced != NULL)
1113 *fmt = forced; 1190 *fmt = forced;
1114 else 1191 else
1115 { 1192 {
1116 // Nope, perform a generic probe 1193 // Nope, perform a generic probe
1117 if (probeOffs >= len) 1194 if (probeOffs >= len)
1118 return -200; 1195 return DMERR_INVALID_DATA;
1119 1196
1120 if (dmC64ProbeBMP(buf + probeOffs, len - probeOffs, fmt) == DM_PROBE_SCORE_FALSE) 1197 if (dmC64ProbeBMP(buf + probeOffs, len - probeOffs, fmt) == DM_PROBE_SCORE_FALSE)
1121 return -201; 1198 return DMERR_INVALID_DATA;
1122 } 1199 }
1123 1200
1124 if (loadOffs >= len) 1201 if (loadOffs >= len)
1125 return -203; 1202 return DMERR_INVALID_ARGS;
1203
1204 if (*fmt == NULL)
1205 return DMERR_INVALID_DATA;
1206
1207 // Allocate memory
1208 if ((*img = dmC64ImageAlloc((*fmt)->width, (*fmt)->height,
1209 (*fmt)->ch_width, (*fmt)->ch_height)) == NULL)
1210 return DMERR_MALLOC;
1126 1211
1127 // Decode the bitmap to memory layout 1212 // Decode the bitmap to memory layout
1128 if ((*fmt)->decode != NULL) 1213 if ((*fmt)->decode != NULL)
1129 return (*fmt)->decode(img, buf + loadOffs, len - loadOffs, *fmt); 1214 return (*fmt)->decode(*img, buf + loadOffs, len - loadOffs, *fmt);
1130 else 1215 else
1131 return dmC64DecodeGenericBMP(img, buf + loadOffs, len - loadOffs, *fmt); 1216 return dmC64DecodeGenericBMP(*img, buf + loadOffs, len - loadOffs, *fmt);
1132 } 1217 }