📄 land.c
字号:
/*--------------------------------------------------* Ray-Casting Heightfield Engine Pre-SVGAlib code by Alex Chalfin Usage: Use the mouse to move l, r, u, & d. '+' and '-' control your forward speed. *--------------------------------------------------*/#include <stdio.h>#include <stdlib.h>#include <string.h>#include <malloc.h>#include <math.h>#include <time.h>#include <unistd.h>#include <vga.h>#include <vgagl.h>#include <vgamouse.h>/*------------------------------------------------------------------------* Floating point related macros *------------------------------------------------------------------------*/#define FLT2INT(a) ((int)(a)) /* float to integer conversion */#define FLT2FXD(a) (FLT2INT((a)*65536)) /* float to 16.16 fixed point *//*------------------------------------------------------------------------* Map size and indexing related macros *------------------------------------------------------------------------*/#define MAPSHIFT 8 /* log2(map_dimention) */#define MAPSIZE (1 << MAPSHIFT) /* size of one side of the map */#define BYTE(a) (a & (MAPSIZE-1)) /* map wrapping macro */#define INDEX(x,y) ((BYTE(y)<<MAPSHIFT)+BYTE(x)) /* std index calculation */#define fpINDEX(x,y) (INDEX(x>>16, y>>16)) /* fixed point 16.16 index calc */#define iINDEX(x,y) (INDEX(FLT2INT(x), FLT2INT(y))) /* flt index calc *//*------------------------------------------------------------------------* A nice random macro (ranged) *------------------------------------------------------------------------*/#define RANDOM(range) (rand() % (range))#define DEG2RAD(ang) ((ang)*2*3.141592/360)/*------------------------------------------------------------------------* Rendering related constants *------------------------------------------------------------------------*/#define FARDEPTH 100 /* how far into horizon to render */#define HEIGHTMUL 48 /* perspective multiplication factor */#define FIELD_OF_VIEW 90 /* 90 degree field of view */#define RENDERWIDTH 320 /* width of the screen to render to */#define RENDERHEIGHT 200 /* height of the screen to render to *//*------------------------------------------------------------------------* Bi-linear filter blend *------------------------------------------------------------------------*/#define BLEND(map,u,v,value) { \ c0 = (int)(map)[fpINDEX(u, v)]; \ c1 = (int)(map)[fpINDEX((u+65536), v)]; \ c2 = (int)(map)[fpINDEX(u, (v+65536))]; \ c3 = (int)(map)[fpINDEX((u+65536),(v+65536))]; \ c11 = (c0 << 8) + (((u & 0xffff) >> 8) * (c1 - c0)); \ c22 = (c2 << 8) + (((u & 0xffff) >> 8) * (c3 - c2)); \ (value) = (c11 << 8) + (((v & 0xffff) >> 8) * (c22 - c11)); \}/*------------------------------------------------------------------------* Types used in rendering process *------------------------------------------------------------------------*/typedef struct tview { float cx, cy; float angle; int z;} tview;/*------------------------------------------------------------------------* Global Variables *------------------------------------------------------------------------*/char heightmap[MAPSIZE * MAPSIZE]; // height field for the voxelschar colormap [MAPSIZE * MAPSIZE]; // colors for the voxelschar vpage [RENDERWIDTH * RENDERHEIGHT]; // a virtual screen page/*------------------------------------------------------------------------* Function Headers *------------------------------------------------------------------------*/void CreateMaps();void CreateFractalMap(int x1, int y1, int x2, int y2);void NewColor(int xa, int ya, int x, int y, int xb, int yb);void SmoothMap();void MakeColorMap();void DrawScreen(tview *v);void MakePalette();void SetRGB(char n, char r, char g, char b);void SetRenderView(float speed, float moveangle, tview *v);short int InitMouse();void ReadMouseCoords(short int *x, short int *y);void CastRay(float x1, float y1, float x2, float y2, int viewer, int scr_x);/*------------------------------------------------------------------------* Da main funk! *------------------------------------------------------------------------*/int main(void){ tview mainview; int x, y, key, quit = 0, height = -1; float angle = 0, speed = 0; printf("Use the '+' and '-' keys to change speed\n"); printf("and the mouse to fly around.\n"); getchar(); CreateMaps(); vga_init(); vga_setmousesupport(1); vga_setmode(G320x200x256); gl_setcontextvga(G320x200x256); MakePalette(); while (!quit) { mouse_update(); x = mouse_getx(); y = mouse_gety(); angle += (float)(x - (RENDERWIDTH / 2)) / 1024.0f; height += ((RENDERHEIGHT / 2) - (int)(y))*16; if (height > 1000*256) height = 1000*256; if (height < ((int)heightmap[iINDEX(mainview.cx, mainview.cy)] << 8)) height = ((int)heightmap[iINDEX(mainview.cx, mainview.cy)]) << 8; mainview.z = height; if ((key = vga_getkey()) > 0) { switch (key) { case '+' : speed += 1.0 / 4.0; if (speed > 16) speed = 16; break; case '-' : speed -= 1.0 / 4.0; if (speed < 0) speed = 0; break; case 27 : if ((key = vga_getkey()) == 0) quit = 1; break; } } SetRenderView(speed, angle, &mainview); DrawScreen(&mainview); vga_waitretrace(); gl_putbox(0, 0, RENDERWIDTH, RENDERHEIGHT, vpage); memset(vpage, 0, RENDERWIDTH * RENDERHEIGHT); } vga_setmode(TEXT); return 0;}/*------------------------------------------------------------------------* SetRenderView - assigns view values based on speed and angle of movement *------------------------------------------------------------------------*/void SetRenderView(float speed, float moveangle, tview *v){ v->cx += speed * cos(moveangle); v->cy += speed * sin(moveangle); v->angle = moveangle;}/*------------------------------------------------------------------------* DrawScreen - given a view structure, render the screen to the virtual buf *------------------------------------------------------------------------*/void DrawScreen(tview *v){ int i_x; float angle; float target_x, target_y; for (i_x = 0; i_x < RENDERWIDTH; i_x++) { angle = FIELD_OF_VIEW * ((float)i_x / (float)(RENDERWIDTH - 1)) - (FIELD_OF_VIEW / 2); target_x = v->cx + FARDEPTH * cos(v->angle + DEG2RAD(angle)); target_y = v->cy + FARDEPTH * sin(v->angle + DEG2RAD(angle)); CastRay(v->cx, v->cy, target_x, target_y, (v->z+(20<<8))<<8, i_x); }}/*------------------------------------------------------------------------* CastRay - casts a ray into the landscape and draws the height sliver *------------------------------------------------------------------------*/void CastRay(float x1, float y1, float x2, float y2, int viewer, int scr_x){ int c0,c1,c2,c3,c11,c22; /* vars for bi-linear interpolation */ int fxd_x, fxd_dx; int fxd_y, fxd_dy; int miny; int depth; int per; int start_h, start_c; int end_h, end_c; int scr_y1, scr_y2; int i_c, i_dc; int i_y; /* store the traversing vars in 16.16 fixed point */ fxd_x = FLT2FXD(x1); fxd_y = FLT2FXD(y1); fxd_dx = FLT2FXD((x2 - x1) / FARDEPTH); fxd_dy = FLT2FXD((y2 - y1) / FARDEPTH); miny = RENDERHEIGHT; /* create the starting height and color */ start_h = 199; BLEND(colormap, fxd_x, fxd_y, start_c); for (depth = 1; depth < FARDEPTH; depth++) { per = (HEIGHTMUL << 16) / depth; /* calculate the color and height in map space */ BLEND(heightmap, fxd_x, fxd_y, end_h); BLEND(colormap, fxd_x, fxd_y, end_c); /* convert the height to screen space */ end_h = (RENDERHEIGHT / 2) - (long)(((long long)(end_h - viewer) * per) >> 32); /* only draw if the new height is less than the old height */ if (end_h < start_h) { /* only draw if the new height is less than the minimum reached height */ if (end_h < miny) { scr_y1 = end_h; scr_y2 = miny - 1; i_c = end_c; i_dc = (start_c - end_c) / (start_h - end_h); miny = end_h; /* reset the min y value to the new highest value */ if (scr_y1 < 0) /* perform some clipping so we don't go off the top of the screen */ { i_c += i_dc * (-scr_y1); scr_y1 = 0; } scr_y1 = ( (int)(vpage) + scr_y1 * RENDERWIDTH + scr_x); scr_y2 = ( (int)(vpage) + scr_y2 * RENDERWIDTH + scr_x); for (i_y = scr_y1; i_y <= scr_y2; i_y += RENDERWIDTH, i_c += i_dc) *(char *)(i_y) = i_c >> 16; } } fxd_x += fxd_dx; fxd_y += fxd_dy; start_h = end_h; start_c = end_c; }}/*------------------------------------------------------------------------* MakePalette - Makes a sandy dark red to red palette *------------------------------------------------------------------------*/void MakePalette(){ int i; for (i = 1; i < 64; i++) { gl_setpalettecolor(i, 16 + (i/4), i/8, 0); } for (i = 64; i < 128; i++) { gl_setpalettecolor(i, 32 + ((i-64)/2), i/8, 0); } /* gl_setpalettecolor(255, 63, 63, 63); */}/*------------------------------------------------------------------------* CreateMaps - calculates heightmap and color map. Allocates draw buffers *------------------------------------------------------------------------*/void CreateMaps(){ int i; srand(getpid()); /* initialize some of the memory */ memset(heightmap, 0, MAPSIZE*MAPSIZE); memset(vpage, 0, RENDERWIDTH * RENDERHEIGHT); printf("Creating %dx%d fractal terrain\n", MAPSIZE, MAPSIZE); heightmap[0] = (rand() % 128) + 64; // initialize starting point on map CreateFractalMap(0, 0, MAPSIZE, MAPSIZE); printf("Smoothing terrain\n"); for (i = 0; i < 5; i++) SmoothMap(); MakeColorMap();}/*------------------------------------------------------------------------* CreateFractalMap - builds a fractal landscape *------------------------------------------------------------------------*/void CreateFractalMap(int x1, int y1, int x2, int y2){ int x, y, c; if (((x2-x1) < 2) && ((y2-y1) < 2)) return; x = (x1 + x2) >> 1; y = (y1 + y2) >> 1; NewColor(x1, y1, x, y1, x2, y1); NewColor(x2, y1, x2, y, x2, y2); NewColor(x1, y2, x, y2, x2, y2); NewColor(x1, y1, x1, y, x1, y2); c = (heightmap[INDEX(x1,y1)] + heightmap[INDEX(x1,y2)] + heightmap[INDEX(x2,y1)] + heightmap[INDEX(x2,y2)]) >> 2; if (heightmap[INDEX(x, y)] == 0) heightmap[INDEX(x, y)] = c; CreateFractalMap(x1, y1, x, y); CreateFractalMap(x, y1, x2, y); CreateFractalMap(x, y, x2, y2); CreateFractalMap(x1, y, x, y2);}/*------------------------------------------------------------------------* NewColor - new color evaluation (fractal landscape function) *------------------------------------------------------------------------*/void NewColor(int xa, int ya, int x, int y, int xb, int yb){ int color; color = abs(xa - xb) + abs(ya - yb); color = RANDOM(color << 1) - color; color = color + ((heightmap[INDEX(xa, ya)] + heightmap[INDEX(xb, yb)] + 1) >> 1); if (color < 1) color = 1; if (color > 255) color = 255; if (heightmap[INDEX(x, y)] == 0) heightmap[INDEX(x, y)] = color;}/*------------------------------------------------------------------------* SmoothMap - smooth the landscape via 3x3 box filter *------------------------------------------------------------------------*/void SmoothMap(){ int x,y; for (x = 0; x < MAPSIZE; x++) for (y = 0; y < MAPSIZE; y++) heightmap[INDEX(x,y)] = (heightmap[INDEX((x-1),(y-1))] + heightmap[INDEX((x-1),(y+1))] + heightmap[INDEX((x+1),(y-1))] + heightmap[INDEX((x+1),(y+1))] + heightmap[INDEX(x, (y-1))] + heightmap[INDEX(x, (y+1))] + heightmap[INDEX((x-1), y )] + heightmap[INDEX( x, y )] + heightmap[INDEX((x+1), y )]) / 9;}/*------------------------------------------------------------------------* MakeColorMap - tries to build a creative color map for the landscape *------------------------------------------------------------------------*/void MakeColorMap(){ int x,y,temp; for (x = 0; x < MAPSIZE; x++) for (y = 0; y < MAPSIZE; y++) { temp = heightmap[INDEX(x,y)] >> 1; if (heightmap[INDEX((x-1),y)] < heightmap[INDEX(x,y)]) { temp -= 8*(heightmap[INDEX(x,y)] - heightmap[INDEX((x-1),y)]); if (temp < 2) temp = 2; } else { if (heightmap[INDEX((x-1),y)] > heightmap[INDEX(x,y)]) { temp += 3*(heightmap[INDEX((x-1),y)] - heightmap[INDEX(x,y)]); if (temp > 127) temp = 127; } } colormap[INDEX(x,y)] = temp; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -