view tools/lib64util.c @ 2576:812b16ee49db

I had been living under apparent false impression that "realfft.c" on which the FFT implementation in DMLIB was basically copied from was released in public domain at some point, but it could very well be that it never was. Correct license is (or seems to be) GNU GPL. Thus I removing the code from DMLIB, and profusely apologize to the author, Philip Van Baren. It was never my intention to distribute code based on his original work under a more liberal license than originally intended.
author Matti Hamalainen <ccr@tnsp.org>
date Fri, 11 Mar 2022 16:32:50 +0200
parents bb44c48cffac
children 9807ae37ad69
line wrap: on
line source

/*
 * Common utility functions for gfxconv and 64vw
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2019-2021 Tecnic Software productions (TNSP)
 *
 * Please read file 'COPYING' for information on license and distribution.
 */
#include "lib64util.h"
#include "dmfile.h"

// Default character file ROM path, if not defined yet
#ifndef DM_DEF_CHARGEN
#define DM_DEF_CHARGEN   "/usr/local/lib64/vice/C64/chargen"
#endif


//
// Some common C64 palettes
//
DMC64Palette dmC64DefaultPalettes[] =
{
    {
        "pepto",
        "Pepto's classic (default)",
        {
            { 0x00, 0x00, 0x00, 0xff },
            { 0xFF, 0xFF, 0xFF, 0xff },
            { 0x68, 0x37, 0x2B, 0xff },
            { 0x70, 0xA4, 0xB2, 0xff },
            { 0x6F, 0x3D, 0x86, 0xff },
            { 0x58, 0x8D, 0x43, 0xff },
            { 0x35, 0x28, 0x79, 0xff },
            { 0xB8, 0xC7, 0x6F, 0xff },
            { 0x6F, 0x4F, 0x25, 0xff },
            { 0x43, 0x39, 0x00, 0xff },
            { 0x9A, 0x67, 0x59, 0xff },
            { 0x44, 0x44, 0x44, 0xff },
            { 0x6C, 0x6C, 0x6C, 0xff },
            { 0x9A, 0xD2, 0x84, 0xff },
            { 0x6C, 0x5E, 0xB5, 0xff },
            { 0x95, 0x95, 0x95, 0xff },
        },
    },
    {
        "colodore",
        "Colodore",
        {
            { 0x00, 0x00, 0x00, 0xff },
            { 0xff, 0xff, 0xff, 0xff },
            { 0x96, 0x28, 0x2e, 0xff },
            { 0x5b, 0xd6, 0xce, 0xff },
            { 0x9f, 0x2d, 0xad, 0xff },
            { 0x41, 0xb9, 0x36, 0xff },
            { 0x27, 0x24, 0xc4, 0xff },
            { 0xef, 0xf3, 0x47, 0xff },
            { 0x9f, 0x48, 0x15, 0xff },
            { 0x5e, 0x35, 0x00, 0xff },
            { 0xda, 0x5f, 0x66, 0xff },
            { 0x47, 0x47, 0x47, 0xff },
            { 0x78, 0x78, 0x78, 0xff },
            { 0x91, 0xff, 0x84, 0xff },
            { 0x68, 0x64, 0xff, 0xff },
            { 0xae, 0xae, 0xae, 0xff },
        },
    },
    {
        "vice3",
        "VICE 3.3",
        {
            { 0x00, 0x00, 0x00, 0xff },
            { 0xfd, 0xfe, 0xfc, 0xff },
            { 0xbe, 0x1a, 0x24, 0xff },
            { 0x30, 0xe6, 0xc6, 0xff },
            { 0xb4, 0x1a, 0xe2, 0xff },
            { 0x1f, 0xd2, 0x1e, 0xff },
            { 0x21, 0x1b, 0xae, 0xff },
            { 0xdf, 0xf6, 0x0a, 0xff },
            { 0xb8, 0x41, 0x04, 0xff },
            { 0x6a, 0x33, 0x04, 0xff },
            { 0xfe, 0x4a, 0x57, 0xff },
            { 0x42, 0x45, 0x40, 0xff },
            { 0x70, 0x74, 0x6f, 0xff },
            { 0x59, 0xfe, 0x59, 0xff },
            { 0x5f, 0x53, 0xfe, 0xff },
            { 0xa4, 0xa7, 0xa2, 0xff },
        },
    },
};

const int ndmC64DefaultPalettes = sizeof(dmC64DefaultPalettes) / sizeof(dmC64DefaultPalettes[0]);


char * dmC64GetImageTypeString(char *buf, const size_t len, const int type, const BOOL lng)
{
    static const char *fmtModesShort[] = { "*", "HiR", "MC", "ECM" };
    static const char *fmtModesLong[] = { "*", "Hires", "Multi-color", "Extended Color Mode" };
    const char *fmtStr;
    size_t nfmt = type & D64_FMT_MODE_MASK;

    if (nfmt < sizeof(fmtModesShort) / sizeof(fmtModesShort[0]))
        fmtStr = lng ? fmtModesLong[nfmt] : fmtModesShort[nfmt];
    else
        fmtStr = lng ? "ERROR" : "ERR";

    snprintf(buf, len,
        "%s %s%s%s%s",
        fmtStr,
        (type & D64_FMT_ILACE) ? (lng ? "interlaced " : "ILace ") : "",
        (type & D64_FMT_FLI)   ? "FLI " : "",
        (type & D64_FMT_CHAR)  ? (lng ? "char-mode" : "CHAR") : "",
        (type & D64_FMT_SPRITES)  ? (lng ? "+ sprite-layer" : "SPR") : ""
        );

    return buf;
}


DM_ATTR_PRINTF_FMT(4, 5)
static void dmC64ImageDumpLine(FILE *fh, const char *indent, const char *field, const char *fmt, ...)
{
    va_list ap;

    fputs(indent, fh);
    fprintf(fh, "%-20s: ", field);
    va_start(ap, fmt);
    vfprintf(fh, fmt, ap);
    va_end(ap);
    fputs("\n", fh);
}


void dmC64ImageDump(FILE *fh, const DMC64Image *img, const DMC64ImageFormat *fmt, const char *indent)
{
    char typeStr[64];

    if (fmt != NULL)
    {
        dmC64ImageDumpLine(fh, indent,
            "Format", "%s [%s]",
            fmt->name, fmt->fext);
    }

    if (img != NULL)
    {
        dmC64GetImageTypeString(typeStr, sizeof(typeStr), img->extraInfo[D64_EI_MODE], TRUE);

        dmC64ImageDumpLine(fh, indent,
            "Type", "%s", typeStr);

        dmC64ImageDumpLine(fh, indent,
            "Internal blocks", "%d", img->nblocks);

        if (img->extraInfo[D64_EI_MODE] & D64_FMT_ILACE)
        {
            char *tmps;
            switch (img->extraInfo[D64_EI_ILACE_TYPE])
            {
                case D64_ILACE_COLOR: tmps = "color"; break;
                case D64_ILACE_RES: tmps = "resolution"; break;
                default: tmps = "ERROR"; break;
            }
            dmC64ImageDumpLine(fh, indent,
                "Interlace type", "%s", tmps);
        }

        if (img->extraInfo[D64_EI_MODE] & D64_FMT_FLI)
        {
            dmC64ImageDumpLine(fh, indent,
                "FLI type", "%d",
                img->extraInfo[D64_EI_FLI_TYPE]);
        }

        dmC64ImageDumpLine(fh, indent,
            "Width x Height", "%d x %d pixels",
            img->fmt->width, img->fmt->height);

        dmC64ImageDumpLine(fh, indent,
            "CHwidth x CHheight", "%d x %d",
            img->fmt->chWidth, img->fmt->chHeight);

        dmC64ImageDumpLine(fh, indent,
            "d020 / border", "%d ($%02x)",
            img->d020, img->d020);

        dmC64ImageDumpLine(fh, indent,
            "d021 / background", "%d ($%02x)",
            img->bgcolor, img->bgcolor);

        if (img->extraInfo[D64_EI_MODE] & D64_FMT_CHAR)
        {
            if ((img->extraInfo[D64_EI_MODE] & D64_FMT_MODE_MASK) == (D64_FMT_MC | D64_FMT_ECM))
            {
                dmC64ImageDumpLine(fh, indent,
                    "d022", "%d ($%02x)",
                    img->d022, img->d022);
                dmC64ImageDumpLine(fh, indent,
                    "d023", "%d ($%02x)",
                    img->d023, img->d023);
            }

            if ((img->extraInfo[D64_EI_MODE] & D64_FMT_MODE_MASK) == D64_FMT_ECM)
            {
                dmC64ImageDumpLine(fh, indent,
                    "d024", "%d ($%02x)",
                    img->d024, img->d024);
            }
        }
    }
    else
    if (fmt != NULL)
    {
        dmC64GetImageTypeString(typeStr, sizeof(typeStr), fmt->format->mode, TRUE);

        dmC64ImageDumpLine(fh, indent,
            "Type", "%s", typeStr);

        dmC64ImageDumpLine(fh, indent,
            "Width x Height", "%d x %d pixels",
            fmt->format->width, fmt->format->height);

        dmC64ImageDumpLine(fh, indent,
            "CHwidth x CHheight", "%d x %d",
            fmt->format->chWidth, fmt->format->chHeight);
    }
}


void argShowC64Formats(FILE *fh, const BOOL rw, const BOOL verbose)
{
    fprintf(fh,
        "Available C64 bitmap formats (-f <frmt>):\n"
        " frmt %s| Type            %s| Description\n"
        "------%s+-----------------%s+-------------------------------------\n",
        rw ? "| RW " : "",
        verbose ? "| Load  | Size  " : "",
        rw ? "+----" : "",
        verbose ? "+-------+-------" : ""
        );

    for (int i = 0; i < ndmC64ImageFormats; i++)
    {
        const DMC64ImageFormat *fmt = dmC64ImageFormatsSorted[i];
        char buf[64];

        fprintf(fh, "%-6s",
            fmt->fext);

        if (rw)
        {
            fprintf(fh, "| %c%c ",
                (fmt->flags & DM_FMT_RD) ? 'R' : ' ',
                (fmt->flags & DM_FMT_WR) ? 'W' : ' '
                );
        }

        fprintf(fh,
            "| %-15s ",
            dmC64GetImageTypeString(buf, sizeof(buf), fmt->format->mode, FALSE)
            );

        if (verbose)
        {
            if (fmt->addr < 0)
            {
                fprintf(fh, "|  %4s ",
                    fmt->addr == -1 ? "?" : "");
            }
            else
            {
                fprintf(fh, "| $%04x ",
                    (uint32_t) fmt->addr);
            }

            if (fmt->size > 0)
            {
                fprintf(fh, "| $%04" DM_PRIx_SIZE_T " ",
                    fmt->size);
            }
            else
            {
                fprintf(fh, "|       ");
            }
        }

        fprintf(fh,
            "| %s%s\n",
            fmt->name,
            fmt->flags & DM_FMT_BROKEN ? " [BROKEN]" : "");
    }

    fprintf(fh, "%d formats supported.\n", ndmC64ImageFormats);
}


void argShowC64PaletteHelp(FILE *fh)
{
    fprintf(fh,
        "\n"
        "Available internal C64 palettes (-p <name>):\n"
        "--------------------------------------------\n");

    for (int n = 0; n < ndmC64DefaultPalettes; n++)
    {
        DMC64Palette *pal = &dmC64DefaultPalettes[n];
        fprintf(fh,
            "%-10s | %s\n",
            pal->name, pal->desc);
    }

    fprintf(fh,
        "\n"
        "Instead of using one of the internal palettes,\n"
        "you can specify an external palette file.\n"
        "\n"
        "Supported palette file formats are:\n"
        "-----------------------------------\n"
        );

    for (int n = 0; n < ndmPaletteFormatList; n++)
    {
        const DMPaletteFormat *fmt = &dmPaletteFormatList[n];
        if (fmt->flags & DM_FMT_RD)
        {
            fprintf(fh,
                "%-6s | %s\n",
                fmt->fext, fmt->name);
        }
    }
    fprintf(fh,
        "\n"
        "Example: -p foobar.bin\n"
        "\n");
}


BOOL argHandleC64PaletteOption(char *optArg, DMC64Palette **ppal, char **palFile)
{
    if (strcasecmp(optArg, "help") == 0 ||
        strcasecmp(optArg, "list") == 0)
    {
        argShowC64PaletteHelp(stdout);
        return FALSE;
    }

    for (int n = 0; n < ndmC64DefaultPalettes; n++)
    {
        DMC64Palette *pal = &dmC64DefaultPalettes[n];
        if (strcasecmp(pal->name, optArg) == 0)
        {
            *ppal = pal;
            return TRUE;
        }
    }

    *palFile = optArg;
    return TRUE;
}


int dmHandleExternalPalette(const char *filename, DMPalette **ppal)
{
    DMResource *fh = NULL;
    const DMImageFormat *ifmt = NULL;
    const DMPaletteFormat *pfmt = NULL;
    DMImage *inImage = NULL;
    Uint8 *dataBuf = NULL;
    size_t dataSize;
    int index, res;

    dmMsg(1, "Probing file '%s' for palette data.\n", filename);

    if ((res = dmReadDataFile(NULL, filename, &dataBuf, &dataSize)) != DMERR_OK)
    {
        dmErrorMsg("No such palette '%s', and no such file found (%s).\n",
            filename, dmErrorStr(res));
        goto done;
    }

    if ((res = dmf_open_memio(NULL, filename, dataBuf, dataSize, &fh)) != DMERR_OK)
    {
        dmErrorMsg("Could not create MemIO handle for input.\n");
        goto done;
    }

    if (dmImageProbeGeneric(dataBuf, dataSize, &ifmt, &index) > 0 &&
        ifmt->read != NULL)
    {
        dmMsg(1, "Probed image format %s (%s)\n",
            ifmt->name, ifmt->fext);

        res = ifmt->read(fh, &inImage);
        if (res != DMERR_OK)
        {
            dmErrorMsg("Could not read image file: %s\n",
                dmErrorStr(res));
            goto done;
        }

        if (inImage->pixfmt != DM_PIXFMT_PALETTE)
        {
            res = dmError(DMERR_INVALID_DATA,
                "Image file is not a paletted format.\n");
        }

        if (inImage->pal == NULL)
        {
            res = dmError(DMERR_NULLPTR,
                "Image file does not have a palette.\n");
        }

        res = dmPaletteCopy(ppal, inImage->pal);
    }
    else
    if (dmPaletteProbeGeneric(dataBuf, dataSize, &pfmt, &index) > 0 &&
        pfmt->read != NULL)
    {
        dmMsg(1, "Probed palette format %s (%s)\n",
            pfmt->name, pfmt->fext);

        res = pfmt->read(fh, ppal);
    }
    else
    {
        res = dmError(DMERR_NOT_SUPPORTED,
            "Not an internal palette or recognized palette file '%s'.\n",
            filename);
    }

done:
    dmf_close(fh);
    dmImageFree(inImage);
    dmFree(dataBuf);

    return res;
}


const char *dmGetChargenROMPath()
{
    const char *path = getenv("CHARGEN_ROM");
    if (path != NULL)
        return path;
    else
        return DM_DEF_CHARGEN;
}