Mercurial > hg > demos > krapula
diff demo.c @ 52:1e1d256a55b3
Rename main code file.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 03 Oct 2016 08:51:31 +0300 |
parents | krapula.c@8c65e57cc81a |
children | b8bbed30748b |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/demo.c Mon Oct 03 08:51:31 2016 +0300 @@ -0,0 +1,698 @@ +#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.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; +}