view demo.c @ 69:f0b26daba6a9

Build adjustments.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 29 Oct 2019 18:16:47 +0200
parents aa06f72f6557
children
line wrap: on
line source

#include "dmengine.h"
#include "dmvecmat.h"
#include "dmperlin.h"
#include <math.h>

static int demoInit();
static void demoShutdown();
static void demoQuit();
static int demoRender();

static DMPerlinContext perlinCtx;

#define DM_COLORS (256)

void dmMakePalette(SDL_Surface *scr)
{
    SDL_Color pal[DM_COLORS];

    for (int n = 0; n < DM_COLORS; n++)
    {
        pal[n].r = n;
        pal[n].g = n;
        pal[n].b = n;
    }

    SDL_SetPaletteColors(scr->format->palette, pal, 0, DM_COLORS);
}


#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(&perlinCtx, x, y, 1.1f, q, 2);
            map[y][x] = (int) (dmClamp10(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;
        }
}


void dmShadowTraceHeightMap2(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;
        }
}


#define CREDITS_SPEED 1000
#define CREDITS_RAND  4

typedef struct
{
    int x, y;
} DMCoords;


typedef struct
{
    int x, y;
    char *filename;
    SDL_Surface *img;
} DMCredits;



static const DMCoords randomCoords[] =
{
    { -300, -430 },
    { 700, -550 },
    { -200, 600 },
    { 700, 600 }
};
const int nrandomCoords = sizeof(randomCoords) / sizeof(randomCoords[0]);


static DMCredits credits[] =
{
    {   91,  223, "g4014.png", NULL },
    {  151,  250, "g4026.png", NULL },
    {  217,  227, "g4020.png", NULL },
    {  173,  268, "g4032.png", NULL },
    {  115,  359, "g4038.png", NULL },

    {  437,  130, "g4062.png", NULL },
    {  457,  102, "g4068.png", NULL },
    {  450,  210, "g4056.png", NULL },

    {  420,  320, "g4044.png", NULL },
    {  486,  381, "g4050.png", NULL },
};

const int ncredits = sizeof(credits) / sizeof(credits[0]);


#define NOSFE_MIN     1
#define NOSFE_MAX     269

SDL_Surface *bmap;
SDL_Surface *nosfe[NOSFE_MAX - NOSFE_MIN + 1];


int demoPreInit(DMEngineData *engine)
{
    dmInitProg("krapula",
        "Lauantai Aamun Krapula",
        "0.2", "(c) 2012 Anciat Prodz & TNSP", "PENIS.");

    engine->optPackFilename = "orvellys.dat";
    engine->optResFlags      = DRF_USE_PACK | DRF_PRELOAD_RES
#ifdef DM_USE_STDIO
     | DRF_USE_STDIO
#endif
     ;

    engine->optAudioSetup   = DM_ASETUP_JSS;

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

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

    return DMERR_OK;
}


static int demoInit(DMEngineData *engine)
{
    int i;

    // Initialize effect stuff
    dmPerlinInit(&perlinCtx, 1234);

    for (i = 0; i < NOSFE_MAX; i++)
    {
        char fname[32];
        snprintf(fname, sizeof(fname), "%08d.jpg", NOSFE_MIN + i);
        engineGetResImage(engine, nosfe[i], fname);
    }

    for (i = 0; i < ncredits; i++)
        engineGetResImage(engine, credits[i].img, credits[i].filename);

    bmap = SDL_CreateRGBSurface(SDL_SWSURFACE, QWIDTH, QHEIGHT, 8, 0, 0, 0, 0);


    // Initialize music player
    JSSModule *mod = NULL;
    engineGetResModule(engine, mod, "krapula.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);

    return DMERR_OK;
}


static void demoShutdown(DMEngineData *engine)
{
    (void) engine;
    SDL_FreeSurface(bmap);
}


static void demoQuit()
{
    dmPrint(0, "Krapulassa on kivaa.\n");
}


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

    if (t < 5)
    {
        //
        // Anciat prodz logo
        //
        int dt = engineGetTime(engine, 0);
        static SDL_Surface *anciat;
        static DMLerpContext lerpX, lerpY, lerpD;
        static DMScaledBlitFunc nblit;
        DMVector light;
        static BOOL nollattu = FALSE;
        if (!nollattu)
        {
            engineGetResImage(engine, anciat, "anciat.png");
            nblit = dmGetScaledBlitFunc(bmap->format, engine->screen->format, DMD_NONE);
            dmMakePalette(bmap);
            dmLerpInit(&lerpX, 0, QWIDTH, 5000);
            dmLerpInit(&lerpY, QHEIGHT * 0.25, QHEIGHT * 0.75, 5000);
            dmLerpInit(&lerpD, 0.04, 0.08, 5000);
            nollattu = TRUE;
        }

        light.x = dmLerpSCurve(&lerpX, dt);
        light.y = dmLerp1(&lerpY, dt);
        light.z = 128;

        dmShadowTraceHeightMap2(bmap->pixels, anciat->pixels, &light);
        nblit(bmap, 0, 0, engine->screen->w, engine->screen->h, engine->screen);
    }
    else
    if (t < 10)
    {
        //
        // Demo "logo" texts
        //
        int dt = engineGetTime(engine, 5);
        static SDL_Surface *logobg, *logolayer1, *logolayer2;
        static DMScaledBlitFunc nblit, kblit;
        static DMLerpContext lerpD;
        static BOOL nollattu = FALSE;

        if (!nollattu)
        {
            engineGetResImage(engine, logobg, "logobg.png");
            engineGetResImage(engine, logolayer1, "logolayer1.png");
            engineGetResImage(engine, logolayer2, "logolayer2.png");

            nblit = dmGetScaledBlitFunc(logobg->format, engine->screen->format, DMD_TRANSPARENT);
            kblit = dmGetScaledBlitFunc(logobg->format, engine->screen->format, DMD_NONE);
            dmLerpInit(&lerpD, 0.01, 500, 10000);
            nollattu = TRUE;
        }

        float q = dmLerpSCurve(&lerpD, dt);
        float t = sin((float) dt / 150.0f);
        int x = t * 25.0f + q, y = t * 35.0f + q*2.0f,
            w = t * 70.0f + q, h = t * 40.0f + q*2.0f;

        float t2 = sin((float) dt / 150.0f + 0.2f);
        int x2 = t2 * 25.0f + q, y2 = t * 35.0f + q*2.0f,
            w2 = t2 * 70.0f + q, h2 = t * 40.0f + q*2.0f;

        kblit(logobg, 0, 0, engine->screen->w, engine->screen->h, engine->screen);
        nblit(logolayer1, -x, -y, engine->screen->w+w, engine->screen->h+h, engine->screen);
        nblit(logolayer2, -x2, -y2, engine->screen->w+w2, engine->screen->h+h2, engine->screen);
    }
    else
    if (t < 20)
    {
        //
        // "Gaytracing"
        //
        int dt = engineGetTime(engine, 10);
        static SDL_Surface *gay, *logobg;
        static DMLerpContext lerpX, lerpY, lerpD;
        static DMScaledBlitFunc nblit, kblit;
        static BOOL nollattu = FALSE;
        DMVector light;
        DMBlockMap heightMap;

        if (!nollattu)
        {
            engineGetResImage(engine, gay, "gay.png");
            engineGetResImage(engine, logobg, "logobg.png");
            nblit = dmGetScaledBlitFunc(bmap->format, engine->screen->format, DMD_NONE);
            kblit = dmGetScaledBlitFunc(logobg->format, engine->screen->format, DMD_TRANSPARENT);
            dmMakePalette(bmap);
            dmLerpInit(&lerpX, QWIDTH, 0, 10000);
            dmLerpInit(&lerpY, QHEIGHT * 0.25, QHEIGHT * 0.75, 10000);
            dmLerpInit(&lerpD, 0.04, 0.08, 10000);
            nollattu = TRUE;
        }

        light.x = dmLerpSCurve(&lerpX, dt);
        light.y = QHEIGHT * 0.5 + sin(dmLerp1(&lerpY, dt)) * 0.5;
        light.z = 128;

        dmMakeBumpMap(heightMap, dmLerpSCurve(&lerpD, dt), 254);

        dmShadowTraceHeightMap(bmap->pixels, heightMap, &light);

        nblit(bmap, 0, 0, engine->screen->w, engine->screen->h, engine->screen);

        if ((dt / 100) % 10 < 5)
        {
            kblit(gay, 0, 0, engine->screen->w, engine->screen->h, engine->screen);
        }
    }
    else
    if (t < 45)
    {
        //
        // Nosfe video/animation + credits
        //
        static SDL_Surface *ruutu;
        static int currState, currCredit, creditStartTime;
        static DMLerpContext lerpX, lerpY, lerpZ;
        static DMScaledBlitFunc nblit, kblit;
        static BOOL stateChange, nollattu = FALSE;
        int currFrame = engineGetTime(engine, 20) * 15 / 1000;
        if (!nollattu)
        {
            engineGetResImage(engine, ruutu, "ruutu.png");
            dmClearSurface(ruutu, dmMapRGBA(ruutu, 0,0,0,0));
            nblit = dmGetScaledBlitFunc(nosfe[0]->format, engine->screen->format, DMD_NONE);
            kblit = dmGetScaledBlitFunc(credits[0].img->format, engine->screen->format, DMD_TRANSPARENT);
            currCredit = -1;
            currState = -1;
            stateChange = TRUE;
            nollattu = TRUE;
        }

        float gt = 1.0f + sin(engineGetTime(engine, 0) / 250.0f);
        int g1 = gt * 25.0f, g2 = gt * 50.0f;
        
        nblit(nosfe[currFrame % NOSFE_MAX], -g1, -g1, engine->screen->w+g2, engine->screen->h+g2, engine->screen);

        if (t >= 30)
        {
            int qtime = engineGetTime(engine, 30);
            int creditTime = engineGetTime(engine, 0) - creditStartTime;
            float zscale;
            if ( ( (qtime / (CREDITS_SPEED + 500)) % 2) == 0 && currState == -1)
                stateChange = TRUE;

            if (stateChange && currCredit < ncredits)
            {
                stateChange = FALSE;
                switch (currState)
                {
                    case 0:
                        {
                        int qt = (qtime / 100) % nrandomCoords;
                        creditStartTime = engineGetTime(engine, 0);
                        creditTime = 0;
                        dmLerpInit(&lerpX, randomCoords[qt].x, credits[currCredit].x - 50, CREDITS_SPEED);
                        dmLerpInit(&lerpY, randomCoords[qt].y, credits[currCredit].y - 50, CREDITS_SPEED);
                        dmLerpInit(&lerpZ, 5.0f, 0.0f, CREDITS_SPEED);
                        currState = 1;
                        }
                        break;

                    case 2:
                        if (creditTime >= CREDITS_SPEED)
                            creditTime = CREDITS_SPEED - 1;

                        zscale = dmLerpSCurve(&lerpZ, creditTime);
                        dmScaledBlitSurface32to32TransparentX(
                            credits[currCredit].img,
                            dmLerpSCurve(&lerpX, creditTime) - (zscale * credits[currCredit].img->w),
                            dmLerpSCurve(&lerpY, creditTime) - (zscale * credits[currCredit].img->h),
                            credits[currCredit].img->w * (1.0f + zscale),
                            credits[currCredit].img->h * (1.0f + zscale),
                            ruutu);

                        currState = -1;
                        break;
                    
                    default:
                        currCredit++;
                        currState = 0;
                        stateChange = TRUE;
                        break;
                }
            }
            

            if (currCredit > 0)
            {
                int zk = cos(engineGetTime(engine, 0) / 250.0f) * 25;
                kblit(ruutu, -zk, -zk, engine->screen->w + zk*2, engine->screen->h + zk*2, engine->screen);
            }

            if (currState == 1)
            {
                if (creditTime >= CREDITS_SPEED)
                {
                    creditTime = CREDITS_SPEED;
                    stateChange = TRUE;
                    currState = 2;
                }

                zscale = dmLerpSCurve(&lerpZ, creditTime);
                kblit(credits[currCredit].img,
                    dmLerpSCurve(&lerpX, creditTime) - (zscale * credits[currCredit].img->w),
                    dmLerpSCurve(&lerpY, creditTime) - (zscale * credits[currCredit].img->h),
                    credits[currCredit].img->w * (1.0f + zscale),
                    credits[currCredit].img->h * (1.0f + zscale),
                    engine->screen);
            }
        }
        
    }
    else
    if (t < 60)
    {
        //
        // Greetings
        //
        int dt = engineGetTime(engine, 45);
        static SDL_Surface *logobg, *greets;
        static DMScaledBlitFunc nblit, kblit;
        static DMLerpContext lerpD;
        static BOOL nollattu = FALSE;

        if (!nollattu)
        {
            engineGetResImage(engine, logobg, "logobg.png");
            engineGetResImage(engine, greets, "greetings.png");
            nblit = dmGetScaledBlitFunc(logobg->format, engine->screen->format, DMD_TRANSPARENT);
            kblit = dmGetScaledBlitFunc(logobg->format, engine->screen->format, DMD_NONE);
            dmLerpInit(&lerpD, 0.01, 500, 10000);
            nollattu = TRUE;
        }

        float q = dmLerpSCurve(&lerpD, dt);
        float t = sin((float) dt / 150.0f),
              j = (1.0 + t) * 15;
        int x = t * 25.0f + q, y = t * 35.0f + q,
            w = t * 70.0f + q*2.0f, h = t * 40.0f + q*2.0f;

        kblit(logobg, -j, -j, engine->screen->w+j*2.0f, engine->screen->h+j*2.0f, engine->screen);
        nblit(greets, -x, -y, engine->screen->w+w, engine->screen->h+h, engine->screen);
    }
    else
        engine->exitFlag = TRUE;


    //
    // Flash/fade thingy
    //
    {
        static SDL_Surface *feidi;
        static int fadeStartTime;
        static BOOL fadeActive, nollattu = FALSE;
        static DMLerpContext fadeLerp;
        BOOL hit;
        int ch;

        if (!nollattu)
        {
            engineGetResImage(engine, feidi, "feidi.png");
            dmLerpInit(&fadeLerp, 255, 0, 250);
            nollattu = TRUE;
        }

        JSS_LOCK(engine->jssPlr);
        for (hit = FALSE, ch = 0; ch < 6; ch++)
        if (engine->jssPlr->channels[ch].nextInstrument == 0)
        {
            hit = TRUE;
            break;
        }
        JSS_UNLOCK(engine->jssPlr);

        if (hit && !fadeActive)
        {
            fadeActive = TRUE;
            fadeStartTime = engineGetTime(engine, 0);
        }
        if (fadeActive)
        {
            int fadeTime = engineGetTime(engine, 0) - fadeStartTime;
            if (fadeTime < 250)
            {
                dmScaledBlitSurface32to32TransparentGA(feidi,
                    0, 0, engine->screen->w, engine->screen->h, engine->screen,
                    dmLerpSCurve(&fadeLerp, fadeTime));
            }
            else
                fadeActive = FALSE;
        }
    }

    return DMERR_OK;
}