Mercurial > hg > dmlib
changeset 651:e2ac08228a0f
Move files to various subdirectories.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Tue, 16 Apr 2013 06:01:42 +0300 |
parents | 107468492257 |
children | d9888292f971 |
files | blittest.c data2inc.c edgui.cpp editor/edgui.cpp editor/edmain.cpp editor/edmain.h editor/edres.cpp editor/edres.h editor/edtimeline.cpp editor/edtimeline.h editor/edtlobj.cpp editor/edtlobj.h editor/edview.cpp editor/edview.h editor/edwaveform.cpp editor/edwaveform.h edmain.cpp edmain.h edres.cpp edres.h edtimeline.cpp edtimeline.h edtlobj.cpp edtlobj.h edview.cpp edview.h edwaveform.cpp edwaveform.h efu.c gentab.c gfxconv.c mod2wav.c objlink.c packed.c ppl.c svg2qd.py testpl.c tests/blittest.c tests/efu.c tests/testpl.c tests/vecmattest.c tests/vptest.c utils/data2inc.c utils/gentab.c utils/gfxconv.c utils/mod2wav.c utils/objlink.c utils/packed.c utils/ppl.c utils/svg2qd.py utils/view64.c utils/viewmod.c utils/xm2jss.c vecmattest.c view64.c viewmod.c vptest.c xm2jss.c |
diffstat | 58 files changed, 11416 insertions(+), 11416 deletions(-) [+] |
line wrap: on
line diff
--- a/blittest.c Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,458 +0,0 @@ -#include "dmlib.h" -#include "dmargs.h" -#include "dmvecmat.h" -#include "dmtext.h" -#include <math.h> - -#define DM_COLORS (256) - -char *optFontFile = "font.ttf"; -BOOL optBenchmark = FALSE; -int optVFlags = SDL_SWSURFACE | SDL_HWPALETTE; -int optScrWidth = 640, optScrHeight = 480, optFontSize = 20, optScrDepth = 32; -int optBenchmarkLen = 20; - -DMOptArg optList[] = { - { 0, '?', "help", "Show this help", OPT_NONE }, - { 2, 'v', "verbose", "Be more verbose", OPT_NONE }, - { 3, 'f', "full", "Fullscreen", OPT_NONE }, - { 4, 'h', "hw", "Use SDL hardware surface", OPT_NONE }, - { 5, 's', "size", "Initial window size/resolution -s 640x480", OPT_ARGREQ }, - { 6, 'd', "depth", "Color depth of mode/window in bits (8/32)", OPT_ARGREQ }, - { 7, 'b', "bench", "Run in benchmark mode", OPT_NONE }, -}; - -const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - dmArgsPrintHelp(stdout, optList, optListN); -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - switch (optN) { - case 0: - argShowHelp(); - exit(0); - break; - - case 2: - dmVerbosity++; - break; - - case 3: - optVFlags |= SDL_FULLSCREEN; - break; - - case 6: - if (optArg) - optScrDepth = atoi(optArg); - break; - - case 5: - { - int w, h; - if (sscanf(optArg, "%dx%d", &w, &h) == 2) - { - if (w < 320 || h < 200 || w > 3200 || h > 3200) - { - dmError("Invalid width or height: %d x %d\n", w, h); - return FALSE; - } - optScrWidth = w; - optScrHeight = h; - } - else - { - dmError("Invalid size argument '%s'.\n", optArg); - return FALSE; - } - } - break; - - case 7: - optBenchmark = TRUE; - break; - - default: - dmError("Unknown option '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -void DM_MakePalette(SDL_Surface *scr) -{ - SDL_Color pal[DM_COLORS]; - int n; - - for (n = 0; n < 256; n++) - { - pal[n].r = n; - pal[n].g = n; - pal[n].b = n; - } - - SDL_SetColors(scr, pal, 0, DM_COLORS); -} - - -void DM_PrintRect(FILE *f, SDL_Rect *r) -{ - fprintf(f, "SDL_Rect <%d, %d : %d, %d>\n", - r->x, r->y, r->w, r->h); -} - -BOOL DM_InitializeVideo(SDL_Surface **screen) -{ - *screen = SDL_SetVideoMode(optScrWidth, optScrHeight, optScrDepth, optVFlags | SDL_RESIZABLE); - if (*screen == NULL) - { - dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); - return FALSE; - } - -#if 0 - SDL_Rect r; - r.x = -50; - r.y = 50; - r.w = 700; - r.h = 300; - DM_PrintRect(stderr, &r); - SDL_SetClipRect(*screen, &r); - DM_PrintRect(stderr, &r); - DM_PrintRect(stderr, &((*screen)->clip_rect)); -#endif - - return TRUE; -} - -void DM_Random(SDL_Surface *screen, int q) -{ - Uint8 *pix = screen->pixels; - int xc, yc; - - for (yc = 0; yc < screen->h; yc++) - { - Uint8 *dp = pix; - - for (xc = 0; xc < screen->w; xc++) - *dp++ = yc + (xc ^ q) + (yc & q); - - pix += screen->pitch; - } -} - -#define QWIDTH 256 -#define QHEIGHT 160 - -typedef Uint8 DMBlockMap[QHEIGHT][QWIDTH]; - - -static DMFloat dmClip(DMFloat a) -{ - return (a < 0.0f ? 0.0f : (a > 1.0f ? 1.0f : a)); -} - - -void dmMakeBumpMap(DMBlockMap map, DMFloat q, DMFloat m) -{ - int x, y; - for (y = 0; y < QHEIGHT; y++) - for (x = 0; x < QWIDTH; x++) - { - DMFloat f = 0.40f + dmPerlinNoise2D(x, y, 1.1f, q, 2); - map[y][x] = (int) (dmClip(f) * m); - } -} - - -void dmShadowTraceHeightMap(DMBlockMap lightMap, DMBlockMap pheightMap, DMVector *light) -{ - int i, j; - - for (j = 0; j < QHEIGHT; j++) - for (i = 0; i < QWIDTH; i++) - { - DMVector vr, vl, va; - DMFloat vrayLen, vfactor; - int vlen; - BOOL wasHit; - - // Perform shadow occlusion via simplistic raytracing - vr.x = i; - vr.y = j; - vr.z = light->z; // - 10.0; -// vr.z = pheightMap[j][i]; - - // Calculate light vector vector - dm_vector_sub_r(&vl, &vr, light); - vrayLen = dm_vector_length(&vl); - -#if 1 - dm_vector_copy(&va, &vl); - dm_vector_normalize(&va); - dm_vector_scale(&va, 0.6f); - dm_vector_copy(&vr, light); - - vlen = 0; - wasHit = FALSE; - do - { - float h; - - // If ray is inside the heightmap, get value - if (vr.x >= 0 && vr.y >= 0 && vr.x < QWIDTH && vr.y < QHEIGHT) - h = pheightMap[(int) vr.y][(int) vr.x]; - else - break; - - // Check for hits - if (h > vr.z) - wasHit = TRUE; - else - { - // Move forwards - dm_vector_add(&vr, &va); - vlen++; - } - } - while (!wasHit && vlen <= vrayLen); - - // Check if the ray hit something, e.g. is this point occluded? - if (wasHit && vlen < vrayLen) - { - vfactor = vlen * 0.01; - } - else - vfactor = vlen * 0.02; -#endif - -#if 1 - { - /* Calculate light's intensity based on the angle it "hits" - * - * 1) Calculate the vectors that form the imaginary "plane" - * 2) Cross-product -> normal vector of the plane - * 2) Normalize the normal vector - * 3) Calculate light vector's hit angle by dot product - */ - DMVector v1, v2; - DMFloat c; - - v1.x = 2.0f; - v1.y = 0.0f; - v1.z = (DMFloat) (pheightMap[j][i] - pheightMap[j][i + 1]); - - v2.x = 0.0f; - v2.y = 2.0f; - v2.z = (DMFloat) (pheightMap[j][i] - pheightMap[j + 1][i]); - - dm_vector_cross(&vr, &v1, &v2); - dm_vector_normalize(&vr); - dm_vector_normalize(&vl); - c = dm_vector_dot(&vl, &vr); - - vrayLen = 255 - (vrayLen * 0.1) * vrayLen + (c * 128.0f) + (vfactor * vfactor * 1255); - } -#else - vrayLen = 255 - vrayLen * vrayLen * (vfactor * vfactor); - if (vrayLen < 0) vrayLen = 0; - vrayLen += pheightMap[j][i]; -#endif - - // Clip result - if (vrayLen < 0) - vrayLen = 0; - else if (vrayLen > 255.0f) - vrayLen = 255.0f; - - lightMap[j][i] = vrayLen; - } -} - - -int main(int argc, char *argv[]) -{ - SDL_Surface *screen = NULL, *bmap = NULL; - TTF_Font *font = NULL; - SDL_Color fontcol={255,155,155,0}; - SDL_Event event; - int mouseX, mouseY; - BOOL initSDL = FALSE, initTTF = FALSE, exitFlag, showMap = FALSE; - - dmInitProg("blittest", "dmlib blittest", "0.2", NULL, NULL); - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, NULL, FALSE)) - exit(1); - - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) - { - dmError("Could not initialize SDL: %s\n", SDL_GetError()); - goto error_exit; - } - initSDL = TRUE; - - - if (TTF_Init() < 0) - { - dmError("Could not initialize FreeType/TTF: %s\n", SDL_GetError()); - goto error_exit; - } - initTTF = TRUE; - - font = TTF_OpenFont(optFontFile, optFontSize); - if (font == NULL) - { - dmError("Could not load TTF font '%s' (%d): %s\n", - optFontFile, optFontSize, SDL_GetError()); - goto error_exit; - } - TTF_SetFontStyle(font, TTF_STYLE_NORMAL); - - if (optBenchmark) - { - screen = SDL_CreateRGBSurface(SDL_SWSURFACE, optScrWidth, optScrHeight, optScrDepth, 0, 0, 0, 0); - if (screen == NULL) - { - dmError("Could not create screen surface.\n"); - goto error_exit; - } - - dmMsg(0, "Benchmark mode, not opening window.\n"); - } - else - { - if (!DM_InitializeVideo(&screen)) - goto error_exit; - - SDL_WM_SetCaption("Halleluja", "DMT"); - } - - dmPerlinInit(); - - bmap = SDL_CreateRGBSurface(SDL_SWSURFACE, QWIDTH, QHEIGHT, 8, 0, 0, 0, 0); - DM_MakePalette(bmap); - DM_Random(bmap, 15); - - DMVector light; - DMBlockMap heightMap; - light.x = light.y = 128; - light.z = 128; - dmMakeBumpMap(heightMap, 0.06, 254); - - - - int numFrames = 0, startTime = SDL_GetTicks(), endTime = 0; - exitFlag = FALSE; - - if (optBenchmark) - dmMsg(0, "Starting benchmark, running for %d seconds.\n", optBenchmarkLen); - - while (!exitFlag) - { - dmMakeBumpMap(heightMap, 0.05 + sin(SDL_GetTicks() * 0.001) * 0.002 , 254); - if (!optBenchmark) - { - while (SDL_PollEvent(&event)) - switch (event.type) - { - case SDL_KEYDOWN: - switch (event.key.keysym.sym) - { - case SDLK_ESCAPE: exitFlag = TRUE; break; - - case SDLK_F5: - showMap = !showMap; - break; - - default: - break; - } - - break; - - case SDL_VIDEORESIZE: - optScrWidth = event.resize.w; - optScrHeight = event.resize.h; - - if (!DM_InitializeVideo(&screen)) - goto error_exit; - - break; - - case SDL_VIDEOEXPOSE: - break; - - case SDL_QUIT: - exit(0); - } - - SDL_GetMouseState(&mouseX, &mouseY); - light.x = ((DMFloat) mouseX * QWIDTH) / (DMFloat) optScrWidth; - light.y = ((DMFloat) mouseY * QHEIGHT) / (DMFloat) optScrHeight; - } - - if (!optBenchmark && SDL_MUSTLOCK(screen) != 0 && SDL_LockSurface(screen) != 0) - { - dmError("Can't lock surface.\n"); - goto error_exit; - } - - - if (showMap) - memcpy(bmap->pixels, heightMap, QWIDTH * QHEIGHT); - else - dmShadowTraceHeightMap(bmap->pixels, heightMap, &light); - - dmScaledBlitSurfaceAny(bmap, 0, 0, screen->w, screen->h, screen, DMD_NONE); - - if (!optBenchmark) - { - dmDrawTTFText(screen, font, fontcol, 0, 0, "%3.1f FPS", - (float) (numFrames * 1000.0f) / (float) (endTime - startTime)); - - if (SDL_MUSTLOCK(screen) != 0) - SDL_UnlockSurface(screen); - - SDL_Flip(screen); - SDL_Delay(10); - } - - endTime = SDL_GetTicks(); - numFrames++; - - if (optBenchmark) - { - if (endTime - startTime > optBenchmarkLen * 1000) - exitFlag = TRUE; - } - } - - // Print benchmark results - dmMsg(0, "%d frames in %d ms, fps = %1.3f\n", - numFrames, endTime - startTime, - (float) (numFrames * 1000.0f) / (float) (endTime - startTime)); - - -error_exit: - dmMsg(0, "Shutting down dmlib.\n"); - if (screen) - SDL_FreeSurface(screen); - - if (font) - TTF_CloseFont(font); - - if (initSDL) - SDL_Quit(); - - if (initTTF) - TTF_Quit(); - - return 0; -}
--- a/data2inc.c Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,404 +0,0 @@ -/* - * data2inc - Convert binary data to "C"-source or XA-compatible include file - * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2003,2009-2012 Tecnic Software productions (TNSP) - * - * Please read file 'COPYING' for information on license and distribution. - */ -#include <errno.h> -#include "dmlib.h" -#include "dmargs.h" -#include "dmmutex.h" - -#define RA_LINEBUF (16) - -enum -{ - FMT_AUTO = 0, - FMT_C, - FMT_ASM -}; - -char *optInFilename = NULL, - *optOutFilename = NULL, - *optObjName = "default_object", - *optDataType = NULL, - *optAddLine = NULL; - -int optIndentation = -1; -int optFormat = FMT_AUTO; -BOOL optHexMode = FALSE, - optQuiet = FALSE, - optExtraData = FALSE, - optFormatting = TRUE; - - -void (*writeHeader) (FILE *, char *) = NULL; -void (*writeDecl) (FILE *, size_t, char *) = NULL; -void (*writeData) (FILE *, Uint8 *, size_t) = NULL; -void (*writeFooter) (FILE *, size_t, char *) = NULL; - - -static DMOptArg optList[] = -{ - { 0, '?', "help", "Show this help", OPT_NONE }, - { 4, 'A', "format-asm", "Output in XA-compatible asm", OPT_NONE }, - { 5, 'C', "format-c", "Output in ANSI C", OPT_NONE }, - { 1, 'n', "name", "Set object name", OPT_ARGREQ }, - { 2, 't', "type", "Set datatype (unsigned char/byte)", OPT_ARGREQ }, - { 3, 'a', "add-line", "Add this line to start of file", OPT_ARGREQ }, - { 6, 'x', "hexadecimal", "Use hexadecimal output", OPT_NONE }, - { 7, 'q', "quiet", "Do not add comments", OPT_NONE }, - { 8, 'f', "no-formatting", "Disable additional output formatting", OPT_NONE }, - { 9, 'i', "indentation", "Set indentation (negative value = tab)", OPT_ARGREQ }, - { 10, 'e', "extra-data", "Add object end labels and size in asm output", OPT_NONE }, -}; - -static const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - dmPrintBanner(stdout, dmProgName, - "[options] [sourcefile] [destfile]"); - - dmArgsPrintHelp(stdout, optList, optListN); - - printf( - "\n" - "To convert a data file to a C structure using 'Uint8' as type:\n" - "$ data2inc -C -n variable_name -t Uint8 input.bin output.h\n" - "\n" - ); -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - switch (optN) - { - case 0: - argShowHelp(); - exit(0); - break; - - case 1: - optObjName = optArg; - break; - - case 2: - optDataType = optArg; - break; - - case 3: - optAddLine = optArg; - break; - - case 4: - optFormat = FMT_ASM; - break; - case 5: - optFormat = FMT_C; - break; - case 6: - optHexMode = TRUE; - break; - case 7: - optQuiet = TRUE; - break; - case 8: - optFormatting = FALSE; - break; - - case 9: - optIndentation = atoi(optArg); - break; - - case 10: - optExtraData = TRUE; - break; - - default: - dmError("Unknown option '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -BOOL argHandleFile(char * currArg) -{ - if (!optInFilename) - optInFilename = currArg; - else - if (!optOutFilename) - optOutFilename = currArg; - else - dmError("Source and destination filenames already specified, extraneous argument '%s'.\n", currArg); - - return TRUE; -} - - -/* Assembler include data output functions - */ -void writeHeader_ASM(FILE * f, char *name) -{ - if (name) - fprintf(f, "; '%s'", name); - else - fprintf(f, "; Generated"); - fprintf(f, " by %s v%s\n", - dmProgName, dmProgVersion); -} - -void writeDecl_ASM(FILE * f, size_t len, char *name) -{ - if (optExtraData) - fprintf(f, "%s_size = %u\n", name, len); - fprintf(f, "%s:\n", name); -} - -void writeData_ASM(FILE * f, Uint8 * buf, size_t len) -{ - size_t i; - - fprintf(f, "%s ", optDataType); - for (i = 0; i < len; i++) - { - if (optFormatting) - { - if (optHexMode) - fprintf(f, "$%.2x", buf[i]); - else - fprintf(f, "%3d", buf[i]); - } - else - { - if (optHexMode) - fprintf(f, "$%x", buf[i]); - else - fprintf(f, "%d", buf[i]); - } - - if (i < (len - 1)) - fprintf(f, ","); - } -} - -void writeFooter_ASM(FILE * f, size_t len, char *name) -{ - (void) len; - if (optExtraData) - fprintf(f, "%s_end: \n", name); - else - fprintf(f, "\n"); -} - - -/* ANSI-C include data output functions - */ -void writeHeader_C(FILE * f, char *name) -{ - if (name) - fprintf(f, "/* '%s' generated", name); - else - fprintf(f, "/* Generated"); - - fprintf(f, " by %s v%s\n" " */\n", - dmProgName, dmProgVersion); -} - -void writeDecl_C(FILE * f, size_t len, char *name) -{ - fprintf(f, "%s %s[%u] = {\n", - optDataType, name, len); - - printf("extern %s %s[%u];\n", - optDataType, name, len); -} - -void writeData_C(FILE * f, Uint8 * buf, size_t len) -{ - size_t i; - - for (i = 0; i < len; i++) - { - if (optFormatting) - { - if (optHexMode) - fprintf(f, "0x%.2x", buf[i]); - else - fprintf(f, "%3d", buf[i]); - } - else - { - if (optHexMode) - fprintf(f, "0x%x", buf[i]); - else - fprintf(f, "%d", buf[i]); - } - - fprintf(f, ","); - } -} - -void writeFooter_C(FILE * f, size_t len, char *name) -{ - (void) len; - (void) name; - fprintf(f, "};\n"); -} - - -off_t dmGetFileSize(FILE *f) -{ - off_t len, pos = ftell(f); - fseeko(f, 0, SEEK_END); - len = ftell(f); - fseek(f, pos, SEEK_SET); - return len; -} - - -int main(int argc, char *argv[]) -{ - FILE *sfile = NULL, *dfile = NULL; - off_t inSize; - Uint8 inBuf[RA_LINEBUF]; - int tmpRes; - - /* Initialize */ - dmInitProg("data2inc", "Data to include converter", "0.6", NULL, NULL); - dmVerbosity = 0; - - /* Parse arguments */ - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, argHandleFile, TRUE)) - exit(1); - - /* Determine output type, if not specified */ - if (optFormat == FMT_AUTO) - { - char *dext; - - if (optOutFilename == NULL) - { - dmError("Output format not specified and no output filename given (try --help)\n"); - exit(1); - } - - /* Check filename extension */ - dext = strrchr(optOutFilename, '.'); - if (dext) - { - dext++; - if (!strcasecmp(dext, "c") || !strcasecmp(dext, "h") || - !strcasecmp(dext, "cc") || !strcasecmp(dext, "cpp") || - !strcasecmp(dext, "hpp") || !strcasecmp(dext, "c++")) - optFormat = FMT_C; - else - optFormat = FMT_ASM; - } else - optFormat = FMT_ASM; - } - - /* Set functions */ - switch (optFormat) - { - case FMT_ASM: - if (!optDataType) - optDataType = ".byte"; - - writeHeader = writeHeader_ASM; - writeDecl = writeDecl_ASM; - writeData = writeData_ASM; - writeFooter = writeFooter_ASM; - break; - - case FMT_C: - if (!optDataType) - optDataType = "unsigned char"; - - writeHeader = writeHeader_C; - writeDecl = writeDecl_C; - writeData = writeData_C; - writeFooter = writeFooter_C; - break; - - case FMT_AUTO: - default: - dmError("Internal error, FMT_AUTO at output function init.\n"); - exit(2); - } - - /* Open the files */ - if (optInFilename == NULL) - sfile = stdin; - else - if ((sfile = fopen(optInFilename, "rb")) == NULL) - { - tmpRes = errno; - dmError("Error opening input file '%s'. (%s)\n", - optInFilename, strerror(tmpRes)); - exit(3); - } - - if (optOutFilename == NULL) - dfile = stdout; - else - if ((dfile = fopen(optOutFilename, "wa")) == NULL) - { - tmpRes = errno; - dmError("Error creating output file '%s'. (%s)\n", - optOutFilename, strerror(tmpRes)); - exit(4); - } - - /* Get sourcefile size */ - inSize = dmGetFileSize(sfile); - - /* Output header */ - if (!optQuiet) - writeHeader(dfile, optOutFilename); - - if (optAddLine) - fprintf(dfile, "%s\n", optAddLine); - - /* Output declaration */ - writeDecl(dfile, inSize, optObjName); - - /* Output data */ - while (!feof(sfile)) - { - tmpRes = fread(inBuf, sizeof(Uint8), RA_LINEBUF, sfile); - if (tmpRes > 0) - { - if (optIndentation < 0) - fprintf(dfile, "\t"); - else - if (optIndentation > 0) - { - int i; - for (i = 0; i < optIndentation; i++) - fputs(" ", dfile); - } - - writeData(dfile, inBuf, tmpRes); - - fprintf(dfile, "\n"); - } - } - - - /* Output footer */ - writeFooter(dfile, inSize, optObjName); - - /* Exit */ - fclose(sfile); - fclose(dfile); - - exit(0); - return 0; -}
--- a/edgui.cpp Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,522 +0,0 @@ -// -// Demo Editor -- Qt GUI setup parts and callbacks -// (C) Copyright 2012 Matti 'ccr' Hämäläinen <ccr@tnsp.org> -// -#include "edmain.h" - -#include <QCloseEvent> -#include <QToolBar> -#include <QMenuBar> -#include <QStatusBar> -#include <QMenu> -#include <QProgressBar> -#include <QFileDialog> -#include <QHBoxLayout> -#include <QVBoxLayout> - - - -void DemoEditor::updateMenuStates() -{ - // Set window title based on document filename and changed status - QString name; - - if (!currTimeline || currTimeline->filename.isEmpty()) - name = DOC_DEF_FILENAME; - else - name = currTimeline->filename; - - if (currTimeline != NULL) - { - if (currTimeline->tl != NULL && currTimeline->tl->name != NULL) - name += " (" + QString(currTimeline->tl->name) + ")"; - - if (currTimeline->touched()) - name = "*" + name; - } - - setWindowTitle(name + " - " + QCoreApplication::applicationName()); - - // Enable menu items based on states - menuActSave->setEnabled(currTimeline != NULL&& currTimeline->touched()); - menuActSaveAs->setEnabled(currTimeline != NULL); - - // Enable undo/redo items and set their texts based on history status - int historyLevels = undoHistory.size(); - QString itemText; - bool itemEnabled; - - if (undoHistoryPos >= 0 && undoHistoryPos < historyLevels) - { - itemText = " " + undoHistory.at(undoHistoryPos)->state(); - itemEnabled = true; - } - else - { - itemText = ""; - itemEnabled = false; - } - - menuActRedo->setEnabled(itemEnabled); - menuActRedo->setText("&Redo" + itemText); - - if (undoHistoryPos > 0 && historyLevels > 0) - { - itemText = " " + undoHistory.at(undoHistoryPos - 1)->state(); - itemEnabled = true; - } - else - { - itemText = ""; - itemEnabled = false; - } - - menuActUndo->setEnabled(itemEnabled); - menuActUndo->setText("&Undo" + itemText); - - update(); -} - - -// -// Show about dialog -// -void DemoEditor::actionAboutBox() -{ - QMessageBox::about(this, - "About "+ QCoreApplication::applicationName(), - "<h1>" + QCoreApplication::applicationName() + - " v"+ QCoreApplication::applicationVersion() +"</h1><br>\n" - "(C) Copyright 2012 Matti 'ccr' Hämäläinen<br>\n" - "<br>\n" - "<b>A demo editor TNSP dmlib engine.</b><br>\n"); -} - - -// -// Show a dialog inquiring the user whether to save the current -// document if it has been modified since last save/load. -// -QMessageBox::StandardButton DemoEditor::showDocumentModifiedDialog() -{ - return QMessageBox::question(this, - "The document has been modified.", - "Do you want to save your changes?", - QMessageBox::Discard | QMessageBox::Cancel | QMessageBox::Save, - QMessageBox::Save); -} - - -// -// Generic error/warning dialog -// -void DemoEditor::showFileErrorDialog(QString operation, int code) -{ -/* - QString msg; - - QMessageBox::error(this, - "A non-critical error occured", - operation -*/ -} - - -void DemoEditor::actionFileNew() -{ - bool okToCreate = true; - - if (currTimeline != NULL && currTimeline->touched()) - { - okToCreate = false; - switch (showDocumentModifiedDialog()) - { - case QMessageBox::Discard: - okToCreate = true; - break; - - case QMessageBox::Save: - actionFileSave(); - if (!currTimeline->touched()) - { - QMessageBox::information(this, - "Document saved", - "The document was saved as " + currTimeline->filename); - - okToCreate = true; - } - break; - - default: - break; - } - } - - if (okToCreate) - createNewFile(); -} - - -void DemoEditor::actionFileOpen() -{ - bool okToOpen = true; - - if (currTimeline != NULL && currTimeline->touched()) - { - okToOpen = false; - - switch (showDocumentModifiedDialog()) - { - case QMessageBox::Discard: - okToOpen = true; - break; - - case QMessageBox::Save: - actionFileSave(); - if (!currTimeline->touched()) - { - QMessageBox::information(this, - "Document saved", - "The document was saved as " + currTimeline->filename); - - okToOpen = true; - } - break; - - default: - break; - } - } - - if (okToOpen) - { - QFileDialog fdialog(this); - - fdialog.setAcceptMode(QFileDialog::AcceptOpen); - fdialog.setFileMode(QFileDialog::ExistingFile); - fdialog.setNameFilter("Demo timeline files (*.demo)"); - fdialog.setDefaultSuffix("demo"); - - if (fdialog.exec()) - readFromFile(fdialog.selectedFiles()[0]); - } -} - - -void DemoEditor::actionFileSaveAs() -{ - if (!currTimeline) - { - qDebug() << "DemoEditor::actionFileSaveAs(): currTimeline == null"; - return; - } - - QFileDialog fdialog(this); - - fdialog.setAcceptMode(QFileDialog::AcceptSave); - fdialog.setFileMode(QFileDialog::AnyFile); - fdialog.setNameFilter("Demo files (*.demo)"); - fdialog.setDefaultSuffix("demo"); - fdialog.setConfirmOverwrite(true); - - fdialog.selectFile(currTimeline->filename.isEmpty() ? currTimeline->filename : DOC_DEF_FILENAME); - - if (fdialog.exec()) - saveToFile(fdialog.selectedFiles()[0]); -} - - -void DemoEditor::actionFileSave() -{ - if (!currTimeline) - { - qDebug() << "DemoEditor::actionFileSave(): currTimeline == null"; - return; - } - - // If filename has been set, save .. otherwise go to save as - if (!currTimeline->filename.isEmpty()) - saveToFile(currTimeline->filename); - else - actionFileSaveAs(); -} - - -void DemoEditor::closeEvent(QCloseEvent *event) -{ - bool okToClose = true; - - if (currTimeline && currTimeline->touched()) - { - okToClose = false; - switch (showDocumentModifiedDialog()) - { - case QMessageBox::Discard: - okToClose = true; - break; - - case QMessageBox::Save: - actionFileSave(); - if (!currTimeline->touched()) - okToClose = true; - break; - - default: - break; - } - } - - if (okToClose) - event->accept(); -} - - -// -// Various menu actions -// -void DemoEditor::actionControlChanged(QAction *act) -{ -// demoView->setToolMode(act->data().toInt()); -} - - -// -// Update statusbar message text -// -void DemoEditor::statusMsg(QString message) -{ - statusBar()->showMessage(message, 0); -} - - -// -// Set active element of an action group based on matching the data -// -void DemoEditor::setActionGroupChecked(QActionGroup *group, QVariant data) -{ - QList<QAction *> items = group->actions(); - - for (int i = 0; i < items.size(); i++) - { - QAction *act = items.at(i); - if (act->data() == data) - { - act->setChecked(true); - return; - } - } -} - - -// -// Helper functions for creating GUI elements -// -QAction * DemoEditor::createToolButton(QActionGroup *group, QString name, QIcon icon, QString statustip, QVariant data) -{ - QAction *action = new QAction(icon, name, group); - - action->setStatusTip(statustip + "."); - action->setCheckable(true); - action->setData(data); - - return action; -} - - -QAction * DemoEditor::createMenuAction(QString name, const QKeySequence &shortcut, QString tooltip) -{ - QAction *action = new QAction(name, this); - - if (shortcut != QKeySequence(QKeySequence::UnknownKey)) - action->setShortcut(shortcut); - - if (!tooltip.isNull()) - action->setStatusTip(tooltip + "."); - - return action; -} - - -QAction * DemoEditor::createMenuGroupAction(QMenu *menu, QActionGroup *group, QString name, const QKeySequence &shortcut, QString tooltip, QVariant data) -{ - QAction *action = createMenuAction(name, shortcut, tooltip); - - action->setCheckable(true); - action->setData(data); - - menu->addAction(action); - group->addAction(action); - - return action; -} - - -#define MCONNECT(menu, act, slot) do { connect(act, SIGNAL(triggered()), this, SLOT(slot)); menu->addAction(act); } while(0) - - -// -// Create GUI elements -// -void DemoEditor::createMainGUI() -{ - QAction *act; - QMenu *fileMenu, *editMenu, *viewMenu, *helpMenu; - - qDebug() << "- Constructing menus"; - - // - // File menu - // - fileMenu = menuBar()->addMenu("&File"); - - act = createMenuAction("&New", QKeySequence::New, "Create a new demo timeline"); - MCONNECT(fileMenu, act, actionFileNew()); - - menuActOpen = createMenuAction("&Open", QKeySequence::Open, "Open a demo timeline file"); - MCONNECT(fileMenu, menuActOpen, actionFileOpen()); - - menuActSave = createMenuAction("&Save", QKeySequence::Save, "Save demo timeline"); - MCONNECT(fileMenu, menuActSave, actionFileSave()); - - menuActSaveAs = createMenuAction("Save &as", QKeySequence::SaveAs, "Save demo timeline as a new file"); - MCONNECT(fileMenu, menuActSaveAs, actionFileSaveAs()); - - fileMenu->addSeparator(); - - QKeySequence qseq(Qt::CTRL + Qt::Key_Q); - act = createMenuAction("&Quit", qseq, "Exit application"); - MCONNECT(fileMenu, act, close()); - - - // - // Edit menu - // - editMenu = menuBar()->addMenu("&Edit"); - - menuActUndo = createMenuAction("&Undo", QKeySequence::Undo, "Undo last change"); - MCONNECT(editMenu, menuActUndo, performUndo()); - - menuActRedo = createMenuAction("&Redo", QKeySequence::Redo, "Redo last change"); - MCONNECT(editMenu, menuActRedo, performRedo()); - -#if 0 - editMenu->addSeparator(); - - menuActCut = createMenuAction("Cu&t", QKeySequence::Cut, "Cut object"); - MCONNECT(editMenu, menuActCut, actionCut()); - - menuActCopy = createMenuAction("&Copy", QKeySequence::Copy, "Copy object"); - MCONNECT(editMenu, menuActCopy, actionCopy()); - - menuActPaste = createMenuAction("&Paste", QKeySequence::Paste, "Paste object"); - MCONNECT(editMenu, menuActPaste, actionPaste()); - - menuActDelete = createMenuAction("&Delete", QKeySequence::Delete, "Delete object"); - MCONNECT(editMenu, menuActDelete, actionDelete()); -#endif - - // - // Help menu - // - helpMenu = menuBar()->addMenu("&Help"); - act = createMenuAction("About", 0, "Show information about application"); - MCONNECT(helpMenu, act, actionAboutBox()); - - - - // - // Controls toolbar - // - qDebug() << "- Constructing toolbars"; - - actGroupControls = new QActionGroup(this); - actGroupControls->setExclusive(true); - connect(actGroupControls, SIGNAL(triggered(QAction*)), this, SLOT(actionControlChanged(QAction *))); - - createToolButton(actGroupControls, "Rewind", QIcon("rewind.png"), - "Rewind to start of the timeline", CTRL_REWIND); - - createToolButton(actGroupControls, "Play start", QIcon("play1.png"), - "Play from start", CTRL_PLAY_START); - - createToolButton(actGroupControls, "Play current", QIcon("play2.png"), - "Play from current position", CTRL_PLAY_CURRENT); - - createToolButton(actGroupControls, "Pause", QIcon("pause.png"), - "Pause", CTRL_PAUSE); - - - QToolBar *controlButtons = new QToolBar("Player controls", this); - controlButtons->setMovable(false); - controlButtons->setFloatable(false); - controlButtons->setIconSize(QSize(CTRL_ICON_SIZE, CTRL_ICON_SIZE)); - controlButtons->setToolButtonStyle(Qt::ToolButtonIconOnly); - controlButtons->addActions(actGroupControls->actions()); - - - // - // Effect resource view - // - qDebug() << "- Constructing effects resource view"; - - resourceView = new QTableView(this); - resourceView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); - resourceView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); - resourceView->setSelectionMode(QAbstractItemView::SingleSelection); - resourceView->setSelectionBehavior(QAbstractItemView::SelectRows); - resourceModel = new QEDResourceModel(this); - resourceView->setModel(resourceModel); - - // - // Construct the main screen - // - qDebug() << "- Constructing main screen layout"; - - QWidget *sideVBoxContainer = new QWidget(); - QSizePolicy sideVBoxPolicy(QSizePolicy::Fixed, QSizePolicy::Ignored); - sideVBoxPolicy.setHeightForWidth(sideVBoxContainer->sizePolicy().hasHeightForWidth()); - sideVBoxContainer->setSizePolicy(sideVBoxPolicy); - - QVBoxLayout *sideVBox = new QVBoxLayout(sideVBoxContainer); - sideVBox->setSpacing(0); - sideVBox->setContentsMargins(0, 0, 0, 0); - sideVBox->addWidget(resourceView); - sideVBox->addWidget(controlButtons); - - - QWidget *holder = new QWidget(); - QVBoxLayout *verticalSplitter = new QVBoxLayout(holder); - QHBoxLayout *horizSplitter = new QHBoxLayout(); - - - timelineScrollBar = new QScrollBar(Qt::Horizontal); - connect(timelineScrollBar, SIGNAL(valueChanged(int)), this, SLOT(actionTimelineScrollChanged(int))); - - timelineAudioTrack = new QEDWaveTrackView(); - connect(timelineAudioTrack, SIGNAL(offsetChanged(float)), this, SLOT(actionOffsetChanged(float))); - connect(timelineAudioTrack, SIGNAL(timeChanged(float)), this, SLOT(actionTimeChanged(float))); - - timelineView = new QEDTimelineView(); - connect(timelineView, SIGNAL(timelineChanged()), this, SLOT(actionTimelineChanged())); - - QScrollArea *scrollArea = new QScrollArea(); - scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); - scrollArea->setWidget(timelineView); - scrollArea->setWidgetResizable(true); - - - demoView = new QEDSWDemoView(this); - - verticalSplitter->addLayout(horizSplitter); - verticalSplitter->addWidget(scrollArea); - verticalSplitter->addWidget(timelineAudioTrack); - verticalSplitter->addWidget(timelineScrollBar); - - horizSplitter->addWidget(sideVBoxContainer); - horizSplitter->addWidget(demoView); - - - updateTimelineView(); - - setCentralWidget(holder); -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/edgui.cpp Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,522 @@ +// +// Demo Editor -- Qt GUI setup parts and callbacks +// (C) Copyright 2012 Matti 'ccr' Hämäläinen <ccr@tnsp.org> +// +#include "edmain.h" + +#include <QCloseEvent> +#include <QToolBar> +#include <QMenuBar> +#include <QStatusBar> +#include <QMenu> +#include <QProgressBar> +#include <QFileDialog> +#include <QHBoxLayout> +#include <QVBoxLayout> + + + +void DemoEditor::updateMenuStates() +{ + // Set window title based on document filename and changed status + QString name; + + if (!currTimeline || currTimeline->filename.isEmpty()) + name = DOC_DEF_FILENAME; + else + name = currTimeline->filename; + + if (currTimeline != NULL) + { + if (currTimeline->tl != NULL && currTimeline->tl->name != NULL) + name += " (" + QString(currTimeline->tl->name) + ")"; + + if (currTimeline->touched()) + name = "*" + name; + } + + setWindowTitle(name + " - " + QCoreApplication::applicationName()); + + // Enable menu items based on states + menuActSave->setEnabled(currTimeline != NULL&& currTimeline->touched()); + menuActSaveAs->setEnabled(currTimeline != NULL); + + // Enable undo/redo items and set their texts based on history status + int historyLevels = undoHistory.size(); + QString itemText; + bool itemEnabled; + + if (undoHistoryPos >= 0 && undoHistoryPos < historyLevels) + { + itemText = " " + undoHistory.at(undoHistoryPos)->state(); + itemEnabled = true; + } + else + { + itemText = ""; + itemEnabled = false; + } + + menuActRedo->setEnabled(itemEnabled); + menuActRedo->setText("&Redo" + itemText); + + if (undoHistoryPos > 0 && historyLevels > 0) + { + itemText = " " + undoHistory.at(undoHistoryPos - 1)->state(); + itemEnabled = true; + } + else + { + itemText = ""; + itemEnabled = false; + } + + menuActUndo->setEnabled(itemEnabled); + menuActUndo->setText("&Undo" + itemText); + + update(); +} + + +// +// Show about dialog +// +void DemoEditor::actionAboutBox() +{ + QMessageBox::about(this, + "About "+ QCoreApplication::applicationName(), + "<h1>" + QCoreApplication::applicationName() + + " v"+ QCoreApplication::applicationVersion() +"</h1><br>\n" + "(C) Copyright 2012 Matti 'ccr' Hämäläinen<br>\n" + "<br>\n" + "<b>A demo editor TNSP dmlib engine.</b><br>\n"); +} + + +// +// Show a dialog inquiring the user whether to save the current +// document if it has been modified since last save/load. +// +QMessageBox::StandardButton DemoEditor::showDocumentModifiedDialog() +{ + return QMessageBox::question(this, + "The document has been modified.", + "Do you want to save your changes?", + QMessageBox::Discard | QMessageBox::Cancel | QMessageBox::Save, + QMessageBox::Save); +} + + +// +// Generic error/warning dialog +// +void DemoEditor::showFileErrorDialog(QString operation, int code) +{ +/* + QString msg; + + QMessageBox::error(this, + "A non-critical error occured", + operation +*/ +} + + +void DemoEditor::actionFileNew() +{ + bool okToCreate = true; + + if (currTimeline != NULL && currTimeline->touched()) + { + okToCreate = false; + switch (showDocumentModifiedDialog()) + { + case QMessageBox::Discard: + okToCreate = true; + break; + + case QMessageBox::Save: + actionFileSave(); + if (!currTimeline->touched()) + { + QMessageBox::information(this, + "Document saved", + "The document was saved as " + currTimeline->filename); + + okToCreate = true; + } + break; + + default: + break; + } + } + + if (okToCreate) + createNewFile(); +} + + +void DemoEditor::actionFileOpen() +{ + bool okToOpen = true; + + if (currTimeline != NULL && currTimeline->touched()) + { + okToOpen = false; + + switch (showDocumentModifiedDialog()) + { + case QMessageBox::Discard: + okToOpen = true; + break; + + case QMessageBox::Save: + actionFileSave(); + if (!currTimeline->touched()) + { + QMessageBox::information(this, + "Document saved", + "The document was saved as " + currTimeline->filename); + + okToOpen = true; + } + break; + + default: + break; + } + } + + if (okToOpen) + { + QFileDialog fdialog(this); + + fdialog.setAcceptMode(QFileDialog::AcceptOpen); + fdialog.setFileMode(QFileDialog::ExistingFile); + fdialog.setNameFilter("Demo timeline files (*.demo)"); + fdialog.setDefaultSuffix("demo"); + + if (fdialog.exec()) + readFromFile(fdialog.selectedFiles()[0]); + } +} + + +void DemoEditor::actionFileSaveAs() +{ + if (!currTimeline) + { + qDebug() << "DemoEditor::actionFileSaveAs(): currTimeline == null"; + return; + } + + QFileDialog fdialog(this); + + fdialog.setAcceptMode(QFileDialog::AcceptSave); + fdialog.setFileMode(QFileDialog::AnyFile); + fdialog.setNameFilter("Demo files (*.demo)"); + fdialog.setDefaultSuffix("demo"); + fdialog.setConfirmOverwrite(true); + + fdialog.selectFile(currTimeline->filename.isEmpty() ? currTimeline->filename : DOC_DEF_FILENAME); + + if (fdialog.exec()) + saveToFile(fdialog.selectedFiles()[0]); +} + + +void DemoEditor::actionFileSave() +{ + if (!currTimeline) + { + qDebug() << "DemoEditor::actionFileSave(): currTimeline == null"; + return; + } + + // If filename has been set, save .. otherwise go to save as + if (!currTimeline->filename.isEmpty()) + saveToFile(currTimeline->filename); + else + actionFileSaveAs(); +} + + +void DemoEditor::closeEvent(QCloseEvent *event) +{ + bool okToClose = true; + + if (currTimeline && currTimeline->touched()) + { + okToClose = false; + switch (showDocumentModifiedDialog()) + { + case QMessageBox::Discard: + okToClose = true; + break; + + case QMessageBox::Save: + actionFileSave(); + if (!currTimeline->touched()) + okToClose = true; + break; + + default: + break; + } + } + + if (okToClose) + event->accept(); +} + + +// +// Various menu actions +// +void DemoEditor::actionControlChanged(QAction *act) +{ +// demoView->setToolMode(act->data().toInt()); +} + + +// +// Update statusbar message text +// +void DemoEditor::statusMsg(QString message) +{ + statusBar()->showMessage(message, 0); +} + + +// +// Set active element of an action group based on matching the data +// +void DemoEditor::setActionGroupChecked(QActionGroup *group, QVariant data) +{ + QList<QAction *> items = group->actions(); + + for (int i = 0; i < items.size(); i++) + { + QAction *act = items.at(i); + if (act->data() == data) + { + act->setChecked(true); + return; + } + } +} + + +// +// Helper functions for creating GUI elements +// +QAction * DemoEditor::createToolButton(QActionGroup *group, QString name, QIcon icon, QString statustip, QVariant data) +{ + QAction *action = new QAction(icon, name, group); + + action->setStatusTip(statustip + "."); + action->setCheckable(true); + action->setData(data); + + return action; +} + + +QAction * DemoEditor::createMenuAction(QString name, const QKeySequence &shortcut, QString tooltip) +{ + QAction *action = new QAction(name, this); + + if (shortcut != QKeySequence(QKeySequence::UnknownKey)) + action->setShortcut(shortcut); + + if (!tooltip.isNull()) + action->setStatusTip(tooltip + "."); + + return action; +} + + +QAction * DemoEditor::createMenuGroupAction(QMenu *menu, QActionGroup *group, QString name, const QKeySequence &shortcut, QString tooltip, QVariant data) +{ + QAction *action = createMenuAction(name, shortcut, tooltip); + + action->setCheckable(true); + action->setData(data); + + menu->addAction(action); + group->addAction(action); + + return action; +} + + +#define MCONNECT(menu, act, slot) do { connect(act, SIGNAL(triggered()), this, SLOT(slot)); menu->addAction(act); } while(0) + + +// +// Create GUI elements +// +void DemoEditor::createMainGUI() +{ + QAction *act; + QMenu *fileMenu, *editMenu, *viewMenu, *helpMenu; + + qDebug() << "- Constructing menus"; + + // + // File menu + // + fileMenu = menuBar()->addMenu("&File"); + + act = createMenuAction("&New", QKeySequence::New, "Create a new demo timeline"); + MCONNECT(fileMenu, act, actionFileNew()); + + menuActOpen = createMenuAction("&Open", QKeySequence::Open, "Open a demo timeline file"); + MCONNECT(fileMenu, menuActOpen, actionFileOpen()); + + menuActSave = createMenuAction("&Save", QKeySequence::Save, "Save demo timeline"); + MCONNECT(fileMenu, menuActSave, actionFileSave()); + + menuActSaveAs = createMenuAction("Save &as", QKeySequence::SaveAs, "Save demo timeline as a new file"); + MCONNECT(fileMenu, menuActSaveAs, actionFileSaveAs()); + + fileMenu->addSeparator(); + + QKeySequence qseq(Qt::CTRL + Qt::Key_Q); + act = createMenuAction("&Quit", qseq, "Exit application"); + MCONNECT(fileMenu, act, close()); + + + // + // Edit menu + // + editMenu = menuBar()->addMenu("&Edit"); + + menuActUndo = createMenuAction("&Undo", QKeySequence::Undo, "Undo last change"); + MCONNECT(editMenu, menuActUndo, performUndo()); + + menuActRedo = createMenuAction("&Redo", QKeySequence::Redo, "Redo last change"); + MCONNECT(editMenu, menuActRedo, performRedo()); + +#if 0 + editMenu->addSeparator(); + + menuActCut = createMenuAction("Cu&t", QKeySequence::Cut, "Cut object"); + MCONNECT(editMenu, menuActCut, actionCut()); + + menuActCopy = createMenuAction("&Copy", QKeySequence::Copy, "Copy object"); + MCONNECT(editMenu, menuActCopy, actionCopy()); + + menuActPaste = createMenuAction("&Paste", QKeySequence::Paste, "Paste object"); + MCONNECT(editMenu, menuActPaste, actionPaste()); + + menuActDelete = createMenuAction("&Delete", QKeySequence::Delete, "Delete object"); + MCONNECT(editMenu, menuActDelete, actionDelete()); +#endif + + // + // Help menu + // + helpMenu = menuBar()->addMenu("&Help"); + act = createMenuAction("About", 0, "Show information about application"); + MCONNECT(helpMenu, act, actionAboutBox()); + + + + // + // Controls toolbar + // + qDebug() << "- Constructing toolbars"; + + actGroupControls = new QActionGroup(this); + actGroupControls->setExclusive(true); + connect(actGroupControls, SIGNAL(triggered(QAction*)), this, SLOT(actionControlChanged(QAction *))); + + createToolButton(actGroupControls, "Rewind", QIcon("rewind.png"), + "Rewind to start of the timeline", CTRL_REWIND); + + createToolButton(actGroupControls, "Play start", QIcon("play1.png"), + "Play from start", CTRL_PLAY_START); + + createToolButton(actGroupControls, "Play current", QIcon("play2.png"), + "Play from current position", CTRL_PLAY_CURRENT); + + createToolButton(actGroupControls, "Pause", QIcon("pause.png"), + "Pause", CTRL_PAUSE); + + + QToolBar *controlButtons = new QToolBar("Player controls", this); + controlButtons->setMovable(false); + controlButtons->setFloatable(false); + controlButtons->setIconSize(QSize(CTRL_ICON_SIZE, CTRL_ICON_SIZE)); + controlButtons->setToolButtonStyle(Qt::ToolButtonIconOnly); + controlButtons->addActions(actGroupControls->actions()); + + + // + // Effect resource view + // + qDebug() << "- Constructing effects resource view"; + + resourceView = new QTableView(this); + resourceView->setHorizontalScrollBarPolicy(Qt::ScrollBarAsNeeded); + resourceView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); + resourceView->setSelectionMode(QAbstractItemView::SingleSelection); + resourceView->setSelectionBehavior(QAbstractItemView::SelectRows); + resourceModel = new QEDResourceModel(this); + resourceView->setModel(resourceModel); + + // + // Construct the main screen + // + qDebug() << "- Constructing main screen layout"; + + QWidget *sideVBoxContainer = new QWidget(); + QSizePolicy sideVBoxPolicy(QSizePolicy::Fixed, QSizePolicy::Ignored); + sideVBoxPolicy.setHeightForWidth(sideVBoxContainer->sizePolicy().hasHeightForWidth()); + sideVBoxContainer->setSizePolicy(sideVBoxPolicy); + + QVBoxLayout *sideVBox = new QVBoxLayout(sideVBoxContainer); + sideVBox->setSpacing(0); + sideVBox->setContentsMargins(0, 0, 0, 0); + sideVBox->addWidget(resourceView); + sideVBox->addWidget(controlButtons); + + + QWidget *holder = new QWidget(); + QVBoxLayout *verticalSplitter = new QVBoxLayout(holder); + QHBoxLayout *horizSplitter = new QHBoxLayout(); + + + timelineScrollBar = new QScrollBar(Qt::Horizontal); + connect(timelineScrollBar, SIGNAL(valueChanged(int)), this, SLOT(actionTimelineScrollChanged(int))); + + timelineAudioTrack = new QEDWaveTrackView(); + connect(timelineAudioTrack, SIGNAL(offsetChanged(float)), this, SLOT(actionOffsetChanged(float))); + connect(timelineAudioTrack, SIGNAL(timeChanged(float)), this, SLOT(actionTimeChanged(float))); + + timelineView = new QEDTimelineView(); + connect(timelineView, SIGNAL(timelineChanged()), this, SLOT(actionTimelineChanged())); + + QScrollArea *scrollArea = new QScrollArea(); + scrollArea->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Maximum); + scrollArea->setWidget(timelineView); + scrollArea->setWidgetResizable(true); + + + demoView = new QEDSWDemoView(this); + + verticalSplitter->addLayout(horizSplitter); + verticalSplitter->addWidget(scrollArea); + verticalSplitter->addWidget(timelineAudioTrack); + verticalSplitter->addWidget(timelineScrollBar); + + horizSplitter->addWidget(sideVBoxContainer); + horizSplitter->addWidget(demoView); + + + updateTimelineView(); + + setCentralWidget(holder); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/edmain.cpp Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,531 @@ +// +// Demo Editor -- Main program +// (C) Copyright 2012 Matti 'ccr' Hämäläinen <ccr@tnsp.org> +// +#include <SDL.h> +#include "dmengine.h" +#include "edmain.h" +#include <QSettings> +#include <QGLWidget> + + +int main(int argc, char *argv[]) +{ + dmVerbosity = 5; + + QApplication app(argc, argv); + + app.setOrganizationName("TNSP"); + app.setOrganizationDomain("tnsp.org"); + app.setApplicationName(PROGRAM_NAME); + app.setApplicationVersion(PROGRAM_VERSION); + + DemoEditor mainWin; + + mainWin.show(); + + return app.exec(); +} + + +void engineAudioCallback(void *userdata, Uint8 * stream, int len) +{ + DMEngineData *engine = (DMEngineData *) userdata; + + if (engine->paused) + { + memset(stream, 0, len); + } + else +#ifdef DM_USE_JSS + { + if (engine->dev != NULL) + jvmRenderAudio(engine->dev, stream, + len / jvmGetSampleSize(engine->dev)); + } +#endif +#ifdef DM_USE_TREMOR + if (engine->audioPos + len >= engine->audioRes->rdataSize) + { + engine->exitFlag = true; + } + else + { + memcpy(stream, (Uint8 *) engine->audioRes->rdata + engine->audioPos, len); + engine->audioPos += len; + } +#endif +} + + +int DemoEditor::reopenResources() +{ + int err; + + if ((err = dmres_init(&engine.resources, engine.optPackFilename, engine.optDataPath, + engine.optResFlags, engineClassifier)) != DMERR_OK) + { + dmError("Could not initialize resource manager: %d, %s.\n", + err, dmErrorStr(err)); + } + return err; +} + + +int DemoEditor::loadResources() +{ + int err, loaded, total; + err = dmres_preload(engine.resources, true, &loaded, &total); + + while ((err = dmres_preload(engine.resources, false, &loaded, &total)) == DMERR_PROGRESS) + { + // Show a nice progress bar while loading + if (total > 0 && (loaded % 2) == 0) + { +/* + if ((err = engineShowProgress(loaded, total)) != DMERR_OK) + return err; +*/ + } + } + return DMERR_OK; +} + + +DemoEditor::DemoEditor() +{ + int err; + + resize(1024, 768); + setWindowTitle(QCoreApplication::applicationName()); + + memset(&engine, 0, sizeof(engine)); + initSDL = FALSE; + currTimeline = NULL; + + // Pre-initialization + if ((err = demoPreInit(&engine)) != DMERR_OK) + goto error_exit; + + // Initialize SDL components + dmPrint(1, "Initializing libSDL.\n"); + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) != 0) + { + dmError("Could not initialize SDL: %s\n", SDL_GetError()); + goto error_exit; + } + initSDL = true; + + // Initialize audio parts + if (engine.optAfmt.freq == 0 && engine.optAfmt.channels == 0) + { + // Defaults, if none seem to be set + engine.optAfmt.freq = 44100; + engine.optAfmt.format = AUDIO_S16SYS; + engine.optAfmt.channels = 2; + engine.optAfmt.samples = engine.optAfmt.freq / 16; + } + +#ifdef DM_USE_JSS + jssInit(); + + switch (engine.optAfmt.format) + { + case AUDIO_S16SYS: + engine.jss_format = JSS_AUDIO_S16; + break; + case AUDIO_U16SYS: + engine.jss_format = JSS_AUDIO_U16; + break; + case AUDIO_S8: + engine.jss_format = JSS_AUDIO_S8; + break; + case AUDIO_U8: + engine.jss_format = JSS_AUDIO_U8; + break; + } + + dmPrint(1, "Initializing miniJSS mixer with fmt=%d, chn=%d, freq=%d\n", + engine.jss_format, engine.optAfmt.channels, engine.optAfmt.freq); + + if ((engine.dev = + jvmInit(engine.jss_format, engine.optAfmt.channels, + engine.optAfmt.freq, JMIX_AUTO)) == NULL) + { + dmError("jvmInit() returned NULL, voi perkele.\n"); + goto error_exit; + } + + if ((engine.plr = jmpInit(engine.dev)) == NULL) + { + dmError("jmpInit() returned NULL\n"); + goto error_exit; + } +#endif + + // Initialize SDL audio + dmPrint(1, "Trying to init SDL audio with: fmt=%d, chn=%d, freq=%d\n", + engine.optAfmt.format, engine.optAfmt.channels, + engine.optAfmt.freq); + + engine.optAfmt.callback = engineAudioCallback; + + if (SDL_OpenAudio(&engine.optAfmt, NULL) < 0) + { + dmError("Couldn't open SDL audio: %s\n", SDL_GetError()); + goto error_exit; + } + + // Initialize SDL video + if (engine.demoInitPreVideo != NULL && + (err = engine.demoInitPreVideo(&engine)) != DMERR_OK) + { + dmError("demoInitPreVideo() failed, %d: %s\n", err, dmErrorStr(err)); + goto error_exit; + } + + dmPrint(1, "Initializing SDL video %d x %d x %dbpp, flags=0x%08x\n", + engine.optVidWidth, engine.optVidHeight, engine.optVidDepth, engine.optVFlags); + + engine.screen = SDL_CreateRGBSurface(SDL_SWSURFACE, engine.optVidWidth, engine.optVidHeight, engine.optVidDepth, 0, 0, 0, 0); + if (engine.screen == NULL) + { + dmError("Could not allocate video backbuffer surface.\n"); + goto error_exit; + } + + if (engine.demoInitPostVideo != NULL && + (err = engine.demoInitPostVideo(&engine)) != DMERR_OK) + { + dmError("demoInitPostVideo() failed, %d: %s\n", err, dmErrorStr(err)); + goto error_exit; + } + + +error_exit: + + // Setup GUI elements + createMainGUI(); + createNewFile(); + timelineView->setTimeline(currTimeline); + settingsRestore(); + initEffectsAndResources(); + statusMsg("Application started."); +} + + +DemoEditor::~DemoEditor() +{ + statusMsg("Shutting down."); + + settingsSave(); + delete demoView; + historyReset(); + + if (engine.screen) + SDL_FreeSurface(engine.screen); + + SDL_LockAudio(); + SDL_PauseAudio(1); +#ifdef DM_USE_JSS + jmpClose(engine.plr); + jvmClose(engine.dev); + jssClose(); +#endif + SDL_UnlockAudio(); + + shutdownEffectsAndResources(); + + if (initSDL) + SDL_Quit(); +} + + +int DemoEditor::getTimelineDuration() +{ + return timelineAudioTrack->getDuration(); +} + + +void DemoEditor::updateResourceView() +{ +} + + +void DemoEditor::updateTimelineView() +{ + demoView->setEngineData(&engine); + + if (engine.audioRes != NULL) + { + timelineAudioTrack->setWaveform( + engine.audioRes->rdata, engine.audioRes->rdataSize, + engine.optAfmt.format, engine.optAfmt.channels, + engine.optAfmt.freq); + } + + timelineAudioTrack->setOffset(currViewOffset); + timelineAudioTrack->setScale(currViewScale); + + + timelineView->setTime(currFrameTime); + timelineView->setOffset(currViewOffset); + timelineView->setScale(currViewScale); + + timelineScrollBar->setRange(0, getTimelineDuration()); + timelineScrollBar->setValue(currViewOffset); +} + + +void DemoEditor::actionTimelineScrollChanged(int value) +{ + currViewOffset = value; + updateTimelineView(); +} + + +void DemoEditor::actionOffsetChanged(float value) +{ + currViewOffset = value; + updateTimelineView(); +} + + +void DemoEditor::actionTimeChanged(float value) +{ + currFrameTime = value; + updateTimelineView(); +} + + +void DemoEditor::actionTimelineChanged() +{ + updateMenuStates(); + update(); +} + + +int DemoEditor::initEffectsAndResources() +{ + int err; + + currViewOffset = 0; + currFrameTime = 0; + currViewScale = 1.0f; + + // Initialize resource subsystem + statusMsg("Initializing resources subsystem."); + if ((err = reopenResources()) != DMERR_OK) + return err; + + // Load resources + statusMsg("Loading resources, please wait..."); + if ((err = loadResources()) != DMERR_OK) + { + dmError("Error loading resources, %d: %s.\n", err, dmErrorStr(err)); + return err; + } + + + // Final initializations + statusMsg("Initializing custom demo data."); + if ((err = engine.demoInit(&engine)) != DMERR_OK) + { + dmError("Failure in demoInit(), %d: %s\n", + err, dmErrorStr(err)); + return err; + } + + // Initialize effects + statusMsg("Initializing effects ..."); + if ((err = engineInitializeEffects(&engine)) != DMERR_OK) + { + dmError("Effects initialization failed, %d: %s\n", + err, dmErrorStr(err)); + return err; + } + + // Etc. + rehash(); + return DMERR_OK; +} + + +void DemoEditor::shutdownEffectsAndResources() +{ + delete currTimeline; + dmFreePreparedTimelineData(engine.ptl); + engineShutdownEffects(&engine); + dmres_close(engine.resources); + + if (engine.demoShutdown != NULL) + engine.demoShutdown(&engine); +} + + +void DemoEditor::rehash() +{ + timelineView->setTimeline(currTimeline); + updateResourceView(); + updateTimelineView(); + updateMenuStates(); + update(); +} + + +void DemoEditor::createNewFile() +{ + delete currTimeline; + currTimeline = new EDTimelineObject(); + + DMTimelineTrack *tr; + dmTimelineAddTrack(currTimeline->tl, &tr, "Penis"); + + DMTimelineEvent *ev; + dmTimelineTrackAddEvent(tr, 500, 100, &ev); + + dmTimelineEventSetEffectByIndex(ev, 0); + + historyReset(); + updateMenuStates(); + update(); +} + + +void DemoEditor::readFromFile(QString filename) +{ + EDTimelineObject *tmp = new EDTimelineObject(); + int ret = tmp->load(filename); + if (ret != DMERR_OK) + { + showFileErrorDialog("Loading demo blob file "+ filename, ret); + delete tmp; + } + else + { + delete currTimeline; + currTimeline = tmp; + rehash(); + } +} + + +void DemoEditor::saveToFile(QString filename) +{ + int ret = currTimeline->save(filename); + if (ret != DMERR_OK) + { + showFileErrorDialog("Saving demo blob file "+ filename, ret); + } + + updateMenuStates(); +} + + +void DemoEditor::settingsRestore() +{ + QSettings s; + + restoreGeometry(s.value("windowGeometry").toByteArray()); + restoreState(s.value("windowState").toByteArray()); +} + + +void DemoEditor::settingsSave() +{ + QSettings s; + + s.setValue("windowGeometry", saveGeometry()); + s.setValue("windowState", saveState()); +} + + +// +// Edit history functionality +// +void DemoEditor::historyReset() +{ + if (currTimeline != NULL) + currTimeline->scrub(); + + undoHistoryPos = -1; + undoHistoryMax = DOC_UNDO_MAX; + undoHistory.clear(); +} + + +void DemoEditor::historyPush(QString description) +{ + if (currTimeline == NULL) + return; + + if (!undoHistory.isEmpty() && undoHistory.last()->state() == "-") + { + delete undoHistory.takeLast(); + } + + while (undoHistory.size() >= undoHistoryMax) + { + delete undoHistory.takeFirst(); + } + + EDTimelineObject *copy = new EDTimelineObject(currTimeline); + copy->setState(description); + undoHistory.append(copy); +} + + +void DemoEditor::historyTop() +{ + if (currTimeline == NULL) + return; + + EDTimelineObject *copy = new EDTimelineObject(currTimeline); + copy->setState("-"); + undoHistory.append(copy); + + undoHistoryPos = undoHistory.size() - 1; + currTimeline->touch(); + updateTimelineView(); + updateMenuStates(); + update(); +} + + +void DemoEditor::historyPop() +{ + if (!undoHistory.isEmpty()) + { + delete undoHistory.takeLast(); + } +} + + +void DemoEditor::performRedo() +{ + if (undoHistoryPos >= 0 && undoHistoryPos < undoHistory.size() - 1) + { + undoHistoryPos++; + delete currTimeline; + currTimeline = new EDTimelineObject(undoHistory.at(undoHistoryPos)); + currTimeline->touch(); + updateTimelineView(); + updateMenuStates(); + update(); + } +} + + +void DemoEditor::performUndo() +{ + if (undoHistoryPos > 0 && undoHistory.size() > 1) + { + undoHistoryPos--; + delete currTimeline; + currTimeline = new EDTimelineObject(undoHistory.at(undoHistoryPos)); + currTimeline->touch(); + updateTimelineView(); + updateMenuStates(); + update(); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/edmain.h Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,132 @@ +#ifndef EDMAIN_H +#define EDMAIN_H + +// Program name etc +#define PROGRAM_NAME "DMPE Editor" +#define PROGRAM_VERSION "0.1" + +// Defaults +#define DOC_DEF_FILENAME "Untitled" +#define DOC_UNDO_MAX 15 + +enum +{ + CTRL_REWIND, + CTRL_PLAY_START, + CTRL_PLAY_CURRENT, + CTRL_PAUSE +}; + +#define CTRL_ICON_SIZE 32 + +#include "edtlobj.h" +#include "edview.h" +#include "edwaveform.h" +#include "edtimeline.h" +#include "edres.h" +#include <QDebug> +#include <QFile> +#include <QApplication> +#include <QMainWindow> +#include <QTableView> +#include <QAction> +#include <QActionGroup> +#include <QSlider> +#include <QMessageBox> +#include <QCheckBox> +#include <QScrollBar> + +class DemoEditor : public QMainWindow +{ + Q_OBJECT + +public: + DemoEditor(); + ~DemoEditor(); + + void settingsRestore(); + void settingsSave(); + + +private slots: + void actionFileNew(); + void actionFileOpen(); + void actionFileSave(); + void actionFileSaveAs(); + + void actionAboutBox(); + + //void actionCut(); + //void actionCopy(); + //void actionPaste(); + //void actionDelete(); + + void performUndo(); + void performRedo(); + + void actionControlChanged(QAction *); + void actionTimelineScrollChanged(int); + void actionOffsetChanged(float); + void actionTimeChanged(float); + void actionTimelineChanged(); + +private: + QAction *menuActUndo, *menuActRedo, *menuActOpen, *menuActSave, *menuActSaveAs; +// QAction *menuActCut, *menuActCopy, *menuActPaste, *menuActDelete; + QActionGroup *actGroupControls; + QScrollBar *timelineScrollBar; + QTableView *resourceView; + QEDResourceModel *resourceModel; + QEDWaveTrackView *timelineAudioTrack; + QEDTimelineView *timelineView; + QEDGLDemoView *demoView; + + + + QAction * createToolButton(QActionGroup *group, QString name, QIcon icon, QString statustip, QVariant data); + QAction * createMenuAction(QString name, const QKeySequence &shortcut, QString tooltip); + QAction * createMenuGroupAction(QMenu *, QActionGroup *, QString name, const QKeySequence &shortcut, QString tooltip, QVariant data); + void setActionGroupChecked(QActionGroup *group, QVariant data); + + + void showFileErrorDialog(QString operation, int code); + QMessageBox::StandardButton showDocumentModifiedDialog(); + void statusMsg(QString message); + void closeEvent(QCloseEvent *event); + void createMainGUI(); + void updateResourceView(); + void updateMenuStates(); + void updateTimelineView(); + + int initEffectsAndResources(); + void shutdownEffectsAndResources(); + void rehash(); + int reopenResources(); + int loadResources(); + bool initializeVideo(); + int getTimelineDuration(); + + void createNewFile(); + void readFromFile(QString filename); + void saveToFile(QString filename); + + + bool initSDL; + float currViewScale; + int currViewOffset; + int currFrameTime; + + EDTimelineObject *currTimeline; + DMEngineData engine; + + QList<EDTimelineObject *> undoHistory; + int undoHistoryPos, undoHistoryMax; + + void historyReset(); + void historyPush(QString description); + void historyTop(); + void historyPop(); +}; + + +#endif // EDMAIN_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/edres.cpp Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,74 @@ +#include "edres.h" +#include "dmengine.h" + + +QEDResourceModel::QEDResourceModel(QObject *parent) + : QAbstractTableModel(parent) +{ +} + + +int QEDResourceModel::rowCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return nengineEffects; +} + + +int QEDResourceModel::columnCount(const QModelIndex &parent) const +{ + Q_UNUSED(parent); + return 2; +} + + +QVariant QEDResourceModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() >= nengineEffects || index.row() < 0) + return QVariant(); + + if (role == Qt::DisplayRole) + { + DMEffect *ef = &engineEffects[index.row()]; + switch (index.column()) + { + case 0: + return QString(ef->name); + + case 1: + return QVariant(ef->nparams); + } + } + return QVariant(); +} + + +QVariant QEDResourceModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (role != Qt::DisplayRole) + return QVariant(); + + if (orientation == Qt::Horizontal) + { + switch (section) { + case 0: + return "Name"; + + case 1: + return "# params"; + } + } + return QVariant(); +} + + +Qt::ItemFlags QEDResourceModel::flags(const QModelIndex &index) const +{ + if (!index.isValid()) + return Qt::ItemIsEnabled; + + return QAbstractTableModel::flags(index); // | Qt::ItemIsEditable; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/edres.h Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,26 @@ +#ifndef RESOURCEMODEL_H +#define RESOURCEMODEL_H + +#include <QAbstractTableModel> +#include <QPair> +#include <QList> + +class QEDResourceModel : public QAbstractTableModel +{ + Q_OBJECT + +public: + QEDResourceModel(QObject *parent = 0); + + int rowCount(const QModelIndex &parent) const; + int columnCount(const QModelIndex &parent) const; + QVariant data(const QModelIndex &index, int role) const; + QVariant headerData(int section, Qt::Orientation orientation, int role) const; + Qt::ItemFlags flags(const QModelIndex &index) const; +// bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); +// QList< QPair<QString, QString> > getList(); + +private: +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/edtimeline.cpp Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,471 @@ +#include <QtGui> +#include "edtimeline.h" + + +QEDTimelineTrackDisplay::QEDTimelineTrackDisplay(QWidget *parent) : QWidget(parent) +{ + track = NULL; + time = offs = 0; + scale = 1.0f; + + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); +} + + +QSize QEDTimelineTrackDisplay::minimumSizeHint() const +{ + return QSize(100, 60); +} + + +QSize QEDTimelineTrackDisplay::sizeHint() const +{ + return QSize(600, 60); +} + + +void QEDTimelineTrackDisplay::setTrack(DMTimelineTrack *mtrack) +{ + track = mtrack; +} + + +float QEDTimelineTrackDisplay::getTimeScale(float value) +{ + return value * scale; +} + + +float QEDTimelineTrackDisplay::getTimeFromCoord(float value) +{ + return value * scale * 1000.0f; +} + + +void QEDTimelineTrackDisplay::setTime(const float mtime) +{ + if (time != mtime && mtime >= 0) + { + time = mtime; + emit timeChanged(time); + } +} + + +void QEDTimelineTrackDisplay::setOffset(const float moffs) +{ + if (offs != moffs && moffs >= 0) + { + offs = moffs; + emit offsetChanged(offs); + } +} + + +void QEDTimelineTrackDisplay::setScale(const float mscale) +{ + if (mscale > 0.05) + scale = mscale; +} + + +void QEDTimelineTrackDisplay::setSelection(const float mstart, const float mend) +{ + if (mstart >= 0 && mend >= 0 && fabs(mend - mstart) > 0) + { + selectionValid = true; + if (mend > mstart) + { + selectionStart = mstart; + selectionDuration = mend - mstart + 1; + } + else + { + selectionStart = mend; + selectionDuration = mstart - mend + 1; + } + emit selectionChanged(selectionStart, selectionDuration); + } +} + + +void QEDTimelineTrackDisplay::clearSelection() +{ + selectionValid = false; + selectionStart = 0; + selectionDuration = 0; + emit selectionChanged(selectionStart, selectionDuration); +} + + +bool QEDTimelineTrackDisplay::getSelection(float *mstart, float *mduration) +{ + if (selectionValid) + { + *mstart = selectionStart; + *mduration = selectionDuration; + } + return selectionValid; +} + + +QList<DMTimelineEvent *> QEDTimelineTrackDisplay::getEventsAt(const int time) +{ + QList<DMTimelineEvent *> list; + + for (int event = 0; event < track->nevents; event++) + { + DMTimelineEvent *ev = track->events[event]; + if (time >= ev->start && time <= ev->start + ev->duration) + list.append(ev); + } + + return list; +} + + + +QList<DMTimelineEvent *> QEDTimelineTrackDisplay::getEventsForRange(const int start, const int duration) +{ + QList<DMTimelineEvent *> list; + + for (int event = 0; event < track->nevents; event++) + { + DMTimelineEvent *ev = track->events[event]; + } + + return list; +} + + +void QEDTimelineTrackDisplay::paintEvent(QPaintEvent *) +{ + if (track == NULL) + return; + + QColor eventColor(150, 150, 150, 128); + QColor invalidEventColor(250, 150, 150, 128); + QColor eventBorder(200, 250, 200, 200); + QColor eventParam(200, 150, 100); + QColor eventText(255, 255, 255); + QColor markerColor(255,255,255); + QColor selectionColor(0,255,0, 150); + QColor selectionEnd(0,255,0, 200); + + QFont fantti; + fantti.setFamily("Arial"); + fantti.setPointSizeF(8.0f); + fantti.setStyleHint(QFont::SansSerif); + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + + + painter.save(); + painter.scale(scale, 1); + + float wd = getTimeScale(width()); + for (int event = 0; event < track->nevents; event++) + { + DMTimelineEvent *ev = track->events[event]; + + float x0 = getTimeScale(ev->start - offs), + x1 = getTimeScale(ev->start + ev->duration - offs); + + if ((x0 >= 0 && x0 < wd) || (x0 < 0 && x1 >= 0)) + { + painter.setFont(fantti); + painter.setBrush(ev->effect != NULL ? eventColor : invalidEventColor); + painter.setPen(eventBorder); + x0 = ev->start - offs; + x1 = ev->duration; + painter.fillRect(x0, 0, x1, height(), eventColor); + + QPainterPath path; + path.addText(QPointF(x0 + 2, 10), fantti, ev->effect != NULL ? QString(ev->effect->name) : "INVALID"); + + painter.save(); + painter.translate(1,1); + painter.setPen(Qt::black); + painter.setBrush(Qt::black); + painter.drawPath(path); + painter.restore(); + + painter.setPen(eventText); + painter.setBrush(eventText); + painter.drawPath(path); + } + + } + + painter.restore(); + + if (selectionValid) + { + float x0 = getTimeScale(selectionStart - offs), + x1 = getTimeScale(selectionStart + selectionDuration - offs); + + if ((x0 >= 0 && x0 < wd) || (x0 < 0 && x1 >= 0)) + { + painter.setBrush(selectionColor); + painter.setPen(selectionEnd); + x0 = selectionStart - offs; + x1 = selectionDuration; + painter.fillRect(x0, 0, x1, height(), eventColor); + + painter.drawLine(x0, 0, x0, height()); + painter.drawLine(x1, 0, x1, height()); + } + } + + + if (time >= offs * scale && time - offs <= width() * scale) + { + int xc = time - offs; + painter.save(); + painter.scale(scale, 1); + painter.setPen(markerColor); + painter.drawLine(xc, 0, xc, height()); + painter.restore(); + } +} + + +void QEDTimelineTrackDisplay::mousePressEvent(QMouseEvent *ev) +{ + switch (ev->button()) + { + case Qt::LeftButton: + if (parent->getActiveTrack() != this) + emit trackActivated(this); + + selectionPoint = ev->pos(); + selectionOffs = offs / scale; + selecting = false; + break; + + case Qt::RightButton: + dragPoint = ev->pos(); + dragOffs = offs / scale; + dragging = false; + break; + + default: + break; + } +} + + +void QEDTimelineTrackDisplay::mouseMoveEvent(QMouseEvent *ev) +{ + if ((ev->buttons() & Qt::LeftButton) && ev->pos().x() != selectionPoint.x()) + { + selecting = true; + setSelection(selectionOffs, offs + (ev->pos().x() - selectionPoint.x()) / scale); + } + if ((ev->buttons() & Qt::RightButton) && ev->pos().x() != dragPoint.x()) + { + dragging = true; + setOffset(dragOffs - (ev->pos().x() - dragPoint.x()) / scale); + } +} + + +void QEDTimelineTrackDisplay::mouseReleaseEvent(QMouseEvent *ev) +{ + if (ev->button() == Qt::LeftButton) + { + if (selecting) + { + selecting = false; + setSelection(selectionOffs + (ev->pos().x() - selectionPoint.x()) / scale); + } + } + else + if (ev->button() == Qt::RightButton && !dragging) + { + setTime(offs + getTimeFromCoord(ev->pos().x())); + } +} + + +QEDTimelineTrackView::QEDTimelineTrackView(QWidget *parent) : QWidget(parent) +{ + QHBoxLayout *mainLayout = new QHBoxLayout(this); + mainLayout->setMargin(0); + track = new QEDTimelineTrackDisplay(this); + + QFrame *infoLayoutContainer = new QFrame(this); + infoLayoutContainer->setFrameStyle(QFrame::StyledPanel | QFrame::Plain); + infoLayoutContainer->setLineWidth(2); + infoLayoutContainer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); + infoLayoutContainer->setFixedWidth(200); + + QVBoxLayout *infoLayout = new QVBoxLayout(infoLayoutContainer); + infoLayout->setMargin(0); + infoName = new QLineEdit(); + infoName->setFrame(false); + infoName->setMaxLength(DT_MAX_NAME_LENGTH); + infoName->setStyleSheet("QLineEdit { background-color: black; color: white; padding: 2px; }"); + connect(infoName, SIGNAL(textEdited(const QString&)), this, SLOT(slotTrackNameChanged(const QString&))); + infoLayout->addWidget(infoName); + + + enabledCheck = new QCheckBox("Enabled"); + infoLayout->addWidget(enabledCheck); + connect(enabledCheck, SIGNAL(toggled(bool)), this, SLOT(slotTrackEnabledChanged(bool))); + + infoData = new QLabel(); + infoData->setStyleSheet("QLabel { padding: 2px; }"); + infoLayout->addWidget(infoData); + + mainLayout->addWidget(infoLayoutContainer); + mainLayout->addWidget(track); +} + + +void QEDTimelineTrackView::update() +{ + if (track != NULL && track->track) + { + infoName->setText(QString(track->track->name)); + enabledCheck->setChecked(track->track->enabled); + infoData->setText(QString("<b>%1</b> events").arg(track->track->nevents)); + } + else + { + infoName->setText(""); + infoData->setText("-"); + enabledCheck->setChecked(false); + } + + QWidget::update(); +} + + +void QEDTimelineTrackView::setTrack(DMTimelineTrack *mtrack) +{ + track->setTrack(mtrack); + update(); +} + + +void QEDTimelineTrackView::slotTrackEnabledChanged(bool value) +{ + track->track->enabled = value; + emit trackChanged(); +} + + +void QEDTimelineTrackView::slotTrackNameChanged(const QString & text) +{ + QByteArray ba = text.toUtf8(); + track->track->name = dm_strdup(ba.constData()); + emit trackChanged(); +} + + + +QEDTimelineView::QEDTimelineView(QWidget *parent) : QWidget(parent) +{ + layout = new QVBoxLayout(this); + tl = NULL; +} + + +void QEDTimelineView::setTimeline(EDTimelineObject *mtl) +{ + tl = mtl; + + delete layout; + layout = new QVBoxLayout(this); + layout->setMargin(0); + + tracks.clear(); + + if (tl != NULL && tl->tl != NULL) + { + for (int track = 0; track < tl->tl->ntracks; track++) + { + QEDTimelineTrackView *vtr = new QEDTimelineTrackView(this); + vtr->setTrack(tl->tl->tracks[track]); + tracks.append(vtr); + layout->addWidget(vtr); + connect(vtr, SIGNAL(trackChanged()), this, SLOT(slotTimelineChanged())); + connect(vtr, SIGNAL(timeChanged(float)), this, SLOT(slotTimeChanged(float))); + connect(vtr, SIGNAL(offsetChanged(float)), this, SLOT(slotOffsetChanged(float))); + connect(vtr, SIGNAL(selectionChanged(float,float)), this, SLOT(slotSelectionChanged(float,float))); + } + } + update(); +} + + +void QEDTimelineView::slotTimelineChanged() +{ + if (tl != NULL) + { + tl->touch(); + emit timelineChanged(); + } +} + + +void QEDTimelineView::setTime(const int mtime) +{ + if (tl != NULL && tl->tl != NULL) + { + QList<QEDTimelineTrackView *>::iterator track; + for (track = tracks.begin(); track != tracks.end(); track++) + { + (*track)->track->setTime(mtime); + } + update(); + } +} + + +void QEDTimelineView::setOffset(const int moffs) +{ + if (tl != NULL && tl->tl != NULL) + { + QList<QEDTimelineTrackView *>::iterator track; + for (track = tracks.begin(); track != tracks.end(); track++) + { + (*track)->track->setOffset(moffs); + } + update(); + } +} + + +void QEDTimelineView::setScale(const float mscale) +{ + if (tl != NULL && tl->tl != NULL) + { + QList<QEDTimelineTrackView *>::iterator track; + for (track = tracks.begin(); track != tracks.end(); track++) + { + (*track)->track->setScale(mscale); + } + update(); + } +} + + +QList<DMTimelineEvent *> QEDTimelineView::getEventsAt(const int time) +{ + if (tl != NULL && tl->tl != NULL && + activeTrack >= 0 && activeTrack < tl->tl->ntracks) + { + return tracks[activeTrack]->tl->getEventsAt(time); + } + else + return QList<DMTimelineEvent *>(); +} + + +QList<DMTimelineEvent *> QEDTimelineView::getEventsForRange(const int start, const int duration) +{ +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/edtimeline.h Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,121 @@ +#ifndef EDTIMELINE_H +#define EDTIMELINE_H + +#include <QWidget> +#include <QCheckBox> +#include <QVBoxLayout> +#include <QLabel> +#include <QLineEdit> +#include "edtlobj.h" +#include "dmengine.h" + + +class QEDTimelineTrackDisplay : public QWidget +{ + Q_OBJECT + +public: + DMTimelineTrack *track; + + QEDTimelineTrackDisplay(QWidget *parent = 0); + void setTrack(DMTimelineTrack *mtrack); + + float getTimeScale(float value); + float getTimeFromCoord(float value); + + void setScale(const float mscale); + + bool getSelection(float *mstart, float *mduration); + QList<DMTimelineEvent *> getEventsAt(const int time); + QList<DMTimelineEvent *> getEventsForRange(const int start, const int duration); + + QSize minimumSizeHint() const; + QSize sizeHint() const; + +public slots: + void setTime(const float mtime); + void setOffset(const float moffs); + void setSelection(const float mstart, const float mend); + void clearSelection(); + +signals: + void selectionChanged(float mstart, float mduration); + void timeChanged(float value); + void offsetChanged(float value); + +protected: + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + + void paintEvent(QPaintEvent *event); + +private: + float scale, time, offs; + + bool selectionValid; + float selectionStart, selectionDuration; + + QPoint selectionPoint, dragPoint; + bool selecting, dragging; + float selectionOffs, dragOffs; +}; + + +class QEDTimelineTrackView : public QWidget +{ + Q_OBJECT + +private: + QLineEdit *infoName; + QLabel *infoData; + QCheckBox *enabledCheck; + +public: + QEDTimelineTrackDisplay *track; + + QEDTimelineTrackView(QWidget *parent = 0); + void setTrack(DMTimelineTrack *mtrack); + void update(); + +private slots: + void slotTrackEnabledChanged(bool); + void slotTrackNameChanged(const QString & text); + +signals: + void trackChanged(); + void selectionChanged(float mstart, float mduration); + void timeChanged(float value); + void offsetChanged(float value); +}; + + +class QEDTimelineView : public QWidget +{ + Q_OBJECT + +private: + QVBoxLayout *layout; + + EDTimelineObject *tl; + QList<QEDTimelineTrackView *> tracks; + int activeTrack; + +public: + QEDTimelineView(QWidget *parent = 0); + void setTimeline(EDTimelineObject *mtl); + + void setTime(const float mtime); + void setOffset(const float moffs); + void setScale(const float mscale); + +private slots: + void slotTimelineChanged(); + +signals: + void timelineChanged(); + void timeChanged(float value); + void offsetChanged(float value); +}; + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/edtlobj.cpp Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,102 @@ +// +// Demo Editor -- Timeline state object +// Wrapper class for DMTimeline data +// (C) Copyright 2012 Matti 'ccr' Hämäläinen <ccr@tnsp.org> +// +#include "edtlobj.h" +#include "dmres.h" + + +EDTimelineObject::EDTimelineObject() +{ + dmTimelineNew(&tl, "Demo"); + scrub(); +} + + +EDTimelineObject::EDTimelineObject(EDTimelineObject *obj) +{ + scrub(); + filename = obj->filename; + dmCopyTimeline(obj->tl, &tl); +} + + +EDTimelineObject::~EDTimelineObject() +{ + dmFreeTimeline(tl); +} + + +int EDTimelineObject::load(QString mfilename) +{ + QByteArray fnba = mfilename.toUtf8(); + DMResource *res; + DMTimeline *tmp; + if ((res = dmf_create_stdio(fnba.data(), "rb")) == NULL) + return DMERR_FOPEN; + + int err = dmLoadTimeline(res, &tmp); + dmf_close(res); + + if (err == DMERR_OK) + { + dmFreeTimeline(tl); + tl = tmp; + scrub(); + if (tl->name != NULL) + filename = QString(tl->name); + else + filename = mfilename; + } + else + { + dmFreeTimeline(tmp); + } + return err; +} + + +int EDTimelineObject::save(QString mfilename) +{ + QByteArray fnba = mfilename.toUtf8(); + DMResource *res; + if ((res = dmf_create_stdio(fnba.data(), "wb")) == NULL) + return DMERR_FOPEN; + + int err = dmSaveTimeline(res, tl); + scrub(); + + dmf_close(res); + return err; +} + + +void EDTimelineObject::touch() +{ + ntouches++; +} + + +void EDTimelineObject::scrub() +{ + ntouches = 0; +} + + +bool EDTimelineObject::touched() +{ + return ntouches; +} + + +void EDTimelineObject::setState(const QString &mstate) +{ + cstate = mstate; +} + + +QString EDTimelineObject::state() const +{ + return cstate; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/edtlobj.h Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,38 @@ +// +// Demo Editor -- Timeline state object +// Wrapper class for DMTimeline data +// (C) Copyright 2012 Matti 'ccr' Hämäläinen <ccr@tnsp.org> +// +#ifndef EDTIMELINEOBJECT_H +#define EDTIMELINEOBJECT_H + +#include "dmengine.h" +#include <QString> + +class EDTimelineObject +{ +private: + QString cstate; + int ntouches; + +public: + QString filename; + DMTimeline *tl; + + EDTimelineObject(); + EDTimelineObject(EDTimelineObject *); + ~EDTimelineObject(); + + int load(QString filename); + int save(QString filename); + + void scrub(); + void touch(); + bool touched(); + + void setState(const QString &mstate); + QString state() const; +}; + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/edview.cpp Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,148 @@ +#include "edview.h" +#include <QtGui> + + +QEDGLDemoView::QEDGLDemoView(QWidget *parent) : + QGLWidget(QGLFormat(QGL::SampleBuffers|QGL::AlphaChannel), parent) +{ + makeCurrent(); + + if (QGLFramebufferObject::hasOpenGLFramebufferBlit()) + { + QGLFramebufferObjectFormat format; + format.setSamples(4); + format.setAttachment(QGLFramebufferObject::CombinedDepthStencil); + +// render_fbo = new QGLFramebufferObject(512, 512, format); +// texture_fbo = new QGLFramebufferObject(512, 512); + } + else + { +// render_fbo = new QGLFramebufferObject(1024, 1024); +// texture_fbo = render_fbo; + } + + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); +} + + +QEDGLDemoView::~QEDGLDemoView() +{ +} + + +QSize QEDGLDemoView::minimumSizeHint() const +{ + return QSize(320, 240); +} + + +QSize QEDGLDemoView::sizeHint() const +{ + return QSize(640, 480); +} + + +void QEDGLDemoView::setEngineData(DMEngineData *mengine) +{ + engine = mengine; +} + + +void QEDGLDemoView::render(int frameTime) +{ + if (engine != NULL) + { + engine->frameTime = frameTime; + + if (engine->demoRender != NULL) + { + engine->demoRender(engine); + } + else + { + dmExecuteTimeline(engine->ptl, engine->screen, engineGetTick(engine)); + } + + engine->frameCount++; + } +} + + +void QEDGLDemoView::paintEvent(QPaintEvent *) +{ + // save the GL state set for QPainter + saveGLState(); + + // restore the GL state that QPainter expects + restoreGLState(); +} + + +void QEDGLDemoView::saveGLState() +{ + glPushAttrib(GL_ALL_ATTRIB_BITS); + glMatrixMode(GL_PROJECTION); + glPushMatrix(); + glMatrixMode(GL_MODELVIEW); + glPushMatrix(); +} + + +void QEDGLDemoView::restoreGLState() +{ + glMatrixMode(GL_PROJECTION); + glPopMatrix(); + glMatrixMode(GL_MODELVIEW); + glPopMatrix(); + glPopAttrib(); +} + + +QEDSWDemoView::QEDSWDemoView(QWidget *parent) : QEDGLDemoView(parent) +{ + img = NULL; +} + + +QEDSWDemoView::~QEDSWDemoView() +{ + delete img; +} + + +void QEDSWDemoView::setEngineData(DMEngineData *mengine) +{ + engine = mengine; + delete img; + + img = new QImage((const uchar *)mengine->screen->pixels, + mengine->screen->w, mengine->screen->h, + mengine->screen->pitch, QImage::Format_RGB32); +} + + +void QEDSWDemoView::paintEvent(QPaintEvent *) +{ + if (img != NULL) + { + QPainter painter(this); + painter.drawImage(QPoint(0, 0), *img); + } +} + + +void QEDSWDemoView::render(int frameTime) +{ + if (SDL_MUSTLOCK(engine->screen) != 0 && SDL_LockSurface(engine->screen) != 0) + return; + + QEDGLDemoView::render(frameTime); + + if (SDL_MUSTLOCK(engine->screen) != 0) + SDL_UnlockSurface(engine->screen); + + update(); +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/edview.h Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,50 @@ +#ifndef EDVIEW_H +#define EDVIEW_H + +#include <QtOpenGL> +#include <QImage> +#include "dmengine.h" + + +class QEDGLDemoView : public QGLWidget +{ + Q_OBJECT + +public: + QEDGLDemoView(QWidget *parent); + ~QEDGLDemoView(); + + QSize minimumSizeHint() const; + QSize sizeHint() const; + + virtual void setEngineData(DMEngineData *mengine); + virtual void render(int frameTime); + void paintEvent(QPaintEvent *); + +private: + void saveGLState(); + void restoreGLState(); + +protected: + DMEngineData *engine; +}; + + +class QEDSWDemoView : public QEDGLDemoView +{ + Q_OBJECT + +public: + QEDSWDemoView(QWidget *parent); + ~QEDSWDemoView(); + + void setEngineData(DMEngineData *mengine); + void render(int frameTime); + void paintEvent(QPaintEvent *); + +private: + QImage *img; +}; + + +#endif
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/edwaveform.cpp Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,418 @@ +#include <QtGui> +#include <SDL_audio.h> +#include "edwaveform.h" + + +QEDWaveTrackDisplay::QEDWaveTrackDisplay(QWidget *parent) : QWidget(parent) +{ + data = NULL; + size = 0; + format = AUDIO_S16SYS; + channels = 1; + freq = 1; + scale = 1.0f; + time = offs = 0; + duration = 0; + sduration = 0; + + setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); +} + + +void QEDWaveTrackDisplay::setWaveform(void *mdata, int msize, int mformat, int mchannels, int mfreq) +{ + data = mdata; + size = msize; + format = mformat; + channels = mchannels; + freq = mfreq; + + int bps = getBps(); + if (bps != 0) + { + // Duration in milliseconds + duration = ((float) (size / bps) / (float) freq) * 1000.0f; + + // Duration in samples + sduration = msize / bps; + } + else + { + duration = 0; + sduration = 0; + } + + update(); +} + + +int QEDWaveTrackDisplay::getBps() +{ + int bps = channels; + switch (format) + { + case AUDIO_S16SYS: + case AUDIO_U16SYS: + bps *= sizeof(quint16); + break; + case AUDIO_S8: + case AUDIO_U8: + bps *= sizeof(quint8); + break; + } + return bps; +} + + +float QEDWaveTrackDisplay::getDuration() +{ + return duration; +} + + +float QEDWaveTrackDisplay::getTimeScale(float value) +{ + return (value * scale * (float) freq) / 1000.0f; +} + + +float QEDWaveTrackDisplay::getTimeFromCoord(float value) +{ + return value * scale; +} + + +void QEDWaveTrackDisplay::setTime(const float mtime) +{ + if (time != mtime && mtime >= 0 && mtime < duration) + { + time = mtime; + emit timeChanged(time); + } +} + + +void QEDWaveTrackDisplay::setOffset(const float moffs) +{ + if (offs != moffs && moffs >= 0 && moffs < getDuration()) + { + offs = moffs; + emit offsetChanged(offs); + } +} + + +void QEDWaveTrackDisplay::setScale(const float mscale) +{ + if (mscale > 0.05) + scale = mscale; + emit scaleChanged(scale); +} + + +void QEDWaveTrackDisplay::setSelection(const float mstart, const float mend) +{ + if (mstart >= 0 && mend >= 0 && fabs(mend - mstart) > 0) + { + selectionValid = true; + if (mend > mstart) + { + selectionStart = mstart; + selectionDuration = mend - mstart + 1; + } + else + { + selectionStart = mend; + selectionDuration = mstart - mend + 1; + } + emit selectionChanged(selectionStart, selectionDuration); + } +} + + +void QEDWaveTrackDisplay::clearSelection() +{ + selectionValid = false; + selectionStart = 0; + selectionDuration = 0; + emit selectionChanged(selectionStart, selectionDuration); +} + + +bool QEDTimelineTrackDisplay::getSelection(float *mstart, float *mduration) +{ + if (selectionValid) + { + *mstart = selectionStart; + *mduration = selectionDuration; + } + return selectionValid; +} + + +float QEDWaveTrackDisplay::getScaledWidth() +{ + return getTimeScale(width()); +} + + +float QEDWaveTrackDisplay::getTime() +{ + return time; +} + + +float QEDWaveTrackDisplay::getOffset() +{ + return offs; +} + + +void QEDWaveTrackDisplay::paintEvent(QPaintEvent *) +{ + QColor waveColor(0, 150, 0); + QColor waveCenterLine(100, 100, 100); + QColor markerColor(255,255,255); + QColor bgColor(0, 0, 0);//255, 255, 255); + + QPainter painter(this); + painter.setRenderHint(QPainter::Antialiasing); + painter.fillRect(QRect(0, 0, width(), height()), bgColor); + + if (data != NULL) + { + int voffs = 0; + + painter.save(); + painter.translate(0, height() / 2); + + painter.setPen(waveCenterLine); + painter.drawLine(0, 0, width(), 0); + + switch (format) + { + case AUDIO_S16SYS: + painter.scale(1.0f, (float) height() / 32768.0f); + break; + case AUDIO_U16SYS: + voffs = -32768; + painter.scale(1.0f, height() / 32768.0f); + break; + + case AUDIO_S8: + painter.scale(1.0f, height() / 128.0f); + break; + case AUDIO_U8: + voffs = -128; + painter.scale(1.0f, height() / 128.0f); + break; + } + + painter.scale(1.0f, 0.5f); + painter.setPen(waveColor); + + float mscale = (scale * (float)freq) / 1000.0f; + int prevY = 0, prevX = 0; + if (format == AUDIO_S16SYS || format == AUDIO_U16SYS) + { + qint16 *buf = (qint16 *) data; + for (int xc = 0; xc < width(); xc++) + { + int moffs = (int) (((offs + xc) * mscale)); + if (moffs >= sduration) break; + int value = buf[moffs * channels] + voffs; + painter.drawLine(prevX, prevY, xc, value); + prevY = value; + prevX = xc; + } + } + else + if (format == AUDIO_S8 || format == AUDIO_U8) + { + qint8 *buf = (qint8 *) data; + for (int xc = 0; xc < width(); xc++) + { + int moffs = (int) (((offs + xc) * mscale)); + if (moffs >= sduration) break; + int value = buf[moffs * channels] + voffs; + painter.drawLine(prevX, prevY, xc, value); + prevY = value; + prevX = xc; + } + } + + painter.restore(); + } + + float xc = getTimeScale(time - offs), wd = getTimeScale(width()); + if (xc >= 0 && xc <= wd) + { + xc = time - offs; + painter.scale(scale, 1.0f); + painter.setPen(markerColor); + painter.drawLine(xc, 0, xc, height()); + } +} + + +void QEDWaveTrackDisplay::mousePressEvent(QMouseEvent *ev) +{ + switch (ev->button()) + { + case Qt::LeftButton: + selectionPoint = ev->pos(); + selectionOffs = offs; + selecting = false; + break; + + case Qt::RightButton: + dragPoint = ev->pos(); + dragOffs = offs; + dragging = false; + break; + + default: + break; + } +} + + +void QEDWaveTrackDisplay::mouseMoveEvent(QMouseEvent *ev) +{ + if ((ev->buttons() & Qt::LeftButton) && ev->pos().x() != selPoint.x()) + { + selecting = true; + setSelection(selectionOffs + (ev->pos().x() - selectionPoint.x()) / scale); + } + if ((ev->buttons() & Qt::RightButton) && ev->pos().x() != dragPoint.x()) + { + dragging = true; + setOffset(dragOffs - (ev->pos().x() - dragPoint.x()) / scale); + } +} + + +void QEDWaveTrackDisplay::mouseReleaseEvent(QMouseEvent *ev) +{ + if (ev->button() == Qt::LeftButton) + { + if (selecting) + { + selecting = false; + setSelection(selOffs + (ev->pos().x() - selPoint.x()) / scale); + } + } + else + if (ev->button() == Qt::RightButton && !dragging) + { + setTime(offs + getTimeFromCoord(ev->pos().x())); + } +} + + +QEDWaveTrackView::QEDWaveTrackView(QWidget *parent) : QWidget(parent) +{ + QHBoxLayout *mainLayout = new QHBoxLayout(this); + mainLayout->setMargin(0); + wave = new QEDWaveTrackDisplay(this); + + QFrame *infoLayoutContainer = new QFrame(this); + infoLayoutContainer->setFrameStyle(QFrame::StyledPanel | QFrame::Plain); + infoLayoutContainer->setLineWidth(2); + infoLayoutContainer->setFixedWidth(200); + + QVBoxLayout *infoLayout = new QVBoxLayout(infoLayoutContainer); + infoLayout->setMargin(0); + infoName = new QLabel("Audio"); + infoName->setStyleSheet("QLabel { background-color: black; color: white; padding: 2px; }"); + infoLayout->addWidget(infoName); + + infoData = new QLabel(); + infoData->setStyleSheet("QLabel { padding: 2px; }"); + infoLayout->addWidget(infoData); + + mainLayout->addWidget(infoLayoutContainer); + mainLayout->addWidget(wave); + + connect(wave, SIGNAL(timeChanged(float)), this, SLOT(slotTimeChanged(float))); + connect(wave, SIGNAL(offsetChanged(float)), this, SLOT(slotOffsetChanged(float))); + connect(wave, SIGNAL(selectionChanged(float,float)), this, SLOT(slotSelectionChanged(float,float))); +} + + +void QEDWaveTrackView::setWaveform(void *mdata, int msize, int mformat, int mchannels, int mfreq) +{ + QString fmt; + switch (mformat) + { + case AUDIO_S16SYS: fmt = "16bit (S)"; break; + case AUDIO_U16SYS: fmt = "16bit (U)"; break; + case AUDIO_S8: fmt = "8bit (S)"; break; + case AUDIO_U8: fmt = "8bit (U)"; break; + default: fmt = "?"; break; + } + infoData->setText(QString("<b>%1</b>, <b>%2</b> ch, <b>%3</b> Hz").arg(fmt).arg(mchannels).arg(mfreq)); + wave->setWaveform(mdata, msize, mformat, mchannels, mfreq); + update(); +} + + +void QEDWaveTrackView::setName(QString name) +{ + infoName->setText(name); + update(); +} + + +void QEDWaveTrackView::setTime(const float mtime) +{ + wave->setTime(mtime); +} + + +void QEDWaveTrackView::setOffset(const float moffs) +{ + wave->setOffset(moffs); +} + + +void QEDWaveTrackView::setScale(const float mscale) +{ + wave->setScale(mscale); +} + + +float QEDWaveTrackView::getTime() +{ + return wave->getTime(); +} + + +float QEDWaveTrackView::getOffset() +{ + return wave->getOffset(); +} + + +float QEDWaveTrackView::getScaledWidth() +{ + return wave->getScaledWidth(); +} + + +void QEDWaveTrackView::slotTimeChanged(float value) +{ + emit timeChanged(value); +} + + +void QEDWaveTrackView::slotOffsetChanged(float value) +{ + emit offsetChanged(value); +} + + +float QEDWaveTrackView::getDuration() +{ + return wave->getDuration(); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/editor/edwaveform.h Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,97 @@ +#ifndef EDWAVEFORM_H +#define EDWAVEFORM_H + +#include <QWidget> +#include <QLabel> +#include "dmengine.h" + +class QEDWaveTrackDisplay : public QWidget +{ + Q_OBJECT + +public: + QEDWaveTrackDisplay(QWidget *parent = 0); + + void setWaveform(void *mdata, int msize, int mformat, int mchannels, int mfreq); + float getScaledWidth(); + void setScale(const float mscale); + int getBps(); + float getDuration(); + float getTimeScale(float value); + float getTimeFromCoord(float value); + float getTime(); + float getOffset(); + + QSize minimumSizeHint() const + { + return QSize(100, 60); + } + + QSize sizeHint() const + { + return QSize(600, 60); + } + +public slots: + void setTime(const float mtime); + void setOffset(const float moffs); + void setSelection(const float mstart, const float mend); + void clearSelection(); + +signals: + void selectionChanged(float mstart, float mduration); + void timeChanged(float value); + void offsetChanged(float value); + +protected: + void mousePressEvent(QMouseEvent *event); + void mouseMoveEvent(QMouseEvent *event); + void mouseReleaseEvent(QMouseEvent *event); + + void paintEvent(QPaintEvent *event); + +private: + float scale, time, offs, duration; // in milliseconds + int size, channels, format, freq, sduration; + void *data; + + bool selectionValid; + float selectionStart, selectionDuration; + + QPoint selectionPoint, dragPoint; + bool selecting, dragging; + float selectionOffs, dragOffs; +}; + + +class QEDWaveTrackView : public QWidget +{ + Q_OBJECT + +private: + QEDWaveTrackDisplay *wave; + QLabel *infoName, *infoData; + +public: + + QEDWaveTrackView(QWidget *parent = 0); + void setWaveform(void *mdata, int mlen, int mformat, int mchannels, int mfreq); + void setName(QString name); + void setTime(const float mtime); + void setOffset(const float moffs); + float getScaledWidth(); + void setScale(const float mscale); + float getDuration(); + float getTime(); + float getOffset(); + +private slots: + void slotTimeChanged(float value); + void slotOffsetChanged(float value); + +signals: + void timeChanged(float value); + void offsetChanged(float value); +}; + +#endif
--- a/edmain.cpp Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,531 +0,0 @@ -// -// Demo Editor -- Main program -// (C) Copyright 2012 Matti 'ccr' Hämäläinen <ccr@tnsp.org> -// -#include <SDL.h> -#include "dmengine.h" -#include "edmain.h" -#include <QSettings> -#include <QGLWidget> - - -int main(int argc, char *argv[]) -{ - dmVerbosity = 5; - - QApplication app(argc, argv); - - app.setOrganizationName("TNSP"); - app.setOrganizationDomain("tnsp.org"); - app.setApplicationName(PROGRAM_NAME); - app.setApplicationVersion(PROGRAM_VERSION); - - DemoEditor mainWin; - - mainWin.show(); - - return app.exec(); -} - - -void engineAudioCallback(void *userdata, Uint8 * stream, int len) -{ - DMEngineData *engine = (DMEngineData *) userdata; - - if (engine->paused) - { - memset(stream, 0, len); - } - else -#ifdef DM_USE_JSS - { - if (engine->dev != NULL) - jvmRenderAudio(engine->dev, stream, - len / jvmGetSampleSize(engine->dev)); - } -#endif -#ifdef DM_USE_TREMOR - if (engine->audioPos + len >= engine->audioRes->rdataSize) - { - engine->exitFlag = true; - } - else - { - memcpy(stream, (Uint8 *) engine->audioRes->rdata + engine->audioPos, len); - engine->audioPos += len; - } -#endif -} - - -int DemoEditor::reopenResources() -{ - int err; - - if ((err = dmres_init(&engine.resources, engine.optPackFilename, engine.optDataPath, - engine.optResFlags, engineClassifier)) != DMERR_OK) - { - dmError("Could not initialize resource manager: %d, %s.\n", - err, dmErrorStr(err)); - } - return err; -} - - -int DemoEditor::loadResources() -{ - int err, loaded, total; - err = dmres_preload(engine.resources, true, &loaded, &total); - - while ((err = dmres_preload(engine.resources, false, &loaded, &total)) == DMERR_PROGRESS) - { - // Show a nice progress bar while loading - if (total > 0 && (loaded % 2) == 0) - { -/* - if ((err = engineShowProgress(loaded, total)) != DMERR_OK) - return err; -*/ - } - } - return DMERR_OK; -} - - -DemoEditor::DemoEditor() -{ - int err; - - resize(1024, 768); - setWindowTitle(QCoreApplication::applicationName()); - - memset(&engine, 0, sizeof(engine)); - initSDL = FALSE; - currTimeline = NULL; - - // Pre-initialization - if ((err = demoPreInit(&engine)) != DMERR_OK) - goto error_exit; - - // Initialize SDL components - dmPrint(1, "Initializing libSDL.\n"); - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) != 0) - { - dmError("Could not initialize SDL: %s\n", SDL_GetError()); - goto error_exit; - } - initSDL = true; - - // Initialize audio parts - if (engine.optAfmt.freq == 0 && engine.optAfmt.channels == 0) - { - // Defaults, if none seem to be set - engine.optAfmt.freq = 44100; - engine.optAfmt.format = AUDIO_S16SYS; - engine.optAfmt.channels = 2; - engine.optAfmt.samples = engine.optAfmt.freq / 16; - } - -#ifdef DM_USE_JSS - jssInit(); - - switch (engine.optAfmt.format) - { - case AUDIO_S16SYS: - engine.jss_format = JSS_AUDIO_S16; - break; - case AUDIO_U16SYS: - engine.jss_format = JSS_AUDIO_U16; - break; - case AUDIO_S8: - engine.jss_format = JSS_AUDIO_S8; - break; - case AUDIO_U8: - engine.jss_format = JSS_AUDIO_U8; - break; - } - - dmPrint(1, "Initializing miniJSS mixer with fmt=%d, chn=%d, freq=%d\n", - engine.jss_format, engine.optAfmt.channels, engine.optAfmt.freq); - - if ((engine.dev = - jvmInit(engine.jss_format, engine.optAfmt.channels, - engine.optAfmt.freq, JMIX_AUTO)) == NULL) - { - dmError("jvmInit() returned NULL, voi perkele.\n"); - goto error_exit; - } - - if ((engine.plr = jmpInit(engine.dev)) == NULL) - { - dmError("jmpInit() returned NULL\n"); - goto error_exit; - } -#endif - - // Initialize SDL audio - dmPrint(1, "Trying to init SDL audio with: fmt=%d, chn=%d, freq=%d\n", - engine.optAfmt.format, engine.optAfmt.channels, - engine.optAfmt.freq); - - engine.optAfmt.callback = engineAudioCallback; - - if (SDL_OpenAudio(&engine.optAfmt, NULL) < 0) - { - dmError("Couldn't open SDL audio: %s\n", SDL_GetError()); - goto error_exit; - } - - // Initialize SDL video - if (engine.demoInitPreVideo != NULL && - (err = engine.demoInitPreVideo(&engine)) != DMERR_OK) - { - dmError("demoInitPreVideo() failed, %d: %s\n", err, dmErrorStr(err)); - goto error_exit; - } - - dmPrint(1, "Initializing SDL video %d x %d x %dbpp, flags=0x%08x\n", - engine.optVidWidth, engine.optVidHeight, engine.optVidDepth, engine.optVFlags); - - engine.screen = SDL_CreateRGBSurface(SDL_SWSURFACE, engine.optVidWidth, engine.optVidHeight, engine.optVidDepth, 0, 0, 0, 0); - if (engine.screen == NULL) - { - dmError("Could not allocate video backbuffer surface.\n"); - goto error_exit; - } - - if (engine.demoInitPostVideo != NULL && - (err = engine.demoInitPostVideo(&engine)) != DMERR_OK) - { - dmError("demoInitPostVideo() failed, %d: %s\n", err, dmErrorStr(err)); - goto error_exit; - } - - -error_exit: - - // Setup GUI elements - createMainGUI(); - createNewFile(); - timelineView->setTimeline(currTimeline); - settingsRestore(); - initEffectsAndResources(); - statusMsg("Application started."); -} - - -DemoEditor::~DemoEditor() -{ - statusMsg("Shutting down."); - - settingsSave(); - delete demoView; - historyReset(); - - if (engine.screen) - SDL_FreeSurface(engine.screen); - - SDL_LockAudio(); - SDL_PauseAudio(1); -#ifdef DM_USE_JSS - jmpClose(engine.plr); - jvmClose(engine.dev); - jssClose(); -#endif - SDL_UnlockAudio(); - - shutdownEffectsAndResources(); - - if (initSDL) - SDL_Quit(); -} - - -int DemoEditor::getTimelineDuration() -{ - return timelineAudioTrack->getDuration(); -} - - -void DemoEditor::updateResourceView() -{ -} - - -void DemoEditor::updateTimelineView() -{ - demoView->setEngineData(&engine); - - if (engine.audioRes != NULL) - { - timelineAudioTrack->setWaveform( - engine.audioRes->rdata, engine.audioRes->rdataSize, - engine.optAfmt.format, engine.optAfmt.channels, - engine.optAfmt.freq); - } - - timelineAudioTrack->setOffset(currViewOffset); - timelineAudioTrack->setScale(currViewScale); - - - timelineView->setTime(currFrameTime); - timelineView->setOffset(currViewOffset); - timelineView->setScale(currViewScale); - - timelineScrollBar->setRange(0, getTimelineDuration()); - timelineScrollBar->setValue(currViewOffset); -} - - -void DemoEditor::actionTimelineScrollChanged(int value) -{ - currViewOffset = value; - updateTimelineView(); -} - - -void DemoEditor::actionOffsetChanged(float value) -{ - currViewOffset = value; - updateTimelineView(); -} - - -void DemoEditor::actionTimeChanged(float value) -{ - currFrameTime = value; - updateTimelineView(); -} - - -void DemoEditor::actionTimelineChanged() -{ - updateMenuStates(); - update(); -} - - -int DemoEditor::initEffectsAndResources() -{ - int err; - - currViewOffset = 0; - currFrameTime = 0; - currViewScale = 1.0f; - - // Initialize resource subsystem - statusMsg("Initializing resources subsystem."); - if ((err = reopenResources()) != DMERR_OK) - return err; - - // Load resources - statusMsg("Loading resources, please wait..."); - if ((err = loadResources()) != DMERR_OK) - { - dmError("Error loading resources, %d: %s.\n", err, dmErrorStr(err)); - return err; - } - - - // Final initializations - statusMsg("Initializing custom demo data."); - if ((err = engine.demoInit(&engine)) != DMERR_OK) - { - dmError("Failure in demoInit(), %d: %s\n", - err, dmErrorStr(err)); - return err; - } - - // Initialize effects - statusMsg("Initializing effects ..."); - if ((err = engineInitializeEffects(&engine)) != DMERR_OK) - { - dmError("Effects initialization failed, %d: %s\n", - err, dmErrorStr(err)); - return err; - } - - // Etc. - rehash(); - return DMERR_OK; -} - - -void DemoEditor::shutdownEffectsAndResources() -{ - delete currTimeline; - dmFreePreparedTimelineData(engine.ptl); - engineShutdownEffects(&engine); - dmres_close(engine.resources); - - if (engine.demoShutdown != NULL) - engine.demoShutdown(&engine); -} - - -void DemoEditor::rehash() -{ - timelineView->setTimeline(currTimeline); - updateResourceView(); - updateTimelineView(); - updateMenuStates(); - update(); -} - - -void DemoEditor::createNewFile() -{ - delete currTimeline; - currTimeline = new EDTimelineObject(); - - DMTimelineTrack *tr; - dmTimelineAddTrack(currTimeline->tl, &tr, "Penis"); - - DMTimelineEvent *ev; - dmTimelineTrackAddEvent(tr, 500, 100, &ev); - - dmTimelineEventSetEffectByIndex(ev, 0); - - historyReset(); - updateMenuStates(); - update(); -} - - -void DemoEditor::readFromFile(QString filename) -{ - EDTimelineObject *tmp = new EDTimelineObject(); - int ret = tmp->load(filename); - if (ret != DMERR_OK) - { - showFileErrorDialog("Loading demo blob file "+ filename, ret); - delete tmp; - } - else - { - delete currTimeline; - currTimeline = tmp; - rehash(); - } -} - - -void DemoEditor::saveToFile(QString filename) -{ - int ret = currTimeline->save(filename); - if (ret != DMERR_OK) - { - showFileErrorDialog("Saving demo blob file "+ filename, ret); - } - - updateMenuStates(); -} - - -void DemoEditor::settingsRestore() -{ - QSettings s; - - restoreGeometry(s.value("windowGeometry").toByteArray()); - restoreState(s.value("windowState").toByteArray()); -} - - -void DemoEditor::settingsSave() -{ - QSettings s; - - s.setValue("windowGeometry", saveGeometry()); - s.setValue("windowState", saveState()); -} - - -// -// Edit history functionality -// -void DemoEditor::historyReset() -{ - if (currTimeline != NULL) - currTimeline->scrub(); - - undoHistoryPos = -1; - undoHistoryMax = DOC_UNDO_MAX; - undoHistory.clear(); -} - - -void DemoEditor::historyPush(QString description) -{ - if (currTimeline == NULL) - return; - - if (!undoHistory.isEmpty() && undoHistory.last()->state() == "-") - { - delete undoHistory.takeLast(); - } - - while (undoHistory.size() >= undoHistoryMax) - { - delete undoHistory.takeFirst(); - } - - EDTimelineObject *copy = new EDTimelineObject(currTimeline); - copy->setState(description); - undoHistory.append(copy); -} - - -void DemoEditor::historyTop() -{ - if (currTimeline == NULL) - return; - - EDTimelineObject *copy = new EDTimelineObject(currTimeline); - copy->setState("-"); - undoHistory.append(copy); - - undoHistoryPos = undoHistory.size() - 1; - currTimeline->touch(); - updateTimelineView(); - updateMenuStates(); - update(); -} - - -void DemoEditor::historyPop() -{ - if (!undoHistory.isEmpty()) - { - delete undoHistory.takeLast(); - } -} - - -void DemoEditor::performRedo() -{ - if (undoHistoryPos >= 0 && undoHistoryPos < undoHistory.size() - 1) - { - undoHistoryPos++; - delete currTimeline; - currTimeline = new EDTimelineObject(undoHistory.at(undoHistoryPos)); - currTimeline->touch(); - updateTimelineView(); - updateMenuStates(); - update(); - } -} - - -void DemoEditor::performUndo() -{ - if (undoHistoryPos > 0 && undoHistory.size() > 1) - { - undoHistoryPos--; - delete currTimeline; - currTimeline = new EDTimelineObject(undoHistory.at(undoHistoryPos)); - currTimeline->touch(); - updateTimelineView(); - updateMenuStates(); - update(); - } -}
--- a/edmain.h Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,132 +0,0 @@ -#ifndef EDMAIN_H -#define EDMAIN_H - -// Program name etc -#define PROGRAM_NAME "DMPE Editor" -#define PROGRAM_VERSION "0.1" - -// Defaults -#define DOC_DEF_FILENAME "Untitled" -#define DOC_UNDO_MAX 15 - -enum -{ - CTRL_REWIND, - CTRL_PLAY_START, - CTRL_PLAY_CURRENT, - CTRL_PAUSE -}; - -#define CTRL_ICON_SIZE 32 - -#include "edtlobj.h" -#include "edview.h" -#include "edwaveform.h" -#include "edtimeline.h" -#include "edres.h" -#include <QDebug> -#include <QFile> -#include <QApplication> -#include <QMainWindow> -#include <QTableView> -#include <QAction> -#include <QActionGroup> -#include <QSlider> -#include <QMessageBox> -#include <QCheckBox> -#include <QScrollBar> - -class DemoEditor : public QMainWindow -{ - Q_OBJECT - -public: - DemoEditor(); - ~DemoEditor(); - - void settingsRestore(); - void settingsSave(); - - -private slots: - void actionFileNew(); - void actionFileOpen(); - void actionFileSave(); - void actionFileSaveAs(); - - void actionAboutBox(); - - //void actionCut(); - //void actionCopy(); - //void actionPaste(); - //void actionDelete(); - - void performUndo(); - void performRedo(); - - void actionControlChanged(QAction *); - void actionTimelineScrollChanged(int); - void actionOffsetChanged(float); - void actionTimeChanged(float); - void actionTimelineChanged(); - -private: - QAction *menuActUndo, *menuActRedo, *menuActOpen, *menuActSave, *menuActSaveAs; -// QAction *menuActCut, *menuActCopy, *menuActPaste, *menuActDelete; - QActionGroup *actGroupControls; - QScrollBar *timelineScrollBar; - QTableView *resourceView; - QEDResourceModel *resourceModel; - QEDWaveTrackView *timelineAudioTrack; - QEDTimelineView *timelineView; - QEDGLDemoView *demoView; - - - - QAction * createToolButton(QActionGroup *group, QString name, QIcon icon, QString statustip, QVariant data); - QAction * createMenuAction(QString name, const QKeySequence &shortcut, QString tooltip); - QAction * createMenuGroupAction(QMenu *, QActionGroup *, QString name, const QKeySequence &shortcut, QString tooltip, QVariant data); - void setActionGroupChecked(QActionGroup *group, QVariant data); - - - void showFileErrorDialog(QString operation, int code); - QMessageBox::StandardButton showDocumentModifiedDialog(); - void statusMsg(QString message); - void closeEvent(QCloseEvent *event); - void createMainGUI(); - void updateResourceView(); - void updateMenuStates(); - void updateTimelineView(); - - int initEffectsAndResources(); - void shutdownEffectsAndResources(); - void rehash(); - int reopenResources(); - int loadResources(); - bool initializeVideo(); - int getTimelineDuration(); - - void createNewFile(); - void readFromFile(QString filename); - void saveToFile(QString filename); - - - bool initSDL; - float currViewScale; - int currViewOffset; - int currFrameTime; - - EDTimelineObject *currTimeline; - DMEngineData engine; - - QList<EDTimelineObject *> undoHistory; - int undoHistoryPos, undoHistoryMax; - - void historyReset(); - void historyPush(QString description); - void historyTop(); - void historyPop(); -}; - - -#endif // EDMAIN_H
--- a/edres.cpp Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,74 +0,0 @@ -#include "edres.h" -#include "dmengine.h" - - -QEDResourceModel::QEDResourceModel(QObject *parent) - : QAbstractTableModel(parent) -{ -} - - -int QEDResourceModel::rowCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent); - return nengineEffects; -} - - -int QEDResourceModel::columnCount(const QModelIndex &parent) const -{ - Q_UNUSED(parent); - return 2; -} - - -QVariant QEDResourceModel::data(const QModelIndex &index, int role) const -{ - if (!index.isValid()) - return QVariant(); - - if (index.row() >= nengineEffects || index.row() < 0) - return QVariant(); - - if (role == Qt::DisplayRole) - { - DMEffect *ef = &engineEffects[index.row()]; - switch (index.column()) - { - case 0: - return QString(ef->name); - - case 1: - return QVariant(ef->nparams); - } - } - return QVariant(); -} - - -QVariant QEDResourceModel::headerData(int section, Qt::Orientation orientation, int role) const -{ - if (role != Qt::DisplayRole) - return QVariant(); - - if (orientation == Qt::Horizontal) - { - switch (section) { - case 0: - return "Name"; - - case 1: - return "# params"; - } - } - return QVariant(); -} - - -Qt::ItemFlags QEDResourceModel::flags(const QModelIndex &index) const -{ - if (!index.isValid()) - return Qt::ItemIsEnabled; - - return QAbstractTableModel::flags(index); // | Qt::ItemIsEditable; -}
--- a/edres.h Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,26 +0,0 @@ -#ifndef RESOURCEMODEL_H -#define RESOURCEMODEL_H - -#include <QAbstractTableModel> -#include <QPair> -#include <QList> - -class QEDResourceModel : public QAbstractTableModel -{ - Q_OBJECT - -public: - QEDResourceModel(QObject *parent = 0); - - int rowCount(const QModelIndex &parent) const; - int columnCount(const QModelIndex &parent) const; - QVariant data(const QModelIndex &index, int role) const; - QVariant headerData(int section, Qt::Orientation orientation, int role) const; - Qt::ItemFlags flags(const QModelIndex &index) const; -// bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole); -// QList< QPair<QString, QString> > getList(); - -private: -}; - -#endif
--- a/edtimeline.cpp Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,471 +0,0 @@ -#include <QtGui> -#include "edtimeline.h" - - -QEDTimelineTrackDisplay::QEDTimelineTrackDisplay(QWidget *parent) : QWidget(parent) -{ - track = NULL; - time = offs = 0; - scale = 1.0f; - - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); -} - - -QSize QEDTimelineTrackDisplay::minimumSizeHint() const -{ - return QSize(100, 60); -} - - -QSize QEDTimelineTrackDisplay::sizeHint() const -{ - return QSize(600, 60); -} - - -void QEDTimelineTrackDisplay::setTrack(DMTimelineTrack *mtrack) -{ - track = mtrack; -} - - -float QEDTimelineTrackDisplay::getTimeScale(float value) -{ - return value * scale; -} - - -float QEDTimelineTrackDisplay::getTimeFromCoord(float value) -{ - return value * scale * 1000.0f; -} - - -void QEDTimelineTrackDisplay::setTime(const float mtime) -{ - if (time != mtime && mtime >= 0) - { - time = mtime; - emit timeChanged(time); - } -} - - -void QEDTimelineTrackDisplay::setOffset(const float moffs) -{ - if (offs != moffs && moffs >= 0) - { - offs = moffs; - emit offsetChanged(offs); - } -} - - -void QEDTimelineTrackDisplay::setScale(const float mscale) -{ - if (mscale > 0.05) - scale = mscale; -} - - -void QEDTimelineTrackDisplay::setSelection(const float mstart, const float mend) -{ - if (mstart >= 0 && mend >= 0 && fabs(mend - mstart) > 0) - { - selectionValid = true; - if (mend > mstart) - { - selectionStart = mstart; - selectionDuration = mend - mstart + 1; - } - else - { - selectionStart = mend; - selectionDuration = mstart - mend + 1; - } - emit selectionChanged(selectionStart, selectionDuration); - } -} - - -void QEDTimelineTrackDisplay::clearSelection() -{ - selectionValid = false; - selectionStart = 0; - selectionDuration = 0; - emit selectionChanged(selectionStart, selectionDuration); -} - - -bool QEDTimelineTrackDisplay::getSelection(float *mstart, float *mduration) -{ - if (selectionValid) - { - *mstart = selectionStart; - *mduration = selectionDuration; - } - return selectionValid; -} - - -QList<DMTimelineEvent *> QEDTimelineTrackDisplay::getEventsAt(const int time) -{ - QList<DMTimelineEvent *> list; - - for (int event = 0; event < track->nevents; event++) - { - DMTimelineEvent *ev = track->events[event]; - if (time >= ev->start && time <= ev->start + ev->duration) - list.append(ev); - } - - return list; -} - - - -QList<DMTimelineEvent *> QEDTimelineTrackDisplay::getEventsForRange(const int start, const int duration) -{ - QList<DMTimelineEvent *> list; - - for (int event = 0; event < track->nevents; event++) - { - DMTimelineEvent *ev = track->events[event]; - } - - return list; -} - - -void QEDTimelineTrackDisplay::paintEvent(QPaintEvent *) -{ - if (track == NULL) - return; - - QColor eventColor(150, 150, 150, 128); - QColor invalidEventColor(250, 150, 150, 128); - QColor eventBorder(200, 250, 200, 200); - QColor eventParam(200, 150, 100); - QColor eventText(255, 255, 255); - QColor markerColor(255,255,255); - QColor selectionColor(0,255,0, 150); - QColor selectionEnd(0,255,0, 200); - - QFont fantti; - fantti.setFamily("Arial"); - fantti.setPointSizeF(8.0f); - fantti.setStyleHint(QFont::SansSerif); - - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing); - - - painter.save(); - painter.scale(scale, 1); - - float wd = getTimeScale(width()); - for (int event = 0; event < track->nevents; event++) - { - DMTimelineEvent *ev = track->events[event]; - - float x0 = getTimeScale(ev->start - offs), - x1 = getTimeScale(ev->start + ev->duration - offs); - - if ((x0 >= 0 && x0 < wd) || (x0 < 0 && x1 >= 0)) - { - painter.setFont(fantti); - painter.setBrush(ev->effect != NULL ? eventColor : invalidEventColor); - painter.setPen(eventBorder); - x0 = ev->start - offs; - x1 = ev->duration; - painter.fillRect(x0, 0, x1, height(), eventColor); - - QPainterPath path; - path.addText(QPointF(x0 + 2, 10), fantti, ev->effect != NULL ? QString(ev->effect->name) : "INVALID"); - - painter.save(); - painter.translate(1,1); - painter.setPen(Qt::black); - painter.setBrush(Qt::black); - painter.drawPath(path); - painter.restore(); - - painter.setPen(eventText); - painter.setBrush(eventText); - painter.drawPath(path); - } - - } - - painter.restore(); - - if (selectionValid) - { - float x0 = getTimeScale(selectionStart - offs), - x1 = getTimeScale(selectionStart + selectionDuration - offs); - - if ((x0 >= 0 && x0 < wd) || (x0 < 0 && x1 >= 0)) - { - painter.setBrush(selectionColor); - painter.setPen(selectionEnd); - x0 = selectionStart - offs; - x1 = selectionDuration; - painter.fillRect(x0, 0, x1, height(), eventColor); - - painter.drawLine(x0, 0, x0, height()); - painter.drawLine(x1, 0, x1, height()); - } - } - - - if (time >= offs * scale && time - offs <= width() * scale) - { - int xc = time - offs; - painter.save(); - painter.scale(scale, 1); - painter.setPen(markerColor); - painter.drawLine(xc, 0, xc, height()); - painter.restore(); - } -} - - -void QEDTimelineTrackDisplay::mousePressEvent(QMouseEvent *ev) -{ - switch (ev->button()) - { - case Qt::LeftButton: - if (parent->getActiveTrack() != this) - emit trackActivated(this); - - selectionPoint = ev->pos(); - selectionOffs = offs / scale; - selecting = false; - break; - - case Qt::RightButton: - dragPoint = ev->pos(); - dragOffs = offs / scale; - dragging = false; - break; - - default: - break; - } -} - - -void QEDTimelineTrackDisplay::mouseMoveEvent(QMouseEvent *ev) -{ - if ((ev->buttons() & Qt::LeftButton) && ev->pos().x() != selectionPoint.x()) - { - selecting = true; - setSelection(selectionOffs, offs + (ev->pos().x() - selectionPoint.x()) / scale); - } - if ((ev->buttons() & Qt::RightButton) && ev->pos().x() != dragPoint.x()) - { - dragging = true; - setOffset(dragOffs - (ev->pos().x() - dragPoint.x()) / scale); - } -} - - -void QEDTimelineTrackDisplay::mouseReleaseEvent(QMouseEvent *ev) -{ - if (ev->button() == Qt::LeftButton) - { - if (selecting) - { - selecting = false; - setSelection(selectionOffs + (ev->pos().x() - selectionPoint.x()) / scale); - } - } - else - if (ev->button() == Qt::RightButton && !dragging) - { - setTime(offs + getTimeFromCoord(ev->pos().x())); - } -} - - -QEDTimelineTrackView::QEDTimelineTrackView(QWidget *parent) : QWidget(parent) -{ - QHBoxLayout *mainLayout = new QHBoxLayout(this); - mainLayout->setMargin(0); - track = new QEDTimelineTrackDisplay(this); - - QFrame *infoLayoutContainer = new QFrame(this); - infoLayoutContainer->setFrameStyle(QFrame::StyledPanel | QFrame::Plain); - infoLayoutContainer->setLineWidth(2); - infoLayoutContainer->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Minimum); - infoLayoutContainer->setFixedWidth(200); - - QVBoxLayout *infoLayout = new QVBoxLayout(infoLayoutContainer); - infoLayout->setMargin(0); - infoName = new QLineEdit(); - infoName->setFrame(false); - infoName->setMaxLength(DT_MAX_NAME_LENGTH); - infoName->setStyleSheet("QLineEdit { background-color: black; color: white; padding: 2px; }"); - connect(infoName, SIGNAL(textEdited(const QString&)), this, SLOT(slotTrackNameChanged(const QString&))); - infoLayout->addWidget(infoName); - - - enabledCheck = new QCheckBox("Enabled"); - infoLayout->addWidget(enabledCheck); - connect(enabledCheck, SIGNAL(toggled(bool)), this, SLOT(slotTrackEnabledChanged(bool))); - - infoData = new QLabel(); - infoData->setStyleSheet("QLabel { padding: 2px; }"); - infoLayout->addWidget(infoData); - - mainLayout->addWidget(infoLayoutContainer); - mainLayout->addWidget(track); -} - - -void QEDTimelineTrackView::update() -{ - if (track != NULL && track->track) - { - infoName->setText(QString(track->track->name)); - enabledCheck->setChecked(track->track->enabled); - infoData->setText(QString("<b>%1</b> events").arg(track->track->nevents)); - } - else - { - infoName->setText(""); - infoData->setText("-"); - enabledCheck->setChecked(false); - } - - QWidget::update(); -} - - -void QEDTimelineTrackView::setTrack(DMTimelineTrack *mtrack) -{ - track->setTrack(mtrack); - update(); -} - - -void QEDTimelineTrackView::slotTrackEnabledChanged(bool value) -{ - track->track->enabled = value; - emit trackChanged(); -} - - -void QEDTimelineTrackView::slotTrackNameChanged(const QString & text) -{ - QByteArray ba = text.toUtf8(); - track->track->name = dm_strdup(ba.constData()); - emit trackChanged(); -} - - - -QEDTimelineView::QEDTimelineView(QWidget *parent) : QWidget(parent) -{ - layout = new QVBoxLayout(this); - tl = NULL; -} - - -void QEDTimelineView::setTimeline(EDTimelineObject *mtl) -{ - tl = mtl; - - delete layout; - layout = new QVBoxLayout(this); - layout->setMargin(0); - - tracks.clear(); - - if (tl != NULL && tl->tl != NULL) - { - for (int track = 0; track < tl->tl->ntracks; track++) - { - QEDTimelineTrackView *vtr = new QEDTimelineTrackView(this); - vtr->setTrack(tl->tl->tracks[track]); - tracks.append(vtr); - layout->addWidget(vtr); - connect(vtr, SIGNAL(trackChanged()), this, SLOT(slotTimelineChanged())); - connect(vtr, SIGNAL(timeChanged(float)), this, SLOT(slotTimeChanged(float))); - connect(vtr, SIGNAL(offsetChanged(float)), this, SLOT(slotOffsetChanged(float))); - connect(vtr, SIGNAL(selectionChanged(float,float)), this, SLOT(slotSelectionChanged(float,float))); - } - } - update(); -} - - -void QEDTimelineView::slotTimelineChanged() -{ - if (tl != NULL) - { - tl->touch(); - emit timelineChanged(); - } -} - - -void QEDTimelineView::setTime(const int mtime) -{ - if (tl != NULL && tl->tl != NULL) - { - QList<QEDTimelineTrackView *>::iterator track; - for (track = tracks.begin(); track != tracks.end(); track++) - { - (*track)->track->setTime(mtime); - } - update(); - } -} - - -void QEDTimelineView::setOffset(const int moffs) -{ - if (tl != NULL && tl->tl != NULL) - { - QList<QEDTimelineTrackView *>::iterator track; - for (track = tracks.begin(); track != tracks.end(); track++) - { - (*track)->track->setOffset(moffs); - } - update(); - } -} - - -void QEDTimelineView::setScale(const float mscale) -{ - if (tl != NULL && tl->tl != NULL) - { - QList<QEDTimelineTrackView *>::iterator track; - for (track = tracks.begin(); track != tracks.end(); track++) - { - (*track)->track->setScale(mscale); - } - update(); - } -} - - -QList<DMTimelineEvent *> QEDTimelineView::getEventsAt(const int time) -{ - if (tl != NULL && tl->tl != NULL && - activeTrack >= 0 && activeTrack < tl->tl->ntracks) - { - return tracks[activeTrack]->tl->getEventsAt(time); - } - else - return QList<DMTimelineEvent *>(); -} - - -QList<DMTimelineEvent *> QEDTimelineView::getEventsForRange(const int start, const int duration) -{ -} -
--- a/edtimeline.h Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,121 +0,0 @@ -#ifndef EDTIMELINE_H -#define EDTIMELINE_H - -#include <QWidget> -#include <QCheckBox> -#include <QVBoxLayout> -#include <QLabel> -#include <QLineEdit> -#include "edtlobj.h" -#include "dmengine.h" - - -class QEDTimelineTrackDisplay : public QWidget -{ - Q_OBJECT - -public: - DMTimelineTrack *track; - - QEDTimelineTrackDisplay(QWidget *parent = 0); - void setTrack(DMTimelineTrack *mtrack); - - float getTimeScale(float value); - float getTimeFromCoord(float value); - - void setScale(const float mscale); - - bool getSelection(float *mstart, float *mduration); - QList<DMTimelineEvent *> getEventsAt(const int time); - QList<DMTimelineEvent *> getEventsForRange(const int start, const int duration); - - QSize minimumSizeHint() const; - QSize sizeHint() const; - -public slots: - void setTime(const float mtime); - void setOffset(const float moffs); - void setSelection(const float mstart, const float mend); - void clearSelection(); - -signals: - void selectionChanged(float mstart, float mduration); - void timeChanged(float value); - void offsetChanged(float value); - -protected: - void mousePressEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - - void paintEvent(QPaintEvent *event); - -private: - float scale, time, offs; - - bool selectionValid; - float selectionStart, selectionDuration; - - QPoint selectionPoint, dragPoint; - bool selecting, dragging; - float selectionOffs, dragOffs; -}; - - -class QEDTimelineTrackView : public QWidget -{ - Q_OBJECT - -private: - QLineEdit *infoName; - QLabel *infoData; - QCheckBox *enabledCheck; - -public: - QEDTimelineTrackDisplay *track; - - QEDTimelineTrackView(QWidget *parent = 0); - void setTrack(DMTimelineTrack *mtrack); - void update(); - -private slots: - void slotTrackEnabledChanged(bool); - void slotTrackNameChanged(const QString & text); - -signals: - void trackChanged(); - void selectionChanged(float mstart, float mduration); - void timeChanged(float value); - void offsetChanged(float value); -}; - - -class QEDTimelineView : public QWidget -{ - Q_OBJECT - -private: - QVBoxLayout *layout; - - EDTimelineObject *tl; - QList<QEDTimelineTrackView *> tracks; - int activeTrack; - -public: - QEDTimelineView(QWidget *parent = 0); - void setTimeline(EDTimelineObject *mtl); - - void setTime(const float mtime); - void setOffset(const float moffs); - void setScale(const float mscale); - -private slots: - void slotTimelineChanged(); - -signals: - void timelineChanged(); - void timeChanged(float value); - void offsetChanged(float value); -}; - -#endif
--- a/edtlobj.cpp Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -// -// Demo Editor -- Timeline state object -// Wrapper class for DMTimeline data -// (C) Copyright 2012 Matti 'ccr' Hämäläinen <ccr@tnsp.org> -// -#include "edtlobj.h" -#include "dmres.h" - - -EDTimelineObject::EDTimelineObject() -{ - dmTimelineNew(&tl, "Demo"); - scrub(); -} - - -EDTimelineObject::EDTimelineObject(EDTimelineObject *obj) -{ - scrub(); - filename = obj->filename; - dmCopyTimeline(obj->tl, &tl); -} - - -EDTimelineObject::~EDTimelineObject() -{ - dmFreeTimeline(tl); -} - - -int EDTimelineObject::load(QString mfilename) -{ - QByteArray fnba = mfilename.toUtf8(); - DMResource *res; - DMTimeline *tmp; - if ((res = dmf_create_stdio(fnba.data(), "rb")) == NULL) - return DMERR_FOPEN; - - int err = dmLoadTimeline(res, &tmp); - dmf_close(res); - - if (err == DMERR_OK) - { - dmFreeTimeline(tl); - tl = tmp; - scrub(); - if (tl->name != NULL) - filename = QString(tl->name); - else - filename = mfilename; - } - else - { - dmFreeTimeline(tmp); - } - return err; -} - - -int EDTimelineObject::save(QString mfilename) -{ - QByteArray fnba = mfilename.toUtf8(); - DMResource *res; - if ((res = dmf_create_stdio(fnba.data(), "wb")) == NULL) - return DMERR_FOPEN; - - int err = dmSaveTimeline(res, tl); - scrub(); - - dmf_close(res); - return err; -} - - -void EDTimelineObject::touch() -{ - ntouches++; -} - - -void EDTimelineObject::scrub() -{ - ntouches = 0; -} - - -bool EDTimelineObject::touched() -{ - return ntouches; -} - - -void EDTimelineObject::setState(const QString &mstate) -{ - cstate = mstate; -} - - -QString EDTimelineObject::state() const -{ - return cstate; -}
--- a/edtlobj.h Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,38 +0,0 @@ -// -// Demo Editor -- Timeline state object -// Wrapper class for DMTimeline data -// (C) Copyright 2012 Matti 'ccr' Hämäläinen <ccr@tnsp.org> -// -#ifndef EDTIMELINEOBJECT_H -#define EDTIMELINEOBJECT_H - -#include "dmengine.h" -#include <QString> - -class EDTimelineObject -{ -private: - QString cstate; - int ntouches; - -public: - QString filename; - DMTimeline *tl; - - EDTimelineObject(); - EDTimelineObject(EDTimelineObject *); - ~EDTimelineObject(); - - int load(QString filename); - int save(QString filename); - - void scrub(); - void touch(); - bool touched(); - - void setState(const QString &mstate); - QString state() const; -}; - - -#endif
--- a/edview.cpp Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,148 +0,0 @@ -#include "edview.h" -#include <QtGui> - - -QEDGLDemoView::QEDGLDemoView(QWidget *parent) : - QGLWidget(QGLFormat(QGL::SampleBuffers|QGL::AlphaChannel), parent) -{ - makeCurrent(); - - if (QGLFramebufferObject::hasOpenGLFramebufferBlit()) - { - QGLFramebufferObjectFormat format; - format.setSamples(4); - format.setAttachment(QGLFramebufferObject::CombinedDepthStencil); - -// render_fbo = new QGLFramebufferObject(512, 512, format); -// texture_fbo = new QGLFramebufferObject(512, 512); - } - else - { -// render_fbo = new QGLFramebufferObject(1024, 1024); -// texture_fbo = render_fbo; - } - - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); -} - - -QEDGLDemoView::~QEDGLDemoView() -{ -} - - -QSize QEDGLDemoView::minimumSizeHint() const -{ - return QSize(320, 240); -} - - -QSize QEDGLDemoView::sizeHint() const -{ - return QSize(640, 480); -} - - -void QEDGLDemoView::setEngineData(DMEngineData *mengine) -{ - engine = mengine; -} - - -void QEDGLDemoView::render(int frameTime) -{ - if (engine != NULL) - { - engine->frameTime = frameTime; - - if (engine->demoRender != NULL) - { - engine->demoRender(engine); - } - else - { - dmExecuteTimeline(engine->ptl, engine->screen, engineGetTick(engine)); - } - - engine->frameCount++; - } -} - - -void QEDGLDemoView::paintEvent(QPaintEvent *) -{ - // save the GL state set for QPainter - saveGLState(); - - // restore the GL state that QPainter expects - restoreGLState(); -} - - -void QEDGLDemoView::saveGLState() -{ - glPushAttrib(GL_ALL_ATTRIB_BITS); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glMatrixMode(GL_MODELVIEW); - glPushMatrix(); -} - - -void QEDGLDemoView::restoreGLState() -{ - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - glPopMatrix(); - glPopAttrib(); -} - - -QEDSWDemoView::QEDSWDemoView(QWidget *parent) : QEDGLDemoView(parent) -{ - img = NULL; -} - - -QEDSWDemoView::~QEDSWDemoView() -{ - delete img; -} - - -void QEDSWDemoView::setEngineData(DMEngineData *mengine) -{ - engine = mengine; - delete img; - - img = new QImage((const uchar *)mengine->screen->pixels, - mengine->screen->w, mengine->screen->h, - mengine->screen->pitch, QImage::Format_RGB32); -} - - -void QEDSWDemoView::paintEvent(QPaintEvent *) -{ - if (img != NULL) - { - QPainter painter(this); - painter.drawImage(QPoint(0, 0), *img); - } -} - - -void QEDSWDemoView::render(int frameTime) -{ - if (SDL_MUSTLOCK(engine->screen) != 0 && SDL_LockSurface(engine->screen) != 0) - return; - - QEDGLDemoView::render(frameTime); - - if (SDL_MUSTLOCK(engine->screen) != 0) - SDL_UnlockSurface(engine->screen); - - update(); -} - -
--- a/edview.h Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,50 +0,0 @@ -#ifndef EDVIEW_H -#define EDVIEW_H - -#include <QtOpenGL> -#include <QImage> -#include "dmengine.h" - - -class QEDGLDemoView : public QGLWidget -{ - Q_OBJECT - -public: - QEDGLDemoView(QWidget *parent); - ~QEDGLDemoView(); - - QSize minimumSizeHint() const; - QSize sizeHint() const; - - virtual void setEngineData(DMEngineData *mengine); - virtual void render(int frameTime); - void paintEvent(QPaintEvent *); - -private: - void saveGLState(); - void restoreGLState(); - -protected: - DMEngineData *engine; -}; - - -class QEDSWDemoView : public QEDGLDemoView -{ - Q_OBJECT - -public: - QEDSWDemoView(QWidget *parent); - ~QEDSWDemoView(); - - void setEngineData(DMEngineData *mengine); - void render(int frameTime); - void paintEvent(QPaintEvent *); - -private: - QImage *img; -}; - - -#endif
--- a/edwaveform.cpp Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,418 +0,0 @@ -#include <QtGui> -#include <SDL_audio.h> -#include "edwaveform.h" - - -QEDWaveTrackDisplay::QEDWaveTrackDisplay(QWidget *parent) : QWidget(parent) -{ - data = NULL; - size = 0; - format = AUDIO_S16SYS; - channels = 1; - freq = 1; - scale = 1.0f; - time = offs = 0; - duration = 0; - sduration = 0; - - setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum); -} - - -void QEDWaveTrackDisplay::setWaveform(void *mdata, int msize, int mformat, int mchannels, int mfreq) -{ - data = mdata; - size = msize; - format = mformat; - channels = mchannels; - freq = mfreq; - - int bps = getBps(); - if (bps != 0) - { - // Duration in milliseconds - duration = ((float) (size / bps) / (float) freq) * 1000.0f; - - // Duration in samples - sduration = msize / bps; - } - else - { - duration = 0; - sduration = 0; - } - - update(); -} - - -int QEDWaveTrackDisplay::getBps() -{ - int bps = channels; - switch (format) - { - case AUDIO_S16SYS: - case AUDIO_U16SYS: - bps *= sizeof(quint16); - break; - case AUDIO_S8: - case AUDIO_U8: - bps *= sizeof(quint8); - break; - } - return bps; -} - - -float QEDWaveTrackDisplay::getDuration() -{ - return duration; -} - - -float QEDWaveTrackDisplay::getTimeScale(float value) -{ - return (value * scale * (float) freq) / 1000.0f; -} - - -float QEDWaveTrackDisplay::getTimeFromCoord(float value) -{ - return value * scale; -} - - -void QEDWaveTrackDisplay::setTime(const float mtime) -{ - if (time != mtime && mtime >= 0 && mtime < duration) - { - time = mtime; - emit timeChanged(time); - } -} - - -void QEDWaveTrackDisplay::setOffset(const float moffs) -{ - if (offs != moffs && moffs >= 0 && moffs < getDuration()) - { - offs = moffs; - emit offsetChanged(offs); - } -} - - -void QEDWaveTrackDisplay::setScale(const float mscale) -{ - if (mscale > 0.05) - scale = mscale; - emit scaleChanged(scale); -} - - -void QEDWaveTrackDisplay::setSelection(const float mstart, const float mend) -{ - if (mstart >= 0 && mend >= 0 && fabs(mend - mstart) > 0) - { - selectionValid = true; - if (mend > mstart) - { - selectionStart = mstart; - selectionDuration = mend - mstart + 1; - } - else - { - selectionStart = mend; - selectionDuration = mstart - mend + 1; - } - emit selectionChanged(selectionStart, selectionDuration); - } -} - - -void QEDWaveTrackDisplay::clearSelection() -{ - selectionValid = false; - selectionStart = 0; - selectionDuration = 0; - emit selectionChanged(selectionStart, selectionDuration); -} - - -bool QEDTimelineTrackDisplay::getSelection(float *mstart, float *mduration) -{ - if (selectionValid) - { - *mstart = selectionStart; - *mduration = selectionDuration; - } - return selectionValid; -} - - -float QEDWaveTrackDisplay::getScaledWidth() -{ - return getTimeScale(width()); -} - - -float QEDWaveTrackDisplay::getTime() -{ - return time; -} - - -float QEDWaveTrackDisplay::getOffset() -{ - return offs; -} - - -void QEDWaveTrackDisplay::paintEvent(QPaintEvent *) -{ - QColor waveColor(0, 150, 0); - QColor waveCenterLine(100, 100, 100); - QColor markerColor(255,255,255); - QColor bgColor(0, 0, 0);//255, 255, 255); - - QPainter painter(this); - painter.setRenderHint(QPainter::Antialiasing); - painter.fillRect(QRect(0, 0, width(), height()), bgColor); - - if (data != NULL) - { - int voffs = 0; - - painter.save(); - painter.translate(0, height() / 2); - - painter.setPen(waveCenterLine); - painter.drawLine(0, 0, width(), 0); - - switch (format) - { - case AUDIO_S16SYS: - painter.scale(1.0f, (float) height() / 32768.0f); - break; - case AUDIO_U16SYS: - voffs = -32768; - painter.scale(1.0f, height() / 32768.0f); - break; - - case AUDIO_S8: - painter.scale(1.0f, height() / 128.0f); - break; - case AUDIO_U8: - voffs = -128; - painter.scale(1.0f, height() / 128.0f); - break; - } - - painter.scale(1.0f, 0.5f); - painter.setPen(waveColor); - - float mscale = (scale * (float)freq) / 1000.0f; - int prevY = 0, prevX = 0; - if (format == AUDIO_S16SYS || format == AUDIO_U16SYS) - { - qint16 *buf = (qint16 *) data; - for (int xc = 0; xc < width(); xc++) - { - int moffs = (int) (((offs + xc) * mscale)); - if (moffs >= sduration) break; - int value = buf[moffs * channels] + voffs; - painter.drawLine(prevX, prevY, xc, value); - prevY = value; - prevX = xc; - } - } - else - if (format == AUDIO_S8 || format == AUDIO_U8) - { - qint8 *buf = (qint8 *) data; - for (int xc = 0; xc < width(); xc++) - { - int moffs = (int) (((offs + xc) * mscale)); - if (moffs >= sduration) break; - int value = buf[moffs * channels] + voffs; - painter.drawLine(prevX, prevY, xc, value); - prevY = value; - prevX = xc; - } - } - - painter.restore(); - } - - float xc = getTimeScale(time - offs), wd = getTimeScale(width()); - if (xc >= 0 && xc <= wd) - { - xc = time - offs; - painter.scale(scale, 1.0f); - painter.setPen(markerColor); - painter.drawLine(xc, 0, xc, height()); - } -} - - -void QEDWaveTrackDisplay::mousePressEvent(QMouseEvent *ev) -{ - switch (ev->button()) - { - case Qt::LeftButton: - selectionPoint = ev->pos(); - selectionOffs = offs; - selecting = false; - break; - - case Qt::RightButton: - dragPoint = ev->pos(); - dragOffs = offs; - dragging = false; - break; - - default: - break; - } -} - - -void QEDWaveTrackDisplay::mouseMoveEvent(QMouseEvent *ev) -{ - if ((ev->buttons() & Qt::LeftButton) && ev->pos().x() != selPoint.x()) - { - selecting = true; - setSelection(selectionOffs + (ev->pos().x() - selectionPoint.x()) / scale); - } - if ((ev->buttons() & Qt::RightButton) && ev->pos().x() != dragPoint.x()) - { - dragging = true; - setOffset(dragOffs - (ev->pos().x() - dragPoint.x()) / scale); - } -} - - -void QEDWaveTrackDisplay::mouseReleaseEvent(QMouseEvent *ev) -{ - if (ev->button() == Qt::LeftButton) - { - if (selecting) - { - selecting = false; - setSelection(selOffs + (ev->pos().x() - selPoint.x()) / scale); - } - } - else - if (ev->button() == Qt::RightButton && !dragging) - { - setTime(offs + getTimeFromCoord(ev->pos().x())); - } -} - - -QEDWaveTrackView::QEDWaveTrackView(QWidget *parent) : QWidget(parent) -{ - QHBoxLayout *mainLayout = new QHBoxLayout(this); - mainLayout->setMargin(0); - wave = new QEDWaveTrackDisplay(this); - - QFrame *infoLayoutContainer = new QFrame(this); - infoLayoutContainer->setFrameStyle(QFrame::StyledPanel | QFrame::Plain); - infoLayoutContainer->setLineWidth(2); - infoLayoutContainer->setFixedWidth(200); - - QVBoxLayout *infoLayout = new QVBoxLayout(infoLayoutContainer); - infoLayout->setMargin(0); - infoName = new QLabel("Audio"); - infoName->setStyleSheet("QLabel { background-color: black; color: white; padding: 2px; }"); - infoLayout->addWidget(infoName); - - infoData = new QLabel(); - infoData->setStyleSheet("QLabel { padding: 2px; }"); - infoLayout->addWidget(infoData); - - mainLayout->addWidget(infoLayoutContainer); - mainLayout->addWidget(wave); - - connect(wave, SIGNAL(timeChanged(float)), this, SLOT(slotTimeChanged(float))); - connect(wave, SIGNAL(offsetChanged(float)), this, SLOT(slotOffsetChanged(float))); - connect(wave, SIGNAL(selectionChanged(float,float)), this, SLOT(slotSelectionChanged(float,float))); -} - - -void QEDWaveTrackView::setWaveform(void *mdata, int msize, int mformat, int mchannels, int mfreq) -{ - QString fmt; - switch (mformat) - { - case AUDIO_S16SYS: fmt = "16bit (S)"; break; - case AUDIO_U16SYS: fmt = "16bit (U)"; break; - case AUDIO_S8: fmt = "8bit (S)"; break; - case AUDIO_U8: fmt = "8bit (U)"; break; - default: fmt = "?"; break; - } - infoData->setText(QString("<b>%1</b>, <b>%2</b> ch, <b>%3</b> Hz").arg(fmt).arg(mchannels).arg(mfreq)); - wave->setWaveform(mdata, msize, mformat, mchannels, mfreq); - update(); -} - - -void QEDWaveTrackView::setName(QString name) -{ - infoName->setText(name); - update(); -} - - -void QEDWaveTrackView::setTime(const float mtime) -{ - wave->setTime(mtime); -} - - -void QEDWaveTrackView::setOffset(const float moffs) -{ - wave->setOffset(moffs); -} - - -void QEDWaveTrackView::setScale(const float mscale) -{ - wave->setScale(mscale); -} - - -float QEDWaveTrackView::getTime() -{ - return wave->getTime(); -} - - -float QEDWaveTrackView::getOffset() -{ - return wave->getOffset(); -} - - -float QEDWaveTrackView::getScaledWidth() -{ - return wave->getScaledWidth(); -} - - -void QEDWaveTrackView::slotTimeChanged(float value) -{ - emit timeChanged(value); -} - - -void QEDWaveTrackView::slotOffsetChanged(float value) -{ - emit offsetChanged(value); -} - - -float QEDWaveTrackView::getDuration() -{ - return wave->getDuration(); -}
--- a/edwaveform.h Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,97 +0,0 @@ -#ifndef EDWAVEFORM_H -#define EDWAVEFORM_H - -#include <QWidget> -#include <QLabel> -#include "dmengine.h" - -class QEDWaveTrackDisplay : public QWidget -{ - Q_OBJECT - -public: - QEDWaveTrackDisplay(QWidget *parent = 0); - - void setWaveform(void *mdata, int msize, int mformat, int mchannels, int mfreq); - float getScaledWidth(); - void setScale(const float mscale); - int getBps(); - float getDuration(); - float getTimeScale(float value); - float getTimeFromCoord(float value); - float getTime(); - float getOffset(); - - QSize minimumSizeHint() const - { - return QSize(100, 60); - } - - QSize sizeHint() const - { - return QSize(600, 60); - } - -public slots: - void setTime(const float mtime); - void setOffset(const float moffs); - void setSelection(const float mstart, const float mend); - void clearSelection(); - -signals: - void selectionChanged(float mstart, float mduration); - void timeChanged(float value); - void offsetChanged(float value); - -protected: - void mousePressEvent(QMouseEvent *event); - void mouseMoveEvent(QMouseEvent *event); - void mouseReleaseEvent(QMouseEvent *event); - - void paintEvent(QPaintEvent *event); - -private: - float scale, time, offs, duration; // in milliseconds - int size, channels, format, freq, sduration; - void *data; - - bool selectionValid; - float selectionStart, selectionDuration; - - QPoint selectionPoint, dragPoint; - bool selecting, dragging; - float selectionOffs, dragOffs; -}; - - -class QEDWaveTrackView : public QWidget -{ - Q_OBJECT - -private: - QEDWaveTrackDisplay *wave; - QLabel *infoName, *infoData; - -public: - - QEDWaveTrackView(QWidget *parent = 0); - void setWaveform(void *mdata, int mlen, int mformat, int mchannels, int mfreq); - void setName(QString name); - void setTime(const float mtime); - void setOffset(const float moffs); - float getScaledWidth(); - void setScale(const float mscale); - float getDuration(); - float getTime(); - float getOffset(); - -private slots: - void slotTimeChanged(float value); - void slotOffsetChanged(float value); - -signals: - void timeChanged(float value); - void offsetChanged(float value); -}; - -#endif
--- a/efu.c Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,478 +0,0 @@ -#include "dmlib.h" -#include "dmargs.h" -#include "dmvecmat.h" -#include "dmimage.h" -#include "dmtext.h" -#include <math.h> - -#define DM_COLORS (256) - -char *optFontFile = "font.ttf", - *optBitmapFilename = "tnsp.png"; -BOOL optBenchmark = FALSE; -int optVFlags = SDL_SWSURFACE | SDL_HWPALETTE; -int optScrWidth = 640, optScrHeight = 480, optFontSize = 20, optScrDepth = 32; -int optBenchmarkLen = 20; - -DMOptArg optList[] = { - { 0, '?', "help", "Show this help", OPT_NONE }, - { 2, 'v', "verbose", "Be more verbose", OPT_NONE }, - { 3, 'f', "full", "Fullscreen", OPT_NONE }, - { 4, 'h', "hw", "Use SDL hardware surface", OPT_NONE }, - { 5, 's', "size", "Initial window size/resolution -s 640x480", OPT_ARGREQ }, - { 6, 'd', "depth", "Color depth of mode/window in bits (8/15/16/32)", OPT_ARGREQ }, - { 7, 'b', "bench", "Run in benchmark mode", OPT_NONE }, -}; - -const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - dmArgsPrintHelp(stdout, optList, optListN); -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - switch (optN) { - case 0: - argShowHelp(); - exit(0); - break; - - case 2: - dmVerbosity++; - break; - - case 3: - optVFlags |= SDL_FULLSCREEN; - break; - - case 6: - if (optArg) - optScrDepth = atoi(optArg); - break; - - case 5: - { - int w, h; - if (sscanf(optArg, "%dx%d", &w, &h) == 2) - { - if (w < 320 || h < 200 || w > 3200 || h > 3200) - { - dmError("Invalid width or height: %d x %d\n", w, h); - return FALSE; - } - optScrWidth = w; - optScrHeight = h; - } - else - { - dmError("Invalid size argument '%s'.\n", optArg); - return FALSE; - } - } - break; - - case 7: - optBenchmark = TRUE; - break; - - default: - dmError("Unknown option '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -void DM_MakePalette(SDL_Surface *scr) -{ - SDL_Color pal[DM_COLORS]; - int n; - - for (n = 0; n < 256; n++) - { - pal[n].r = n; - pal[n].g = n; - pal[n].b = n; - } - - SDL_SetColors(scr, pal, 0, DM_COLORS); -} - - -void DM_PrintRect(FILE *f, SDL_Rect *r) -{ - fprintf(f, "SDL_Rect <%d, %d : %d, %d>\n", - r->x, r->y, r->w, r->h); -} - -BOOL DM_InitializeVideo(SDL_Surface **screen) -{ - *screen = SDL_SetVideoMode(optScrWidth, optScrHeight, optScrDepth, optVFlags | SDL_RESIZABLE); - if (*screen == NULL) - { - dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); - return FALSE; - } - -#if 0 - SDL_Rect r; - r.x = -50; - r.y = 50; - r.w = 700; - r.h = 300; - DM_PrintRect(stderr, &r); - SDL_SetClipRect(*screen, &r); - DM_PrintRect(stderr, &r); - DM_PrintRect(stderr, &((*screen)->clip_rect)); -#endif - - return TRUE; -} - -void DM_Random(SDL_Surface *screen, int q) -{ - Uint8 *pix = screen->pixels; - int xc, yc; - - for (yc = 0; yc < screen->h; yc++) - { - Uint8 *dp = pix; - - for (xc = 0; xc < screen->w; xc++) - *dp++ = yc + (xc ^ q) + (yc & q); - - pix += screen->pitch; - } -} - - -#define QWIDTH 256 -#define QHEIGHT 160 - -typedef Uint8 DMBlockMap[QHEIGHT][QWIDTH]; - - -void dmMakeBumpMap(DMBlockMap map, DMFloat q, DMFloat m) -{ - int x, y; - for (y = 0; y < QHEIGHT; y++) - for (x = 0; x < QWIDTH; x++) - { - DMFloat f = 0.40f + dmPerlinNoise2D(x, y, 1.1f, q, 2); - map[y][x] = (int) (dmClamp10(f) * m); - } -} - - -void dmShadowTraceHeightMap(DMBlockMap lightMap, DMBlockMap pheightMap, DMVector *light) -{ - int i, j; - - light->z = 150; - - for (j = 0; j < QHEIGHT; j++) - for (i = 0; i < QWIDTH; i++) - { - DMVector vr, vl, va; - DMFloat vrayLen, vfactor; - int vlen; - BOOL wasHit; - - // Perform shadow occlusion via simplistic raytracing - vr.x = i; - vr.y = j; - vr.z = 200; //light->z; // - 10.0; - - // Calculate light vector vector - dm_vector_sub_r(&vl, &vr, light); - vrayLen = dm_vector_length(&vl); - -#if 1 - dm_vector_copy(&va, &vl); - dm_vector_normalize(&va); - dm_vector_copy(&vr, light); - - vlen = 0; - wasHit = FALSE; - do - { - float h; - - // If ray is inside the heightmap, get value - if (vr.x >= 0 && vr.y >= 0 && vr.x < QWIDTH && vr.y < QHEIGHT) - h = pheightMap[(int) vr.y][(int) vr.x]; - else - break; - - // Check for hits - if (h > vr.z) - wasHit = TRUE; - else - { - // Move forwards - dm_vector_add(&vr, &va); - vlen++; - } - } - while (!wasHit && vlen <= vrayLen); - - // Check if the ray hit something, e.g. is this point occluded? - if (wasHit && vlen < vrayLen) - { - vfactor = vlen * 0.05; - } - else - vfactor = vlen * 0.001; -#endif - -#if 0 - { - /* Calculate light's intensity based on the angle it "hits" - * - * 1) Calculate the vectors that form the imaginary "plane" - * 2) Cross-product -> normal vector of the plane - * 2) Normalize the normal vector - * 3) Calculate light vector's hit angle by dot product - */ - DMVector v1, v2; - DMFloat c; - - v1.x = 2.0f; - v1.y = 0.0f; - v1.z = (DMFloat) (pheightMap[j][i] - pheightMap[j][i + 1]); - - v2.x = 0.0f; - v2.y = 2.0f; - v2.z = (DMFloat) (pheightMap[j][i] - pheightMap[j + 1][i]); - - dm_vector_cross(&vr, &v1, &v2); - dm_vector_normalize(&vr); - dm_vector_normalize(&vl); - c = dm_vector_dot(&vl, &vr); - - vrayLen = 255 - (vrayLen * 0.1) * vrayLen + (c * 128.0f) + (vfactor * vfactor * 1255); - } -#else - vrayLen = 255 - vrayLen * vrayLen * (vfactor * vfactor); - if (vrayLen < 0) vrayLen = 0; - vrayLen -= pheightMap[j][i]; -#endif - - // Clip result - if (vrayLen < 0) - vrayLen = 0; - else if (vrayLen > 255.0f) - vrayLen = 255.0f; - - lightMap[j][i] = vrayLen; - } -} - - -int main(int argc, char *argv[]) -{ - SDL_Surface *screen = NULL, *bmap = NULL, *logo = NULL; - TTF_Font *font = NULL; - SDL_Color fontcol={255,155,155,0}; - SDL_Event event; - int mouseX, mouseY; - BOOL initSDL = FALSE, initTTF = FALSE, exitFlag, showMap = FALSE; - - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, NULL, FALSE)) - exit(1); - - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) - { - dmError("Could not initialize SDL: %s\n", SDL_GetError()); - goto error_exit; - } - initSDL = TRUE; - - - if (TTF_Init() < 0) - { - dmError("Could not initialize FreeType/TTF: %s\n", SDL_GetError()); - goto error_exit; - } - initTTF = TRUE; - - font = TTF_OpenFont(optFontFile, optFontSize); - if (font == NULL) - { - dmError("Could not load TTF font '%s' (%d): %s\n", - optFontFile, optFontSize, SDL_GetError()); - goto error_exit; - } - TTF_SetFontStyle(font, TTF_STYLE_NORMAL); - - - DMResource *res = dmf_create_stdio(optBitmapFilename, "rb"); - if (res == NULL) - { - dmError("Could not open resource file '%s'.\n", optBitmapFilename); - goto error_exit; - } - logo = dmLoadImage(res); - dmf_close(res); - if (logo == NULL) - { - dmError("Could not load image file '%s'.\n", optBitmapFilename); - goto error_exit; - } - - - if (optBenchmark) - { - screen = SDL_CreateRGBSurface(SDL_SWSURFACE, optScrWidth, optScrHeight, optScrDepth, 0, 0, 0, 0); - if (screen == NULL) - { - dmError("Could not create screen surface.\n"); - goto error_exit; - } - - dmMsg(0, "Benchmark mode, not opening window.\n"); - } - else - { - if (!DM_InitializeVideo(&screen)) - goto error_exit; - - SDL_WM_SetCaption("Halleluja", "DMT"); - } - - dmPerlinInit(); - - bmap = SDL_CreateRGBSurface(SDL_SWSURFACE, QWIDTH, QHEIGHT, 8, 0, 0, 0, 0); - DM_MakePalette(bmap); - DM_Random(bmap, 15); - - DMVector light; - DMBlockMap heightMap; - light.x = light.y = 128; - light.z = 128; - dmMakeBumpMap(heightMap, 0.06, 254); - - - - int numFrames = 0, startTime = SDL_GetTicks(), endTime = 0; - exitFlag = FALSE; - - if (optBenchmark) - dmMsg(0, "Starting benchmark, running for %d seconds.\n", optBenchmarkLen); - - while (!exitFlag) - { - if (!optBenchmark) - { - while (SDL_PollEvent(&event)) - switch (event.type) - { - case SDL_KEYDOWN: - switch (event.key.keysym.sym) - { - case SDLK_ESCAPE: exitFlag = TRUE; break; - - case SDLK_F1: - DM_Random(bmap, (SDL_GetTicks() / 10) % 1000); - break; - - case SDLK_F5: - showMap = !showMap; - break; - - default: - break; - } - - break; - - case SDL_VIDEORESIZE: - optScrWidth = event.resize.w; - optScrHeight = event.resize.h; - - if (!DM_InitializeVideo(&screen)) - goto error_exit; - - break; - - case SDL_VIDEOEXPOSE: - break; - - case SDL_QUIT: - exit(0); - } - - SDL_GetMouseState(&mouseX, &mouseY); - light.x = ((DMFloat) mouseX * QWIDTH) / (DMFloat) optScrWidth; - light.y = ((DMFloat) mouseY * QHEIGHT) / (DMFloat) optScrHeight; - } - - if (!optBenchmark && SDL_MUSTLOCK(screen) != 0 && SDL_LockSurface(screen) != 0) - { - dmError("Can't lock surface.\n"); - goto error_exit; - } - - - if (showMap) - memcpy(bmap->pixels, heightMap, QWIDTH * QHEIGHT); - else - dmShadowTraceHeightMap(bmap->pixels, logo->pixels, &light); - - dmScaledBlitSurfaceAny(bmap, 0, 0, screen->w, screen->h, screen, DMD_NONE); - - - - if (!optBenchmark) - { - dmDrawTTFText(screen, font, fontcol, 0, 0, "%3.1f FPS", - (float) (numFrames * 1000.0f) / (float) (endTime - startTime)); - - if (SDL_MUSTLOCK(screen) != 0) - SDL_UnlockSurface(screen); - - SDL_Flip(screen); - SDL_Delay(20); - } - - endTime = SDL_GetTicks(); - numFrames++; - - if (optBenchmark) - { - if (endTime - startTime > optBenchmarkLen * 1000) - exitFlag = TRUE; - } - } - - // Print benchmark results - dmMsg(0, "%d frames in %d ms, fps = %1.3f\n", - numFrames, endTime - startTime, - (float) (numFrames * 1000.0f) / (float) (endTime - startTime)); - - -error_exit: - dmMsg(0, "Shutting down dmlib.\n"); - if (screen) - SDL_FreeSurface(screen); - - if (logo) - SDL_FreeSurface(logo); - - if (font) - TTF_CloseFont(font); - - if (initSDL) - SDL_Quit(); - - if (initTTF) - TTF_Quit(); - - return 0; -}
--- a/gentab.c Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,264 +0,0 @@ -#include "dmlib.h" -#include "dmargs.h" -#include <math.h> - -enum -{ - MT_SIN, - MT_COS, - MT_SMOOTH1, - MT_SCURVE, - MT_SMOOTH1_CLAMP, - MT_SCURVE_CLAMP, - MT_SIN_SCURVE, - - MT_LAST -}; - - -typedef struct -{ - char *name; - char *desc; -} DMTransType; - -static DMTransType dmTransTypes[MT_LAST] = -{ - { "sin", "Sine" }, - { "cos", "Cosine" }, - { "smooth1", "Smoothstep1 LERP" }, - { "scurve", "S-curve LERP" }, - { "smooth1-clamp", "Clamped smoothstep1 LERP" }, - { "scurve-clamp", "Clamped S-curve LERP" }, - { "sin-scurve", "Sine S-curve" }, -}; - - -DMFloat - optSOffset = 0.0f, - optSAmplitude = 1.0f, - optSOmega = 1.0f, - optStartValue = 0.0f, - optEndValue = 1.0f; - -int optNSteps = 64, - optPerLine = 16, - optTransType = -1; - -char - *optObjectName = NULL, - *optOutFilename = NULL; - - -static DMOptArg optList[] = -{ - { 0, '?', "help", "Show this help", OPT_NONE }, - { 1, 'v', "verbose", "Increase verbosity", OPT_NONE }, - { 2, 'o', "output", "Set output file (default stdout)", OPT_ARGREQ }, - { 3, 'n', "name", "Set output object name", OPT_ARGREQ }, - - { 4, 's', "steps", "Number of steps/values in output table", OPT_ARGREQ }, - { 5, 't', "type", "Curve/interpolation type (see list)", OPT_ARGREQ }, - - { 6, 'O', "offset", "Output data offset", OPT_ARGREQ }, - { 7, 'A', "amplitude", "Output amplitude scale", OPT_ARGREQ }, - { 8, 'W', "omega", "Omega (w) multiplier", OPT_ARGREQ }, - - { 9, 'S', "start", "Start value (only smooth/scurve)", OPT_ARGREQ }, - { 10, 'E', "end", "End value (only smooth/scurve)", OPT_ARGREQ }, -}; - -static const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - int index; - dmPrintBanner(stdout, dmProgName, "[options]"); - dmArgsPrintHelp(stdout, optList, optListN); - - printf("\nAvailable types:\n"); - for (index = 0; index < MT_LAST; index++) - { - DMTransType *tm = &dmTransTypes[index]; - printf("%-15s | %s\n", tm->name, tm->desc); - } - printf("\n"); -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - switch (optN) - { - case 0: - argShowHelp(); - exit(0); - break; - - case 1: - dmVerbosity++; - break; - - case 2: - optOutFilename = optArg; - break; - - case 3: - optObjectName = optArg; - break; - - case 4: - { - int tmp; - if (sscanf(optArg, "%d", &tmp) != 1) - { - dmError("Invalid number of steps argument '%s'.\n", optArg); - return FALSE; - } - optNSteps = tmp; - } - break; - - case 5: - { - int index; - for (index = 0; index < MT_LAST; index++) - { - DMTransType *tm = &dmTransTypes[index]; - if (strcasecmp(tm->name, optArg) == 0) - { - optTransType = index; - return TRUE; - } - } - dmError("Invalid transformation type option '%s'.\n", - optArg); - return FALSE; - } - break; - - case 6: - case 7: - case 8: - case 9: - case 10: - { - DMFloat tmp; - if (sscanf(optArg, "%f", &tmp) != 1) - { - dmError("Invalid %s option argument '%s', expected a floating point value.\n", - currArg, optArg); - return FALSE; - } - switch (optN) - { - case 6: optSOffset = tmp; break; - case 7: optSAmplitude = tmp; break; - case 8: optSOmega = tmp; break; - case 9: optStartValue = tmp; break; - case 10: optEndValue = tmp; break; - } - } - break; - - default: - dmError("Unknown argument '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -int main(int argc, char *argv[]) -{ - FILE *outFile; - DMLerpContext ctx; - int step, n; - - dmInitProg("gentab", "Sine, etc. table generator", "0.1", NULL, NULL); - dmVerbosity = 1; - - // Parse arguments - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, NULL, TRUE)) - exit(1); - - // Check settings - if (optTransType < 0) - { - dmError("No transformation type set, perhaps try --help\n"); - return -1; - } - - if (optObjectName == NULL) - { - dmError("Object name not specified, try --help\n"); - return -2; - } - - if (optOutFilename == NULL) - outFile = stdout; - else - if ((outFile = fopen(optOutFilename, "w")) == NULL) - { - int err = dmGetErrno(); - dmError("Could not open output file '%s', %d: %s\n", - optOutFilename, err, dmErrorStr(err)); - return -2; - } - - - // Generate table - dmLerpInit(&ctx, optStartValue, optEndValue, optNSteps); - - fprintf(outFile, - "cnt_%s = %d\n" - "vtab_%s: ", - optObjectName, - optNSteps, - optObjectName - ); - - for (n = 0, step = 0; step < optNSteps; step++) - { - DMFloat t = ((DMFloat) step * optSOmega) / (DMFloat) optNSteps, delta, value; - - switch (optTransType) - { - case MT_SIN: delta = sin(t * 2 * DM_PI); break; - case MT_COS: delta = cos(t * 2 * DM_PI); break; - - case MT_SMOOTH1: delta = dmLerp1(&ctx, step); break; - case MT_SCURVE: delta = dmLerpSCurve(&ctx, step); break; - case MT_SMOOTH1_CLAMP: delta = dmLerp1Clamp(&ctx, step); break; - case MT_SCURVE_CLAMP: delta = dmLerpSCurveClamp(&ctx, step); break; - case MT_SIN_SCURVE: delta = dmLerpSCurveClamp(&ctx, step); break; - - default: delta = 0; - } - - value = optSOffset + delta * optSAmplitude; - - // Print the value - if (n == 0) - fprintf(outFile, "\t.byte "); - - fprintf(outFile, "%ld%s", - lrint(value), - (n < optPerLine - 1) ? "," : ""); - - if (++n >= optPerLine) - { - fprintf(outFile, "\n"); - n = 0; - } - } - if (n > 0) - fprintf(outFile, "\n"); - - fprintf(outFile, "\n"); - - return 0; -}
--- a/gfxconv.c Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1697 +0,0 @@ -/* - * gfxconv - Convert various graphics formats - * 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 "dmmutex.h" -#include "libgfx.h" -#include "lib64gfx.h" - -//#define UNFINISHED 1 - -#define DM_MAX_COLORS 256 - -#define ASC_NBITS 8 -#define ASC_NCOLORS 4 -static const char dmASCIIPalette[ASC_NCOLORS] = ".:X#"; - -enum -{ - FFMT_AUTO = 0, - - FFMT_ASCII, - FFMT_ANSI, - FFMT_IMAGE, - - FFMT_CHAR, - FFMT_SPRITE, - FFMT_BITMAP, - - FFMT_LAST -}; - - -typedef struct -{ - char *name; - char *fext; - BOOL in, out; - int format; - int subformat; -} DMConvFormat; - - -static DMConvFormat convFormatList[] = -{ - { - "ASCII text", "asc", FALSE, TRUE, - FFMT_ASCII , 0, - }, - { - "ANSI colored text", "ansi", FALSE, TRUE, - FFMT_ANSI , 0, - }, - { - "PNG image file", "png", TRUE, TRUE, - FFMT_IMAGE , IMGFMT_PNG, - }, - { - "PPM image file", "ppm", FALSE, TRUE, - FFMT_IMAGE , IMGFMT_PPM, - }, - { - "PCX image file", "pcx", TRUE, TRUE, - FFMT_IMAGE , IMGFMT_PCX, - }, - { - "IFF ILBM file", "lbm", TRUE, FALSE, - FFMT_IMAGE , IMGFMT_ILBM, - }, - { - "Bitplaned RAW (intl/non-intl) image file", "raw", FALSE, TRUE, - FFMT_IMAGE , IMGFMT_RAW, - }, - { - "IFFMaster RAW image file", "araw", FALSE, TRUE, - FFMT_IMAGE , IMGFMT_ARAW, - }, - - { - "C64 bitmap image file", NULL, TRUE, TRUE, - FFMT_BITMAP , -1, - }, - - { - "C64 character/font data", "chr", TRUE, TRUE, - FFMT_CHAR , 0 - }, - { - "C64 sprite data", "spr", TRUE, TRUE, - FFMT_SPRITE , 0 - }, -}; - -static const int nconvFormatList = sizeof(convFormatList) / sizeof(convFormatList[0]); - - -typedef struct -{ - BOOL triplet, alpha; - DMColor color; - int from, to; -} DMMapValue; - - - -char *optInFilename = NULL, - *optOutFilename = NULL; -int optInFormat = FFMT_AUTO, - optOutFormat = FFMT_ASCII, - optInSubFormat = IMGFMT_PNG, - optOutSubFormat = IMGFMT_PNG, - optItemCount = -1, - optPlanedWidth = 1, - optForcedFormat = -1; -int optInSkip = 0; -BOOL optInMulticolor = FALSE, - optSequential = FALSE, - optRemapColors = FALSE, - optRemapRemove = FALSE; -int optNRemapTable = 0; -DMMapValue optRemapTable[DM_MAX_COLORS]; -int optColors[C64_MAX_COLORS]; - -DMImageSpec optSpec = -{ - .scale = 1, - .nplanes = 4, - .interleave = FALSE, - .paletted = FALSE, - .format = 0, -}; - -static DMOptArg optList[] = -{ - { 0, '?', "help", "Show this help", OPT_NONE }, - { 15, 'v', "verbose", "Increase verbosity", OPT_NONE }, - { 3, 'o', "output", "Output filename", OPT_ARGREQ }, - { 1, 'i', "informat", "Set input format ([s]prite, [c]har, [b]itmap, [i]mage)", OPT_ARGREQ }, - { 2, 'm', "multicolor", "Input is multicolor / output in multicolor", OPT_NONE }, - { 4, 's', "skip", "Skip bytes in input", OPT_ARGREQ }, - { 5, 'f', "format", "Output format (see --formats)", OPT_ARGREQ }, - { 17, 'F', "formats", "Output format (see list below)", OPT_NONE }, - { 8, 'q', "sequential", "Output sequential files (image output only)", OPT_NONE }, - { 6, 'c', "colormap", "Color mappings (see below for information)", OPT_ARGREQ }, - { 7, 'n', "numitems", "How many 'items' to view (default: all)", OPT_ARGREQ }, - { 9, 'S', "scale", "Scale output by x (image output only)", OPT_ARGREQ }, - { 10, 'b', "bformat", "Force input bitmap format (see below)", OPT_ARGREQ }, - { 11, 'w', "width", "Item width (number of items per row, min 1)", OPT_ARGREQ }, - { 12, 'P', "paletted", "Use indexed/paletted output (png, pcx output only)", OPT_NONE }, - { 13, 'B', "bplanes", "Bits per pixel OR # of bitplanes (certain output formats)", OPT_ARGREQ }, - { 14, 'I', "interleave", "Interleave scanlines (default: output whole planes)", OPT_NONE }, - { 16, 'R', "remap", "Remap output image colors (-R <(#RRGGBB|index):index>[,<..>] | -R @map.txt)", OPT_ARGREQ }, - { 18, 'r', "remap-remove", "Remove unused colors from remapped palette (requires -R)", OPT_NONE }, -}; - -static const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowFormats() -{ - int i; - - printf( - "Available input/output formats:\n" - " Ext | I | O | Description\n" - "------+---+---+-----------------------------------------------\n" - ); - - for (i = 0; i < nconvFormatList; i++) - { - DMConvFormat *fmt = &convFormatList[i]; - printf("%-5s | %c | %c | %s\n", - fmt->fext ? fmt->fext : "", - fmt->in ? 'X' : ' ', - fmt->out ? 'X' : ' ', - fmt->name); - } - - printf( - "\n" - "(Not all input->output combinations are actually supported.)\n" - "\n" - "Available bitmap formats:\n" - " Ext | Type | Description\n" - "------+-----------------+-------------------------------------\n" - ); - - for (i = 0; i < ndmC64ImageFormats; i++) - { - const DMC64ImageFormat *fmt = &dmC64ImageFormats[i]; - char buf[64]; - printf("%-5s | %-15s | %s\n", - fmt->fext, - dmC64GetImageTypeString(buf, sizeof(buf), fmt->type), - fmt->name); - } -} - - -void argShowHelp() -{ - dmPrintBanner(stdout, dmProgName, "[options] <input file>"); - dmArgsPrintHelp(stdout, optList, optListN); - - printf( - "\n" - "Color map definitions are used for ANSI and image output, to declare what\n" - "output colors of the C64 palette are used for each single color/multi color\n" - "bit-combination. For example, if the input is multi color sprite or char,\n" - "you can define colors like: -c 0,8,3,15 .. for single color: -c 0,1\n" - "The numbers are palette indexes, and the order is for bit(pair)-values\n" - "00, 01, 10, 11 (multi color) and 0, 1 (single color). NOTICE! 255 is the\n" - "special color that can be used for transparency.\n" - ); -} - - -int dmGetConvFormat(int format, int subformat) -{ - int i; - for (i = 0; i < nconvFormatList; i++) - { - DMConvFormat *fmt = &convFormatList[i]; - if (fmt->format == format && - fmt->subformat == subformat) - return i; - } - return -1; -} - - -BOOL dmGetFormatByExt(const char *fext, int *format, int *subformat) -{ - int i; - if (fext == NULL) - return FALSE; - - for (i = 0; i < nconvFormatList; i++) - { - DMConvFormat *fmt = &convFormatList[i]; - if (fmt->fext != NULL && - strcasecmp(fext, fmt->fext) == 0) - { - *format = fmt->format; - *subformat = fmt->subformat; - return TRUE; - } - } - - for (i = 0; i < ndmC64ImageFormats; i++) - { - const DMC64ImageFormat *fmt = &dmC64ImageFormats[i]; - if (fmt->fext != NULL && - strcasecmp(fext, fmt->fext) == 0) - { - *format = FFMT_BITMAP; - *subformat = i; - return TRUE; - } - } - - return FALSE; -} - - -static BOOL dmParseMapOptionMapItem(const char *popt, DMMapValue *value, const int nmax, const char *msg) -{ - char *end, *split, *opt = dm_strdup(popt); - - if (opt == NULL) - goto error; - - if ((end = split = strchr(opt, ':')) == NULL) - { - dmError("Invalid %s value '%s', expected <(#|%)RRGGBB|[$|0x]index>:<[$|0x]index>.\n", msg, opt); - goto error; - } - - // Trim whitespace - *end = 0; - for (end--; end > opt && *end && isspace(*end); end--) - *end = 0; - - // Parse either a hex triplet color definition or a normal value - if (*opt == '#' || *opt == '%') - { - int colR, colG, colB, colA; - - if (sscanf(opt + 1, "%2x%2x%2x%2x", &colR, &colG, &colB, &colA) == 4 || - sscanf(opt + 1, "%2X%2X%2X%2X", &colR, &colG, &colB, &colA) == 4) - { - value->alpha = TRUE; - value->color.a = colA; - } - else - if (sscanf(opt + 1, "%2x%2x%2x", &colR, &colG, &colB) != 3 && - sscanf(opt + 1, "%2X%2X%2X", &colR, &colG, &colB) != 3) - { - dmError("Invalid %s value '%s', expected a hex triplet, got '%s'.\n", msg, popt, opt + 1); - goto error; - } - - value->color.r = colR; - value->color.g = colG; - value->color.b = colB; - value->triplet = TRUE; - } - else - { - if (!dmGetIntVal(opt, &value->from)) - { - dmError("Invalid %s value '%s', could not parse source value '%s'.\n", msg, popt, opt); - goto error; - } - value->triplet = FALSE; - } - - // Trim whitespace - split++; - while (*split && isspace(*split)) split++; - - // Parse destination value - if (!dmGetIntVal(split, &value->to)) - { - dmError("Invalid %s value '%s', could not parse destination value '%s'.\n", msg, popt, split); - goto error; - } - - if (!value->triplet && (value->from < 0 || value->from > 255)) - { - dmError("Invalid %s map source color index value %d, must be [0..255].\n", msg, value->from); - goto error; - } - - if (value->to < 0 || value->to > nmax) - { - dmError("Invalid %s map destination color index value %d, must be [0..%d].\n", msg, value->to, nmax); - goto error; - } - - dmFree(opt); - return TRUE; - -error: - dmFree(opt); - return FALSE; -} - - -static BOOL dmParseMapOptionItem(char *opt, char *end, void *pvalue, const int index, const int nmax, const BOOL requireIndex, const char *msg) -{ - // Trim whitespace - if (end != NULL) - { - *end = 0; - for (end--; end > opt && *end && isspace(*end); end--) - *end = 0; - } - while (*opt && isspace(*opt)) opt++; - - // Parse item based on mode - if (requireIndex) - { - DMMapValue *value = (DMMapValue *) pvalue; - if (!dmParseMapOptionMapItem(opt, &value[index], nmax, msg)) - return FALSE; - } - else - { - int *value = (int *) pvalue; - char *split = strchr(opt, ':'); - if (split != NULL) - { - dmError("Unexpected ':' in indexed %s '%s'.\n", msg, opt); - return FALSE; - } - - if (!dmGetIntVal(opt, &value[index])) - { - dmError("Invalid %s value '%s', could not parse.\n", msg, opt); - return FALSE; - } - } - - return TRUE; -} - - -BOOL dmParseMapOptionString(char *opt, void *values, int *nvalues, const int nmax, const BOOL requireIndex, const char *msg) -{ - char *end, *start = opt; - - *nvalues = 0; - while (*nvalues < nmax && *start && (end = strchr(start, ',')) != NULL) - { - if (!dmParseMapOptionItem(start, end, values, *nvalues, nmax, requireIndex, msg)) - return FALSE; - - start = end + 1; - (*nvalues)++; - } - - if (*start && *nvalues < nmax) - { - if (!dmParseMapOptionItem(start, NULL, values, *nvalues, nmax, requireIndex, msg)) - return FALSE; - - (*nvalues)++; - } - - return TRUE; -} - - -int dmParseColorRemapFile(const char *filename, DMMapValue *values, int *nvalue, const int nmax) -{ - FILE *fp; - char line[512]; - int res = DMERR_OK; - - if ((fp = fopen(filename, "r")) == NULL) - { - res = dmGetErrno(); - dmError("Could not open color remap file '%s' for reading, %d: %s\n", - res, dmErrorStr(res)); - return res; - } - - while (fgets(line, sizeof(line), fp)) - { - char *start = line; - while (*start && isspace(*start)) start++; - - if (*start != 0 && *start != ';') - { - if (!dmParseMapOptionMapItem(line, &values[*nvalue], nmax, "mapping file")) - goto error; - else - { - (*nvalue)++; - if (*nvalue >= nmax) - { - dmError("Too many mapping pairs in '%s', maximum is %d.\n", - filename, nmax); - goto error; - } - } - } - } - -error: - fclose(fp); - return res; -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - switch (optN) - { - case 0: - argShowHelp(); - exit(0); - break; - - case 17: - argShowFormats(); - exit(0); - break; - - case 15: - dmVerbosity++; - break; - - case 1: - switch (tolower(optArg[0])) - { - case 's': - optInFormat = FFMT_SPRITE; - break; - case 'c': - optInFormat = FFMT_CHAR; - break; - case 'b': - optInFormat = FFMT_BITMAP; - break; - case 'i': - optInFormat = FFMT_IMAGE; - break; - default: - dmError("Invalid input format '%s'.\n", optArg); - return FALSE; - } - break; - - case 2: - optInMulticolor = TRUE; - break; - - case 3: - optOutFilename = optArg; - break; - - case 4: - if (!dmGetIntVal(optArg, &optInSkip)) - { - dmError("Invalid skip value argument '%s'.\n", optArg); - return FALSE; - } - break; - - case 5: - if (!dmGetFormatByExt(optArg, &optOutFormat, &optOutSubFormat)) - { - dmError("Invalid output format '%s'.\n", optArg); - return FALSE; - } - break; - - case 6: - { - int index, ncolors; - if (!dmParseMapOptionString(optArg, optColors, - &ncolors, C64_MAX_COLORS, FALSE, "color table option")) - return FALSE; - - dmMsg(1, "Set color table: "); - for (index = 0; index < ncolors; index++) - { - dmPrint(1, "[%d:%d]%s", - index, optColors[index], - (index < ncolors) ? ", " : ""); - } - dmPrint(1, "\n"); - } - break; - - case 7: - if (sscanf(optArg, "%d", &optItemCount) != 1) - { - dmError("Invalid count value argument '%s'.\n", optArg); - return FALSE; - } - break; - - case 8: - optSequential = TRUE; - break; - - case 9: - { - int tmp = atoi(optArg); - if (tmp < 1 || tmp > 50) - { - dmError("Invalid scale value '%s'.\n", optArg); - return FALSE; - } - optSpec.scale = tmp; - } - break; - - case 11: - { - int tmp = atoi(optArg); - if (tmp < 1 || tmp > 512) - { - dmError("Invalid width value '%s'.\n", optArg); - return FALSE; - } - optPlanedWidth = tmp; - } - break; - - case 12: - optSpec.paletted = TRUE; - break; - - case 13: - { - int tmp = atoi(optArg); - if (tmp < 1 || tmp > 8) - { - dmError("Invalid bitplanes/bpp value '%s'.\n", optArg); - return FALSE; - } - optSpec.nplanes = tmp; - } - break; - - case 14: - optSpec.interleave = TRUE; - break; - - - case 16: - if (optArg[0] == '@') - { - if (optArg[1] != 0) - { - int res; - if ((res = dmParseColorRemapFile(optArg + 1, - optRemapTable, &optNRemapTable, DM_MAX_COLORS)) != DMERR_OK) - return FALSE; - } - else - { - dmError("No remap filename given.\n"); - return FALSE; - } - } - else - { - if (!dmParseMapOptionString(optArg, optRemapTable, - &optNRemapTable, DM_MAX_COLORS, TRUE, "color remap option")) - return FALSE; - } - - optRemapColors = TRUE; - break; - - case 18: - optRemapRemove = TRUE; - break; - - default: - dmError("Unknown option '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -BOOL argHandleFile(char *currArg) -{ - if (!optInFilename) - optInFilename = currArg; - else - { - dmError("Source filename already specified, extraneous argument '%s'.\n", - currArg); - return FALSE; - } - - return TRUE; -} - - -void dmPrintByte(FILE *out, int byte, int format, BOOL multicolor) -{ - int i; - - if (multicolor) - { - for (i = ASC_NBITS; i; i -= 2) - { - int val = (byte & (3ULL << (i - 2))) >> (i - 2); - char ch; - switch (format) - { - case FFMT_ASCII: - ch = dmASCIIPalette[val]; - fprintf(out, "%c%c", ch, ch); - break; - case FFMT_ANSI: - fprintf(out, "%c[0;%d;%dm##%c[0m", - 0x1b, - 1, - 31 + optColors[val], - 0x1b); - break; - } - } - } - else - { - for (i = ASC_NBITS; i; i--) - { - int val = (byte & (1ULL << (i - 1))) >> (i - 1); - char ch; - switch (format) - { - case FFMT_ASCII: - ch = val ? '#' : '.'; - fputc(ch, out); - break; - case FFMT_ANSI: - fprintf(out, "%c[0;%d;%dm %c[0m", - 0x1b, - 1, - 31 + optColors[val], - 0x1b); - break; - } - } - } -} - - -void dmDumpCharASCII(FILE *outFile, const Uint8 *buf, int *offs, int format, BOOL multicolor) -{ - int yc; - - for (yc = 0; yc < C64_CHR_HEIGHT; yc++) - { - fprintf(outFile, "%04x : ", *offs); - dmPrintByte(outFile, buf[yc], format, multicolor); - fprintf(outFile, "\n"); - (*offs)++; - } -} - - -void dmDumpSpriteASCII(FILE *outFile, const Uint8 *buf, int *offs, int format, BOOL multicolor) -{ - int bufOffs, xc, yc; - - for (bufOffs = yc = 0; yc < C64_SPR_HEIGHT; yc++) - { - fprintf(outFile, "%04x : ", *offs); - for (xc = 0; xc < C64_SPR_WIDTH; xc++) - { - dmPrintByte(outFile, buf[bufOffs], format, multicolor); - fprintf(outFile, " "); - bufOffs++; - (*offs)++; - } - fprintf(outFile, "\n"); - } - (*offs)++; -} - - -#ifdef UNFINISHED -int dmConvertBMP2(DMImage *screen, const DM64Image *img) -{ - int yc; - Uint8 *dp = screen->data; - - for (yc = 0; yc < screen->height; yc++) - { - Uint8 *d = dp; - const int y = yc / 8, yb = yc & 7; - const int scroffsy = y * C64_SCR_CH_WIDTH; - const int bmoffsy = y * C64_SCR_WIDTH; - int xc; - - for (xc = 0; xc < screen->width / 2; xc++) - { - const int x = xc / 4; - const int scroffs = scroffsy + x; - const int b = img->bitmap[0][bmoffsy + (x * 8) + yb]; - const int v = 6 - ((xc * 2) & 6); - Uint8 c; - - switch ((b >> v) & 3) - { - case 0: c = img->bgcolor; break; - case 1: c = img->screen[0][scroffs] >> 4; break; - case 2: c = img->screen[0][scroffs] & 15; break; - case 3: c = img->color[0][scroffs] & 15; break; - } - - *d++ = c; - *d++ = c; - } - - dp += screen->pitch; - } - - return 0; -} -#endif - - -int dmRemapImageColors(DMImage *image) -{ - DMColor *npal = dmCalloc(image->ncolors, sizeof(DMColor)); - int *mapping = dmMalloc(image->ncolors * sizeof(int)); - BOOL *mapped = dmMalloc(image->ncolors * sizeof(BOOL)); - BOOL *used = dmMalloc(image->ncolors * sizeof(BOOL)); - int n, index, xc, yc, ncolors; - - dmMsg(1, "Remapping %d output image colors of %d colors.\n", optNRemapTable, image->ncolors); - - if (npal == NULL || mapping == NULL || mapped == NULL || used == NULL) - { - dmError("Could not allocate memory for reused palette.\n"); - return DMERR_MALLOC; - } - - for (index = 0; index < image->ncolors; index++) - { - mapping[index] = -1; - mapped[index] = used[index] = FALSE; - } - - // Find used colors - dmMsg(2, "Scanning image for used colors...\n"); - for (ncolors = yc = 0; yc < image->height; yc++) - { - Uint8 *dp = image->data + image->pitch * yc; - for (xc = 0; xc < image->width; xc++) - { - Uint8 col = dp[xc]; - if (col < image->ncolors && !used[col]) - { - used[col] = TRUE; - ncolors++; - } - } - } - dmMsg(2, "Found %d used colors, creating remap-table.\n", ncolors); - - // Match and mark mapped colors - for (index = 0; index < optNRemapTable; index++) - { - DMMapValue *map = &optRemapTable[index]; - if (map->triplet) - { - BOOL found = FALSE; - for (n = 0; n < image->ncolors; n++) - { - if (dmCompareColor(&(image->pal[n]), &(map->color), map->alpha)) - { - dmMsg(3, "RGBA match #%02x%02x%02x%02x: %d -> %d\n", - map->color.r, map->color.g, map->color.b, map->color.a, - n, - map->to); - - mapping[n] = map->to; - mapped[map->to] = TRUE; - found = TRUE; - } - } - - if (!found) - { - dmMsg(3, "No RGBA match found for map index %d, #%02x%02x%02x%02x\n", - index, - map->color.r, map->color.g, map->color.b, map->color.a); - } - } - else - { - dmMsg(3, "Map index: %d -> %d\n", - map->from, map->to); - - mapping[map->from] = map->to; - mapped[map->to] = TRUE; - } - } - - - // Fill in the rest - if (optRemapRemove) - { - dmMsg(2, "Removing unused colors.\n"); - for (index = 0; index < image->ncolors; index++) - if (mapping[index] < 0 && used[index]) - { - for (n = 0; n < image->ncolors; n++) - if (!mapped[n]) - { - mapping[index] = n; - mapped[n] = TRUE; - break; - } - } - } - else - { - for (index = 0; index < image->ncolors; index++) - if (mapping[index] < 0) - { - for (n = 0; n < image->ncolors; n++) - if (!mapped[n]) - { - mapping[index] = n; - mapped[n] = TRUE; - break; - } - } - } - - // Calculate final number of palette colors - ncolors = 0; - for (index = 0; index < image->ncolors; index++) - { - if (mapping[index] + 1 > ncolors) - ncolors = mapping[index] + 1; - } - - // Copy palette entries - for (index = 0; index < image->ncolors; index++) - { - if (mapping[index] >= 0) - { - memcpy(&npal[mapping[index]], &(image->pal[index]), sizeof(DMColor)); - } - } - - // Remap image - dmMsg(1, "Remapping image to %d colors...\n", ncolors); - for (yc = 0; yc < image->height; yc++) - { - Uint8 *dp = image->data + image->pitch * yc; - for (xc = 0; xc < image->width; xc++) - { - Uint8 col = dp[xc]; - if (col < image->ncolors && mapping[col] >= 0 && mapping[col] < image->ncolors) - dp[xc] = mapping[col]; - else - dp[xc] = 0; - } - } - - // Set new palette, free memory - dmFree(image->pal); - image->pal = npal; - image->ncolors = ncolors; - - dmFree(mapping); - dmFree(mapped); - dmFree(used); - return DMERR_OK; -} - - -int dmWriteBitmap(const char *filename, DMC64Image *image, int iformat, BOOL enableFixUps) -{ - FILE *outFile = NULL; - Uint8 *buf = NULL; - size_t bufSize; - int res = DMERR_OK; - const DMC64ImageFormat *fmt = &dmC64ImageFormats[iformat]; - - dmMsg(1, "Converting to %s format bitmap.\n", fmt->name); - if (image->type != fmt->type && enableFixUps) - { - // Try to do some simple fixups - if ((fmt->type & D64_FMT_FLI) && (image->type & D64_FMT_FLI) == 0) - { - dmMsg(1, "Upconverting multicolor to FLI.\n"); - int i; - for (i = 1; i < C64_SCR_MAX_BANK; i++) - { - memcpy(image->color[i], image->color[0], C64_SCR_COLOR_SIZE); - memcpy(image->screen[i], image->screen[0], C64_SCR_SCREEN_SIZE); - } - } - } - - - if ((res = dmC64EncodeGenericBMP(&buf, &bufSize, image, fmt)) != DMERR_OK) - goto error; - - dmMsg(2, "Result: %d bytes\n", bufSize); - - if ((outFile = fopen(filename, "wb")) == NULL) - { - res = dmGetErrno(); - dmError("Error opening output file '%s', %d: %s\n", - filename, res, dmErrorStr(res)); - goto error; - } - - if (!dm_fwrite_str(outFile, buf, bufSize)) - { - res = dmGetErrno(); - dmError("Error writing image data to '%s', %d: %s\n", - filename, res, dmErrorStr(res)); - } - -error: - if (outFile != NULL) - fclose(outFile); - dmFree(buf); - return res; -} - - -int dmWriteImage(const char *filename, DMImage *image, DMImageSpec *spec, int iformat, BOOL info) -{ - if (info) - { - dmMsg(1, "Outputting %s image %d x %d -> %d x %d [%d]\n", - dmImageFormatList[iformat].fext, - image->width, image->height, - image->width * spec->scale, image->height * spec->scale, - spec->scale); - } - - // Perform color remapping - if (optRemapColors) - { - int res; - if ((res = dmRemapImageColors(image)) != DMERR_OK) - return res; - } - - switch (iformat) - { -#ifdef DM_USE_LIBPNG - case IMGFMT_PNG: - if (info) dmMsg(2, "%s output.\n", spec->paletted ? "Indexed 8bpp" : "32bit RGBA"); - spec->format = spec->paletted ? DM_IFMT_PALETTE : DM_IFMT_RGBA; - return dmWritePNGImage(filename, image, spec); -#endif - - case IMGFMT_PPM: - if (info) dmMsg(2, "24bit RGB output.\n"); - spec->format = DM_IFMT_RGB; - return dmWritePPMImage(filename, image, spec); - - case IMGFMT_PCX: - if (info) dmMsg(2, "%s output.\n", spec->paletted ? "Indexed 8bpp" : "24bit RGB"); - return dmWritePCXImage(filename, image, spec); - - case IMGFMT_RAW: - case IMGFMT_ARAW: - { - FILE *fp; - char *dataFilename, *fext, *tmpFilename = dm_strdup(filename); - - // Form data file filename - if (tmpFilename == NULL) - return DMERR_MALLOC; - - fext = strrchr(tmpFilename, '.'); - if (fext != NULL) - *fext = 0; - dataFilename = dm_strdup_printf("%s.inc", tmpFilename); - dmFree(tmpFilename); - - // Open data file for writing - if ((fp = fopen(dataFilename, "w")) == NULL) - dmError("Could not create '%s'.\n", dataFilename); - dmFree(dataFilename); - - if (fp != NULL) - { - // Strip extension - int i; - char *palID = dm_strdup_printf("img_%s", filename); - char *fext = strrchr(palID, '.'); - if (fext != NULL) - *fext = 0; - - // Replace any non-alphanumerics - for (i = 0; palID[i]; i++) - { - if (isalnum(palID[i])) - palID[i] = tolower(palID[i]); - else - palID[i] = '_'; - } - - if (iformat == IMGFMT_ARAW) - { - fprintf(fp, - "%s_width: dw.w %d\n" - "%s_height: dw.w %d\n" - "%s_nplanes: dw.w %d\n" - "%s_ncolors: dw.w %d\n" - "%s_palette:\n", - palID, image->width, - palID, image->height, - palID, spec->nplanes, - palID, image->ncolors, - palID); - - dmWriteIFFMasterRAWPalette(fp, image, 1 << optSpec.nplanes, NULL, NULL); - - fprintf(fp, - "%s: incbin \"%s\"\n", - palID, filename); - } - else - { - fprintf(fp, - "%s_width: dw.w %d\n" - "%s_height: dw.w %d\n" - "%s_nplanes: dw.w %d\n", - palID, image->width, - palID, image->height, - palID, spec->nplanes); - } - - fclose(fp); - dmFree(palID); - } - - if (info) dmMsg(2, "%d bitplanes, %s interleave.\n", spec->nplanes, spec->interleave ? "with" : "without"); - return dmWriteRAWImage(filename, image, spec); - } - break; - - default: - return DMERR_INVALID_DATA; - } -} - - -static Uint8 dmConvertByte(const Uint8 *sp, const BOOL multicolor) -{ - Uint8 byte = 0; - int xc; - - if (multicolor) - { - for (xc = 0; xc < 8 / 2; xc++) - { - Uint8 pixel = sp[xc * 2] & 3; - byte |= pixel << (6 - (xc * 2)); - } - } - else - { - for (xc = 0; xc < 8; xc++) - { - Uint8 pixel = sp[xc] == 0 ? 0 : 1; - byte |= pixel << (7 - xc); - } - } - - return byte; -} - - -BOOL dmConvertImage2Char(Uint8 *buf, const DMImage *image, - const int xoffs, const int yoffs, const BOOL multicolor) -{ - int yc; - - if (xoffs < 0 || yoffs < 0 || - xoffs + C64_CHR_WIDTH_PX > image->width || - yoffs + C64_CHR_HEIGHT > image->height) - return FALSE; - - for (yc = 0; yc < C64_CHR_HEIGHT; yc++) - { - const Uint8 *sp = image->data + ((yc + yoffs) * image->pitch) + xoffs; - buf[yc] = dmConvertByte(sp, multicolor); - } - - return TRUE; -} - - -BOOL dmConvertImage2Sprite(Uint8 *buf, const DMImage *image, - const int xoffs, const int yoffs, const BOOL multicolor) -{ - int yc, xc; - - if (xoffs < 0 || yoffs < 0 || - xoffs + C64_SPR_WIDTH_PX > image->width || - yoffs + C64_SPR_HEIGHT > image->height) - return FALSE; - - for (yc = 0; yc < C64_SPR_HEIGHT; yc++) - { - for (xc = 0; xc < C64_SPR_WIDTH_PX / C64_SPR_WIDTH; xc++) - { - const Uint8 *sp = image->data + ((yc + yoffs) * image->pitch) + (xc * 8) + xoffs; - buf[(yc * C64_SPR_WIDTH) + xc] = dmConvertByte(sp, multicolor); - } - } - - return TRUE; -} - - -int dmWriteSpritesAndChars(const char *filename, DMImage *image, int outFormat, BOOL multicolor) -{ - int outBlockW, outBlockH, bx, by; - FILE *outFile = NULL; - Uint8 *buf = NULL; - size_t bufSize; - char *outType; - - switch (outFormat) - { - case FFMT_CHAR: - bufSize = C64_CHR_SIZE; - outBlockW = image->width / C64_CHR_WIDTH_PX; - outBlockH = image->height / C64_CHR_HEIGHT; - outType = "char"; - break; - - case FFMT_SPRITE: - bufSize = C64_SPR_SIZE; - outBlockW = image->width / C64_SPR_WIDTH_PX; - outBlockH = image->height / C64_SPR_HEIGHT; - outType = "sprite"; - break; - - default: - dmError("Invalid output format %d, internal error.\n", outFormat); - goto error; - } - - if (outBlockW <= 0 || outBlockH <= 0) - { - dmError("Source image dimensions too small for conversion, block dimensions %d x %d.\n", - outBlockW, outBlockH); - goto error; - } - - if ((outFile = fopen(filename, "wb")) == NULL) - { - int err = dmGetErrno(); - dmError("Could not open '%s' for writing, %d: %s.\n", - filename, err, dmErrorStr(err)); - goto error; - } - - if ((buf = dmMalloc(bufSize)) == NULL) - { - dmError("Could not allocate %d bytes for conversion buffer.\n", - bufSize); - goto error; - } - - dmMsg(1, "Writing %d x %d = %d blocks of %s data...\n", - outBlockW, outBlockH, outBlockW * outBlockH, outType); - - for (by = 0; by < outBlockH; by++) - for (bx = 0; bx < outBlockW; bx++) - { - switch (outFormat) - { - case FFMT_CHAR: - if (!dmConvertImage2Char(buf, image, - bx * C64_CHR_WIDTH_PX, by * C64_CHR_HEIGHT, - multicolor)) - goto error; - break; - - case FFMT_SPRITE: - if (!dmConvertImage2Sprite(buf, image, - bx * C64_SPR_WIDTH_PX, by * C64_SPR_HEIGHT, - multicolor)) - goto error; - } - - if (!dm_fwrite_str(outFile, buf, bufSize)) - { - int err = dmGetErrno(); - dmError("Error writing data block %d,%d to '%s', %d: %s\n", - bx, by, filename, err, dmErrorStr(err)); - goto error; - } - } - - fclose(outFile); - dmFree(buf); - return 0; - -error: - if (outFile != NULL) - fclose(outFile); - dmFree(buf); - return -1; -} - - -int dmDumpSpritesAndChars(FILE *inFile) -{ - int dataOffs, itemCount, outWidth, outWidthPX, outHeight; - size_t bufSize; - Uint8 *bufData; - - switch (optInFormat) - { - case FFMT_CHAR: - bufSize = C64_CHR_SIZE; - outWidth = C64_CHR_WIDTH; - outWidthPX = C64_CHR_WIDTH_PX; - outHeight = C64_CHR_HEIGHT; - break; - - case FFMT_SPRITE: - bufSize = C64_SPR_SIZE; - outWidth = C64_SPR_WIDTH; - outWidthPX = C64_SPR_WIDTH_PX; - outHeight = C64_SPR_HEIGHT; - break; - - default: - dmError("Invalid input format %d, internal error.\n", optInFormat); - return -1; - } - - if ((bufData = dmMalloc(bufSize)) == NULL) - { - dmError("Could not allocate temporary buffer of %d bytes.\n", bufSize); - return -2; - } - - - dataOffs = optInSkip; - itemCount = 0; - - if (optOutFormat == FFMT_ANSI || optOutFormat == FFMT_ASCII) - { - BOOL error = FALSE; - FILE *outFile; - - if (optOutFilename == NULL) - outFile = stdout; - else - if ((outFile = fopen(optOutFilename, "w")) == NULL) - { - int res = dmGetErrno(); - dmError("Error opening output file '%s', %d: %s\n", - optOutFilename, res, dmErrorStr(res)); - goto error; - } - - while (!feof(inFile) && !error && (optItemCount < 0 || itemCount < optItemCount)) - { - memset(bufData, 0, bufSize); - - if (fread(bufData, 1, bufSize, inFile) != bufSize) - { - dmError("Could not read full bufferful (%d bytes) of data at 0x%x.\n", - bufSize, dataOffs); - error = TRUE; - } - - fprintf(outFile, "---- : -------------- #%d\n", itemCount); - - switch (optInFormat) - { - case FFMT_CHAR: - dmDumpCharASCII(outFile, bufData, &dataOffs, optOutFormat, optInMulticolor); - break; - case FFMT_SPRITE: - dmDumpSpriteASCII(outFile, bufData, &dataOffs, optOutFormat, optInMulticolor); - break; - } - itemCount++; - } - - fclose(outFile); - } - else - if (optOutFormat == FFMT_IMAGE) - { - DMImage *outImage = NULL; - char *outFilename = NULL; - int outX = 0, outY = 0, err; - - if (optSequential) - { - if (optOutFilename == NULL) - { - dmError("Sequential image output requires filename template.\n"); - goto error; - } - - outImage = dmImageAlloc(outWidthPX, outHeight); - dmMsg(1, "Outputting sequence of %d images @ %d x %d -> %d x %d.\n", - optItemCount, - outImage->width, outImage->height, - outImage->width * optSpec.scale, outImage->height * optSpec.scale); - } - else - { - int outIWidth, outIHeight; - if (optItemCount <= 0) - { - dmError("Single-image output requires count to be set (-n).\n"); - goto error; - } - - outIWidth = optPlanedWidth; - outIHeight = (optItemCount / optPlanedWidth); - if (optItemCount % optPlanedWidth) - outIHeight++; - - outImage = dmImageAlloc(outWidthPX * outIWidth, outIHeight * outHeight); - } - - outImage->constpal = TRUE; - outImage->pal = dmC64Palette; - outImage->ncolors = C64_NCOLORS; - outImage->ctransp = 255; - - while (!feof(inFile) && (optItemCount < 0 || itemCount < optItemCount)) - { - memset(bufData, 0, bufSize); - - if (fread(bufData, 1, bufSize, inFile) != bufSize) - { - dmError("Could not read full bufferful (%d bytes) of data at 0x%x.\n", - bufSize, dataOffs); - break; - } - - if ((err = dmC64ConvertCSData(outImage, outX * outWidthPX, outY * outHeight, - bufData, outWidth, outHeight, optInMulticolor, optColors)) != DMERR_OK) - { - dmError("Internal error in conversion of raw data to bitmap: %d.\n", err); - break; - } - - if (optSequential) - { - outFilename = dm_strdup_printf("%s%04d.%s", optOutFilename, itemCount, convFormatList[optOutFormat].fext); - if (outFilename == NULL) - { - dmError("Could not allocate memory for filename template?\n"); - goto error; - } - - dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); - dmFree(outFilename); - } - else - { - if (++outX >= optPlanedWidth) - { - outX = 0; - outY++; - } - } - - itemCount++; - } - - if (!optSequential) - { - dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); - } - - dmImageFree(outImage); - } - else - if (optOutFormat == FFMT_BITMAP) - { - if (optSequential) - { - dmError("Sequential output not supported for spr/char -> bitmap conversion.\n"); - goto error; - } - } - - dmFree(bufData); - return 0; - -error: - dmFree(bufData); - return -1; -} - - -int main(int argc, char *argv[]) -{ - FILE *inFile; - const DMC64ImageFormat *cfmt; - DMC64Image cimage; - Uint8 *dataBuf = NULL; - size_t dataSize; - int i; - - // Default colors - for (i = 0; i < C64_MAX_COLORS; i++) - optColors[i] = i; - - // Initialize and parse commandline - dmInitProg("gfxconv", "Simple graphics converter", "0.75", NULL, NULL); - - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, argHandleFile, TRUE)) - exit(1); - -#ifndef DM_USE_LIBPNG - if (optOutFormat == IMGFMT_PNG) - { - dmError("PNG output format support not compiled in, sorry.\n"); - goto error; - } -#endif - - // Determine input format, if not specified' - if (optInFormat == FFMT_AUTO && optInFilename != NULL) - { - char *dext = strrchr(optInFilename, '.'); - dmMsg(4, "Trying to determine file format by extension.\n"); - if (dext) - { - dmGetFormatByExt(dext + 1, &optInFormat, &optInSubFormat); - } - } - - if (optInFilename == NULL) - { - if (optInFormat == FFMT_AUTO) - { - dmError("Standard input cannot be used without specifying input format.\n"); - dmError("Perhaps you should try using --help\n"); - goto error; - } - inFile = stdin; - } - else - if ((inFile = fopen(optInFilename, "rb")) == NULL) - { - int res = dmGetErrno(); - dmError("Error opening input file '%s', %d: %s\n", - optInFilename, res, dmErrorStr(res)); - goto error; - } - - if (dmReadDataFile(inFile, NULL, &dataBuf, &dataSize) != 0) - goto error; - - if (optInFormat == FFMT_AUTO || optInFormat == FFMT_BITMAP) - { - // Probe for format - const DMC64ImageFormat *forced = NULL; - int res; - - if (optForcedFormat >= 0) - { - forced = &dmC64ImageFormats[optForcedFormat]; - dmMsg(0,"Forced %s format image, type %d, %s\n", - forced->name, forced->type, forced->fext); - } - - res = dmC64DecodeBMP(&cimage, dataBuf, dataSize, optInSkip, optInSkip + 2, &cfmt, forced); - if (forced == NULL && cfmt != NULL) - { - dmMsg(1,"Probed %s format image, type %d, %s\n", - cfmt->name, cfmt->type, cfmt->fext); - } - - if (res == 0) - optInFormat = FFMT_BITMAP; - } - - if (optInFormat == FFMT_AUTO || optInFormat == FFMT_IMAGE) - { - DMImageFormat *ifmt = NULL; - int index; - dmMsg(4, "Trying to probe image formats.\n"); - if (dmImageProbeGeneric(dataBuf + optInSkip, dataSize - optInSkip, &ifmt, &index) > 0) - { - optInFormat = FFMT_IMAGE; - optInSubFormat = index; - dmMsg(2, "Probed %s format image.\n", ifmt->fext); - } - } - - if (optInFormat == FFMT_AUTO) - { - dmError("No input format specified, and could not be determined automatically.\n"); - exit(1); - } - - // Skip, if needed - if (fseek(inFile, optInSkip, SEEK_SET) != 0) - { - int res = dmGetErrno(); - dmError("Could not seek to file position %d (0x%x): %s\n", - optInSkip, optInSkip, dmErrorStr(res)); - goto error; - } - - int inFormat = dmGetConvFormat(optInFormat, optInSubFormat), - outFormat = dmGetConvFormat(optOutFormat, optOutSubFormat); - - if (inFormat != -1 && outFormat != -1) - { - char *inFmtName = convFormatList[inFormat].name, - *inFmtExt = convFormatList[inFormat].fext, - *outFmtName = convFormatList[outFormat].name, - *outFmtExt = convFormatList[outFormat].fext; - - if (optInFormat == FFMT_BITMAP) - inFmtExt = cfmt->name; - - dmMsg(1, "Attempting conversion %s (%s) -> %s (%s)\n", - inFmtName, inFmtExt, outFmtName, outFmtExt); - } - - switch (optInFormat) - { - case FFMT_SPRITE: - case FFMT_CHAR: - dmDumpSpritesAndChars(inFile); - break; - - case FFMT_BITMAP: - { - DMImage *outImage = NULL; - int res = DMERR_OK; - - if (optOutFilename == NULL) - { - dmError("Output filename not set, required for image formats.\n"); - goto error; - } - - switch (optOutFormat) - { - case FFMT_IMAGE: - res = dmC64ConvertBMP2Image(&outImage, &cimage, cfmt, TRUE); - - if (res != DMERR_OK || outImage == NULL) - { - dmError("Error in bitmap to image conversion.\n"); - goto error; - } - - res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); - break; - - - case FFMT_BITMAP: - res = dmWriteBitmap(optOutFilename, &cimage, optOutSubFormat, TRUE); - break; - - case FFMT_CHAR: - case FFMT_SPRITE: - res = dmWriteSpritesAndChars(optOutFilename, outImage, optOutFormat, optInMulticolor); - break; - - default: - dmError("Unsupported output format for bitmap/image conversion.\n"); - break; - } - - dmImageFree(outImage); - } - break; - - case FFMT_IMAGE: - { - DMImage *outImage = NULL; - int res = DMERR_OK; - - if (optOutFilename == NULL) - { - dmError("Output filename not set, required for image formats.\n"); - goto error; - } - - // Read input - DMImageFormat *ifmt = &dmImageFormatList[optInSubFormat]; - if (ifmt->readFILE != NULL) - res = ifmt->readFILE(inFile, &outImage); - else - dmError("Unsupported input image format for bitmap/image conversion.\n"); - - if (res != DMERR_OK || outImage == NULL) - break; - - switch (optOutFormat) - { - case FFMT_IMAGE: - res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); - break; - - case FFMT_CHAR: - case FFMT_SPRITE: - res = dmWriteSpritesAndChars(optOutFilename, outImage, optOutFormat, optInMulticolor); - break; - - default: - dmError("Unsupported output format for bitmap/image conversion.\n"); - break; - } - - dmImageFree(outImage); - } - break; - } - - fclose(inFile); - - dmFree(dataBuf); - exit(0); - return 0; - -error: - dmFree(dataBuf); - return -3; - exit(3); -}
--- a/mod2wav.c Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,314 +0,0 @@ -/* - * mod2wav - Render XM/JSSMOD module to WAV waveform file - * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2007 Tecnic Software productions (TNSP) - * - * Please read file 'COPYING' for information on license and distribution. - */ -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> -#include "jss.h" -#include "jssmod.h" -#include "jssmix.h" -#include "jssplr.h" -#include "dmlib.h" -#include "dmargs.h" -#include "dmwav.h" -#include "dmmutex.h" - - -char *optInFilename = NULL, *optOutFilename = NULL; -int optOutFormat = JSS_AUDIO_S16, - optOutChannels = 2, - optOutFreq = 44100, - optMuteOChannels = -1, - optStartOrder = -1; -BOOL optUsePlayTime = FALSE; -size_t optPlayTime; - - -DMOptArg optList[] = -{ - { 0, '?', "help", "Show this help", OPT_NONE }, - { 2, 'v', "verbose", "Be more verbose", OPT_NONE }, - { 3, '1', "16bit", "16-bit output", OPT_NONE }, - { 4, '8', "8bit", "8-bit output", OPT_NONE }, - { 5, 'm', "mono", "Mono output", OPT_NONE }, - { 6, 's', "stereo", "Stereo output", OPT_NONE }, - { 7, 'f', "freq", "Output frequency", OPT_ARGREQ }, - { 8, 'M', "mute", "Mute other channels than #", OPT_ARGREQ }, - { 9, 'o', "order", "Start from order #", OPT_ARGREQ }, - { 10, 't', "time", "Play for # seconds", OPT_ARGREQ }, -// {10, 'l', "loop", "Loop for # times", OPT_ARGREQ }, -}; - -const int optListN = sizeof(optList) / sizeof(optList[0]); - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - (void) optArg; - - switch (optN) - { - case 0: - dmPrintBanner(stdout, dmProgName, - "[options] [sourcefile] [destfile]"); - - dmArgsPrintHelp(stdout, optList, optListN); - exit(0); - break; - - case 2: - dmVerbosity++; - break; - - case 3: - optOutFormat = JSS_AUDIO_S16; - break; - - case 4: - optOutFormat = JSS_AUDIO_U8; - break; - - case 5: - optOutChannels = JSS_AUDIO_MONO; - break; - - case 6: - optOutChannels = JSS_AUDIO_STEREO; - break; - - case 7: - optOutFreq = atoi(optArg); - break; - - case 8: - optMuteOChannels = atoi(optArg); - break; - - case 9: - optStartOrder = atoi(optArg); - break; - - case 10: - optPlayTime = atoi(optArg); - optUsePlayTime = TRUE; - break; - - default: - dmError("Unknown argument '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -BOOL argHandleFile(char *currArg) -{ - if (!optInFilename) - optInFilename = currArg; - else - if (!optOutFilename) - optOutFilename = currArg; - else - { - dmError("Too many filename arguments (only source and dest needed) '%s'\n", currArg); - return FALSE; - } - - return TRUE; -} - - -int main(int argc, char *argv[]) -{ - DMResource *inFile = NULL; - FILE *outFile = NULL; - JSSModule *mod = NULL; - JSSMixer *dev = NULL; - JSSPlayer *plr = NULL; - int result = -1; - size_t bufLen = 1024*4, dataTotal, dataWritten, sampSize; - Uint8 *mb = NULL; - - dmInitProg("mod2wav", "XM/JSSMOD to WAV renderer", "0.2", NULL, NULL); - dmVerbosity = 1; - - // Parse arguments - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, argHandleFile, TRUE)) - exit(1); - - // Check arguments - if (optInFilename == NULL || optOutFilename == NULL) - { - dmError("Input or output file not specified. Try --help.\n"); - return 1; - } - - // Initialize miniJSS - jssInit(); - - // Open the source file - if ((inFile = dmf_create_stdio(optInFilename, "rb")) == NULL) - { - dmError("Error opening input file '%s', %d: %s\n", - optInFilename, errno, strerror(errno)); - return 1; - } - - // Read module file - fprintf(stderr, "Reading file: %s\n", optInFilename); -#ifdef JSS_SUP_XM - fprintf(stderr, "* Trying XM...\n"); - result = jssLoadXM(inFile, &mod); -#endif -#ifdef JSS_SUP_JSSMOD - if (result != 0) - { - size_t bufgot, bufsize = dmfsize(inFile); - Uint8 *buf = dmMalloc(bufsize); - dmfseek(inFile, 0L, SEEK_SET); - fprintf(stderr, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf); - if ((bufgot = dmfread(buf, 1, bufsize, inFile)) != bufsize) - { - fprintf(stderr, "Error reading file (not enough data %d), #%d: %s\n", - bufgot, dmferror(inFile), dmErrorStr(dmferror(inFile))); - return 2; - } - result = jssLoadJSSMOD(buf, bufsize, &mod); - dmFree(buf); - } -#endif - dmf_close(inFile); - if (result != DMERR_OK) - { - dmError("Error loading module file, %d: %s\n", - result, dmErrorStr(result)); - return 3; - } - - // Try to convert it - if ((result = jssConvertModuleForPlaying(mod)) != DMERR_OK) - { - dmError("Could not convert module for playing, %d: %s\n", - result, dmErrorStr(result)); - return 3; - } - - // Open mixer - dev = jvmInit(optOutFormat, optOutChannels, optOutFreq, JMIX_AUTO); - if (dev == NULL) - { - dmError("jvmInit() returned NULL\n"); - return 4; - } - - sampSize = jvmGetSampleSize(dev); - if ((mb = dmMalloc(bufLen * sampSize)) == NULL) - { - dmError("Could not allocate mixing buffer\n"); - return 5; - } - - dmMsg(1, "Using fmt=%d, bits=%d, channels=%d, freq=%d [%d / sample]\n", - optOutFormat, jvmGetSampleRes(dev), optOutChannels, optOutFreq, - sampSize); - - // Initialize player - if ((plr = jmpInit(dev)) == NULL) - { - dmError("jmpInit() returned NULL.\n"); - return 6; - } - - // Set callback - jvmSetCallback(dev, jmpExec, plr); - - // Initialize playing - jmpSetModule(plr, mod); - if (optStartOrder >= 0) - { - dmMsg(1, "Starting from song order #%d\n", optStartOrder); - } else - optStartOrder = 0; - - jmpPlayOrder(plr, optStartOrder); - jvmSetGlobalVol(dev, 150); - - if (optMuteOChannels > 0 && optMuteOChannels <= mod->nchannels) - { - int i; - for (i = 0; i < mod->nchannels; i++) - jvmMute(dev, i, TRUE); - jvmMute(dev, optMuteOChannels - 1, FALSE); - } - - // Open output file - if ((outFile = fopen(optOutFilename, "wb")) == NULL) - { - dmError("Error opening output file '%s'. (%s)\n", optInFilename, strerror(errno)); - return 7; - } - - // Write initial header - dmWriteWAVHeader(outFile, jvmGetSampleRes(dev), optOutFreq, optOutChannels, 1024); - - // Render audio data and output to file - if (optUsePlayTime) - dmMsg(1, "Rendering module (%d seconds) ...\n", optPlayTime); - else - dmMsg(1, "Rendering module ...\n"); - - optPlayTime *= optOutFreq; - dataTotal = 0; - dataWritten = 1; - while (plr->isPlaying && dataWritten > 0) - { - size_t writeLen = bufLen; - if (optUsePlayTime && (writeLen + dataTotal) > optPlayTime) - writeLen = optPlayTime - dataTotal; - - if (writeLen > 0) - { - jvmRenderAudio(dev, mb, writeLen); -#if (SDL_BYTEORDER == SDL_BIG_ENDIAN) - jssEncodeSample16((Uint16 *)mb, writeLen * optOutChannels, jsampSwapEndianess); -#endif - dataWritten = fwrite(mb, sampSize, writeLen, outFile); - if (dataWritten < writeLen) - { - dmError("Error writing data!\n"); - fclose(outFile); - return 8; - } - dataTotal += dataWritten; - } - - if (optUsePlayTime && dataTotal >= optPlayTime) - break; - } - - // Write the correct header - if (fseek(outFile, 0L, SEEK_SET) != 0) - { - dmError("Error rewinding to header position!\n"); - return 9; - } - - dmWriteWAVHeader(outFile, jvmGetSampleRes(dev), optOutFreq, optOutChannels, dataTotal); - - // Done! - fclose(outFile); - - jmpClose(plr); - jvmClose(dev); - jssFreeModule(mod); - jssClose(); - - dmMsg(1, "OK.\n"); - return 0; -}
--- a/objlink.c Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,990 +0,0 @@ -/* - * objlink - Link files (RAW and PRG) into one PRG object - * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2002-2012 Tecnic Software productions (TNSP) - * - * Please read file 'COPYING' for information on license and distribution. - */ -#include <errno.h> -#include "dmlib.h" -#include "dmargs.h" -#include "dmfile.h" -#include "dmmutex.h" - -#define MAX_FILENAMES (128) -#define MAX_MEMBLOCKS (128) - - -/* Typedefs - */ -typedef struct -{ - ssize_t start, end; // Start and end address - int type; // Type - char *name; // Name of the block - int placement; -} DMMemBlock; - -typedef struct -{ - char *name; // Description of memory model - char *desc; - ssize_t size; // Total addressable memory size - ssize_t nmemBlocks; // Defined memory areas - DMMemBlock memBlocks[MAX_MEMBLOCKS]; -} DMMemModel; - -typedef struct -{ - char *filename; - int type; - int placement; - ssize_t addr; -} DMSourceFile; - -// Source file type -enum -{ - STYPE_RAW = 1, - STYPE_PRG, - STYPE_PRGA -}; - -// How to determine block placement / address -enum -{ - PLACE_STATIC = 1, // Already known - PLACE_ARGUMENT, // Commandline argument - PLACE_FILE, // From file -}; - -enum -{ - FMT_GENERIC = 1, - FMT_PLAIN, - FMT_DECIMAL -}; - -enum -{ - MTYPE_NONE = 0, - MTYPE_ROM, // Hard ROM - MTYPE_ROM_WT, // Write to RAM through ROM - MTYPE_IO, // I/O lines - MTYPE_RES // RESERVED -}; - -enum -{ - LA_NONE = -2, - LA_AUTO = -1 -}; - -/* Memory models - */ -const DMMemModel memoryModels[] = { - { "C64 unrestricted", "$01 = $34", (64*1024), 0, { - { 0, 0, 0, NULL, 0 } - }}, - - { "C64 normal (IO+Basic+Kernal)", "$01 = $37", (64*1024), 3, { - { 0xA000, 0xBFFF, MTYPE_ROM_WT, "Basic ROM", PLACE_STATIC }, - { 0xD000, 0xDFFF, MTYPE_IO, "I/O", PLACE_STATIC }, - { 0xE000, 0xFFFF, MTYPE_ROM_WT, "Kernal ROM", PLACE_STATIC }, - }}, - - { "C64 modified (IO+Kernal)", "$01 = $36", (64*1024), 2, { - { 0xD000, 0xDFFF, MTYPE_IO, "I/O", PLACE_STATIC }, - { 0xE000, 0xFFFF, MTYPE_ROM_WT, "Kernal ROM", PLACE_STATIC }, - }}, - - { "C64 modified (IO only)", "$01 = $35", (64*1024), 1, { - { 0xD000, 0xDFFF, MTYPE_IO, "I/O", PLACE_STATIC }, - }}, - - { "C64 modified (Char+Kernal+Basic)", "$01 = $33", (64*1024), 3, { - { 0xA000, 0xBFFF, MTYPE_ROM_WT, "Basic ROM", PLACE_STATIC }, - { 0xD000, 0xDFFF, MTYPE_ROM, "Char ROM", PLACE_STATIC }, - { 0xE000, 0xFFFF, MTYPE_ROM_WT, "Kernal ROM", PLACE_STATIC }, - }}, - -/* - { "C64 normal", "$01 = $37", (64*1024), 0, { - { 0x0000, 0x0000, MTYPE_RAM, "" }, - }}, -*/ -}; - -static const int nmemoryModels = sizeof(memoryModels) / sizeof(memoryModels[0]); - - -/* Global variables - */ -int nsrcFiles = 0; // Number of source files -DMSourceFile srcFiles[MAX_FILENAMES]; // Source file names - -int nmemBlocks = 0; -DMMemBlock memBlocks[MAX_FILENAMES]; - -char *optLinkFileName = NULL; -int optLinkFileFormat = FMT_GENERIC; - -BOOL optDescribe = FALSE, - optAllowOverlap = FALSE; - -Uint32 optInitValue = 0; -int optInitValueType = 1; -ssize_t optCropStart, optCropEnd; -BOOL optCropOutput = FALSE; - -ssize_t optLoadAddress = LA_AUTO; - -int optMemModel = 0; -const DMMemModel *memModel = NULL; -Uint8 *memory = NULL; - -char *optDestName = NULL; - - -/* Arguments - */ -static DMOptArg optList[] = { - { 0, '?', "help", "Show this help", OPT_NONE }, - { 1, 'r', "input-raw", "RAW input: -r <file>:<addr>", OPT_ARGREQ }, - { 2, 'p', "input-prg", "PRG input: -p <file>[:<addr>]", OPT_ARGREQ }, - { 12, 's', "section", "Reserved section: -s <start>-<end>[,name] or <start>:<len>[,name]", OPT_ARGREQ }, - { 5, 'o', "output", "Specify output file, -o <file>", OPT_ARGREQ }, - { 6, 'O', "overlap", "Allow overlapping memory areas", OPT_NONE }, - { 7, 'm', "model", "Set memory model", OPT_ARGREQ }, - { 8, 'l', "link-file", "Output addresses and labels into file", OPT_ARGREQ }, - { 9, 'f', "format", "Format of link-file: (g)eneric, (p)lain, (d)ecimal", OPT_ARGREQ }, - { 10, 'i', "initvalue", "Initialize memory with: -i <byte/word/dword>:[bwd]", OPT_ARGREQ }, - { 11, 'd', "describe", "Output ASCII memory map description", OPT_NONE }, - { 13, 'c', "crop", "Crop output file to: -c <start>-<end> or <start>:<len>", OPT_ARGREQ }, - { 14, 'L', "load-address","Set output file load address (or 'none' for 'raw' output)", OPT_ARGREQ }, -}; - -static const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - int i; - - dmPrintBanner(stdout, dmProgName, "[options]"); - dmArgsPrintHelp(stdout, optList, optListN); - - printf( - "\n" - "Each numeric argument can be prefixed with $ or 0x for hexadecimal values.\n" - "NOTICE! -p filename:<addr> will ignore load address and use <addr> instead!\n" - "\n" - "Available memory models:\n"); - - for (i = 0; i < nmemoryModels; i++) - { - const DMMemModel *m = &memoryModels[i]; - printf(" %d = %-40s [%s] (%d kB)\n", - i, m->name, m->desc, m->size / 1024); - } -} - - -off_t dmGetFileSize(FILE *f) -{ - off_t len, pos = ftell(f); - fseeko(f, 0, SEEK_END); - len = ftell(f); - fseek(f, pos, SEEK_SET); - return len; -} - - -/* Memory block handling - */ -void reserveMemBlock(ssize_t startAddr, ssize_t endAddr, const char *blockName, int blockType) -{ - if (startAddr > endAddr) - { - dmError("ERROR! Block '%s' has startAddr=$%.4x > endAddr=$%.4x!\n", - blockName, startAddr, endAddr); - exit(4); - } - - if (nmemBlocks < MAX_FILENAMES) - { - memBlocks[nmemBlocks].start = startAddr; - memBlocks[nmemBlocks].end = endAddr; - memBlocks[nmemBlocks].name = dm_strdup(blockName); - memBlocks[nmemBlocks].type = blockType; - nmemBlocks++; - } - else - { - dmError("Maximum number of memBlock definitions (%d) exceeded!\n", - MAX_FILENAMES); - exit(4); - } -} - - -int compareMemBlock(const void *cva, const void *cvb) -{ - const DMMemBlock *a = cva, *b = cvb; - return a->start - b->start; -} - - -BOOL dmParseSection(const char *arg, ssize_t *sectStart, ssize_t *sectEnd, char **sectName, BOOL canHasName) -{ - char sectMode, *sep, *str, *namesep; - ssize_t tmpi; - - // Define reserved section - // Create a copy of the argument - if ((str = dm_strdup(arg)) == NULL) - { - dmError("Could not allocate temporary string!\n"); - exit(128); - } - - // Get start address - if ((sep = strchr(str, '-')) == NULL && - (sep = strchr(str, ':')) == NULL) - { - dmError("Section definition '%s' invalid.\n", arg); - goto error; - } - sectMode = *sep; - *sep = 0; - - // Get value - if (!dmGetIntVal(str, sectStart)) - { - dmError("Section start address '%s' in '%s' invalid.\n", str, arg); - goto error; - } - - // Check for name - namesep = strchr(sep + 1, ','); - if (canHasName && namesep != NULL) - { - *namesep = 0; - namesep++; - if (*namesep == 0) - { - dmError("Section definition '%s' name is empty. Either specify name or leave it out.\n", - arg); - goto error; - } - *sectName = dm_strdup(namesep); - } - else - if (namesep != NULL) - { - dmError("Section definition does not allow a name, syntax error in '%s' at '%s'.\n", - arg, namesep); - goto error; - } - - // Get end address or length - if (!dmGetIntVal(sep + 1, &tmpi)) - { - dmError("Section %s '%s' in '%s' invalid.\n", - sectMode == '-' ? "end address" : "length", - sep + 1, arg); - goto error; - } - - if (sectMode == ':') - { - *sectEnd = *sectStart + tmpi - 1; - } - else - { - if (tmpi < *sectStart) - { - dmError("Section start address > end address in '%s'.\n", - arg); - goto error; - } - *sectEnd = tmpi; - } - - dmFree(str); - return TRUE; - -error: - dmFree(str); - return FALSE; -} - - -BOOL dmParseInputFile(char *arg, const int type1, const int type2, const char *desc, BOOL requireAddr) -{ - ssize_t tmpi = 0; - BOOL hasAddr = FALSE; - char *sep; - - if ((sep = strrchr(arg, ':')) != NULL) - { - *sep = 0; - if (!dmGetIntVal(sep + 1, &tmpi)) - { - dmError("Invalid %s address '%s' specified for '%s'.\n", - desc, sep + 1, arg); - return FALSE; - } - hasAddr = TRUE; - } - else - if (requireAddr) - { - dmError("No %s loading address specified for '%s'.\n", desc, arg); - return FALSE; - } - - srcFiles[nsrcFiles].filename = arg; - srcFiles[nsrcFiles].type = hasAddr ? type1 : type2; - srcFiles[nsrcFiles].addr = tmpi; - nsrcFiles++; - return TRUE; -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - char *p; - ssize_t tmpi; - - switch (optN) { - case 0: - argShowHelp(); - exit(0); - break; - - case 1: - // Add RAW - if (!dmParseInputFile(optArg, STYPE_RAW, STYPE_RAW, "RAW", TRUE)) - return FALSE; - break; - - case 2: - // Add PRG - if (!dmParseInputFile(optArg, STYPE_PRGA, STYPE_PRG, "PRG", FALSE)) - return FALSE; - break; - - case 5: - // Set output file name - optDestName = optArg; - break; - - case 6: - // Allow overlapping segments - optAllowOverlap = TRUE; - dmError("Warning, allowing overlapping data.\n"); - break; - - case 7: - // Set memory model - optMemModel = atoi(optArg); - if (optMemModel < 0 || optMemModel >= nmemoryModels) - { - dmError("Invalid memory model number %i!\n", optMemModel); - return FALSE; - } - break; - - case 8: - // Linker file - optLinkFileName = optArg; - break; - - case 9: - // Linker file format - switch (tolower(optArg[0])) - { - case 'g': - optLinkFileFormat = FMT_GENERIC; - break; - case 'p': - optLinkFileFormat = FMT_PLAIN; - break; - case 'd': - optLinkFileFormat = FMT_DECIMAL; - break; - - default: - dmError("Invalid/unknown linker file format '%s'!\n", - optArg); - return FALSE; - } - break; - - case 10: - // Initialization value - optInitValueType = 1; - if ((p = strrchr(optArg, ':')) != NULL) - { - *p = 0; - switch (tolower(p[1])) - { - case 'b': optInitValueType = 1; break; - case 'w': optInitValueType = 2; break; - case 'd': optInitValueType = 4; break; - default: - dmError("Invalid init value type '%c' specified for '%s'.\n", - p[1], optArg); - return FALSE; - } - } - if (!dmGetIntVal(optArg, &tmpi)) - { - dmError("Invalid initvalue '%s'.\n", optArg); - return FALSE; - } - optInitValue = tmpi; - break; - - case 11: - // Set describe mode - optDescribe = TRUE; - break; - - case 12: - { - char *sectName = "Clear"; - ssize_t sectStart, sectEnd, sectLen; - if (!dmParseSection(optArg, §Start, §End, §Name, TRUE)) - return FALSE; - - // Allocate memory block - sectLen = sectEnd - sectStart + 1; - dmMsg(1, "Reserve $%.4x - $%.4x ($%x, %d bytes) as '%s'\n", - sectStart, sectEnd, sectLen, sectLen, sectName); - - reserveMemBlock(sectStart, sectEnd, sectName, MTYPE_RES); - } - break; - - case 13: - { - size_t cropLen; - if (!dmParseSection(optArg, &optCropStart, &optCropEnd, NULL, FALSE)) - return FALSE; - - cropLen = optCropEnd - optCropEnd + 1; - dmMsg(1, "Cutting output to $%.4x - $%.4x ($%x, %d bytes)\n", - optCropStart, optCropEnd, cropLen, cropLen); - - optCropOutput = TRUE; - } - break; - - case 14: - // Set loading address - if (strcasecmp(optArg, "none") == 0) - optLoadAddress = LA_NONE; - else - { - if (!dmGetIntVal(optArg, &tmpi)) - { - dmError("Invalid loading address '%s'.\n", optArg); - return FALSE; - } - if (tmpi < 0 || tmpi >= 64*1024) - { - dmError("Invalid or insane loading address %d/$%x!\n", - tmpi); - return FALSE; - } - optLoadAddress = tmpi; - } - break; - - default: - dmError("Unknown argument '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -int dmLoadPRG(const char *filename, BOOL forceAddr, const ssize_t destAddr) -{ - FILE *f; - ssize_t dataSize, loadAddr, endAddr; - Uint16 tmpAddr; - - // Open the input file - if ((f = fopen(filename, "rb")) == NULL) - { - dmError("Error opening input file '%s' (%s).\n", - filename, strerror(errno)); - return 1; - } - - // Get filesize - if ((dataSize = dmGetFileSize(f) - 2) < 0) - { - dmError("Error getting file size for '%s'.\n", filename); - return 6; - } - - // Get loading address - if (!dm_fread_le16(f, &tmpAddr)) - { - dmError("Error reading input file '%s' (%s).\n", - filename, strerror(errno)); - return 2; - } - - // Show information - loadAddr = forceAddr ? destAddr : tmpAddr; - endAddr = loadAddr + dataSize - 1; - - dmPrint(1, "* Loading '%s', %s at $%.4x-$%.4x", - filename, forceAddr ? "PRGA" : "PRG", loadAddr, endAddr); - - if (endAddr >= memModel->size) - { - dmPrint(1, " .. Does not fit into the memory!\n"); - return 5; - } - - // Load data - if (fread(&memory[loadAddr], dataSize, 1, f) < 1) - { - dmPrint(1, " .. Error: %s.\n", - strerror(errno)); - return 4; - } - - dmPrint(1, " .. OK\n"); - - // Add to list of blocks - reserveMemBlock(loadAddr, endAddr, filename, MTYPE_RES); - - return 0; -} - - -int dmLoadRAW(const char *filename, const ssize_t destAddr) -{ - FILE *f; - ssize_t dataSize, endAddr; - - // Open the input file - if ((f = fopen(filename, "rb")) == NULL) - { - dmError("Error opening input file '%s' (%s).\n", - filename, strerror(errno)); - return 1; - } - - // Get filesize - if ((dataSize = dmGetFileSize(f)) < 0) - { - dmError("Error getting file size for '%s'.\n", filename); - return 6; - } - - // Show information - endAddr = destAddr + dataSize - 1; - dmPrint(1, "* Loading '%s', RAW at $%.4x-$%.4x", - filename, destAddr, endAddr); - - if (endAddr >= memModel->size) - { - dmPrint(1, " .. Does not fit into the memory!\n"); - return 5; - } - - // Load data - if (fread(&memory[destAddr], dataSize, 1, f) < 1) - { - dmPrint(1, " .. Error: %s.\n", - strerror(errno)); - return 4; - } - - dmPrint(1, " .. OK\n"); - - // Add info to list - reserveMemBlock(destAddr, endAddr, filename, MTYPE_RES); - - return 0; -} - - -int outputLinkData(FILE *dfile, const char *blockName, const int blockStart, const int blockEnd) -{ - char *tmpStr, *s, *t; - int blockSize; - - blockSize = (blockEnd - blockStart + 1); - - // Create label name from filename - tmpStr = dm_strdup(blockName); - if (tmpStr == NULL) - { - dmError("Could not allocate memory for string '%s'!\n", - blockName); - return -1; - } - - if ((t = strrchr(tmpStr, '/'))) - s = (t + 1); - else if ((t = strrchr(tmpStr, '\\'))) - s = (t + 1); - else - s = tmpStr; - - if ((t = strrchr(s, '.'))) - *t = 0; - - for (t = s; *t; t++) - { - if (!isalnum(*t)) - *t = '_'; - } - - // Print the label line - switch (optLinkFileFormat) - { - case FMT_PLAIN: - fprintf(dfile, "%s = $%.4x\n", tmpStr, blockStart); - break; - - case FMT_DECIMAL: - fprintf(dfile, "%s = %d\n", tmpStr, blockStart); - break; - - case FMT_GENERIC: - default: - fprintf(dfile, "; %s ($%.4x - $%.4x, %d/$%x bytes)\n", - blockName, blockStart, blockEnd, blockSize, blockSize); - fprintf(dfile, "%s = $%.4x\n", s, blockStart); - break; - } - - dmFree(tmpStr); - return 0; -} - - -/* Print out an ASCII presentation of memory map - */ -void memPrintLine(FILE *f) -{ - fprintf(f, " +------------------------------------------+\n"); -} - -void memPrintEmpty(FILE *f, ssize_t n) -{ - ssize_t i; - for (i = 0; i < n; i++) - fprintf(f, " | |\n"); -} - -void dmDescribeMemory(FILE *f) -{ - int i; - DMMemBlock *prev = NULL; - - memPrintLine(f); - - for (i = 0; i < nmemBlocks; i++) - { - DMMemBlock *curr = &memBlocks[i]; - char desc[512], *s; - ssize_t siz, kz; - - // Check for empty, unreserved areas - siz = (curr->start - 1) - (prev->end + 1) + 1; - if (prev != NULL && siz > 1) - { - kz = siz / (1024 * 2); - - if (kz > 1) memPrintEmpty(f, kz); - - snprintf(desc, sizeof(desc), "EMPTY (%d)", siz); - fprintf(f, "$%.4x - $%.4x | %-40s |\n", prev->end + 1, curr->start - 1, desc); - - if (kz > 1) memPrintEmpty(f, kz); - memPrintLine(f); - } - prev = curr; - - // Print current block - switch (curr->type) - { - case MTYPE_NONE: s = "N/A (NC)"; break; - case MTYPE_ROM: s = "ROM"; break; - case MTYPE_ROM_WT: s = "ROM/WT"; break; - case MTYPE_IO: s = "I/O"; break; - case MTYPE_RES: s = "RSVD"; break; - default: s = "????"; break; - } - - siz = curr->end - curr->start + 1; - kz = siz / (1024 * 2); - - if (kz > 1) memPrintEmpty(f, kz); - snprintf(desc, sizeof(desc), "%s (%s, %d)", curr->name, s, siz); - fprintf(f, "$%.4x - $%.4x | %-40s |\n", curr->start, curr->end, desc); - if (kz > 1) memPrintEmpty(f, kz); - memPrintLine(f); - - } - - fprintf(f, - "\n" - "NC = Not Connected\n" - "RSVD = Reserved\n" - "ROM/WT = RAM under 'write-through' ROM\n" - "\n" - ); -} - - -/* - * The main program - */ -int main(int argc, char *argv[]) -{ - FILE *dfile = NULL; - BOOL hasOverlaps; - int i, j; - ssize_t startAddr, endAddr, dataSize, totalSize; - - dmInitProg("objlink", "Simple file-linker", "0.80", NULL, NULL); - dmVerbosity = 1; - - // Parse arguments - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, NULL, TRUE)) - exit(1); - - if (nsrcFiles < 1) - { - dmError("Nothing to do. (try --help)\n"); - exit(0); - } - - // Allocate memory - memModel = &memoryModels[optMemModel]; - dmMsg(1, "Using memory model #%d '%s', %d bytes.\n", - optMemModel, memModel->name, memModel->size); - - memory = (Uint8 *) dmMalloc(memModel->size + 32); - if (memory == NULL) - { - dmError("Could not allocate memory.\n"); - exit(2); - } - - // Initialize memory - dmMsg(1, "Initializing memory with "); - - if (optInitValueType == 1 || optInitValue <= 0xff) - { - dmPrint(1, "BYTE 0x%.2x\n", optInitValue); - memset(memory, optInitValue, memModel->size); - } - else - if (optInitValueType == 2 || optInitValue <= 0xffff) - { - uint16_t *mp = (uint16_t *) memory; - dmPrint(1, "WORD 0x%.4x\n", optInitValue); - for (i = memModel->size / sizeof(*mp); i; i--) - { - *mp++ = optInitValue; - } - } - else - { - Uint32 *mp = (Uint32 *) memory; - dmPrint(1, "DWORD 0x%.8x\n", optInitValue); - for (i = memModel->size / sizeof(*mp); i; i--) - { - *mp++ = optInitValue; - } - } - - // Load the datafiles - for (i = 0; i < nsrcFiles; i++) - switch (srcFiles[i].type) - { - case STYPE_RAW: - dmLoadRAW(srcFiles[i].filename, srcFiles[i].addr); - break; - - case STYPE_PRG: - dmLoadPRG(srcFiles[i].filename, FALSE, 0); - break; - - case STYPE_PRGA: - dmLoadPRG(srcFiles[i].filename, TRUE, srcFiles[i].addr); - break; - } - - // Add memory model blocks - dmMsg(1, "Applying memory model restrictions...\n"); - for (i = 0; i < memModel->nmemBlocks; i++) - { - reserveMemBlock( - memModel->memBlocks[i].start, - memModel->memBlocks[i].end, - memModel->memBlocks[i].name, - memModel->memBlocks[i].type); - } - - // Sort the blocks - qsort(memBlocks, nmemBlocks, sizeof(DMMemBlock), compareMemBlock); - - // Check for overlapping conflicts - hasOverlaps = FALSE; - for (i = 0; i < nmemBlocks; i++) - for (j = 0; j < nmemBlocks; j++) - if (j != i && memBlocks[i].type == MTYPE_RES) - { - DMMemBlock *mbi = &memBlocks[i], - *mbj = &memBlocks[j]; - - // Check for per-file conflicts - if ((mbj->start >= mbi->start && mbj->start <= mbi->end) || - (mbj->end >= mbi->start && mbj->end <= mbi->end)) - { - dmPrint(1, "* '%s' and '%s' overlap ($%.4x-$%.4x vs $%.4x-$%.4x)\n", - mbi->name, mbj->name, mbi->start, - mbi->end, mbj->start, mbj->end); - hasOverlaps = TRUE; - } - } - - if (!optAllowOverlap && hasOverlaps) - { - dmError("Error occured, overlaps not allowed.\n"); - exit(5); - } - - // Find out start and end-addresses - startAddr = memModel->size; - totalSize = endAddr = 0; - for (i = 0; i < nmemBlocks; i++) - { - DMMemBlock *mbi = &memBlocks[i]; - if (mbi->type == MTYPE_RES) - { - if (mbi->start < startAddr) - startAddr = mbi->start; - - if (mbi->end > endAddr) - endAddr = mbi->end; - - totalSize += (mbi->end - mbi->start + 1); - } - } - - if (startAddr >= memModel->size || endAddr < startAddr) - { - dmError("Invalid saveblock addresses (start=$%.4x, end=$%.4x)!\n", startAddr, endAddr); - exit(8); - } - - // Output linkfile - if (optLinkFileName) - { - dmMsg(1, "Writing linkfile to '%s'\n", optLinkFileName); - if ((dfile = fopen(optLinkFileName, "wb")) == NULL) - { - dmError("Error creating file '%s' (%s).\n", optLinkFileName, strerror(errno)); - exit(1); - } - - switch (optLinkFileFormat) - { - case FMT_GENERIC: - default: - fprintf(dfile, "; Definitions generated by %s v%s\n", - dmProgName, dmProgVersion); - break; - } - - for (i = 0; i < nmemBlocks; i++) - { - DMMemBlock *mbi = &memBlocks[i]; - outputLinkData(dfile, mbi->name, mbi->start, mbi->end); - } - - fclose(dfile); - } - - // Show some information - if (optCropOutput) - { - startAddr = optCropStart; - endAddr = optCropEnd; - } - - dataSize = endAddr - startAddr + 1; - - if (dataSize - totalSize > 0) - { - dmMsg(1, "Total of %d/$%x bytes unused(?) areas.\n", - dataSize - totalSize, dataSize - totalSize); - } - - dmMsg(1, "Writing $%.4x - $%.4x (%d/$%x bytes) ", - startAddr, endAddr, dataSize, dataSize); - - - // Open the destination file - if (optDestName == NULL) - { - dfile = stdout; - dmPrint(1, "...\n"); - } - else if ((dfile = fopen(optDestName, "wb")) == NULL) - { - dmError("Error creating output file '%s' (%s).\n", optDestName, strerror(errno)); - exit(1); - } - else - dmPrint(1, "to '%s'\n", optDestName); - - // Save loading address - if (optLoadAddress >= 0) - { - dmMsg(1, "Using specified loading address $%.4x\n", optLoadAddress); - dm_fwrite_le16(dfile, optLoadAddress); - } - else - if (optLoadAddress == LA_AUTO) - { - dmMsg(1, "Using automatic loading address $%.4x\n", startAddr); - dm_fwrite_le16(dfile, startAddr); - } - else - { - dmMsg(1, "Writing raw output, without loading address.\n"); - } - - // Save the data - if (fwrite(&memory[startAddr], dataSize, 1, dfile) < 1) - { - dmError("Error writing to file (%s)\n", strerror(errno)); - } - - fclose(dfile); - - // Describe - if (optDescribe) - dmDescribeMemory(stdout); - - exit(0); - return 0; -}
--- a/packed.c Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,465 +0,0 @@ -/* - * PACKed - PACKfile EDitor - * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2011 Tecnic Software productions (TNSP) - */ -#include "dmlib.h" -#include "dmargs.h" -#include "dmpack.h" -#include "dmpackutil.h" -#include "dmres.h" -#include "dmmutex.h" -#include <errno.h> - -#define SET_MAX_FILES (4096) -#define SET_DEFAULT_PACK "data.pak" - -enum -{ - CMD_NONE = 0, - CMD_CREATE, - CMD_ADD, - CMD_LIST, - CMD_EXTRACT -} DCOMMAND; - -enum -{ - PACK_EXTRACTED = 0x0001, -}; - -int nsrcFilenames = 0; -char * srcFilenames[SET_MAX_FILES]; -char * optPackFilename = NULL; -BOOL optCompress = TRUE; -int optCommand = CMD_NONE; -int optDefResFlags = 0; - - -static DMOptArg optList[] = -{ - { 0, '?', "help", "Show this help", OPT_NONE }, - { 1, 'p', "pack", "Set pack filename (default: " SET_DEFAULT_PACK ")", OPT_ARGREQ }, - { 2, 'c', "create", "Create and add files to PACK", OPT_NONE }, - { 3, 'a', "add", "Add files to PACK", OPT_NONE }, - { 4, 'l', "list", "List files in PACK", OPT_NONE }, - { 5, 'e', "extract", "Extract files from PACK", OPT_NONE }, - { 6, 'n', "nocompress", "No compression", OPT_NONE }, - { 7, 'v', "verbose", "Increase verbosity", OPT_NONE }, - { 8, 'f', "resflags", "Set default resource flags (-f 0xff)", OPT_ARGREQ }, -}; - -static const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - dmPrintBanner(stdout, dmProgName, "[options] [-p <packfilename>] [filename[s]]"); - dmArgsPrintHelp(stdout, optList, optListN); - fprintf(stdout, - "\n" - "Examples:\n" - "$ %s -p test.pak -l -- list files in test.pak\n" - "$ %s -a foobar.jpg -- add foobar.jpg in " SET_DEFAULT_PACK "\n" - "$ %s -x foobar.jpg -- extract foobar.jpg from " SET_DEFAULT_PACK "\n", - dmProgName, dmProgName, dmProgName); -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - (void) optArg; - switch (optN) - { - case 0: - argShowHelp(); - exit(0); - break; - - case 1: - optPackFilename = optArg; - break; - case 2: - optCommand = CMD_CREATE; - break; - case 3: - optCommand = CMD_ADD; - break; - case 4: - optCommand = CMD_LIST; - break; - case 5: - optCommand = CMD_EXTRACT; - break; - - case 6: - optCompress = FALSE; - break; - - case 7: - dmVerbosity++; - break; - - case 8: - { - int i; - if (!dmGetIntVal(optArg, &i)) - { - dmError("Invalid flags value '%s'.\n", optArg); - return FALSE; - } - optDefResFlags = i; - } - break; - - default: - dmError("Unknown argument '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -BOOL argHandleFile(char *currArg) -{ - if (nsrcFilenames < SET_MAX_FILES) - { - srcFilenames[nsrcFilenames] = currArg; - nsrcFilenames++; - } - else - { - dmError("Maximum number of input files (%d) exceeded!\n", - SET_MAX_FILES); - return FALSE; - } - return TRUE; -} - - -/* Compare a string to a pattern. Case-SENSITIVE version. - * The matching pattern can consist of any normal characters plus - * wildcards ? and *. "?" matches any character and "*" matches - * any number of characters. - */ -BOOL dm_strmatch(const char *str, const char *pattern) -{ - BOOL didMatch = TRUE, isAnyMode = FALSE, isEnd = FALSE; - const char *tmpPattern = NULL; - - // Check given pattern and string - if (str == NULL || pattern == NULL) - return FALSE; - - // Start comparision - do { - didMatch = FALSE; - switch (*pattern) - { - case '?': - // Any single character matches - if (*str) - { - didMatch = TRUE; - pattern++; - str++; - } - break; - - case '*': - didMatch = TRUE; - pattern++; - if (!*pattern) - isEnd = TRUE; - isAnyMode = TRUE; - tmpPattern = pattern; - break; - - case 0: - if (isAnyMode) - { - if (*str) - str++; - else - isEnd = TRUE; - } - else - { - if (*str) - { - if (tmpPattern) - { - isAnyMode = TRUE; - pattern = tmpPattern; - } - else - didMatch = FALSE; - } - else - isEnd = TRUE; - } - break; - default: - if (isAnyMode) - { - if (*pattern == *str) - { - isAnyMode = FALSE; - didMatch = TRUE; - } - else - { - if (*str) - { - didMatch = TRUE; - str++; - } - } - } - else - { - if (*pattern == *str) - { - didMatch = TRUE; - if (*pattern) - pattern++; - if (*str) - str++; - } - else - { - if (tmpPattern) - { - didMatch = TRUE; - isAnyMode = TRUE; - pattern = tmpPattern; - } - } - } - - if (!*str && !*pattern) - isEnd = TRUE; - break; - - } // switch - - } while (didMatch && !isEnd); - - return didMatch; -} - - -int dmAddFileToPack(DMPackFile *pack, const char *filename, int compression, int resFlags) -{ - DMPackEntry *node; - int res = dm_pack_add_file(pack, filename, compression, resFlags, &node); - - if (res != DMERR_OK) - { - dmPrint(1, "%-32s [ERROR:%d]\n", - filename, res); - } - else - { - char tmp[16]; - dmres_flags_to_symbolic(tmp, sizeof(tmp), node->resFlags); - dmPrint(1, "%-32s ['%s', s=%d, c=%d, o=%ld, f=%s]\n", - filename, node->filename, - node->size, node->length, node->offset, - tmp); - } - - return res; -} - - -int main(int argc, char *argv[]) -{ - int i, res = 0; - DMPackFile *pack = NULL; - -#ifndef __WIN32 - stderr = stdout; -#endif - - // Parse arguments - dmInitProg("packed", "Pack File Editor", "0.4", NULL, NULL); - dmVerbosity = 1; - - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, argHandleFile, TRUE)) - exit(1); - - // Check PACK filename - if (optPackFilename == NULL) - optPackFilename = SET_DEFAULT_PACK; - - if (optCommand == CMD_NONE) - { - argShowHelp(); - dmError("Nothing to do.\n"); - exit(0); - return 0; - } - - dmMsg(1, "Processing %s ...\n", optPackFilename); - - // Execute command - switch (optCommand) - { - case CMD_CREATE: - case CMD_ADD: - switch (optCommand) - { - case CMD_CREATE: - dmMsg(1, "Creating new PACK\n"); - res = dm_pack_create(optPackFilename, &pack); - break; - - case CMD_ADD: - dmMsg(1, "Opening existing PACK\n"); - res = dm_pack_open(optPackFilename, &pack, FALSE); - break; - } - - // Add files into PACK - if (res == DMERR_OK) - { - dmMsg(1, "Adding %d files...\n", nsrcFilenames); - - for (i = 0; i < nsrcFilenames; i++) - { - // Handle resource definition files - if (srcFilenames[i][0] == '@') - { - } - else - { - dmAddFileToPack(pack, srcFilenames[i], optCompress, optDefResFlags); - } - } - - dmMsg(1, "w=%d\n", dm_pack_write(pack)); - dmMsg(1, "c=%d\n", dm_pack_close(pack)); - } - else - { - dmError("Could not open packfile, error #%d: %s\n", res, - dmErrorStr(res)); - } - break; - - case CMD_LIST: - // List files in PACK - res = dm_pack_open(optPackFilename, &pack, TRUE); - if (res == DMERR_OK) - { - DMPackEntry *node; - for (i = 0, node = pack->entries; node; i++) - node = node->next; - dmMsg(1, "%d files total\n", i); - - dmPrint(0, "%-32s | %8s | %8s | %8s | %s\n", - "Name", "Size", "CSize", "Offset", "ResFlags"); - - for (node = pack->entries; node != NULL; node = node->next) - { - BOOL match; - - // Check for matches - if (nsrcFilenames > 0) - { - match = FALSE; - for (i = 0; i < nsrcFilenames && !match; i++) - { - match = dm_strmatch(node->filename, srcFilenames[i]); - } - } - else - match = TRUE; - - if (match) - { - char flags[16]; - dmres_flags_to_symbolic(flags, sizeof(flags), node->resFlags); - - dmPrint(0, "%-32s | %8d | %8d | %08x | %s\n", - node->filename, node->size, node->length, - node->offset, flags); - } - } - - dmMsg(1, "c=%d\n", dm_pack_close(pack)); - } - else - dmError("Could not open packfile, error #%d: %s\n", res, - dmErrorStr(res)); - break; - - case CMD_EXTRACT: - // Extract files from PACK - res = dm_pack_open(optPackFilename, &pack, TRUE); - if (res == DMERR_OK) - { - DMPackEntry *node; - FILE *resFile = fopen(DMRES_RES_FILE, "w"); - if (resFile == NULL) - { - dmError("Could not create resource output file '%s' #%d: %s\n", - DMRES_RES_FILE, errno, strerror(errno)); - } - - for (node = pack->entries; node != NULL; node = node->next) - { - BOOL match; - - // Check for matches - if (nsrcFilenames > 0) - { - match = FALSE; - for (i = 0; (i < nsrcFilenames) && !match; i++) - { - match = dm_strmatch(node->filename, srcFilenames[i]); - } - } - else - match = TRUE; - - if (match && (node->privFlags & PACK_EXTRACTED) == 0) - { - char tmp[16]; - - // Mark as done - node->privFlags |= PACK_EXTRACTED; - - // Print one entry - dmres_flags_to_symbolic(tmp, sizeof(tmp), node->resFlags); - dmPrint(0, "Extracting: %-32s [siz=%d, cmp=%d, offs=0x%08x, flags=%s]\n", - node->filename, node->size, node->length, - node->offset, tmp); - - dm_pack_extract_file(pack, node); - - if (resFile != NULL) - { - fprintf(resFile, - "%s|%s\n", node->filename, tmp); - } - } - } - - dmMsg(1, "c=%d\n", dm_pack_close(pack)); - - if (resFile != NULL) - fclose(resFile); - } - else - dmError("Could not open packfile, error #%d: %s\n", res, - dmErrorStr(res)); - break; - - } - - return 0; -}
--- a/ppl.c Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,932 +0,0 @@ -/* - * Cyrbe Pasci Player - A simple SDL-based UI for XM module playing - * 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 <SDL.h> -#include "dmlib.h" - -#include "jss.h" -#include "jssmod.h" -#include "jssmix.h" -#include "jssplr.h" - -#include "dmargs.h" -#include "dmimage.h" -#include "dmtext.h" - -#include "setupfont.h" - - -struct -{ - BOOL exitFlag; - SDL_Surface *screen; - SDL_Event event; - int optScrWidth, optScrHeight, optVFlags, optScrDepth; - - int actChannel; - BOOL pauseFlag; - - JSSModule *mod; - JSSMixer *dev; - JSSPlayer *plr; - SDL_AudioSpec afmt; -} engine; - -struct -{ - Uint32 boxBg, inboxBg, box1, box2, viewDiv, activeRow, activeChannel; -} col; - - -DMBitmapFont *font = NULL; - -char *optFilename = NULL; -int optOutFormat = JSS_AUDIO_S16, - optOutChannels = 2, - optOutFreq = 48000, - optMuteOChannels = -1, - optStartOrder = 0; -BOOL optUsePlayTime = FALSE; -size_t optPlayTime; - - -DMOptArg optList[] = -{ - { 0, '?', "help", "Show this help", OPT_NONE }, - { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, - { 2, 0, "fs", "Fullscreen", OPT_NONE }, - { 3, 'w', "window", "Initial window size/resolution -w 640x480", OPT_ARGREQ }, - - { 4, '1', "16bit", "16-bit output", OPT_NONE }, - { 5, '8', "8bit", "8-bit output", OPT_NONE }, - { 6, 'm', "mono", "Mono output", OPT_NONE }, - { 7, 's', "stereo", "Stereo output", OPT_NONE }, - { 8, 'f', "freq", "Output frequency", OPT_ARGREQ }, - - { 9, 'M', "mute", "Mute other channels than #", OPT_ARGREQ }, - { 10, 'o', "order", "Start from order #", OPT_ARGREQ }, - { 11, 't', "time", "Play for # seconds", OPT_ARGREQ }, -}; - -const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - dmPrintBanner(stdout, dmProgName, "[options] <module>"); - dmArgsPrintHelp(stdout, optList, optListN); -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - switch (optN) { - case 0: - argShowHelp(); - exit(0); - break; - - case 1: - dmVerbosity++; - break; - - case 2: - engine.optVFlags |= SDL_FULLSCREEN; - break; - - case 3: - { - int w, h; - if (sscanf(optArg, "%dx%d", &w, &h) == 2) - { - if (w < 320 || h < 200 || w > 3200 || h > 3200) - { - dmError("Invalid width or height: %d x %d\n", w, h); - return FALSE; - } - engine.optScrWidth = w; - engine.optScrHeight = h; - } - else - { - dmError("Invalid size argument '%s'.\n", optArg); - return FALSE; - } - } - break; - - case 4: - optOutFormat = JSS_AUDIO_S16; - break; - - case 5: - optOutFormat = JSS_AUDIO_U8; - break; - - case 6: - optOutChannels = JSS_AUDIO_MONO; - break; - - case 7: - optOutChannels = JSS_AUDIO_STEREO; - break; - - case 8: - optOutFreq = atoi(optArg); - break; - - case 9: - optMuteOChannels = atoi(optArg); - break; - - case 10: - optStartOrder = atoi(optArg); - break; - - case 11: - optPlayTime = atoi(optArg); - optUsePlayTime = TRUE; - break; - - default: - dmError("Unknown option '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -BOOL argHandleFile(char *currArg) -{ - if (!optFilename) - optFilename = currArg; - else - { - dmError("Too many filename arguments '%s'\n", currArg); - return FALSE; - } - - return TRUE; -} - - -void dmDrawBMTextConstQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt) -{ - const char *ptr = fmt; - DMUnscaledBlitFunc blit = NULL; - - while (*ptr) - { - int ch = *ptr++; - SDL_Surface *glyph; - - if (ch == '_') - { - xc += 4; - continue; - } - - if (ch >= 0 && ch < font->nglyphs && (glyph = font->glyphs[ch]) != NULL) - { - if (blit == NULL) - blit = dmGetUnscaledBlitFunc(glyph->format, screen->format, mode); - - blit(glyph, xc, yc, screen); - xc += font->width; - } - else - xc += font->width; - } -} - - -void dmDrawBMTextVAQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt, va_list ap) -{ - char tmp[512]; - vsnprintf(tmp, sizeof(tmp), fmt, ap); - dmDrawBMTextConstQ(screen, font, mode, xc, yc, tmp); -} - - -void dmDrawBMTextQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - dmDrawBMTextVAQ(screen, font, mode, xc, yc, fmt, ap); - va_end(ap); -} - - -Uint32 dmCol(float r, float g, float b) -{ - return dmMapRGB(engine.screen, 255.0f * r, 255.0f * g, 255.0f * b); -} - - -BOOL dmInitializeVideo() -{ - SDL_FreeSurface(engine.screen); - - engine.screen = SDL_SetVideoMode( - engine.optScrWidth, engine.optScrHeight, engine.optScrDepth, - engine.optVFlags | SDL_RESIZABLE | SDL_SWSURFACE | SDL_HWPALETTE); - - if (engine.screen == NULL) - { - dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); - return FALSE; - } - - col.inboxBg = dmCol(0.6, 0.5, 0.2); - col.boxBg = dmCol(0.7, 0.6, 0.3); - col.box1 = dmCol(1.0, 0.9, 0.6); - col.box2 = dmCol(0.3, 0.3, 0.15); - col.viewDiv = dmCol(0,0,0); - col.activeRow = dmCol(0.5,0.4,0.1); - col.activeChannel = dmCol(0.6, 0.8, 0.2); - - return TRUE; -} - - -void dmDisplayChn(SDL_Surface *screen, int x0, int y0, int x1, int y1, int nchannel, JSSChannel *chn) -{ - int yh = y1 - y0 - 2; - if (yh < 10 || chn == NULL) - return; - - int xc, ym = y0 + (y1 - y0) / 2, vol = FP_GETH(chn->chVolume); - int pitch = screen->pitch / sizeof(Uint32); - int len = FP_GETH(chn->chSize); - DMFixedPoint offs = chn->chPos; - Uint32 coln = dmCol(0.0, 0.8, 0.0), colx = dmCol(1.0, 0, 0); - Uint32 *pix = screen->pixels; - Sint16 *data = chn->chData; - - - dmFillBox3D(screen, x0, y0, x1, y1, - (chn->chMute ? dmCol(0.3,0.1,0.1) : dmCol(0,0,0)), - nchannel == engine.actChannel ? colx : col.box2, - nchannel == engine.actChannel ? colx : col.box1); - - if (chn->chData == NULL || !chn->chPlaying) - return; - - if (chn->chDirection) - { - for (xc = x0 + 1; xc < x1 - 1; xc++) - { - if (FP_GETH(offs) >= len) - break; - Sint16 val = ym + (data[FP_GETH(offs)] * yh * vol) / (65535 * 255); - pix[xc + val * pitch] = coln; - FP_ADD(offs, chn->chDeltaO); - } - } - else - { - for (xc = x0 + 1; xc < x1 - 1; xc++) - { - if (FP_GETH(offs) < 0) - break; - Sint16 val = ym + (data[FP_GETH(offs)] * yh * vol) / (65535 * 255); - pix[xc + val * pitch] = coln; - FP_SUB(offs, chn->chDeltaO); - } - } -} - - -void dmDisplayChannels(SDL_Surface *screen, int x0, int y0, int x1, int y1, JSSMixer *dev) -{ - int nchannel, qx, qy, - qwidth = x1 - x0, - qheight = y1 - y0, - nwidth = jsetNChannels, - nheight = 1; - - if (qheight < 40) - return; - - while (qwidth / nwidth <= 60 && qheight / nheight >= 40) - { - nheight++; - nwidth /= nheight; - } - -// fprintf(stderr, "%d x %d\n", nwidth, nheight); - - if (qheight / nheight <= 40) - { - nwidth = qwidth / 60; - nheight = qheight / 40; - } - - qwidth /= nwidth; - qheight /= nheight; - - for (nchannel = qy = 0; qy < nheight && nchannel < jsetNChannels; qy++) - { - for (qx = 0; qx < nwidth && nchannel < jsetNChannels; qx++) - { - int xc = x0 + qx * qwidth, - yc = y0 + qy * qheight; - - dmDisplayChn(screen, xc + 1, yc + 1, - xc + qwidth - 1, yc + qheight - 1, - nchannel, &dev->channels[nchannel]); - - nchannel++; - } - } -} - - -static const char patNoteTable[12][3] = -{ - "C-", "C#", "D-", - "D#", "E-", "F-", - "F#", "G-", "G#", - "A-", "A#", "B-" -}; - - -#define jmpNMODEffectTable (36) -static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - -static const char jmpHexTab[16] = "0123456789ABCDEF"; - -static inline char dmHexVal(int v) -{ - return jmpHexTab[v & 15]; -} - -void dmPrintNote(SDL_Surface *screen, int xc, int yc, JSSNote *n) -{ - char text[32]; - char *ptr = text; - - switch (n->note) - { - case jsetNotSet: - strcpy(ptr, "..._"); - break; - case jsetNoteOff: - strcpy(ptr, "===_"); - break; - default: - sprintf(ptr, "%s%i_", - patNoteTable[n->note % 12], - n->note / 12); - break; - } - - ptr += 4; - - if (n->instrument != jsetNotSet) - { - int v = n->instrument + 1; - *ptr++ = dmHexVal(v >> 4); - *ptr++ = dmHexVal(v); - } - else - { - *ptr++ = '.'; - *ptr++ = '.'; - } - *ptr++ = '_'; - - if (n->volume == jsetNotSet) - { - *ptr++ = '.'; - *ptr++ = '.'; - } - else - if (n->volume >= 0x00 && n->volume <= 0x40) - { - *ptr++ = dmHexVal(n->volume >> 4); - *ptr++ = dmHexVal(n->volume); - } - else - { - char c; - switch (n->volume & 0xf0) - { - case 0x50: c = '-'; break; - case 0x60: c = '+'; break; - case 0x70: c = '/'; break; - case 0x80: c = '\\'; break; - case 0x90: c = 'S'; break; - case 0xa0: c = 'V'; break; - case 0xb0: c = 'P'; break; - case 0xc0: c = '<'; break; - case 0xd0: c = '>'; break; - case 0xe0: c = 'M'; break; - default: c = '?'; break; - } - *ptr++ = c; - *ptr++ = dmHexVal(n->volume); - } - *ptr++ = '_'; - - if (n->effect >= 0 && n->effect < jmpNMODEffectTable) - *ptr++ = jmpMODEffectTable[n->effect]; - else - *ptr++ = (n->effect == jsetNotSet ? '.' : '?'); - - if (n->param != jsetNotSet) - { - *ptr++ = dmHexVal(n->param >> 4); - *ptr++ = dmHexVal(n->param); - } - else - { - *ptr++ = '.'; - *ptr++ = '.'; - } - - *ptr = 0; - - dmDrawBMTextConstQ(screen, font, DMD_TRANSPARENT, xc, yc, text); -} - - -void dmDisplayPattern(SDL_Surface *screen, int x0, int y0, int x1, int y1, JSSPattern *pat, int row) -{ - int cwidth = (font->width * 10 + 3 * 4 + 5), - lwidth = 6 + font->width * 3, - qy0 = y0 + font->height + 2, - qy1 = y1 - font->height - 2, - qwidth = ((x1 - x0 - lwidth) / cwidth), - qheight = ((qy1 - qy0 - 4) / (font->height + 1)), - nrow, nchannel, yc, choffs, - midrow = qheight / 2; - - if (engine.actChannel < qwidth / 2) - choffs = 0; - else - if (engine.actChannel >= pat->nchannels - qwidth/2) - choffs = pat->nchannels - qwidth; - else - choffs = engine.actChannel - qwidth/2; - - dmDrawBox3D(screen, x0 + lwidth, qy0, x1, qy1, col.box2, col.box1); - - for (nchannel = 0; nchannel < qwidth; nchannel++) - { - int bx0 = x0 + lwidth + 1 + nchannel * cwidth, - bx1 = bx0 + cwidth; - - if (engine.actChannel == nchannel + choffs) - { - dmFillRect(screen, bx0+1, qy0 + 1, bx1-1, qy1 - 1, col.activeChannel); - } - else - { - dmFillRect(screen, bx0+1, qy0 + 1, bx1-1, qy1 - 1, col.inboxBg); - } - } - - yc = qy0 + 2 + (font->height + 1) * midrow; - dmFillRect(screen, x0 + lwidth + 1, yc - 1, x1 - 1, yc + font->height, col.activeRow); - - for (nchannel = 0; nchannel < qwidth; nchannel++) - { - int bx0 = x0 + lwidth + 1 + nchannel * cwidth, - bx1 = bx0 + cwidth; - - dmDrawVLine(screen, qy0 + 1, qy1 - 1, bx1, col.viewDiv); - - if (jvmGetMute(engine.dev, nchannel + choffs)) - { - dmDrawBMTextConstQ(screen, font, DMD_TRANSPARENT, - bx0 + (cwidth - font->width * 5) / 2, qy1 + 3, "MUTED"); - } - - dmDrawBMTextQ(screen, font, DMD_TRANSPARENT, - bx0 + (cwidth - font->width * 3) / 2, y0 + 1, "%3d", - nchannel + choffs); - } - - for (nrow = 0; nrow < qheight; nrow++) - { - int crow = nrow - midrow + row; - yc = qy0 + 2 + (font->height + 1) * nrow; - - if (crow >= 0 && crow < pat->nrows) - { - dmDrawBMTextQ(screen, font, DMD_TRANSPARENT, x0, yc, "%03d", crow); - - for (nchannel = 0; nchannel < qwidth; nchannel++) - { - if (choffs + nchannel >= pat->nchannels) - break; - - dmPrintNote(screen, x0 + lwidth + 4 + nchannel * cwidth, yc, - pat->data + (pat->nchannels * crow) + choffs + nchannel); - } - } - } -} - - -void audioCallback(void *userdata, Uint8 *stream, int len) -{ - JSSMixer *d = (JSSMixer *) userdata; - - if (d != NULL) - { - jvmRenderAudio(d, stream, len / jvmGetSampleSize(d)); - } -} - - -void dmMuteChannels(BOOL mute) -{ - int i; - for (i = 0; i < engine.mod->nchannels; i++) - jvmMute(engine.dev, i, mute); -} - -int main(int argc, char *argv[]) -{ - BOOL initSDL = FALSE, audioInit = FALSE; - DMResource *file = NULL; - int result = -1; - BOOL muteState = FALSE; - - memset(&engine, 0, sizeof(engine)); - - engine.optScrWidth = 640; - engine.optScrHeight = 480; - engine.optScrDepth = 32; - - dmInitProg("CBP", "Cyrbe Basci Player", "0.1", NULL, NULL); - - // Parse arguments - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, argHandleFile, TRUE)) - exit(1); - - // Open the files - if (optFilename == NULL) - { - dmError("No filename specified.\n"); - return 1; - } - - if ((file = dmf_create_stdio(optFilename, "rb")) == NULL) - { - int err = dmGetErrno(); - dmError("Error opening file '%s', %d: (%s)\n", - optFilename, err, dmErrorStr(err)); - return 1; - } - - // Initialize miniJSS - jssInit(); - - // Read module file - dmMsg(1, "Reading file: %s\n", optFilename); -#ifdef JSS_SUP_XM - dmMsg(2, "* Trying XM...\n"); - result = jssLoadXM(file, &engine.mod); -#endif -#ifdef JSS_SUP_JSSMOD - if (result != 0) - { - size_t bufgot, bufsize = dmfsize(file); - Uint8 *buf = dmMalloc(bufsize); - dmfseek(file, 0L, SEEK_SET); - dmMsg(2, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf); - if ((bufgot = dmfread(buf, 1, bufsize, file)) != bufsize) - { - dmf_close(file); - dmError("Error reading file (not enough data %d), #%d: %s\n", - bufgot, dmferror(file), dmErrorStr(dmferror(file))); - goto error_exit; - } - result = jssLoadJSSMOD(buf, bufsize, &engine.mod); - dmFree(buf); - } -#endif - dmf_close(file); - - if (result != DMERR_OK) - { - dmError("Error loading module file, %d: %s\n", - result, dmErrorStr(result)); - goto error_exit; - } - - // Try to convert it - if ((result = jssConvertModuleForPlaying(engine.mod)) != DMERR_OK) - { - dmError("Could not convert module for playing, %d: %s\n", - result, dmErrorStr(result)); - goto error_exit; - } - - // Get font -// file = dmf_create_stdio("fnsmall.fnt", "rb"); - file = dmf_create_memio(NULL, "pplfont.fnt", engineSetupFont, sizeof(engineSetupFont)); - if (file == NULL) - { - dmError("Error opening font file 'pplfont.fnt'.\n"); - goto error_exit; - } - result = dmLoadBitmapFont(file, &font); - dmf_close(file); - if (result != DMERR_OK) - { - dmError("Could not load font from file, %d: %s\n", - result, dmErrorStr(result)); - goto error_exit; - } - - // Initialize SDL components - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) != 0) - { - dmError("Could not initialize SDL: %s\n", SDL_GetError()); - goto error_exit; - } - initSDL = TRUE; - - - // Initialize mixing device - dmMsg(2, "Initializing miniJSS mixer with: %d, %d, %d\n", - optOutFormat, optOutChannels, optOutFreq); - - engine.dev = jvmInit(optOutFormat, optOutChannels, optOutFreq, JMIX_AUTO); - if (engine.dev == NULL) - { - dmError("jvmInit() returned NULL\n"); - goto error_exit; - } - - switch (optOutFormat) - { - case JSS_AUDIO_S16: engine.afmt.format = AUDIO_S16SYS; break; - case JSS_AUDIO_U16: engine.afmt.format = AUDIO_U16SYS; break; - case JSS_AUDIO_S8: engine.afmt.format = AUDIO_S8; break; - case JSS_AUDIO_U8: engine.afmt.format = AUDIO_U8; break; - default: - dmError("Unsupported audio format %d (could not set matching SDL format)\n", - optOutFormat); - goto error_exit; - } - - engine.afmt.freq = optOutFreq; - engine.afmt.channels = optOutChannels; - engine.afmt.samples = optOutFreq / 16; - engine.afmt.callback = audioCallback; - engine.afmt.userdata = (void *) engine.dev; - - // Open the audio device - if (SDL_OpenAudio(&engine.afmt, NULL) < 0) - { - dmError("Couldn't open SDL audio: %s\n", - SDL_GetError()); - goto error_exit; - } - audioInit = TRUE; - - // Initialize player - if ((engine.plr = jmpInit(engine.dev)) == NULL) - { - dmError("jmpInit() returned NULL\n"); - goto error_exit; - } - - jvmSetCallback(engine.dev, jmpExec, engine.plr); - jmpSetModule(engine.plr, engine.mod); - jmpPlayOrder(engine.plr, optStartOrder); - jvmSetGlobalVol(engine.dev, 64); - - if (optMuteOChannels >= 0 && optMuteOChannels < engine.mod->nchannels) - { - dmMuteChannels(TRUE); - jvmMute(engine.dev, optMuteOChannels, FALSE); - engine.actChannel = optMuteOChannels; - muteState = TRUE; - } - - // Initialize video - if (!dmInitializeVideo()) - goto error_exit; - - SDL_WM_SetCaption(dmProgDesc, dmProgName); - - SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); - - // okay, main loop here ... "play" module and print out info - SDL_LockAudio(); - SDL_PauseAudio(0); - SDL_UnlockAudio(); - - int currTick, prevTick = 0, prevRow = -1; - - while (!engine.exitFlag) - { - currTick = SDL_GetTicks(); - BOOL force = (currTick - prevTick > 500), updated = FALSE; - - while (SDL_PollEvent(&engine.event)) - switch (engine.event.type) - { - case SDL_KEYDOWN: - switch (engine.event.key.keysym.sym) - { - case SDLK_ESCAPE: - engine.exitFlag = TRUE; - break; - - case SDLK_SPACE: - engine.pauseFlag = !engine.pauseFlag; - SDL_PauseAudio(engine.pauseFlag); - break; - - case SDLK_LEFT: - if (engine.actChannel > 0) - { - engine.actChannel--; - force = TRUE; - } - break; - - case SDLK_RIGHT: - if (engine.actChannel < engine.mod->nchannels) - { - engine.actChannel++; - force = TRUE; - } - break; - - case SDLK_m: - if (engine.event.key.keysym.mod & KMOD_SHIFT) - { - muteState = !muteState; - dmMuteChannels(muteState); - } - else - if (engine.event.key.keysym.mod & KMOD_CTRL) - { - dmMuteChannels(FALSE); - } - else - { - jvmMute(engine.dev, engine.actChannel, !jvmGetMute(engine.dev, engine.actChannel)); - } - force = TRUE; - break; - - case SDLK_PAGEUP: - JSS_LOCK(engine.dev); - JSS_LOCK(engine.plr); - jmpChangeOrder(engine.plr, dmClamp(engine.plr->order - 1, 0, engine.mod->norders)); - JSS_UNLOCK(engine.plr); - JSS_UNLOCK(engine.dev); - force = TRUE; - break; - - case SDLK_PAGEDOWN: - JSS_LOCK(engine.dev); - JSS_LOCK(engine.plr); - jmpChangeOrder(engine.plr, dmClamp(engine.plr->order + 1, 0, engine.mod->norders)); - JSS_UNLOCK(engine.plr); - JSS_UNLOCK(engine.dev); - force = TRUE; - break; - - case SDLK_f: - engine.optVFlags ^= SDL_FULLSCREEN; - if (!dmInitializeVideo()) - goto error_exit; - force = TRUE; - break; - - default: - break; - } - - break; - - case SDL_VIDEORESIZE: - engine.optScrWidth = engine.event.resize.w; - engine.optScrHeight = engine.event.resize.h; - - if (!dmInitializeVideo()) - goto error_exit; - - break; - - case SDL_VIDEOEXPOSE: - break; - - case SDL_QUIT: - engine.exitFlag = TRUE; - break; - } - - -#if 1 - JSS_LOCK(engine.plr); - JSSPattern *currPattern = engine.plr->pattern; - int currRow = engine.plr->row; - if (!engine.plr->isPlaying) - engine.exitFlag = TRUE; - JSS_UNLOCK(engine.plr); - - if (currRow != prevRow || force) - { - prevRow = currRow; - force = TRUE; - } - - // Draw frame - if (SDL_MUSTLOCK(engine.screen) != 0 && SDL_LockSurface(engine.screen) != 0) - { - dmError("Can't lock surface.\n"); - goto error_exit; - } - - if (force) - { - dmClearSurface(engine.screen, col.boxBg); - - dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5, "%s v%s by ccr/TNSP - (c) Copyright 2012 TNSP", dmProgDesc, dmProgVersion); - - dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5 + 12 + 11, - "Song: '%s'", - engine.mod->moduleName); - - dmDisplayPattern(engine.screen, 5, 40, - engine.screen->w - 6, engine.screen->h * 0.8, - currPattern, currRow); - - JSS_LOCK(engine.plr); - dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5 + 12, - "Tempo: %3d | Speed: %3d | Row: %3d/%-3d | Order: %3d/%-3d | Pattern: %3d/%-3d", - engine.plr->tempo, engine.plr->speed, - engine.plr->row, engine.plr->pattern->nrows, - engine.plr->order, engine.mod->norders, - engine.plr->npattern, engine.mod->npatterns); - JSS_UNLOCK(engine.plr); - updated = TRUE; - } - - if (force || currTick - prevTick >= (engine.pauseFlag ? 100 : 20)) - { - JSS_LOCK(engine.dev); - dmDisplayChannels(engine.screen, 5, engine.screen->h * 0.8 + 5, - engine.screen->w - 5, engine.screen->h - 5, engine.dev); - JSS_UNLOCK(engine.dev); - updated = TRUE; - } - - if (force) - prevTick = currTick; - -#endif - // Flip screen - if (SDL_MUSTLOCK(engine.screen) != 0) - SDL_UnlockSurface(engine.screen); - - if (updated) - SDL_Flip(engine.screen); - - SDL_Delay(engine.pauseFlag ? 100 : 30); - } - -error_exit: - if (engine.screen) - SDL_FreeSurface(engine.screen); - - dmMsg(0, "Audio shutdown.\n"); - if (audioInit) - { - SDL_LockAudio(); - SDL_PauseAudio(1); - SDL_UnlockAudio(); - SDL_CloseAudio(); - } - - jmpClose(engine.plr); - jvmClose(engine.dev); - jssFreeModule(engine.mod); - - dmFreeBitmapFont(font); - - if (initSDL) - SDL_Quit(); - - jssClose(); - - return 0; -}
--- a/svg2qd.py Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,102 +0,0 @@ -#!/usr/bin/python -import sys -import re -import xml.etree.ElementTree as ET - - -def bf(x) : - return int(round(float(x))) - - -def printVertex(v) : - if type(v) is list : - return "{:.2f},{:.2f},{:.2f}".format(v[0], v[1], v[2]) - else : - return v - - -def getTransform(elem) : - if "transform" in elem.attrib : - ntrans = elem.attrib["transform"] - tmatch = re.compile(r"translate\((.*?)\)", re.IGNORECASE) - for trns in tmatch.finditer(ntrans) : - coord = trns.group(1).split(",") - return [float(coord[0]), float(coord[1]), 0] - return None - - -def getStyle(elem) : - style = {} - if "style" in elem.attrib : - for elem in elem.attrib["style"].split(";") : - kv = elem.split(":") - style[kv[0]] = kv[1] - return style - - -def printVertices(type, vertices, width, level) : - if len(vertices) > 0 : - list = map(lambda v:printVertex(v), vertices) - str = "# "+ type - if type == "m" : - str = "R" - elif type == "M" : - str = "L" - elif type == "c" : - str = "R" - print "{}{}{} {} {}".format(" "*level, str, len(vertices)-1, " ".join(list), width) - - -def printPath(path, level) : - style = getStyle(path) - width = bf(style["stroke-width"]) - - trans = getTransform(path) - if trans : - print "{}G{}".format(" "*level, printVertex(trans)) - - vertices = [] - type = "" - for elem in path.attrib["d"].split(" ") : - if elem == "m" or elem == "M" : - printVertices(type, vertices, width, level) - vertices = [] - type = elem - elif elem == "z" : - vertices.append("Z") - elif elem == "c" or elem == "C" : - print "Curves not supported! Path ID '{}':\n{}".format(path.attrib["id"], path.attrib["d"]) - sys.exit(0) - else : - tmp = elem.split(",") - px = float(tmp[0]) - py = float(tmp[1]) - vertices.append([px, py, 0]) - - printVertices(type, vertices, width, level) - if trans : - print "{}E\n".format(" "*level) - - -def iterateDocument(elems, level) : - for elem in elems: - if elem.tag == "{http://www.w3.org/2000/svg}g" : - print "\n{}# GROUP".format(" "*level) - tmp = getTransform(elem) - if tmp : - print "{}G{}".format(" "*level, printVertex(getTransform(elem))) - iterateDocument(elem, level + 1) - print "{}E\n".format(" "*level) - else : - iterateDocument(elem, level) - elif elem.tag == "{http://www.w3.org/2000/svg}path" : - printPath(elem, level) - - -# Ns. paaohjelma -if len(sys.argv) != 2 : - print "Usage: "+sys.argv[0]+" <input.svg>" - sys.exit(1) - -tree = ET.parse(sys.argv[1]) -iterateDocument(tree.getroot(), 0)
--- a/testpl.c Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,267 +0,0 @@ -#include "jss.h" -#include "jssmod.h" -#include "jssmix.h" -#include "jssplr.h" -#include <errno.h> -#include <string.h> -#include <unistd.h> -#include <SDL.h> - - -static const char patNoteTable[12][3] = -{ - "C-", "C#", "D-", - "D#", "E-", "F-", - "F#", "G-", "G#", - "A-", "A#", "B-" -}; - - -#define jmpNMODEffectTable (36) -static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - -void printRow(FILE * f, JSSPattern * p, int row) -{ - int j, k; - char c; - JSSNote *n; - - if (!p) - return; - - n = &(p->data[p->nchannels * row]); - - fprintf(f, "%.2x: ", row); - - k = p->nchannels < 5 ? p->nchannels : 5; - - for (j = 0; j < k; j++) - { - switch (n->note) - { - case jsetNotSet: - fprintf(f, "... "); - break; - case jsetNoteOff: - fprintf(f, "=== "); - break; - default: - fprintf(f, "%s%i ", patNoteTable[n->note % 12], n->note / 12); - break; - } - - if (n->instrument != jsetNotSet) - fprintf(f, "%.2x ", n->instrument + 1); - else - fprintf(f, ".. "); - - if (n->volume == jsetNotSet) - fprintf(f, ".. "); - else if (n->volume >= 0x00 && n->volume <= 0x40) - fprintf(f, "%.2x ", n->volume); - else - { - switch (n->volume & 0xf0) - { - case 0x50: c = '-'; break; - case 0x60: c = '+'; break; - case 0x70: c = '/'; break; - case 0x80: c = '\\'; break; - case 0x90: c = 'S'; break; - case 0xa0: c = 'V'; break; - case 0xb0: c = 'P'; break; - case 0xc0: c = '<'; break; - case 0xd0: c = '>'; break; - case 0xe0: c = 'M'; break; - default: c = '?'; break; - } - fprintf(f, "%c%x ", c, (n->volume & 0x0f)); - } - - if (n->effect >= 0 && n->effect < jmpNMODEffectTable) - fprintf(f, "%c", jmpMODEffectTable[n->effect]); - else if (n->effect == jsetNotSet) - fprintf(f, "."); - else - fprintf(f, "?"); - - if (n->param != jsetNotSet) - fprintf(f, "%.2x|", n->param); - else - fprintf(f, "..|"); - - n++; - } -} - - -void audioCallback(void *userdata, Uint8 *stream, int len) -{ - JSSMixer *d = (JSSMixer *) userdata; - - if (d != NULL) - { - jvmRenderAudio(d, stream, len / jvmGetSampleSize(d)); - } -} - - -int main(int argc, char *argv[]) -{ - SDL_AudioSpec afmt; - DMResource *file = NULL; - char *sname = NULL; - int result = -1; - JSSModule *mod = NULL; - JSSMixer *dev = NULL; - JSSPlayer *plr = NULL; - - if (argc > 1) - sname = argv[1]; - - // Open the files - if (sname == NULL) - file = dmf_create_stdio_stream(stdin); - else if ((file = dmf_create_stdio(sname, "rb")) == NULL) - { - fprintf(stderr, "Error opening input file '%s'. (%s)\n", - sname, strerror(errno)); - return 1; - } - - // Initialize miniJSS - fprintf(stderr, "Initializing miniJSS\n"); - jssInit(); - - - // Read module file - fprintf(stderr, "Reading file: %s\n", sname); -#ifdef JSS_SUP_XM - fprintf(stderr, "* Trying XM...\n"); - result = jssLoadXM(file, &mod); -#endif -#ifdef JSS_SUP_JSSMOD - if (result != 0) - { - size_t bufgot, bufsize = dmfsize(file); - Uint8 *buf = dmMalloc(bufsize); - dmfseek(file, 0L, SEEK_SET); - fprintf(stderr, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf); - if ((bufgot = dmfread(buf, 1, bufsize, file)) != bufsize) - { - fprintf(stderr, "Error reading file (not enough data %d), #%d: %s\n", - bufgot, dmferror(file), dmErrorStr(dmferror(file))); - return 2; - } - result = jssLoadJSSMOD(buf, bufsize, &mod); - dmFree(buf); - } -#endif - dmf_close(file); - - if (result != DMERR_OK) - { - fprintf(stderr, "Error loading module file, %d: %s\n", - result, dmErrorStr(result)); - return 3; - } - - // Try to convert it - if ((result = jssConvertModuleForPlaying(mod)) != DMERR_OK) - { - fprintf(stderr, "Could not convert module for playing, %d: %s\n", - result, dmErrorStr(result)); - return 3; - } - - // Initialize SDL audio - afmt.freq = 48000; - afmt.format = AUDIO_S16SYS; - afmt.channels = 2; - - // Initialize mixing device - fprintf(stderr, "Initializing miniJSS mixer with: %d, %d, %d\n", - JSS_AUDIO_S16, afmt.channels, afmt.freq); - - dev = jvmInit(JSS_AUDIO_S16, afmt.channels, afmt.freq, JMIX_AUTO); - if (dev == NULL) - { - fprintf(stderr, "jvmInit() returned NULL\n"); - return 3; - } - - afmt.samples = afmt.freq / 4; - afmt.callback = audioCallback; - afmt.userdata = (void *) dev; - - // Open the audio device - fprintf(stderr, "Trying to init SDL with: %d, %d, %d\n", - afmt.format, afmt.channels, afmt.freq); - - if (SDL_OpenAudio(&afmt, NULL) < 0) - { - fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError()); - return 4; - } - - // Initialize player - if ((plr = jmpInit(dev)) == NULL) - { - fprintf(stderr, "jmpInit() returned NULL\n"); - return 4; - } - - // Initialize playing - jvmSetCallback(dev, jmpExec, plr); - jmpSetModule(plr, mod); - jmpPlayOrder(plr, 0); - jvmSetGlobalVol(dev, 60); - - // okay, main loop here ... "play" module and print out info - printf("----------------------------------------------------\n"); - SDL_LockAudio(); - SDL_PauseAudio(0); - SDL_UnlockAudio(); - BOOL playing = TRUE; - while (playing) - { - JSSPattern *pattern; - int currRow, prevRow; - - JSS_LOCK(plr); - currRow = prevRow = plr->row; - JSS_UNLOCK(plr); - - while (currRow == prevRow && playing) - { - JSS_LOCK(plr); - currRow = plr->row; - playing = plr->isPlaying; - pattern = plr->pattern; - JSS_UNLOCK(plr); - SDL_Delay(50); - } - - if (playing) - { - printRow(stdout, pattern, currRow); - printf("\n"); - } - } - - printf("----------------------------------------------------\n"); - - SDL_LockAudio(); - SDL_PauseAudio(1); - jmpClose(plr); - jvmClose(dev); - jssFreeModule(mod); - SDL_UnlockAudio(); - - SDL_Quit(); - - jssClose(); - - return 0; -}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/blittest.c Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,458 @@ +#include "dmlib.h" +#include "dmargs.h" +#include "dmvecmat.h" +#include "dmtext.h" +#include <math.h> + +#define DM_COLORS (256) + +char *optFontFile = "font.ttf"; +BOOL optBenchmark = FALSE; +int optVFlags = SDL_SWSURFACE | SDL_HWPALETTE; +int optScrWidth = 640, optScrHeight = 480, optFontSize = 20, optScrDepth = 32; +int optBenchmarkLen = 20; + +DMOptArg optList[] = { + { 0, '?', "help", "Show this help", OPT_NONE }, + { 2, 'v', "verbose", "Be more verbose", OPT_NONE }, + { 3, 'f', "full", "Fullscreen", OPT_NONE }, + { 4, 'h', "hw", "Use SDL hardware surface", OPT_NONE }, + { 5, 's', "size", "Initial window size/resolution -s 640x480", OPT_ARGREQ }, + { 6, 'd', "depth", "Color depth of mode/window in bits (8/32)", OPT_ARGREQ }, + { 7, 'b', "bench", "Run in benchmark mode", OPT_NONE }, +}; + +const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + dmArgsPrintHelp(stdout, optList, optListN); +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + switch (optN) { + case 0: + argShowHelp(); + exit(0); + break; + + case 2: + dmVerbosity++; + break; + + case 3: + optVFlags |= SDL_FULLSCREEN; + break; + + case 6: + if (optArg) + optScrDepth = atoi(optArg); + break; + + case 5: + { + int w, h; + if (sscanf(optArg, "%dx%d", &w, &h) == 2) + { + if (w < 320 || h < 200 || w > 3200 || h > 3200) + { + dmError("Invalid width or height: %d x %d\n", w, h); + return FALSE; + } + optScrWidth = w; + optScrHeight = h; + } + else + { + dmError("Invalid size argument '%s'.\n", optArg); + return FALSE; + } + } + break; + + case 7: + optBenchmark = TRUE; + break; + + default: + dmError("Unknown option '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +void DM_MakePalette(SDL_Surface *scr) +{ + SDL_Color pal[DM_COLORS]; + int n; + + for (n = 0; n < 256; n++) + { + pal[n].r = n; + pal[n].g = n; + pal[n].b = n; + } + + SDL_SetColors(scr, pal, 0, DM_COLORS); +} + + +void DM_PrintRect(FILE *f, SDL_Rect *r) +{ + fprintf(f, "SDL_Rect <%d, %d : %d, %d>\n", + r->x, r->y, r->w, r->h); +} + +BOOL DM_InitializeVideo(SDL_Surface **screen) +{ + *screen = SDL_SetVideoMode(optScrWidth, optScrHeight, optScrDepth, optVFlags | SDL_RESIZABLE); + if (*screen == NULL) + { + dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); + return FALSE; + } + +#if 0 + SDL_Rect r; + r.x = -50; + r.y = 50; + r.w = 700; + r.h = 300; + DM_PrintRect(stderr, &r); + SDL_SetClipRect(*screen, &r); + DM_PrintRect(stderr, &r); + DM_PrintRect(stderr, &((*screen)->clip_rect)); +#endif + + return TRUE; +} + +void DM_Random(SDL_Surface *screen, int q) +{ + Uint8 *pix = screen->pixels; + int xc, yc; + + for (yc = 0; yc < screen->h; yc++) + { + Uint8 *dp = pix; + + for (xc = 0; xc < screen->w; xc++) + *dp++ = yc + (xc ^ q) + (yc & q); + + pix += screen->pitch; + } +} + +#define QWIDTH 256 +#define QHEIGHT 160 + +typedef Uint8 DMBlockMap[QHEIGHT][QWIDTH]; + + +static DMFloat dmClip(DMFloat a) +{ + return (a < 0.0f ? 0.0f : (a > 1.0f ? 1.0f : a)); +} + + +void dmMakeBumpMap(DMBlockMap map, DMFloat q, DMFloat m) +{ + int x, y; + for (y = 0; y < QHEIGHT; y++) + for (x = 0; x < QWIDTH; x++) + { + DMFloat f = 0.40f + dmPerlinNoise2D(x, y, 1.1f, q, 2); + map[y][x] = (int) (dmClip(f) * m); + } +} + + +void dmShadowTraceHeightMap(DMBlockMap lightMap, DMBlockMap pheightMap, DMVector *light) +{ + int i, j; + + for (j = 0; j < QHEIGHT; j++) + for (i = 0; i < QWIDTH; i++) + { + DMVector vr, vl, va; + DMFloat vrayLen, vfactor; + int vlen; + BOOL wasHit; + + // Perform shadow occlusion via simplistic raytracing + vr.x = i; + vr.y = j; + vr.z = light->z; // - 10.0; +// vr.z = pheightMap[j][i]; + + // Calculate light vector vector + dm_vector_sub_r(&vl, &vr, light); + vrayLen = dm_vector_length(&vl); + +#if 1 + dm_vector_copy(&va, &vl); + dm_vector_normalize(&va); + dm_vector_scale(&va, 0.6f); + dm_vector_copy(&vr, light); + + vlen = 0; + wasHit = FALSE; + do + { + float h; + + // If ray is inside the heightmap, get value + if (vr.x >= 0 && vr.y >= 0 && vr.x < QWIDTH && vr.y < QHEIGHT) + h = pheightMap[(int) vr.y][(int) vr.x]; + else + break; + + // Check for hits + if (h > vr.z) + wasHit = TRUE; + else + { + // Move forwards + dm_vector_add(&vr, &va); + vlen++; + } + } + while (!wasHit && vlen <= vrayLen); + + // Check if the ray hit something, e.g. is this point occluded? + if (wasHit && vlen < vrayLen) + { + vfactor = vlen * 0.01; + } + else + vfactor = vlen * 0.02; +#endif + +#if 1 + { + /* Calculate light's intensity based on the angle it "hits" + * + * 1) Calculate the vectors that form the imaginary "plane" + * 2) Cross-product -> normal vector of the plane + * 2) Normalize the normal vector + * 3) Calculate light vector's hit angle by dot product + */ + DMVector v1, v2; + DMFloat c; + + v1.x = 2.0f; + v1.y = 0.0f; + v1.z = (DMFloat) (pheightMap[j][i] - pheightMap[j][i + 1]); + + v2.x = 0.0f; + v2.y = 2.0f; + v2.z = (DMFloat) (pheightMap[j][i] - pheightMap[j + 1][i]); + + dm_vector_cross(&vr, &v1, &v2); + dm_vector_normalize(&vr); + dm_vector_normalize(&vl); + c = dm_vector_dot(&vl, &vr); + + vrayLen = 255 - (vrayLen * 0.1) * vrayLen + (c * 128.0f) + (vfactor * vfactor * 1255); + } +#else + vrayLen = 255 - vrayLen * vrayLen * (vfactor * vfactor); + if (vrayLen < 0) vrayLen = 0; + vrayLen += pheightMap[j][i]; +#endif + + // Clip result + if (vrayLen < 0) + vrayLen = 0; + else if (vrayLen > 255.0f) + vrayLen = 255.0f; + + lightMap[j][i] = vrayLen; + } +} + + +int main(int argc, char *argv[]) +{ + SDL_Surface *screen = NULL, *bmap = NULL; + TTF_Font *font = NULL; + SDL_Color fontcol={255,155,155,0}; + SDL_Event event; + int mouseX, mouseY; + BOOL initSDL = FALSE, initTTF = FALSE, exitFlag, showMap = FALSE; + + dmInitProg("blittest", "dmlib blittest", "0.2", NULL, NULL); + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, NULL, FALSE)) + exit(1); + + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) + { + dmError("Could not initialize SDL: %s\n", SDL_GetError()); + goto error_exit; + } + initSDL = TRUE; + + + if (TTF_Init() < 0) + { + dmError("Could not initialize FreeType/TTF: %s\n", SDL_GetError()); + goto error_exit; + } + initTTF = TRUE; + + font = TTF_OpenFont(optFontFile, optFontSize); + if (font == NULL) + { + dmError("Could not load TTF font '%s' (%d): %s\n", + optFontFile, optFontSize, SDL_GetError()); + goto error_exit; + } + TTF_SetFontStyle(font, TTF_STYLE_NORMAL); + + if (optBenchmark) + { + screen = SDL_CreateRGBSurface(SDL_SWSURFACE, optScrWidth, optScrHeight, optScrDepth, 0, 0, 0, 0); + if (screen == NULL) + { + dmError("Could not create screen surface.\n"); + goto error_exit; + } + + dmMsg(0, "Benchmark mode, not opening window.\n"); + } + else + { + if (!DM_InitializeVideo(&screen)) + goto error_exit; + + SDL_WM_SetCaption("Halleluja", "DMT"); + } + + dmPerlinInit(); + + bmap = SDL_CreateRGBSurface(SDL_SWSURFACE, QWIDTH, QHEIGHT, 8, 0, 0, 0, 0); + DM_MakePalette(bmap); + DM_Random(bmap, 15); + + DMVector light; + DMBlockMap heightMap; + light.x = light.y = 128; + light.z = 128; + dmMakeBumpMap(heightMap, 0.06, 254); + + + + int numFrames = 0, startTime = SDL_GetTicks(), endTime = 0; + exitFlag = FALSE; + + if (optBenchmark) + dmMsg(0, "Starting benchmark, running for %d seconds.\n", optBenchmarkLen); + + while (!exitFlag) + { + dmMakeBumpMap(heightMap, 0.05 + sin(SDL_GetTicks() * 0.001) * 0.002 , 254); + if (!optBenchmark) + { + while (SDL_PollEvent(&event)) + switch (event.type) + { + case SDL_KEYDOWN: + switch (event.key.keysym.sym) + { + case SDLK_ESCAPE: exitFlag = TRUE; break; + + case SDLK_F5: + showMap = !showMap; + break; + + default: + break; + } + + break; + + case SDL_VIDEORESIZE: + optScrWidth = event.resize.w; + optScrHeight = event.resize.h; + + if (!DM_InitializeVideo(&screen)) + goto error_exit; + + break; + + case SDL_VIDEOEXPOSE: + break; + + case SDL_QUIT: + exit(0); + } + + SDL_GetMouseState(&mouseX, &mouseY); + light.x = ((DMFloat) mouseX * QWIDTH) / (DMFloat) optScrWidth; + light.y = ((DMFloat) mouseY * QHEIGHT) / (DMFloat) optScrHeight; + } + + if (!optBenchmark && SDL_MUSTLOCK(screen) != 0 && SDL_LockSurface(screen) != 0) + { + dmError("Can't lock surface.\n"); + goto error_exit; + } + + + if (showMap) + memcpy(bmap->pixels, heightMap, QWIDTH * QHEIGHT); + else + dmShadowTraceHeightMap(bmap->pixels, heightMap, &light); + + dmScaledBlitSurfaceAny(bmap, 0, 0, screen->w, screen->h, screen, DMD_NONE); + + if (!optBenchmark) + { + dmDrawTTFText(screen, font, fontcol, 0, 0, "%3.1f FPS", + (float) (numFrames * 1000.0f) / (float) (endTime - startTime)); + + if (SDL_MUSTLOCK(screen) != 0) + SDL_UnlockSurface(screen); + + SDL_Flip(screen); + SDL_Delay(10); + } + + endTime = SDL_GetTicks(); + numFrames++; + + if (optBenchmark) + { + if (endTime - startTime > optBenchmarkLen * 1000) + exitFlag = TRUE; + } + } + + // Print benchmark results + dmMsg(0, "%d frames in %d ms, fps = %1.3f\n", + numFrames, endTime - startTime, + (float) (numFrames * 1000.0f) / (float) (endTime - startTime)); + + +error_exit: + dmMsg(0, "Shutting down dmlib.\n"); + if (screen) + SDL_FreeSurface(screen); + + if (font) + TTF_CloseFont(font); + + if (initSDL) + SDL_Quit(); + + if (initTTF) + TTF_Quit(); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/efu.c Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,478 @@ +#include "dmlib.h" +#include "dmargs.h" +#include "dmvecmat.h" +#include "dmimage.h" +#include "dmtext.h" +#include <math.h> + +#define DM_COLORS (256) + +char *optFontFile = "font.ttf", + *optBitmapFilename = "tnsp.png"; +BOOL optBenchmark = FALSE; +int optVFlags = SDL_SWSURFACE | SDL_HWPALETTE; +int optScrWidth = 640, optScrHeight = 480, optFontSize = 20, optScrDepth = 32; +int optBenchmarkLen = 20; + +DMOptArg optList[] = { + { 0, '?', "help", "Show this help", OPT_NONE }, + { 2, 'v', "verbose", "Be more verbose", OPT_NONE }, + { 3, 'f', "full", "Fullscreen", OPT_NONE }, + { 4, 'h', "hw", "Use SDL hardware surface", OPT_NONE }, + { 5, 's', "size", "Initial window size/resolution -s 640x480", OPT_ARGREQ }, + { 6, 'd', "depth", "Color depth of mode/window in bits (8/15/16/32)", OPT_ARGREQ }, + { 7, 'b', "bench", "Run in benchmark mode", OPT_NONE }, +}; + +const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + dmArgsPrintHelp(stdout, optList, optListN); +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + switch (optN) { + case 0: + argShowHelp(); + exit(0); + break; + + case 2: + dmVerbosity++; + break; + + case 3: + optVFlags |= SDL_FULLSCREEN; + break; + + case 6: + if (optArg) + optScrDepth = atoi(optArg); + break; + + case 5: + { + int w, h; + if (sscanf(optArg, "%dx%d", &w, &h) == 2) + { + if (w < 320 || h < 200 || w > 3200 || h > 3200) + { + dmError("Invalid width or height: %d x %d\n", w, h); + return FALSE; + } + optScrWidth = w; + optScrHeight = h; + } + else + { + dmError("Invalid size argument '%s'.\n", optArg); + return FALSE; + } + } + break; + + case 7: + optBenchmark = TRUE; + break; + + default: + dmError("Unknown option '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +void DM_MakePalette(SDL_Surface *scr) +{ + SDL_Color pal[DM_COLORS]; + int n; + + for (n = 0; n < 256; n++) + { + pal[n].r = n; + pal[n].g = n; + pal[n].b = n; + } + + SDL_SetColors(scr, pal, 0, DM_COLORS); +} + + +void DM_PrintRect(FILE *f, SDL_Rect *r) +{ + fprintf(f, "SDL_Rect <%d, %d : %d, %d>\n", + r->x, r->y, r->w, r->h); +} + +BOOL DM_InitializeVideo(SDL_Surface **screen) +{ + *screen = SDL_SetVideoMode(optScrWidth, optScrHeight, optScrDepth, optVFlags | SDL_RESIZABLE); + if (*screen == NULL) + { + dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); + return FALSE; + } + +#if 0 + SDL_Rect r; + r.x = -50; + r.y = 50; + r.w = 700; + r.h = 300; + DM_PrintRect(stderr, &r); + SDL_SetClipRect(*screen, &r); + DM_PrintRect(stderr, &r); + DM_PrintRect(stderr, &((*screen)->clip_rect)); +#endif + + return TRUE; +} + +void DM_Random(SDL_Surface *screen, int q) +{ + Uint8 *pix = screen->pixels; + int xc, yc; + + for (yc = 0; yc < screen->h; yc++) + { + Uint8 *dp = pix; + + for (xc = 0; xc < screen->w; xc++) + *dp++ = yc + (xc ^ q) + (yc & q); + + pix += screen->pitch; + } +} + + +#define QWIDTH 256 +#define QHEIGHT 160 + +typedef Uint8 DMBlockMap[QHEIGHT][QWIDTH]; + + +void dmMakeBumpMap(DMBlockMap map, DMFloat q, DMFloat m) +{ + int x, y; + for (y = 0; y < QHEIGHT; y++) + for (x = 0; x < QWIDTH; x++) + { + DMFloat f = 0.40f + dmPerlinNoise2D(x, y, 1.1f, q, 2); + map[y][x] = (int) (dmClamp10(f) * m); + } +} + + +void dmShadowTraceHeightMap(DMBlockMap lightMap, DMBlockMap pheightMap, DMVector *light) +{ + int i, j; + + light->z = 150; + + for (j = 0; j < QHEIGHT; j++) + for (i = 0; i < QWIDTH; i++) + { + DMVector vr, vl, va; + DMFloat vrayLen, vfactor; + int vlen; + BOOL wasHit; + + // Perform shadow occlusion via simplistic raytracing + vr.x = i; + vr.y = j; + vr.z = 200; //light->z; // - 10.0; + + // Calculate light vector vector + dm_vector_sub_r(&vl, &vr, light); + vrayLen = dm_vector_length(&vl); + +#if 1 + dm_vector_copy(&va, &vl); + dm_vector_normalize(&va); + dm_vector_copy(&vr, light); + + vlen = 0; + wasHit = FALSE; + do + { + float h; + + // If ray is inside the heightmap, get value + if (vr.x >= 0 && vr.y >= 0 && vr.x < QWIDTH && vr.y < QHEIGHT) + h = pheightMap[(int) vr.y][(int) vr.x]; + else + break; + + // Check for hits + if (h > vr.z) + wasHit = TRUE; + else + { + // Move forwards + dm_vector_add(&vr, &va); + vlen++; + } + } + while (!wasHit && vlen <= vrayLen); + + // Check if the ray hit something, e.g. is this point occluded? + if (wasHit && vlen < vrayLen) + { + vfactor = vlen * 0.05; + } + else + vfactor = vlen * 0.001; +#endif + +#if 0 + { + /* Calculate light's intensity based on the angle it "hits" + * + * 1) Calculate the vectors that form the imaginary "plane" + * 2) Cross-product -> normal vector of the plane + * 2) Normalize the normal vector + * 3) Calculate light vector's hit angle by dot product + */ + DMVector v1, v2; + DMFloat c; + + v1.x = 2.0f; + v1.y = 0.0f; + v1.z = (DMFloat) (pheightMap[j][i] - pheightMap[j][i + 1]); + + v2.x = 0.0f; + v2.y = 2.0f; + v2.z = (DMFloat) (pheightMap[j][i] - pheightMap[j + 1][i]); + + dm_vector_cross(&vr, &v1, &v2); + dm_vector_normalize(&vr); + dm_vector_normalize(&vl); + c = dm_vector_dot(&vl, &vr); + + vrayLen = 255 - (vrayLen * 0.1) * vrayLen + (c * 128.0f) + (vfactor * vfactor * 1255); + } +#else + vrayLen = 255 - vrayLen * vrayLen * (vfactor * vfactor); + if (vrayLen < 0) vrayLen = 0; + vrayLen -= pheightMap[j][i]; +#endif + + // Clip result + if (vrayLen < 0) + vrayLen = 0; + else if (vrayLen > 255.0f) + vrayLen = 255.0f; + + lightMap[j][i] = vrayLen; + } +} + + +int main(int argc, char *argv[]) +{ + SDL_Surface *screen = NULL, *bmap = NULL, *logo = NULL; + TTF_Font *font = NULL; + SDL_Color fontcol={255,155,155,0}; + SDL_Event event; + int mouseX, mouseY; + BOOL initSDL = FALSE, initTTF = FALSE, exitFlag, showMap = FALSE; + + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, NULL, FALSE)) + exit(1); + + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) + { + dmError("Could not initialize SDL: %s\n", SDL_GetError()); + goto error_exit; + } + initSDL = TRUE; + + + if (TTF_Init() < 0) + { + dmError("Could not initialize FreeType/TTF: %s\n", SDL_GetError()); + goto error_exit; + } + initTTF = TRUE; + + font = TTF_OpenFont(optFontFile, optFontSize); + if (font == NULL) + { + dmError("Could not load TTF font '%s' (%d): %s\n", + optFontFile, optFontSize, SDL_GetError()); + goto error_exit; + } + TTF_SetFontStyle(font, TTF_STYLE_NORMAL); + + + DMResource *res = dmf_create_stdio(optBitmapFilename, "rb"); + if (res == NULL) + { + dmError("Could not open resource file '%s'.\n", optBitmapFilename); + goto error_exit; + } + logo = dmLoadImage(res); + dmf_close(res); + if (logo == NULL) + { + dmError("Could not load image file '%s'.\n", optBitmapFilename); + goto error_exit; + } + + + if (optBenchmark) + { + screen = SDL_CreateRGBSurface(SDL_SWSURFACE, optScrWidth, optScrHeight, optScrDepth, 0, 0, 0, 0); + if (screen == NULL) + { + dmError("Could not create screen surface.\n"); + goto error_exit; + } + + dmMsg(0, "Benchmark mode, not opening window.\n"); + } + else + { + if (!DM_InitializeVideo(&screen)) + goto error_exit; + + SDL_WM_SetCaption("Halleluja", "DMT"); + } + + dmPerlinInit(); + + bmap = SDL_CreateRGBSurface(SDL_SWSURFACE, QWIDTH, QHEIGHT, 8, 0, 0, 0, 0); + DM_MakePalette(bmap); + DM_Random(bmap, 15); + + DMVector light; + DMBlockMap heightMap; + light.x = light.y = 128; + light.z = 128; + dmMakeBumpMap(heightMap, 0.06, 254); + + + + int numFrames = 0, startTime = SDL_GetTicks(), endTime = 0; + exitFlag = FALSE; + + if (optBenchmark) + dmMsg(0, "Starting benchmark, running for %d seconds.\n", optBenchmarkLen); + + while (!exitFlag) + { + if (!optBenchmark) + { + while (SDL_PollEvent(&event)) + switch (event.type) + { + case SDL_KEYDOWN: + switch (event.key.keysym.sym) + { + case SDLK_ESCAPE: exitFlag = TRUE; break; + + case SDLK_F1: + DM_Random(bmap, (SDL_GetTicks() / 10) % 1000); + break; + + case SDLK_F5: + showMap = !showMap; + break; + + default: + break; + } + + break; + + case SDL_VIDEORESIZE: + optScrWidth = event.resize.w; + optScrHeight = event.resize.h; + + if (!DM_InitializeVideo(&screen)) + goto error_exit; + + break; + + case SDL_VIDEOEXPOSE: + break; + + case SDL_QUIT: + exit(0); + } + + SDL_GetMouseState(&mouseX, &mouseY); + light.x = ((DMFloat) mouseX * QWIDTH) / (DMFloat) optScrWidth; + light.y = ((DMFloat) mouseY * QHEIGHT) / (DMFloat) optScrHeight; + } + + if (!optBenchmark && SDL_MUSTLOCK(screen) != 0 && SDL_LockSurface(screen) != 0) + { + dmError("Can't lock surface.\n"); + goto error_exit; + } + + + if (showMap) + memcpy(bmap->pixels, heightMap, QWIDTH * QHEIGHT); + else + dmShadowTraceHeightMap(bmap->pixels, logo->pixels, &light); + + dmScaledBlitSurfaceAny(bmap, 0, 0, screen->w, screen->h, screen, DMD_NONE); + + + + if (!optBenchmark) + { + dmDrawTTFText(screen, font, fontcol, 0, 0, "%3.1f FPS", + (float) (numFrames * 1000.0f) / (float) (endTime - startTime)); + + if (SDL_MUSTLOCK(screen) != 0) + SDL_UnlockSurface(screen); + + SDL_Flip(screen); + SDL_Delay(20); + } + + endTime = SDL_GetTicks(); + numFrames++; + + if (optBenchmark) + { + if (endTime - startTime > optBenchmarkLen * 1000) + exitFlag = TRUE; + } + } + + // Print benchmark results + dmMsg(0, "%d frames in %d ms, fps = %1.3f\n", + numFrames, endTime - startTime, + (float) (numFrames * 1000.0f) / (float) (endTime - startTime)); + + +error_exit: + dmMsg(0, "Shutting down dmlib.\n"); + if (screen) + SDL_FreeSurface(screen); + + if (logo) + SDL_FreeSurface(logo); + + if (font) + TTF_CloseFont(font); + + if (initSDL) + SDL_Quit(); + + if (initTTF) + TTF_Quit(); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/testpl.c Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,267 @@ +#include "jss.h" +#include "jssmod.h" +#include "jssmix.h" +#include "jssplr.h" +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <SDL.h> + + +static const char patNoteTable[12][3] = +{ + "C-", "C#", "D-", + "D#", "E-", "F-", + "F#", "G-", "G#", + "A-", "A#", "B-" +}; + + +#define jmpNMODEffectTable (36) +static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + +void printRow(FILE * f, JSSPattern * p, int row) +{ + int j, k; + char c; + JSSNote *n; + + if (!p) + return; + + n = &(p->data[p->nchannels * row]); + + fprintf(f, "%.2x: ", row); + + k = p->nchannels < 5 ? p->nchannels : 5; + + for (j = 0; j < k; j++) + { + switch (n->note) + { + case jsetNotSet: + fprintf(f, "... "); + break; + case jsetNoteOff: + fprintf(f, "=== "); + break; + default: + fprintf(f, "%s%i ", patNoteTable[n->note % 12], n->note / 12); + break; + } + + if (n->instrument != jsetNotSet) + fprintf(f, "%.2x ", n->instrument + 1); + else + fprintf(f, ".. "); + + if (n->volume == jsetNotSet) + fprintf(f, ".. "); + else if (n->volume >= 0x00 && n->volume <= 0x40) + fprintf(f, "%.2x ", n->volume); + else + { + switch (n->volume & 0xf0) + { + case 0x50: c = '-'; break; + case 0x60: c = '+'; break; + case 0x70: c = '/'; break; + case 0x80: c = '\\'; break; + case 0x90: c = 'S'; break; + case 0xa0: c = 'V'; break; + case 0xb0: c = 'P'; break; + case 0xc0: c = '<'; break; + case 0xd0: c = '>'; break; + case 0xe0: c = 'M'; break; + default: c = '?'; break; + } + fprintf(f, "%c%x ", c, (n->volume & 0x0f)); + } + + if (n->effect >= 0 && n->effect < jmpNMODEffectTable) + fprintf(f, "%c", jmpMODEffectTable[n->effect]); + else if (n->effect == jsetNotSet) + fprintf(f, "."); + else + fprintf(f, "?"); + + if (n->param != jsetNotSet) + fprintf(f, "%.2x|", n->param); + else + fprintf(f, "..|"); + + n++; + } +} + + +void audioCallback(void *userdata, Uint8 *stream, int len) +{ + JSSMixer *d = (JSSMixer *) userdata; + + if (d != NULL) + { + jvmRenderAudio(d, stream, len / jvmGetSampleSize(d)); + } +} + + +int main(int argc, char *argv[]) +{ + SDL_AudioSpec afmt; + DMResource *file = NULL; + char *sname = NULL; + int result = -1; + JSSModule *mod = NULL; + JSSMixer *dev = NULL; + JSSPlayer *plr = NULL; + + if (argc > 1) + sname = argv[1]; + + // Open the files + if (sname == NULL) + file = dmf_create_stdio_stream(stdin); + else if ((file = dmf_create_stdio(sname, "rb")) == NULL) + { + fprintf(stderr, "Error opening input file '%s'. (%s)\n", + sname, strerror(errno)); + return 1; + } + + // Initialize miniJSS + fprintf(stderr, "Initializing miniJSS\n"); + jssInit(); + + + // Read module file + fprintf(stderr, "Reading file: %s\n", sname); +#ifdef JSS_SUP_XM + fprintf(stderr, "* Trying XM...\n"); + result = jssLoadXM(file, &mod); +#endif +#ifdef JSS_SUP_JSSMOD + if (result != 0) + { + size_t bufgot, bufsize = dmfsize(file); + Uint8 *buf = dmMalloc(bufsize); + dmfseek(file, 0L, SEEK_SET); + fprintf(stderr, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf); + if ((bufgot = dmfread(buf, 1, bufsize, file)) != bufsize) + { + fprintf(stderr, "Error reading file (not enough data %d), #%d: %s\n", + bufgot, dmferror(file), dmErrorStr(dmferror(file))); + return 2; + } + result = jssLoadJSSMOD(buf, bufsize, &mod); + dmFree(buf); + } +#endif + dmf_close(file); + + if (result != DMERR_OK) + { + fprintf(stderr, "Error loading module file, %d: %s\n", + result, dmErrorStr(result)); + return 3; + } + + // Try to convert it + if ((result = jssConvertModuleForPlaying(mod)) != DMERR_OK) + { + fprintf(stderr, "Could not convert module for playing, %d: %s\n", + result, dmErrorStr(result)); + return 3; + } + + // Initialize SDL audio + afmt.freq = 48000; + afmt.format = AUDIO_S16SYS; + afmt.channels = 2; + + // Initialize mixing device + fprintf(stderr, "Initializing miniJSS mixer with: %d, %d, %d\n", + JSS_AUDIO_S16, afmt.channels, afmt.freq); + + dev = jvmInit(JSS_AUDIO_S16, afmt.channels, afmt.freq, JMIX_AUTO); + if (dev == NULL) + { + fprintf(stderr, "jvmInit() returned NULL\n"); + return 3; + } + + afmt.samples = afmt.freq / 4; + afmt.callback = audioCallback; + afmt.userdata = (void *) dev; + + // Open the audio device + fprintf(stderr, "Trying to init SDL with: %d, %d, %d\n", + afmt.format, afmt.channels, afmt.freq); + + if (SDL_OpenAudio(&afmt, NULL) < 0) + { + fprintf(stderr, "Couldn't open audio: %s\n", SDL_GetError()); + return 4; + } + + // Initialize player + if ((plr = jmpInit(dev)) == NULL) + { + fprintf(stderr, "jmpInit() returned NULL\n"); + return 4; + } + + // Initialize playing + jvmSetCallback(dev, jmpExec, plr); + jmpSetModule(plr, mod); + jmpPlayOrder(plr, 0); + jvmSetGlobalVol(dev, 60); + + // okay, main loop here ... "play" module and print out info + printf("----------------------------------------------------\n"); + SDL_LockAudio(); + SDL_PauseAudio(0); + SDL_UnlockAudio(); + BOOL playing = TRUE; + while (playing) + { + JSSPattern *pattern; + int currRow, prevRow; + + JSS_LOCK(plr); + currRow = prevRow = plr->row; + JSS_UNLOCK(plr); + + while (currRow == prevRow && playing) + { + JSS_LOCK(plr); + currRow = plr->row; + playing = plr->isPlaying; + pattern = plr->pattern; + JSS_UNLOCK(plr); + SDL_Delay(50); + } + + if (playing) + { + printRow(stdout, pattern, currRow); + printf("\n"); + } + } + + printf("----------------------------------------------------\n"); + + SDL_LockAudio(); + SDL_PauseAudio(1); + jmpClose(plr); + jvmClose(dev); + jssFreeModule(mod); + SDL_UnlockAudio(); + + SDL_Quit(); + + jssClose(); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/vecmattest.c Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,85 @@ +#include "dmlib.h" +#include "dmvecmat.h" +#include "dmmutex.h" + +void printTest(const char *test, int expected, int result) +{ + fprintf(stderr, "Test '%s': %s\n", test, + expected == result ? "OK" : "FAILED!"); +} + +#define tst(X, R) printTest(# X, (X), (R)) + + +void dm_vector_fprintf(FILE *f, const char *name, DMVector *v) +{ + if (name != NULL) + fprintf(f, "%s=", name); + + fprintf(f, "[<%1.3f, %1.3f, %1.3f>=%1.3f]", v->x, v->y, v->z, dm_vector_length(v)); + + if (name != NULL) + fprintf(f, "\n"); +} + + +void dm_vector_printf(const char *name, DMVector *v) +{ + dm_vector_fprintf(stdout, name, v); +} + + +void dm_matrix_fprintf(FILE *f, const char *name, DMMatrix *mat) +{ + int i, j, k, pad = 0; + char *tmp = NULL; + + if (name != NULL) + { + tmp = dm_strdup_printf("%s=", name); + pad = strlen(tmp); + } + + for (i = 0; i < DM_MATRIX_SIZE; i++) + { + if (i == 1) + fputs(tmp, f); + else + for (k = 0; k < pad; k++) + fputc(' ', f); + + fprintf(f, "["); + for (j = 0; j < DM_MATRIX_SIZE; j++) + fprintf(f, "% 8.3f%s", mat->m[i][j], j < DM_MATRIX_SIZE - 1 ? " " : ""); + + fprintf(f, "]\n"); + } +} + + +void dm_matrix_printf(const char *name, DMMatrix *mat) +{ + dm_matrix_fprintf(stdout, name, mat); +} + + +int main(int argc, char *argv[]) +{ + DMVector a = { -5, 1, 17, 0 }, b = { 1, 2, 0.5, 0 }; + DMMatrix m; + + (void) argc; + (void) argv; + + dm_vector_printf("a", &a); + dm_vector_printf("b", &a); + + dm_matrix_rot_a(&m, 0.5, 0.9, 0.1); + dm_matrix_printf("m", &m); + + dm_vector_mul_by_mat(&b, &a, &m); + + dm_vector_printf("nb", &b); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/tests/vptest.c Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,394 @@ +#include "dmlib.h" +#include "dmargs.h" +#include "dmres.h" +#include "dmimage.h" +#include "dmtext.h" +#include "dmq3d.h" +#include "dmvecmat.h" +#include <math.h> + +#define DM_COLORS (256) + +char *optFontFile = "font.ttf", + *optBitmapFilename = "blurri.png"; +BOOL optBenchmark = FALSE; +int optVFlags = SDL_SWSURFACE | SDL_HWPALETTE; +int optScrWidth = 640, optScrHeight = 480, optFontSize = 8, optScrDepth = 32; +int optBenchmarkLen = 20; + +DMOptArg optList[] = { + { 0, '?', "help", "Show this help", OPT_NONE }, + { 2, 'v', "verbose", "Be more verbose", OPT_NONE }, + { 3, 'f', "full", "Fullscreen", OPT_NONE }, + { 4, 'h', "hw", "Use SDL hardware surface", OPT_NONE }, + { 5, 's', "size", "Initial window size/resolution -s 640x480", OPT_ARGREQ }, + { 6, 'd', "depth", "Color depth of mode/window in bits (8/15/16/32)", OPT_ARGREQ }, + { 7, 'b', "bench", "Run in benchmark mode", OPT_NONE }, +}; + +const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + dmArgsPrintHelp(stdout, optList, optListN); +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + switch (optN) { + case 0: + argShowHelp(); + exit(0); + break; + + case 2: + dmVerbosity++; + break; + + case 3: + optVFlags |= SDL_FULLSCREEN; + break; + + case 6: + if (optArg) + optScrDepth = atoi(optArg); + break; + + case 5: + { + int w, h; + if (sscanf(optArg, "%dx%d", &w, &h) == 2) + { + if (w < 320 || h < 200 || w > 3200 || h > 3200) + { + dmError("Invalid width or height: %d x %d\n", w, h); + return FALSE; + } + optScrWidth = w; + optScrHeight = h; + } + else + { + dmError("Invalid size argument '%s'.\n", optArg); + return FALSE; + } + } + break; + + case 7: + optBenchmark = TRUE; + break; + + default: + dmError("Unknown option '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +void DM_PrintRect(FILE *f, SDL_Rect *r) +{ + fprintf(f, "SDL_Rect <%d, %d : %d, %d>\n", + r->x, r->y, r->w, r->h); +} + + +BOOL DM_InitializeVideo(SDL_Surface **screen) +{ + *screen = SDL_SetVideoMode(optScrWidth, optScrHeight, optScrDepth, optVFlags | SDL_RESIZABLE); + if (*screen == NULL) + { + dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); + return FALSE; + } + return TRUE; +} + + +int main(int argc, char *argv[]) +{ + SDL_Surface *screen = NULL, *bmap = NULL, *fbmap = NULL, *screen2 = NULL; + SDL_Color fontcol = { 255, 155, 155, 0 }; + SDL_Event event; + TTF_Font *font = NULL; + int mouseX, mouseY, bx, by, err; + BOOL initSDL = FALSE, initTTF = FALSE, exitFlag; + DM3DVectorSpriteModel *model, *model2; + + dmVerbosity = 5; + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, NULL, FALSE)) + exit(1); + + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) + { + dmError("Could not initialize SDL: %s\n", SDL_GetError()); + goto error_exit; + } + initSDL = TRUE; + + + if (TTF_Init() < 0) + { + dmError("Could not initialize FreeType/TTF: %s\n", SDL_GetError()); + goto error_exit; + } + initTTF = TRUE; + + font = TTF_OpenFont(optFontFile, optFontSize); + if (font == NULL) + { + dmError("Could not load TTF font '%s' (%d): %s\n", + optFontFile, optFontSize, SDL_GetError()); + goto error_exit; + } + TTF_SetFontStyle(font, TTF_STYLE_NORMAL); + + DMResource *res = dmf_create_stdio(optBitmapFilename, "rb"); + if (res == NULL) + { + dmError("Could not open resource file '%s'.\n", optBitmapFilename); + goto error_exit; + } + bmap = dmLoadImage(res); + dmf_close(res); + if (bmap == NULL) + { + dmError("Could not load image file '%s'.\n", optBitmapFilename); + goto error_exit; + } + + res = dmf_create_stdio("trans6x6.png", "rb"); + if (res == NULL) + { + dmError("Could not open resource file '%s'.\n", optBitmapFilename); + goto error_exit; + } + fbmap = dmLoadImage(res); + dmf_close(res); + if (fbmap == NULL) + { + dmError("Could not load image file '%s'.\n", optBitmapFilename); + goto error_exit; + } + + + res = dmf_create_stdio("mole.3d", "r"); + if (res == NULL) + { + dmError("Could not open resource file '%s'.\n", optBitmapFilename); + goto error_exit; + } + err = dmRead3DVectorSpriteModel(res, &model); + dmf_close(res); + dmMsg(0, "Loaded, %d: %s\n", err, dmErrorStr(err)); + + res = dmf_create_stdio("roto.3d", "r"); + if (res == NULL) + { + dmError("Could not open resource file '%s'.\n", optBitmapFilename); + goto error_exit; + } + err = dmRead3DVectorSpriteModel(res, &model2); + dmf_close(res); + dmMsg(0, "Loaded, %d: %s\n", err, dmErrorStr(err)); + + if (optBenchmark) + { + screen = SDL_CreateRGBSurface(SDL_SWSURFACE, optScrWidth, optScrHeight, optScrDepth, 0, 0, 0, 0); + if (screen == NULL) + { + dmError("Could not create screen surface.\n"); + goto error_exit; + } + + dmMsg(0, "Benchmark mode, not opening window.\n"); + } + else + { + if (!DM_InitializeVideo(&screen)) + goto error_exit; + + SDL_WM_SetCaption("Halleluja", "DMT"); + } + + screen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, optScrWidth, optScrHeight, optScrDepth, 0, 0, 0, 0); + Uint32 lcol = dmMapRGB(screen, 255,255,255); + + int numFrames = 0, startTime = SDL_GetTicks(), endTime = 0; + exitFlag = FALSE; + + if (optBenchmark) + dmMsg(0, "Starting benchmark, running for %d seconds.\n", optBenchmarkLen); + + while (!exitFlag) + { + if (!optBenchmark) + { + while (SDL_PollEvent(&event)) + switch (event.type) + { + case SDL_KEYDOWN: + switch (event.key.keysym.sym) + { + case SDLK_ESCAPE: exitFlag = TRUE; break; + + default: + break; + } + + break; + + case SDL_VIDEORESIZE: + optScrWidth = event.resize.w; + optScrHeight = event.resize.h; + + if (!DM_InitializeVideo(&screen)) + goto error_exit; + + break; + + case SDL_VIDEOEXPOSE: + break; + + case SDL_QUIT: + exit(0); + } + + SDL_GetMouseState(&mouseX, &mouseY); + bx = 300 - ((DMFloat) mouseX * 500.0f ) / (DMFloat) optScrWidth; + by = 300 - ((DMFloat) mouseY * 500.0f ) / (DMFloat) optScrHeight; + } + else + { + bx = 0; + by = 0; + } + + if (!optBenchmark && SDL_MUSTLOCK(screen) != 0 && SDL_LockSurface(screen) != 0) + { + dmError("Can't lock surface.\n"); + goto error_exit; + } + + + dmClearSurface(screen, 0); + + float f = SDL_GetTicks() / 150.0f, + qw2 = (float) 132.0 * (1.0 + sin(f) * 0.1), + qh2 = (float) 132.0 * (1.0 + sin(f) * 0.1); + +#if 1 + dmScaledBlitSurfaceAny(bmap, bx-qw2, by-qh2, bmap->w+qw2, bmap->h+qh2, screen, + DMD_TRANSPARENT +// DMD_SATURATE +// DMD_NONE + ); +#endif +#if 0 + float qw = (float) 32.0 * (1.0 + sin(f) * 0.1), + qh = (float) 32.0 * (1.0 + sin(f) * 0.1), + dmScaledBlitSurface32to32TransparentGA(bmap, bx*2-qw, by*2-qh, bmap->w+qw, bmap->h+qh, screen, + 128 + sin(f*0.1) * 120.0f); +#endif + +#if 1 + DMVector pos; + + DMMatrix mat; +// dm_matrix_rot_a(&mat, f*0.1, 0, (3.1415926535f * 2.0f * ((DMFloat) mouseX + (DMFloat) mouseY) ) / 500.0f); +// dm_matrix_rot_a(&mat, f*0.1, f*0.1, f*0.1); + dm_matrix_rot_a(&mat, 0, 0, f*0.1); + + pos.x = -118; + pos.y = 0; + pos.z = 100; + + dmDraw3DVectorSpriteModel(screen, model2, &pos, &mat, fbmap, lcol); + + pos.x = 118; + pos.y = 0; + pos.z = 100; + + dm_matrix_rot_a(&mat, 0, 0, -f*0.1+0.125); + dmDraw3DVectorSpriteModel(screen, model2, &pos, &mat, fbmap, lcol); + + +#endif + +#if 0 + int np; + dmClearSurface(screen2, 0); + for (np = 1; np <= 5; np++) + { + float n = ((float) np - 0.5f) * np; + dmScaledBlitSurface32to32TransparentGA(screen, -n, -n, screen->w + n*2.0f, screen->h + n*2.0f, screen2, + 210 - np * 10 + ); + dmDirectBlitSurface(screen2, screen); + } + + dmDraw3DVectorSpriteModel(screen, model, &pos, &mat, fbmap, lcol); + + for (np = 1; np <= 5; np++) + { + float n = ((float) np - 0.5f) / 2.0f; + dmScaledBlitSurface32to32TransparentGA(screen, -n, -n, screen->w + n*2.0f, screen->h + n*2.0f, screen2, + 210 - np * 10 + ); + dmDirectBlitSurface(screen2, screen); + } + +#endif + + if (!optBenchmark) + { + dmDrawTTFText(screen, font, fontcol, 0, 0, "%3.1f FPS", + (float) (numFrames * 1000.0f) / (float) (endTime - startTime)); + + if (SDL_MUSTLOCK(screen) != 0) + SDL_UnlockSurface(screen); + + SDL_Flip(screen); + SDL_Delay(25); + } + + endTime = SDL_GetTicks(); + numFrames++; + + if (optBenchmark) + { + if (endTime - startTime > optBenchmarkLen * 1000) + exitFlag = TRUE; + } + } + + // Print benchmark results + dmMsg(0, "%d frames in %d ms, fps = %1.3f\n", + numFrames, endTime - startTime, + (float) (numFrames * 1000.0f) / (float) (endTime - startTime)); + + +error_exit: + dmMsg(0, "Shutting down dmlib.\n"); + if (screen) + SDL_FreeSurface(screen); + + if (bmap) + SDL_FreeSurface(bmap); + + if (font) + TTF_CloseFont(font); + + if (initSDL) + SDL_Quit(); + + if (initTTF) + TTF_Quit(); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/data2inc.c Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,404 @@ +/* + * data2inc - Convert binary data to "C"-source or XA-compatible include file + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2003,2009-2012 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#include <errno.h> +#include "dmlib.h" +#include "dmargs.h" +#include "dmmutex.h" + +#define RA_LINEBUF (16) + +enum +{ + FMT_AUTO = 0, + FMT_C, + FMT_ASM +}; + +char *optInFilename = NULL, + *optOutFilename = NULL, + *optObjName = "default_object", + *optDataType = NULL, + *optAddLine = NULL; + +int optIndentation = -1; +int optFormat = FMT_AUTO; +BOOL optHexMode = FALSE, + optQuiet = FALSE, + optExtraData = FALSE, + optFormatting = TRUE; + + +void (*writeHeader) (FILE *, char *) = NULL; +void (*writeDecl) (FILE *, size_t, char *) = NULL; +void (*writeData) (FILE *, Uint8 *, size_t) = NULL; +void (*writeFooter) (FILE *, size_t, char *) = NULL; + + +static DMOptArg optList[] = +{ + { 0, '?', "help", "Show this help", OPT_NONE }, + { 4, 'A', "format-asm", "Output in XA-compatible asm", OPT_NONE }, + { 5, 'C', "format-c", "Output in ANSI C", OPT_NONE }, + { 1, 'n', "name", "Set object name", OPT_ARGREQ }, + { 2, 't', "type", "Set datatype (unsigned char/byte)", OPT_ARGREQ }, + { 3, 'a', "add-line", "Add this line to start of file", OPT_ARGREQ }, + { 6, 'x', "hexadecimal", "Use hexadecimal output", OPT_NONE }, + { 7, 'q', "quiet", "Do not add comments", OPT_NONE }, + { 8, 'f', "no-formatting", "Disable additional output formatting", OPT_NONE }, + { 9, 'i', "indentation", "Set indentation (negative value = tab)", OPT_ARGREQ }, + { 10, 'e', "extra-data", "Add object end labels and size in asm output", OPT_NONE }, +}; + +static const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + dmPrintBanner(stdout, dmProgName, + "[options] [sourcefile] [destfile]"); + + dmArgsPrintHelp(stdout, optList, optListN); + + printf( + "\n" + "To convert a data file to a C structure using 'Uint8' as type:\n" + "$ data2inc -C -n variable_name -t Uint8 input.bin output.h\n" + "\n" + ); +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + switch (optN) + { + case 0: + argShowHelp(); + exit(0); + break; + + case 1: + optObjName = optArg; + break; + + case 2: + optDataType = optArg; + break; + + case 3: + optAddLine = optArg; + break; + + case 4: + optFormat = FMT_ASM; + break; + case 5: + optFormat = FMT_C; + break; + case 6: + optHexMode = TRUE; + break; + case 7: + optQuiet = TRUE; + break; + case 8: + optFormatting = FALSE; + break; + + case 9: + optIndentation = atoi(optArg); + break; + + case 10: + optExtraData = TRUE; + break; + + default: + dmError("Unknown option '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char * currArg) +{ + if (!optInFilename) + optInFilename = currArg; + else + if (!optOutFilename) + optOutFilename = currArg; + else + dmError("Source and destination filenames already specified, extraneous argument '%s'.\n", currArg); + + return TRUE; +} + + +/* Assembler include data output functions + */ +void writeHeader_ASM(FILE * f, char *name) +{ + if (name) + fprintf(f, "; '%s'", name); + else + fprintf(f, "; Generated"); + fprintf(f, " by %s v%s\n", + dmProgName, dmProgVersion); +} + +void writeDecl_ASM(FILE * f, size_t len, char *name) +{ + if (optExtraData) + fprintf(f, "%s_size = %u\n", name, len); + fprintf(f, "%s:\n", name); +} + +void writeData_ASM(FILE * f, Uint8 * buf, size_t len) +{ + size_t i; + + fprintf(f, "%s ", optDataType); + for (i = 0; i < len; i++) + { + if (optFormatting) + { + if (optHexMode) + fprintf(f, "$%.2x", buf[i]); + else + fprintf(f, "%3d", buf[i]); + } + else + { + if (optHexMode) + fprintf(f, "$%x", buf[i]); + else + fprintf(f, "%d", buf[i]); + } + + if (i < (len - 1)) + fprintf(f, ","); + } +} + +void writeFooter_ASM(FILE * f, size_t len, char *name) +{ + (void) len; + if (optExtraData) + fprintf(f, "%s_end: \n", name); + else + fprintf(f, "\n"); +} + + +/* ANSI-C include data output functions + */ +void writeHeader_C(FILE * f, char *name) +{ + if (name) + fprintf(f, "/* '%s' generated", name); + else + fprintf(f, "/* Generated"); + + fprintf(f, " by %s v%s\n" " */\n", + dmProgName, dmProgVersion); +} + +void writeDecl_C(FILE * f, size_t len, char *name) +{ + fprintf(f, "%s %s[%u] = {\n", + optDataType, name, len); + + printf("extern %s %s[%u];\n", + optDataType, name, len); +} + +void writeData_C(FILE * f, Uint8 * buf, size_t len) +{ + size_t i; + + for (i = 0; i < len; i++) + { + if (optFormatting) + { + if (optHexMode) + fprintf(f, "0x%.2x", buf[i]); + else + fprintf(f, "%3d", buf[i]); + } + else + { + if (optHexMode) + fprintf(f, "0x%x", buf[i]); + else + fprintf(f, "%d", buf[i]); + } + + fprintf(f, ","); + } +} + +void writeFooter_C(FILE * f, size_t len, char *name) +{ + (void) len; + (void) name; + fprintf(f, "};\n"); +} + + +off_t dmGetFileSize(FILE *f) +{ + off_t len, pos = ftell(f); + fseeko(f, 0, SEEK_END); + len = ftell(f); + fseek(f, pos, SEEK_SET); + return len; +} + + +int main(int argc, char *argv[]) +{ + FILE *sfile = NULL, *dfile = NULL; + off_t inSize; + Uint8 inBuf[RA_LINEBUF]; + int tmpRes; + + /* Initialize */ + dmInitProg("data2inc", "Data to include converter", "0.6", NULL, NULL); + dmVerbosity = 0; + + /* Parse arguments */ + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, argHandleFile, TRUE)) + exit(1); + + /* Determine output type, if not specified */ + if (optFormat == FMT_AUTO) + { + char *dext; + + if (optOutFilename == NULL) + { + dmError("Output format not specified and no output filename given (try --help)\n"); + exit(1); + } + + /* Check filename extension */ + dext = strrchr(optOutFilename, '.'); + if (dext) + { + dext++; + if (!strcasecmp(dext, "c") || !strcasecmp(dext, "h") || + !strcasecmp(dext, "cc") || !strcasecmp(dext, "cpp") || + !strcasecmp(dext, "hpp") || !strcasecmp(dext, "c++")) + optFormat = FMT_C; + else + optFormat = FMT_ASM; + } else + optFormat = FMT_ASM; + } + + /* Set functions */ + switch (optFormat) + { + case FMT_ASM: + if (!optDataType) + optDataType = ".byte"; + + writeHeader = writeHeader_ASM; + writeDecl = writeDecl_ASM; + writeData = writeData_ASM; + writeFooter = writeFooter_ASM; + break; + + case FMT_C: + if (!optDataType) + optDataType = "unsigned char"; + + writeHeader = writeHeader_C; + writeDecl = writeDecl_C; + writeData = writeData_C; + writeFooter = writeFooter_C; + break; + + case FMT_AUTO: + default: + dmError("Internal error, FMT_AUTO at output function init.\n"); + exit(2); + } + + /* Open the files */ + if (optInFilename == NULL) + sfile = stdin; + else + if ((sfile = fopen(optInFilename, "rb")) == NULL) + { + tmpRes = errno; + dmError("Error opening input file '%s'. (%s)\n", + optInFilename, strerror(tmpRes)); + exit(3); + } + + if (optOutFilename == NULL) + dfile = stdout; + else + if ((dfile = fopen(optOutFilename, "wa")) == NULL) + { + tmpRes = errno; + dmError("Error creating output file '%s'. (%s)\n", + optOutFilename, strerror(tmpRes)); + exit(4); + } + + /* Get sourcefile size */ + inSize = dmGetFileSize(sfile); + + /* Output header */ + if (!optQuiet) + writeHeader(dfile, optOutFilename); + + if (optAddLine) + fprintf(dfile, "%s\n", optAddLine); + + /* Output declaration */ + writeDecl(dfile, inSize, optObjName); + + /* Output data */ + while (!feof(sfile)) + { + tmpRes = fread(inBuf, sizeof(Uint8), RA_LINEBUF, sfile); + if (tmpRes > 0) + { + if (optIndentation < 0) + fprintf(dfile, "\t"); + else + if (optIndentation > 0) + { + int i; + for (i = 0; i < optIndentation; i++) + fputs(" ", dfile); + } + + writeData(dfile, inBuf, tmpRes); + + fprintf(dfile, "\n"); + } + } + + + /* Output footer */ + writeFooter(dfile, inSize, optObjName); + + /* Exit */ + fclose(sfile); + fclose(dfile); + + exit(0); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/gentab.c Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,264 @@ +#include "dmlib.h" +#include "dmargs.h" +#include <math.h> + +enum +{ + MT_SIN, + MT_COS, + MT_SMOOTH1, + MT_SCURVE, + MT_SMOOTH1_CLAMP, + MT_SCURVE_CLAMP, + MT_SIN_SCURVE, + + MT_LAST +}; + + +typedef struct +{ + char *name; + char *desc; +} DMTransType; + +static DMTransType dmTransTypes[MT_LAST] = +{ + { "sin", "Sine" }, + { "cos", "Cosine" }, + { "smooth1", "Smoothstep1 LERP" }, + { "scurve", "S-curve LERP" }, + { "smooth1-clamp", "Clamped smoothstep1 LERP" }, + { "scurve-clamp", "Clamped S-curve LERP" }, + { "sin-scurve", "Sine S-curve" }, +}; + + +DMFloat + optSOffset = 0.0f, + optSAmplitude = 1.0f, + optSOmega = 1.0f, + optStartValue = 0.0f, + optEndValue = 1.0f; + +int optNSteps = 64, + optPerLine = 16, + optTransType = -1; + +char + *optObjectName = NULL, + *optOutFilename = NULL; + + +static DMOptArg optList[] = +{ + { 0, '?', "help", "Show this help", OPT_NONE }, + { 1, 'v', "verbose", "Increase verbosity", OPT_NONE }, + { 2, 'o', "output", "Set output file (default stdout)", OPT_ARGREQ }, + { 3, 'n', "name", "Set output object name", OPT_ARGREQ }, + + { 4, 's', "steps", "Number of steps/values in output table", OPT_ARGREQ }, + { 5, 't', "type", "Curve/interpolation type (see list)", OPT_ARGREQ }, + + { 6, 'O', "offset", "Output data offset", OPT_ARGREQ }, + { 7, 'A', "amplitude", "Output amplitude scale", OPT_ARGREQ }, + { 8, 'W', "omega", "Omega (w) multiplier", OPT_ARGREQ }, + + { 9, 'S', "start", "Start value (only smooth/scurve)", OPT_ARGREQ }, + { 10, 'E', "end", "End value (only smooth/scurve)", OPT_ARGREQ }, +}; + +static const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + int index; + dmPrintBanner(stdout, dmProgName, "[options]"); + dmArgsPrintHelp(stdout, optList, optListN); + + printf("\nAvailable types:\n"); + for (index = 0; index < MT_LAST; index++) + { + DMTransType *tm = &dmTransTypes[index]; + printf("%-15s | %s\n", tm->name, tm->desc); + } + printf("\n"); +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + switch (optN) + { + case 0: + argShowHelp(); + exit(0); + break; + + case 1: + dmVerbosity++; + break; + + case 2: + optOutFilename = optArg; + break; + + case 3: + optObjectName = optArg; + break; + + case 4: + { + int tmp; + if (sscanf(optArg, "%d", &tmp) != 1) + { + dmError("Invalid number of steps argument '%s'.\n", optArg); + return FALSE; + } + optNSteps = tmp; + } + break; + + case 5: + { + int index; + for (index = 0; index < MT_LAST; index++) + { + DMTransType *tm = &dmTransTypes[index]; + if (strcasecmp(tm->name, optArg) == 0) + { + optTransType = index; + return TRUE; + } + } + dmError("Invalid transformation type option '%s'.\n", + optArg); + return FALSE; + } + break; + + case 6: + case 7: + case 8: + case 9: + case 10: + { + DMFloat tmp; + if (sscanf(optArg, "%f", &tmp) != 1) + { + dmError("Invalid %s option argument '%s', expected a floating point value.\n", + currArg, optArg); + return FALSE; + } + switch (optN) + { + case 6: optSOffset = tmp; break; + case 7: optSAmplitude = tmp; break; + case 8: optSOmega = tmp; break; + case 9: optStartValue = tmp; break; + case 10: optEndValue = tmp; break; + } + } + break; + + default: + dmError("Unknown argument '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +int main(int argc, char *argv[]) +{ + FILE *outFile; + DMLerpContext ctx; + int step, n; + + dmInitProg("gentab", "Sine, etc. table generator", "0.1", NULL, NULL); + dmVerbosity = 1; + + // Parse arguments + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, NULL, TRUE)) + exit(1); + + // Check settings + if (optTransType < 0) + { + dmError("No transformation type set, perhaps try --help\n"); + return -1; + } + + if (optObjectName == NULL) + { + dmError("Object name not specified, try --help\n"); + return -2; + } + + if (optOutFilename == NULL) + outFile = stdout; + else + if ((outFile = fopen(optOutFilename, "w")) == NULL) + { + int err = dmGetErrno(); + dmError("Could not open output file '%s', %d: %s\n", + optOutFilename, err, dmErrorStr(err)); + return -2; + } + + + // Generate table + dmLerpInit(&ctx, optStartValue, optEndValue, optNSteps); + + fprintf(outFile, + "cnt_%s = %d\n" + "vtab_%s: ", + optObjectName, + optNSteps, + optObjectName + ); + + for (n = 0, step = 0; step < optNSteps; step++) + { + DMFloat t = ((DMFloat) step * optSOmega) / (DMFloat) optNSteps, delta, value; + + switch (optTransType) + { + case MT_SIN: delta = sin(t * 2 * DM_PI); break; + case MT_COS: delta = cos(t * 2 * DM_PI); break; + + case MT_SMOOTH1: delta = dmLerp1(&ctx, step); break; + case MT_SCURVE: delta = dmLerpSCurve(&ctx, step); break; + case MT_SMOOTH1_CLAMP: delta = dmLerp1Clamp(&ctx, step); break; + case MT_SCURVE_CLAMP: delta = dmLerpSCurveClamp(&ctx, step); break; + case MT_SIN_SCURVE: delta = dmLerpSCurveClamp(&ctx, step); break; + + default: delta = 0; + } + + value = optSOffset + delta * optSAmplitude; + + // Print the value + if (n == 0) + fprintf(outFile, "\t.byte "); + + fprintf(outFile, "%ld%s", + lrint(value), + (n < optPerLine - 1) ? "," : ""); + + if (++n >= optPerLine) + { + fprintf(outFile, "\n"); + n = 0; + } + } + if (n > 0) + fprintf(outFile, "\n"); + + fprintf(outFile, "\n"); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/gfxconv.c Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,1697 @@ +/* + * gfxconv - Convert various graphics formats + * 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 "dmmutex.h" +#include "libgfx.h" +#include "lib64gfx.h" + +//#define UNFINISHED 1 + +#define DM_MAX_COLORS 256 + +#define ASC_NBITS 8 +#define ASC_NCOLORS 4 +static const char dmASCIIPalette[ASC_NCOLORS] = ".:X#"; + +enum +{ + FFMT_AUTO = 0, + + FFMT_ASCII, + FFMT_ANSI, + FFMT_IMAGE, + + FFMT_CHAR, + FFMT_SPRITE, + FFMT_BITMAP, + + FFMT_LAST +}; + + +typedef struct +{ + char *name; + char *fext; + BOOL in, out; + int format; + int subformat; +} DMConvFormat; + + +static DMConvFormat convFormatList[] = +{ + { + "ASCII text", "asc", FALSE, TRUE, + FFMT_ASCII , 0, + }, + { + "ANSI colored text", "ansi", FALSE, TRUE, + FFMT_ANSI , 0, + }, + { + "PNG image file", "png", TRUE, TRUE, + FFMT_IMAGE , IMGFMT_PNG, + }, + { + "PPM image file", "ppm", FALSE, TRUE, + FFMT_IMAGE , IMGFMT_PPM, + }, + { + "PCX image file", "pcx", TRUE, TRUE, + FFMT_IMAGE , IMGFMT_PCX, + }, + { + "IFF ILBM file", "lbm", TRUE, FALSE, + FFMT_IMAGE , IMGFMT_ILBM, + }, + { + "Bitplaned RAW (intl/non-intl) image file", "raw", FALSE, TRUE, + FFMT_IMAGE , IMGFMT_RAW, + }, + { + "IFFMaster RAW image file", "araw", FALSE, TRUE, + FFMT_IMAGE , IMGFMT_ARAW, + }, + + { + "C64 bitmap image file", NULL, TRUE, TRUE, + FFMT_BITMAP , -1, + }, + + { + "C64 character/font data", "chr", TRUE, TRUE, + FFMT_CHAR , 0 + }, + { + "C64 sprite data", "spr", TRUE, TRUE, + FFMT_SPRITE , 0 + }, +}; + +static const int nconvFormatList = sizeof(convFormatList) / sizeof(convFormatList[0]); + + +typedef struct +{ + BOOL triplet, alpha; + DMColor color; + int from, to; +} DMMapValue; + + + +char *optInFilename = NULL, + *optOutFilename = NULL; +int optInFormat = FFMT_AUTO, + optOutFormat = FFMT_ASCII, + optInSubFormat = IMGFMT_PNG, + optOutSubFormat = IMGFMT_PNG, + optItemCount = -1, + optPlanedWidth = 1, + optForcedFormat = -1; +int optInSkip = 0; +BOOL optInMulticolor = FALSE, + optSequential = FALSE, + optRemapColors = FALSE, + optRemapRemove = FALSE; +int optNRemapTable = 0; +DMMapValue optRemapTable[DM_MAX_COLORS]; +int optColors[C64_MAX_COLORS]; + +DMImageSpec optSpec = +{ + .scale = 1, + .nplanes = 4, + .interleave = FALSE, + .paletted = FALSE, + .format = 0, +}; + +static DMOptArg optList[] = +{ + { 0, '?', "help", "Show this help", OPT_NONE }, + { 15, 'v', "verbose", "Increase verbosity", OPT_NONE }, + { 3, 'o', "output", "Output filename", OPT_ARGREQ }, + { 1, 'i', "informat", "Set input format ([s]prite, [c]har, [b]itmap, [i]mage)", OPT_ARGREQ }, + { 2, 'm', "multicolor", "Input is multicolor / output in multicolor", OPT_NONE }, + { 4, 's', "skip", "Skip bytes in input", OPT_ARGREQ }, + { 5, 'f', "format", "Output format (see --formats)", OPT_ARGREQ }, + { 17, 'F', "formats", "Output format (see list below)", OPT_NONE }, + { 8, 'q', "sequential", "Output sequential files (image output only)", OPT_NONE }, + { 6, 'c', "colormap", "Color mappings (see below for information)", OPT_ARGREQ }, + { 7, 'n', "numitems", "How many 'items' to view (default: all)", OPT_ARGREQ }, + { 9, 'S', "scale", "Scale output by x (image output only)", OPT_ARGREQ }, + { 10, 'b', "bformat", "Force input bitmap format (see below)", OPT_ARGREQ }, + { 11, 'w', "width", "Item width (number of items per row, min 1)", OPT_ARGREQ }, + { 12, 'P', "paletted", "Use indexed/paletted output (png, pcx output only)", OPT_NONE }, + { 13, 'B', "bplanes", "Bits per pixel OR # of bitplanes (certain output formats)", OPT_ARGREQ }, + { 14, 'I', "interleave", "Interleave scanlines (default: output whole planes)", OPT_NONE }, + { 16, 'R', "remap", "Remap output image colors (-R <(#RRGGBB|index):index>[,<..>] | -R @map.txt)", OPT_ARGREQ }, + { 18, 'r', "remap-remove", "Remove unused colors from remapped palette (requires -R)", OPT_NONE }, +}; + +static const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowFormats() +{ + int i; + + printf( + "Available input/output formats:\n" + " Ext | I | O | Description\n" + "------+---+---+-----------------------------------------------\n" + ); + + for (i = 0; i < nconvFormatList; i++) + { + DMConvFormat *fmt = &convFormatList[i]; + printf("%-5s | %c | %c | %s\n", + fmt->fext ? fmt->fext : "", + fmt->in ? 'X' : ' ', + fmt->out ? 'X' : ' ', + fmt->name); + } + + printf( + "\n" + "(Not all input->output combinations are actually supported.)\n" + "\n" + "Available bitmap formats:\n" + " Ext | Type | Description\n" + "------+-----------------+-------------------------------------\n" + ); + + for (i = 0; i < ndmC64ImageFormats; i++) + { + const DMC64ImageFormat *fmt = &dmC64ImageFormats[i]; + char buf[64]; + printf("%-5s | %-15s | %s\n", + fmt->fext, + dmC64GetImageTypeString(buf, sizeof(buf), fmt->type), + fmt->name); + } +} + + +void argShowHelp() +{ + dmPrintBanner(stdout, dmProgName, "[options] <input file>"); + dmArgsPrintHelp(stdout, optList, optListN); + + printf( + "\n" + "Color map definitions are used for ANSI and image output, to declare what\n" + "output colors of the C64 palette are used for each single color/multi color\n" + "bit-combination. For example, if the input is multi color sprite or char,\n" + "you can define colors like: -c 0,8,3,15 .. for single color: -c 0,1\n" + "The numbers are palette indexes, and the order is for bit(pair)-values\n" + "00, 01, 10, 11 (multi color) and 0, 1 (single color). NOTICE! 255 is the\n" + "special color that can be used for transparency.\n" + ); +} + + +int dmGetConvFormat(int format, int subformat) +{ + int i; + for (i = 0; i < nconvFormatList; i++) + { + DMConvFormat *fmt = &convFormatList[i]; + if (fmt->format == format && + fmt->subformat == subformat) + return i; + } + return -1; +} + + +BOOL dmGetFormatByExt(const char *fext, int *format, int *subformat) +{ + int i; + if (fext == NULL) + return FALSE; + + for (i = 0; i < nconvFormatList; i++) + { + DMConvFormat *fmt = &convFormatList[i]; + if (fmt->fext != NULL && + strcasecmp(fext, fmt->fext) == 0) + { + *format = fmt->format; + *subformat = fmt->subformat; + return TRUE; + } + } + + for (i = 0; i < ndmC64ImageFormats; i++) + { + const DMC64ImageFormat *fmt = &dmC64ImageFormats[i]; + if (fmt->fext != NULL && + strcasecmp(fext, fmt->fext) == 0) + { + *format = FFMT_BITMAP; + *subformat = i; + return TRUE; + } + } + + return FALSE; +} + + +static BOOL dmParseMapOptionMapItem(const char *popt, DMMapValue *value, const int nmax, const char *msg) +{ + char *end, *split, *opt = dm_strdup(popt); + + if (opt == NULL) + goto error; + + if ((end = split = strchr(opt, ':')) == NULL) + { + dmError("Invalid %s value '%s', expected <(#|%)RRGGBB|[$|0x]index>:<[$|0x]index>.\n", msg, opt); + goto error; + } + + // Trim whitespace + *end = 0; + for (end--; end > opt && *end && isspace(*end); end--) + *end = 0; + + // Parse either a hex triplet color definition or a normal value + if (*opt == '#' || *opt == '%') + { + int colR, colG, colB, colA; + + if (sscanf(opt + 1, "%2x%2x%2x%2x", &colR, &colG, &colB, &colA) == 4 || + sscanf(opt + 1, "%2X%2X%2X%2X", &colR, &colG, &colB, &colA) == 4) + { + value->alpha = TRUE; + value->color.a = colA; + } + else + if (sscanf(opt + 1, "%2x%2x%2x", &colR, &colG, &colB) != 3 && + sscanf(opt + 1, "%2X%2X%2X", &colR, &colG, &colB) != 3) + { + dmError("Invalid %s value '%s', expected a hex triplet, got '%s'.\n", msg, popt, opt + 1); + goto error; + } + + value->color.r = colR; + value->color.g = colG; + value->color.b = colB; + value->triplet = TRUE; + } + else + { + if (!dmGetIntVal(opt, &value->from)) + { + dmError("Invalid %s value '%s', could not parse source value '%s'.\n", msg, popt, opt); + goto error; + } + value->triplet = FALSE; + } + + // Trim whitespace + split++; + while (*split && isspace(*split)) split++; + + // Parse destination value + if (!dmGetIntVal(split, &value->to)) + { + dmError("Invalid %s value '%s', could not parse destination value '%s'.\n", msg, popt, split); + goto error; + } + + if (!value->triplet && (value->from < 0 || value->from > 255)) + { + dmError("Invalid %s map source color index value %d, must be [0..255].\n", msg, value->from); + goto error; + } + + if (value->to < 0 || value->to > nmax) + { + dmError("Invalid %s map destination color index value %d, must be [0..%d].\n", msg, value->to, nmax); + goto error; + } + + dmFree(opt); + return TRUE; + +error: + dmFree(opt); + return FALSE; +} + + +static BOOL dmParseMapOptionItem(char *opt, char *end, void *pvalue, const int index, const int nmax, const BOOL requireIndex, const char *msg) +{ + // Trim whitespace + if (end != NULL) + { + *end = 0; + for (end--; end > opt && *end && isspace(*end); end--) + *end = 0; + } + while (*opt && isspace(*opt)) opt++; + + // Parse item based on mode + if (requireIndex) + { + DMMapValue *value = (DMMapValue *) pvalue; + if (!dmParseMapOptionMapItem(opt, &value[index], nmax, msg)) + return FALSE; + } + else + { + int *value = (int *) pvalue; + char *split = strchr(opt, ':'); + if (split != NULL) + { + dmError("Unexpected ':' in indexed %s '%s'.\n", msg, opt); + return FALSE; + } + + if (!dmGetIntVal(opt, &value[index])) + { + dmError("Invalid %s value '%s', could not parse.\n", msg, opt); + return FALSE; + } + } + + return TRUE; +} + + +BOOL dmParseMapOptionString(char *opt, void *values, int *nvalues, const int nmax, const BOOL requireIndex, const char *msg) +{ + char *end, *start = opt; + + *nvalues = 0; + while (*nvalues < nmax && *start && (end = strchr(start, ',')) != NULL) + { + if (!dmParseMapOptionItem(start, end, values, *nvalues, nmax, requireIndex, msg)) + return FALSE; + + start = end + 1; + (*nvalues)++; + } + + if (*start && *nvalues < nmax) + { + if (!dmParseMapOptionItem(start, NULL, values, *nvalues, nmax, requireIndex, msg)) + return FALSE; + + (*nvalues)++; + } + + return TRUE; +} + + +int dmParseColorRemapFile(const char *filename, DMMapValue *values, int *nvalue, const int nmax) +{ + FILE *fp; + char line[512]; + int res = DMERR_OK; + + if ((fp = fopen(filename, "r")) == NULL) + { + res = dmGetErrno(); + dmError("Could not open color remap file '%s' for reading, %d: %s\n", + res, dmErrorStr(res)); + return res; + } + + while (fgets(line, sizeof(line), fp)) + { + char *start = line; + while (*start && isspace(*start)) start++; + + if (*start != 0 && *start != ';') + { + if (!dmParseMapOptionMapItem(line, &values[*nvalue], nmax, "mapping file")) + goto error; + else + { + (*nvalue)++; + if (*nvalue >= nmax) + { + dmError("Too many mapping pairs in '%s', maximum is %d.\n", + filename, nmax); + goto error; + } + } + } + } + +error: + fclose(fp); + return res; +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + switch (optN) + { + case 0: + argShowHelp(); + exit(0); + break; + + case 17: + argShowFormats(); + exit(0); + break; + + case 15: + dmVerbosity++; + break; + + case 1: + switch (tolower(optArg[0])) + { + case 's': + optInFormat = FFMT_SPRITE; + break; + case 'c': + optInFormat = FFMT_CHAR; + break; + case 'b': + optInFormat = FFMT_BITMAP; + break; + case 'i': + optInFormat = FFMT_IMAGE; + break; + default: + dmError("Invalid input format '%s'.\n", optArg); + return FALSE; + } + break; + + case 2: + optInMulticolor = TRUE; + break; + + case 3: + optOutFilename = optArg; + break; + + case 4: + if (!dmGetIntVal(optArg, &optInSkip)) + { + dmError("Invalid skip value argument '%s'.\n", optArg); + return FALSE; + } + break; + + case 5: + if (!dmGetFormatByExt(optArg, &optOutFormat, &optOutSubFormat)) + { + dmError("Invalid output format '%s'.\n", optArg); + return FALSE; + } + break; + + case 6: + { + int index, ncolors; + if (!dmParseMapOptionString(optArg, optColors, + &ncolors, C64_MAX_COLORS, FALSE, "color table option")) + return FALSE; + + dmMsg(1, "Set color table: "); + for (index = 0; index < ncolors; index++) + { + dmPrint(1, "[%d:%d]%s", + index, optColors[index], + (index < ncolors) ? ", " : ""); + } + dmPrint(1, "\n"); + } + break; + + case 7: + if (sscanf(optArg, "%d", &optItemCount) != 1) + { + dmError("Invalid count value argument '%s'.\n", optArg); + return FALSE; + } + break; + + case 8: + optSequential = TRUE; + break; + + case 9: + { + int tmp = atoi(optArg); + if (tmp < 1 || tmp > 50) + { + dmError("Invalid scale value '%s'.\n", optArg); + return FALSE; + } + optSpec.scale = tmp; + } + break; + + case 11: + { + int tmp = atoi(optArg); + if (tmp < 1 || tmp > 512) + { + dmError("Invalid width value '%s'.\n", optArg); + return FALSE; + } + optPlanedWidth = tmp; + } + break; + + case 12: + optSpec.paletted = TRUE; + break; + + case 13: + { + int tmp = atoi(optArg); + if (tmp < 1 || tmp > 8) + { + dmError("Invalid bitplanes/bpp value '%s'.\n", optArg); + return FALSE; + } + optSpec.nplanes = tmp; + } + break; + + case 14: + optSpec.interleave = TRUE; + break; + + + case 16: + if (optArg[0] == '@') + { + if (optArg[1] != 0) + { + int res; + if ((res = dmParseColorRemapFile(optArg + 1, + optRemapTable, &optNRemapTable, DM_MAX_COLORS)) != DMERR_OK) + return FALSE; + } + else + { + dmError("No remap filename given.\n"); + return FALSE; + } + } + else + { + if (!dmParseMapOptionString(optArg, optRemapTable, + &optNRemapTable, DM_MAX_COLORS, TRUE, "color remap option")) + return FALSE; + } + + optRemapColors = TRUE; + break; + + case 18: + optRemapRemove = TRUE; + break; + + default: + dmError("Unknown option '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char *currArg) +{ + if (!optInFilename) + optInFilename = currArg; + else + { + dmError("Source filename already specified, extraneous argument '%s'.\n", + currArg); + return FALSE; + } + + return TRUE; +} + + +void dmPrintByte(FILE *out, int byte, int format, BOOL multicolor) +{ + int i; + + if (multicolor) + { + for (i = ASC_NBITS; i; i -= 2) + { + int val = (byte & (3ULL << (i - 2))) >> (i - 2); + char ch; + switch (format) + { + case FFMT_ASCII: + ch = dmASCIIPalette[val]; + fprintf(out, "%c%c", ch, ch); + break; + case FFMT_ANSI: + fprintf(out, "%c[0;%d;%dm##%c[0m", + 0x1b, + 1, + 31 + optColors[val], + 0x1b); + break; + } + } + } + else + { + for (i = ASC_NBITS; i; i--) + { + int val = (byte & (1ULL << (i - 1))) >> (i - 1); + char ch; + switch (format) + { + case FFMT_ASCII: + ch = val ? '#' : '.'; + fputc(ch, out); + break; + case FFMT_ANSI: + fprintf(out, "%c[0;%d;%dm %c[0m", + 0x1b, + 1, + 31 + optColors[val], + 0x1b); + break; + } + } + } +} + + +void dmDumpCharASCII(FILE *outFile, const Uint8 *buf, int *offs, int format, BOOL multicolor) +{ + int yc; + + for (yc = 0; yc < C64_CHR_HEIGHT; yc++) + { + fprintf(outFile, "%04x : ", *offs); + dmPrintByte(outFile, buf[yc], format, multicolor); + fprintf(outFile, "\n"); + (*offs)++; + } +} + + +void dmDumpSpriteASCII(FILE *outFile, const Uint8 *buf, int *offs, int format, BOOL multicolor) +{ + int bufOffs, xc, yc; + + for (bufOffs = yc = 0; yc < C64_SPR_HEIGHT; yc++) + { + fprintf(outFile, "%04x : ", *offs); + for (xc = 0; xc < C64_SPR_WIDTH; xc++) + { + dmPrintByte(outFile, buf[bufOffs], format, multicolor); + fprintf(outFile, " "); + bufOffs++; + (*offs)++; + } + fprintf(outFile, "\n"); + } + (*offs)++; +} + + +#ifdef UNFINISHED +int dmConvertBMP2(DMImage *screen, const DM64Image *img) +{ + int yc; + Uint8 *dp = screen->data; + + for (yc = 0; yc < screen->height; yc++) + { + Uint8 *d = dp; + const int y = yc / 8, yb = yc & 7; + const int scroffsy = y * C64_SCR_CH_WIDTH; + const int bmoffsy = y * C64_SCR_WIDTH; + int xc; + + for (xc = 0; xc < screen->width / 2; xc++) + { + const int x = xc / 4; + const int scroffs = scroffsy + x; + const int b = img->bitmap[0][bmoffsy + (x * 8) + yb]; + const int v = 6 - ((xc * 2) & 6); + Uint8 c; + + switch ((b >> v) & 3) + { + case 0: c = img->bgcolor; break; + case 1: c = img->screen[0][scroffs] >> 4; break; + case 2: c = img->screen[0][scroffs] & 15; break; + case 3: c = img->color[0][scroffs] & 15; break; + } + + *d++ = c; + *d++ = c; + } + + dp += screen->pitch; + } + + return 0; +} +#endif + + +int dmRemapImageColors(DMImage *image) +{ + DMColor *npal = dmCalloc(image->ncolors, sizeof(DMColor)); + int *mapping = dmMalloc(image->ncolors * sizeof(int)); + BOOL *mapped = dmMalloc(image->ncolors * sizeof(BOOL)); + BOOL *used = dmMalloc(image->ncolors * sizeof(BOOL)); + int n, index, xc, yc, ncolors; + + dmMsg(1, "Remapping %d output image colors of %d colors.\n", optNRemapTable, image->ncolors); + + if (npal == NULL || mapping == NULL || mapped == NULL || used == NULL) + { + dmError("Could not allocate memory for reused palette.\n"); + return DMERR_MALLOC; + } + + for (index = 0; index < image->ncolors; index++) + { + mapping[index] = -1; + mapped[index] = used[index] = FALSE; + } + + // Find used colors + dmMsg(2, "Scanning image for used colors...\n"); + for (ncolors = yc = 0; yc < image->height; yc++) + { + Uint8 *dp = image->data + image->pitch * yc; + for (xc = 0; xc < image->width; xc++) + { + Uint8 col = dp[xc]; + if (col < image->ncolors && !used[col]) + { + used[col] = TRUE; + ncolors++; + } + } + } + dmMsg(2, "Found %d used colors, creating remap-table.\n", ncolors); + + // Match and mark mapped colors + for (index = 0; index < optNRemapTable; index++) + { + DMMapValue *map = &optRemapTable[index]; + if (map->triplet) + { + BOOL found = FALSE; + for (n = 0; n < image->ncolors; n++) + { + if (dmCompareColor(&(image->pal[n]), &(map->color), map->alpha)) + { + dmMsg(3, "RGBA match #%02x%02x%02x%02x: %d -> %d\n", + map->color.r, map->color.g, map->color.b, map->color.a, + n, + map->to); + + mapping[n] = map->to; + mapped[map->to] = TRUE; + found = TRUE; + } + } + + if (!found) + { + dmMsg(3, "No RGBA match found for map index %d, #%02x%02x%02x%02x\n", + index, + map->color.r, map->color.g, map->color.b, map->color.a); + } + } + else + { + dmMsg(3, "Map index: %d -> %d\n", + map->from, map->to); + + mapping[map->from] = map->to; + mapped[map->to] = TRUE; + } + } + + + // Fill in the rest + if (optRemapRemove) + { + dmMsg(2, "Removing unused colors.\n"); + for (index = 0; index < image->ncolors; index++) + if (mapping[index] < 0 && used[index]) + { + for (n = 0; n < image->ncolors; n++) + if (!mapped[n]) + { + mapping[index] = n; + mapped[n] = TRUE; + break; + } + } + } + else + { + for (index = 0; index < image->ncolors; index++) + if (mapping[index] < 0) + { + for (n = 0; n < image->ncolors; n++) + if (!mapped[n]) + { + mapping[index] = n; + mapped[n] = TRUE; + break; + } + } + } + + // Calculate final number of palette colors + ncolors = 0; + for (index = 0; index < image->ncolors; index++) + { + if (mapping[index] + 1 > ncolors) + ncolors = mapping[index] + 1; + } + + // Copy palette entries + for (index = 0; index < image->ncolors; index++) + { + if (mapping[index] >= 0) + { + memcpy(&npal[mapping[index]], &(image->pal[index]), sizeof(DMColor)); + } + } + + // Remap image + dmMsg(1, "Remapping image to %d colors...\n", ncolors); + for (yc = 0; yc < image->height; yc++) + { + Uint8 *dp = image->data + image->pitch * yc; + for (xc = 0; xc < image->width; xc++) + { + Uint8 col = dp[xc]; + if (col < image->ncolors && mapping[col] >= 0 && mapping[col] < image->ncolors) + dp[xc] = mapping[col]; + else + dp[xc] = 0; + } + } + + // Set new palette, free memory + dmFree(image->pal); + image->pal = npal; + image->ncolors = ncolors; + + dmFree(mapping); + dmFree(mapped); + dmFree(used); + return DMERR_OK; +} + + +int dmWriteBitmap(const char *filename, DMC64Image *image, int iformat, BOOL enableFixUps) +{ + FILE *outFile = NULL; + Uint8 *buf = NULL; + size_t bufSize; + int res = DMERR_OK; + const DMC64ImageFormat *fmt = &dmC64ImageFormats[iformat]; + + dmMsg(1, "Converting to %s format bitmap.\n", fmt->name); + if (image->type != fmt->type && enableFixUps) + { + // Try to do some simple fixups + if ((fmt->type & D64_FMT_FLI) && (image->type & D64_FMT_FLI) == 0) + { + dmMsg(1, "Upconverting multicolor to FLI.\n"); + int i; + for (i = 1; i < C64_SCR_MAX_BANK; i++) + { + memcpy(image->color[i], image->color[0], C64_SCR_COLOR_SIZE); + memcpy(image->screen[i], image->screen[0], C64_SCR_SCREEN_SIZE); + } + } + } + + + if ((res = dmC64EncodeGenericBMP(&buf, &bufSize, image, fmt)) != DMERR_OK) + goto error; + + dmMsg(2, "Result: %d bytes\n", bufSize); + + if ((outFile = fopen(filename, "wb")) == NULL) + { + res = dmGetErrno(); + dmError("Error opening output file '%s', %d: %s\n", + filename, res, dmErrorStr(res)); + goto error; + } + + if (!dm_fwrite_str(outFile, buf, bufSize)) + { + res = dmGetErrno(); + dmError("Error writing image data to '%s', %d: %s\n", + filename, res, dmErrorStr(res)); + } + +error: + if (outFile != NULL) + fclose(outFile); + dmFree(buf); + return res; +} + + +int dmWriteImage(const char *filename, DMImage *image, DMImageSpec *spec, int iformat, BOOL info) +{ + if (info) + { + dmMsg(1, "Outputting %s image %d x %d -> %d x %d [%d]\n", + dmImageFormatList[iformat].fext, + image->width, image->height, + image->width * spec->scale, image->height * spec->scale, + spec->scale); + } + + // Perform color remapping + if (optRemapColors) + { + int res; + if ((res = dmRemapImageColors(image)) != DMERR_OK) + return res; + } + + switch (iformat) + { +#ifdef DM_USE_LIBPNG + case IMGFMT_PNG: + if (info) dmMsg(2, "%s output.\n", spec->paletted ? "Indexed 8bpp" : "32bit RGBA"); + spec->format = spec->paletted ? DM_IFMT_PALETTE : DM_IFMT_RGBA; + return dmWritePNGImage(filename, image, spec); +#endif + + case IMGFMT_PPM: + if (info) dmMsg(2, "24bit RGB output.\n"); + spec->format = DM_IFMT_RGB; + return dmWritePPMImage(filename, image, spec); + + case IMGFMT_PCX: + if (info) dmMsg(2, "%s output.\n", spec->paletted ? "Indexed 8bpp" : "24bit RGB"); + return dmWritePCXImage(filename, image, spec); + + case IMGFMT_RAW: + case IMGFMT_ARAW: + { + FILE *fp; + char *dataFilename, *fext, *tmpFilename = dm_strdup(filename); + + // Form data file filename + if (tmpFilename == NULL) + return DMERR_MALLOC; + + fext = strrchr(tmpFilename, '.'); + if (fext != NULL) + *fext = 0; + dataFilename = dm_strdup_printf("%s.inc", tmpFilename); + dmFree(tmpFilename); + + // Open data file for writing + if ((fp = fopen(dataFilename, "w")) == NULL) + dmError("Could not create '%s'.\n", dataFilename); + dmFree(dataFilename); + + if (fp != NULL) + { + // Strip extension + int i; + char *palID = dm_strdup_printf("img_%s", filename); + char *fext = strrchr(palID, '.'); + if (fext != NULL) + *fext = 0; + + // Replace any non-alphanumerics + for (i = 0; palID[i]; i++) + { + if (isalnum(palID[i])) + palID[i] = tolower(palID[i]); + else + palID[i] = '_'; + } + + if (iformat == IMGFMT_ARAW) + { + fprintf(fp, + "%s_width: dw.w %d\n" + "%s_height: dw.w %d\n" + "%s_nplanes: dw.w %d\n" + "%s_ncolors: dw.w %d\n" + "%s_palette:\n", + palID, image->width, + palID, image->height, + palID, spec->nplanes, + palID, image->ncolors, + palID); + + dmWriteIFFMasterRAWPalette(fp, image, 1 << optSpec.nplanes, NULL, NULL); + + fprintf(fp, + "%s: incbin \"%s\"\n", + palID, filename); + } + else + { + fprintf(fp, + "%s_width: dw.w %d\n" + "%s_height: dw.w %d\n" + "%s_nplanes: dw.w %d\n", + palID, image->width, + palID, image->height, + palID, spec->nplanes); + } + + fclose(fp); + dmFree(palID); + } + + if (info) dmMsg(2, "%d bitplanes, %s interleave.\n", spec->nplanes, spec->interleave ? "with" : "without"); + return dmWriteRAWImage(filename, image, spec); + } + break; + + default: + return DMERR_INVALID_DATA; + } +} + + +static Uint8 dmConvertByte(const Uint8 *sp, const BOOL multicolor) +{ + Uint8 byte = 0; + int xc; + + if (multicolor) + { + for (xc = 0; xc < 8 / 2; xc++) + { + Uint8 pixel = sp[xc * 2] & 3; + byte |= pixel << (6 - (xc * 2)); + } + } + else + { + for (xc = 0; xc < 8; xc++) + { + Uint8 pixel = sp[xc] == 0 ? 0 : 1; + byte |= pixel << (7 - xc); + } + } + + return byte; +} + + +BOOL dmConvertImage2Char(Uint8 *buf, const DMImage *image, + const int xoffs, const int yoffs, const BOOL multicolor) +{ + int yc; + + if (xoffs < 0 || yoffs < 0 || + xoffs + C64_CHR_WIDTH_PX > image->width || + yoffs + C64_CHR_HEIGHT > image->height) + return FALSE; + + for (yc = 0; yc < C64_CHR_HEIGHT; yc++) + { + const Uint8 *sp = image->data + ((yc + yoffs) * image->pitch) + xoffs; + buf[yc] = dmConvertByte(sp, multicolor); + } + + return TRUE; +} + + +BOOL dmConvertImage2Sprite(Uint8 *buf, const DMImage *image, + const int xoffs, const int yoffs, const BOOL multicolor) +{ + int yc, xc; + + if (xoffs < 0 || yoffs < 0 || + xoffs + C64_SPR_WIDTH_PX > image->width || + yoffs + C64_SPR_HEIGHT > image->height) + return FALSE; + + for (yc = 0; yc < C64_SPR_HEIGHT; yc++) + { + for (xc = 0; xc < C64_SPR_WIDTH_PX / C64_SPR_WIDTH; xc++) + { + const Uint8 *sp = image->data + ((yc + yoffs) * image->pitch) + (xc * 8) + xoffs; + buf[(yc * C64_SPR_WIDTH) + xc] = dmConvertByte(sp, multicolor); + } + } + + return TRUE; +} + + +int dmWriteSpritesAndChars(const char *filename, DMImage *image, int outFormat, BOOL multicolor) +{ + int outBlockW, outBlockH, bx, by; + FILE *outFile = NULL; + Uint8 *buf = NULL; + size_t bufSize; + char *outType; + + switch (outFormat) + { + case FFMT_CHAR: + bufSize = C64_CHR_SIZE; + outBlockW = image->width / C64_CHR_WIDTH_PX; + outBlockH = image->height / C64_CHR_HEIGHT; + outType = "char"; + break; + + case FFMT_SPRITE: + bufSize = C64_SPR_SIZE; + outBlockW = image->width / C64_SPR_WIDTH_PX; + outBlockH = image->height / C64_SPR_HEIGHT; + outType = "sprite"; + break; + + default: + dmError("Invalid output format %d, internal error.\n", outFormat); + goto error; + } + + if (outBlockW <= 0 || outBlockH <= 0) + { + dmError("Source image dimensions too small for conversion, block dimensions %d x %d.\n", + outBlockW, outBlockH); + goto error; + } + + if ((outFile = fopen(filename, "wb")) == NULL) + { + int err = dmGetErrno(); + dmError("Could not open '%s' for writing, %d: %s.\n", + filename, err, dmErrorStr(err)); + goto error; + } + + if ((buf = dmMalloc(bufSize)) == NULL) + { + dmError("Could not allocate %d bytes for conversion buffer.\n", + bufSize); + goto error; + } + + dmMsg(1, "Writing %d x %d = %d blocks of %s data...\n", + outBlockW, outBlockH, outBlockW * outBlockH, outType); + + for (by = 0; by < outBlockH; by++) + for (bx = 0; bx < outBlockW; bx++) + { + switch (outFormat) + { + case FFMT_CHAR: + if (!dmConvertImage2Char(buf, image, + bx * C64_CHR_WIDTH_PX, by * C64_CHR_HEIGHT, + multicolor)) + goto error; + break; + + case FFMT_SPRITE: + if (!dmConvertImage2Sprite(buf, image, + bx * C64_SPR_WIDTH_PX, by * C64_SPR_HEIGHT, + multicolor)) + goto error; + } + + if (!dm_fwrite_str(outFile, buf, bufSize)) + { + int err = dmGetErrno(); + dmError("Error writing data block %d,%d to '%s', %d: %s\n", + bx, by, filename, err, dmErrorStr(err)); + goto error; + } + } + + fclose(outFile); + dmFree(buf); + return 0; + +error: + if (outFile != NULL) + fclose(outFile); + dmFree(buf); + return -1; +} + + +int dmDumpSpritesAndChars(FILE *inFile) +{ + int dataOffs, itemCount, outWidth, outWidthPX, outHeight; + size_t bufSize; + Uint8 *bufData; + + switch (optInFormat) + { + case FFMT_CHAR: + bufSize = C64_CHR_SIZE; + outWidth = C64_CHR_WIDTH; + outWidthPX = C64_CHR_WIDTH_PX; + outHeight = C64_CHR_HEIGHT; + break; + + case FFMT_SPRITE: + bufSize = C64_SPR_SIZE; + outWidth = C64_SPR_WIDTH; + outWidthPX = C64_SPR_WIDTH_PX; + outHeight = C64_SPR_HEIGHT; + break; + + default: + dmError("Invalid input format %d, internal error.\n", optInFormat); + return -1; + } + + if ((bufData = dmMalloc(bufSize)) == NULL) + { + dmError("Could not allocate temporary buffer of %d bytes.\n", bufSize); + return -2; + } + + + dataOffs = optInSkip; + itemCount = 0; + + if (optOutFormat == FFMT_ANSI || optOutFormat == FFMT_ASCII) + { + BOOL error = FALSE; + FILE *outFile; + + if (optOutFilename == NULL) + outFile = stdout; + else + if ((outFile = fopen(optOutFilename, "w")) == NULL) + { + int res = dmGetErrno(); + dmError("Error opening output file '%s', %d: %s\n", + optOutFilename, res, dmErrorStr(res)); + goto error; + } + + while (!feof(inFile) && !error && (optItemCount < 0 || itemCount < optItemCount)) + { + memset(bufData, 0, bufSize); + + if (fread(bufData, 1, bufSize, inFile) != bufSize) + { + dmError("Could not read full bufferful (%d bytes) of data at 0x%x.\n", + bufSize, dataOffs); + error = TRUE; + } + + fprintf(outFile, "---- : -------------- #%d\n", itemCount); + + switch (optInFormat) + { + case FFMT_CHAR: + dmDumpCharASCII(outFile, bufData, &dataOffs, optOutFormat, optInMulticolor); + break; + case FFMT_SPRITE: + dmDumpSpriteASCII(outFile, bufData, &dataOffs, optOutFormat, optInMulticolor); + break; + } + itemCount++; + } + + fclose(outFile); + } + else + if (optOutFormat == FFMT_IMAGE) + { + DMImage *outImage = NULL; + char *outFilename = NULL; + int outX = 0, outY = 0, err; + + if (optSequential) + { + if (optOutFilename == NULL) + { + dmError("Sequential image output requires filename template.\n"); + goto error; + } + + outImage = dmImageAlloc(outWidthPX, outHeight); + dmMsg(1, "Outputting sequence of %d images @ %d x %d -> %d x %d.\n", + optItemCount, + outImage->width, outImage->height, + outImage->width * optSpec.scale, outImage->height * optSpec.scale); + } + else + { + int outIWidth, outIHeight; + if (optItemCount <= 0) + { + dmError("Single-image output requires count to be set (-n).\n"); + goto error; + } + + outIWidth = optPlanedWidth; + outIHeight = (optItemCount / optPlanedWidth); + if (optItemCount % optPlanedWidth) + outIHeight++; + + outImage = dmImageAlloc(outWidthPX * outIWidth, outIHeight * outHeight); + } + + outImage->constpal = TRUE; + outImage->pal = dmC64Palette; + outImage->ncolors = C64_NCOLORS; + outImage->ctransp = 255; + + while (!feof(inFile) && (optItemCount < 0 || itemCount < optItemCount)) + { + memset(bufData, 0, bufSize); + + if (fread(bufData, 1, bufSize, inFile) != bufSize) + { + dmError("Could not read full bufferful (%d bytes) of data at 0x%x.\n", + bufSize, dataOffs); + break; + } + + if ((err = dmC64ConvertCSData(outImage, outX * outWidthPX, outY * outHeight, + bufData, outWidth, outHeight, optInMulticolor, optColors)) != DMERR_OK) + { + dmError("Internal error in conversion of raw data to bitmap: %d.\n", err); + break; + } + + if (optSequential) + { + outFilename = dm_strdup_printf("%s%04d.%s", optOutFilename, itemCount, convFormatList[optOutFormat].fext); + if (outFilename == NULL) + { + dmError("Could not allocate memory for filename template?\n"); + goto error; + } + + dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); + dmFree(outFilename); + } + else + { + if (++outX >= optPlanedWidth) + { + outX = 0; + outY++; + } + } + + itemCount++; + } + + if (!optSequential) + { + dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); + } + + dmImageFree(outImage); + } + else + if (optOutFormat == FFMT_BITMAP) + { + if (optSequential) + { + dmError("Sequential output not supported for spr/char -> bitmap conversion.\n"); + goto error; + } + } + + dmFree(bufData); + return 0; + +error: + dmFree(bufData); + return -1; +} + + +int main(int argc, char *argv[]) +{ + FILE *inFile; + const DMC64ImageFormat *cfmt; + DMC64Image cimage; + Uint8 *dataBuf = NULL; + size_t dataSize; + int i; + + // Default colors + for (i = 0; i < C64_MAX_COLORS; i++) + optColors[i] = i; + + // Initialize and parse commandline + dmInitProg("gfxconv", "Simple graphics converter", "0.75", NULL, NULL); + + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, argHandleFile, TRUE)) + exit(1); + +#ifndef DM_USE_LIBPNG + if (optOutFormat == IMGFMT_PNG) + { + dmError("PNG output format support not compiled in, sorry.\n"); + goto error; + } +#endif + + // Determine input format, if not specified' + if (optInFormat == FFMT_AUTO && optInFilename != NULL) + { + char *dext = strrchr(optInFilename, '.'); + dmMsg(4, "Trying to determine file format by extension.\n"); + if (dext) + { + dmGetFormatByExt(dext + 1, &optInFormat, &optInSubFormat); + } + } + + if (optInFilename == NULL) + { + if (optInFormat == FFMT_AUTO) + { + dmError("Standard input cannot be used without specifying input format.\n"); + dmError("Perhaps you should try using --help\n"); + goto error; + } + inFile = stdin; + } + else + if ((inFile = fopen(optInFilename, "rb")) == NULL) + { + int res = dmGetErrno(); + dmError("Error opening input file '%s', %d: %s\n", + optInFilename, res, dmErrorStr(res)); + goto error; + } + + if (dmReadDataFile(inFile, NULL, &dataBuf, &dataSize) != 0) + goto error; + + if (optInFormat == FFMT_AUTO || optInFormat == FFMT_BITMAP) + { + // Probe for format + const DMC64ImageFormat *forced = NULL; + int res; + + if (optForcedFormat >= 0) + { + forced = &dmC64ImageFormats[optForcedFormat]; + dmMsg(0,"Forced %s format image, type %d, %s\n", + forced->name, forced->type, forced->fext); + } + + res = dmC64DecodeBMP(&cimage, dataBuf, dataSize, optInSkip, optInSkip + 2, &cfmt, forced); + if (forced == NULL && cfmt != NULL) + { + dmMsg(1,"Probed %s format image, type %d, %s\n", + cfmt->name, cfmt->type, cfmt->fext); + } + + if (res == 0) + optInFormat = FFMT_BITMAP; + } + + if (optInFormat == FFMT_AUTO || optInFormat == FFMT_IMAGE) + { + DMImageFormat *ifmt = NULL; + int index; + dmMsg(4, "Trying to probe image formats.\n"); + if (dmImageProbeGeneric(dataBuf + optInSkip, dataSize - optInSkip, &ifmt, &index) > 0) + { + optInFormat = FFMT_IMAGE; + optInSubFormat = index; + dmMsg(2, "Probed %s format image.\n", ifmt->fext); + } + } + + if (optInFormat == FFMT_AUTO) + { + dmError("No input format specified, and could not be determined automatically.\n"); + exit(1); + } + + // Skip, if needed + if (fseek(inFile, optInSkip, SEEK_SET) != 0) + { + int res = dmGetErrno(); + dmError("Could not seek to file position %d (0x%x): %s\n", + optInSkip, optInSkip, dmErrorStr(res)); + goto error; + } + + int inFormat = dmGetConvFormat(optInFormat, optInSubFormat), + outFormat = dmGetConvFormat(optOutFormat, optOutSubFormat); + + if (inFormat != -1 && outFormat != -1) + { + char *inFmtName = convFormatList[inFormat].name, + *inFmtExt = convFormatList[inFormat].fext, + *outFmtName = convFormatList[outFormat].name, + *outFmtExt = convFormatList[outFormat].fext; + + if (optInFormat == FFMT_BITMAP) + inFmtExt = cfmt->name; + + dmMsg(1, "Attempting conversion %s (%s) -> %s (%s)\n", + inFmtName, inFmtExt, outFmtName, outFmtExt); + } + + switch (optInFormat) + { + case FFMT_SPRITE: + case FFMT_CHAR: + dmDumpSpritesAndChars(inFile); + break; + + case FFMT_BITMAP: + { + DMImage *outImage = NULL; + int res = DMERR_OK; + + if (optOutFilename == NULL) + { + dmError("Output filename not set, required for image formats.\n"); + goto error; + } + + switch (optOutFormat) + { + case FFMT_IMAGE: + res = dmC64ConvertBMP2Image(&outImage, &cimage, cfmt, TRUE); + + if (res != DMERR_OK || outImage == NULL) + { + dmError("Error in bitmap to image conversion.\n"); + goto error; + } + + res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); + break; + + + case FFMT_BITMAP: + res = dmWriteBitmap(optOutFilename, &cimage, optOutSubFormat, TRUE); + break; + + case FFMT_CHAR: + case FFMT_SPRITE: + res = dmWriteSpritesAndChars(optOutFilename, outImage, optOutFormat, optInMulticolor); + break; + + default: + dmError("Unsupported output format for bitmap/image conversion.\n"); + break; + } + + dmImageFree(outImage); + } + break; + + case FFMT_IMAGE: + { + DMImage *outImage = NULL; + int res = DMERR_OK; + + if (optOutFilename == NULL) + { + dmError("Output filename not set, required for image formats.\n"); + goto error; + } + + // Read input + DMImageFormat *ifmt = &dmImageFormatList[optInSubFormat]; + if (ifmt->readFILE != NULL) + res = ifmt->readFILE(inFile, &outImage); + else + dmError("Unsupported input image format for bitmap/image conversion.\n"); + + if (res != DMERR_OK || outImage == NULL) + break; + + switch (optOutFormat) + { + case FFMT_IMAGE: + res = dmWriteImage(optOutFilename, outImage, &optSpec, optOutSubFormat, TRUE); + break; + + case FFMT_CHAR: + case FFMT_SPRITE: + res = dmWriteSpritesAndChars(optOutFilename, outImage, optOutFormat, optInMulticolor); + break; + + default: + dmError("Unsupported output format for bitmap/image conversion.\n"); + break; + } + + dmImageFree(outImage); + } + break; + } + + fclose(inFile); + + dmFree(dataBuf); + exit(0); + return 0; + +error: + dmFree(dataBuf); + return -3; + exit(3); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/mod2wav.c Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,314 @@ +/* + * mod2wav - Render XM/JSSMOD module to WAV waveform file + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2007 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> +#include "jss.h" +#include "jssmod.h" +#include "jssmix.h" +#include "jssplr.h" +#include "dmlib.h" +#include "dmargs.h" +#include "dmwav.h" +#include "dmmutex.h" + + +char *optInFilename = NULL, *optOutFilename = NULL; +int optOutFormat = JSS_AUDIO_S16, + optOutChannels = 2, + optOutFreq = 44100, + optMuteOChannels = -1, + optStartOrder = -1; +BOOL optUsePlayTime = FALSE; +size_t optPlayTime; + + +DMOptArg optList[] = +{ + { 0, '?', "help", "Show this help", OPT_NONE }, + { 2, 'v', "verbose", "Be more verbose", OPT_NONE }, + { 3, '1', "16bit", "16-bit output", OPT_NONE }, + { 4, '8', "8bit", "8-bit output", OPT_NONE }, + { 5, 'm', "mono", "Mono output", OPT_NONE }, + { 6, 's', "stereo", "Stereo output", OPT_NONE }, + { 7, 'f', "freq", "Output frequency", OPT_ARGREQ }, + { 8, 'M', "mute", "Mute other channels than #", OPT_ARGREQ }, + { 9, 'o', "order", "Start from order #", OPT_ARGREQ }, + { 10, 't', "time", "Play for # seconds", OPT_ARGREQ }, +// {10, 'l', "loop", "Loop for # times", OPT_ARGREQ }, +}; + +const int optListN = sizeof(optList) / sizeof(optList[0]); + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + (void) optArg; + + switch (optN) + { + case 0: + dmPrintBanner(stdout, dmProgName, + "[options] [sourcefile] [destfile]"); + + dmArgsPrintHelp(stdout, optList, optListN); + exit(0); + break; + + case 2: + dmVerbosity++; + break; + + case 3: + optOutFormat = JSS_AUDIO_S16; + break; + + case 4: + optOutFormat = JSS_AUDIO_U8; + break; + + case 5: + optOutChannels = JSS_AUDIO_MONO; + break; + + case 6: + optOutChannels = JSS_AUDIO_STEREO; + break; + + case 7: + optOutFreq = atoi(optArg); + break; + + case 8: + optMuteOChannels = atoi(optArg); + break; + + case 9: + optStartOrder = atoi(optArg); + break; + + case 10: + optPlayTime = atoi(optArg); + optUsePlayTime = TRUE; + break; + + default: + dmError("Unknown argument '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char *currArg) +{ + if (!optInFilename) + optInFilename = currArg; + else + if (!optOutFilename) + optOutFilename = currArg; + else + { + dmError("Too many filename arguments (only source and dest needed) '%s'\n", currArg); + return FALSE; + } + + return TRUE; +} + + +int main(int argc, char *argv[]) +{ + DMResource *inFile = NULL; + FILE *outFile = NULL; + JSSModule *mod = NULL; + JSSMixer *dev = NULL; + JSSPlayer *plr = NULL; + int result = -1; + size_t bufLen = 1024*4, dataTotal, dataWritten, sampSize; + Uint8 *mb = NULL; + + dmInitProg("mod2wav", "XM/JSSMOD to WAV renderer", "0.2", NULL, NULL); + dmVerbosity = 1; + + // Parse arguments + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, argHandleFile, TRUE)) + exit(1); + + // Check arguments + if (optInFilename == NULL || optOutFilename == NULL) + { + dmError("Input or output file not specified. Try --help.\n"); + return 1; + } + + // Initialize miniJSS + jssInit(); + + // Open the source file + if ((inFile = dmf_create_stdio(optInFilename, "rb")) == NULL) + { + dmError("Error opening input file '%s', %d: %s\n", + optInFilename, errno, strerror(errno)); + return 1; + } + + // Read module file + fprintf(stderr, "Reading file: %s\n", optInFilename); +#ifdef JSS_SUP_XM + fprintf(stderr, "* Trying XM...\n"); + result = jssLoadXM(inFile, &mod); +#endif +#ifdef JSS_SUP_JSSMOD + if (result != 0) + { + size_t bufgot, bufsize = dmfsize(inFile); + Uint8 *buf = dmMalloc(bufsize); + dmfseek(inFile, 0L, SEEK_SET); + fprintf(stderr, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf); + if ((bufgot = dmfread(buf, 1, bufsize, inFile)) != bufsize) + { + fprintf(stderr, "Error reading file (not enough data %d), #%d: %s\n", + bufgot, dmferror(inFile), dmErrorStr(dmferror(inFile))); + return 2; + } + result = jssLoadJSSMOD(buf, bufsize, &mod); + dmFree(buf); + } +#endif + dmf_close(inFile); + if (result != DMERR_OK) + { + dmError("Error loading module file, %d: %s\n", + result, dmErrorStr(result)); + return 3; + } + + // Try to convert it + if ((result = jssConvertModuleForPlaying(mod)) != DMERR_OK) + { + dmError("Could not convert module for playing, %d: %s\n", + result, dmErrorStr(result)); + return 3; + } + + // Open mixer + dev = jvmInit(optOutFormat, optOutChannels, optOutFreq, JMIX_AUTO); + if (dev == NULL) + { + dmError("jvmInit() returned NULL\n"); + return 4; + } + + sampSize = jvmGetSampleSize(dev); + if ((mb = dmMalloc(bufLen * sampSize)) == NULL) + { + dmError("Could not allocate mixing buffer\n"); + return 5; + } + + dmMsg(1, "Using fmt=%d, bits=%d, channels=%d, freq=%d [%d / sample]\n", + optOutFormat, jvmGetSampleRes(dev), optOutChannels, optOutFreq, + sampSize); + + // Initialize player + if ((plr = jmpInit(dev)) == NULL) + { + dmError("jmpInit() returned NULL.\n"); + return 6; + } + + // Set callback + jvmSetCallback(dev, jmpExec, plr); + + // Initialize playing + jmpSetModule(plr, mod); + if (optStartOrder >= 0) + { + dmMsg(1, "Starting from song order #%d\n", optStartOrder); + } else + optStartOrder = 0; + + jmpPlayOrder(plr, optStartOrder); + jvmSetGlobalVol(dev, 150); + + if (optMuteOChannels > 0 && optMuteOChannels <= mod->nchannels) + { + int i; + for (i = 0; i < mod->nchannels; i++) + jvmMute(dev, i, TRUE); + jvmMute(dev, optMuteOChannels - 1, FALSE); + } + + // Open output file + if ((outFile = fopen(optOutFilename, "wb")) == NULL) + { + dmError("Error opening output file '%s'. (%s)\n", optInFilename, strerror(errno)); + return 7; + } + + // Write initial header + dmWriteWAVHeader(outFile, jvmGetSampleRes(dev), optOutFreq, optOutChannels, 1024); + + // Render audio data and output to file + if (optUsePlayTime) + dmMsg(1, "Rendering module (%d seconds) ...\n", optPlayTime); + else + dmMsg(1, "Rendering module ...\n"); + + optPlayTime *= optOutFreq; + dataTotal = 0; + dataWritten = 1; + while (plr->isPlaying && dataWritten > 0) + { + size_t writeLen = bufLen; + if (optUsePlayTime && (writeLen + dataTotal) > optPlayTime) + writeLen = optPlayTime - dataTotal; + + if (writeLen > 0) + { + jvmRenderAudio(dev, mb, writeLen); +#if (SDL_BYTEORDER == SDL_BIG_ENDIAN) + jssEncodeSample16((Uint16 *)mb, writeLen * optOutChannels, jsampSwapEndianess); +#endif + dataWritten = fwrite(mb, sampSize, writeLen, outFile); + if (dataWritten < writeLen) + { + dmError("Error writing data!\n"); + fclose(outFile); + return 8; + } + dataTotal += dataWritten; + } + + if (optUsePlayTime && dataTotal >= optPlayTime) + break; + } + + // Write the correct header + if (fseek(outFile, 0L, SEEK_SET) != 0) + { + dmError("Error rewinding to header position!\n"); + return 9; + } + + dmWriteWAVHeader(outFile, jvmGetSampleRes(dev), optOutFreq, optOutChannels, dataTotal); + + // Done! + fclose(outFile); + + jmpClose(plr); + jvmClose(dev); + jssFreeModule(mod); + jssClose(); + + dmMsg(1, "OK.\n"); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/objlink.c Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,990 @@ +/* + * objlink - Link files (RAW and PRG) into one PRG object + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2002-2012 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#include <errno.h> +#include "dmlib.h" +#include "dmargs.h" +#include "dmfile.h" +#include "dmmutex.h" + +#define MAX_FILENAMES (128) +#define MAX_MEMBLOCKS (128) + + +/* Typedefs + */ +typedef struct +{ + ssize_t start, end; // Start and end address + int type; // Type + char *name; // Name of the block + int placement; +} DMMemBlock; + +typedef struct +{ + char *name; // Description of memory model + char *desc; + ssize_t size; // Total addressable memory size + ssize_t nmemBlocks; // Defined memory areas + DMMemBlock memBlocks[MAX_MEMBLOCKS]; +} DMMemModel; + +typedef struct +{ + char *filename; + int type; + int placement; + ssize_t addr; +} DMSourceFile; + +// Source file type +enum +{ + STYPE_RAW = 1, + STYPE_PRG, + STYPE_PRGA +}; + +// How to determine block placement / address +enum +{ + PLACE_STATIC = 1, // Already known + PLACE_ARGUMENT, // Commandline argument + PLACE_FILE, // From file +}; + +enum +{ + FMT_GENERIC = 1, + FMT_PLAIN, + FMT_DECIMAL +}; + +enum +{ + MTYPE_NONE = 0, + MTYPE_ROM, // Hard ROM + MTYPE_ROM_WT, // Write to RAM through ROM + MTYPE_IO, // I/O lines + MTYPE_RES // RESERVED +}; + +enum +{ + LA_NONE = -2, + LA_AUTO = -1 +}; + +/* Memory models + */ +const DMMemModel memoryModels[] = { + { "C64 unrestricted", "$01 = $34", (64*1024), 0, { + { 0, 0, 0, NULL, 0 } + }}, + + { "C64 normal (IO+Basic+Kernal)", "$01 = $37", (64*1024), 3, { + { 0xA000, 0xBFFF, MTYPE_ROM_WT, "Basic ROM", PLACE_STATIC }, + { 0xD000, 0xDFFF, MTYPE_IO, "I/O", PLACE_STATIC }, + { 0xE000, 0xFFFF, MTYPE_ROM_WT, "Kernal ROM", PLACE_STATIC }, + }}, + + { "C64 modified (IO+Kernal)", "$01 = $36", (64*1024), 2, { + { 0xD000, 0xDFFF, MTYPE_IO, "I/O", PLACE_STATIC }, + { 0xE000, 0xFFFF, MTYPE_ROM_WT, "Kernal ROM", PLACE_STATIC }, + }}, + + { "C64 modified (IO only)", "$01 = $35", (64*1024), 1, { + { 0xD000, 0xDFFF, MTYPE_IO, "I/O", PLACE_STATIC }, + }}, + + { "C64 modified (Char+Kernal+Basic)", "$01 = $33", (64*1024), 3, { + { 0xA000, 0xBFFF, MTYPE_ROM_WT, "Basic ROM", PLACE_STATIC }, + { 0xD000, 0xDFFF, MTYPE_ROM, "Char ROM", PLACE_STATIC }, + { 0xE000, 0xFFFF, MTYPE_ROM_WT, "Kernal ROM", PLACE_STATIC }, + }}, + +/* + { "C64 normal", "$01 = $37", (64*1024), 0, { + { 0x0000, 0x0000, MTYPE_RAM, "" }, + }}, +*/ +}; + +static const int nmemoryModels = sizeof(memoryModels) / sizeof(memoryModels[0]); + + +/* Global variables + */ +int nsrcFiles = 0; // Number of source files +DMSourceFile srcFiles[MAX_FILENAMES]; // Source file names + +int nmemBlocks = 0; +DMMemBlock memBlocks[MAX_FILENAMES]; + +char *optLinkFileName = NULL; +int optLinkFileFormat = FMT_GENERIC; + +BOOL optDescribe = FALSE, + optAllowOverlap = FALSE; + +Uint32 optInitValue = 0; +int optInitValueType = 1; +ssize_t optCropStart, optCropEnd; +BOOL optCropOutput = FALSE; + +ssize_t optLoadAddress = LA_AUTO; + +int optMemModel = 0; +const DMMemModel *memModel = NULL; +Uint8 *memory = NULL; + +char *optDestName = NULL; + + +/* Arguments + */ +static DMOptArg optList[] = { + { 0, '?', "help", "Show this help", OPT_NONE }, + { 1, 'r', "input-raw", "RAW input: -r <file>:<addr>", OPT_ARGREQ }, + { 2, 'p', "input-prg", "PRG input: -p <file>[:<addr>]", OPT_ARGREQ }, + { 12, 's', "section", "Reserved section: -s <start>-<end>[,name] or <start>:<len>[,name]", OPT_ARGREQ }, + { 5, 'o', "output", "Specify output file, -o <file>", OPT_ARGREQ }, + { 6, 'O', "overlap", "Allow overlapping memory areas", OPT_NONE }, + { 7, 'm', "model", "Set memory model", OPT_ARGREQ }, + { 8, 'l', "link-file", "Output addresses and labels into file", OPT_ARGREQ }, + { 9, 'f', "format", "Format of link-file: (g)eneric, (p)lain, (d)ecimal", OPT_ARGREQ }, + { 10, 'i', "initvalue", "Initialize memory with: -i <byte/word/dword>:[bwd]", OPT_ARGREQ }, + { 11, 'd', "describe", "Output ASCII memory map description", OPT_NONE }, + { 13, 'c', "crop", "Crop output file to: -c <start>-<end> or <start>:<len>", OPT_ARGREQ }, + { 14, 'L', "load-address","Set output file load address (or 'none' for 'raw' output)", OPT_ARGREQ }, +}; + +static const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + int i; + + dmPrintBanner(stdout, dmProgName, "[options]"); + dmArgsPrintHelp(stdout, optList, optListN); + + printf( + "\n" + "Each numeric argument can be prefixed with $ or 0x for hexadecimal values.\n" + "NOTICE! -p filename:<addr> will ignore load address and use <addr> instead!\n" + "\n" + "Available memory models:\n"); + + for (i = 0; i < nmemoryModels; i++) + { + const DMMemModel *m = &memoryModels[i]; + printf(" %d = %-40s [%s] (%d kB)\n", + i, m->name, m->desc, m->size / 1024); + } +} + + +off_t dmGetFileSize(FILE *f) +{ + off_t len, pos = ftell(f); + fseeko(f, 0, SEEK_END); + len = ftell(f); + fseek(f, pos, SEEK_SET); + return len; +} + + +/* Memory block handling + */ +void reserveMemBlock(ssize_t startAddr, ssize_t endAddr, const char *blockName, int blockType) +{ + if (startAddr > endAddr) + { + dmError("ERROR! Block '%s' has startAddr=$%.4x > endAddr=$%.4x!\n", + blockName, startAddr, endAddr); + exit(4); + } + + if (nmemBlocks < MAX_FILENAMES) + { + memBlocks[nmemBlocks].start = startAddr; + memBlocks[nmemBlocks].end = endAddr; + memBlocks[nmemBlocks].name = dm_strdup(blockName); + memBlocks[nmemBlocks].type = blockType; + nmemBlocks++; + } + else + { + dmError("Maximum number of memBlock definitions (%d) exceeded!\n", + MAX_FILENAMES); + exit(4); + } +} + + +int compareMemBlock(const void *cva, const void *cvb) +{ + const DMMemBlock *a = cva, *b = cvb; + return a->start - b->start; +} + + +BOOL dmParseSection(const char *arg, ssize_t *sectStart, ssize_t *sectEnd, char **sectName, BOOL canHasName) +{ + char sectMode, *sep, *str, *namesep; + ssize_t tmpi; + + // Define reserved section + // Create a copy of the argument + if ((str = dm_strdup(arg)) == NULL) + { + dmError("Could not allocate temporary string!\n"); + exit(128); + } + + // Get start address + if ((sep = strchr(str, '-')) == NULL && + (sep = strchr(str, ':')) == NULL) + { + dmError("Section definition '%s' invalid.\n", arg); + goto error; + } + sectMode = *sep; + *sep = 0; + + // Get value + if (!dmGetIntVal(str, sectStart)) + { + dmError("Section start address '%s' in '%s' invalid.\n", str, arg); + goto error; + } + + // Check for name + namesep = strchr(sep + 1, ','); + if (canHasName && namesep != NULL) + { + *namesep = 0; + namesep++; + if (*namesep == 0) + { + dmError("Section definition '%s' name is empty. Either specify name or leave it out.\n", + arg); + goto error; + } + *sectName = dm_strdup(namesep); + } + else + if (namesep != NULL) + { + dmError("Section definition does not allow a name, syntax error in '%s' at '%s'.\n", + arg, namesep); + goto error; + } + + // Get end address or length + if (!dmGetIntVal(sep + 1, &tmpi)) + { + dmError("Section %s '%s' in '%s' invalid.\n", + sectMode == '-' ? "end address" : "length", + sep + 1, arg); + goto error; + } + + if (sectMode == ':') + { + *sectEnd = *sectStart + tmpi - 1; + } + else + { + if (tmpi < *sectStart) + { + dmError("Section start address > end address in '%s'.\n", + arg); + goto error; + } + *sectEnd = tmpi; + } + + dmFree(str); + return TRUE; + +error: + dmFree(str); + return FALSE; +} + + +BOOL dmParseInputFile(char *arg, const int type1, const int type2, const char *desc, BOOL requireAddr) +{ + ssize_t tmpi = 0; + BOOL hasAddr = FALSE; + char *sep; + + if ((sep = strrchr(arg, ':')) != NULL) + { + *sep = 0; + if (!dmGetIntVal(sep + 1, &tmpi)) + { + dmError("Invalid %s address '%s' specified for '%s'.\n", + desc, sep + 1, arg); + return FALSE; + } + hasAddr = TRUE; + } + else + if (requireAddr) + { + dmError("No %s loading address specified for '%s'.\n", desc, arg); + return FALSE; + } + + srcFiles[nsrcFiles].filename = arg; + srcFiles[nsrcFiles].type = hasAddr ? type1 : type2; + srcFiles[nsrcFiles].addr = tmpi; + nsrcFiles++; + return TRUE; +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + char *p; + ssize_t tmpi; + + switch (optN) { + case 0: + argShowHelp(); + exit(0); + break; + + case 1: + // Add RAW + if (!dmParseInputFile(optArg, STYPE_RAW, STYPE_RAW, "RAW", TRUE)) + return FALSE; + break; + + case 2: + // Add PRG + if (!dmParseInputFile(optArg, STYPE_PRGA, STYPE_PRG, "PRG", FALSE)) + return FALSE; + break; + + case 5: + // Set output file name + optDestName = optArg; + break; + + case 6: + // Allow overlapping segments + optAllowOverlap = TRUE; + dmError("Warning, allowing overlapping data.\n"); + break; + + case 7: + // Set memory model + optMemModel = atoi(optArg); + if (optMemModel < 0 || optMemModel >= nmemoryModels) + { + dmError("Invalid memory model number %i!\n", optMemModel); + return FALSE; + } + break; + + case 8: + // Linker file + optLinkFileName = optArg; + break; + + case 9: + // Linker file format + switch (tolower(optArg[0])) + { + case 'g': + optLinkFileFormat = FMT_GENERIC; + break; + case 'p': + optLinkFileFormat = FMT_PLAIN; + break; + case 'd': + optLinkFileFormat = FMT_DECIMAL; + break; + + default: + dmError("Invalid/unknown linker file format '%s'!\n", + optArg); + return FALSE; + } + break; + + case 10: + // Initialization value + optInitValueType = 1; + if ((p = strrchr(optArg, ':')) != NULL) + { + *p = 0; + switch (tolower(p[1])) + { + case 'b': optInitValueType = 1; break; + case 'w': optInitValueType = 2; break; + case 'd': optInitValueType = 4; break; + default: + dmError("Invalid init value type '%c' specified for '%s'.\n", + p[1], optArg); + return FALSE; + } + } + if (!dmGetIntVal(optArg, &tmpi)) + { + dmError("Invalid initvalue '%s'.\n", optArg); + return FALSE; + } + optInitValue = tmpi; + break; + + case 11: + // Set describe mode + optDescribe = TRUE; + break; + + case 12: + { + char *sectName = "Clear"; + ssize_t sectStart, sectEnd, sectLen; + if (!dmParseSection(optArg, §Start, §End, §Name, TRUE)) + return FALSE; + + // Allocate memory block + sectLen = sectEnd - sectStart + 1; + dmMsg(1, "Reserve $%.4x - $%.4x ($%x, %d bytes) as '%s'\n", + sectStart, sectEnd, sectLen, sectLen, sectName); + + reserveMemBlock(sectStart, sectEnd, sectName, MTYPE_RES); + } + break; + + case 13: + { + size_t cropLen; + if (!dmParseSection(optArg, &optCropStart, &optCropEnd, NULL, FALSE)) + return FALSE; + + cropLen = optCropEnd - optCropEnd + 1; + dmMsg(1, "Cutting output to $%.4x - $%.4x ($%x, %d bytes)\n", + optCropStart, optCropEnd, cropLen, cropLen); + + optCropOutput = TRUE; + } + break; + + case 14: + // Set loading address + if (strcasecmp(optArg, "none") == 0) + optLoadAddress = LA_NONE; + else + { + if (!dmGetIntVal(optArg, &tmpi)) + { + dmError("Invalid loading address '%s'.\n", optArg); + return FALSE; + } + if (tmpi < 0 || tmpi >= 64*1024) + { + dmError("Invalid or insane loading address %d/$%x!\n", + tmpi); + return FALSE; + } + optLoadAddress = tmpi; + } + break; + + default: + dmError("Unknown argument '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +int dmLoadPRG(const char *filename, BOOL forceAddr, const ssize_t destAddr) +{ + FILE *f; + ssize_t dataSize, loadAddr, endAddr; + Uint16 tmpAddr; + + // Open the input file + if ((f = fopen(filename, "rb")) == NULL) + { + dmError("Error opening input file '%s' (%s).\n", + filename, strerror(errno)); + return 1; + } + + // Get filesize + if ((dataSize = dmGetFileSize(f) - 2) < 0) + { + dmError("Error getting file size for '%s'.\n", filename); + return 6; + } + + // Get loading address + if (!dm_fread_le16(f, &tmpAddr)) + { + dmError("Error reading input file '%s' (%s).\n", + filename, strerror(errno)); + return 2; + } + + // Show information + loadAddr = forceAddr ? destAddr : tmpAddr; + endAddr = loadAddr + dataSize - 1; + + dmPrint(1, "* Loading '%s', %s at $%.4x-$%.4x", + filename, forceAddr ? "PRGA" : "PRG", loadAddr, endAddr); + + if (endAddr >= memModel->size) + { + dmPrint(1, " .. Does not fit into the memory!\n"); + return 5; + } + + // Load data + if (fread(&memory[loadAddr], dataSize, 1, f) < 1) + { + dmPrint(1, " .. Error: %s.\n", + strerror(errno)); + return 4; + } + + dmPrint(1, " .. OK\n"); + + // Add to list of blocks + reserveMemBlock(loadAddr, endAddr, filename, MTYPE_RES); + + return 0; +} + + +int dmLoadRAW(const char *filename, const ssize_t destAddr) +{ + FILE *f; + ssize_t dataSize, endAddr; + + // Open the input file + if ((f = fopen(filename, "rb")) == NULL) + { + dmError("Error opening input file '%s' (%s).\n", + filename, strerror(errno)); + return 1; + } + + // Get filesize + if ((dataSize = dmGetFileSize(f)) < 0) + { + dmError("Error getting file size for '%s'.\n", filename); + return 6; + } + + // Show information + endAddr = destAddr + dataSize - 1; + dmPrint(1, "* Loading '%s', RAW at $%.4x-$%.4x", + filename, destAddr, endAddr); + + if (endAddr >= memModel->size) + { + dmPrint(1, " .. Does not fit into the memory!\n"); + return 5; + } + + // Load data + if (fread(&memory[destAddr], dataSize, 1, f) < 1) + { + dmPrint(1, " .. Error: %s.\n", + strerror(errno)); + return 4; + } + + dmPrint(1, " .. OK\n"); + + // Add info to list + reserveMemBlock(destAddr, endAddr, filename, MTYPE_RES); + + return 0; +} + + +int outputLinkData(FILE *dfile, const char *blockName, const int blockStart, const int blockEnd) +{ + char *tmpStr, *s, *t; + int blockSize; + + blockSize = (blockEnd - blockStart + 1); + + // Create label name from filename + tmpStr = dm_strdup(blockName); + if (tmpStr == NULL) + { + dmError("Could not allocate memory for string '%s'!\n", + blockName); + return -1; + } + + if ((t = strrchr(tmpStr, '/'))) + s = (t + 1); + else if ((t = strrchr(tmpStr, '\\'))) + s = (t + 1); + else + s = tmpStr; + + if ((t = strrchr(s, '.'))) + *t = 0; + + for (t = s; *t; t++) + { + if (!isalnum(*t)) + *t = '_'; + } + + // Print the label line + switch (optLinkFileFormat) + { + case FMT_PLAIN: + fprintf(dfile, "%s = $%.4x\n", tmpStr, blockStart); + break; + + case FMT_DECIMAL: + fprintf(dfile, "%s = %d\n", tmpStr, blockStart); + break; + + case FMT_GENERIC: + default: + fprintf(dfile, "; %s ($%.4x - $%.4x, %d/$%x bytes)\n", + blockName, blockStart, blockEnd, blockSize, blockSize); + fprintf(dfile, "%s = $%.4x\n", s, blockStart); + break; + } + + dmFree(tmpStr); + return 0; +} + + +/* Print out an ASCII presentation of memory map + */ +void memPrintLine(FILE *f) +{ + fprintf(f, " +------------------------------------------+\n"); +} + +void memPrintEmpty(FILE *f, ssize_t n) +{ + ssize_t i; + for (i = 0; i < n; i++) + fprintf(f, " | |\n"); +} + +void dmDescribeMemory(FILE *f) +{ + int i; + DMMemBlock *prev = NULL; + + memPrintLine(f); + + for (i = 0; i < nmemBlocks; i++) + { + DMMemBlock *curr = &memBlocks[i]; + char desc[512], *s; + ssize_t siz, kz; + + // Check for empty, unreserved areas + siz = (curr->start - 1) - (prev->end + 1) + 1; + if (prev != NULL && siz > 1) + { + kz = siz / (1024 * 2); + + if (kz > 1) memPrintEmpty(f, kz); + + snprintf(desc, sizeof(desc), "EMPTY (%d)", siz); + fprintf(f, "$%.4x - $%.4x | %-40s |\n", prev->end + 1, curr->start - 1, desc); + + if (kz > 1) memPrintEmpty(f, kz); + memPrintLine(f); + } + prev = curr; + + // Print current block + switch (curr->type) + { + case MTYPE_NONE: s = "N/A (NC)"; break; + case MTYPE_ROM: s = "ROM"; break; + case MTYPE_ROM_WT: s = "ROM/WT"; break; + case MTYPE_IO: s = "I/O"; break; + case MTYPE_RES: s = "RSVD"; break; + default: s = "????"; break; + } + + siz = curr->end - curr->start + 1; + kz = siz / (1024 * 2); + + if (kz > 1) memPrintEmpty(f, kz); + snprintf(desc, sizeof(desc), "%s (%s, %d)", curr->name, s, siz); + fprintf(f, "$%.4x - $%.4x | %-40s |\n", curr->start, curr->end, desc); + if (kz > 1) memPrintEmpty(f, kz); + memPrintLine(f); + + } + + fprintf(f, + "\n" + "NC = Not Connected\n" + "RSVD = Reserved\n" + "ROM/WT = RAM under 'write-through' ROM\n" + "\n" + ); +} + + +/* + * The main program + */ +int main(int argc, char *argv[]) +{ + FILE *dfile = NULL; + BOOL hasOverlaps; + int i, j; + ssize_t startAddr, endAddr, dataSize, totalSize; + + dmInitProg("objlink", "Simple file-linker", "0.80", NULL, NULL); + dmVerbosity = 1; + + // Parse arguments + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, NULL, TRUE)) + exit(1); + + if (nsrcFiles < 1) + { + dmError("Nothing to do. (try --help)\n"); + exit(0); + } + + // Allocate memory + memModel = &memoryModels[optMemModel]; + dmMsg(1, "Using memory model #%d '%s', %d bytes.\n", + optMemModel, memModel->name, memModel->size); + + memory = (Uint8 *) dmMalloc(memModel->size + 32); + if (memory == NULL) + { + dmError("Could not allocate memory.\n"); + exit(2); + } + + // Initialize memory + dmMsg(1, "Initializing memory with "); + + if (optInitValueType == 1 || optInitValue <= 0xff) + { + dmPrint(1, "BYTE 0x%.2x\n", optInitValue); + memset(memory, optInitValue, memModel->size); + } + else + if (optInitValueType == 2 || optInitValue <= 0xffff) + { + uint16_t *mp = (uint16_t *) memory; + dmPrint(1, "WORD 0x%.4x\n", optInitValue); + for (i = memModel->size / sizeof(*mp); i; i--) + { + *mp++ = optInitValue; + } + } + else + { + Uint32 *mp = (Uint32 *) memory; + dmPrint(1, "DWORD 0x%.8x\n", optInitValue); + for (i = memModel->size / sizeof(*mp); i; i--) + { + *mp++ = optInitValue; + } + } + + // Load the datafiles + for (i = 0; i < nsrcFiles; i++) + switch (srcFiles[i].type) + { + case STYPE_RAW: + dmLoadRAW(srcFiles[i].filename, srcFiles[i].addr); + break; + + case STYPE_PRG: + dmLoadPRG(srcFiles[i].filename, FALSE, 0); + break; + + case STYPE_PRGA: + dmLoadPRG(srcFiles[i].filename, TRUE, srcFiles[i].addr); + break; + } + + // Add memory model blocks + dmMsg(1, "Applying memory model restrictions...\n"); + for (i = 0; i < memModel->nmemBlocks; i++) + { + reserveMemBlock( + memModel->memBlocks[i].start, + memModel->memBlocks[i].end, + memModel->memBlocks[i].name, + memModel->memBlocks[i].type); + } + + // Sort the blocks + qsort(memBlocks, nmemBlocks, sizeof(DMMemBlock), compareMemBlock); + + // Check for overlapping conflicts + hasOverlaps = FALSE; + for (i = 0; i < nmemBlocks; i++) + for (j = 0; j < nmemBlocks; j++) + if (j != i && memBlocks[i].type == MTYPE_RES) + { + DMMemBlock *mbi = &memBlocks[i], + *mbj = &memBlocks[j]; + + // Check for per-file conflicts + if ((mbj->start >= mbi->start && mbj->start <= mbi->end) || + (mbj->end >= mbi->start && mbj->end <= mbi->end)) + { + dmPrint(1, "* '%s' and '%s' overlap ($%.4x-$%.4x vs $%.4x-$%.4x)\n", + mbi->name, mbj->name, mbi->start, + mbi->end, mbj->start, mbj->end); + hasOverlaps = TRUE; + } + } + + if (!optAllowOverlap && hasOverlaps) + { + dmError("Error occured, overlaps not allowed.\n"); + exit(5); + } + + // Find out start and end-addresses + startAddr = memModel->size; + totalSize = endAddr = 0; + for (i = 0; i < nmemBlocks; i++) + { + DMMemBlock *mbi = &memBlocks[i]; + if (mbi->type == MTYPE_RES) + { + if (mbi->start < startAddr) + startAddr = mbi->start; + + if (mbi->end > endAddr) + endAddr = mbi->end; + + totalSize += (mbi->end - mbi->start + 1); + } + } + + if (startAddr >= memModel->size || endAddr < startAddr) + { + dmError("Invalid saveblock addresses (start=$%.4x, end=$%.4x)!\n", startAddr, endAddr); + exit(8); + } + + // Output linkfile + if (optLinkFileName) + { + dmMsg(1, "Writing linkfile to '%s'\n", optLinkFileName); + if ((dfile = fopen(optLinkFileName, "wb")) == NULL) + { + dmError("Error creating file '%s' (%s).\n", optLinkFileName, strerror(errno)); + exit(1); + } + + switch (optLinkFileFormat) + { + case FMT_GENERIC: + default: + fprintf(dfile, "; Definitions generated by %s v%s\n", + dmProgName, dmProgVersion); + break; + } + + for (i = 0; i < nmemBlocks; i++) + { + DMMemBlock *mbi = &memBlocks[i]; + outputLinkData(dfile, mbi->name, mbi->start, mbi->end); + } + + fclose(dfile); + } + + // Show some information + if (optCropOutput) + { + startAddr = optCropStart; + endAddr = optCropEnd; + } + + dataSize = endAddr - startAddr + 1; + + if (dataSize - totalSize > 0) + { + dmMsg(1, "Total of %d/$%x bytes unused(?) areas.\n", + dataSize - totalSize, dataSize - totalSize); + } + + dmMsg(1, "Writing $%.4x - $%.4x (%d/$%x bytes) ", + startAddr, endAddr, dataSize, dataSize); + + + // Open the destination file + if (optDestName == NULL) + { + dfile = stdout; + dmPrint(1, "...\n"); + } + else if ((dfile = fopen(optDestName, "wb")) == NULL) + { + dmError("Error creating output file '%s' (%s).\n", optDestName, strerror(errno)); + exit(1); + } + else + dmPrint(1, "to '%s'\n", optDestName); + + // Save loading address + if (optLoadAddress >= 0) + { + dmMsg(1, "Using specified loading address $%.4x\n", optLoadAddress); + dm_fwrite_le16(dfile, optLoadAddress); + } + else + if (optLoadAddress == LA_AUTO) + { + dmMsg(1, "Using automatic loading address $%.4x\n", startAddr); + dm_fwrite_le16(dfile, startAddr); + } + else + { + dmMsg(1, "Writing raw output, without loading address.\n"); + } + + // Save the data + if (fwrite(&memory[startAddr], dataSize, 1, dfile) < 1) + { + dmError("Error writing to file (%s)\n", strerror(errno)); + } + + fclose(dfile); + + // Describe + if (optDescribe) + dmDescribeMemory(stdout); + + exit(0); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/packed.c Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,465 @@ +/* + * PACKed - PACKfile EDitor + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2011 Tecnic Software productions (TNSP) + */ +#include "dmlib.h" +#include "dmargs.h" +#include "dmpack.h" +#include "dmpackutil.h" +#include "dmres.h" +#include "dmmutex.h" +#include <errno.h> + +#define SET_MAX_FILES (4096) +#define SET_DEFAULT_PACK "data.pak" + +enum +{ + CMD_NONE = 0, + CMD_CREATE, + CMD_ADD, + CMD_LIST, + CMD_EXTRACT +} DCOMMAND; + +enum +{ + PACK_EXTRACTED = 0x0001, +}; + +int nsrcFilenames = 0; +char * srcFilenames[SET_MAX_FILES]; +char * optPackFilename = NULL; +BOOL optCompress = TRUE; +int optCommand = CMD_NONE; +int optDefResFlags = 0; + + +static DMOptArg optList[] = +{ + { 0, '?', "help", "Show this help", OPT_NONE }, + { 1, 'p', "pack", "Set pack filename (default: " SET_DEFAULT_PACK ")", OPT_ARGREQ }, + { 2, 'c', "create", "Create and add files to PACK", OPT_NONE }, + { 3, 'a', "add", "Add files to PACK", OPT_NONE }, + { 4, 'l', "list", "List files in PACK", OPT_NONE }, + { 5, 'e', "extract", "Extract files from PACK", OPT_NONE }, + { 6, 'n', "nocompress", "No compression", OPT_NONE }, + { 7, 'v', "verbose", "Increase verbosity", OPT_NONE }, + { 8, 'f', "resflags", "Set default resource flags (-f 0xff)", OPT_ARGREQ }, +}; + +static const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + dmPrintBanner(stdout, dmProgName, "[options] [-p <packfilename>] [filename[s]]"); + dmArgsPrintHelp(stdout, optList, optListN); + fprintf(stdout, + "\n" + "Examples:\n" + "$ %s -p test.pak -l -- list files in test.pak\n" + "$ %s -a foobar.jpg -- add foobar.jpg in " SET_DEFAULT_PACK "\n" + "$ %s -x foobar.jpg -- extract foobar.jpg from " SET_DEFAULT_PACK "\n", + dmProgName, dmProgName, dmProgName); +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + (void) optArg; + switch (optN) + { + case 0: + argShowHelp(); + exit(0); + break; + + case 1: + optPackFilename = optArg; + break; + case 2: + optCommand = CMD_CREATE; + break; + case 3: + optCommand = CMD_ADD; + break; + case 4: + optCommand = CMD_LIST; + break; + case 5: + optCommand = CMD_EXTRACT; + break; + + case 6: + optCompress = FALSE; + break; + + case 7: + dmVerbosity++; + break; + + case 8: + { + int i; + if (!dmGetIntVal(optArg, &i)) + { + dmError("Invalid flags value '%s'.\n", optArg); + return FALSE; + } + optDefResFlags = i; + } + break; + + default: + dmError("Unknown argument '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char *currArg) +{ + if (nsrcFilenames < SET_MAX_FILES) + { + srcFilenames[nsrcFilenames] = currArg; + nsrcFilenames++; + } + else + { + dmError("Maximum number of input files (%d) exceeded!\n", + SET_MAX_FILES); + return FALSE; + } + return TRUE; +} + + +/* Compare a string to a pattern. Case-SENSITIVE version. + * The matching pattern can consist of any normal characters plus + * wildcards ? and *. "?" matches any character and "*" matches + * any number of characters. + */ +BOOL dm_strmatch(const char *str, const char *pattern) +{ + BOOL didMatch = TRUE, isAnyMode = FALSE, isEnd = FALSE; + const char *tmpPattern = NULL; + + // Check given pattern and string + if (str == NULL || pattern == NULL) + return FALSE; + + // Start comparision + do { + didMatch = FALSE; + switch (*pattern) + { + case '?': + // Any single character matches + if (*str) + { + didMatch = TRUE; + pattern++; + str++; + } + break; + + case '*': + didMatch = TRUE; + pattern++; + if (!*pattern) + isEnd = TRUE; + isAnyMode = TRUE; + tmpPattern = pattern; + break; + + case 0: + if (isAnyMode) + { + if (*str) + str++; + else + isEnd = TRUE; + } + else + { + if (*str) + { + if (tmpPattern) + { + isAnyMode = TRUE; + pattern = tmpPattern; + } + else + didMatch = FALSE; + } + else + isEnd = TRUE; + } + break; + default: + if (isAnyMode) + { + if (*pattern == *str) + { + isAnyMode = FALSE; + didMatch = TRUE; + } + else + { + if (*str) + { + didMatch = TRUE; + str++; + } + } + } + else + { + if (*pattern == *str) + { + didMatch = TRUE; + if (*pattern) + pattern++; + if (*str) + str++; + } + else + { + if (tmpPattern) + { + didMatch = TRUE; + isAnyMode = TRUE; + pattern = tmpPattern; + } + } + } + + if (!*str && !*pattern) + isEnd = TRUE; + break; + + } // switch + + } while (didMatch && !isEnd); + + return didMatch; +} + + +int dmAddFileToPack(DMPackFile *pack, const char *filename, int compression, int resFlags) +{ + DMPackEntry *node; + int res = dm_pack_add_file(pack, filename, compression, resFlags, &node); + + if (res != DMERR_OK) + { + dmPrint(1, "%-32s [ERROR:%d]\n", + filename, res); + } + else + { + char tmp[16]; + dmres_flags_to_symbolic(tmp, sizeof(tmp), node->resFlags); + dmPrint(1, "%-32s ['%s', s=%d, c=%d, o=%ld, f=%s]\n", + filename, node->filename, + node->size, node->length, node->offset, + tmp); + } + + return res; +} + + +int main(int argc, char *argv[]) +{ + int i, res = 0; + DMPackFile *pack = NULL; + +#ifndef __WIN32 + stderr = stdout; +#endif + + // Parse arguments + dmInitProg("packed", "Pack File Editor", "0.4", NULL, NULL); + dmVerbosity = 1; + + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, argHandleFile, TRUE)) + exit(1); + + // Check PACK filename + if (optPackFilename == NULL) + optPackFilename = SET_DEFAULT_PACK; + + if (optCommand == CMD_NONE) + { + argShowHelp(); + dmError("Nothing to do.\n"); + exit(0); + return 0; + } + + dmMsg(1, "Processing %s ...\n", optPackFilename); + + // Execute command + switch (optCommand) + { + case CMD_CREATE: + case CMD_ADD: + switch (optCommand) + { + case CMD_CREATE: + dmMsg(1, "Creating new PACK\n"); + res = dm_pack_create(optPackFilename, &pack); + break; + + case CMD_ADD: + dmMsg(1, "Opening existing PACK\n"); + res = dm_pack_open(optPackFilename, &pack, FALSE); + break; + } + + // Add files into PACK + if (res == DMERR_OK) + { + dmMsg(1, "Adding %d files...\n", nsrcFilenames); + + for (i = 0; i < nsrcFilenames; i++) + { + // Handle resource definition files + if (srcFilenames[i][0] == '@') + { + } + else + { + dmAddFileToPack(pack, srcFilenames[i], optCompress, optDefResFlags); + } + } + + dmMsg(1, "w=%d\n", dm_pack_write(pack)); + dmMsg(1, "c=%d\n", dm_pack_close(pack)); + } + else + { + dmError("Could not open packfile, error #%d: %s\n", res, + dmErrorStr(res)); + } + break; + + case CMD_LIST: + // List files in PACK + res = dm_pack_open(optPackFilename, &pack, TRUE); + if (res == DMERR_OK) + { + DMPackEntry *node; + for (i = 0, node = pack->entries; node; i++) + node = node->next; + dmMsg(1, "%d files total\n", i); + + dmPrint(0, "%-32s | %8s | %8s | %8s | %s\n", + "Name", "Size", "CSize", "Offset", "ResFlags"); + + for (node = pack->entries; node != NULL; node = node->next) + { + BOOL match; + + // Check for matches + if (nsrcFilenames > 0) + { + match = FALSE; + for (i = 0; i < nsrcFilenames && !match; i++) + { + match = dm_strmatch(node->filename, srcFilenames[i]); + } + } + else + match = TRUE; + + if (match) + { + char flags[16]; + dmres_flags_to_symbolic(flags, sizeof(flags), node->resFlags); + + dmPrint(0, "%-32s | %8d | %8d | %08x | %s\n", + node->filename, node->size, node->length, + node->offset, flags); + } + } + + dmMsg(1, "c=%d\n", dm_pack_close(pack)); + } + else + dmError("Could not open packfile, error #%d: %s\n", res, + dmErrorStr(res)); + break; + + case CMD_EXTRACT: + // Extract files from PACK + res = dm_pack_open(optPackFilename, &pack, TRUE); + if (res == DMERR_OK) + { + DMPackEntry *node; + FILE *resFile = fopen(DMRES_RES_FILE, "w"); + if (resFile == NULL) + { + dmError("Could not create resource output file '%s' #%d: %s\n", + DMRES_RES_FILE, errno, strerror(errno)); + } + + for (node = pack->entries; node != NULL; node = node->next) + { + BOOL match; + + // Check for matches + if (nsrcFilenames > 0) + { + match = FALSE; + for (i = 0; (i < nsrcFilenames) && !match; i++) + { + match = dm_strmatch(node->filename, srcFilenames[i]); + } + } + else + match = TRUE; + + if (match && (node->privFlags & PACK_EXTRACTED) == 0) + { + char tmp[16]; + + // Mark as done + node->privFlags |= PACK_EXTRACTED; + + // Print one entry + dmres_flags_to_symbolic(tmp, sizeof(tmp), node->resFlags); + dmPrint(0, "Extracting: %-32s [siz=%d, cmp=%d, offs=0x%08x, flags=%s]\n", + node->filename, node->size, node->length, + node->offset, tmp); + + dm_pack_extract_file(pack, node); + + if (resFile != NULL) + { + fprintf(resFile, + "%s|%s\n", node->filename, tmp); + } + } + } + + dmMsg(1, "c=%d\n", dm_pack_close(pack)); + + if (resFile != NULL) + fclose(resFile); + } + else + dmError("Could not open packfile, error #%d: %s\n", res, + dmErrorStr(res)); + break; + + } + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/ppl.c Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,932 @@ +/* + * Cyrbe Pasci Player - A simple SDL-based UI for XM module playing + * 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 <SDL.h> +#include "dmlib.h" + +#include "jss.h" +#include "jssmod.h" +#include "jssmix.h" +#include "jssplr.h" + +#include "dmargs.h" +#include "dmimage.h" +#include "dmtext.h" + +#include "setupfont.h" + + +struct +{ + BOOL exitFlag; + SDL_Surface *screen; + SDL_Event event; + int optScrWidth, optScrHeight, optVFlags, optScrDepth; + + int actChannel; + BOOL pauseFlag; + + JSSModule *mod; + JSSMixer *dev; + JSSPlayer *plr; + SDL_AudioSpec afmt; +} engine; + +struct +{ + Uint32 boxBg, inboxBg, box1, box2, viewDiv, activeRow, activeChannel; +} col; + + +DMBitmapFont *font = NULL; + +char *optFilename = NULL; +int optOutFormat = JSS_AUDIO_S16, + optOutChannels = 2, + optOutFreq = 48000, + optMuteOChannels = -1, + optStartOrder = 0; +BOOL optUsePlayTime = FALSE; +size_t optPlayTime; + + +DMOptArg optList[] = +{ + { 0, '?', "help", "Show this help", OPT_NONE }, + { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, + { 2, 0, "fs", "Fullscreen", OPT_NONE }, + { 3, 'w', "window", "Initial window size/resolution -w 640x480", OPT_ARGREQ }, + + { 4, '1', "16bit", "16-bit output", OPT_NONE }, + { 5, '8', "8bit", "8-bit output", OPT_NONE }, + { 6, 'm', "mono", "Mono output", OPT_NONE }, + { 7, 's', "stereo", "Stereo output", OPT_NONE }, + { 8, 'f', "freq", "Output frequency", OPT_ARGREQ }, + + { 9, 'M', "mute", "Mute other channels than #", OPT_ARGREQ }, + { 10, 'o', "order", "Start from order #", OPT_ARGREQ }, + { 11, 't', "time", "Play for # seconds", OPT_ARGREQ }, +}; + +const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + dmPrintBanner(stdout, dmProgName, "[options] <module>"); + dmArgsPrintHelp(stdout, optList, optListN); +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + switch (optN) { + case 0: + argShowHelp(); + exit(0); + break; + + case 1: + dmVerbosity++; + break; + + case 2: + engine.optVFlags |= SDL_FULLSCREEN; + break; + + case 3: + { + int w, h; + if (sscanf(optArg, "%dx%d", &w, &h) == 2) + { + if (w < 320 || h < 200 || w > 3200 || h > 3200) + { + dmError("Invalid width or height: %d x %d\n", w, h); + return FALSE; + } + engine.optScrWidth = w; + engine.optScrHeight = h; + } + else + { + dmError("Invalid size argument '%s'.\n", optArg); + return FALSE; + } + } + break; + + case 4: + optOutFormat = JSS_AUDIO_S16; + break; + + case 5: + optOutFormat = JSS_AUDIO_U8; + break; + + case 6: + optOutChannels = JSS_AUDIO_MONO; + break; + + case 7: + optOutChannels = JSS_AUDIO_STEREO; + break; + + case 8: + optOutFreq = atoi(optArg); + break; + + case 9: + optMuteOChannels = atoi(optArg); + break; + + case 10: + optStartOrder = atoi(optArg); + break; + + case 11: + optPlayTime = atoi(optArg); + optUsePlayTime = TRUE; + break; + + default: + dmError("Unknown option '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char *currArg) +{ + if (!optFilename) + optFilename = currArg; + else + { + dmError("Too many filename arguments '%s'\n", currArg); + return FALSE; + } + + return TRUE; +} + + +void dmDrawBMTextConstQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt) +{ + const char *ptr = fmt; + DMUnscaledBlitFunc blit = NULL; + + while (*ptr) + { + int ch = *ptr++; + SDL_Surface *glyph; + + if (ch == '_') + { + xc += 4; + continue; + } + + if (ch >= 0 && ch < font->nglyphs && (glyph = font->glyphs[ch]) != NULL) + { + if (blit == NULL) + blit = dmGetUnscaledBlitFunc(glyph->format, screen->format, mode); + + blit(glyph, xc, yc, screen); + xc += font->width; + } + else + xc += font->width; + } +} + + +void dmDrawBMTextVAQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt, va_list ap) +{ + char tmp[512]; + vsnprintf(tmp, sizeof(tmp), fmt, ap); + dmDrawBMTextConstQ(screen, font, mode, xc, yc, tmp); +} + + +void dmDrawBMTextQ(SDL_Surface *screen, DMBitmapFont *font, int mode, int xc, int yc, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + dmDrawBMTextVAQ(screen, font, mode, xc, yc, fmt, ap); + va_end(ap); +} + + +Uint32 dmCol(float r, float g, float b) +{ + return dmMapRGB(engine.screen, 255.0f * r, 255.0f * g, 255.0f * b); +} + + +BOOL dmInitializeVideo() +{ + SDL_FreeSurface(engine.screen); + + engine.screen = SDL_SetVideoMode( + engine.optScrWidth, engine.optScrHeight, engine.optScrDepth, + engine.optVFlags | SDL_RESIZABLE | SDL_SWSURFACE | SDL_HWPALETTE); + + if (engine.screen == NULL) + { + dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); + return FALSE; + } + + col.inboxBg = dmCol(0.6, 0.5, 0.2); + col.boxBg = dmCol(0.7, 0.6, 0.3); + col.box1 = dmCol(1.0, 0.9, 0.6); + col.box2 = dmCol(0.3, 0.3, 0.15); + col.viewDiv = dmCol(0,0,0); + col.activeRow = dmCol(0.5,0.4,0.1); + col.activeChannel = dmCol(0.6, 0.8, 0.2); + + return TRUE; +} + + +void dmDisplayChn(SDL_Surface *screen, int x0, int y0, int x1, int y1, int nchannel, JSSChannel *chn) +{ + int yh = y1 - y0 - 2; + if (yh < 10 || chn == NULL) + return; + + int xc, ym = y0 + (y1 - y0) / 2, vol = FP_GETH(chn->chVolume); + int pitch = screen->pitch / sizeof(Uint32); + int len = FP_GETH(chn->chSize); + DMFixedPoint offs = chn->chPos; + Uint32 coln = dmCol(0.0, 0.8, 0.0), colx = dmCol(1.0, 0, 0); + Uint32 *pix = screen->pixels; + Sint16 *data = chn->chData; + + + dmFillBox3D(screen, x0, y0, x1, y1, + (chn->chMute ? dmCol(0.3,0.1,0.1) : dmCol(0,0,0)), + nchannel == engine.actChannel ? colx : col.box2, + nchannel == engine.actChannel ? colx : col.box1); + + if (chn->chData == NULL || !chn->chPlaying) + return; + + if (chn->chDirection) + { + for (xc = x0 + 1; xc < x1 - 1; xc++) + { + if (FP_GETH(offs) >= len) + break; + Sint16 val = ym + (data[FP_GETH(offs)] * yh * vol) / (65535 * 255); + pix[xc + val * pitch] = coln; + FP_ADD(offs, chn->chDeltaO); + } + } + else + { + for (xc = x0 + 1; xc < x1 - 1; xc++) + { + if (FP_GETH(offs) < 0) + break; + Sint16 val = ym + (data[FP_GETH(offs)] * yh * vol) / (65535 * 255); + pix[xc + val * pitch] = coln; + FP_SUB(offs, chn->chDeltaO); + } + } +} + + +void dmDisplayChannels(SDL_Surface *screen, int x0, int y0, int x1, int y1, JSSMixer *dev) +{ + int nchannel, qx, qy, + qwidth = x1 - x0, + qheight = y1 - y0, + nwidth = jsetNChannels, + nheight = 1; + + if (qheight < 40) + return; + + while (qwidth / nwidth <= 60 && qheight / nheight >= 40) + { + nheight++; + nwidth /= nheight; + } + +// fprintf(stderr, "%d x %d\n", nwidth, nheight); + + if (qheight / nheight <= 40) + { + nwidth = qwidth / 60; + nheight = qheight / 40; + } + + qwidth /= nwidth; + qheight /= nheight; + + for (nchannel = qy = 0; qy < nheight && nchannel < jsetNChannels; qy++) + { + for (qx = 0; qx < nwidth && nchannel < jsetNChannels; qx++) + { + int xc = x0 + qx * qwidth, + yc = y0 + qy * qheight; + + dmDisplayChn(screen, xc + 1, yc + 1, + xc + qwidth - 1, yc + qheight - 1, + nchannel, &dev->channels[nchannel]); + + nchannel++; + } + } +} + + +static const char patNoteTable[12][3] = +{ + "C-", "C#", "D-", + "D#", "E-", "F-", + "F#", "G-", "G#", + "A-", "A#", "B-" +}; + + +#define jmpNMODEffectTable (36) +static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + +static const char jmpHexTab[16] = "0123456789ABCDEF"; + +static inline char dmHexVal(int v) +{ + return jmpHexTab[v & 15]; +} + +void dmPrintNote(SDL_Surface *screen, int xc, int yc, JSSNote *n) +{ + char text[32]; + char *ptr = text; + + switch (n->note) + { + case jsetNotSet: + strcpy(ptr, "..._"); + break; + case jsetNoteOff: + strcpy(ptr, "===_"); + break; + default: + sprintf(ptr, "%s%i_", + patNoteTable[n->note % 12], + n->note / 12); + break; + } + + ptr += 4; + + if (n->instrument != jsetNotSet) + { + int v = n->instrument + 1; + *ptr++ = dmHexVal(v >> 4); + *ptr++ = dmHexVal(v); + } + else + { + *ptr++ = '.'; + *ptr++ = '.'; + } + *ptr++ = '_'; + + if (n->volume == jsetNotSet) + { + *ptr++ = '.'; + *ptr++ = '.'; + } + else + if (n->volume >= 0x00 && n->volume <= 0x40) + { + *ptr++ = dmHexVal(n->volume >> 4); + *ptr++ = dmHexVal(n->volume); + } + else + { + char c; + switch (n->volume & 0xf0) + { + case 0x50: c = '-'; break; + case 0x60: c = '+'; break; + case 0x70: c = '/'; break; + case 0x80: c = '\\'; break; + case 0x90: c = 'S'; break; + case 0xa0: c = 'V'; break; + case 0xb0: c = 'P'; break; + case 0xc0: c = '<'; break; + case 0xd0: c = '>'; break; + case 0xe0: c = 'M'; break; + default: c = '?'; break; + } + *ptr++ = c; + *ptr++ = dmHexVal(n->volume); + } + *ptr++ = '_'; + + if (n->effect >= 0 && n->effect < jmpNMODEffectTable) + *ptr++ = jmpMODEffectTable[n->effect]; + else + *ptr++ = (n->effect == jsetNotSet ? '.' : '?'); + + if (n->param != jsetNotSet) + { + *ptr++ = dmHexVal(n->param >> 4); + *ptr++ = dmHexVal(n->param); + } + else + { + *ptr++ = '.'; + *ptr++ = '.'; + } + + *ptr = 0; + + dmDrawBMTextConstQ(screen, font, DMD_TRANSPARENT, xc, yc, text); +} + + +void dmDisplayPattern(SDL_Surface *screen, int x0, int y0, int x1, int y1, JSSPattern *pat, int row) +{ + int cwidth = (font->width * 10 + 3 * 4 + 5), + lwidth = 6 + font->width * 3, + qy0 = y0 + font->height + 2, + qy1 = y1 - font->height - 2, + qwidth = ((x1 - x0 - lwidth) / cwidth), + qheight = ((qy1 - qy0 - 4) / (font->height + 1)), + nrow, nchannel, yc, choffs, + midrow = qheight / 2; + + if (engine.actChannel < qwidth / 2) + choffs = 0; + else + if (engine.actChannel >= pat->nchannels - qwidth/2) + choffs = pat->nchannels - qwidth; + else + choffs = engine.actChannel - qwidth/2; + + dmDrawBox3D(screen, x0 + lwidth, qy0, x1, qy1, col.box2, col.box1); + + for (nchannel = 0; nchannel < qwidth; nchannel++) + { + int bx0 = x0 + lwidth + 1 + nchannel * cwidth, + bx1 = bx0 + cwidth; + + if (engine.actChannel == nchannel + choffs) + { + dmFillRect(screen, bx0+1, qy0 + 1, bx1-1, qy1 - 1, col.activeChannel); + } + else + { + dmFillRect(screen, bx0+1, qy0 + 1, bx1-1, qy1 - 1, col.inboxBg); + } + } + + yc = qy0 + 2 + (font->height + 1) * midrow; + dmFillRect(screen, x0 + lwidth + 1, yc - 1, x1 - 1, yc + font->height, col.activeRow); + + for (nchannel = 0; nchannel < qwidth; nchannel++) + { + int bx0 = x0 + lwidth + 1 + nchannel * cwidth, + bx1 = bx0 + cwidth; + + dmDrawVLine(screen, qy0 + 1, qy1 - 1, bx1, col.viewDiv); + + if (jvmGetMute(engine.dev, nchannel + choffs)) + { + dmDrawBMTextConstQ(screen, font, DMD_TRANSPARENT, + bx0 + (cwidth - font->width * 5) / 2, qy1 + 3, "MUTED"); + } + + dmDrawBMTextQ(screen, font, DMD_TRANSPARENT, + bx0 + (cwidth - font->width * 3) / 2, y0 + 1, "%3d", + nchannel + choffs); + } + + for (nrow = 0; nrow < qheight; nrow++) + { + int crow = nrow - midrow + row; + yc = qy0 + 2 + (font->height + 1) * nrow; + + if (crow >= 0 && crow < pat->nrows) + { + dmDrawBMTextQ(screen, font, DMD_TRANSPARENT, x0, yc, "%03d", crow); + + for (nchannel = 0; nchannel < qwidth; nchannel++) + { + if (choffs + nchannel >= pat->nchannels) + break; + + dmPrintNote(screen, x0 + lwidth + 4 + nchannel * cwidth, yc, + pat->data + (pat->nchannels * crow) + choffs + nchannel); + } + } + } +} + + +void audioCallback(void *userdata, Uint8 *stream, int len) +{ + JSSMixer *d = (JSSMixer *) userdata; + + if (d != NULL) + { + jvmRenderAudio(d, stream, len / jvmGetSampleSize(d)); + } +} + + +void dmMuteChannels(BOOL mute) +{ + int i; + for (i = 0; i < engine.mod->nchannels; i++) + jvmMute(engine.dev, i, mute); +} + +int main(int argc, char *argv[]) +{ + BOOL initSDL = FALSE, audioInit = FALSE; + DMResource *file = NULL; + int result = -1; + BOOL muteState = FALSE; + + memset(&engine, 0, sizeof(engine)); + + engine.optScrWidth = 640; + engine.optScrHeight = 480; + engine.optScrDepth = 32; + + dmInitProg("CBP", "Cyrbe Basci Player", "0.1", NULL, NULL); + + // Parse arguments + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, argHandleFile, TRUE)) + exit(1); + + // Open the files + if (optFilename == NULL) + { + dmError("No filename specified.\n"); + return 1; + } + + if ((file = dmf_create_stdio(optFilename, "rb")) == NULL) + { + int err = dmGetErrno(); + dmError("Error opening file '%s', %d: (%s)\n", + optFilename, err, dmErrorStr(err)); + return 1; + } + + // Initialize miniJSS + jssInit(); + + // Read module file + dmMsg(1, "Reading file: %s\n", optFilename); +#ifdef JSS_SUP_XM + dmMsg(2, "* Trying XM...\n"); + result = jssLoadXM(file, &engine.mod); +#endif +#ifdef JSS_SUP_JSSMOD + if (result != 0) + { + size_t bufgot, bufsize = dmfsize(file); + Uint8 *buf = dmMalloc(bufsize); + dmfseek(file, 0L, SEEK_SET); + dmMsg(2, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf); + if ((bufgot = dmfread(buf, 1, bufsize, file)) != bufsize) + { + dmf_close(file); + dmError("Error reading file (not enough data %d), #%d: %s\n", + bufgot, dmferror(file), dmErrorStr(dmferror(file))); + goto error_exit; + } + result = jssLoadJSSMOD(buf, bufsize, &engine.mod); + dmFree(buf); + } +#endif + dmf_close(file); + + if (result != DMERR_OK) + { + dmError("Error loading module file, %d: %s\n", + result, dmErrorStr(result)); + goto error_exit; + } + + // Try to convert it + if ((result = jssConvertModuleForPlaying(engine.mod)) != DMERR_OK) + { + dmError("Could not convert module for playing, %d: %s\n", + result, dmErrorStr(result)); + goto error_exit; + } + + // Get font +// file = dmf_create_stdio("fnsmall.fnt", "rb"); + file = dmf_create_memio(NULL, "pplfont.fnt", engineSetupFont, sizeof(engineSetupFont)); + if (file == NULL) + { + dmError("Error opening font file 'pplfont.fnt'.\n"); + goto error_exit; + } + result = dmLoadBitmapFont(file, &font); + dmf_close(file); + if (result != DMERR_OK) + { + dmError("Could not load font from file, %d: %s\n", + result, dmErrorStr(result)); + goto error_exit; + } + + // Initialize SDL components + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) != 0) + { + dmError("Could not initialize SDL: %s\n", SDL_GetError()); + goto error_exit; + } + initSDL = TRUE; + + + // Initialize mixing device + dmMsg(2, "Initializing miniJSS mixer with: %d, %d, %d\n", + optOutFormat, optOutChannels, optOutFreq); + + engine.dev = jvmInit(optOutFormat, optOutChannels, optOutFreq, JMIX_AUTO); + if (engine.dev == NULL) + { + dmError("jvmInit() returned NULL\n"); + goto error_exit; + } + + switch (optOutFormat) + { + case JSS_AUDIO_S16: engine.afmt.format = AUDIO_S16SYS; break; + case JSS_AUDIO_U16: engine.afmt.format = AUDIO_U16SYS; break; + case JSS_AUDIO_S8: engine.afmt.format = AUDIO_S8; break; + case JSS_AUDIO_U8: engine.afmt.format = AUDIO_U8; break; + default: + dmError("Unsupported audio format %d (could not set matching SDL format)\n", + optOutFormat); + goto error_exit; + } + + engine.afmt.freq = optOutFreq; + engine.afmt.channels = optOutChannels; + engine.afmt.samples = optOutFreq / 16; + engine.afmt.callback = audioCallback; + engine.afmt.userdata = (void *) engine.dev; + + // Open the audio device + if (SDL_OpenAudio(&engine.afmt, NULL) < 0) + { + dmError("Couldn't open SDL audio: %s\n", + SDL_GetError()); + goto error_exit; + } + audioInit = TRUE; + + // Initialize player + if ((engine.plr = jmpInit(engine.dev)) == NULL) + { + dmError("jmpInit() returned NULL\n"); + goto error_exit; + } + + jvmSetCallback(engine.dev, jmpExec, engine.plr); + jmpSetModule(engine.plr, engine.mod); + jmpPlayOrder(engine.plr, optStartOrder); + jvmSetGlobalVol(engine.dev, 64); + + if (optMuteOChannels >= 0 && optMuteOChannels < engine.mod->nchannels) + { + dmMuteChannels(TRUE); + jvmMute(engine.dev, optMuteOChannels, FALSE); + engine.actChannel = optMuteOChannels; + muteState = TRUE; + } + + // Initialize video + if (!dmInitializeVideo()) + goto error_exit; + + SDL_WM_SetCaption(dmProgDesc, dmProgName); + + SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL); + + // okay, main loop here ... "play" module and print out info + SDL_LockAudio(); + SDL_PauseAudio(0); + SDL_UnlockAudio(); + + int currTick, prevTick = 0, prevRow = -1; + + while (!engine.exitFlag) + { + currTick = SDL_GetTicks(); + BOOL force = (currTick - prevTick > 500), updated = FALSE; + + while (SDL_PollEvent(&engine.event)) + switch (engine.event.type) + { + case SDL_KEYDOWN: + switch (engine.event.key.keysym.sym) + { + case SDLK_ESCAPE: + engine.exitFlag = TRUE; + break; + + case SDLK_SPACE: + engine.pauseFlag = !engine.pauseFlag; + SDL_PauseAudio(engine.pauseFlag); + break; + + case SDLK_LEFT: + if (engine.actChannel > 0) + { + engine.actChannel--; + force = TRUE; + } + break; + + case SDLK_RIGHT: + if (engine.actChannel < engine.mod->nchannels) + { + engine.actChannel++; + force = TRUE; + } + break; + + case SDLK_m: + if (engine.event.key.keysym.mod & KMOD_SHIFT) + { + muteState = !muteState; + dmMuteChannels(muteState); + } + else + if (engine.event.key.keysym.mod & KMOD_CTRL) + { + dmMuteChannels(FALSE); + } + else + { + jvmMute(engine.dev, engine.actChannel, !jvmGetMute(engine.dev, engine.actChannel)); + } + force = TRUE; + break; + + case SDLK_PAGEUP: + JSS_LOCK(engine.dev); + JSS_LOCK(engine.plr); + jmpChangeOrder(engine.plr, dmClamp(engine.plr->order - 1, 0, engine.mod->norders)); + JSS_UNLOCK(engine.plr); + JSS_UNLOCK(engine.dev); + force = TRUE; + break; + + case SDLK_PAGEDOWN: + JSS_LOCK(engine.dev); + JSS_LOCK(engine.plr); + jmpChangeOrder(engine.plr, dmClamp(engine.plr->order + 1, 0, engine.mod->norders)); + JSS_UNLOCK(engine.plr); + JSS_UNLOCK(engine.dev); + force = TRUE; + break; + + case SDLK_f: + engine.optVFlags ^= SDL_FULLSCREEN; + if (!dmInitializeVideo()) + goto error_exit; + force = TRUE; + break; + + default: + break; + } + + break; + + case SDL_VIDEORESIZE: + engine.optScrWidth = engine.event.resize.w; + engine.optScrHeight = engine.event.resize.h; + + if (!dmInitializeVideo()) + goto error_exit; + + break; + + case SDL_VIDEOEXPOSE: + break; + + case SDL_QUIT: + engine.exitFlag = TRUE; + break; + } + + +#if 1 + JSS_LOCK(engine.plr); + JSSPattern *currPattern = engine.plr->pattern; + int currRow = engine.plr->row; + if (!engine.plr->isPlaying) + engine.exitFlag = TRUE; + JSS_UNLOCK(engine.plr); + + if (currRow != prevRow || force) + { + prevRow = currRow; + force = TRUE; + } + + // Draw frame + if (SDL_MUSTLOCK(engine.screen) != 0 && SDL_LockSurface(engine.screen) != 0) + { + dmError("Can't lock surface.\n"); + goto error_exit; + } + + if (force) + { + dmClearSurface(engine.screen, col.boxBg); + + dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5, "%s v%s by ccr/TNSP - (c) Copyright 2012 TNSP", dmProgDesc, dmProgVersion); + + dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5 + 12 + 11, + "Song: '%s'", + engine.mod->moduleName); + + dmDisplayPattern(engine.screen, 5, 40, + engine.screen->w - 6, engine.screen->h * 0.8, + currPattern, currRow); + + JSS_LOCK(engine.plr); + dmDrawBMTextQ(engine.screen, font, DMD_TRANSPARENT, 5, 5 + 12, + "Tempo: %3d | Speed: %3d | Row: %3d/%-3d | Order: %3d/%-3d | Pattern: %3d/%-3d", + engine.plr->tempo, engine.plr->speed, + engine.plr->row, engine.plr->pattern->nrows, + engine.plr->order, engine.mod->norders, + engine.plr->npattern, engine.mod->npatterns); + JSS_UNLOCK(engine.plr); + updated = TRUE; + } + + if (force || currTick - prevTick >= (engine.pauseFlag ? 100 : 20)) + { + JSS_LOCK(engine.dev); + dmDisplayChannels(engine.screen, 5, engine.screen->h * 0.8 + 5, + engine.screen->w - 5, engine.screen->h - 5, engine.dev); + JSS_UNLOCK(engine.dev); + updated = TRUE; + } + + if (force) + prevTick = currTick; + +#endif + // Flip screen + if (SDL_MUSTLOCK(engine.screen) != 0) + SDL_UnlockSurface(engine.screen); + + if (updated) + SDL_Flip(engine.screen); + + SDL_Delay(engine.pauseFlag ? 100 : 30); + } + +error_exit: + if (engine.screen) + SDL_FreeSurface(engine.screen); + + dmMsg(0, "Audio shutdown.\n"); + if (audioInit) + { + SDL_LockAudio(); + SDL_PauseAudio(1); + SDL_UnlockAudio(); + SDL_CloseAudio(); + } + + jmpClose(engine.plr); + jvmClose(engine.dev); + jssFreeModule(engine.mod); + + dmFreeBitmapFont(font); + + if (initSDL) + SDL_Quit(); + + jssClose(); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/svg2qd.py Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,102 @@ +#!/usr/bin/python +import sys +import re +import xml.etree.ElementTree as ET + + +def bf(x) : + return int(round(float(x))) + + +def printVertex(v) : + if type(v) is list : + return "{:.2f},{:.2f},{:.2f}".format(v[0], v[1], v[2]) + else : + return v + + +def getTransform(elem) : + if "transform" in elem.attrib : + ntrans = elem.attrib["transform"] + tmatch = re.compile(r"translate\((.*?)\)", re.IGNORECASE) + for trns in tmatch.finditer(ntrans) : + coord = trns.group(1).split(",") + return [float(coord[0]), float(coord[1]), 0] + return None + + +def getStyle(elem) : + style = {} + if "style" in elem.attrib : + for elem in elem.attrib["style"].split(";") : + kv = elem.split(":") + style[kv[0]] = kv[1] + return style + + +def printVertices(type, vertices, width, level) : + if len(vertices) > 0 : + list = map(lambda v:printVertex(v), vertices) + str = "# "+ type + if type == "m" : + str = "R" + elif type == "M" : + str = "L" + elif type == "c" : + str = "R" + print "{}{}{} {} {}".format(" "*level, str, len(vertices)-1, " ".join(list), width) + + +def printPath(path, level) : + style = getStyle(path) + width = bf(style["stroke-width"]) + + trans = getTransform(path) + if trans : + print "{}G{}".format(" "*level, printVertex(trans)) + + vertices = [] + type = "" + for elem in path.attrib["d"].split(" ") : + if elem == "m" or elem == "M" : + printVertices(type, vertices, width, level) + vertices = [] + type = elem + elif elem == "z" : + vertices.append("Z") + elif elem == "c" or elem == "C" : + print "Curves not supported! Path ID '{}':\n{}".format(path.attrib["id"], path.attrib["d"]) + sys.exit(0) + else : + tmp = elem.split(",") + px = float(tmp[0]) + py = float(tmp[1]) + vertices.append([px, py, 0]) + + printVertices(type, vertices, width, level) + if trans : + print "{}E\n".format(" "*level) + + +def iterateDocument(elems, level) : + for elem in elems: + if elem.tag == "{http://www.w3.org/2000/svg}g" : + print "\n{}# GROUP".format(" "*level) + tmp = getTransform(elem) + if tmp : + print "{}G{}".format(" "*level, printVertex(getTransform(elem))) + iterateDocument(elem, level + 1) + print "{}E\n".format(" "*level) + else : + iterateDocument(elem, level) + elif elem.tag == "{http://www.w3.org/2000/svg}path" : + printPath(elem, level) + + +# Ns. paaohjelma +if len(sys.argv) != 2 : + print "Usage: "+sys.argv[0]+" <input.svg>" + sys.exit(1) + +tree = ET.parse(sys.argv[1]) +iterateDocument(tree.getroot(), 0)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/view64.c Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,321 @@ +/* + * 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; + + +static 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 }, +}; + +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() +{ + int i; + + dmPrintBanner(stdout, dmProgName, "[options] <input image file>"); + dmArgsPrintHelp(stdout, optList, optListN); + + printf("\nAvailable bitmap formats:\n"); + for (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) + { + dmError("Invalid scale factor %1.0f, see help for valid values.\n", factor); + return FALSE; + } + + dmSetScaleFactor(factor); + } + else + { + dmError("Invalid scale factor '%s'.\n", optArg); + return FALSE; + } + } + break; + + case 4: + { + int i; + if (sscanf(optArg, "%d", &i) == 1) + { + if (i < 0 || i >= ndmC64ImageFormats) + { + dmError("Invalid image format index %d, see help for valid values.\n", i); + return FALSE; + } + optForcedFormat = i; + } + else + { + dmError("Invalid image format argument '%s'.\n", optArg); + return FALSE; + } + } + break; + + default: + dmError("Unknown option '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char *filename) +{ + if (optFilename == NULL) + { + optFilename = dm_strdup(filename); + return TRUE; + } + else + { + dmError("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) + { + dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); + return FALSE; + } + return TRUE; +} + + +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 image; + 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, FALSE)) + exit(1); + + + if (optFilename == NULL) + { + dmError("No input file specified, perhaps you need some --help\n"); + goto error; + } + + if ((ret = dmReadDataFile(NULL, optFilename, &dataBuf, &dataSize)) != DMERR_OK) + goto error; + + dmMsg(1, "Read %d bytes of input.\n", dataSize); + + // 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(&image, dataBuf, dataSize, 0, 2, &fmt, forced); + if (forced == NULL && fmt != NULL) + { + dmMsg(0,"Probed %s format image, type %d, %s\n", + fmt->name, fmt->type, fmt->fext); + } + + if (ret < 0) + { + dmError("Probing could not find any matching image format (%d). Perhaps try forcing a format via -f\n", ret); + return -1; + } + + + // Initialize libSDL + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) + { + dmError("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) + { + dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); + goto error; + } + + // Create surface (we are lazy and ugly) + surf = SDL_CreateRGBSurface(SDL_SWSURFACE, C64_SCR_WIDTH, C64_SCR_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.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, &image, TRUE); + else + ret = dmC64ConvertGenericBMP2Image(&bmap, &image, TRUE); + + + // Set window title and caption + windowTitle = dm_strdup_printf("%s - %s", dmProgName, optFilename); + 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) + { + if (SDL_MUSTLOCK(screen) != 0 && SDL_LockSurface(screen) != 0) + { + dmError("Can't lock surface.\n"); + goto error; + } + + dmScaledBlitSurface8to8(surf, 0, 0, screen->w, screen->h, 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: + if (screen) + SDL_FreeSurface(screen); + + if (initSDL) + SDL_Quit(); + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/viewmod.c Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,475 @@ +/* + * viewmod - View information about given module file + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2006-2007 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#include "jss.h" +#include "jssmod.h" +#include <errno.h> +#include <string.h> +#include "dmargs.h" +#include "dmmutex.h" + + +char *optFilename = NULL; +BOOL optViewPatterns = FALSE, + optViewInstruments = FALSE, + optViewExtInstruments = FALSE, + optViewGeneralInfo = FALSE; + + +DMOptArg optList[] = +{ + { 0, '?', "help", "Show this help and exit", OPT_NONE }, + { 1, 'p', "patterns", "View patterns", OPT_NONE }, + { 2, 'i', "instruments", "View instruments", OPT_NONE }, + { 5, 'e', "extinstruments", "View extended instruments", OPT_NONE }, + { 3, 'g', "general", "General information", OPT_NONE }, + { 4, 'v', "verbose", "Be more verbose", OPT_NONE }, +}; + +const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + dmPrintBanner(stdout, dmProgName, "[options] [modfile]"); + dmArgsPrintHelp(stdout, optList, optListN); +} + + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + (void) optArg; + + switch (optN) + { + case 0: + argShowHelp(); + exit(0); + break; + + case 1: + optViewPatterns = TRUE; + break; + + case 2: + optViewInstruments = TRUE; + break; + + case 3: + optViewGeneralInfo = TRUE; + break; + + case 4: + dmVerbosity++; + break; + + case 5: + optViewExtInstruments = TRUE; + break; + + default: + dmError("Unknown argument '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char *currArg) +{ + // Was not option argument + if (!optFilename) + optFilename = currArg; + else { + dmError("Gay error '%s'!\n", currArg); + return FALSE; + } + + return TRUE; +} + + +const char patNoteTable[12][3] = +{ + "C-", "C#", "D-", + "D#", "E-", "F-", + "F#", "G-", "G#", + "A-", "A#", "B-" +}; + +#define jmpNMODEffectTable (36) +static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + +/* Print a given pattern + */ +void printPattern(FILE *f, JSSPattern *p) +{ + int i, j; + char c; + JSSNote *n; + + if (!p) + return; + + n = p->data; + + for (i = 0; i < p->nrows; i++) + { + fprintf(f, "%.2x: ", i); + + for (j = 0; j < p->nchannels; j++) + { + switch (n->note) + { + case jsetNotSet: + fprintf(f, "... "); + break; + case jsetNoteOff: + fprintf(f, "=== "); + break; + default: + fprintf(f, "%s%i ", patNoteTable[n->note % 12], n->note / 12); + break; + } + + if (n->instrument != jsetNotSet) + fprintf(f, "%.2x ", n->instrument + 1); // Because FT2 is 1-based and we use 0 internally + else + fprintf(f, ".. "); + + if (n->volume == jsetNotSet) + fprintf(f, ".. "); + else if (n->volume >= 0x00 && n->volume <= 0x40) + fprintf(f, "%.2x ", n->volume); + else + { + switch (n->volume & 0xf0) + { + case 0x50: c = '-'; break; + case 0x60: c = '+'; break; + case 0x70: c = '/'; break; + case 0x80: c = '\\'; break; + case 0x90: c = 'S'; break; + case 0xa0: c = 'V'; break; + case 0xb0: c = 'P'; break; + case 0xc0: c = '<'; break; + case 0xd0: c = '>'; break; + case 0xe0: c = 'M'; break; + default: c = '?'; break; + } + fprintf(f, "%c%x ", c, (n->volume & 0x0f)); + } + + if (n->effect >= 0 && n->effect < jmpNMODEffectTable) + fprintf(f, "%c", jmpMODEffectTable[n->effect]); + else if (n->effect == jsetNotSet) + fprintf(f, "."); + else + fprintf(f, "?"); + + if (n->param != jsetNotSet) + fprintf(f, "%.2x|", n->param); + else + fprintf(f, "..|"); + + n++; + } + + fprintf(f, "\n"); + } +} + + +/* + * Print given extended instrument + */ +void printEnvelope(FILE *f, JSSEnvelope *e, char *s) +{ + int i; + + fprintf(f, + "\t%s-envelope:\n" + "\t - flags.....: %.4x", s, e->flags); + + if (e->flags & jenvfUsed) + fprintf(f, " [used]"); + if (e->flags & jenvfSustain) + fprintf(f, " [sust]"); + if (e->flags & jenvfLooped) + fprintf(f, " [loop]"); + + fprintf(f, "\n" + "\t - npoints...: %i\n" + "\t - sustain...: %i\n" + "\t - loopS.....: %i\n" + "\t - loopE.....: %i\n", + e->npoints, e->sustain, e->loopS, e->loopE); + + if (dmVerbosity >= 2) + { + fprintf(f, "\t - Points....:"); + for (i = 0; i < e->npoints; i++) + { + fprintf(f, " [%i:%i]", + e->points[i].frame, e->points[i].value); + } + + fprintf(f, "\n"); + } +} + + +void printExtInstrument(FILE *f, JSSExtInstrument *i) +{ + if (!i) + { + fprintf(f, "\n"); + return; + } + +#ifndef JSS_LIGHT + if (i->desc) + fprintf(f, + "Description: '%s'\n", i->desc); +#endif + fprintf(f, + "nsamples.......: %i\n" + "vibratoType....: %i\n" + "vibratoSweep...: %i\n" + "vibratoDepth...: %i\n" + "vibratoRate....: %i\n" + "fadeOut........: %i\n", + i->nsamples, i->vibratoType, i->vibratoSweep, + i->vibratoDepth, i->vibratoRate, i->fadeOut); + + if (dmVerbosity >= 1) + { + printEnvelope(f, &i->volumeEnv, "Volume"); + printEnvelope(f, &i->panningEnv, "Panning"); + } + fprintf(f, "\n"); +} + + +void printInstrument(FILE *f, JSSInstrument *i) +{ + if (!i) + { + fprintf(f, "\n"); + return; + } + + if (dmVerbosity >= 1) + { +#ifndef JSS_LIGHT + if (i->desc) + fprintf(f, "Description: '%s'\n", i->desc); +#endif + fprintf(f, + "size...........: %ld (0x%lx)\n" + "loopStart......: %ld (0x%lx)\n" + "loopEnd........: %ld (0x%lx)\n" + "volume.........: %d (0x%x)\n" + "flags..........: 0x%x ", + (unsigned long) i->size, (unsigned long) i->size, + (unsigned long) i->loopS, (unsigned long) i->loopE, + (unsigned long) i->loopS, (unsigned long) i->loopE, + i->volume, i->volume, + i->flags); + + if (i->flags & jsfLooped) fprintf(f, "[loop] "); + if (i->flags & jsfBiDi) fprintf(f, "[bi-di] "); + if (i->flags & jsf16bit) fprintf(f, "[16bit] "); + + fprintf(f, + "\nC4BaseSpeed....: %d (0x%x)\n" + "ERelNote.......: %d (%s%d)\n" + "EFineTune......: %d\n" + "EPanning,,,....: %d (0x%x)\n\n", + i->C4BaseSpeed, i->C4BaseSpeed, + i->ERelNote, patNoteTable[(48 + i->ERelNote) % 12], (48 + i->ERelNote) / 12, + i->EFineTune, i->EPanning, i->EPanning); + } + else + { +#ifndef JSS_LIGHT + if (i->desc) + fprintf(f, "'%s', ", i->desc); +#endif + fprintf(f, + "s=%ld (%lx), l=%ld-%ld (%lx-%lx), v=%i (%x), f=0x%x, c4=%i (%x), rn=%i (%s%i), ft=%i, pn=%i (%x)\n", + (unsigned long) i->size, (unsigned long) i->size, + (unsigned long) i->loopS, (unsigned long) i->loopE, + (unsigned long) i->loopS, (unsigned long) i->loopE, + i->volume, i->volume, i->flags, i->C4BaseSpeed, + i->C4BaseSpeed, i->ERelNote, + patNoteTable[(48 + i->ERelNote) % 12], + (48 + i->ERelNote) / 12, i->EFineTune, + i->EPanning, i->EPanning); + } +} + + +void printGeneralInfo(FILE *f, JSSModule *m) +{ + int i; + + if (!m) + return; + + fprintf(f, "Module type.....: %i\n", m->moduleType); +#ifndef JSS_LIGHT + if (m->moduleName) + fprintf(f, "Module name.....: '%s'\n", m->moduleName); + if (m->trackerName) + fprintf(f, "Tracker name....: '%s'\n", m->trackerName); +#endif + fprintf(f, + "Speed...........: %d ticks\n" + "Tempo...........: %d bpm\n" + "Flags...........: %x ", + m->defSpeed, m->defTempo, m->defFlags); + + if (m->defFlags & jmdfAmigaPeriods) fprintf(f, "[Amiga periods] "); + if (m->defFlags & jmdfAmigaLimits) fprintf(f, "[Amiga limits] "); + if (m->defFlags & jmdfStereo) fprintf(f, "[stereo] "); + if (m->defFlags & jmdfFT2Replay) fprintf(f, "[FT2 replay] "); + if (m->defFlags & jmdfST300Slides) fprintf(f, "[ST300 slides] "); + if (m->defFlags & jmdfByteLStart) fprintf(f, "[ByteStart] "); + + fprintf(f, "\n" + "Restart pos.....: %d (order)\n" + "IntVersion......: %x\n" + "Channels........: %d\n" + "Instruments.....: %d\n" + "Ext.instruments.: %d\n" + "Patterns........: %d\n" + "Orders..........: %d\n", + m->defRestartPos, m->intVersion, m->nchannels, + m->ninstruments, m->nextInstruments, m->npatterns, + m->norders); + + if (dmVerbosity >= 1) + { + fprintf(f, "Orderlist: "); + for (i = 0; i < m->norders - 1; i++) + fprintf(f, "%d, ", m->orderList[i]); + if (i < m->norders) + fprintf(f, "%d", m->orderList[i]); + fprintf(f, "\n"); + } +} + + + +int main(int argc, char *argv[]) +{ + int result = -1, i; + DMResource *file; + JSSModule *mod; + + dmInitProg("viewmod", "miniJSS Module Viewer", "0.4", NULL, NULL); + dmVerbosity = 0; + + // Parse arguments + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, argHandleFile, TRUE)) + exit(1); + + // Initialize miniJSS + jssInit(); + + // Open the file + dmMsg(1, "Reading module file '%s'\n", optFilename); + if (optFilename == NULL) + file = dmf_create_stdio_stream(stdin); + else if ((file = dmf_create_stdio(optFilename, "rb")) == NULL) + { + dmError("Error opening input file '%s'. (%s)\n", + optFilename, strerror(errno)); + return 1; + } + + // Read module file + dmMsg(1, "Reading file: %s\n", optFilename); +#ifdef JSS_SUP_XM + dmMsg(1, "* Trying XM...\n"); + result = jssLoadXM(file, &mod); +#endif +#ifdef JSS_SUP_JSSMOD + if (result != 0) + { + size_t bufgot, bufsize = dmfsize(file); + Uint8 *buf = dmMalloc(bufsize); + dmfseek(file, 0L, SEEK_SET); + dmMsg(1, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf); + if ((bufgot = dmfread(buf, 1, bufsize, file)) != bufsize) + { + dmError("Error reading file (not enough data %d), #%d: %s\n", + bufgot, dmferror(file), dmErrorStr(dmferror(file))); + return 2; + } + result = jssLoadJSSMOD(buf, bufsize, &mod); + dmFree(buf); + } +#endif + dmf_close(file); + if (result != DMERR_OK) + { + dmError("Error loading module file, %d: %s\n", + result, dmErrorStr(result)); + return 3; + } + + // Print out information + if (optViewGeneralInfo) + printGeneralInfo(stdout, mod); + + if (optViewPatterns) + { + for (i = 0; i < mod->npatterns; i++) + { + printf("\nPattern #%03i:\n", i); + printPattern(stdout, mod->patterns[i]); + } + } + + if (optViewExtInstruments) + { + printf("\n" + "ExtInstruments:\n" + "---------------\n" + ); + for (i = 0; i < mod->nextInstruments; i++) + { + printf("#%03i: ", i + 1); + printExtInstrument(stdout, mod->extInstruments[i]); + } + } + + if (optViewInstruments) + { + printf("\n" + "Instruments:\n" + "------------\n" + ); + for (i = 0; i < mod->ninstruments; i++) + { + printf("#%03i: ", i + 1); + printInstrument(stdout, mod->instruments[i]); + } + } + + // Free module data + jssFreeModule(mod); + jssClose(); + + exit(0); + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/utils/xm2jss.c Tue Apr 16 06:01:42 2013 +0300 @@ -0,0 +1,1040 @@ +/* + * xm2jss - Convert XM module to JSSMOD + * Programmed and designed by Matti 'ccr' Hamalainen + * (C) Copyright 2006-2009 Tecnic Software productions (TNSP) + * + * Please read file 'COPYING' for information on license and distribution. + */ +#include <stdio.h> +#include <errno.h> +#include "jss.h" +#include "jssmod.h" +#include "jssplr.h" +#include "dmlib.h" +#include "dmargs.h" +#include "dmres.h" +#include "dmmutex.h" + + +#define jmpNMODEffectTable (36) +static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + + +char *optInFilename = NULL, *optOutFilename = NULL; +BOOL optIgnoreErrors = FALSE, + optStripExtInstr = FALSE, + optStripInstr = FALSE, + optStripSamples = FALSE, + optOptimize = FALSE; + +int optPatternMode = PATMODE_COMP_HORIZ, + optSampMode16 = jsampDelta, + optSampMode8 = jsampFlipSign | jsampDelta; + +#define SAMPMODE_MASK (jsampFlipSign | jsampSwapEndianess | jsampSplit | jsampDelta) + + +static const char* patModeTable[PATMODE_LAST] = +{ + "Raw horizontal", + "Compressed horizontal (similar to XM modules)", + "Raw vertical", + "Compressed vertical", + "Raw vertical for each element", +}; + + +DMOptArg optList[] = { + { 0, '?', "help", "Show this help", OPT_NONE }, + { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, + { 2, 'i', "ignore", "Ignore errors", OPT_NONE }, + { 3, 'p', "patterns", "Pattern storage mode", OPT_ARGREQ }, + { 4, 'E', "strip-ext-instr","Strip ext. instruments (implies -I -S)", OPT_NONE }, + { 5, 'I', "strip-instr", "Strip instruments (implies -S)", OPT_NONE }, + { 6, 'S', "strip-samples", "Strip instr. sampledata", OPT_NONE }, + { 7, '8', "smode8", "8-bit sample conversion flags", OPT_ARGREQ }, + { 8, '1', "smode16", "16-bit sample conversion flags", OPT_ARGREQ }, + { 9, 'O', "optimize", "Optimize module", OPT_NONE }, +}; + +const int optListN = sizeof(optList) / sizeof(optList[0]); + + +void argShowHelp() +{ + int i; + + dmPrintBanner(stdout, dmProgName, "[options] <input.xm> <output.jmod>"); + dmArgsPrintHelp(stdout, optList, optListN); + + printf("\n" + "Pattern storage modes:\n"); + + for (i = 1; i < PATMODE_LAST; i++) + printf(" %d = %s\n", i, patModeTable[i-1]); + + printf( + "\n" + "Sample data conversion flags (summative):\n" + " 1 = Delta encoding (DEF 8 & 16)\n" + " 2 = Flip signedness (DEF 8)\n" + " 4 = Swap endianess (affects 16-bit only)\n" + " 8 = Split and de-interleave hi/lo bytes (affects 16-bit only)\n" + "\n" + ); +} + +BOOL argHandleOpt(const int optN, char *optArg, char *currArg) +{ + (void) optArg; + + switch (optN) + { + case 0: + argShowHelp(); + exit(0); + break; + + case 1: + dmVerbosity++; + break; + + case 2: + optIgnoreErrors = TRUE; + break; + + case 3: + optPatternMode = atoi(optArg); + if (optPatternMode <= 0 || optPatternMode >= PATMODE_LAST) + { + dmError("Unknown pattern conversion mode %d\n", optPatternMode); + return FALSE; + } + break; + + case 4: optStripExtInstr = TRUE; break; + case 5: optStripInstr = TRUE; break; + case 6: optStripSamples = TRUE; break; + + case 7: optSampMode8 = atoi(optArg) & SAMPMODE_MASK; break; + case 8: optSampMode16 = atoi(optArg) & SAMPMODE_MASK; break; + + case 9: optOptimize = TRUE; break; + + default: + dmError("Unknown argument '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +BOOL argHandleFile(char *currArg) +{ + // Was not option argument + if (!optInFilename) + optInFilename = currArg; + else + if (!optOutFilename) + optOutFilename = currArg; + else + { + dmError("Too many filename arguments specified, '%s'.\n", currArg); + return FALSE; + } + + return TRUE; +} + + +/* These functions and the macro mess are meant to make the + * conversion routines themselves clearer and simpler. + */ +BOOL jsPutByte(Uint8 *patBuf, size_t patBufSize, size_t *npatBuf, Uint8 val) +{ + if (*npatBuf >= patBufSize) + return FALSE; + else + { + patBuf[*npatBuf] = val; + (*npatBuf)++; + return TRUE; + } +} + +#define JSPUTBYTE(x) do { if (!jsPutByte(patBuf, patBufSize, patSize, x)) return DMERR_BOUNDS; } while (0) + +#define JSCOMP(x,z) do { if ((x) != jsetNotSet) { qflags |= (z); qcomp++; } } while (0) + +#define JSCOMPPUT(xf,xv,qv) do { \ + if (qflags & (xf)) { \ + if ((xv) < 0 || (xv) > 255) \ + JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, \ + "%s value out of bounds %d.\n", qv, (xv)); \ + JSPUTBYTE(xv); \ + } \ +} while (0) + +#define JSCONVPUT(xv,qv) do { \ + if ((xv) != jsetNotSet) { \ + if ((xv) < 0 || (xv) > 254) \ + JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, \ + "%s value out of bounds %d.\n", qv, (xv)); \ + JSPUTBYTE((xv) + 1); \ + } else { \ + JSPUTBYTE(0); \ + } \ +} while (0) + + +/* Convert a note + */ +static int jssConvertNote(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSNote *note) +{ + Uint8 tmp; + if (note->note == jsetNotSet) + tmp = 0; + else if (note->note == jsetNoteOff) + tmp = 127; + else + tmp = note->note + 1; + + if (tmp > 0x7f) + JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp); + + JSPUTBYTE(tmp & 0x7f); + + JSCONVPUT(note->instrument, "Instrument"); + JSCONVPUT(note->volume, "Volume"); + JSCONVPUT(note->effect, "Effect"); + + tmp = (note->param != jsetNotSet) ? note->param : 0; + JSPUTBYTE(tmp); + + return DMERR_OK; +} + + +/* Compress a note + */ +static int jssCompressNote(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSNote *note) +{ + Uint8 qflags = 0; + int qcomp = 0; + + JSCOMP(note->note, COMP_NOTE); + JSCOMP(note->instrument, COMP_INSTRUMENT); + JSCOMP(note->volume, COMP_VOLUME); + JSCOMP(note->effect, COMP_EFFECT); + if (note->param != jsetNotSet && note->param != 0) + { + qflags |= COMP_PARAM; + qcomp++; + } + + if (qcomp < 4) + { + JSPUTBYTE(qflags | 0x80); + + if (note->note != jsetNotSet) + { + Uint8 tmp = (note->note != jsetNoteOff) ? note->note : 127; + if (tmp > 0x7f) + JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp); + JSPUTBYTE(tmp); + } + + JSCOMPPUT(COMP_INSTRUMENT, note->instrument, "Instrument"); + JSCOMPPUT(COMP_VOLUME, note->volume, "Volume"); + JSCOMPPUT(COMP_EFFECT, note->effect, "Effect"); + JSCOMPPUT(COMP_PARAM, note->param, "Param"); + } else + return jssConvertNote(patBuf, patBufSize, patSize, note); + + return DMERR_OK; +} + + +/* Compress pattern + */ +static int jssConvertPatternCompHoriz(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) +{ + int row, channel; + *patSize = 0; + + for (row = 0; row < pattern->nrows; row++) + for (channel = 0; channel < pattern->nchannels; channel++) + { + const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; + const int res = jssCompressNote(patBuf, patBufSize, patSize, note); + if (res != DMERR_OK) + { + JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", + patBuf, patBufSize, *patSize, row, channel); + return res; + } + } + + return DMERR_OK; +} + + +static int jssConvertPatternCompVert(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) +{ + int row, channel; + *patSize = 0; + + for (channel = 0; channel < pattern->nchannels; channel++) + for (row = 0; row < pattern->nrows; row++) + { + const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; + const int res = jssCompressNote(patBuf, patBufSize, patSize, note); + if (res != DMERR_OK) + { + JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", + patBuf, patBufSize, *patSize, row, channel); + return res; + } + } + + return DMERR_OK; +} + + +/* Convert a pattern + */ +static int jssConvertPatternRawHoriz(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) +{ + int row, channel; + *patSize = 0; + + for (row = 0; row < pattern->nrows; row++) + for (channel = 0; channel < pattern->nchannels; channel++) + { + const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; + const int res = jssConvertNote(patBuf, patBufSize, patSize, note); + if (res != DMERR_OK) + { + JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", + patBuf, patBufSize, *patSize, row, channel); + return res; + } + } + + return DMERR_OK; +} + + +static int jssConvertPatternRawVert(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) +{ + int row, channel; + *patSize = 0; + + for (channel = 0; channel < pattern->nchannels; channel++) + for (row = 0; row < pattern->nrows; row++) + { + const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; + const int res = jssConvertNote(patBuf, patBufSize, patSize, note); + if (res != DMERR_OK) + { + JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", + patBuf, patBufSize, *patSize, row, channel); + return res; + } + } + + return DMERR_OK; +} + + +#define JSFOREACHNOTE1 \ + for (channel = 0; channel < pattern->nchannels; channel++) \ + for (row = 0; row < pattern->nrows; row++) { \ + const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; + +#define JSFOREACHNOTE2 } + +static int jssConvertPatternRawElem(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) +{ + Uint8 tmp; + int row, channel; + *patSize = 0; + + JSFOREACHNOTE1; + if (note->note == jsetNotSet) + tmp = 0; + else if (note->note == jsetNoteOff) + tmp = 127; + else + tmp = note->note + 1; + if (tmp > 0x7f) + JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp); + JSPUTBYTE(tmp); + JSFOREACHNOTE2; + + JSFOREACHNOTE1; + JSCONVPUT(note->instrument, "Instrument"); + JSFOREACHNOTE2; + + JSFOREACHNOTE1; + JSCONVPUT(note->volume, "Volume"); + JSFOREACHNOTE2; + + JSFOREACHNOTE1; + JSCONVPUT(note->effect, "Effect"); + JSFOREACHNOTE2; + + JSFOREACHNOTE1; + tmp = (note->param != jsetNotSet) ? note->param : 0; + JSPUTBYTE(tmp); + JSFOREACHNOTE2; + + return DMERR_OK; +} + +#undef JSFOREACHNOTE1 +#undef JSFOREACHNOTE2 + + +static void jssCopyEnvelope(JSSMODEnvelope *je, JSSEnvelope *e) +{ + int i; + + je->flags = e->flags; + je->npoints = e->npoints; + je->sustain = e->sustain; + je->loopS = e->loopS; + je->loopE = e->loopE; + + for (i = 0; i < e->npoints; i++) + { + je->points[i].frame = e->points[i].frame; + je->points[i].value = e->points[i].value; + } +} + + +/* Save a JSSMOD file + */ +int jssSaveJSSMOD(FILE *outFile, JSSModule *m, int patMode, int flags8, int flags16) +{ + JSSMODHeader jssH; + int i, pattern, order, instr, totalSize; + const size_t patBufSize = 64*1024; // 64kB pattern buffer + Uint8 *patBuf; + + // Check the module + if (m == NULL) + JSSERROR(DMERR_NULLPTR, DMERR_NULLPTR, "Module pointer was NULL\n"); + + if ((m->nchannels < 1) || (m->npatterns < 1) || (m->norders < 1)) + JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, + "Module had invalid values (nchannels=%i, npatterns=%i, norders=%i)\n", + m->nchannels, m->npatterns, m->norders); + + // Create the JSSMOD header + jssH.idMagic[0] = 'J'; + jssH.idMagic[1] = 'M'; + jssH.idVersion = JSSMOD_VERSION; + jssH.norders = m->norders; + jssH.npatterns = m->npatterns; + jssH.nchannels = m->nchannels; + jssH.nextInstruments = m->nextInstruments; + jssH.ninstruments = m->ninstruments; + jssH.defFlags = m->defFlags; + jssH.intVersion = m->intVersion; + jssH.defRestartPos = m->defRestartPos; + jssH.defSpeed = m->defSpeed; + jssH.defTempo = m->defTempo; + jssH.patMode = patMode; + + // Write header + totalSize = sizeof(jssH); + if (fwrite(&jssH, sizeof(jssH), 1, outFile) != 1) + JSSERROR(DMERR_FWRITE, DMERR_FWRITE, "Could not write JSSMOD header!\n"); + + dmMsg(1," * JSSMOD-header 0x%04x, %d bytes.\n", JSSMOD_VERSION, totalSize); + + // Write orders list + for (totalSize = order = 0; order < m->norders; order++) + { + Uint16 tmp = m->orderList[order]; + totalSize += sizeof(tmp); + if (fwrite(&tmp, sizeof(tmp), 1, outFile) != 1) + JSSERROR(DMERR_FWRITE, DMERR_FWRITE, "Could not write JSSMOD orders list.\n"); + } + + dmMsg(1," * %d item orders list, %d bytes.\n", + m->norders, totalSize); + + // Allocate pattern compression buffer + if ((patBuf = dmMalloc(patBufSize)) == NULL) + JSSERROR(DMERR_MALLOC, DMERR_MALLOC, + "Error allocating memory for pattern compression buffer.\n"); + + + // Write patterns + for (totalSize = pattern = 0; pattern < m->npatterns; pattern++) + { + JSSMODPattern patHead; + size_t finalSize = 0; + + switch (patMode) + { + case PATMODE_RAW_HORIZ: + i = jssConvertPatternRawHoriz(patBuf, patBufSize, &finalSize, m->patterns[pattern]); + break; + case PATMODE_COMP_HORIZ: + i = jssConvertPatternCompHoriz(patBuf, patBufSize, &finalSize, m->patterns[pattern]); + break; + case PATMODE_RAW_VERT: + i = jssConvertPatternRawVert(patBuf, patBufSize, &finalSize, m->patterns[pattern]); + break; + case PATMODE_COMP_VERT: + i = jssConvertPatternCompVert(patBuf, patBufSize, &finalSize, m->patterns[pattern]); + break; + case PATMODE_RAW_ELEM: + i = jssConvertPatternRawElem(patBuf, patBufSize, &finalSize, m->patterns[pattern]); + break; + default: + i = DMERR_INVALID_DATA; + dmFree(patBuf); + JSSERROR(DMERR_INVALID_DATA, DMERR_INVALID_DATA, + "Unsupported pattern conversion mode %d.\n", patMode); + break; + } + + if (i != DMERR_OK) + { + dmFree(patBuf); + JSSERROR(i, i, "Error converting pattern data #%i\n", pattern); + } + else + { + dmMsg(3, " - Pattern %d size %d bytes\n", pattern, finalSize); + patHead.nrows = m->patterns[pattern]->nrows; + patHead.size = finalSize; + totalSize += finalSize + sizeof(patHead); + + if (fwrite(&patHead, sizeof(patHead), 1, outFile) != 1) + { + dmFree(patBuf); + JSSERROR(DMERR_FWRITE, DMERR_FWRITE, + "Error writing pattern #%d header\n", pattern); + } + + if (fwrite(patBuf, sizeof(Uint8), finalSize, outFile) != finalSize) + { + dmFree(patBuf); + JSSERROR(DMERR_FWRITE, DMERR_FWRITE, + "Error writing pattern #%d data\n", pattern); + } + } + } + dmFree(patBuf); + dmMsg(1," * %d patterns, %d bytes.\n", m->npatterns, totalSize); + + // Write extended instruments + for (totalSize = instr = 0; instr < m->nextInstruments; instr++) + { + JSSMODExtInstrument jssE; + JSSExtInstrument *einst = m->extInstruments[instr]; + + memset(&jssE, 0, sizeof(jssE)); + + if (einst) + { + // Create header + jssE.nsamples = einst->nsamples; + for (i = 0; i < jsetNNotes; i++) + { + int snum = einst->sNumForNotes[i]; + jssE.sNumForNotes[i] = (snum != jsetNotSet) ? snum : 0; + } + + jssCopyEnvelope(&jssE.volumeEnv, &(einst->volumeEnv)); + jssCopyEnvelope(&jssE.panningEnv, &(einst->panningEnv)); + jssE.vibratoType = einst->vibratoType; + jssE.vibratoSweep = einst->vibratoSweep; + jssE.vibratoDepth = einst->vibratoDepth; + jssE.fadeOut = einst->fadeOut; + } else + JSSWARNING(DMERR_NULLPTR, DMERR_NULLPTR, "Extended instrument #%i NULL!\n", instr); + + // Write to file + totalSize += sizeof(jssE); + if (fwrite(&jssE, sizeof(jssE), 1, outFile) != 1) + JSSERROR(DMERR_FWRITE, DMERR_FWRITE, + "Could not write JSSMOD extended instrument #%i to file!\n", instr); + } + dmMsg(1," * %d Extended Instruments, %d bytes.\n", m->nextInstruments, totalSize); + + + // Write sample instrument headers + for (totalSize = instr = 0; instr < m->ninstruments; instr++) + { + JSSMODInstrument jssI; + JSSInstrument *pInst = m->instruments[instr]; + + memset(&jssI, 0, sizeof(jssI)); + + // Create header + if (pInst) + { + jssI.size = pInst->size; + jssI.loopS = pInst->loopS; + jssI.loopE = pInst->loopE; + jssI.volume = pInst->volume; + jssI.flags = pInst->flags; + jssI.C4BaseSpeed = pInst->C4BaseSpeed; + jssI.ERelNote = pInst->ERelNote; + jssI.EFineTune = pInst->EFineTune; + jssI.EPanning = pInst->EPanning; + jssI.hasData = (pInst->data != NULL) ? TRUE : FALSE; + jssI.convFlags = (pInst->flags & jsf16bit) ? flags16 : flags8; + } + else + JSSWARNING(DMERR_NULLPTR, DMERR_NULLPTR, "Instrument #%i NULL!\n", instr); + + // Write to file + totalSize += sizeof(jssI); + if (fwrite(&jssI, sizeof(jssI), 1, outFile) != 1) + JSSERROR(DMERR_FWRITE, DMERR_FWRITE, + "Could not write JSSMOD instrument #%i to file!\n", instr); + } + dmMsg(1," * %d Instrument headers, %d bytes.\n", m->ninstruments, totalSize); + + // Write sample data + for (totalSize = instr = 0; instr < m->ninstruments; instr++) + if (m->instruments[instr]) + { + JSSInstrument *inst = m->instruments[instr]; + if (inst->data != NULL) + { + size_t res; + if (inst->flags & jsf16bit) + { + jssEncodeSample16(inst->data, inst->size, flags16); + res = fwrite(inst->data, sizeof(Uint16), inst->size, outFile); + } + else + { + jssEncodeSample8(inst->data, inst->size, flags8); + res = fwrite(inst->data, sizeof(Uint8), inst->size, outFile); + } + + totalSize += inst->size; + if (res != (size_t) inst->size) + JSSERROR(DMERR_FWRITE, DMERR_FWRITE, + "Could not write JSSMOD sample #%i to file!\n", instr); + } + } + dmMsg(1," * %d samples, %d bytes.\n", m->ninstruments, totalSize); + + return DMERR_OK; +} + + +/* Optimize a given module + */ +JSSModule *optimizeModule(JSSModule *m) +{ + BOOL usedPatterns[jsetMaxPatterns + 1], + usedInstruments[jsetMaxInstruments + 1], + usedExtInstruments[jsetMaxInstruments + 1]; + int mapExtInstruments[jsetMaxInstruments + 1], + mapInstruments[jsetMaxInstruments + 1], + mapPatterns[jsetMaxPatterns + 1]; + JSSModule *r = NULL; + int i, n8, n16; + + // Allocate a new module + if ((r = jssAllocateModule()) == NULL) + return NULL; + + // Allocate tables + + // Copy things + r->moduleType = m->moduleType; + r->moduleName = dm_strdup(m->moduleName); + r->trackerName = dm_strdup(m->trackerName); + r->defSpeed = m->defSpeed; + r->defTempo = m->defTempo; + r->defFlags = m->defFlags; + r->defRestartPos = m->defRestartPos; + r->intVersion = m->intVersion; + r->nchannels = m->nchannels; + r->norders = m->norders; + for (i = 0; i < jsetNChannels; i++) + r->defPanning[i] = m->defPanning[i]; + + // Initialize values + for (i = 0; i <= jsetMaxInstruments; i++) + { + usedExtInstruments[i] = FALSE; + usedInstruments[i] = FALSE; + mapExtInstruments[i] = jsetNotSet; + mapInstruments[i] = jsetNotSet; + } + + for (i = 0; i <= jsetMaxPatterns; i++) + { + usedPatterns[i] = FALSE; + mapPatterns[i] = jsetNotSet; + } + + // Find out all used patterns and ext.instruments + for (i = 0; i < m->norders; i++) + { + int pattern = m->orderList[i]; + if (pattern >= 0 && pattern < m->npatterns) + { + JSSPattern *p = m->patterns[pattern]; + if (p != NULL) + { + int row, channel; + JSSNote *n = p->data; + + // Mark pattern as used + usedPatterns[pattern] = TRUE; + + // Check all notes + for (row = 0; row < p->nrows; row++) + for (channel = 0; channel < p->nchannels; channel++, n++) + { + if (n->instrument != jsetNotSet) + { + if (optStripExtInstr || (n->instrument >= 0 && n->instrument < m->nextInstruments)) + usedExtInstruments[n->instrument] = TRUE; + else + dmMsg(2, "Pattern 0x%x, row=0x%x, chn=%d has invalid instrument 0x%x\n", + pattern, row, channel, n->instrument); + } + } + } + else + { + dmError("Pattern 0x%x is used on order 0x%x, but has no data!\n", + pattern, i); + } + } + else + if (pattern != jsetMaxPatterns) + { + dmError("Order 0x%x has invalid pattern number 0x%x!\n", + i, pattern); + } + } + + // Find out used instruments + for (i = 0; i <= jsetMaxInstruments; i++) + if (usedExtInstruments[i] && m->extInstruments[i] != NULL) + { + int note; + JSSExtInstrument *e = m->extInstruments[i]; + + for (note = 0; note < jsetNNotes; note++) + if (e->sNumForNotes[note] != jsetNotSet) + { + int q = e->sNumForNotes[note]; + if (q >= 0 && q < m->ninstruments) + { + usedInstruments[q] = TRUE; + } + else + { + dmError("Ext.instrument #%d sNumForNotes[%d] value out range (%d < %d).\n", + i, m->ninstruments, q); + } + } + } + + // Create pattern mappings + r->npatterns = 0; + dmMsg(1, "Unused patterns: "); + + for (i = 0; i <= jsetMaxPatterns; i++) + if (m->patterns[i] != NULL) + { + if (!usedPatterns[i]) + { + dmPrint(2, "0x%x, ", i); + } + else + { + if (i >= m->npatterns) + dmError("Pattern 0x%x >= 0x%x, but used!\n", i, m->npatterns); + + mapPatterns[i] = r->npatterns; + r->patterns[r->npatterns] = m->patterns[i]; + (r->npatterns)++; + } + } + dmPrint(2, "\n"); + + dmMsg(1, "%d used patterns, %d unused.\n", + r->npatterns, m->npatterns - r->npatterns); + + + // Re-map instruments + dmMsg(1, "Unused instruments: "); + for (n8 = n16 = i = 0; i <= jsetMaxInstruments; i++) + if (m->instruments[i] != NULL) + { + if (!usedInstruments[i] && !optStripInstr) + { + dmPrint(2, "0x%x, ", i); + } + else + { + JSSInstrument *ip = m->instruments[i]; + if (i >= m->ninstruments) + dmError("Instrument 0x%x >= 0x%x, but used!\n", i, m->ninstruments); + + mapInstruments[i] = r->ninstruments; + r->instruments[r->ninstruments] = ip; + (r->ninstruments)++; + + if (ip->flags & jsf16bit) + n16++; + else + n8++; + } + } + dmPrint(2, "\n"); + dmMsg(1, "Total of (%d) 16-bit, (%d) 8-bit samples, (%d) instruments.\n", + n16, n8, r->ninstruments); + + // Re-map ext.instruments + dmMsg(1, "Unused ext.instruments: "); + for (i = 0; i < jsetMaxInstruments; i++) + if (usedExtInstruments[i]) + { + if (i >= m->nextInstruments && !optStripExtInstr) + { + dmError("Ext.instrument 0x%x >= 0x%x, but used!\n", + i, m->nextInstruments); + } + else + if (m->extInstruments[i] != NULL) + { + JSSExtInstrument *e = m->extInstruments[i]; + int note; + + mapExtInstruments[i] = r->nextInstruments; + r->extInstruments[r->nextInstruments] = e; + (r->nextInstruments)++; + + // Re-map sNumForNotes + for (note = 0; note < jsetNNotes; note++) + { + int q = e->sNumForNotes[note]; + if (q != jsetNotSet) + { + int map; + if (q >= 0 && q <= jsetMaxInstruments) + { + map = mapInstruments[q]; + } + else + { + map = jsetNotSet; + dmError("e=%d, note=%d, q=%d/%d\n", i, note, q, r->ninstruments); + } + e->sNumForNotes[note] = map; + } + } + } + else + { + dmPrint(2, "[0x%x==NULL], ", i); + mapExtInstruments[i] = jsetNotSet; + } + } + else + { + if (i < m->nextInstruments && m->extInstruments[i] != NULL) + { + dmPrint(2, "0x%x, ", i); + } + } + dmPrint(2, "\n"); + dmMsg(1, "%d extended instruments.\n", r->nextInstruments); + + + // Remap pattern instrument data + for (i = 0; i < r->npatterns; i++) + { + int row, channel; + JSSPattern *p = r->patterns[i]; + JSSNote *n = p->data; + + for (row = 0; row < p->nrows; row++) + for (channel = 0; channel < p->nchannels; channel++, n++) + { + char effect; + + if (!optStripExtInstr) + { + if (n->instrument >= 0 && n->instrument <= jsetMaxInstruments) + n->instrument = mapExtInstruments[n->instrument]; + + if (n->instrument != jsetNotSet && r->extInstruments[n->instrument] == NULL) + dmError("Non-existing instrument used #%d.\n", n->instrument); + } + + JMPGETEFFECT(effect, n->effect); + + switch (effect) + { + case 'C': // Cxx = Set volume + if (n->volume == jsetNotSet) + { + n->volume = n->param; + n->effect = jsetNotSet; + n->param = jsetNotSet; + } + break; + } + } + } + + // Remap orders list + for (i = 0; i < m->norders; i++) + { + r->orderList[i] = mapPatterns[m->orderList[i]]; + } + + return r; +} + + +int main(int argc, char *argv[]) +{ + DMResource *sfile = NULL; + FILE *dfile = NULL; + JSSModule *sm, *dm; + int result; + + dmInitProg("xm2jss", "XM to JSSMOD converter", "0.6", NULL, NULL); + dmVerbosity = 0; + + // Parse arguments + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, argHandleFile, TRUE)) + exit(1); + + // Check arguments + if (optInFilename == NULL || optOutFilename == NULL) + { + dmError("Input or output file not specified. Try --help.\n"); + return 1; + } + + // Read the source file + if ((sfile = dmf_create_stdio(optInFilename, "rb")) == NULL) + { + dmError("Error opening input file '%s', %d: %s\n", + optInFilename, errno, strerror(errno)); + return 1; + } + + // Initialize miniJSS + jssInit(); + + // Read file + dmMsg(1, "Reading XM-format file ...\n"); + result = jssLoadXM(sfile, &sm); + dmf_close(sfile); + if (result != 0) + { + dmError("Error while loading XM file (%i), ", result); + if (optIgnoreErrors) + fprintf(stderr, "ignoring. This may cause problems.\n"); + else + { + fprintf(stderr, "giving up. Use --ignore if you want to try to convert anyway.\n"); + return 2; + } + } + + // Check stripping settings + if (optStripExtInstr) optStripInstr = TRUE; + if (optStripInstr) optStripSamples = TRUE; + + // Remove samples + if (optStripSamples) + { + int i; + + dmMsg(1, "Stripping samples...\n"); + for (i = 0; i < sm->ninstruments; i++) + { + dmFree(sm->instruments[i]->data); + sm->instruments[i]->data = NULL; + } + } + + // Remove instruments + if (optStripInstr) + { + int i; + + dmMsg(1, "Stripping instruments...\n"); + for (i = 0; i < sm->ninstruments; i++) + { + dmFree(sm->instruments[i]); + sm->instruments[i] = NULL; + } + sm->ninstruments = 0; + } + + // Remove ext.instruments + if (optStripExtInstr) + { + int i; + + dmMsg(1, "Stripping ext.instruments...\n"); + for (i = 0; i < sm->nextInstruments; i++) + { + dmFree(sm->extInstruments[i]); + sm->extInstruments[i] = NULL; + } + sm->nextInstruments = 0; + } + // Run the optimization procedure + if (optOptimize) + { + dmMsg(1, "Optimizing module data...\n"); + dm = optimizeModule(sm); + } else + dm = sm; + + // Write output file + if ((dfile = fopen(optOutFilename, "wb")) == NULL) + { + dmError("Error creating output file '%s', %d: %s\n", + optOutFilename, errno, strerror(errno)); + return 1; + } + + dmMsg(1, "Writing JSSMOD-format file [patMode=0x%04x, samp8=0x%02x, samp16=0x%02x]\n", + optPatternMode, optSampMode8, optSampMode16); + + result = jssSaveJSSMOD(dfile, dm, optPatternMode, optSampMode8, optSampMode16); + + fclose(dfile); + + if (result != 0) + { + dmError("Error while saving JSSMOD file, %d: %s\n", + result, dmErrorStr(result)); + dmError("WARNING: The resulting file may be broken!\n"); + } + else + { + dmMsg(1, "Conversion complete.\n"); + } + return 0; +}
--- a/vecmattest.c Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,85 +0,0 @@ -#include "dmlib.h" -#include "dmvecmat.h" -#include "dmmutex.h" - -void printTest(const char *test, int expected, int result) -{ - fprintf(stderr, "Test '%s': %s\n", test, - expected == result ? "OK" : "FAILED!"); -} - -#define tst(X, R) printTest(# X, (X), (R)) - - -void dm_vector_fprintf(FILE *f, const char *name, DMVector *v) -{ - if (name != NULL) - fprintf(f, "%s=", name); - - fprintf(f, "[<%1.3f, %1.3f, %1.3f>=%1.3f]", v->x, v->y, v->z, dm_vector_length(v)); - - if (name != NULL) - fprintf(f, "\n"); -} - - -void dm_vector_printf(const char *name, DMVector *v) -{ - dm_vector_fprintf(stdout, name, v); -} - - -void dm_matrix_fprintf(FILE *f, const char *name, DMMatrix *mat) -{ - int i, j, k, pad = 0; - char *tmp = NULL; - - if (name != NULL) - { - tmp = dm_strdup_printf("%s=", name); - pad = strlen(tmp); - } - - for (i = 0; i < DM_MATRIX_SIZE; i++) - { - if (i == 1) - fputs(tmp, f); - else - for (k = 0; k < pad; k++) - fputc(' ', f); - - fprintf(f, "["); - for (j = 0; j < DM_MATRIX_SIZE; j++) - fprintf(f, "% 8.3f%s", mat->m[i][j], j < DM_MATRIX_SIZE - 1 ? " " : ""); - - fprintf(f, "]\n"); - } -} - - -void dm_matrix_printf(const char *name, DMMatrix *mat) -{ - dm_matrix_fprintf(stdout, name, mat); -} - - -int main(int argc, char *argv[]) -{ - DMVector a = { -5, 1, 17, 0 }, b = { 1, 2, 0.5, 0 }; - DMMatrix m; - - (void) argc; - (void) argv; - - dm_vector_printf("a", &a); - dm_vector_printf("b", &a); - - dm_matrix_rot_a(&m, 0.5, 0.9, 0.1); - dm_matrix_printf("m", &m); - - dm_vector_mul_by_mat(&b, &a, &m); - - dm_vector_printf("nb", &b); - - return 0; -}
--- a/view64.c Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,321 +0,0 @@ -/* - * 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; - - -static 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 }, -}; - -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() -{ - int i; - - dmPrintBanner(stdout, dmProgName, "[options] <input image file>"); - dmArgsPrintHelp(stdout, optList, optListN); - - printf("\nAvailable bitmap formats:\n"); - for (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) - { - dmError("Invalid scale factor %1.0f, see help for valid values.\n", factor); - return FALSE; - } - - dmSetScaleFactor(factor); - } - else - { - dmError("Invalid scale factor '%s'.\n", optArg); - return FALSE; - } - } - break; - - case 4: - { - int i; - if (sscanf(optArg, "%d", &i) == 1) - { - if (i < 0 || i >= ndmC64ImageFormats) - { - dmError("Invalid image format index %d, see help for valid values.\n", i); - return FALSE; - } - optForcedFormat = i; - } - else - { - dmError("Invalid image format argument '%s'.\n", optArg); - return FALSE; - } - } - break; - - default: - dmError("Unknown option '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -BOOL argHandleFile(char *filename) -{ - if (optFilename == NULL) - { - optFilename = dm_strdup(filename); - return TRUE; - } - else - { - dmError("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) - { - dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); - return FALSE; - } - return TRUE; -} - - -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 image; - 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, FALSE)) - exit(1); - - - if (optFilename == NULL) - { - dmError("No input file specified, perhaps you need some --help\n"); - goto error; - } - - if ((ret = dmReadDataFile(NULL, optFilename, &dataBuf, &dataSize)) != DMERR_OK) - goto error; - - dmMsg(1, "Read %d bytes of input.\n", dataSize); - - // 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(&image, dataBuf, dataSize, 0, 2, &fmt, forced); - if (forced == NULL && fmt != NULL) - { - dmMsg(0,"Probed %s format image, type %d, %s\n", - fmt->name, fmt->type, fmt->fext); - } - - if (ret < 0) - { - dmError("Probing could not find any matching image format (%d). Perhaps try forcing a format via -f\n", ret); - return -1; - } - - - // Initialize libSDL - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) - { - dmError("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) - { - dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); - goto error; - } - - // Create surface (we are lazy and ugly) - surf = SDL_CreateRGBSurface(SDL_SWSURFACE, C64_SCR_WIDTH, C64_SCR_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.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, &image, TRUE); - else - ret = dmC64ConvertGenericBMP2Image(&bmap, &image, TRUE); - - - // Set window title and caption - windowTitle = dm_strdup_printf("%s - %s", dmProgName, optFilename); - 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) - { - if (SDL_MUSTLOCK(screen) != 0 && SDL_LockSurface(screen) != 0) - { - dmError("Can't lock surface.\n"); - goto error; - } - - dmScaledBlitSurface8to8(surf, 0, 0, screen->w, screen->h, 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: - if (screen) - SDL_FreeSurface(screen); - - if (initSDL) - SDL_Quit(); - - return 0; -}
--- a/viewmod.c Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,475 +0,0 @@ -/* - * viewmod - View information about given module file - * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2006-2007 Tecnic Software productions (TNSP) - * - * Please read file 'COPYING' for information on license and distribution. - */ -#include "jss.h" -#include "jssmod.h" -#include <errno.h> -#include <string.h> -#include "dmargs.h" -#include "dmmutex.h" - - -char *optFilename = NULL; -BOOL optViewPatterns = FALSE, - optViewInstruments = FALSE, - optViewExtInstruments = FALSE, - optViewGeneralInfo = FALSE; - - -DMOptArg optList[] = -{ - { 0, '?', "help", "Show this help and exit", OPT_NONE }, - { 1, 'p', "patterns", "View patterns", OPT_NONE }, - { 2, 'i', "instruments", "View instruments", OPT_NONE }, - { 5, 'e', "extinstruments", "View extended instruments", OPT_NONE }, - { 3, 'g', "general", "General information", OPT_NONE }, - { 4, 'v', "verbose", "Be more verbose", OPT_NONE }, -}; - -const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - dmPrintBanner(stdout, dmProgName, "[options] [modfile]"); - dmArgsPrintHelp(stdout, optList, optListN); -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - (void) optArg; - - switch (optN) - { - case 0: - argShowHelp(); - exit(0); - break; - - case 1: - optViewPatterns = TRUE; - break; - - case 2: - optViewInstruments = TRUE; - break; - - case 3: - optViewGeneralInfo = TRUE; - break; - - case 4: - dmVerbosity++; - break; - - case 5: - optViewExtInstruments = TRUE; - break; - - default: - dmError("Unknown argument '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -BOOL argHandleFile(char *currArg) -{ - // Was not option argument - if (!optFilename) - optFilename = currArg; - else { - dmError("Gay error '%s'!\n", currArg); - return FALSE; - } - - return TRUE; -} - - -const char patNoteTable[12][3] = -{ - "C-", "C#", "D-", - "D#", "E-", "F-", - "F#", "G-", "G#", - "A-", "A#", "B-" -}; - -#define jmpNMODEffectTable (36) -static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - -/* Print a given pattern - */ -void printPattern(FILE *f, JSSPattern *p) -{ - int i, j; - char c; - JSSNote *n; - - if (!p) - return; - - n = p->data; - - for (i = 0; i < p->nrows; i++) - { - fprintf(f, "%.2x: ", i); - - for (j = 0; j < p->nchannels; j++) - { - switch (n->note) - { - case jsetNotSet: - fprintf(f, "... "); - break; - case jsetNoteOff: - fprintf(f, "=== "); - break; - default: - fprintf(f, "%s%i ", patNoteTable[n->note % 12], n->note / 12); - break; - } - - if (n->instrument != jsetNotSet) - fprintf(f, "%.2x ", n->instrument + 1); // Because FT2 is 1-based and we use 0 internally - else - fprintf(f, ".. "); - - if (n->volume == jsetNotSet) - fprintf(f, ".. "); - else if (n->volume >= 0x00 && n->volume <= 0x40) - fprintf(f, "%.2x ", n->volume); - else - { - switch (n->volume & 0xf0) - { - case 0x50: c = '-'; break; - case 0x60: c = '+'; break; - case 0x70: c = '/'; break; - case 0x80: c = '\\'; break; - case 0x90: c = 'S'; break; - case 0xa0: c = 'V'; break; - case 0xb0: c = 'P'; break; - case 0xc0: c = '<'; break; - case 0xd0: c = '>'; break; - case 0xe0: c = 'M'; break; - default: c = '?'; break; - } - fprintf(f, "%c%x ", c, (n->volume & 0x0f)); - } - - if (n->effect >= 0 && n->effect < jmpNMODEffectTable) - fprintf(f, "%c", jmpMODEffectTable[n->effect]); - else if (n->effect == jsetNotSet) - fprintf(f, "."); - else - fprintf(f, "?"); - - if (n->param != jsetNotSet) - fprintf(f, "%.2x|", n->param); - else - fprintf(f, "..|"); - - n++; - } - - fprintf(f, "\n"); - } -} - - -/* - * Print given extended instrument - */ -void printEnvelope(FILE *f, JSSEnvelope *e, char *s) -{ - int i; - - fprintf(f, - "\t%s-envelope:\n" - "\t - flags.....: %.4x", s, e->flags); - - if (e->flags & jenvfUsed) - fprintf(f, " [used]"); - if (e->flags & jenvfSustain) - fprintf(f, " [sust]"); - if (e->flags & jenvfLooped) - fprintf(f, " [loop]"); - - fprintf(f, "\n" - "\t - npoints...: %i\n" - "\t - sustain...: %i\n" - "\t - loopS.....: %i\n" - "\t - loopE.....: %i\n", - e->npoints, e->sustain, e->loopS, e->loopE); - - if (dmVerbosity >= 2) - { - fprintf(f, "\t - Points....:"); - for (i = 0; i < e->npoints; i++) - { - fprintf(f, " [%i:%i]", - e->points[i].frame, e->points[i].value); - } - - fprintf(f, "\n"); - } -} - - -void printExtInstrument(FILE *f, JSSExtInstrument *i) -{ - if (!i) - { - fprintf(f, "\n"); - return; - } - -#ifndef JSS_LIGHT - if (i->desc) - fprintf(f, - "Description: '%s'\n", i->desc); -#endif - fprintf(f, - "nsamples.......: %i\n" - "vibratoType....: %i\n" - "vibratoSweep...: %i\n" - "vibratoDepth...: %i\n" - "vibratoRate....: %i\n" - "fadeOut........: %i\n", - i->nsamples, i->vibratoType, i->vibratoSweep, - i->vibratoDepth, i->vibratoRate, i->fadeOut); - - if (dmVerbosity >= 1) - { - printEnvelope(f, &i->volumeEnv, "Volume"); - printEnvelope(f, &i->panningEnv, "Panning"); - } - fprintf(f, "\n"); -} - - -void printInstrument(FILE *f, JSSInstrument *i) -{ - if (!i) - { - fprintf(f, "\n"); - return; - } - - if (dmVerbosity >= 1) - { -#ifndef JSS_LIGHT - if (i->desc) - fprintf(f, "Description: '%s'\n", i->desc); -#endif - fprintf(f, - "size...........: %ld (0x%lx)\n" - "loopStart......: %ld (0x%lx)\n" - "loopEnd........: %ld (0x%lx)\n" - "volume.........: %d (0x%x)\n" - "flags..........: 0x%x ", - (unsigned long) i->size, (unsigned long) i->size, - (unsigned long) i->loopS, (unsigned long) i->loopE, - (unsigned long) i->loopS, (unsigned long) i->loopE, - i->volume, i->volume, - i->flags); - - if (i->flags & jsfLooped) fprintf(f, "[loop] "); - if (i->flags & jsfBiDi) fprintf(f, "[bi-di] "); - if (i->flags & jsf16bit) fprintf(f, "[16bit] "); - - fprintf(f, - "\nC4BaseSpeed....: %d (0x%x)\n" - "ERelNote.......: %d (%s%d)\n" - "EFineTune......: %d\n" - "EPanning,,,....: %d (0x%x)\n\n", - i->C4BaseSpeed, i->C4BaseSpeed, - i->ERelNote, patNoteTable[(48 + i->ERelNote) % 12], (48 + i->ERelNote) / 12, - i->EFineTune, i->EPanning, i->EPanning); - } - else - { -#ifndef JSS_LIGHT - if (i->desc) - fprintf(f, "'%s', ", i->desc); -#endif - fprintf(f, - "s=%ld (%lx), l=%ld-%ld (%lx-%lx), v=%i (%x), f=0x%x, c4=%i (%x), rn=%i (%s%i), ft=%i, pn=%i (%x)\n", - (unsigned long) i->size, (unsigned long) i->size, - (unsigned long) i->loopS, (unsigned long) i->loopE, - (unsigned long) i->loopS, (unsigned long) i->loopE, - i->volume, i->volume, i->flags, i->C4BaseSpeed, - i->C4BaseSpeed, i->ERelNote, - patNoteTable[(48 + i->ERelNote) % 12], - (48 + i->ERelNote) / 12, i->EFineTune, - i->EPanning, i->EPanning); - } -} - - -void printGeneralInfo(FILE *f, JSSModule *m) -{ - int i; - - if (!m) - return; - - fprintf(f, "Module type.....: %i\n", m->moduleType); -#ifndef JSS_LIGHT - if (m->moduleName) - fprintf(f, "Module name.....: '%s'\n", m->moduleName); - if (m->trackerName) - fprintf(f, "Tracker name....: '%s'\n", m->trackerName); -#endif - fprintf(f, - "Speed...........: %d ticks\n" - "Tempo...........: %d bpm\n" - "Flags...........: %x ", - m->defSpeed, m->defTempo, m->defFlags); - - if (m->defFlags & jmdfAmigaPeriods) fprintf(f, "[Amiga periods] "); - if (m->defFlags & jmdfAmigaLimits) fprintf(f, "[Amiga limits] "); - if (m->defFlags & jmdfStereo) fprintf(f, "[stereo] "); - if (m->defFlags & jmdfFT2Replay) fprintf(f, "[FT2 replay] "); - if (m->defFlags & jmdfST300Slides) fprintf(f, "[ST300 slides] "); - if (m->defFlags & jmdfByteLStart) fprintf(f, "[ByteStart] "); - - fprintf(f, "\n" - "Restart pos.....: %d (order)\n" - "IntVersion......: %x\n" - "Channels........: %d\n" - "Instruments.....: %d\n" - "Ext.instruments.: %d\n" - "Patterns........: %d\n" - "Orders..........: %d\n", - m->defRestartPos, m->intVersion, m->nchannels, - m->ninstruments, m->nextInstruments, m->npatterns, - m->norders); - - if (dmVerbosity >= 1) - { - fprintf(f, "Orderlist: "); - for (i = 0; i < m->norders - 1; i++) - fprintf(f, "%d, ", m->orderList[i]); - if (i < m->norders) - fprintf(f, "%d", m->orderList[i]); - fprintf(f, "\n"); - } -} - - - -int main(int argc, char *argv[]) -{ - int result = -1, i; - DMResource *file; - JSSModule *mod; - - dmInitProg("viewmod", "miniJSS Module Viewer", "0.4", NULL, NULL); - dmVerbosity = 0; - - // Parse arguments - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, argHandleFile, TRUE)) - exit(1); - - // Initialize miniJSS - jssInit(); - - // Open the file - dmMsg(1, "Reading module file '%s'\n", optFilename); - if (optFilename == NULL) - file = dmf_create_stdio_stream(stdin); - else if ((file = dmf_create_stdio(optFilename, "rb")) == NULL) - { - dmError("Error opening input file '%s'. (%s)\n", - optFilename, strerror(errno)); - return 1; - } - - // Read module file - dmMsg(1, "Reading file: %s\n", optFilename); -#ifdef JSS_SUP_XM - dmMsg(1, "* Trying XM...\n"); - result = jssLoadXM(file, &mod); -#endif -#ifdef JSS_SUP_JSSMOD - if (result != 0) - { - size_t bufgot, bufsize = dmfsize(file); - Uint8 *buf = dmMalloc(bufsize); - dmfseek(file, 0L, SEEK_SET); - dmMsg(1, "* Trying JSSMOD (%d bytes, %p)...\n", bufsize, buf); - if ((bufgot = dmfread(buf, 1, bufsize, file)) != bufsize) - { - dmError("Error reading file (not enough data %d), #%d: %s\n", - bufgot, dmferror(file), dmErrorStr(dmferror(file))); - return 2; - } - result = jssLoadJSSMOD(buf, bufsize, &mod); - dmFree(buf); - } -#endif - dmf_close(file); - if (result != DMERR_OK) - { - dmError("Error loading module file, %d: %s\n", - result, dmErrorStr(result)); - return 3; - } - - // Print out information - if (optViewGeneralInfo) - printGeneralInfo(stdout, mod); - - if (optViewPatterns) - { - for (i = 0; i < mod->npatterns; i++) - { - printf("\nPattern #%03i:\n", i); - printPattern(stdout, mod->patterns[i]); - } - } - - if (optViewExtInstruments) - { - printf("\n" - "ExtInstruments:\n" - "---------------\n" - ); - for (i = 0; i < mod->nextInstruments; i++) - { - printf("#%03i: ", i + 1); - printExtInstrument(stdout, mod->extInstruments[i]); - } - } - - if (optViewInstruments) - { - printf("\n" - "Instruments:\n" - "------------\n" - ); - for (i = 0; i < mod->ninstruments; i++) - { - printf("#%03i: ", i + 1); - printInstrument(stdout, mod->instruments[i]); - } - } - - // Free module data - jssFreeModule(mod); - jssClose(); - - exit(0); - return 0; -}
--- a/vptest.c Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,394 +0,0 @@ -#include "dmlib.h" -#include "dmargs.h" -#include "dmres.h" -#include "dmimage.h" -#include "dmtext.h" -#include "dmq3d.h" -#include "dmvecmat.h" -#include <math.h> - -#define DM_COLORS (256) - -char *optFontFile = "font.ttf", - *optBitmapFilename = "blurri.png"; -BOOL optBenchmark = FALSE; -int optVFlags = SDL_SWSURFACE | SDL_HWPALETTE; -int optScrWidth = 640, optScrHeight = 480, optFontSize = 8, optScrDepth = 32; -int optBenchmarkLen = 20; - -DMOptArg optList[] = { - { 0, '?', "help", "Show this help", OPT_NONE }, - { 2, 'v', "verbose", "Be more verbose", OPT_NONE }, - { 3, 'f', "full", "Fullscreen", OPT_NONE }, - { 4, 'h', "hw", "Use SDL hardware surface", OPT_NONE }, - { 5, 's', "size", "Initial window size/resolution -s 640x480", OPT_ARGREQ }, - { 6, 'd', "depth", "Color depth of mode/window in bits (8/15/16/32)", OPT_ARGREQ }, - { 7, 'b', "bench", "Run in benchmark mode", OPT_NONE }, -}; - -const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - dmArgsPrintHelp(stdout, optList, optListN); -} - - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - switch (optN) { - case 0: - argShowHelp(); - exit(0); - break; - - case 2: - dmVerbosity++; - break; - - case 3: - optVFlags |= SDL_FULLSCREEN; - break; - - case 6: - if (optArg) - optScrDepth = atoi(optArg); - break; - - case 5: - { - int w, h; - if (sscanf(optArg, "%dx%d", &w, &h) == 2) - { - if (w < 320 || h < 200 || w > 3200 || h > 3200) - { - dmError("Invalid width or height: %d x %d\n", w, h); - return FALSE; - } - optScrWidth = w; - optScrHeight = h; - } - else - { - dmError("Invalid size argument '%s'.\n", optArg); - return FALSE; - } - } - break; - - case 7: - optBenchmark = TRUE; - break; - - default: - dmError("Unknown option '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -void DM_PrintRect(FILE *f, SDL_Rect *r) -{ - fprintf(f, "SDL_Rect <%d, %d : %d, %d>\n", - r->x, r->y, r->w, r->h); -} - - -BOOL DM_InitializeVideo(SDL_Surface **screen) -{ - *screen = SDL_SetVideoMode(optScrWidth, optScrHeight, optScrDepth, optVFlags | SDL_RESIZABLE); - if (*screen == NULL) - { - dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); - return FALSE; - } - return TRUE; -} - - -int main(int argc, char *argv[]) -{ - SDL_Surface *screen = NULL, *bmap = NULL, *fbmap = NULL, *screen2 = NULL; - SDL_Color fontcol = { 255, 155, 155, 0 }; - SDL_Event event; - TTF_Font *font = NULL; - int mouseX, mouseY, bx, by, err; - BOOL initSDL = FALSE, initTTF = FALSE, exitFlag; - DM3DVectorSpriteModel *model, *model2; - - dmVerbosity = 5; - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, NULL, FALSE)) - exit(1); - - if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) - { - dmError("Could not initialize SDL: %s\n", SDL_GetError()); - goto error_exit; - } - initSDL = TRUE; - - - if (TTF_Init() < 0) - { - dmError("Could not initialize FreeType/TTF: %s\n", SDL_GetError()); - goto error_exit; - } - initTTF = TRUE; - - font = TTF_OpenFont(optFontFile, optFontSize); - if (font == NULL) - { - dmError("Could not load TTF font '%s' (%d): %s\n", - optFontFile, optFontSize, SDL_GetError()); - goto error_exit; - } - TTF_SetFontStyle(font, TTF_STYLE_NORMAL); - - DMResource *res = dmf_create_stdio(optBitmapFilename, "rb"); - if (res == NULL) - { - dmError("Could not open resource file '%s'.\n", optBitmapFilename); - goto error_exit; - } - bmap = dmLoadImage(res); - dmf_close(res); - if (bmap == NULL) - { - dmError("Could not load image file '%s'.\n", optBitmapFilename); - goto error_exit; - } - - res = dmf_create_stdio("trans6x6.png", "rb"); - if (res == NULL) - { - dmError("Could not open resource file '%s'.\n", optBitmapFilename); - goto error_exit; - } - fbmap = dmLoadImage(res); - dmf_close(res); - if (fbmap == NULL) - { - dmError("Could not load image file '%s'.\n", optBitmapFilename); - goto error_exit; - } - - - res = dmf_create_stdio("mole.3d", "r"); - if (res == NULL) - { - dmError("Could not open resource file '%s'.\n", optBitmapFilename); - goto error_exit; - } - err = dmRead3DVectorSpriteModel(res, &model); - dmf_close(res); - dmMsg(0, "Loaded, %d: %s\n", err, dmErrorStr(err)); - - res = dmf_create_stdio("roto.3d", "r"); - if (res == NULL) - { - dmError("Could not open resource file '%s'.\n", optBitmapFilename); - goto error_exit; - } - err = dmRead3DVectorSpriteModel(res, &model2); - dmf_close(res); - dmMsg(0, "Loaded, %d: %s\n", err, dmErrorStr(err)); - - if (optBenchmark) - { - screen = SDL_CreateRGBSurface(SDL_SWSURFACE, optScrWidth, optScrHeight, optScrDepth, 0, 0, 0, 0); - if (screen == NULL) - { - dmError("Could not create screen surface.\n"); - goto error_exit; - } - - dmMsg(0, "Benchmark mode, not opening window.\n"); - } - else - { - if (!DM_InitializeVideo(&screen)) - goto error_exit; - - SDL_WM_SetCaption("Halleluja", "DMT"); - } - - screen2 = SDL_CreateRGBSurface(SDL_SWSURFACE, optScrWidth, optScrHeight, optScrDepth, 0, 0, 0, 0); - Uint32 lcol = dmMapRGB(screen, 255,255,255); - - int numFrames = 0, startTime = SDL_GetTicks(), endTime = 0; - exitFlag = FALSE; - - if (optBenchmark) - dmMsg(0, "Starting benchmark, running for %d seconds.\n", optBenchmarkLen); - - while (!exitFlag) - { - if (!optBenchmark) - { - while (SDL_PollEvent(&event)) - switch (event.type) - { - case SDL_KEYDOWN: - switch (event.key.keysym.sym) - { - case SDLK_ESCAPE: exitFlag = TRUE; break; - - default: - break; - } - - break; - - case SDL_VIDEORESIZE: - optScrWidth = event.resize.w; - optScrHeight = event.resize.h; - - if (!DM_InitializeVideo(&screen)) - goto error_exit; - - break; - - case SDL_VIDEOEXPOSE: - break; - - case SDL_QUIT: - exit(0); - } - - SDL_GetMouseState(&mouseX, &mouseY); - bx = 300 - ((DMFloat) mouseX * 500.0f ) / (DMFloat) optScrWidth; - by = 300 - ((DMFloat) mouseY * 500.0f ) / (DMFloat) optScrHeight; - } - else - { - bx = 0; - by = 0; - } - - if (!optBenchmark && SDL_MUSTLOCK(screen) != 0 && SDL_LockSurface(screen) != 0) - { - dmError("Can't lock surface.\n"); - goto error_exit; - } - - - dmClearSurface(screen, 0); - - float f = SDL_GetTicks() / 150.0f, - qw2 = (float) 132.0 * (1.0 + sin(f) * 0.1), - qh2 = (float) 132.0 * (1.0 + sin(f) * 0.1); - -#if 1 - dmScaledBlitSurfaceAny(bmap, bx-qw2, by-qh2, bmap->w+qw2, bmap->h+qh2, screen, - DMD_TRANSPARENT -// DMD_SATURATE -// DMD_NONE - ); -#endif -#if 0 - float qw = (float) 32.0 * (1.0 + sin(f) * 0.1), - qh = (float) 32.0 * (1.0 + sin(f) * 0.1), - dmScaledBlitSurface32to32TransparentGA(bmap, bx*2-qw, by*2-qh, bmap->w+qw, bmap->h+qh, screen, - 128 + sin(f*0.1) * 120.0f); -#endif - -#if 1 - DMVector pos; - - DMMatrix mat; -// dm_matrix_rot_a(&mat, f*0.1, 0, (3.1415926535f * 2.0f * ((DMFloat) mouseX + (DMFloat) mouseY) ) / 500.0f); -// dm_matrix_rot_a(&mat, f*0.1, f*0.1, f*0.1); - dm_matrix_rot_a(&mat, 0, 0, f*0.1); - - pos.x = -118; - pos.y = 0; - pos.z = 100; - - dmDraw3DVectorSpriteModel(screen, model2, &pos, &mat, fbmap, lcol); - - pos.x = 118; - pos.y = 0; - pos.z = 100; - - dm_matrix_rot_a(&mat, 0, 0, -f*0.1+0.125); - dmDraw3DVectorSpriteModel(screen, model2, &pos, &mat, fbmap, lcol); - - -#endif - -#if 0 - int np; - dmClearSurface(screen2, 0); - for (np = 1; np <= 5; np++) - { - float n = ((float) np - 0.5f) * np; - dmScaledBlitSurface32to32TransparentGA(screen, -n, -n, screen->w + n*2.0f, screen->h + n*2.0f, screen2, - 210 - np * 10 - ); - dmDirectBlitSurface(screen2, screen); - } - - dmDraw3DVectorSpriteModel(screen, model, &pos, &mat, fbmap, lcol); - - for (np = 1; np <= 5; np++) - { - float n = ((float) np - 0.5f) / 2.0f; - dmScaledBlitSurface32to32TransparentGA(screen, -n, -n, screen->w + n*2.0f, screen->h + n*2.0f, screen2, - 210 - np * 10 - ); - dmDirectBlitSurface(screen2, screen); - } - -#endif - - if (!optBenchmark) - { - dmDrawTTFText(screen, font, fontcol, 0, 0, "%3.1f FPS", - (float) (numFrames * 1000.0f) / (float) (endTime - startTime)); - - if (SDL_MUSTLOCK(screen) != 0) - SDL_UnlockSurface(screen); - - SDL_Flip(screen); - SDL_Delay(25); - } - - endTime = SDL_GetTicks(); - numFrames++; - - if (optBenchmark) - { - if (endTime - startTime > optBenchmarkLen * 1000) - exitFlag = TRUE; - } - } - - // Print benchmark results - dmMsg(0, "%d frames in %d ms, fps = %1.3f\n", - numFrames, endTime - startTime, - (float) (numFrames * 1000.0f) / (float) (endTime - startTime)); - - -error_exit: - dmMsg(0, "Shutting down dmlib.\n"); - if (screen) - SDL_FreeSurface(screen); - - if (bmap) - SDL_FreeSurface(bmap); - - if (font) - TTF_CloseFont(font); - - if (initSDL) - SDL_Quit(); - - if (initTTF) - TTF_Quit(); - - return 0; -}
--- a/xm2jss.c Tue Apr 16 05:55:13 2013 +0300 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,1040 +0,0 @@ -/* - * xm2jss - Convert XM module to JSSMOD - * Programmed and designed by Matti 'ccr' Hamalainen - * (C) Copyright 2006-2009 Tecnic Software productions (TNSP) - * - * Please read file 'COPYING' for information on license and distribution. - */ -#include <stdio.h> -#include <errno.h> -#include "jss.h" -#include "jssmod.h" -#include "jssplr.h" -#include "dmlib.h" -#include "dmargs.h" -#include "dmres.h" -#include "dmmutex.h" - - -#define jmpNMODEffectTable (36) -static const char jmpMODEffectTable[jmpNMODEffectTable] = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; - - -char *optInFilename = NULL, *optOutFilename = NULL; -BOOL optIgnoreErrors = FALSE, - optStripExtInstr = FALSE, - optStripInstr = FALSE, - optStripSamples = FALSE, - optOptimize = FALSE; - -int optPatternMode = PATMODE_COMP_HORIZ, - optSampMode16 = jsampDelta, - optSampMode8 = jsampFlipSign | jsampDelta; - -#define SAMPMODE_MASK (jsampFlipSign | jsampSwapEndianess | jsampSplit | jsampDelta) - - -static const char* patModeTable[PATMODE_LAST] = -{ - "Raw horizontal", - "Compressed horizontal (similar to XM modules)", - "Raw vertical", - "Compressed vertical", - "Raw vertical for each element", -}; - - -DMOptArg optList[] = { - { 0, '?', "help", "Show this help", OPT_NONE }, - { 1, 'v', "verbose", "Be more verbose", OPT_NONE }, - { 2, 'i', "ignore", "Ignore errors", OPT_NONE }, - { 3, 'p', "patterns", "Pattern storage mode", OPT_ARGREQ }, - { 4, 'E', "strip-ext-instr","Strip ext. instruments (implies -I -S)", OPT_NONE }, - { 5, 'I', "strip-instr", "Strip instruments (implies -S)", OPT_NONE }, - { 6, 'S', "strip-samples", "Strip instr. sampledata", OPT_NONE }, - { 7, '8', "smode8", "8-bit sample conversion flags", OPT_ARGREQ }, - { 8, '1', "smode16", "16-bit sample conversion flags", OPT_ARGREQ }, - { 9, 'O', "optimize", "Optimize module", OPT_NONE }, -}; - -const int optListN = sizeof(optList) / sizeof(optList[0]); - - -void argShowHelp() -{ - int i; - - dmPrintBanner(stdout, dmProgName, "[options] <input.xm> <output.jmod>"); - dmArgsPrintHelp(stdout, optList, optListN); - - printf("\n" - "Pattern storage modes:\n"); - - for (i = 1; i < PATMODE_LAST; i++) - printf(" %d = %s\n", i, patModeTable[i-1]); - - printf( - "\n" - "Sample data conversion flags (summative):\n" - " 1 = Delta encoding (DEF 8 & 16)\n" - " 2 = Flip signedness (DEF 8)\n" - " 4 = Swap endianess (affects 16-bit only)\n" - " 8 = Split and de-interleave hi/lo bytes (affects 16-bit only)\n" - "\n" - ); -} - -BOOL argHandleOpt(const int optN, char *optArg, char *currArg) -{ - (void) optArg; - - switch (optN) - { - case 0: - argShowHelp(); - exit(0); - break; - - case 1: - dmVerbosity++; - break; - - case 2: - optIgnoreErrors = TRUE; - break; - - case 3: - optPatternMode = atoi(optArg); - if (optPatternMode <= 0 || optPatternMode >= PATMODE_LAST) - { - dmError("Unknown pattern conversion mode %d\n", optPatternMode); - return FALSE; - } - break; - - case 4: optStripExtInstr = TRUE; break; - case 5: optStripInstr = TRUE; break; - case 6: optStripSamples = TRUE; break; - - case 7: optSampMode8 = atoi(optArg) & SAMPMODE_MASK; break; - case 8: optSampMode16 = atoi(optArg) & SAMPMODE_MASK; break; - - case 9: optOptimize = TRUE; break; - - default: - dmError("Unknown argument '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -BOOL argHandleFile(char *currArg) -{ - // Was not option argument - if (!optInFilename) - optInFilename = currArg; - else - if (!optOutFilename) - optOutFilename = currArg; - else - { - dmError("Too many filename arguments specified, '%s'.\n", currArg); - return FALSE; - } - - return TRUE; -} - - -/* These functions and the macro mess are meant to make the - * conversion routines themselves clearer and simpler. - */ -BOOL jsPutByte(Uint8 *patBuf, size_t patBufSize, size_t *npatBuf, Uint8 val) -{ - if (*npatBuf >= patBufSize) - return FALSE; - else - { - patBuf[*npatBuf] = val; - (*npatBuf)++; - return TRUE; - } -} - -#define JSPUTBYTE(x) do { if (!jsPutByte(patBuf, patBufSize, patSize, x)) return DMERR_BOUNDS; } while (0) - -#define JSCOMP(x,z) do { if ((x) != jsetNotSet) { qflags |= (z); qcomp++; } } while (0) - -#define JSCOMPPUT(xf,xv,qv) do { \ - if (qflags & (xf)) { \ - if ((xv) < 0 || (xv) > 255) \ - JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, \ - "%s value out of bounds %d.\n", qv, (xv)); \ - JSPUTBYTE(xv); \ - } \ -} while (0) - -#define JSCONVPUT(xv,qv) do { \ - if ((xv) != jsetNotSet) { \ - if ((xv) < 0 || (xv) > 254) \ - JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, \ - "%s value out of bounds %d.\n", qv, (xv)); \ - JSPUTBYTE((xv) + 1); \ - } else { \ - JSPUTBYTE(0); \ - } \ -} while (0) - - -/* Convert a note - */ -static int jssConvertNote(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSNote *note) -{ - Uint8 tmp; - if (note->note == jsetNotSet) - tmp = 0; - else if (note->note == jsetNoteOff) - tmp = 127; - else - tmp = note->note + 1; - - if (tmp > 0x7f) - JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp); - - JSPUTBYTE(tmp & 0x7f); - - JSCONVPUT(note->instrument, "Instrument"); - JSCONVPUT(note->volume, "Volume"); - JSCONVPUT(note->effect, "Effect"); - - tmp = (note->param != jsetNotSet) ? note->param : 0; - JSPUTBYTE(tmp); - - return DMERR_OK; -} - - -/* Compress a note - */ -static int jssCompressNote(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSNote *note) -{ - Uint8 qflags = 0; - int qcomp = 0; - - JSCOMP(note->note, COMP_NOTE); - JSCOMP(note->instrument, COMP_INSTRUMENT); - JSCOMP(note->volume, COMP_VOLUME); - JSCOMP(note->effect, COMP_EFFECT); - if (note->param != jsetNotSet && note->param != 0) - { - qflags |= COMP_PARAM; - qcomp++; - } - - if (qcomp < 4) - { - JSPUTBYTE(qflags | 0x80); - - if (note->note != jsetNotSet) - { - Uint8 tmp = (note->note != jsetNoteOff) ? note->note : 127; - if (tmp > 0x7f) - JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp); - JSPUTBYTE(tmp); - } - - JSCOMPPUT(COMP_INSTRUMENT, note->instrument, "Instrument"); - JSCOMPPUT(COMP_VOLUME, note->volume, "Volume"); - JSCOMPPUT(COMP_EFFECT, note->effect, "Effect"); - JSCOMPPUT(COMP_PARAM, note->param, "Param"); - } else - return jssConvertNote(patBuf, patBufSize, patSize, note); - - return DMERR_OK; -} - - -/* Compress pattern - */ -static int jssConvertPatternCompHoriz(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) -{ - int row, channel; - *patSize = 0; - - for (row = 0; row < pattern->nrows; row++) - for (channel = 0; channel < pattern->nchannels; channel++) - { - const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; - const int res = jssCompressNote(patBuf, patBufSize, patSize, note); - if (res != DMERR_OK) - { - JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", - patBuf, patBufSize, *patSize, row, channel); - return res; - } - } - - return DMERR_OK; -} - - -static int jssConvertPatternCompVert(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) -{ - int row, channel; - *patSize = 0; - - for (channel = 0; channel < pattern->nchannels; channel++) - for (row = 0; row < pattern->nrows; row++) - { - const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; - const int res = jssCompressNote(patBuf, patBufSize, patSize, note); - if (res != DMERR_OK) - { - JSSERROR(res, res, "Note compression failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", - patBuf, patBufSize, *patSize, row, channel); - return res; - } - } - - return DMERR_OK; -} - - -/* Convert a pattern - */ -static int jssConvertPatternRawHoriz(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) -{ - int row, channel; - *patSize = 0; - - for (row = 0; row < pattern->nrows; row++) - for (channel = 0; channel < pattern->nchannels; channel++) - { - const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; - const int res = jssConvertNote(patBuf, patBufSize, patSize, note); - if (res != DMERR_OK) - { - JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", - patBuf, patBufSize, *patSize, row, channel); - return res; - } - } - - return DMERR_OK; -} - - -static int jssConvertPatternRawVert(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) -{ - int row, channel; - *patSize = 0; - - for (channel = 0; channel < pattern->nchannels; channel++) - for (row = 0; row < pattern->nrows; row++) - { - const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; - const int res = jssConvertNote(patBuf, patBufSize, patSize, note); - if (res != DMERR_OK) - { - JSSERROR(res, res, "Note conversion failed [patBuf=%p, patBufSize=%d, patSize=%d, row=%d, chn=%d]\n", - patBuf, patBufSize, *patSize, row, channel); - return res; - } - } - - return DMERR_OK; -} - - -#define JSFOREACHNOTE1 \ - for (channel = 0; channel < pattern->nchannels; channel++) \ - for (row = 0; row < pattern->nrows; row++) { \ - const JSSNote *note = &pattern->data[(pattern->nchannels * row) + channel]; - -#define JSFOREACHNOTE2 } - -static int jssConvertPatternRawElem(Uint8 *patBuf, const size_t patBufSize, size_t *patSize, const JSSPattern *pattern) -{ - Uint8 tmp; - int row, channel; - *patSize = 0; - - JSFOREACHNOTE1; - if (note->note == jsetNotSet) - tmp = 0; - else if (note->note == jsetNoteOff) - tmp = 127; - else - tmp = note->note + 1; - if (tmp > 0x7f) - JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, "Note value out of bounds %d > 0x7f.\n", tmp); - JSPUTBYTE(tmp); - JSFOREACHNOTE2; - - JSFOREACHNOTE1; - JSCONVPUT(note->instrument, "Instrument"); - JSFOREACHNOTE2; - - JSFOREACHNOTE1; - JSCONVPUT(note->volume, "Volume"); - JSFOREACHNOTE2; - - JSFOREACHNOTE1; - JSCONVPUT(note->effect, "Effect"); - JSFOREACHNOTE2; - - JSFOREACHNOTE1; - tmp = (note->param != jsetNotSet) ? note->param : 0; - JSPUTBYTE(tmp); - JSFOREACHNOTE2; - - return DMERR_OK; -} - -#undef JSFOREACHNOTE1 -#undef JSFOREACHNOTE2 - - -static void jssCopyEnvelope(JSSMODEnvelope *je, JSSEnvelope *e) -{ - int i; - - je->flags = e->flags; - je->npoints = e->npoints; - je->sustain = e->sustain; - je->loopS = e->loopS; - je->loopE = e->loopE; - - for (i = 0; i < e->npoints; i++) - { - je->points[i].frame = e->points[i].frame; - je->points[i].value = e->points[i].value; - } -} - - -/* Save a JSSMOD file - */ -int jssSaveJSSMOD(FILE *outFile, JSSModule *m, int patMode, int flags8, int flags16) -{ - JSSMODHeader jssH; - int i, pattern, order, instr, totalSize; - const size_t patBufSize = 64*1024; // 64kB pattern buffer - Uint8 *patBuf; - - // Check the module - if (m == NULL) - JSSERROR(DMERR_NULLPTR, DMERR_NULLPTR, "Module pointer was NULL\n"); - - if ((m->nchannels < 1) || (m->npatterns < 1) || (m->norders < 1)) - JSSERROR(DMERR_BOUNDS, DMERR_BOUNDS, - "Module had invalid values (nchannels=%i, npatterns=%i, norders=%i)\n", - m->nchannels, m->npatterns, m->norders); - - // Create the JSSMOD header - jssH.idMagic[0] = 'J'; - jssH.idMagic[1] = 'M'; - jssH.idVersion = JSSMOD_VERSION; - jssH.norders = m->norders; - jssH.npatterns = m->npatterns; - jssH.nchannels = m->nchannels; - jssH.nextInstruments = m->nextInstruments; - jssH.ninstruments = m->ninstruments; - jssH.defFlags = m->defFlags; - jssH.intVersion = m->intVersion; - jssH.defRestartPos = m->defRestartPos; - jssH.defSpeed = m->defSpeed; - jssH.defTempo = m->defTempo; - jssH.patMode = patMode; - - // Write header - totalSize = sizeof(jssH); - if (fwrite(&jssH, sizeof(jssH), 1, outFile) != 1) - JSSERROR(DMERR_FWRITE, DMERR_FWRITE, "Could not write JSSMOD header!\n"); - - dmMsg(1," * JSSMOD-header 0x%04x, %d bytes.\n", JSSMOD_VERSION, totalSize); - - // Write orders list - for (totalSize = order = 0; order < m->norders; order++) - { - Uint16 tmp = m->orderList[order]; - totalSize += sizeof(tmp); - if (fwrite(&tmp, sizeof(tmp), 1, outFile) != 1) - JSSERROR(DMERR_FWRITE, DMERR_FWRITE, "Could not write JSSMOD orders list.\n"); - } - - dmMsg(1," * %d item orders list, %d bytes.\n", - m->norders, totalSize); - - // Allocate pattern compression buffer - if ((patBuf = dmMalloc(patBufSize)) == NULL) - JSSERROR(DMERR_MALLOC, DMERR_MALLOC, - "Error allocating memory for pattern compression buffer.\n"); - - - // Write patterns - for (totalSize = pattern = 0; pattern < m->npatterns; pattern++) - { - JSSMODPattern patHead; - size_t finalSize = 0; - - switch (patMode) - { - case PATMODE_RAW_HORIZ: - i = jssConvertPatternRawHoriz(patBuf, patBufSize, &finalSize, m->patterns[pattern]); - break; - case PATMODE_COMP_HORIZ: - i = jssConvertPatternCompHoriz(patBuf, patBufSize, &finalSize, m->patterns[pattern]); - break; - case PATMODE_RAW_VERT: - i = jssConvertPatternRawVert(patBuf, patBufSize, &finalSize, m->patterns[pattern]); - break; - case PATMODE_COMP_VERT: - i = jssConvertPatternCompVert(patBuf, patBufSize, &finalSize, m->patterns[pattern]); - break; - case PATMODE_RAW_ELEM: - i = jssConvertPatternRawElem(patBuf, patBufSize, &finalSize, m->patterns[pattern]); - break; - default: - i = DMERR_INVALID_DATA; - dmFree(patBuf); - JSSERROR(DMERR_INVALID_DATA, DMERR_INVALID_DATA, - "Unsupported pattern conversion mode %d.\n", patMode); - break; - } - - if (i != DMERR_OK) - { - dmFree(patBuf); - JSSERROR(i, i, "Error converting pattern data #%i\n", pattern); - } - else - { - dmMsg(3, " - Pattern %d size %d bytes\n", pattern, finalSize); - patHead.nrows = m->patterns[pattern]->nrows; - patHead.size = finalSize; - totalSize += finalSize + sizeof(patHead); - - if (fwrite(&patHead, sizeof(patHead), 1, outFile) != 1) - { - dmFree(patBuf); - JSSERROR(DMERR_FWRITE, DMERR_FWRITE, - "Error writing pattern #%d header\n", pattern); - } - - if (fwrite(patBuf, sizeof(Uint8), finalSize, outFile) != finalSize) - { - dmFree(patBuf); - JSSERROR(DMERR_FWRITE, DMERR_FWRITE, - "Error writing pattern #%d data\n", pattern); - } - } - } - dmFree(patBuf); - dmMsg(1," * %d patterns, %d bytes.\n", m->npatterns, totalSize); - - // Write extended instruments - for (totalSize = instr = 0; instr < m->nextInstruments; instr++) - { - JSSMODExtInstrument jssE; - JSSExtInstrument *einst = m->extInstruments[instr]; - - memset(&jssE, 0, sizeof(jssE)); - - if (einst) - { - // Create header - jssE.nsamples = einst->nsamples; - for (i = 0; i < jsetNNotes; i++) - { - int snum = einst->sNumForNotes[i]; - jssE.sNumForNotes[i] = (snum != jsetNotSet) ? snum : 0; - } - - jssCopyEnvelope(&jssE.volumeEnv, &(einst->volumeEnv)); - jssCopyEnvelope(&jssE.panningEnv, &(einst->panningEnv)); - jssE.vibratoType = einst->vibratoType; - jssE.vibratoSweep = einst->vibratoSweep; - jssE.vibratoDepth = einst->vibratoDepth; - jssE.fadeOut = einst->fadeOut; - } else - JSSWARNING(DMERR_NULLPTR, DMERR_NULLPTR, "Extended instrument #%i NULL!\n", instr); - - // Write to file - totalSize += sizeof(jssE); - if (fwrite(&jssE, sizeof(jssE), 1, outFile) != 1) - JSSERROR(DMERR_FWRITE, DMERR_FWRITE, - "Could not write JSSMOD extended instrument #%i to file!\n", instr); - } - dmMsg(1," * %d Extended Instruments, %d bytes.\n", m->nextInstruments, totalSize); - - - // Write sample instrument headers - for (totalSize = instr = 0; instr < m->ninstruments; instr++) - { - JSSMODInstrument jssI; - JSSInstrument *pInst = m->instruments[instr]; - - memset(&jssI, 0, sizeof(jssI)); - - // Create header - if (pInst) - { - jssI.size = pInst->size; - jssI.loopS = pInst->loopS; - jssI.loopE = pInst->loopE; - jssI.volume = pInst->volume; - jssI.flags = pInst->flags; - jssI.C4BaseSpeed = pInst->C4BaseSpeed; - jssI.ERelNote = pInst->ERelNote; - jssI.EFineTune = pInst->EFineTune; - jssI.EPanning = pInst->EPanning; - jssI.hasData = (pInst->data != NULL) ? TRUE : FALSE; - jssI.convFlags = (pInst->flags & jsf16bit) ? flags16 : flags8; - } - else - JSSWARNING(DMERR_NULLPTR, DMERR_NULLPTR, "Instrument #%i NULL!\n", instr); - - // Write to file - totalSize += sizeof(jssI); - if (fwrite(&jssI, sizeof(jssI), 1, outFile) != 1) - JSSERROR(DMERR_FWRITE, DMERR_FWRITE, - "Could not write JSSMOD instrument #%i to file!\n", instr); - } - dmMsg(1," * %d Instrument headers, %d bytes.\n", m->ninstruments, totalSize); - - // Write sample data - for (totalSize = instr = 0; instr < m->ninstruments; instr++) - if (m->instruments[instr]) - { - JSSInstrument *inst = m->instruments[instr]; - if (inst->data != NULL) - { - size_t res; - if (inst->flags & jsf16bit) - { - jssEncodeSample16(inst->data, inst->size, flags16); - res = fwrite(inst->data, sizeof(Uint16), inst->size, outFile); - } - else - { - jssEncodeSample8(inst->data, inst->size, flags8); - res = fwrite(inst->data, sizeof(Uint8), inst->size, outFile); - } - - totalSize += inst->size; - if (res != (size_t) inst->size) - JSSERROR(DMERR_FWRITE, DMERR_FWRITE, - "Could not write JSSMOD sample #%i to file!\n", instr); - } - } - dmMsg(1," * %d samples, %d bytes.\n", m->ninstruments, totalSize); - - return DMERR_OK; -} - - -/* Optimize a given module - */ -JSSModule *optimizeModule(JSSModule *m) -{ - BOOL usedPatterns[jsetMaxPatterns + 1], - usedInstruments[jsetMaxInstruments + 1], - usedExtInstruments[jsetMaxInstruments + 1]; - int mapExtInstruments[jsetMaxInstruments + 1], - mapInstruments[jsetMaxInstruments + 1], - mapPatterns[jsetMaxPatterns + 1]; - JSSModule *r = NULL; - int i, n8, n16; - - // Allocate a new module - if ((r = jssAllocateModule()) == NULL) - return NULL; - - // Allocate tables - - // Copy things - r->moduleType = m->moduleType; - r->moduleName = dm_strdup(m->moduleName); - r->trackerName = dm_strdup(m->trackerName); - r->defSpeed = m->defSpeed; - r->defTempo = m->defTempo; - r->defFlags = m->defFlags; - r->defRestartPos = m->defRestartPos; - r->intVersion = m->intVersion; - r->nchannels = m->nchannels; - r->norders = m->norders; - for (i = 0; i < jsetNChannels; i++) - r->defPanning[i] = m->defPanning[i]; - - // Initialize values - for (i = 0; i <= jsetMaxInstruments; i++) - { - usedExtInstruments[i] = FALSE; - usedInstruments[i] = FALSE; - mapExtInstruments[i] = jsetNotSet; - mapInstruments[i] = jsetNotSet; - } - - for (i = 0; i <= jsetMaxPatterns; i++) - { - usedPatterns[i] = FALSE; - mapPatterns[i] = jsetNotSet; - } - - // Find out all used patterns and ext.instruments - for (i = 0; i < m->norders; i++) - { - int pattern = m->orderList[i]; - if (pattern >= 0 && pattern < m->npatterns) - { - JSSPattern *p = m->patterns[pattern]; - if (p != NULL) - { - int row, channel; - JSSNote *n = p->data; - - // Mark pattern as used - usedPatterns[pattern] = TRUE; - - // Check all notes - for (row = 0; row < p->nrows; row++) - for (channel = 0; channel < p->nchannels; channel++, n++) - { - if (n->instrument != jsetNotSet) - { - if (optStripExtInstr || (n->instrument >= 0 && n->instrument < m->nextInstruments)) - usedExtInstruments[n->instrument] = TRUE; - else - dmMsg(2, "Pattern 0x%x, row=0x%x, chn=%d has invalid instrument 0x%x\n", - pattern, row, channel, n->instrument); - } - } - } - else - { - dmError("Pattern 0x%x is used on order 0x%x, but has no data!\n", - pattern, i); - } - } - else - if (pattern != jsetMaxPatterns) - { - dmError("Order 0x%x has invalid pattern number 0x%x!\n", - i, pattern); - } - } - - // Find out used instruments - for (i = 0; i <= jsetMaxInstruments; i++) - if (usedExtInstruments[i] && m->extInstruments[i] != NULL) - { - int note; - JSSExtInstrument *e = m->extInstruments[i]; - - for (note = 0; note < jsetNNotes; note++) - if (e->sNumForNotes[note] != jsetNotSet) - { - int q = e->sNumForNotes[note]; - if (q >= 0 && q < m->ninstruments) - { - usedInstruments[q] = TRUE; - } - else - { - dmError("Ext.instrument #%d sNumForNotes[%d] value out range (%d < %d).\n", - i, m->ninstruments, q); - } - } - } - - // Create pattern mappings - r->npatterns = 0; - dmMsg(1, "Unused patterns: "); - - for (i = 0; i <= jsetMaxPatterns; i++) - if (m->patterns[i] != NULL) - { - if (!usedPatterns[i]) - { - dmPrint(2, "0x%x, ", i); - } - else - { - if (i >= m->npatterns) - dmError("Pattern 0x%x >= 0x%x, but used!\n", i, m->npatterns); - - mapPatterns[i] = r->npatterns; - r->patterns[r->npatterns] = m->patterns[i]; - (r->npatterns)++; - } - } - dmPrint(2, "\n"); - - dmMsg(1, "%d used patterns, %d unused.\n", - r->npatterns, m->npatterns - r->npatterns); - - - // Re-map instruments - dmMsg(1, "Unused instruments: "); - for (n8 = n16 = i = 0; i <= jsetMaxInstruments; i++) - if (m->instruments[i] != NULL) - { - if (!usedInstruments[i] && !optStripInstr) - { - dmPrint(2, "0x%x, ", i); - } - else - { - JSSInstrument *ip = m->instruments[i]; - if (i >= m->ninstruments) - dmError("Instrument 0x%x >= 0x%x, but used!\n", i, m->ninstruments); - - mapInstruments[i] = r->ninstruments; - r->instruments[r->ninstruments] = ip; - (r->ninstruments)++; - - if (ip->flags & jsf16bit) - n16++; - else - n8++; - } - } - dmPrint(2, "\n"); - dmMsg(1, "Total of (%d) 16-bit, (%d) 8-bit samples, (%d) instruments.\n", - n16, n8, r->ninstruments); - - // Re-map ext.instruments - dmMsg(1, "Unused ext.instruments: "); - for (i = 0; i < jsetMaxInstruments; i++) - if (usedExtInstruments[i]) - { - if (i >= m->nextInstruments && !optStripExtInstr) - { - dmError("Ext.instrument 0x%x >= 0x%x, but used!\n", - i, m->nextInstruments); - } - else - if (m->extInstruments[i] != NULL) - { - JSSExtInstrument *e = m->extInstruments[i]; - int note; - - mapExtInstruments[i] = r->nextInstruments; - r->extInstruments[r->nextInstruments] = e; - (r->nextInstruments)++; - - // Re-map sNumForNotes - for (note = 0; note < jsetNNotes; note++) - { - int q = e->sNumForNotes[note]; - if (q != jsetNotSet) - { - int map; - if (q >= 0 && q <= jsetMaxInstruments) - { - map = mapInstruments[q]; - } - else - { - map = jsetNotSet; - dmError("e=%d, note=%d, q=%d/%d\n", i, note, q, r->ninstruments); - } - e->sNumForNotes[note] = map; - } - } - } - else - { - dmPrint(2, "[0x%x==NULL], ", i); - mapExtInstruments[i] = jsetNotSet; - } - } - else - { - if (i < m->nextInstruments && m->extInstruments[i] != NULL) - { - dmPrint(2, "0x%x, ", i); - } - } - dmPrint(2, "\n"); - dmMsg(1, "%d extended instruments.\n", r->nextInstruments); - - - // Remap pattern instrument data - for (i = 0; i < r->npatterns; i++) - { - int row, channel; - JSSPattern *p = r->patterns[i]; - JSSNote *n = p->data; - - for (row = 0; row < p->nrows; row++) - for (channel = 0; channel < p->nchannels; channel++, n++) - { - char effect; - - if (!optStripExtInstr) - { - if (n->instrument >= 0 && n->instrument <= jsetMaxInstruments) - n->instrument = mapExtInstruments[n->instrument]; - - if (n->instrument != jsetNotSet && r->extInstruments[n->instrument] == NULL) - dmError("Non-existing instrument used #%d.\n", n->instrument); - } - - JMPGETEFFECT(effect, n->effect); - - switch (effect) - { - case 'C': // Cxx = Set volume - if (n->volume == jsetNotSet) - { - n->volume = n->param; - n->effect = jsetNotSet; - n->param = jsetNotSet; - } - break; - } - } - } - - // Remap orders list - for (i = 0; i < m->norders; i++) - { - r->orderList[i] = mapPatterns[m->orderList[i]]; - } - - return r; -} - - -int main(int argc, char *argv[]) -{ - DMResource *sfile = NULL; - FILE *dfile = NULL; - JSSModule *sm, *dm; - int result; - - dmInitProg("xm2jss", "XM to JSSMOD converter", "0.6", NULL, NULL); - dmVerbosity = 0; - - // Parse arguments - if (!dmArgsProcess(argc, argv, optList, optListN, - argHandleOpt, argHandleFile, TRUE)) - exit(1); - - // Check arguments - if (optInFilename == NULL || optOutFilename == NULL) - { - dmError("Input or output file not specified. Try --help.\n"); - return 1; - } - - // Read the source file - if ((sfile = dmf_create_stdio(optInFilename, "rb")) == NULL) - { - dmError("Error opening input file '%s', %d: %s\n", - optInFilename, errno, strerror(errno)); - return 1; - } - - // Initialize miniJSS - jssInit(); - - // Read file - dmMsg(1, "Reading XM-format file ...\n"); - result = jssLoadXM(sfile, &sm); - dmf_close(sfile); - if (result != 0) - { - dmError("Error while loading XM file (%i), ", result); - if (optIgnoreErrors) - fprintf(stderr, "ignoring. This may cause problems.\n"); - else - { - fprintf(stderr, "giving up. Use --ignore if you want to try to convert anyway.\n"); - return 2; - } - } - - // Check stripping settings - if (optStripExtInstr) optStripInstr = TRUE; - if (optStripInstr) optStripSamples = TRUE; - - // Remove samples - if (optStripSamples) - { - int i; - - dmMsg(1, "Stripping samples...\n"); - for (i = 0; i < sm->ninstruments; i++) - { - dmFree(sm->instruments[i]->data); - sm->instruments[i]->data = NULL; - } - } - - // Remove instruments - if (optStripInstr) - { - int i; - - dmMsg(1, "Stripping instruments...\n"); - for (i = 0; i < sm->ninstruments; i++) - { - dmFree(sm->instruments[i]); - sm->instruments[i] = NULL; - } - sm->ninstruments = 0; - } - - // Remove ext.instruments - if (optStripExtInstr) - { - int i; - - dmMsg(1, "Stripping ext.instruments...\n"); - for (i = 0; i < sm->nextInstruments; i++) - { - dmFree(sm->extInstruments[i]); - sm->extInstruments[i] = NULL; - } - sm->nextInstruments = 0; - } - // Run the optimization procedure - if (optOptimize) - { - dmMsg(1, "Optimizing module data...\n"); - dm = optimizeModule(sm); - } else - dm = sm; - - // Write output file - if ((dfile = fopen(optOutFilename, "wb")) == NULL) - { - dmError("Error creating output file '%s', %d: %s\n", - optOutFilename, errno, strerror(errno)); - return 1; - } - - dmMsg(1, "Writing JSSMOD-format file [patMode=0x%04x, samp8=0x%02x, samp16=0x%02x]\n", - optPatternMode, optSampMode8, optSampMode16); - - result = jssSaveJSSMOD(dfile, dm, optPatternMode, optSampMode8, optSampMode16); - - fclose(dfile); - - if (result != 0) - { - dmError("Error while saving JSSMOD file, %d: %s\n", - result, dmErrorStr(result)); - dmError("WARNING: The resulting file may be broken!\n"); - } - else - { - dmMsg(1, "Conversion complete.\n"); - } - return 0; -}