Mercurial > hg > dmlib
view tests/blittest.c @ 2555:6249aa494e83
Rename "ROM/WT" blocks to just "WT", move the description to --help.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sun, 27 Feb 2022 16:38:35 +0200 |
parents | b7cd5dd0b82e |
children | 9807ae37ad69 |
line wrap: on
line source
#include "dmlib.h" #include "dmargs.h" #include "dmvecmat.h" #include "dmtext.h" #include "dmperlin.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; DMPerlinContext perlinCtx; static const 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, 0, 80 - 2); } 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) { dmErrorMsg("Invalid width or height: %d x %d\n", w, h); return FALSE; } optScrWidth = w; optScrHeight = h; } else { dmErrorMsg("Invalid size argument '%s'.\n", optArg); return FALSE; } } break; case 7: optBenchmark = TRUE; break; default: dmErrorMsg("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) { dmErrorMsg("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(&perlinCtx, 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, OPTH_BAILOUT)) exit(1); if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) != 0) { dmErrorMsg("Could not initialize SDL: %s\n", SDL_GetError()); goto error_exit; } initSDL = TRUE; if (TTF_Init() < 0) { dmErrorMsg("Could not initialize FreeType/TTF: %s\n", SDL_GetError()); goto error_exit; } initTTF = TRUE; font = TTF_OpenFont(optFontFile, optFontSize); if (font == NULL) { dmErrorMsg("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) { dmErrorMsg("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(&perlinCtx, 1234); 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) { dmErrorMsg("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; }