changeset 58:08913cea6de1

Branch merge.
author Matti Hamalainen <ccr@tnsp.org>
date Tue, 04 Oct 2016 00:15:43 +0300
parents 51110f424dfd (current diff) 41df6868905c (diff)
children 7daf69b39f34
files demo.c krapula.c
diffstat 10 files changed, 760 insertions(+), 729 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile	Wed Mar 04 04:42:09 2015 +0200
+++ b/Makefile	Tue Oct 04 00:15:43 2016 +0300
@@ -1,23 +1,27 @@
 #
-# Generic UNIX targets
+# Generic build target
 #
-SDL_CFLAGS=`sdl-config --cflags`
-SDL_LDFLAGS=`sdl-config --static-libs`
+DMLIB = ./dmlib/
+MAKE ?= make
 
-TREMOR_CFLAGS=-I/usr/local/lib/
-TREMOR_LDFLAGS=/usr/local/lib/libvorbisidec.a /usr/lib/i386-linux-gnu/libogg.a
+export DMLIB
 
-LIBPNG_CFLAGS=`pkg-config --cflags libpng`
-LIBPNG_LDFLAGS=`pkg-config --libs libpng`
+unix:
+	$(MAKE) -f $(DMLIB)Makefile EXEEXT=.bin
 
-ZLIB_CFLAGS=`pkg-config --cflags zlib`
-ZLIB_LDFLAGS=`pkg-config --libs zlib`
-
-RANLIB=ranlib
+mingw-win32:
+	$(MAKE) -f $(DMLIB)Makefile.cross-mingw \
+	OBJPATH=./obj/win32/ \
+	MINGW_PREFIX=i686-w64-mingw32- \
+	MINGW_PATH=/usr/i686-w64-mingw32
 
-DMLIB = ./dmlib/
-BINPATH ?= ./
-OBJPATH ?= ./obj/unix/
-EXEEXT ?= .bin
+mingw-win64:
+	$(MAKE) -f $(DMLIB)Makefile.cross-mingw \
+	OBJPATH=./obj/win64/ \
+	MINGW_PREFIX=x86_64-w64-mingw32- \
+	MINGW_PATH=/usr/x86_64-w64-mingw32
 
-include $(DMLIB)Makefile.gen
+clean:
+	-$(MAKE) -f $(DMLIB)Makefile clean EXEEXT=.bin
+	-$(MAKE) -f $(DMLIB)Makefile.cross-mingw clean
+	
\ No newline at end of file
--- a/build-data.sh	Wed Mar 04 04:42:09 2015 +0200
+++ b/build-data.sh	Tue Oct 04 00:15:43 2016 +0300
@@ -5,11 +5,11 @@
 
 if test ! -x "$CPACKED"; then
 	make -f Makefile clean
-	make -f Makefile EXEEXT=".bin" BINPATH="$CPWD/" "$CPACKED"
+	make -f Makefile EXEEXT=".bin" TOOL_BINPATH="$CPWD/" "$CPACKED"
 fi
 
-cd "$CPWD/data" && $CPACKED -c -p "$CPWD/exe/$CPACKFILE" *
+cd "$CPWD/data" && $CPACKED -c -p "$CPWD/$CBINPATH/$CPACKFILE" *
 
 if test ! -e "$CPWD/$CPACKFILE"; then
-	ln -s "$CPWD/exe/$CPACKFILE" "$CPWD/$CPACKFILE"
+	ln -s "$CPWD/$CBINPATH/$CPACKFILE" "$CPWD/$CPACKFILE"
 fi
--- a/build.sh	Wed Mar 04 04:42:09 2015 +0200
+++ b/build.sh	Tue Oct 04 00:15:43 2016 +0300
@@ -2,24 +2,24 @@
 . ./build.cfg
 CPWD=`pwd`
 
-for build in amd:k8 intel:core2; do
+for build in intel:core2; do
 	# Split into platform and march
 	platform=`echo "$build"|cut -d ':' -f 1`
 	march=`echo "$build"|cut -d ':' -f 2`
 	
 	# Build Unix binary
 	make -f Makefile clean
-	make -f Makefile EXTRA_CFLAGS="-march=$march" EXEEXT=".bin" BINPATH="$CPWD/"
-	(strip "$CPWD/${CEXE}.bin" && mv "$CPWD/${CEXE}.bin" "$CPWD/${CBINPATH}${CEXE}-${platform}-linux32.bin") || exit 1
+	make -f Makefile EXTRA_CFLAGS="-O3 -march=$march" EXEEXT=".bin" BINPATH="$CPWD/"
+	(strip "$CPWD/${CEXE}.bin" && mv "$CPWD/${CEXE}.bin" "$CPWD/${CBINPATH}/${CEXE}-linux-x86.bin") || exit 1
 
 	# Build Win32 executable
 	make -f Makefile.w32 clean
-	make -f Makefile.w32 EXTRA_CFLAGS="-march=$march" EXEEXT=".exe" BINPATH="$CPWD/"
-	(mv "$CPWD/${CEXE}.exe" "$CPWD/${CBINPATH}${CEXE}_${platform}_win32.exe") || exit 1
+	make -f Makefile.w32 EXTRA_CFLAGS="-O3 -march=$march" EXEEXT=".exe" BINPATH="$CPWD/"
+	(mv "$CPWD/${CEXE}.exe" "$CPWD/${CBINPATH}/${CEXE}-win32.exe") || exit 1
 done
 
 (cd "$CPWD" && exec ./build-data.sh) || exit 1
 
 rm -f "$CPWD/$CZIP"
 
-cd "$CPWD/${CBINPATH}" && zip -9 "$CPWD/$CZIP" *
+cd "$CPWD/${CBINPATH}/" && zip -9 "$CPWD/$CZIP" *
--- a/config.mak	Wed Mar 04 04:42:09 2015 +0200
+++ b/config.mak	Tue Oct 04 00:15:43 2016 +0300
@@ -1,7 +1,9 @@
 # Additional binaries (aka the demo)
 DEMO_BIN=krapula
-DEMO_OBJS=krapula.o dmsimple.o
-BINARIES=$(DEMO_BIN)
+DEMO_OBJS=demo.o dmsimple.o
+
+TOOL_BINPATH=bin/
+TESTS_BINPATH=$(TOOL_BINPATH)
 
 # Build engine tests and tools? (Please notice that what
 # actually gets built it also affected by other options)
@@ -29,7 +31,6 @@
 DM_USE_STDIO=no
 DM_USE_MEMIO=no
 
-
 DM_GFX_BM_TEXT=yes
 DM_GFX_TTF_TEXT=no
 DM_GFX_LINES=no
@@ -46,7 +47,7 @@
 JSS=yes
 
 # Build a special "light"/minimized version by removing all
-# error messages and few other things.
+# error messages and few other things. (disabled by DM_DEBUG=yes)
 JSS_LIGHT=yes
 
 # Build with extra debugging code? (disabled by JSS_LIGHT=yes)
@@ -83,5 +84,3 @@
 ### Locking/thread support
 ###
 JSS_SUP_THREADS=yes
-
-
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/data/SetupData.txt	Tue Oct 04 00:15:43 2016 +0300
@@ -0,0 +1,31 @@
+# Tässä määritellään videomoodikonfiguraatiovalikon elementit.
+# Taustakuvat on aina SetupImage.png, jonka PITÄÄ olla kokoa 640x480
+# Haluttu fontti on SetupFont.dmf, jonka voi luoda fontconv-ohjelmalla
+# esim. Truetype TTF-fonttitiedostosta (kaikki TTF-fontit eivät kyllä
+# konvertoidu kauniisti.)
+
+# Koot ja koordinaatit määritetään desimaalilukuina, esim.
+# X (vaaka)-koordinaatti 0.5 on ruudun puoliväli. Koossa 0.5
+# tarkoittaa luonnollisesti puolta (50%) koko ruudusta.
+
+# Resoluutiovalikon sijainti 
+menuPos 0.1 0.35
+
+# Resoluutiovalikon koko
+menuDim 0.8 0.4
+
+menuBarOffs 0 -0.002
+
+menuBarDimAdj 0 0.01
+
+# Fullscreen/windowed -tekstin sijainti
+text1Pos 0.04 0.9
+
+# "Enter to start" tekstin sijainti
+text2Pos 0.25 0.85
+
+# Keskitetäänkö valikon tekstit (0 = ei, 1 = kyllä)
+menuCenter 1
+
+# Tiivistetäänkö fontti:
+textCondensed 1
Binary file data/SetupFont.dmf has changed
Binary file data/SetupImage.png has changed
Binary file data/SetupMenuBar.png has changed
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/demo.c	Tue Oct 04 00:15:43 2016 +0300
@@ -0,0 +1,695 @@
+#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];
+    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);
+}
+
+
+#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->optDataPath  = NULL;
+    engine->optResFlags  = DRF_USE_PACK | DRF_PRELOAD_RES;
+
+    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;
+    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.jss");
+
+    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;
+}
--- a/krapula.c	Wed Mar 04 04:42:09 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,698 +0,0 @@
-#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];
-    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);
-}
-
-
-#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->optDataPath  = NULL;
-    engine->optResFlags  = DRF_USE_PACK | DRF_PRELOAD_RES;
-
-    engine->optAudioSetup    = DM_ASETUP_JSS;
-    engine->optAfmt.freq     = 44100;
-    engine->optAfmt.format   = AUDIO_S16SYS;
-    engine->optAfmt.channels = 2;
-
-    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;
-    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.jss");
-
-    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;
-}