Mercurial > hg > dmlib
view tools/lib64gfx.h @ 2208:90ec1ec89c56
Revamp the palette handling in lib64gfx somewhat, add helper functions to
lib64util for handling external palette file options and add support for
specifying one of the "internal" palettes or external (.act) palette file to
gfxconv and 64vw.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 14 Jun 2019 05:01:12 +0300 |
parents | 7694b5c8edc1 |
children | 75b5bb490f38 |
line wrap: on
line source
/* * Functions for reading and converting various restricted * C64/etc and/or indexed/paletted graphics formats. * Programmed and designed by Matti 'ccr' Hamalainen * (C) Copyright 2012-2019 Tecnic Software productions (TNSP) * * Please read file 'COPYING' for information on license and distribution. */ #ifndef LIB64GFX_H #define LIB64GFX_H 1 #include "libgfx.h" #include "dmgrowbuf.h" #ifdef __cplusplus extern "C" { #endif // Bitmap constants #define D64_SCR_WIDTH 320 #define D64_SCR_HEIGHT 200 #define D64_SCR_CH_WIDTH (D64_SCR_WIDTH/8) #define D64_SCR_CH_HEIGHT (D64_SCR_HEIGHT/8) #define D64_MAX_EXTRA_DATA 16 #define D64_MAX_EXTRA_INFO 64 // C64 video screen pixel aspect ratio on PAL #define D64_SCR_PAR_XY (0.9365f) // Sprite constants #define D64_SPR_WIDTH_PX 24 #define D64_SPR_HEIGHT_PX 21 #define D64_SPR_WIDTH_UT (D64_SPR_WIDTH_PX / 8) // bytes #define D64_SPR_HEIGHT_UT D64_SPR_HEIGHT_PX #define D64_SPR_SIZE ((D64_SPR_WIDTH_UT * D64_SPR_HEIGHT_UT) + 1) // Character constants #define D64_CHR_WIDTH_PX 8 #define D64_CHR_HEIGHT_PX 8 #define D64_CHR_WIDTH_UT 1 // bytes #define D64_CHR_HEIGHT_UT 8 // lines #define D64_CHR_SIZE (D64_CHR_WIDTH_UT * D64_CHR_HEIGHT_UT) // Etc. #define D64_NCOLORS 16 #define D64_VIDBANK_SIZE (16*1024) #define D64_MAX_SPRITES 1024 #define D64_MAX_CHARS 256 // Different supported flags/modes enum { D64_FMT_HIRES = 0x0001, // Hi-res D64_FMT_MC = 0x0002, // MultiColor D64_FMT_ECM = 0x0003, // ECM mode (applies only to character mode) D64_FMT_MODE_MASK = 0x000f, D64_FMT_ILACE = 0x0010, // Interlace D64_FMT_FLI = 0x0020, // FLI D64_FMT_CHAR = 0x0040, // Character mode D64_FMT_BORDER = 0x0080, // Uses border area }; // Different types of interlace enum { D64_ILACE_NONE = 0x0000, // Not set (invalid for interlaced images) D64_ILACE_RES = 0x0001, // Interlace doubles resolution D64_ILACE_COLOR = 0x0002, // Uses color mixing }; // Charmode screen memory configuration enum { D64_CHCFG_SCREEN, // Use screen memory D64_CHCFG_LINEAR = 1, // Generate linear pattern so that first line // of chars is 0-39, second 40-79, up to 255. }; // Various extra settings (see DMC64Image::extraInfo[]) enum { D64_EI_CHAR_CASE = 0, D64_EI_CHAR_MODE, D64_EI_CHAR_CUSTOM, }; // Image <-> bitmap conversion dithering enum { D64_DITH_NONE = 0, // No dithering }; // Different enc/dec operation types (op->type) enum { DO_COPY, // Perform copy between memory (from/to offset) and subject DO_SET_MEM, // Set subject value or fill subject memory area to byte value from offset DO_SET_OP, // Like above but value from op->offs field instead DO_SET_MEM_HI, // Copy one byte value like DO_SET_MEM, but high nibble only DO_SET_MEM_LO, // Like above, but low nibble DO_FUNC, // Execute specified decoding / encoding function DO_CHAR_CFG, // Set character mode configuration DO_LAST, // Last opcode, end processing }; // "Subjects" of operations (op->subject) enum { DS_COLOR_RAM, DS_BITMAP_RAM, DS_SCREEN_RAM, DS_EXTRA_DATA, DS_CHAR_DATA, DS_D020, DS_BGCOL, DS_D021, DS_D022, DS_D023, DS_D024, DS_LAST }; // Operation flags (op->flags) enum { DF_NORMAL = 0xffff, DF_DECODE = 0x0001, DF_ENCODE = 0x0002, }; typedef struct { char *name; char *desc; DMColor colors[D64_NCOLORS]; } DMC64Palette; typedef struct { int dither; // Dither mode (D64_DITH_*) BOOL aspect; // Correct pixel aspect ratio? DMPalette *pal; // Use this palette DMC64Palette *cpal; // If ^pal == NULL, use this C64 palette } DMC64ImageConvSpec; typedef struct { Uint8 *data; size_t size; } DMC64MemBlock; typedef struct { BOOL multicolor, xexpand, yexpand; int color, xc, yc; Uint8 data[D64_SPR_HEIGHT_UT][D64_SPR_WIDTH_UT]; } DMC64Sprite; typedef struct _DMC64ImageCommonFormat DMC64ImageCommonFormat; typedef struct _DMC64ImageFormat DMC64ImageFormat; typedef struct _DMC64Image { DMC64ImageCommonFormat *fmt; int laceType, // Interlace type (D64_ILACE_*) nblocks, // Number of internal blocks used nbanks; // Number of videobanks used // Bitmaps, color RAM, screen, etc. blocks * nblocks // Not all of them may be allocated DMC64MemBlock *color, *bitmap, *screen, *charData; // Other standard colours Uint8 d020, bgcolor, d022, d023, d024; // Extra data areas used by some formats, // for example raster colours might be stored DMC64MemBlock extraData[D64_MAX_EXTRA_DATA]; // Extra information / settings used by some formats, // for example some PETSCII-type formats. // See D64_EI_* constants. Uint8 extraInfo[D64_MAX_EXTRA_INFO]; //DMC64Sprite sprites[D64_MAX_SPRITES]; } DMC64Image; typedef struct _DMC64EncDecOp { int type; // Operation type (DO_*) int subject; // Operation "subject" (DS_*) size_t offs; // Offset in "memory" int bank; // Bank number or extradata index size_t size; // Size of data (0 for "default") size_t offs2; // Offset in data-block int (*decFunction)(const struct _DMC64EncDecOp *op, DMC64Image *img, const DMGrowBuf *buf, const DMC64ImageCommonFormat *fmt); int (*encFunction)(const struct _DMC64EncDecOp *op, DMGrowBuf *buf, const DMC64Image *img, const DMC64ImageCommonFormat *fmt); int flags; // Operation flags (DF_*) } DMC64EncDecOp; #define D64_MAX_ENCDEC_OPS 32 typedef DMC64EncDecOp DMC64EncDecOpList[D64_MAX_ENCDEC_OPS]; typedef int (*DMC64GetPixelFunc)(Uint8 *col, const DMC64Image *img, const int rasterX, const int rasterY); typedef struct _DMC64ImageCommonFormat { int type, // Type flags, see D64_FMT_* width, height, // Width and height in pixels chWidth, chHeight, // Width and height in charblocks aspectX, aspectY; // Pixel aspectX/Y int (*convertFrom)(DMImage *, const DMC64Image *, const DMC64ImageFormat *fmt, const DMC64ImageConvSpec *spec); int (*convertTo)(DMC64Image *, const DMImage *, const DMC64ImageFormat *fmt, const DMC64ImageConvSpec *spec); DMC64GetPixelFunc getPixel; DMC64EncDecOpList encdecOps; } DMC64ImageCommonFormat; typedef struct _DMC64ImageFormat { char *fext; // Filename extension char *name; // Format description/name size_t addr; // Loading address (0 if no loading address) size_t size; // Size, including loading address. Only used in probing and encoding. int flags; // DM_FMT_* flags, see libgfx.h int (*probe)(const DMGrowBuf *buf, const DMC64ImageFormat *fmt); int (*decode)(DMC64Image *img, const DMGrowBuf *buf, const DMC64ImageFormat *fmt); int (*encode)(DMGrowBuf *buf, const DMC64Image *img, const DMC64ImageFormat *fmt); DMC64ImageCommonFormat formatDef, *format; } DMC64ImageFormat; // // Compression types // enum { DM_COMP_RLE_MARKER = 1, // RLE with a separate marker byte DM_COMP_RLE_MASK = 2, // RLE that has marker bits and lower part acts as run length }; // Compression flags enum { DM_RLE_BYTE_RUNS = 0x0001, // Uses one-byte run lengths DM_RLE_WORD_RUNS = 0x0002, // Uses two-byte (word) run lengths DM_RLE_RUNS_MASK = 0x000f, DM_RLE_ORDER_1 = 0x0010, // Order: <marker>, <count/run length>, <data> DM_RLE_ORDER_2 = 0x0020, // Order: <marker>, <data>, <count/run length> DM_RLE_ORDER_MASK = 0x00f0, DM_RLE_BACKWARDS_INPUT = 0x0100, // Input is read backwards DM_RLE_BACKWARDS_OUTPUT = 0x0200, // Output is written backwards DM_RLE_ZERO_COUNT_MAX = 0x0400, // Zero "count" / run length value is max run (2^8, 2^16) DM_OUT_CROP_NONE = 0x0000, DM_OUT_CROP_START = 0x1000, DM_OUT_CROP_END = 0x2000, DM_OUT_CROP_MASK = 0xf000, }; typedef struct { char *func; size_t cropOutLen; int type; // DM_COMP_* int flags; // Uint8 // DM_COMP_RLE_MARKER mode rleMarkerB, // Marker byte for byte length runs (if DM_RLE_BYTE_RUNS used) rleMarkerW, // Marker byte for word length runs (if DM_RLE_WORD_RUNS used) // DM_COMP_RLE_MASK mode rleMarkerBits, rleMarkerMask, // Mask bits for marker: data & rleMarkerMask == rleMarkerBits rleCountMask; // Mask bits for length: count = data & rleCountMask unsigned int // Minimum and maximum run lengths rleMinCountB, rleMinCountW, rleMaxCountB, rleMaxCountW; } DMCompParams; // // Global variables // extern DMC64Palette dmC64DefaultPalettes[]; extern const int ndmC64DefaultPalettes; extern DMC64ImageFormat dmC64ImageFormats[]; extern const int ndmC64ImageFormats; extern DMC64ImageFormat **dmC64ImageFormatsSorted; // // Library init/close // int dmLib64GFXInit(void); void dmLib64GFXClose(void); // // Miscellaneous functions // int dmC64ProbeBMP(const DMGrowBuf *buf, const DMC64ImageFormat **fmt); int dmC64PaletteFromC64Palette(DMPalette **ppal, const DMC64Palette *cpal, const BOOL mixed); int dmC64SetImagePalette(DMImage *img, const DMC64ImageConvSpec *spec, const BOOL mixed); BOOL dmCompareAddr16(const DMGrowBuf *buf, const size_t offs, const Uint16 addr); int dmC64MemBlockAlloc(DMC64MemBlock *blk, const size_t size); int dmC64MemBlockCopy(DMC64MemBlock *dst, const DMC64MemBlock *src); void dmC64MemBlockFree(DMC64MemBlock *blk); // C64 bitmap image allocation/freeing DMC64Image *dmC64ImageAlloc(const DMC64ImageFormat *fmt); void dmC64ImageFree(DMC64Image *img); // Encoding and decoding of formats and images int dmC64ConvertCSDataToImage(DMImage *img, int xoffs, int yoffs, const Uint8 *inBuf, int width, int height, BOOL multicolor, int *colors); int dmC64ImageGetNumBlocks(const DMC64ImageFormat *fmt); const char *dmC64GetOpSubjectName(const int subject); const DMC64MemBlock * dmC64GetOpMemBlock(const DMC64Image *img, const int subject, const int bank); int dmC64SanityCheckEncDecOp(const int i, const DMC64EncDecOp *op, const DMC64Image *img); int dmC64MemBlockAllocSubj(DMC64Image *img, const int subject, const int bank); size_t dmC64GetSubjectSize(const int subject, const DMC64ImageCommonFormat *fmt); size_t dmC64GetOpSubjectSize(const DMC64EncDecOp *op, const DMC64ImageCommonFormat *fmt); int dmC64DecodeGenericBMP(DMC64Image *img, const DMGrowBuf *buf, const DMC64ImageFormat *fmt); int dmC64EncodeGenericBMP(const BOOL allocate, DMGrowBuf *buf, const DMC64Image *img, const DMC64ImageFormat *fmt); int dmC64ConvertBMP2Image(DMImage **pdst, const DMC64Image *src, const DMC64ImageFormat *fmt, const DMC64ImageConvSpec *spec); int dmC64ConvertImage2BMP(DMC64Image **pdst, const DMImage *src, const DMC64ImageFormat *fmt, const DMC64ImageConvSpec *spec); int dmC64DecodeBMP(DMC64Image **img, const DMGrowBuf *buf, const size_t probeOffs, const size_t loadOffs, const DMC64ImageFormat **fmt, const DMC64ImageFormat *forced); int dmC64EncodeBMP(DMGrowBuf *buf, const DMC64Image *img, const DMC64ImageFormat *fmt); int dmC64ConvertGenericBMP2Image(DMImage *dst, const DMC64Image *src, const DMC64ImageFormat *fmt, const DMC64ImageConvSpec *spec); int dmC64ConvertGenericImage2BMP(DMC64Image *dst, const DMImage *src, const DMC64ImageFormat *fmt, const DMC64ImageConvSpec *spec); void dmGenericRLEAnalyze(const DMGrowBuf *buf, DMCompParams *cfg); void dmSetupRLEBuffers(DMGrowBuf *dst, DMGrowBuf *src, const DMCompParams *cfg); void dmFinishRLEBuffers(DMGrowBuf *dst, DMGrowBuf *src, const DMCompParams *cfg); int dmGenericRLEOutputRun(DMGrowBuf *dst, const DMCompParams *cfg, const Uint8 data, const unsigned int count); int dmEncodeGenericRLESequence(DMGrowBuf *dst, const Uint8 data, const unsigned int count, const DMCompParams *cfg); int dmDecodeGenericRLE(DMGrowBuf *dst, const DMGrowBuf *src, const DMCompParams *cfg); int dmDecodeGenericRLEAlloc(DMGrowBuf *dst, const DMGrowBuf *src, const DMCompParams *cfg); int dmEncodeGenericRLE(DMGrowBuf *dst, const DMGrowBuf *src, const DMCompParams *cfg); int dmEncodeGenericRLEAlloc(DMGrowBuf *dst, const DMGrowBuf *src, const DMCompParams *cfg); // // Macros for defining variables used in getpixel functions // #define DM_C64_GENERIC_SC_PIXEL_DEFS(ximg) \ const int \ x = rasterX / 8, \ y = rasterY / 8, \ yoffs = y * ximg->fmt->chWidth, \ bmoffs = yoffs * 8 + (rasterY & 7) + (x * 8), \ scroffs = yoffs + x, \ vshift = 7 - (rasterX & 7); #define DM_C64_GENERIC_MC_PIXEL_DEFS(ximg) \ const int \ x = rasterX / 4, \ y = rasterY / 8, \ yoffs = y * (ximg)->fmt->chWidth, \ bmoffs = yoffs * 8 + (rasterY & 7) + (x * 8), \ scroffs = yoffs + x, \ vshift = 6 - ((rasterX * 2) & 6); #define DM_C64_GENERIC_CHAR_PIXEL(ximg) \ const int \ x = rasterX / 8, \ y = rasterY / 8, \ scroffs = y * (ximg)->fmt->chWidth + x; \ // // Inline helper functions for pixel format decoding // static inline int dmC64GetGenericSCPixel(Uint8 *col, const DMC64Image *img, const int bmoffs, const int scroffs, const int vshift, const int vbank, const int bitmap) { if ((img->bitmap[bitmap].data[bmoffs] >> vshift) & 1) *col = img->screen[vbank].data[scroffs] >> 4; else *col = img->screen[vbank].data[scroffs] & 15; return DMERR_OK; } static inline int dmC64GetGenericMCPixel(Uint8 *col, const DMC64Image *img, const int bmoffs, const int scroffs, const int vshift, const int vbank, const int bitmap, const int cbank, const int bgcolor) { switch ((img->bitmap[bitmap].data[bmoffs] >> vshift) & 3) { case 0: *col = bgcolor; break; case 1: *col = img->screen[vbank].data[scroffs] >> 4; break; case 2: *col = img->screen[vbank].data[scroffs] & 15; break; default: *col = img->color[cbank].data[scroffs] & 15; break; } return DMERR_OK; } static inline int dmC64GetGenericCharSCPixel(Uint8 *col, const DMC64Image *img, const int scroffs, const int rasterX, const int chrbank, const size_t chroffs, const int chr, const int cbank, const int bgcolor) { if (chroffs >= img->charData[chrbank].size) { return dmError(DMERR_INVALID_DATA, "Character map index #%d out of bounds for char ROM data.\n", chr); } const int vshift = 7 - (rasterX & 7); if ((img->charData[chrbank].data[chroffs] >> vshift) & 1) *col = img->color[cbank].data[scroffs]; else *col = bgcolor; return DMERR_OK; } static inline int dmC64GetGenericCharMCPixel(Uint8 *col, const DMC64Image *img, const int scroffs, const int rasterX, const int chrbank, const size_t chroffs, const int chr, const int cbank, const int bgcolor, const int bgd022, const int bgd023) { if (chroffs >= img->charData[chrbank].size) { return dmError(DMERR_INVALID_DATA, "Character map index #%d out of bounds for char ROM data.\n", chr); } const int ccol = img->color[cbank].data[scroffs]; if (ccol & 8) { const int vshift = 6 - (rasterX & 6); switch ((img->charData[chrbank].data[chroffs] >> vshift) & 3) { case 0: *col = bgcolor; break; case 1: *col = bgd022; break; case 2: *col = bgd023; break; case 3: *col = ccol & 7; } } else { const int vshift = 7 - (rasterX & 7); if ((img->charData[chrbank].data[chroffs] >> vshift) & 1) *col = ccol & 7; else *col = bgcolor; } return DMERR_OK; } static inline int dmC64GetGenericCharECMPixel(Uint8 *col, const DMC64Image *img, const int scroffs, const int rasterX, const int chrbank, const size_t chroffs, const int chr, const int cbank, const int bgcolor, const int bgd022, const int bgd023, const int bgd024) { if (chroffs >= img->charData[0].size) { return dmError(DMERR_INVALID_DATA, "Character map index #%d out of bounds for char ROM data.\n", chr); } const int vshift = 7 - (rasterX & 7); if ((img->charData[chrbank].data[chroffs] >> vshift) & 1) *col = img->color[cbank].data[scroffs] & 15; else switch ((chr >> 6) & 3) { case 0: *col = bgcolor; break; case 1: *col = bgd022; break; case 2: *col = bgd023; break; case 3: *col = bgd024; break; } return DMERR_OK; } static inline const DMC64EncDecOp * fmtGetEncDecOp(const DMC64ImageFormat *fmt, const int index) { return &fmt->format->encdecOps[index]; } #ifdef __cplusplus } #endif #endif // LIB64GFX_H