# HG changeset patch # User Matti Hamalainen # Date 1348788564 -10800 # Node ID 9578b979556a0c5fa7ee8bb04834a7f277619585 # Parent f5711d6e0cb5a30345e725d4cb66a0f6135433e1 Import main code. diff -r f5711d6e0cb5 -r 9578b979556a krapula.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/krapula.c Fri Sep 28 02:29:24 2012 +0300 @@ -0,0 +1,1005 @@ +#include "dmlib.h" +#include "dmargs.h" +#include "dmvecmat.h" +#include "dmres.h" +#include "dmimage.h" + +#include "jss.h" +#include "jssmod.h" +#include "jssmix.h" +#include "jssplr.h" + +#include + +#define DM_COLORS (256) + +static BOOL dmDoLoadImage(SDL_Surface **img, const char *fname) +{ + DMResource *file = dmf_open(fname); + if (file == NULL) + return FALSE; + + if ((*img = dmLoadImage(file)) == NULL) + { + dmf_close(file); + return FALSE; + } + + dmf_close(file); + return TRUE; +} + +#define LOADIMAGE(img, fname) \ + do { \ + if (!dmDoLoadImage(&(img), fname)) \ + goto error_exit; \ + } while (0) + + + +typedef struct +{ + int x, y; +} DMCoords; + + +typedef struct +{ + int x, y; + char *filename; + SDL_Surface *img; +} DMCredits; + + +typedef struct +{ + int currFrame, endTime, startTime, totalFrameTime; + BOOL pauseFlag, exitFlag; + SDL_Surface *screen; + SDL_Event event; +} DMEngineData; + + +typedef struct +{ + int currFrame, endTime, startTime; +} DMFrameData; + + + + +int optVFlags = SDL_SWSURFACE | SDL_HWPALETTE; +int optScrWidth = 640, optScrHeight = 480; +int optBenchmarkLen = 20; + + +DMOptArg optList[] = { + { 0, '?', "help", "Show this help", OPT_NONE }, + { 2, 'v', "verbose", "Be more verbose", OPT_NONE }, + { 3, 'f', "fs", "Fullscreen", OPT_NONE }, +// { 5, 's', "size", "Screen resolution -s 640x480", OPT_ARGREQ }, +}; + +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 2: + dmVerbosity++; + break; + + case 3: + optVFlags |= SDL_FULLSCREEN; + break; + + case 5: + { + int w, h; + if (sscanf(optArg, "%dx%d", &w, &h) == 2) + { + if (w < 320 || h < 200 || w > 1024 || h > 768) + { + dmError("Invalid width or height: %d x %d\n", w, h); + return FALSE; + } + optScrWidth = w; + optScrHeight = h; + } + else + { + dmError("Invalid size argument '%s'.\n", optArg); + return FALSE; + } + } + 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); +} + + +BOOL dmInitializeVideo(SDL_Surface **screen) +{ + *screen = SDL_SetVideoMode(optScrWidth, optScrHeight, 32, optVFlags); // | SDL_RESIZABLE); + if (*screen == NULL) + { + dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); + return FALSE; + } + + SDL_ShowCursor(SDL_DISABLE); + return TRUE; +} + + +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; + } +} + + +void dmAudioCallback(void *userdata, Uint8 *stream, int len) +{ + JSSMixer *d = (JSSMixer *) userdata; + + if (d != NULL) + { + jvmRenderAudio(d, stream, len / jvmGetSampleSize(d)); + } +} + +#define DEBUG 0 + +#define CREDITS_SPEED 1000 +#define CREDITS_RAND 4 + +#define NOSFE_MIN 1 +#define NOSFE_MAX 269 + +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]); + + +DMEngineData engine; +DMFrameData frame; + +SDL_Surface *nosfe[NOSFE_MAX - NOSFE_MIN + 1]; + +SDL_Surface *logobg, *logolayer1, *logolayer2, + *anciat, *gay, *ruutu, *greets; + + +int engineGetTick() +{ + return (frame.startTime - engine.startTime) + DEBUG * 1000; +} + +float engineGetTimeDT() +{ + return (float) engineGetTick() / 1000.0f; +} + + +int engineGetTimeDTi() +{ + return (float) engineGetTick() / 1000; +} + + +int engineGetTime(int t) +{ + return engineGetTick() - (1000 * t);; +} + + +int engineGetDT(int t) +{ + return engineGetTime(t) / 1000; +} + + +int dmScaledBlitSurface32to32TransparentX(SDL_Surface *src, const int x0, const int y0, const int dwidth, const int dheight, SDL_Surface *dst); + + + +int main(int argc, char *argv[]) +{ + BOOL initSDL = FALSE; + JSSModule *mod = NULL; + JSSMixer *dev = NULL; + JSSPlayer *plr = NULL; + int err, i; + DMResource *tfile; + SDL_AudioSpec *a_desired = NULL, *a_obtained = NULL; + + memset(&frame, 0, sizeof(frame)); + memset(&engine, 0, sizeof(engine)); + + dmInitProg("krapula", "Lauantai Aamun Krapula", "0.2", "(c) 2012 Anciat Prodz & TNSP", "PENIS."); + if (!dmArgsProcess(argc, argv, optList, optListN, + argHandleOpt, NULL, FALSE)) + exit(1); + + dmPrint(0, "%s\n", dmProgDesc); + dmPrint(0, "%s\n", dmProgAuthor); + dmPrint(0, "TNSP PIERUPASKA engine 2012 'passeli professional' loading.\n"); + + // Open packfs + if ((err = dmres_init("orvellys.dat", NULL, DRF_USE_PACK)) != DMERR_OK) + { + dmError("Could not initialize PACKFS: %d, %s.\n", err, dmErrorStr(err)); + goto error_exit; + } + + dmMsg(0, "miniJSS audio kyrpe XD\n"); + jssInit(); + + + // Dataa + dmPrint(0, "cachetaan motion jpeg videota (blz wait) .."); + for (i = 0; i < NOSFE_MAX; i++) + { + char fname[64]; + snprintf(fname, sizeof(fname), "%08d.jpg", NOSFE_MIN + i); + dmPrint(0, "."); + + if (!dmDoLoadImage(&nosfe[i], fname)) + { + dmError("Error uncompressing motion jpeg video.\n"); + goto error_exit; + } + } + dmPrint(0,"ok\n"); + + dmPrint(0, "ogei, loput resurssit .."); + LOADIMAGE(logobg, "logobg.png"); + LOADIMAGE(logolayer1, "logolayer1.png"); + LOADIMAGE(logolayer2, "logolayer2.png"); + LOADIMAGE(anciat, "anciat.png"); + LOADIMAGE(gay, "gay.png"); + LOADIMAGE(ruutu, "ruutu.png"); + LOADIMAGE(greets, "greetings.png"); + + for (i = 0; i < ncredits; i++) + LOADIMAGE(credits[i].img, credits[i].filename); + + dmPrint(0, "joo\n"); + + if ((tfile = dmf_open("krapula.xm")) == NULL) + { + dmError("EI VOINU MUSSIIKKIA LADATA!!!\n"); + goto error_exit; + } + + err = jssLoadXM(tfile, &mod); + dmf_close(tfile); + if (err != DMERR_OK) + { + dmError("Joasdfok XM motuuli ei?? %d\n", err); + goto error_exit; + } + + + // Initialize SDL components + if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_AUDIO | SDL_INIT_TIMER) != 0) + { + dmError("Could not initialize SDL: %s\n", SDL_GetError()); + goto error_exit; + } + initSDL = TRUE; + + + // Audio kyrvet + a_desired = dmMalloc(sizeof(SDL_AudioSpec)); + a_obtained = dmMalloc(sizeof(SDL_AudioSpec)); + if (!a_desired || !a_obtained) + { + fprintf(stderr, "Could not allocate SDL shit\n"); + return 3; + } + + a_desired->freq = 48000; + a_desired->format = AUDIO_S16SYS; + a_desired->channels = 2; + + dmMsg(0, "Initializing miniJSS mixer with: %d, %d, %d\n", + JSS_AUDIO_S16, a_desired->channels, a_desired->freq); + + dev = jvmInit(JSS_AUDIO_S16, a_desired->channels, a_desired->freq, JMIX_AUTO); + if (!dev) + { + dmError("jvmInit() returned NULL, voi perkele.\n"); + goto error_exit; + } + + a_desired->samples = 16*1024; + a_desired->callback = dmAudioCallback; + a_desired->userdata = (void *) dev; + + /* Open the audio device */ + dmMsg(0, "Trying to init SDL audio with: %d, %d, %d\n", + a_desired->format, a_desired->channels, a_desired->freq); + + if (SDL_OpenAudio(a_desired, a_obtained) < 0) + { + dmError("Couldn't open audio: %s\n", SDL_GetError()); + goto error_exit; + } + + dmMsg(0, "SDL gave us: %d, %d, %d\n", + a_obtained->format, a_obtained->channels, a_obtained->freq); + + if ((a_obtained->format != a_desired->format) || + (a_obtained->channels != a_desired->channels) || + (a_obtained->freq != a_desired->freq)) + { + dmError("Could not get wanted audio parameters from SDL!\n"); + goto error_exit; + } + + dmFree(a_desired); + + plr = jmpInit(dev); + if (!plr) + { + dmError("jmpInit() returned NULL\n"); + goto error_exit; + } + + /* Set callback, init module */ + jvmSetCallback(dev, jmpExec, plr); + jmpSetModule(plr, mod); + jmpPlayOrder(plr, 0); + jvmSetGlobalVol(dev, 55); + + // Joo + if (!dmInitializeVideo(&engine.screen)) + goto error_exit; + + SDL_WM_SetCaption(dmProgDesc, dmProgName); + + // efut + dmPerlinInit(); + + SDL_Surface *bmap = SDL_CreateRGBSurface(SDL_SWSURFACE, QWIDTH, QHEIGHT, 8, 0, 0, 0, 0); + + + dmMsg(0, "We are go.\n"); + SDL_PauseAudio(0); + + engine.startTime = SDL_GetTicks(); + + + while (!engine.exitFlag) + { + + while (SDL_PollEvent(&engine.event)) + switch (engine.event.type) + { + case SDL_KEYDOWN: + switch (engine.event.key.keysym.sym) + { + case SDLK_ESCAPE: + engine.exitFlag = TRUE; + break; + + case SDLK_SPACE: + engine.pauseFlag = !engine.pauseFlag; + break; + + default: + break; + } + + break; + +#if 0 + case SDL_VIDEORESIZE: + optScrWidth = engine.event.resize.w; + optScrHeight = engine.event.resize.h; + + if (!dmInitializeVideo(&engine.screen)) + goto error_exit; + break; +#endif + + case SDL_VIDEOEXPOSE: + break; + + case SDL_QUIT: + engine.exitFlag = TRUE; + break; + } + + // Draw frame + frame.startTime = SDL_GetTicks(); + + if (SDL_MUSTLOCK(engine.screen) != 0 && SDL_LockSurface(engine.screen) != 0) + { + dmError("Can't lock surface.\n"); + goto error_exit; + } + + float t = engineGetTimeDT(); + + if (t < 5) + { + int dt = engineGetTime(0); + static DMLerpContext lerpX, lerpY, lerpD; + static DMScaledBlitFunc nblit; + DMVector light; + static BOOL nollattu = FALSE; + if (!nollattu) + { + 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 DMScaledBlitFunc nblit, kblit; + static DMLerpContext lerpD; + static BOOL nollattu = FALSE; + + if (!nollattu) + { + 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 DMLerpContext lerpX, lerpY, lerpD; + static DMScaledBlitFunc nblit, kblit; + static BOOL nollattu = FALSE; + DMVector light; + DMBlockMap heightMap; + + if (!nollattu) + { + 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 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) + { + 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) + { +// fprintf(stderr, "[%6d] stateChange: st=%d, credit=%d\n", creditTime, currState, currCredit); + 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; + } + +// fprintf(stderr, "[%6d] changed: st=%d, credit=%d, chg=%d\n", creditTime, currState, currCredit, stateChange); + } + + + 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 DMScaledBlitFunc nblit, kblit; + static DMLerpContext lerpD; + static BOOL nollattu = FALSE; + + if (!nollattu) + { + 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, + w = t * 70.0f + q*2.0f, h = t * 40.0f + q*2.0f; + + kblit(logobg, 0, 0, engine.screen->w, engine.screen->h, engine.screen); + nblit(greets, -x, -y, engine.screen->w+w, engine.screen->h+h, engine.screen); + } + else + engine.exitFlag = TRUE; + + // Flip screen + if (SDL_MUSTLOCK(engine.screen) != 0) + SDL_UnlockSurface(engine.screen); + + SDL_Flip(engine.screen); + SDL_Delay(20); + frame.endTime = SDL_GetTicks(); + + engine.currFrame++; + engine.totalFrameTime += frame.endTime - frame.startTime; + } + + // Print benchmark results + engine.endTime = SDL_GetTicks(); + dmMsg(0, "%d frames in %d ms, fps = %1.3f\n", + engine.currFrame, engine.endTime - engine.startTime, + (float) (engine.currFrame * 1000.0f) / (float) engine.totalFrameTime); + + +error_exit: + dmMsg(0, "Shutting down.\n"); + SDL_ShowCursor(SDL_ENABLE); + SDL_PauseAudio(1); + + if (engine.screen) + SDL_FreeSurface(engine.screen); + + jmpClose(plr); + jvmClose(dev); + jssFreeModule(mod); + + dmres_close(); + + if (initSDL) + SDL_Quit(); + + dmPrint(0, "SDL on muuten melko paska kirjasto.\n"); + + return 0; +}