view krapula.c @ 22:af6fad875a28

Cleanups.
author Matti Hamalainen <ccr@tnsp.org>
date Sun, 30 Sep 2012 19:12:32 +0300
parents ea93b1d5c894
children c9cd46294786
line wrap: on
line source

#include "dmsimple.h"
#include "dmvecmat.h"

#include <math.h>


#define DM_COLORS (256)


DMOptArg optList[] =
{
    { 0, '?', "help",       "Show this help", OPT_NONE },
    { 1, 'v', "verbose",    "Be more verbose", OPT_NONE },
    { 2, 'f', "fs",         "Fullscreen", OPT_NONE },
};

const int optListN = sizeof(optList) / sizeof(optList[0]);



void argShowHelp()
{
    dmPrintBanner(stdout, dmProgName, "[options]");
    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;

    default:
        dmError("Unknown option '%s'.\n", currArg);
        return FALSE;
    }
    
    return TRUE;
}




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


void dmPerlin(SDL_Surface *screen, float f)
{
    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++ = 128 + dmPerlinNoise2D(xc, yc, 0.01, 0.1, 3) / 34.0;
        }

        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;
        }
}


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(int argc, char *argv[])
{
    dmInitProg("krapula", "Lauantai Aamun Krapula", "0.2", "(c) 2012 Anciat Prodz & TNSP", "PENIS.");

    engine.optScrWidth  = 640;
    engine.optScrHeight = 480;
    engine.optBitDepth  = 32;
    engine.optVFlags    = SDL_SWSURFACE | SDL_HWPALETTE;


    if (!dmArgsProcess(argc, argv, optList, optListN,
        argHandleOpt, NULL, FALSE))
        return DMERR_INIT_FAIL;

    dmPrint(0, "%s\n", dmProgDesc);
    dmPrint(0, "%s\n", dmProgAuthor);
    dmPrint(0, "TNSP PIERUPASKA engine 2012 'passeli professional' loading.\n");

    return DMERR_OK;
}


int demoGlobalInit()
{
    int i;

    // Initialize effect stuff
    dmPerlinInit();

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

    for (i = 0; i < ncredits; i++)
        engineGetResImage(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(mod, "krapula.xm");
    jvmSetCallback(engine.dev, jmpExec, engine.plr);
    jmpSetModule(engine.plr, mod);
    jmpPlayOrder(engine.plr, 0);
    jvmSetGlobalVol(engine.dev, 55);
    SDL_PauseAudio(0);

    return DMERR_OK;
}


int demoMainTick()
{
    float t = engineGetTimeDT();

    if (t < 5)
    {
        int dt = engineGetTime(0);
        static SDL_Surface *anciat;
        static DMLerpContext lerpX, lerpY, lerpD;
        static DMScaledBlitFunc nblit;
        DMVector light;
        static BOOL nollattu = FALSE;
        if (!nollattu)
        {
            engineGetResImage(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)
    {
        int dt = engineGetTime(5);
        static SDL_Surface *logobg, *logolayer1, *logolayer2;
        static DMScaledBlitFunc nblit, kblit;
        static DMLerpContext lerpD;
        static BOOL nollattu = FALSE;

        if (!nollattu)
        {
            engineGetResImage(logobg, "logobg.png");
            engineGetResImage(logolayer1, "logolayer1.png");
            engineGetResImage(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)
    {
        int dt = engineGetTime(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(gay, "gay.png");
            engineGetResImage(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)
    {
        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(20) * 15 / 1000;
        if (!nollattu)
        {
            engineGetResImage(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(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(30);
            int creditTime = (engineGetTime(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(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)
            {
                kblit(ruutu, 0, 0, engine.screen->w, engine.screen->h, 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)
    {
        int dt = engineGetTime(45);
        static SDL_Surface *logobg, *greets;
        static DMScaledBlitFunc nblit, kblit;
        static DMLerpContext lerpD;
        static BOOL nollattu = FALSE;

        if (!nollattu)
        {
            engineGetResImage(logobg, "logobg.png");
            engineGetResImage(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;


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

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

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

        if (hit && !fadeActive)
        {
            fadeActive = TRUE;
            fadeStartTime = engineGetTime(0);
        }
        if (fadeActive)
        {
            int fadeTime = engineGetTime(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;
}


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