view demo.c @ 21:cc0a227b7734

Jne.
author Matti Hamalainen <ccr@tnsp.org>
date Sat, 23 May 2015 08:46:57 +0300
parents da7ac3f7d014
children feba3bc729a5
line wrap: on
line source

#include "dmengine.h"
#include "dmtext.h"
#include "dmfft.h"
#include "dmvecmat.h"
#include <math.h>

static int demoInit(DMEngineData *engine);
static void demoShutdown(DMEngineData *engine);
static int demoRender(DMEngineData *engine);


int demoPreInit(DMEngineData *engine)
{
    dmInitProg("bussi",
        "Bussi by AnCiat ProDucTionz",
        "0", "ENGINE INITTIALISSSIZING!!!!!", NULL);

    engine->optPackFilename  = "bussi.dat";
    engine->optDataPath      = NULL;

//    engine->optResFlags      = DRF_USE_PACK | DRF_PRELOAD_RES;
    engine->optResFlags      = DRF_USE_PACK | DRF_PRELOAD_RES | DRF_USE_STDIO;

    engine->optAudioSetup    = DM_ASETUP_JSS;

    engine->optVidSetup      = DM_VSETUP_ASPECT;
    engine->optVidWidth      = 640;
    engine->optVidHeight     = 480;
    engine->optVidDepth      = 32;
    engine->optVFlags        = SDL_SWSURFACE;

    engine->demoInit = demoInit;
    engine->demoRender = demoRender;
    engine->demoShutdown = demoShutdown;

    return DMERR_OK;
}


#define FFT_SIZE 128
DMFFTContext fft;
DMResource *teksti = NULL;
DMBitmapFont *font = NULL;

typedef struct
{
    int layer;
    int freq;
    int max;
    float ypos;
    float speed;
    char *filename;
    SDL_Surface *img;
    int count;
} DMItemDef;


typedef struct
{
    BOOL enabled;
    float xtime, xpos, ypos;
    DMItemDef *ref;
} DMFooItemDef;


static DMItemDef items[] = 
{
    { 0,  3, 1,  0.53, 0.2, "viitta.png", NULL, 0 },
    { 0,  1, 3,  -0.2, 0.05, "pilvi.png", NULL, 0 },
    { 0,  1, 3,  0.28 , 0.1 , "puu_pv_2.png", NULL, 0 },
    { 1,  9, 2,  0.25 , 0.8 , "puu_pv_1.png", NULL, 0 },
};

static const int nitems = sizeof(items) / sizeof(items[0]);




static int demoInit(DMEngineData *engine)
{
    int i;
    JSSModule *mod = NULL;
    SDL_Color pal[DMFONT_NPALETTE];
    DMResource *tmp;

    // FFT init
    dmInitializeFFT(&fft, FFT_SIZE);

    // Skrolliteksti
    if ((teksti = engineFindResource(engine, "skrolli.txt")) == NULL)
        return DMERR_INIT_FAIL;

    // Skrollerin fontti
    if ((tmp = engineFindResource(engine, "fontti.dmf")) == NULL)
        return DMERR_INIT_FAIL;
    
    if ((i = dmLoadBitmapFont(tmp, &font)) != DMERR_OK)
        return i;

    for (i = 0; i < DMFONT_NPALETTE; i++)
    {
        pal[i].r = pal[i].g = pal[i].b = i * 8;
        pal[i].unused = i > 0 ? 255 : 0;
    }

    dmSetBitmapFontPalette(font, pal, 0, DMFONT_NPALETTE);

    // Musa
    engineGetResModule(engine, mod, "pas2.xm");

    if ((i = jssConvertModuleForPlaying(mod)) != DMERR_OK)
    {
        dmErrorMsg("Could not convert module for playing, %d: %s\n",
            i, dmErrorStr(i));
        return DMERR_INIT_FAIL;
    }
    
    jvmSetCallback(engine->jssDev, jmpExec, engine->jssPlr);
    jmpSetModule(engine->jssPlr, mod);
    jmpPlayOrder(engine->jssPlr, 0);
    jvmSetGlobalVol(engine->jssDev, 55);


    // Osa kuvadatasta
    for (i = 0; i < nitems; i++)
        engineGetResImage(engine, items[i].img, items[i].filename);

    // Jne
    srand(15);

    return DMERR_OK;
}


static void demoShutdown(DMEngineData *engine)
{
    (void) engine;
    dmEndFFT(&fft);
    dmFreeBitmapFont(font);
}


static inline float dmCX(DMEngineData *engine, const float x)
{
    return (x * engine->screen->w);
}


static inline float dmCY(DMEngineData *engine, const float y)
{
    return (y * engine->screen->h);
}


static inline float dmQX(DMEngineData *engine, SDL_Surface *img, const float x)
{
    return engine->optVidNative ? (img->w * x) : (img->w * engine->screen->w * x) / 640.0f;
}


static inline float dmQY(DMEngineData *engine, SDL_Surface *img, const float y)
{
    return engine->optVidNative ? (img->h * y) : (img->h * engine->screen->h * y) / 480.0f;
}


#define DM_RADIAL_BLUR(YC, XC) \
        DMVector p1 = { xc, yc, 0, 0 }, p2 = { cx, cy, 0, 0 }, v; \
        dm_vector_sub_r(&v, &p2, &p1); \
        dm_vector_scale(&v, scale); \
        dm_vector_add(&v, &p1); \
        if (v.y YC || v.x XC) continue; \
        DMColor *dp = pix + xc, \
                 *q = ((DMColor *)img->pixels) + ((int)(v.y) * pitch) + (int)v.x; \
        dp->r = (q->r + dp->r) / 2; \
        dp->g = (q->g + dp->g) / 2; \
        dp->b = (q->b + dp->b) / 2;



void dmRadialBlur(SDL_Surface *img, const int cx, const int cy, const DMFloat scale)
{
    const int pitch = img->pitch / sizeof(DMColor);
    int xc, yc;

#pragma omp parallel private(yc, xc) shared(img)
    {
#pragma omp sections nowait
        {
#pragma omp section
            for (yc = cy; yc >= 0; yc--)
            {
                DMColor *pix = ((DMColor *)img->pixels) + yc * pitch;
                for (xc = cx + 1; xc < img->w; xc++)
                {
                    DM_RADIAL_BLUR(< 0, >= img->w)
                }
            }

#pragma omp section
            for (yc = cy; yc >= 0; yc--)
            {
                DMColor *pix = ((DMColor *)img->pixels) + yc * pitch;
                for (xc = cx; xc > 0; xc--)
                {
                    DM_RADIAL_BLUR(< 0, < 0)
                }    
            }

#pragma omp section
            for (yc = cy + 1; yc < img->h; yc++)
            {
                DMColor *pix = ((DMColor *)img->pixels) + yc * pitch;
                for (xc = cx; xc > 0; xc--)
                {
                    DM_RADIAL_BLUR(>= img->h, < 0)
                }    
            }

#pragma omp section
            for (yc = cy + 1; yc < img->h; yc++)
            {
                DMColor *pix = ((DMColor *)img->pixels) + yc * pitch;
                for (xc = cx + 1; xc < img->w; xc++)
                {
                    DM_RADIAL_BLUR(>= img->h, >= img->w)
                }    
            }
        }
    }
}


static int my_toupper(int ch)
{
    switch (ch)
    {
        case 0xe4: return 142;
        case 0xf6: return 153;
        default:
            if (ch >= 'a' && ch <= 'z')
                return ch - 'a' + 'A';
            else
                return ch;
    }
}


static DMItemDef * dmGetItem(int t)
{
    int i;
    for (i = 0; i < nitems; i++)
    {
        DMItemDef *def = &items[i];
        if (t % def->freq == 0 && def->count <= def->max)
            return def;
    }
    return NULL;
}


static void dmRenderItems(DMEngineData *engine, DMScaledBlitFunc ablit, DMFooItemDef *mitems, const int nmitems, const int layer)
{
    int i;
    for (i = 0; i < nmitems; i++)
    {
        DMFooItemDef *item = &mitems[i];

        if (item->enabled && item->ref->layer == layer)
        {
            ablit(item->ref->img,
                dmCX(engine, item->xpos),
                dmCY(engine, item->ypos),
                dmQX(engine, item->ref->img, 1),
                dmQY(engine, item->ref->img, 1),
                engine->screen);
        }
    }
}


static int demoRender(DMEngineData *engine)
{
    float t = engineGetTimeDT(engine);

    //
    // Do FFT
    //
    DMFFTType fftPow = 0;
    BOOL fftOK = FALSE;
    static DMFFTType fftAmp[FFT_SIZE / 2];
    static DMFFTType fftData[FFT_SIZE];

    dmMutexLock(engine->audioStreamMutex);
    if (engine->audioStreamBuf != 0 && engine->audioStreamLen > FFT_SIZE)
    {
        int i;
        Sint16 *buf = (Sint16 *) engine->audioStreamBuf;
        for (i = 0; i < FFT_SIZE; i++)
        {
            fftData[i] = *buf;
            buf += 2;
        }
        fftOK = TRUE;
    }
    dmMutexUnlock(engine->audioStreamMutex);

    if (fftOK)
    {
        dmRealFFT(&fft, fftData);
        dmConvertFFTtoPowerAndSum(&fft, fftData, fftAmp, 1.0, &fftPow, 0.00004f);
    }


    //
    // Taustaskrolli
    //
    {
        static SDL_Surface *tausta = NULL,
                *aurinko = NULL,
                *bussi = NULL,
                *rengas = NULL;

        static DMScaledBlitFunc cblit = NULL, ablit = NULL;
        static BOOL nollattu = FALSE;
        static DMLerpContext fadeLerp, fadeLerp2, fadeLerp3;

        if (!nollattu)
        {
            dmLerpInit(&fadeLerp, 0, 255, 3000);
            dmLerpInit(&fadeLerp2, 0, 255, 4000);
            dmLerpInit(&fadeLerp3, 0, 1.2, 3000);
            engineGetResImage(engine, tausta, "tausta_pv.png");
            engineGetResImage(engine, aurinko, "aurinko.png");
            engineGetResImage(engine, bussi, "auto.png");
            engineGetResImage(engine, rengas, "rengas.png");
            cblit = dmGetScaledBlitFunc(tausta->format, engine->screen->format, DMD_NONE);
            ablit = dmGetScaledBlitFunc(bussi->format, engine->screen->format, DMD_TRANSPARENT);
        }

        int x1 = - ((int)dmQX(engine, tausta, t * 0.2) % (int) dmQX(engine, tausta, 1)),
            x2 = x1 + dmQX(engine, tausta, 1);

        cblit(tausta, x1, 0, dmQX(engine, tausta, 1), dmQY(engine, tausta, 1), engine->screen);
        cblit(tausta, x2, 0, dmQX(engine, tausta, 1), dmQY(engine, tausta, 1), engine->screen);

        float qm = sin(t * 0.1 + fftPow * 5) * 0.05, qm2 = qm * 10;
        ablit(aurinko,
            dmCX(engine, 0.8 - dmLerpSCurveClamp(&fadeLerp3, engineGetTime(engine, 0) * 0.01) * 0.3 - qm),
            dmCY(engine, 0.05 - qm),
            dmQX(engine, aurinko, 1 + qm2),
            dmQY(engine, aurinko, 1 + qm2),
            engine->screen);

        // Puut ym. liikennejutut
        #define DM_MAX_MITEMS 16
        static DMFooItemDef mitems[DM_MAX_MITEMS];
        if (t > 6)
        {
            float dt = (t - 6);
            static BOOL nollattu = FALSE;
            int i;

            if (!nollattu)
            {
                memset(mitems, 0, sizeof(mitems));
                nollattu = TRUE;
            }

            for (i = 0; i < DM_MAX_MITEMS; i++)
            {
                DMFooItemDef *item = &mitems[i];
                if (!item->enabled && (item->ref = dmGetItem((int) t * 10 + 1)) != NULL)
                {
                    item->enabled = TRUE;
                    item->ref->count++;
                    item->xtime = dt;
                    item->ypos = item->ref->ypos + sin(dt) * 0.001f;
                }
            }
            for (i = 0; i < DM_MAX_MITEMS; i++)
            {
                DMFooItemDef *item = &mitems[i];
                if (item->enabled)
                {
                    float xpos = (dt - item->xtime) * item->ref->speed;
                    if (xpos > 1.5)
                    {
                        item->enabled = FALSE;
                        item->ref->count--;
                    }
                    else
                        item->xpos = 1 - xpos;
                }
            }
        }

        dmRenderItems(engine, ablit, mitems, DM_MAX_MITEMS, 0);
        
        // Bussi ajaa sisään
        if (t > 14)
        {
            float
                dt = engineGetTime(engine, 14),
                ajelu = dmLerpSCurveClamp(&fadeLerp3, dt),
                xc = dmCX(engine, -1 + ajelu),
                yc = dmCY(engine, 0.38 + sin(t * 10) * 0.005),
                yc2 = yc + dmQY(engine, bussi, 0.7) + dmCY(engine, sin(t * 20) * 0.001);
            
            ablit(rengas, xc + dmQX(engine, bussi, 0.07), yc2, dmQX(engine, rengas, 1), dmQY(engine, rengas, 1), engine->screen);
            ablit(rengas, xc + dmQX(engine, bussi, 0.80), yc2, dmQX(engine, rengas, 1), dmQY(engine, rengas, 1), engine->screen);
            ablit(bussi, xc, yc, dmQX(engine, bussi, 1), dmQY(engine, bussi, 1), engine->screen);
        }
        

        dmRenderItems(engine, ablit, mitems, DM_MAX_MITEMS, 1);
    }

    //
    // AP logo
    //
    if (t > 4 && t < 8)
    {
        int dt = engineGetTime(engine, 4);
        static DMLerpContext fadeLerp;
        static SDL_Surface *logo = NULL;
        static BOOL nollattu = FALSE;
        if (!nollattu)
        {
            dmLerpInit(&fadeLerp, 0, 255, 1000);
            engineGetResImage(engine, logo, "ap.png");
            nollattu = TRUE;
        }

        int fadeVal;
        if (dt < 1000)
            fadeVal = dmLerpSCurveClamp(&fadeLerp, dt);
        else
        if (dt > 3000)
            fadeVal = 255 - dmLerpSCurveClamp(&fadeLerp, dt - 3000);
        else
            fadeVal = 255;

        dmScaledBlitSurface32to32TransparentGA(logo,
            dmQX(engine, logo, 0.2),
            dmQY(engine, logo, 0.3),
            dmQX(engine, logo, 1),
            dmQY(engine, logo, 1),
            engine->screen, fadeVal);
    }

    //
    // BUSSI logo
    //
    if (t > 10 && t < 14)
    {
        int dt = engineGetTime(engine, 10);
        static DMLerpContext fadeLerp;
        static SDL_Surface *logo = NULL, *logo2 = NULL;
        static BOOL nollattu = FALSE;
        if (!nollattu)
        {
            dmLerpInit(&fadeLerp, 0, 255, 1000);
            engineGetResImage(engine, logo, "bussi_logo.png");
            engineGetResImage(engine, logo2, "dosa.png");
            nollattu = TRUE;
        }

        int fadeVal, fadeVal2;
        if (dt < 1000)
            fadeVal = dmLerpSCurveClamp(&fadeLerp, dt);
        else
        if (dt > 3000)
            fadeVal = 255 - dmLerpSCurveClamp(&fadeLerp, dt - 3000);
        else
            fadeVal = 255;

        if (dt > 1000)
        {
            if (dt < 2000)
                fadeVal2 = dmLerpSCurveClamp(&fadeLerp, dt - 1000);
            else
            if (dt > 3000)
                fadeVal2 = 255 - dmLerpSCurveClamp(&fadeLerp, dt - 3000);
            else
                fadeVal2 = 255;
        }
        else
            fadeVal2 = 0;

        dmScaledBlitSurface32to32TransparentGA(logo,
            dmCX(engine, 0.10),
            dmCY(engine, 0.2),
            dmQX(engine, logo, 1),
            dmQY(engine, logo, 1),
            engine->screen, fadeVal);

        dmScaledBlitSurface32to32TransparentGA(logo2,
            dmCX(engine, 0.6),
            dmCY(engine, 0.6),
            dmQX(engine, logo2, 1),
            dmQY(engine, logo2, 1),
            engine->screen, fadeVal2);
    }


    //
    // Skrolleri
    //
    if (t > 3)
    {
        int tt = engineGetTime(engine, 2);
        static DMScaledBlitFunc cblit, qblit;
        static BOOL nollattu = FALSE;
        if (!nollattu)
        {
            cblit = dmGetScaledBlitFunc(font->glyphs[65]->format, engine->screen->format, DMD_TRANSPARENT);
            qblit = dmGetScaledBlitFunc(font->glyphs[65]->format, engine->screen->format, DMD_SATURATE);
        }

        size_t txtLen = teksti->rawSize - 1;
        Uint8 *txtData = teksti->rawData;
        int fwidth = font->width * 2 + 2;
        int xc, offs, scrollTime = tt / 10,
            scrWidth = engine->screen->w / (dmQX(engine, font->glyphs[65], 1) + dmCX(engine, 0.001));

        for (xc = offs = 0; offs < scrWidth; offs++)
        {
            int ch = txtData[((scrollTime / fwidth) + offs) % txtLen];
            SDL_Surface *glyph = dmGetBMGlyph(font, my_toupper(ch));
            if (glyph != NULL)
            {
                float mt = (offs * 20 + tt) / 100.0f;
                int dx = xc - (scrollTime % fwidth),
                    dy = dmCY(engine, 0.8 + sin(mt) * 0.05),
                    dw = glyph->w * 2 * (1.0f + sin(mt) * 0.1f),
                    dh = glyph->h * 2 * (1.0f + cos(mt) * 0.2f);
                    
                cblit(glyph, dx+1, dy+1, dw+1, dh+1, engine->screen);
                qblit(glyph, dx, dy, dw, dh, engine->screen);
            }
            xc += fwidth;
        }
    }

    //
    // Alku- ja Loppufeidi
    //
    {
        static DMLerpContext fadeLerp, fadeLerp2;
        static SDL_Surface *feidi = NULL;
        static BOOL nollattu = FALSE;
        if (!nollattu)
        {
            engineGetResImage(engine, feidi, "feidi.png");
            dmLerpInit(&fadeLerp, 255, 0, 3000);
            dmLerpInit(&fadeLerp2, 0, 255, 5000);
        }

        int fadeVal = -1;
        if (t < 5)
            fadeVal = dmLerpSCurveClamp(&fadeLerp, engineGetTime(engine, 0));
        else
        if (t > 70)
            fadeVal = dmLerpSCurveClamp(&fadeLerp2, engineGetTime(engine, 70));

        if (fadeVal >= 0)
        {
            dmScaledBlitSurface32to32TransparentGA(feidi,
                0,
                0,
                dmQX(engine, feidi, 1),
                dmQY(engine, feidi, 1),
                engine->screen,
                fadeVal);
        }
    }

    //
    // Maskaus
    //
    {
        static DMScaledBlitFunc cblit = NULL;
        static SDL_Surface *maski = NULL;
        static BOOL nollattu = FALSE;

        if (!nollattu)
        {
            engineGetResImage(engine, maski, "maski.png");
            cblit = dmGetScaledBlitFunc(maski->format, engine->screen->format, DMD_TRANSPARENT);
        }

        cblit(maski,
            0, 0,
            dmQX(engine, maski, 1),
            dmQY(engine, maski, 1),
            engine->screen);
    }


    if (t > 75)
        return 1;
    else
        return DMERR_OK;
}