Mercurial > hg > dmlib
view tools/64vw.c @ 1931:410679d2fe8a
"Enable" the image->c64 bitmap conversion path in gfxconv. It does not work
without the necessary bits elsewhere, though. Also add DMC64ImageConvSpec
structure for delivering conversion parameters, though it is not yet used
either.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Thu, 28 Jun 2018 17:26:30 +0300 |
parents | cc4570c0bca5 |
children | 8896d5676f1b |
line wrap: on
line source
/* * 64vw - Display some C64 etc graphics formats via libSDL * Programmed and designed by Matti 'ccr' Hamalainen * (C) Copyright 2012-2018 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> #define SET_SKIP_AMOUNT 10 int optVFlags = 0; int optScrWidth, optScrHeight; int optForcedFormat = -1; BOOL optInfoOnly = FALSE, optProbeOnly = FALSE, optListOnly = FALSE; size_t noptFilenames1 = 0, noptFilenames2 = 0; char **optFilenames = NULL; 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 --formats)", OPT_ARGREQ }, { 5, 'F', "formats", "List supported input formats", OPT_NONE }, { 6, 'i', "info", "Print information only (no display)", OPT_NONE }, { 7, 'l', "list", "Output list of files that were recognized (implies -i)", OPT_NONE }, { 8, 'p', "probe", "Probe only (do not attempt to decode the image)", 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 argShowFormats() { printf( "Available C64 bitmap formats (-f <frmt>):\n" " frmt | Type | Description\n" "------+-----------------+-------------------------------------\n" ); for (int i = 0; i < ndmC64ImageFormats; i++) { const DMC64ImageFormat *fmt = &dmC64ImageFormats[i]; char buf[64]; printf("%-6s| %-15s | %s%s\n", fmt->fext, dmC64GetImageTypeString(buf, sizeof(buf), fmt->format->type, FALSE), fmt->name, fmt->flags & DM_FMT_BROKEN ? " [BROKEN]" : ""); } printf("%d formats supported.\n", ndmC64ImageFormats); } void argShowHelp() { dmPrintBanner(stdout, dmProgName, "[options] <input image file>"); dmArgsPrintHelp(stdout, optList, optListN, 0); } 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_WINDOW_FULLSCREEN_DESKTOP; 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: optForcedFormat = -1; for (int i = 0; i < ndmC64ImageFormats; i++) { const DMC64ImageFormat *fmt = &dmC64ImageFormats[i]; if (fmt->fext != NULL && strcasecmp(optArg, fmt->fext) == 0) { optForcedFormat = i; break; } } if (optForcedFormat < 0) { dmErrorMsg("Invalid image format argument '%s'.\n", optArg); return FALSE; } break; case 5: argShowFormats(); exit(0); break; case 7: optListOnly = TRUE; // Fallthrough case 6: if (dmVerbosity < 1) dmVerbosity = 1; optInfoOnly = TRUE; break; case 8: if (dmVerbosity < 1) dmVerbosity = 1; optProbeOnly = TRUE; break; default: dmErrorMsg("Unknown option '%s'.\n", currArg); return FALSE; } return TRUE; } BOOL argHandleFile1(char *filename) { (void) filename; noptFilenames1++; return TRUE; } BOOL argHandleFile2(char *filename) { if (noptFilenames2 < noptFilenames1) { optFilenames[noptFilenames2++] = filename; return TRUE; } else return FALSE; } int dmReadC64Image(const char *filename, const DMC64ImageFormat *forced, const DMC64ImageFormat **fmt, DMC64Image **cimage) { Uint8 *dataBuf = NULL; size_t dataSize; DMGrowBuf tmp; int ret; if ((ret = dmReadDataFile(NULL, filename, &dataBuf, &dataSize)) != DMERR_OK) goto exit; dmGrowBufConstCreateFrom(&tmp, dataBuf, dataSize); if (optProbeOnly) ret = dmC64ProbeBMP(&tmp, fmt) != DM_PROBE_SCORE_FALSE ? DMERR_OK : DMERR_NOT_SUPPORTED; else ret = dmC64DecodeBMP(cimage, &tmp, 0, 2, fmt, forced); exit: dmFree(dataBuf); return ret; } int dmDecodeC64Image(const DMC64Image *cimage, const DMC64ImageFormat *fmt, SDL_Surface *surf, const DMC64ImageConvSpec *spec) { DMImage bmap; int ret; memset(&bmap, 0, sizeof(bmap)); bmap.size = surf->pitch * surf->h; bmap.data = surf->pixels; bmap.pitch = surf->pitch; bmap.width = surf->w; bmap.height = surf->h; bmap.ncolors = C64_NCOLORS; bmap.constpal = TRUE; bmap.pal = dmDefaultC64Palette; if (fmt->format->convertFrom != NULL) ret = fmt->format->convertFrom(&bmap, cimage, fmt, spec); else ret = dmC64ConvertGenericBMP2Image(&bmap, cimage, fmt, spec); SDL_SetPaletteColors(surf->format->palette, (SDL_Color *) bmap.pal, 0, bmap.ncolors); return ret; } int main(int argc, char *argv[]) { const DMC64ImageFormat *forced; DMC64ImageConvSpec spec; SDL_Window *window = NULL; SDL_Renderer *renderer = NULL; SDL_Texture *texture = NULL; SDL_Surface *surf = NULL; BOOL initSDL = FALSE, exitFlag, needRedraw; size_t currIndex, prevIndex; int ret; dmC64InitializeFormats(); dmSetScaleFactor(2.0); memset(&spec, 0, sizeof(spec)); dmInitProg("64vw", "Display some C64 bitmap graphics formats", "0.4", NULL, NULL); // Parse arguments, round #1 if (!dmArgsProcess(argc, argv, optList, optListN, argHandleOpt, argHandleFile1, OPTH_BAILOUT)) exit(1); if (noptFilenames1 == 0) { dmErrorMsg("No input file(s) specified, perhaps you need some --help\n"); goto exit; } // Allocate space for filename pointers if ((optFilenames = dmCalloc(noptFilenames1, sizeof(char *))) == NULL) { dmErrorMsg("Could not allocate memory for input file list.\n"); goto exit; } // Assign the filename pointers if (!dmArgsProcess(argc, argv, optList, optListN, NULL, argHandleFile2, OPTH_BAILOUT | OPTH_ONLY_OTHER)) goto exit; // Check for forced input format if (optForcedFormat >= 0) { forced = &dmC64ImageFormats[optForcedFormat]; dmMsg(0, "Forced %s format image, type %d, %s\n", forced->name, forced->format->type, forced->fext); } else forced = NULL; // If we are simply displaying file information, no need to initialize SDL etc if (optInfoOnly || optProbeOnly) { for (size_t n = 0; n < noptFilenames2; n++) { char *filename = optFilenames[n]; const DMC64ImageFormat *fmt = NULL; DMC64Image *cimage = NULL; if ((ret = dmReadC64Image(filename, forced, &fmt, &cimage)) != DMERR_OK) { if (!optListOnly) { dmErrorMsg("Could not read image file '%s', %d: %s\n", filename, ret, dmErrorStr(ret)); } } else if (optListOnly) { fprintf(stdout, "%s\n", filename); } else { fprintf(stdout, "\n%s\n", filename); dmC64ImageDump(stdout, cimage, fmt, " "); } dmC64ImageFree(cimage); } goto exit; } // Initialize libSDL if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) { dmErrorMsg("Could not initialize SDL: %s\n", SDL_GetError()); goto exit; } initSDL = TRUE; // Open window if ((window = SDL_CreateWindow(dmProgName, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, optScrWidth, optScrHeight, optVFlags | SDL_WINDOW_RESIZABLE //| SDL_WINDOW_HIDDEN )) == NULL) { dmErrorMsg("Can't create an SDL window: %s\n", SDL_GetError()); goto exit; } if ((renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_PRESENTVSYNC)) == NULL) { dmErrorMsg("Can't create an SDL renderer: %s\n", SDL_GetError()); goto exit; } // SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "best"); // Start main loop currIndex = 0; prevIndex = 1; 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: case SDLK_q: exitFlag = TRUE; break; case SDLK_DOWN: case SDLK_LEFT: if (currIndex > 0) currIndex--; else currIndex = 0; break; case SDLK_UP: case SDLK_RIGHT: if (currIndex < noptFilenames2 - 1) currIndex++; else currIndex = noptFilenames2 - 1; break; case SDLK_PAGEDOWN: if (currIndex > SET_SKIP_AMOUNT) currIndex -= SET_SKIP_AMOUNT; else currIndex = 0; break; case SDLK_PAGEUP: if (currIndex < noptFilenames2 - 1 - SET_SKIP_AMOUNT) currIndex += SET_SKIP_AMOUNT; else currIndex = noptFilenames2 - 1; break; case SDLK_HOME: currIndex = 0; break; case SDLK_END: currIndex = noptFilenames2 - 1; break; case SDLK_f: optVFlags ^= SDL_WINDOW_FULLSCREEN_DESKTOP; if (SDL_SetWindowFullscreen(window, optVFlags) != 0) goto exit; break; default: break; } needRedraw = TRUE; break; case SDL_WINDOWEVENT: switch (event.window.event) { case SDL_WINDOWEVENT_EXPOSED: needRedraw = TRUE; break; case SDL_WINDOWEVENT_RESIZED: optScrWidth = event.window.data1; optScrHeight = event.window.data2; needRedraw = TRUE; break; } break; case SDL_QUIT: goto exit; } if (currIndex != prevIndex) { char *filename = optFilenames[currIndex]; const DMC64ImageFormat *fmt = NULL; DMC64Image *cimage = NULL; char *title = NULL; if (surf != NULL) { SDL_FreeSurface(surf); surf = NULL; } if ((ret = dmReadC64Image(filename, forced, &fmt, &cimage)) != DMERR_OK) { dmErrorMsg("Failed to decode bitmap data %d: %s\n", ret, dmErrorStr(ret)); goto fail; } if (fmt == NULL || cimage == NULL) { dmErrorMsg("Probing could not find any matching image format. Perhaps try forcing a format via -f.\n"); goto fail; } // Create surface (we are lazy and ugly) if ((surf = SDL_CreateRGBSurfaceWithFormat(0, cimage->width, cimage->height, 8, SDL_PIXELFORMAT_INDEX8)) == NULL) { dmC64ImageFree(cimage); dmErrorMsg("Could not allocate surface.\n"); goto exit; } if (dmDecodeC64Image(cimage, fmt, surf, &spec) == DMERR_OK) { title = dm_strdup_printf("%s - [%d / %d] %s (%dx%d @ %s)", dmProgName, currIndex + 1, noptFilenames2, filename, cimage->width, cimage->height, fmt->name); if (dmVerbosity >= 1) { fprintf(stdout, "\n%s\n", filename); dmC64ImageDump(stdout, cimage, fmt, " "); } } fail: dmC64ImageFree(cimage); if (surf == NULL && (surf = SDL_CreateRGBSurfaceWithFormat(0, C64_SCR_WIDTH, C64_SCR_HEIGHT, 8, SDL_PIXELFORMAT_INDEX8)) == NULL) { dmErrorMsg("Could not allocate surface.\n"); goto exit; } if (texture != NULL) SDL_DestroyTexture(texture); if ((texture = SDL_CreateTextureFromSurface(renderer, surf)) == NULL) { dmErrorMsg("Could not create texture from surface: %s\n", SDL_GetError()); goto exit; } if (title == NULL) { title = dm_strdup_printf("%s - %s [%d / %d]", dmProgName, filename, currIndex + 1, noptFilenames2); } SDL_SetWindowTitle(window, title); dmFree(title); needRedraw = TRUE; prevIndex = currIndex; } if (needRedraw) { SDL_RenderClear(renderer); SDL_RenderCopy(renderer, texture, NULL, NULL); SDL_RenderPresent(renderer); needRedraw = FALSE; } SDL_Delay(50); } exit: // Cleanup dmFree(optFilenames); if (texture != NULL) SDL_DestroyTexture(texture); if (renderer != NULL) SDL_DestroyRenderer(renderer); if (window != NULL) SDL_DestroyWindow(window); if (surf != NULL) SDL_FreeSurface(surf); if (initSDL) SDL_Quit(); return 0; }