Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /*
- Landscape rendering
- Ok.. i know that voxel is something else... but a lot of people is using
- the name "voxel" to mean this kind of rendering tecnique.
- I wrote this to explain the basic idea behind the rendering of newvox4;
- newvox4 is very badly written (it's named 4 because is the fourth of
- a sequel of experiments) and is coded in pascal + asm.
- Since i got a few request of an explanation i decided to write the kernel
- of the rendering in C hoping that this will be easier to understand.
- This implements only the base landscape (no sky or floating ball) and
- with keyboard only support but i think you can get the idea of how I
- implemented those other things.
- I'm releasing this code to the public domain for free... and as it's
- probably really obvious there's no warranty of any kind on it.
- You can do whatever you want with this source; however a credit in any
- program that uses part of this code would be really appreciated :)
- Any comment is welcome :)
- Andrea "6502" Griffini, programmer
- agriff@ix.netcom.com
- http://vv.val.net/~agriffini
- */
- #include <fdlibm.h>
- #include <SDL/SDL.h>
- #define TWOPI (2.0 * M_PI)
- typedef unsigned char byte;
- float altitude = 30.0f;
- const int view_dist = 200;
- int auto_height = 1;
- byte HMap[256*256]; /* Height field */
- byte CMap[256*256]; /* Color map */
- byte Video[320*240]; /* Off-screen buffer */
- /* I know this is not the way to efficiently do it, please don't kill me */
- #define lookup_size 32768
- double cos_table[lookup_size];
- double sin_table[lookup_size];
- const double luscale = lookup_size / TWOPI;
- /* Reduces a value to 0..255 (used in height field computation) */
- int Clamp(int x)
- {
- return (x<0 ? 0 : (x>255 ? 255 : x));
- }
- void calculate_tables(void) {
- int i;
- double angle = 0.0;
- for (i = 0; i < lookup_size; ++i) {
- sin_table[i] = sin(angle);
- cos_table[i] = cos(angle);
- angle += TWOPI / lookup_size;
- }
- }
- double get_sin(double rad) {
- rad = rad - TWOPI * floor(rad / TWOPI);
- return sin_table[(int)(rad * luscale)];
- }
- double get_cos(double rad) {
- rad = rad - TWOPI * floor(rad / TWOPI);
- return cos_table[(int)(rad * luscale)];
- }
- unsigned int lfsr113(void)
- {
- static unsigned int z1 = 12345, z2 = 12345, z3 = 12345, z4 = 12345;
- unsigned int b;
- b = ((z1 << 6) ^ z1) >> 13;
- z1 = ((z1 & 4294967294U) << 18) ^ b;
- b = ((z2 << 2) ^ z2) >> 27;
- z2 = ((z2 & 4294967288U) << 2) ^ b;
- b = ((z3 << 13) ^ z3) >> 21;
- z3 = ((z3 & 4294967280U) << 7) ^ b;
- b = ((z4 << 3) ^ z4) >> 12;
- z4 = ((z4 & 4294967168U) << 13) ^ b;
- return (z1 ^ z2 ^ z3 ^ z4);
- }
- /* Heightfield and colormap computation */
- void ComputeMap(void)
- {
- int p,i,j,k,k2,p2;
- /* Start from a plasma clouds fractal */
- HMap[0]=128;
- for ( p=256; p>1; p=p2 )
- {
- p2=p>>1;
- k=p*8+20; k2=k>>1;
- for ( i=0; i<256; i+=p )
- {
- for ( j=0; j<256; j+=p )
- {
- int a,b,c,d;
- a=HMap[(i<<8)+j];
- b=HMap[(((i+p)&255)<<8)+j];
- c=HMap[(i<<8)+((j+p)&255)];
- d=HMap[(((i+p)&255)<<8)+((j+p)&255)];
- HMap[(i<<8)+((j+p2)&255)]=
- Clamp(((a+c)>>1)+(lfsr113()%k-k2));
- HMap[(((i+p2)&255)<<8)+((j+p2)&255)]=
- Clamp(((a+b+c+d)>>2)+(lfsr113()%k-k2));
- HMap[(((i+p2)&255)<<8)+j]=
- Clamp(((a+b)>>1)+(lfsr113()%k-k2));
- }
- }
- }
- /* Smoothing */
- for ( k=0; k<3; k++ )
- for ( i=0; i<256*256; i+=256 )
- for ( j=0; j<256; j++ )
- {
- HMap[i+j]=(HMap[((i+256)&0xFF00)+j]+HMap[i+((j+1)&0xFF)]+
- HMap[((i-256)&0xFF00)+j]+HMap[i+((j-1)&0xFF)])>>2;
- }
- /* Color computation (derivative of the height field) */
- for ( i=0; i<256*256; i+=256 )
- for ( j=0; j<256; j++ )
- {
- k=128+(HMap[((i+256)&0xFF00)+((j+1)&255)]-HMap[i+j])*4;
- if ( k<0 ) k=0; if (k>255) k=255;
- CMap[i+j]=k;
- }
- }
- int lasty[320], /* Last pixel drawn on a given column */
- lastc[320]; /* Color of last pixel on a column */
- /*
- Draw a "section" of the landscape; x0,y0 and x1,y1 and the xy coordinates
- on the height field, hy is the viewpoint height, s is the scaling factor
- for the distance. x0,y0,x1,y1 are 16.16 fixed point numbers and the
- scaling factor is a 16.8 fixed point value.
- */
- void Line(int x0,int y0,int x1,int y1,int hy,int s)
- {
- int i,sx,sy;
- /* Compute xy speed */
- sx=(x1-x0)/320; sy=(y1-y0)/320;
- for ( i=0; i<320; i++ )
- {
- int c,y,h,u0,v0,u1,v1,a,b,h0,h1,h2,h3;
- /* Compute the xy coordinates; a and b will be the position inside the
- single map cell (0..255).
- */
- u0=(x0>>16)&0xFF; a=(x0>>8)&255;
- v0=((y0>>8)&0xFF00); b=(y0>>8)&255;
- u1=(u0+1)&0xFF;
- v1=(v0+256)&0xFF00;
- /* Fetch the height at the four corners of the square the point is in */
- h0=HMap[u0+v0]; h2=HMap[u0+v1];
- h1=HMap[u1+v0]; h3=HMap[u1+v1];
- /* Compute the height using bilinear interpolation */
- h0=(h0<<8)+a*(h1-h0);
- h2=(h2<<8)+a*(h3-h2);
- h=((h0<<8)+b*(h2-h0))>>16;
- /* Fetch the color at the four corners of the square the point is in */
- h0=CMap[u0+v0]; h2=CMap[u0+v1];
- h1=CMap[u1+v0]; h3=CMap[u1+v1];
- /* Compute the color using bilinear interpolation (in 16.16) */
- h0=(h0<<8)+a*(h1-h0);
- h2=(h2<<8)+a*(h3-h2);
- c=((h0<<8)+b*(h2-h0));
- /* Compute screen height using the scaling factor */
- y=(((h-hy)*s)>>11)+100;
- /* Draw the column */
- if ( y<(a=lasty[i]) )
- {
- unsigned char *b=Video+a*320+i;
- int sc,cc;
- if ( lastc[i]==-1 )
- lastc[i]=c;
- sc=(c-lastc[i])/(a-y);
- cc=lastc[i];
- if ( a>239 ) { b-=(a-239)*320; cc+=(a-239)*sc; a=239; }
- if ( y<0 ) y=0;
- while ( y<=a )
- {
- *b=cc>>18; cc+=sc;
- b-=320; a--;
- }
- lasty[i]=y;
- }
- lastc[i]=c;
- /* Advance to next xy position */
- x0+=sx; y0+=sy;
- }
- }
- float FOV=3.141592654/4; /* half of the xy field of view */
- /*
- // Draw the view from the point x0,y0 (16.16) looking at angle a
- */
- void View(int x0,int y0,float aa,SDL_Surface *screen)
- {
- int d;
- int a,b,h,u0,v0,u1,v1,h0,h1,h2,h3;
- /* Clear offscreen buffer */
- memset(Video,0,320*240);
- /* Initialize last-y and last-color arrays */
- for ( d=0; d<320; d++ )
- {
- lasty[d]=240;
- lastc[d]=-1;
- }
- /* Compute viewpoint height value */
- /* Compute the xy coordinates; a and b will be the position inside the
- single map cell (0..255).
- */
- u0=(x0>>16)&0xFF; a=(x0>>8)&255;
- v0=((y0>>8)&0xFF00); //b=(y0>>8)&255;
- u1=(u0+1)&0xFF;
- v1=(v0+256)&0xFF00;
- /* Fetch the height at the four corners of the square the point is in */
- h0=HMap[u0+v0]; h2=HMap[u0+v1];
- h1=HMap[u1+v0]; h3=HMap[u1+v1];
- /* Compute the height using bilinear interpolation */
- h0=(h0<<8)+a*(h1-h0);
- h2=(h2<<8)+a*(h3-h2);
- h=((h0<<8)+b*(h2-h0))>>16;
- /* Draw the landscape from near to far without overdraw */
- for ( d=0; d<view_dist; d+=1+(d>>6) )
- {
- Line(x0+d*65536*get_cos(aa-FOV),y0+d*65536*get_sin(aa-FOV),
- x0+d*65536*get_cos(aa+FOV),y0+d*65536*get_sin(aa+FOV),
- auto_height?h-20:altitude,256*256/(d+1));
- }
- /* Blit the final image to the screen */
- if ( SDL_LockSurface(screen) == 0 ) {
- int row;
- Uint8 *src, *dst;
- src = Video;
- dst = (Uint8 *)screen->pixels;
- for ( row=screen->h; row>0; --row )
- {
- memcpy(dst, src, 320);
- src += 320;
- dst += screen->pitch;
- }
- SDL_UnlockSurface(screen);
- }
- SDL_UpdateRect(screen, 0, 0, 0, 0);
- }
- int main(int argc, char *argv[])
- {
- SDL_Surface *screen;
- int done;
- int i,k;
- float ss,sa,a,s,salt;
- int x0,y0;
- SDL_Color colors[64];
- SDL_Event event;
- Uint8 *keystate;
- /* Initialize SDL */
- if ( SDL_Init(SDL_INIT_VIDEO) < 0 )
- {
- fprintf(stderr, "Couldn't initialize SDL: %s\n", SDL_GetError());
- exit(1);
- }
- /* Enter 320x240x256 mode */
- screen = SDL_SetVideoMode(320, 240, 8,
- SDL_SWSURFACE);
- if ( screen == NULL )
- {
- fprintf(stderr, "Couldn't init video mode: %s\n", SDL_GetError());
- exit(1);
- }
- /* Set up the first 64 colors to a grayscale */
- for ( i=0; i<64; i++ )
- {
- colors[i].r = i*4;//screen->format->palette->colors[i].r*4;
- colors[i].g = i*3;//screen->format->palette->colors[i].g*4;
- colors[i].b = i*3;//screen->format->palette->colors[i].b*4;
- }
- SDL_SetColors(screen, colors, 0, 64);
- /* Compute the height map */
- calculate_tables();
- ComputeMap();
- /* Main loop
- a = angle
- x0,y0 = current position
- s = speed constant
- ss = current forward/backward speed
- sa = angular speed
- */
- done=0;
- a=0; k=x0=y0=0;
- s=256; /*s=4096;*/
- ss=0; sa=0; salt=0;
- while(!done)
- {
- /* Draw the frame */
- View(x0,y0,a,screen);
- /* Update position/angle */
- x0+=ss*get_cos(a); y0+=ss*get_sin(a);
- a+=sa;
- altitude+=salt;
- /* Slowly reset the angle to 0 */
- if ( sa != 0 )
- {
- if ( sa < 0 )
- sa += 0.001;
- else
- sa -= 0.001;
- }
- if ( salt != 0 )
- {
- if ( salt < 0 )
- salt += 0.05;
- else
- salt -= 0.05;
- }
- /* User input */
- while ( SDL_PollEvent(&event) )
- {
- if ( event.type == SDL_QUIT )
- {
- done = 1;
- }
- }
- keystate = SDL_GetKeyState(NULL);
- if ( keystate[SDLK_ESCAPE] ) {
- done = 1;
- }
- if ( keystate[SDLK_UP] ) {
- ss+=s;
- }
- if ( keystate[SDLK_DOWN] ) {
- ss-=s;
- }
- if ( keystate[SDLK_RIGHT] ) {
- sa+=0.003;
- }
- if ( keystate[SDLK_LEFT] ) {
- sa-=0.003;
- }
- if ( keystate[SDLK_MINUS] ) {
- salt+=0.2;
- }
- if ( keystate[SDLK_PLUS] ) {
- salt-=0.2;
- }
- if ( keystate[SDLK_5] ) {
- auto_height = !auto_height;
- }
- }
- /* Exit to text mode */
- SDL_Quit();
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement