Mercurial > hg > dmlib
view tools/64vw.c @ 2121:f12ac487954b
Rename the "shift" variable/function argument used for bitshift of c64 bitmap/char pixels.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 27 May 2019 00:04:02 +0300 |
parents | 88d37ec1b4d6 |
children | 47ddbedf5b56 |
line wrap: on
line source
/* * 64vw - Display some C64 etc graphics formats via libSDL * 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. */ #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; if ((ret = dmSetDefaultC64Palette(&bmap)) != DMERR_OK) return ret; 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->colors, 0, bmap.pal->ncolors); dmPaletteFree(bmap.pal); 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 && ret != DMERR_NOT_SUPPORTED) { dmErrorMsg("Could not decode file '%s': %s\n", filename, 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_SPACE: 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) { if (ret != DMERR_NOT_SUPPORTED) { dmErrorMsg("Could not decode file '%s': %s\n", filename, 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->fmt->width, cimage->fmt->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->fmt->width, cimage->fmt->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 - [%d / %d] %s", dmProgName, currIndex + 1, noptFilenames2, filename); } 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; }