Advertisement
Guest User

Landscape renderer

a guest
Mar 29th, 2013
102
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 10.38 KB | None | 0 0
  1. #include <stdlib.h>
  2. #include <math.h>
  3. #include <stdio.h>
  4. #include <time.h>
  5. #include <sys/time.h>
  6. #include <sys/types.h>
  7. #include <sys/resource.h>
  8. #include <SDL.h>
  9. #include <SDL_ttf.h>
  10.  
  11. unsigned int scw = 800;
  12. unsigned int sch = 600;
  13.  
  14. unsigned long mapw = 4096;
  15. unsigned long maph = 4096;
  16.  
  17. unsigned int mapw_pow = 12;
  18.  
  19. unsigned long bin1;
  20. unsigned long bin2;
  21.  
  22. long dd;
  23. float *a;
  24. long *dx, *dy;
  25.  
  26. char* my_itoa(unsigned int val)
  27. {
  28.     static char buf[11];
  29.     short i=10;
  30.     for(;val&&i;--i,val/=10)buf[i]="0123456789"[val%10];
  31.     return &buf[i+1];
  32. }
  33.  
  34. double mygettime()
  35. {
  36.   struct timeval tv;
  37.   if(gettimeofday(&tv, 0) < 0)
  38.   {
  39.     perror("oops");
  40.   }
  41.   return (double)tv.tv_sec + (0.000001 * (double)tv.tv_usec);
  42. }
  43.  
  44. inline void fillarray_long (long *a, long val, long num)
  45. {
  46.     int i;
  47.     for (i=0; i<num; i++) a[i] = val;
  48. }
  49.  
  50. inline void fillarray_float (float *a, float val, int num)
  51. {
  52.     int i;
  53.     for (i=0; i<num; i++) a[i] = val;
  54. }
  55.  
  56. void print_time (struct timeval time)
  57. {
  58.     printf ("%ld s, %ld us ", time.tv_sec, time.tv_usec);
  59. }
  60.  
  61. void print_statistics ()
  62. {
  63.     struct rusage rusage;
  64.     getrusage (RUSAGE_SELF, &rusage);
  65.  
  66.     printf ("Demo was working ");
  67.     print_time (rusage.ru_utime);
  68.     printf ("of user time; ");
  69.     print_time (rusage.ru_stime);
  70.     printf ("of system time;\n");
  71.     printf ("With %ld page faults and %ld page reclaims\n",
  72.             rusage.ru_majflt, rusage.ru_minflt);
  73. }
  74.  
  75. void calc_ray_deltas (float ang)
  76. {
  77.     unsigned int sx;
  78.  
  79.     float cosang = cos(ang);
  80.     float sinang = sin(ang);
  81.    
  82.     for (sx=0; sx<scw; sx++)
  83.     {
  84.         dx[sx] = dd*(cosang - a[sx]*sinang);
  85.         dy[sx] = dd*(cosang*a[sx] + sinang);
  86.     }
  87. }
  88.  
  89. void checkevents(float *ang, long *x, long *y, long *dz, long sdz)
  90. {
  91.     SDL_Event event;
  92.     if (SDL_PollEvent(&event))
  93.     {
  94.         switch (event.type) {
  95.         case SDL_QUIT:
  96.             print_statistics();
  97.             free (a); free (dx); free (dy);
  98.             SDL_Quit();
  99.             exit(0);
  100.         }
  101.     }
  102.     Uint8 *keystate = SDL_GetKeyState (NULL);
  103.  
  104.     if ((keystate[SDLK_LEFT]) || (keystate[SDLK_RIGHT]))
  105.     {
  106.         if (keystate[SDLK_LEFT]) *ang -= 0.02;
  107.         else if (keystate[SDLK_RIGHT]) *ang += 0.02;
  108.  
  109.         calc_ray_deltas (*ang);
  110.     }
  111.    
  112.     if (keystate[SDLK_UP]) *dz -= sdz;
  113.     else if (keystate[SDLK_DOWN]) *dz += sdz;
  114.  
  115.     if (keystate[SDLK_a] || keystate[SDLK_d] || keystate[SDLK_w] || keystate[SDLK_s])
  116.     {
  117.         long xd, yd;
  118.         xd = 0;
  119.         yd = 0;
  120.         if (keystate[SDLK_a]) yd = -3<<16;
  121.         else if (keystate[SDLK_d]) yd = 3<<16;
  122.         if (keystate[SDLK_w]) xd = 3<<16;
  123.         else if (keystate[SDLK_s]) xd = -3<<16;
  124.        
  125.         *x += xd*cos(*ang) - yd*sin(*ang);
  126.         *y += yd*cos(*ang) + xd*sin(*ang);
  127.     }
  128. }
  129.  
  130. void blacken_screen (SDL_Surface *screen)
  131. {
  132.     SDL_Rect rect;
  133.     rect.x = 0;
  134.     rect.y = 0;
  135.     rect.w = scw;
  136.     rect.h = sch;
  137.  
  138.     SDL_FillRect (screen, &rect, 0);
  139. }
  140.  
  141. inline int get_idx (long x, long y)
  142. {
  143.     return (((x<<mapw_pow)&bin1) + (y&bin2))>>16;
  144. }
  145.  
  146. inline Uint32 tex_bilinear_filter (SDL_PixelFormat *fmt, Uint32 *tex, long x, long y)
  147. {
  148.     Uint32 colxy = tex[get_idx(x, y)];
  149.     Uint8 rxy, gxy, bxy;
  150.     SDL_GetRGB (colxy, fmt, &rxy, &gxy, &bxy);
  151.  
  152.     Uint32 colx_y = tex[get_idx(x+65536, y)];
  153.     Uint8 rx_y, gx_y, bx_y;
  154.     SDL_GetRGB (colx_y, fmt, &rx_y, &gx_y, &bx_y);
  155.    
  156.     Uint32 colxy_ = tex[get_idx(x, y+65536)];
  157.     Uint8 rxy_, gxy_, bxy_;
  158.     SDL_GetRGB (colxy_, fmt, &rxy_, &gxy_, &bxy_);
  159.  
  160.     Uint32 colx_y_ = tex[get_idx(x+65536, y+65536)];
  161.     Uint8 rx_y_, gx_y_, bx_y_;
  162.     SDL_GetRGB (colx_y_, fmt, &rx_y_, &gx_y_, &bx_y_);
  163.  
  164.     Uint32 r, g, b;
  165.  
  166.     // Integer variant
  167.     long delta = 1<<16;
  168.     long mask = delta - 1;
  169.  
  170.     long diffx = x&mask;
  171.     long diffy = y&mask;
  172.  
  173.     long oppx = delta - diffx;
  174.     long oppy = delta - diffy;
  175.  
  176.     r =  ((rxy*oppx + rx_y*diffx)*oppy)>>32;
  177.     r += ((rxy_*oppx + rx_y_*diffx)*diffy)>>32;
  178.  
  179.     g =  ((gxy*oppx + gx_y*diffx)*oppy)>>32;
  180.     g += ((gxy_*oppx + gx_y_*diffx)*diffy)>>32;
  181.  
  182.     b =  ((bxy*oppx + bx_y*diffx)*oppy)>>32;
  183.     b += ((bxy_*oppx + bx_y_*diffx)*diffy)>>32;
  184.  
  185. #if 0
  186.     float diffx = (float)(x&mask)/65536.0;
  187.     float diffy = (float)(y&mask)/65536.0;
  188.  
  189.     float oppx = 1 - diffx;
  190.     float oppy = 1 - diffy;
  191.  
  192.     r =  (rxy*oppx + rx_y*diffx)*oppx + (rxy_*oppx + rx_y_*diffx)*diffy;
  193.     g =  (gxy*oppx + gx_y*diffx)*oppy + (gxy_*oppx + gx_y_*diffx)*diffy;
  194.     b =  (bxy*oppx + bx_y*diffx)*oppy + (bxy_*oppx + bx_y_*diffx)*diffy;
  195. #endif
  196.  
  197.     return SDL_MapRGB (fmt, r, g, b);
  198. }
  199.  
  200. inline long hm_bilinear_filter (Uint8 *map, long x, long y)
  201. {
  202.     // Integer variant
  203.     long delta = 1<<16;
  204.     long mask = delta - 1;
  205.    
  206.     long diffx = x&mask;
  207.     long diffy = y&mask;
  208.  
  209.     long oppx = delta - diffx;
  210.     long oppy = delta - diffy;
  211.  
  212.     long res =  ((map[get_idx(x, y)]*oppx + map[get_idx(x+delta, y)]*diffx)*oppy)>>16;
  213.     res += ((map[get_idx(x, y+delta)]*oppx + map[get_idx(x+delta, y+delta)]*diffx)*diffy)>>16;
  214.     return res;
  215.  
  216.     // Floating point variant
  217.     #if 0
  218.     long delta = 1<<16;
  219.     long mask = delta - 1;
  220.    
  221.     float diffx = (float)(x&mask)/65536.0;
  222.     float diffy = (float)(y&mask)/65536.0;
  223.  
  224.     float oppx = 1 - diffx;
  225.     float oppy = 1 - diffy;
  226.  
  227.     float res =  (map[get_idx(x, y)]*oppx + map[get_idx(x+delta, y)]*diffx)*oppy;
  228.     res += (map[get_idx(x, y+delta)]*oppx + map[get_idx(x+delta, y+delta)]*diffx)*diffy;
  229.  
  230.     return (long)(res*65536);
  231.     #endif
  232. }
  233.  
  234. int main (int argc, char *argv[])
  235. {
  236.     if (argc != 4)
  237.     {
  238.         printf ("Usage: ./test heightmap.bmp texture.bmp scale_factor\n");
  239.         printf ("Textures must be 4096x4096\n");
  240.         exit(0);
  241.     }
  242.    
  243.     if ( SDL_Init(SDL_INIT_VIDEO) < 0 )
  244.     {
  245.         fprintf(stderr, "Cannot initialize SDL: %s\n", SDL_GetError());
  246.         exit(1);
  247.     }
  248.  
  249.     if (TTF_Init()==-1)
  250.     {
  251.         printf ("Error Init TTF\n");
  252.         exit(1);
  253.     }
  254.    
  255.     TTF_Font *font = TTF_OpenFont ("tahoma.ttf", 24);
  256.     SDL_Color fontcolor;
  257.     fontcolor.r = 255;
  258.     fontcolor.g = 255;
  259.     fontcolor.b = 255;
  260.  
  261.     SDL_Rect dest;
  262.     dest.x = 20;
  263.     dest.y = 20;
  264.     SDL_Surface *textrend = TTF_RenderText_Solid (font, "FPS: ", fontcolor);
  265.    
  266.     SDL_Surface *screen;
  267.     screen = SDL_SetVideoMode(scw, sch, 32, SDL_HWSURFACE | SDL_DOUBLEBUF);
  268.     if ( screen == NULL )
  269.     {// Если установить разрешение не удалось
  270.         fprintf(stderr, "Cannot set resolution %ix%i: %s\n", scw, sch, SDL_GetError());
  271.         exit(1);
  272.     }
  273.  
  274.     SDL_Surface *hm = SDL_LoadBMP (argv[1]);
  275.     if (!hm)
  276.     {
  277.         printf ("Error loading heightmap\n");
  278.         return -1;
  279.     }
  280.     Uint8 *hei = hm->pixels;
  281.  
  282.     SDL_Surface *text = SDL_LoadBMP (argv[2]);
  283.     if (!text)
  284.     {
  285.         printf ("Error loading texture\n");
  286.         exit(1);
  287.     }
  288.     Uint32 *col = text->pixels;
  289.  
  290.     long posx = 0;
  291.     long posy = 0;
  292.     long posz;
  293.  
  294.     float ang = 0;
  295.  
  296.     dd = 2<<16;
  297.     long de = dd * 228; // 228 is the max "distance"
  298.  
  299.     long startdz = 3<<16;
  300.     long sdz = 30<<16;
  301.     int sx;
  302.  
  303.     bin1 = (mapw*(maph-1))<<16;
  304.     bin2 = (maph-1)<<16;
  305.  
  306.     double time1 = mygettime();
  307.     double time2;
  308.     unsigned int frames = 0;
  309.  
  310.     unsigned int again;
  311.     long d[scw];
  312.     long h[scw];
  313.     Uint32 color[scw];
  314.  
  315.     a = malloc (sizeof (float)*scw);
  316.     float amax = 3.1415/2.9;
  317.     float da = 2*amax/scw;
  318.  
  319.     a[0] = -amax;
  320.     for (sx=1; sx<scw; sx++) a[sx] = a[sx-1]+da;
  321.  
  322.     dx = malloc (sizeof (long)*scw);
  323.     dy = malloc (sizeof (long)*scw);
  324.  
  325.     long x[scw];
  326.     long y[scw];
  327.     long z[scw];
  328.  
  329.     long dz[scw];
  330.  
  331.     int scale;
  332.     sscanf (argv[3], "%i", &scale);
  333.  
  334.     calc_ray_deltas (ang);
  335.  
  336.     long zbuf[scw*sch];
  337.     while (1)
  338.     {
  339.         SDL_LockSurface(screen);
  340.         blacken_screen (screen);
  341.  
  342.         int standing_at_idx = get_idx (posx, posy);
  343.         posz = (400<<16) + (hei[standing_at_idx]<<(16+scale));
  344.        
  345.         fillarray_long (h, posz, scw);
  346.         fillarray_long (d, 0, scw);
  347.  
  348.         fillarray_long (x, posx, scw);
  349.         fillarray_long (y, posy, scw);
  350.         fillarray_long (z, posz, scw);
  351.  
  352.         fillarray_long (dz, sdz, scw);
  353.         int p = scw*sch-1;
  354.         do
  355.         {
  356.             again = 0;
  357.             for (sx=scw-1; sx>=0; sx--)
  358.             {
  359.                 int newdata = 0;
  360.                 while (h[sx] <= z[sx])
  361.                 {
  362.                     long curd;
  363.                     curd = d[sx];
  364.                     if (curd>=de)
  365.                     {
  366.                         again++;
  367.                         zbuf[p] = de;
  368.                         goto label2;
  369.                     }
  370.  
  371.                     x[sx] += dx[sx];
  372.                     y[sx] += dy[sx];
  373.                     z[sx] -= dz[sx];
  374.  
  375. #ifdef HEIGHTMAP_BILINEAR
  376.                     h[sx] = hm_bilinear_filter (hei, x[sx], y[sx])<<scale;
  377. #else
  378.                     h[sx] = hei[get_idx(x[sx], y[sx])]<<(16+scale);
  379. #endif
  380.                     d[sx] += dd;
  381.                     newdata = 1;
  382.                 }
  383.                
  384.                 if (newdata)
  385.                 {
  386.                     newdata = 0;
  387. #ifdef TEX_BILINEAR
  388.                     color[sx] = tex_bilinear_filter (screen->format, col, x[sx], y[sx]);
  389. #else
  390.                     color[sx] = col[get_idx(x[sx], y[sx])];
  391. #endif
  392.                 }
  393.  
  394.                 if (p < 0) goto label1;
  395.                
  396.                 zbuf[p] = d[sx];
  397.                 *((Uint32*)screen->pixels+p) = color[sx];
  398.                 dz[sx] -= dd>>4;
  399.                 z[sx] += d[sx]>>4; // >>4 is internal scale factor
  400.             label2: p--;
  401.             }
  402.         }
  403.         while (again<scw);
  404.     label1: ;
  405.         SDL_UnlockSurface(screen);
  406.         SDL_BlitSurface (textrend, NULL, screen, &dest);
  407.         SDL_Flip (screen);
  408.         checkevents (&ang, &posx, &posy, &sdz, startdz);
  409.        
  410.         frames++;
  411.        
  412.         time2 = mygettime() - time1;
  413.         if (time2 > 1.0)
  414.         {
  415.             SDL_FreeSurface (textrend);
  416.             char fpsstring[30] = "FPS: ";
  417.             strcat (fpsstring, my_itoa (frames));
  418.             textrend = TTF_RenderText_Solid (font, fpsstring, fontcolor);
  419.             frames = 0;
  420.             time1 = mygettime();
  421.         }
  422.     }
  423. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement