view tools/view64.c @ 1404:89725addaeaf

Improve error checking.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 30 Oct 2017 20:33:28 +0200
parents 009534f27de5
children c29f1cea4a1c
line wrap: on
line source

/*
 * view64 - Display some C64 etc graphics formats via libSDL
 * Programmed and designed by Matti 'ccr' Hamalainen
 * (C) Copyright 2012 Tecnic Software productions (TNSP)
 *
 * Please read file 'COPYING' for information on license and distribution.
 */
#include "dmlib.h"
#include "dmargs.h"
#include "dmfile.h"
#include "lib64gfx.h"
#include <SDL.h>


char * optFilename = NULL;
int    optVFlags = SDL_SWSURFACE | SDL_HWPALETTE;
int    optScrWidth, optScrHeight;
int    optForcedFormat = -1;
BOOL   optProbeOnly = FALSE;


static const DMOptArg optList[] =
{
    { 0, '?', "help",       "Show this help", OPT_NONE },
    { 1, 'v', "verbose",    "Be more verbose", OPT_NONE },
    { 2,   0, "fs",         "Fullscreen", OPT_NONE },
    { 3, 'S', "scale",      "Scale image by factor (1-10)", OPT_ARGREQ },
    { 4, 'f', "format",     "Force input format (see list below)", OPT_ARGREQ },
    { 5, 'p', "probe",      "Probe only (no display)", OPT_NONE },
};

const int optListN = sizeof(optList) / sizeof(optList[0]);


void dmSetScaleFactor(float factor)
{
    optScrWidth = (int) ((float) C64_SCR_WIDTH * factor * C64_SCR_PAR_XY);
    optScrHeight = (int) ((float) C64_SCR_HEIGHT * factor);
}


void argShowHelp()
{
    dmPrintBanner(stdout, dmProgName, "[options] <input image file>");
    dmArgsPrintHelp(stdout, optList, optListN, 0);

    printf("\nAvailable bitmap formats:\n");
    for (int i = 0; i < ndmC64ImageFormats; i++)
    {
        const DMC64ImageFormat *fmt = &dmC64ImageFormats[i];
        char buf[64];
        printf("%3d | %-5s | %-15s | %s\n",
            i, fmt->fext,
            dmC64GetImageTypeString(buf, sizeof(buf), fmt->type),
            fmt->name);
    }
}


BOOL argHandleOpt(const int optN, char *optArg, char *currArg)
{
    switch (optN)
    {
        case 0:
            argShowHelp();
            exit(0);
            break;

        case 1:
            dmVerbosity++;
            break;

        case 2:
            optVFlags |= SDL_FULLSCREEN;
            break;

        case 3:
            {
                float factor;
                if (sscanf(optArg, "%f", &factor) == 1)
                {
                    if (factor < 1 || factor >= 10)
                    {
                        dmErrorMsg("Invalid scale factor %1.0f, see help for valid values.\n", factor);
                        return FALSE;
                    }

                    dmSetScaleFactor(factor);
                }
                else
                {
                    dmErrorMsg("Invalid scale factor '%s'.\n", optArg);
                    return FALSE;
                }
            }
            break;

        case 4:
            {
                int i;
                if (sscanf(optArg, "%d", &i) == 1)
                {
                    if (i < 0 || i >= ndmC64ImageFormats)
                    {
                        dmErrorMsg("Invalid image format index %d, see help for valid values.\n", i);
                        return FALSE;
                    }
                    optForcedFormat = i;
                }
                else
                {
                    dmErrorMsg("Invalid image format argument '%s'.\n", optArg);
                    return FALSE;
                }
            }
            break;

        case 5:
            if (dmVerbosity < 1)
                dmVerbosity = 1;
            optProbeOnly = TRUE;
            break;

        default:
            dmErrorMsg("Unknown option '%s'.\n", currArg);
            return FALSE;
    }

    return TRUE;
}


BOOL argHandleFile(char *filename)
{
    if (optFilename == NULL)
    {
        optFilename = dm_strdup(filename);
        return TRUE;
    }
    else
    {
        dmErrorMsg("Too many filenames specified ('%s')\n", filename);
        return FALSE;
    }
}


BOOL dmInitializeVideo(SDL_Surface **screen)
{
    *screen = SDL_SetVideoMode(optScrWidth, optScrHeight, 8, optVFlags | SDL_RESIZABLE);
    if (*screen == NULL)
    {
        dmErrorMsg("Can't SDL_SetVideoMode(): %s\n", SDL_GetError());
        return FALSE;
    }
    return TRUE;
}


void dmDumpC64Image(const size_t size, const DMC64Image *img, const DMC64ImageFormat *fmt)
{
    char typeStr[64];

    snprintf(typeStr, sizeof(typeStr),
        "%s%s%s%s",
        ((img->type & D64_FMT_MC) ? "MultiColor" : "Hires"),
        ((img->type & D64_FMT_ILACE) ? " Interlaced" : ""),
        ((img->type & D64_FMT_FLI) ? " FLI" : ""),
        ((img->type & D64_FMT_CHAR) ? " CHAR" : "")
        );

    dmPrint(1,
        "Format              : %s [%s]\n"
        "Data size           : %" DM_PRIu_SIZE_T "\n"
        "Type                : %s\n"
        "Banks               : %d\n",
        fmt->name, fmt->fext,
        size,
        typeStr,
        img->nbanks);

    if (img->type & D64_FMT_ILACE)
    {
        char *tmps;
        switch(img->laceType)
        {
            case D64_ILACE_COLOR: tmps = "color"; break;
            case D64_ILACE_RES: tmps = "resolution"; break;
            default: tmps = "ERROR"; break;
        }
        dmPrint(1,
            "Interlace type      : %s\n",
            tmps);
    }

    dmPrint(1,
        "Width x Height      : %d x %d\n"
        "CHwidth x CHheight  : %d x %d\n",
        img->width, img->height,
        img->ch_width, img->ch_height);
}


int main(int argc, char *argv[])
{
    SDL_Surface *screen = NULL, *surf = NULL;
    DMImage bmap;
    BOOL initSDL = FALSE, exitFlag, needRedraw;
    const DMC64ImageFormat *fmt = NULL, *forced;
    DMC64Image *cimage = NULL;
    char *windowTitle;
    Uint8 *dataBuf = NULL;
    size_t dataSize;
    int ret;

    dmSetScaleFactor(2.0);

    dmInitProg("view64", "Display some C64 bitmap graphics formats", "0.2", NULL, NULL);

    /* Parse arguments */
    if (!dmArgsProcess(argc, argv, optList, optListN,
        argHandleOpt, argHandleFile, OPTH_BAILOUT))
        exit(1);


    if (optFilename == NULL)
    {
        dmErrorMsg("No input file specified, perhaps you need some --help\n");
        goto error;
    }

    dmPrint(1, "\n%s\n", optFilename);
    if ((ret = dmReadDataFile(NULL, optFilename, &dataBuf, &dataSize)) != DMERR_OK)
        goto error;


    // Probe for format
    if (optForcedFormat >= 0)
    {
        forced = &dmC64ImageFormats[optForcedFormat];
        dmMsg(0, "Forced %s format image, type %d, %s\n",
            forced->name, forced->type, forced->fext);
    }
    else
        forced = NULL;

    ret = dmC64DecodeBMP(&cimage, dataBuf, dataSize, 0, 2, &fmt, forced);

    if (ret != DMERR_OK)
    {
        dmErrorMsg("Failed to decode bitmap data %d: %s\n", ret, dmErrorStr(ret));
        goto error;
    }

    if (fmt == NULL)
    {
        dmErrorMsg("Probing could not find any matching image format. Perhaps try forcing a format via -f.\n");
        goto error;
    }

    dmDumpC64Image(dataSize, cimage, fmt);

    if (optProbeOnly)
        goto error;

    // Initialize libSDL
    if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0)
    {
        dmErrorMsg("Could not initialize SDL: %s\n", SDL_GetError());
        goto error;
    }
    initSDL = TRUE;


    // Open window/set video mode
    screen = SDL_SetVideoMode(optScrWidth, optScrHeight, 8, optVFlags | SDL_RESIZABLE);
    if (screen == NULL)
    {
        dmErrorMsg("Can't SDL_SetVideoMode(): %s\n", SDL_GetError());
        goto error;
    }

    // Create surface (we are lazy and ugly)
    surf = SDL_CreateRGBSurface(SDL_SWSURFACE, cimage->width, cimage->height, 8, 0, 0, 0, 0);
    SDL_SetColors(surf, (SDL_Color *)dmC64Palette, 0, C64_NCOLORS);
    SDL_SetColors(screen, (SDL_Color *)dmC64Palette, 0, C64_NCOLORS);

    // Convert bitmap (this is a bit ugly and lazy here)
    bmap.size = surf->pitch * surf->h;
    bmap.data = surf->pixels;
    bmap.pitch = surf->pitch;
    bmap.width = surf->w;
    bmap.height = surf->h;
    bmap.constpal = TRUE;

    if (fmt->convertFrom != NULL)
        ret = fmt->convertFrom(&bmap, cimage, fmt);
    else
        ret = dmC64ConvertGenericBMP2Image(&bmap, cimage, fmt);

    if (ret != DMERR_OK)
    {
        dmErrorMsg("Failed to convert bitmap data %d: %s\n", ret, dmErrorStr(ret));
        goto error;
    }

    // Set window title and caption
    windowTitle = dm_strdup_printf("%s - %s (%d x %d)",
        dmProgName, optFilename, cimage->width, cimage->height);

    SDL_WM_SetCaption(windowTitle, dmProgName);
    dmFree(windowTitle);


    // Start main loop
    needRedraw = TRUE;
    exitFlag = FALSE;
    while (!exitFlag)
    {
        SDL_Event event;
        while (SDL_PollEvent(&event))
        switch (event.type)
        {
            case SDL_KEYDOWN:
                switch (event.key.keysym.sym)
                {
                    case SDLK_ESCAPE: exitFlag = TRUE; break;

                    default:
                        break;
                }

                needRedraw = TRUE;
                break;

            case SDL_VIDEORESIZE:
                optScrWidth  = event.resize.w;
                optScrHeight = event.resize.h;
                if (!dmInitializeVideo(&screen))
                    goto error;

                needRedraw = TRUE;
                break;

            case SDL_VIDEOEXPOSE:
                needRedraw = TRUE;
                break;

            case SDL_QUIT:
                exit(0);
        }

        if (needRedraw)
        {
            float aspect = (float) bmap.height / (float) bmap.width;
            int sheight = optScrHeight / aspect;
            int ypos = (optScrHeight - sheight) / 2;

            if (SDL_MUSTLOCK(screen) != 0 && SDL_LockSurface(screen) != 0)
            {
                dmErrorMsg("Can't lock surface.\n");
                goto error;
            }

            dmScaledBlitSurface8to8(surf, 0, ypos, optScrWidth, sheight, screen);
            SDL_SetColors(screen, (SDL_Color *)dmC64Palette, 0, C64_NCOLORS);

            if (SDL_MUSTLOCK(screen) != 0)
                SDL_UnlockSurface(screen);

            SDL_Flip(screen);
            needRedraw = FALSE;
        }

        SDL_Delay(100);
    }


error:
    dmC64ImageFree(cimage);

    if (screen)
        SDL_FreeSurface(screen);

    if (initSDL)
        SDL_Quit();

    return 0;
}