Mercurial > hg > demos > krapula
view krapula.c @ 17:758a39d3f750
Various "engine" cleanups.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 29 Sep 2012 13:27:38 +0300 |
parents | 833dad075e3b |
children | ccc5cdce91e3 |
line wrap: on
line source
#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 <math.h> #define DM_COLORS (256) 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 engineAudioCallback(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; 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 engineResImageLoad(DMResource *res) { SDL_Surface *img = dmLoadImage(res); if (res != NULL) { res->rdata = img; return DMERR_OK; } else return dmferror(res); } void engineResImageFree(DMResource *res) { SDL_FreeSurface((SDL_Surface *)res->rdata); } int engineResModuleLoad(DMResource *res) { return jssLoadXM(res, (JSSModule **) &(res->rdata)); } void engineResModuleFree(DMResource *res) { jssFreeModule((JSSModule *) res->rdata); } static DMResourceDataOps engineResImage = { engineResImageLoad, engineResImageFree }; static DMResourceDataOps engineResModule = { engineResModuleLoad, engineResModuleFree }; int engineClassifier(DMResource *res) { DMResourceDataOps *rops = NULL; char *fext; if (res == NULL) return DMERR_NULLPTR; if ((fext = strrchr(res->filename, '.')) != NULL) { if (strcasecmp(fext, ".png") == 0 || strcasecmp(fext, ".jpg") == 0) rops = &engineResImage; else if (strcasecmp(fext, ".xm") == 0 || strcasecmp(fext, ".jmod") == 0) rops = &engineResModule; } res->rops = rops; return DMERR_OK; } void *engineGetResource(const char *name) { DMResource *res = dmres_find(name); if (res != NULL && res->rdata != NULL) return res->rdata; else { dmError("Could not find resource '%s'.\n", name); return NULL; } } #define engineGetResImage(name) (SDL_Surface *) engineGetResource(name) #define engineGetResModule(name) (JSSModule *) engineGetResource(name) int engineLoadResources() { int err, loaded, total; err = dmres_preload(TRUE, &loaded, &total); while ((err = dmres_preload(FALSE, &loaded, &total)) == DMERR_PROGRESS) { // Show a nice progress bar while loading if (total > 0 && (loaded % 2) == 0) { int dx = 60, dh = 20, dw = engine.screen->w - (2 * dx), dy = (engine.screen->h - dh) / 2; if (SDL_MUSTLOCK(engine.screen) != 0 && SDL_LockSurface(engine.screen) != 0) return DMERR_INIT_FAIL; // Draw the progress bar dmClearSurface(engine.screen, dmMapRGBA(engine.screen, 0,0,0,0)); dmFillRect(engine.screen, dx, dy, dx+dw, dy+dh, dmMapRGB(engine.screen, 255,255,255)); dmFillRect(engine.screen, dx+1, dy+1, dx+dw-1, dy+dh-1, dmMapRGB(engine.screen, 0,0,0)); if (total > 0) { dmFillRect(engine.screen, dx+3, dy+3, dx + 3 + ((dw - 3) * loaded) / total, dy + dh - 3, dmMapRGB(engine.screen, 200,200,200)); } // Flip screen if (SDL_MUSTLOCK(engine.screen) != 0) SDL_UnlockSurface(engine.screen); SDL_Flip(engine.screen); } } return err; } int main(int argc, char *argv[]) { BOOL initSDL = FALSE; JSSModule *mod = NULL; JSSMixer *dev = NULL; JSSPlayer *plr = NULL; int err, i; SDL_AudioSpec afmt; memset(&afmt, 0, sizeof(afmt)); 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"); // Initialize resource subsystem dmPrint(1, "Initializing resources subsystem.\n"); if ((err = dmres_init("orvellys.dat", NULL, DRF_USE_PACK | DRF_PRELOAD_RES, engineClassifier)) != DMERR_OK) { dmError("Could not initialize resource manager: %d, %s.\n", err, dmErrorStr(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; // Initialize JSS jssInit(); afmt.freq = 44100; afmt.format = AUDIO_S16SYS; afmt.channels = 2; afmt.samples = 16*1024; dmPrint(1, "Initializing miniJSS mixer with: %d, %d, %d\n", JSS_AUDIO_S16, afmt.channels, afmt.freq); if ((dev = jvmInit(JSS_AUDIO_S16, afmt.channels, afmt.freq, JMIX_AUTO)) == NULL) { dmError("jvmInit() returned NULL, voi perkele.\n"); goto error_exit; } if ((plr = jmpInit(dev)) == NULL) { dmError("jmpInit() returned NULL\n"); goto error_exit; } // Initialize SDL audio dmPrint(1, "Trying to init SDL audio with: %d, %d, %d\n", afmt.format, afmt.channels, afmt.freq); afmt.callback = engineAudioCallback; afmt.userdata = (void *) dev; if (SDL_OpenAudio(&afmt, NULL) < 0) { dmError("Couldn't open audio: %s\n", SDL_GetError()); goto error_exit; } // Initialize SDL video dmPrint(1, "Initializing SDL video %d x %d x %dbpp - %08x flags\n", optScrWidth, optScrHeight, 32, optVFlags); engine.screen = SDL_SetVideoMode(optScrWidth, optScrHeight, 32, optVFlags); if (engine.screen == NULL) { dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); goto error_exit; } SDL_ShowCursor(SDL_DISABLE); SDL_WM_SetCaption(dmProgDesc, dmProgName); // Load resources err = engineLoadResources(); if (err != DMERR_OK) { dmError("Error loading resources, %d: %s.\n", err, dmErrorStr(err)); goto error_exit; } // Initialize effect stuff dmPerlinInit(); SDL_Surface *nosfe[NOSFE_MAX - NOSFE_MIN + 1]; for (i = 0; i < NOSFE_MAX; i++) { char fname[64]; snprintf(fname, sizeof(fname), "%08d.jpg", NOSFE_MIN + i); nosfe[i] = engineGetResImage(fname); } for (i = 0; i < ncredits; i++) credits[i].img = engineGetResImage(credits[i].filename); SDL_Surface *bmap = SDL_CreateRGBSurface(SDL_SWSURFACE, QWIDTH, QHEIGHT, 8, 0, 0, 0, 0); // Initialize music player jvmSetCallback(dev, jmpExec, plr); jmpSetModule(plr, engineGetResModule("krapula.xm")); jmpPlayOrder(plr, 0); jvmSetGlobalVol(dev, 55); 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; 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) { SDL_Surface *anciat; int dt = engineGetTime(0); static DMLerpContext lerpX, lerpY, lerpD; static DMScaledBlitFunc nblit; DMVector light; static BOOL nollattu = FALSE; if (!nollattu) { anciat = engineGetResImage("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) { SDL_Surface *logobg, *logolayer1, *logolayer2; int dt = engineGetTime(5); static DMScaledBlitFunc nblit, kblit; static DMLerpContext lerpD; static BOOL nollattu = FALSE; if (!nollattu) { logobg = engineGetResImage("logobg.png"); logolayer1 = engineGetResImage("logolayer1.png"); logolayer2 = engineGetResImage("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) { SDL_Surface *gay, *logobg; int dt = engineGetTime(10); static DMLerpContext lerpX, lerpY, lerpD; static DMScaledBlitFunc nblit, kblit; static BOOL nollattu = FALSE; DMVector light; DMBlockMap heightMap; if (!nollattu) { gay = engineGetResImage("gay.png"); logobg = engineGetResImage("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) { ruutu = engineGetResImage("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) { // 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) { SDL_Surface *logobg, *greets; int dt = engineGetTime(45); static DMScaledBlitFunc nblit, kblit; static DMLerpContext lerpD; static BOOL nollattu = FALSE; if (!nollattu) { logobg = engineGetResImage("logobg.png"); greets = engineGetResImage("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) { feidi = engineGetResImage("feidi.png"); dmLerpInit(&fadeLerp, 255, 0, 250); nollattu = TRUE; } JSS_LOCK(plr); for (hit = FALSE, ch = 0; ch < 6; ch++) if (plr->iCExtInstrumentN[ch] == 0) { hit = TRUE; break; } JSS_UNLOCK(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; } } // Flip screen if (SDL_MUSTLOCK(engine.screen) != 0) SDL_UnlockSurface(engine.screen); SDL_Flip(engine.screen); SDL_Delay(20); // Get frame time, etc 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); SDL_LockAudio(); jmpClose(plr); jvmClose(dev); jssFreeModule(mod); jssClose(); SDL_UnlockAudio(); dmres_close(); if (initSDL) SDL_Quit(); dmPrint(0, "SDL on muuten melko paska kirjasto.\n"); return 0; }