view dmsimple.c @ 96:6bf5220fa47e

Urgh .. use memset to silence some bogus GCC warnings about using potentially uninitialized values, while that will not actually be possible. In any case, it is annoying.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 02 Oct 2012 18:52:28 +0300
parents 4bbfc0274b29
children d5d27f262227
line wrap: on
line source

#include "dmsimple.h"


DMEngineData engine;
DMFrameData frame;


int engineShowProgress(int loaded, int total)
{
    int dx = 60,
        dh = 20,
        dw = engine.screen->w - (2 * dx),
        dy = (engine.screen->h - dh) / 2;
    
    if (SDL_MUSTLOCK(engine.screen) != 0 && SDL_LockSurface(engine.screen) != 0)
        return DMERR_INIT_FAIL;
    
    // Draw the progress bar
    dmClearSurface(engine.screen, dmMapRGBA(engine.screen, 0,0,0,0));
    dmFillRect(engine.screen, dx, dy, dx+dw, dy+dh, dmMapRGB(engine.screen, 255,255,255));
    dmFillRect(engine.screen, dx+1, dy+1, dx+dw-1, dy+dh-1, dmMapRGB(engine.screen, 0,0,0));

    if (total > 0)
    {
        dmFillRect(engine.screen,
            dx+3, dy+3,
            dx + 3 + ((dw - 3) * loaded) / total,
            dy + dh - 3,
            dmMapRGB(engine.screen, 200,200,200));
    }

    // Flip screen
    if (SDL_MUSTLOCK(engine.screen) != 0)
        SDL_UnlockSurface(engine.screen);

    SDL_Flip(engine.screen);
    return DMERR_OK;
}


int engineLoadResources()
{
    int err, loaded, total;
    
    err = dmres_preload(TRUE, &loaded, &total);

    while ((err = dmres_preload(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 err;
}


int engineGetTick()
{
    return (frame.startTime - engine.startTime) + engine.adjustTime;
}


float engineGetTimeDT()
{
    return (float) engineGetTick() / 1000.0f;
}


int engineGetTimeDTi()
{
    return (float) engineGetTick() / 1000;
}


int engineGetTime(int t)
{
    return engineGetTick() - (1000 * t);
}


int engineGetDT(int t)
{
    return engineGetTime(t) / 1000;
}


static int engineResImageLoad(DMResource *res)
{
    SDL_Surface *img = dmLoadImage(res);
    if (res != NULL)
    {
        res->rdata = img;
        return DMERR_OK;
    }
    else
        return dmferror(res);
}

static void engineResImageFree(DMResource *res)
{
    SDL_FreeSurface((SDL_Surface *)res->rdata);
}

static int engineResModuleLoad(DMResource *res)
{
    return jssLoadXM(res, (JSSModule **) &(res->rdata));
}

static void engineResModuleFree(DMResource *res)
{
    jssFreeModule((JSSModule *) res->rdata);
}


static DMResourceDataOps engineResImage =
{
    engineResImageLoad,
    engineResImageFree
};

static DMResourceDataOps engineResModule =
{
    engineResModuleLoad,
    engineResModuleFree
};


static int engineClassifier(DMResource *res)
{
    DMResourceDataOps *rops = NULL;
    char *fext;

    if (res == NULL)
        return DMERR_NULLPTR;
    
    if ((fext = strrchr(res->filename, '.')) != NULL)
    {
        if (strcasecmp(fext, ".png") == 0 || strcasecmp(fext, ".jpg") == 0)
            rops = &engineResImage;
        else
        if (strcasecmp(fext, ".xm") == 0 || strcasecmp(fext, ".jmod") == 0)
            rops = &engineResModule;
    }
    
    res->rops = rops;
    
    return DMERR_OK;
}


void *engineGetResource(const char *name)
{
    DMResource *res = dmres_find(name);
    if (res != NULL && res->rdata != NULL)
        return res->rdata;
    else
    {
        dmError("Could not find resource '%s'.\n", name);
        return NULL;
    }
}


#ifdef DM_DEBUG
static void engineAudioCallbackStream(void *userdata, Uint8 *stream, int len)
{
    if (engine.paused)
    {
        memset(stream, 0, len);
    }
    else
    {
        JSSMixer *d = (JSSMixer *) userdata;
        if (d != NULL)
        {
            int pos = ((engine.adjustTime * d->outFreq) / 1000) * jvmGetSampleSize(d) +
                engine.audioSamples;
            
            memcpy(stream, engine.audioBuf + pos, len);

            engine.audioSamples += len;
        }
    }
}

void engineAdjustTime(int adj)
{
    if (engine.optDebug)
    {
        int tmp = engine.adjustTime + adj;
        if (tmp < 0)
            tmp = 0;
        else
        if (tmp >= engine.demoDuration * 1000)
            tmp = engine.demoDuration * 1000;

        engine.pauseFlag = TRUE;
        engine.adjustTime = tmp;
        dmPrint(0, "adj=%d, adjtime=%d\n", adj, engine.adjustTime);
    }
}
#endif


static void engineAudioCallback(void *userdata, Uint8 *stream, int len)
{
    if (engine.paused)
    {
        memset(stream, 0, len);
    }
    else
    {
        JSSMixer *d = (JSSMixer *) userdata;
        if (d != NULL)
            jvmRenderAudio(d, stream, len / jvmGetSampleSize(d));
    }
}


int main(int argc, char *argv[])
{
    int err;
    BOOL initSDL = FALSE;
    SDL_AudioSpec afmt;

    memset(&afmt, 0, sizeof(afmt));
    memset(&frame, 0, sizeof(frame));
    memset(&engine, 0, sizeof(engine));

    // Pre-initialization
    if ((err = demoPreInit(argc, argv)) != DMERR_OK)
        goto error_exit;

    // Initialize resource subsystem
    dmPrint(1, "Initializing resources subsystem.\n");
    if ((err = dmres_init("orvellys.dat", NULL, DRF_USE_PACK | DRF_PRELOAD_RES, engineClassifier)) != DMERR_OK)
    {
        dmError("Could not initialize resource manager: %d, %s.\n", err, dmErrorStr(err));
        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 JSS
    jssInit();

    afmt.freq     = 44100;
    afmt.format   = AUDIO_S16SYS;
    afmt.channels = 2;
    afmt.samples  = 16*1024;

    dmPrint(1, "Initializing miniJSS mixer with: %d, %d, %d\n",
        JSS_AUDIO_S16, afmt.channels, afmt.freq);

    if ((engine.dev = jvmInit(JSS_AUDIO_S16, afmt.channels, afmt.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;
    }

    // Initialize SDL audio
    dmPrint(1, "Trying to init SDL audio with: %d, %d, %d\n",
        afmt.format, afmt.channels, afmt.freq);

#ifdef DM_DEBUG
    if (engine.optDebug)
    {
        afmt.callback = engineAudioCallbackStream;
        afmt.userdata = (void *) engine.dev;
    }
    else
#endif
    {
        afmt.callback = engineAudioCallback;
        afmt.userdata = (void *) engine.dev;
    }
    
    if (SDL_OpenAudio(&afmt, NULL) < 0)
    {
        dmError("Couldn't open audio: %s\n", SDL_GetError());
        goto error_exit;
    }

    // Initialize SDL video
    dmPrint(1, "Initializing SDL video %d x %d x %dbpp, flags=0x%08x\n",
        engine.optScrWidth, engine.optScrHeight, engine.optBitDepth, engine.optVFlags);

    engine.screen = SDL_SetVideoMode(engine.optScrWidth, engine.optScrHeight, engine.optBitDepth, engine.optVFlags);
    if (engine.screen == NULL)
    {
        dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError());
        goto error_exit;
    }

    SDL_ShowCursor(SDL_DISABLE);
    SDL_WM_SetCaption(dmProgDesc, dmProgName);


    // Load resources
    if ((err = engineLoadResources()) != DMERR_OK)
    {
        dmError("Error loading resources, %d: %s.\n",
            err, dmErrorStr(err));
        goto error_exit;
    }

    // Final initializations
    if ((err = demoInit()) != DMERR_OK)
        goto error_exit;

#ifdef DM_DEBUG
    if (engine.optDebug)
    {
        Uint8 *ptr;
        int left = engine.dev->outFreq * engine.demoDuration;
        engine.audioBufSize = jvmGetSampleSize(engine.dev) * engine.dev->outFreq * engine.demoDuration;
        if ((engine.audioBuf = dmMalloc(engine.audioBufSize)) == NULL)
        {
            dmError("Could not allocate audio stream buffer of %d bytes.\n",
                engine.audioBufSize);
            goto error_exit;
        }
        
        ptr = engine.audioBuf;
        while (left > 0)
        {
            int length = left;
            if (length > 16*1024)
                length = 16*1024;

            jvmRenderAudio(engine.dev, ptr, length);
            ptr += jvmGetSampleSize(engine.dev) * length;
            left -= length;
        }
    }
#endif

    SDL_PauseAudio(0);
    engine.startTime = SDL_GetTicks();

    while (!engine.exitFlag)
    {
        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;
                        break;

#ifdef DM_DEBUG
                    case SDLK_LEFT:  engineAdjustTime(-500); break;
                    case SDLK_RIGHT: engineAdjustTime( 500); break;
                    case SDLK_UP:    engineAdjustTime( 1000); break;
                    case SDLK_DOWN:  engineAdjustTime(-1000); break;
#endif

                    default:
                        break;
                }

                break;

            case SDL_VIDEOEXPOSE:
                break;

            case SDL_QUIT:
                engine.exitFlag = TRUE;
                break;
        }

        // Draw frame
        frame.startTime = SDL_GetTicks();
        if (engine.pauseFlag != engine.paused)
        {
            engine.paused = engine.pauseFlag;
            engine.pauseTime = engineGetTick();
        }
        
        if (engine.paused)
        {
            engine.startTime = frame.startTime - engine.pauseTime;
        }

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

        // Call main tick
        if ((err = demoMainTick()) != DMERR_OK)
            goto error_exit;

        // Flip screen
        if (SDL_MUSTLOCK(engine.screen) != 0)
            SDL_UnlockSurface(engine.screen);

        SDL_Flip(engine.screen);
        SDL_Delay(20);

        // Get frame time, etc
        frame.endTime = SDL_GetTicks();
        engine.currFrame++;
        engine.totalFrameTime += frame.endTime - frame.startTime;
    }

    // Print benchmark results
    engine.endTime = SDL_GetTicks();
    dmPrint(1, "%d frames in %d ms, fps = %1.3f\n",
        engine.currFrame, engine.endTime - engine.startTime,
        (float) (engine.currFrame * 1000.0f) / (float) engine.totalFrameTime);


error_exit:

    dmPrint(1, "Shutting down.\n");
    SDL_ShowCursor(SDL_ENABLE);
    SDL_PauseAudio(1);

    if (engine.screen)
        SDL_FreeSurface(engine.screen);

    SDL_LockAudio();
    jmpClose(engine.plr);
    jvmClose(engine.dev);
    jssClose();
    SDL_UnlockAudio();

    dmres_close();    

    demoShutdown();

    if (initSDL)
        SDL_Quit();

    demoQuit();
    
    return 0;
}