Mercurial > hg > dmlib
view blittest.c @ 510:43ea59887c69
Start work on making C64 formats encoding possible by changing DMDecodeOps
to DMEncDecOps and adding fields and op enums for custom encode functions, renaming,
etc. Split generic op sanity checking into a separate function in
preparation for its use in generic encoding function.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Mon, 19 Nov 2012 15:06:01 +0200 |
parents | 7d611ebac3e5 |
children |
line wrap: on
line source
#include "dmlib.h" #include "dmargs.h" #include "dmvecmat.h" #include "dmtext.h" #include <math.h> #define DM_COLORS (256) char *optFontFile = "font.ttf"; BOOL optBenchmark = FALSE; int optVFlags = SDL_SWSURFACE | SDL_HWPALETTE; int optScrWidth = 640, optScrHeight = 480, optFontSize = 20, optScrDepth = 32; int optBenchmarkLen = 20; DMOptArg optList[] = { { 0, '?', "help", "Show this help", OPT_NONE }, { 2, 'v', "verbose", "Be more verbose", OPT_NONE }, { 3, 'f', "full", "Fullscreen", OPT_NONE }, { 4, 'h', "hw", "Use SDL hardware surface", OPT_NONE }, { 5, 's', "size", "Initial window size/resolution -s 640x480", OPT_ARGREQ }, { 6, 'd', "depth", "Color depth of mode/window in bits (8/32)", OPT_ARGREQ }, { 7, 'b', "bench", "Run in benchmark mode", OPT_NONE }, }; const int optListN = sizeof(optList) / sizeof(optList[0]); void argShowHelp() { 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 6: if (optArg) optScrDepth = atoi(optArg); break; case 5: { int w, h; if (sscanf(optArg, "%dx%d", &w, &h) == 2) { if (w < 320 || h < 200 || w > 3200 || h > 3200) { 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; case 7: optBenchmark = TRUE; break; default: dmError("Unknown option '%s'.\n", currArg); return FALSE; } return TRUE; } void DM_MakePalette(SDL_Surface *scr) { SDL_Color pal[DM_COLORS]; int n; for (n = 0; n < 256; n++) { pal[n].r = n; pal[n].g = n; pal[n].b = n; } SDL_SetColors(scr, pal, 0, DM_COLORS); } void DM_PrintRect(FILE *f, SDL_Rect *r) { fprintf(f, "SDL_Rect <%d, %d : %d, %d>\n", r->x, r->y, r->w, r->h); } BOOL DM_InitializeVideo(SDL_Surface **screen) { *screen = SDL_SetVideoMode(optScrWidth, optScrHeight, optScrDepth, optVFlags | SDL_RESIZABLE); if (*screen == NULL) { dmError("Can't SDL_SetVideoMode(): %s\n", SDL_GetError()); return FALSE; } #if 0 SDL_Rect r; r.x = -50; r.y = 50; r.w = 700; r.h = 300; DM_PrintRect(stderr, &r); SDL_SetClipRect(*screen, &r); DM_PrintRect(stderr, &r); DM_PrintRect(stderr, &((*screen)->clip_rect)); #endif return TRUE; } void DM_Random(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; } } #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; } } int main(int argc, char *argv[]) { SDL_Surface *screen = NULL, *bmap = NULL; TTF_Font *font = NULL; SDL_Color fontcol={255,155,155,0}; SDL_Event event; int mouseX, mouseY; BOOL initSDL = FALSE, initTTF = FALSE, exitFlag, showMap = FALSE; dmInitProg("blittest", "dmlib blittest", "0.2", NULL, NULL); if (!dmArgsProcess(argc, argv, optList, optListN, argHandleOpt, NULL, FALSE)) exit(1); if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) { dmError("Could not initialize SDL: %s\n", SDL_GetError()); goto error_exit; } initSDL = TRUE; if (TTF_Init() < 0) { dmError("Could not initialize FreeType/TTF: %s\n", SDL_GetError()); goto error_exit; } initTTF = TRUE; font = TTF_OpenFont(optFontFile, optFontSize); if (font == NULL) { dmError("Could not load TTF font '%s' (%d): %s\n", optFontFile, optFontSize, SDL_GetError()); goto error_exit; } TTF_SetFontStyle(font, TTF_STYLE_NORMAL); if (optBenchmark) { screen = SDL_CreateRGBSurface(SDL_SWSURFACE, optScrWidth, optScrHeight, optScrDepth, 0, 0, 0, 0); if (screen == NULL) { dmError("Could not create screen surface.\n"); goto error_exit; } dmMsg(0, "Benchmark mode, not opening window.\n"); } else { if (!DM_InitializeVideo(&screen)) goto error_exit; SDL_WM_SetCaption("Halleluja", "DMT"); } dmPerlinInit(); bmap = SDL_CreateRGBSurface(SDL_SWSURFACE, QWIDTH, QHEIGHT, 8, 0, 0, 0, 0); DM_MakePalette(bmap); DM_Random(bmap, 15); DMVector light; DMBlockMap heightMap; light.x = light.y = 128; light.z = 128; dmMakeBumpMap(heightMap, 0.06, 254); int numFrames = 0, startTime = SDL_GetTicks(), endTime = 0; exitFlag = FALSE; if (optBenchmark) dmMsg(0, "Starting benchmark, running for %d seconds.\n", optBenchmarkLen); while (!exitFlag) { dmMakeBumpMap(heightMap, 0.05 + sin(SDL_GetTicks() * 0.001) * 0.002 , 254); if (!optBenchmark) { while (SDL_PollEvent(&event)) switch (event.type) { case SDL_KEYDOWN: switch (event.key.keysym.sym) { case SDLK_ESCAPE: exitFlag = TRUE; break; case SDLK_F5: showMap = !showMap; break; default: break; } break; case SDL_VIDEORESIZE: optScrWidth = event.resize.w; optScrHeight = event.resize.h; if (!DM_InitializeVideo(&screen)) goto error_exit; break; case SDL_VIDEOEXPOSE: break; case SDL_QUIT: exit(0); } SDL_GetMouseState(&mouseX, &mouseY); light.x = ((DMFloat) mouseX * QWIDTH) / (DMFloat) optScrWidth; light.y = ((DMFloat) mouseY * QHEIGHT) / (DMFloat) optScrHeight; } if (!optBenchmark && SDL_MUSTLOCK(screen) != 0 && SDL_LockSurface(screen) != 0) { dmError("Can't lock surface.\n"); goto error_exit; } if (showMap) memcpy(bmap->pixels, heightMap, QWIDTH * QHEIGHT); else dmShadowTraceHeightMap(bmap->pixels, heightMap, &light); dmScaledBlitSurfaceAny(bmap, 0, 0, screen->w, screen->h, screen, DMD_NONE); if (!optBenchmark) { dmDrawTTFText(screen, font, fontcol, 0, 0, "%3.1f FPS", (float) (numFrames * 1000.0f) / (float) (endTime - startTime)); if (SDL_MUSTLOCK(screen) != 0) SDL_UnlockSurface(screen); SDL_Flip(screen); SDL_Delay(10); } endTime = SDL_GetTicks(); numFrames++; if (optBenchmark) { if (endTime - startTime > optBenchmarkLen * 1000) exitFlag = TRUE; } } // Print benchmark results dmMsg(0, "%d frames in %d ms, fps = %1.3f\n", numFrames, endTime - startTime, (float) (numFrames * 1000.0f) / (float) (endTime - startTime)); error_exit: dmMsg(0, "Shutting down dmlib.\n"); if (screen) SDL_FreeSurface(screen); if (font) TTF_CloseFont(font); if (initSDL) SDL_Quit(); if (initTTF) TTF_Quit(); return 0; }