home *** CD-ROM | disk | FTP | other *** search
/ Black Art of 3D Game Programming / Black_Art_of_3D_Game_Programming.iso / source / borland / chap_16 / voxel.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-05-12  |  9.9 KB  |  425 lines

  1.  
  2. // VOXEL.C - Single texture based, ray casted voxel engine
  3.  
  4. // I N C L U D E S ///////////////////////////////////////////////////////////
  5.  
  6. #include <io.h>
  7. #include <conio.h>
  8. #include <stdio.h>
  9. #include <stdlib.h>
  10. #include <dos.h>
  11. #include <bios.h>
  12. #include <fcntl.h>
  13. #include <memory.h>
  14. #include <malloc.h>
  15. #include <math.h>
  16. #include <string.h>
  17.  
  18. #include "black3.h"
  19. #include "black4.h"
  20. #include "black5.h"
  21.  
  22. // D E F I N E S /////////////////////////////////////////////////////////////
  23.  
  24. #define WORLD_X_SIZE   320  // width of universe
  25. #define WORLD_Y_SIZE   200  // height of universe
  26.  
  27. // constants used to represent angles for the ray casting a 60 degree field of
  28. // view
  29.  
  30. #define ANGLE_0        0
  31. #define ANGLE_1        5
  32. #define ANGLE_2        10
  33. #define ANGLE_4        20
  34. #define ANGLE_5        25
  35. #define ANGLE_6        30
  36. #define ANGLE_15       80
  37. #define ANGLE_30       160
  38. #define ANGLE_45       240
  39. #define ANGLE_60       320
  40. #define ANGLE_90       480
  41. #define ANGLE_135      720
  42. #define ANGLE_180      960
  43. #define ANGLE_225      1200
  44. #define ANGLE_270      1440
  45. #define ANGLE_315      1680
  46. #define ANGLE_360      1920
  47.  
  48. // there are 1920 degrees in our circle or 360/1920 is the conversion factor
  49. // from real degrees to our degrees
  50.  
  51. #define ANGULAR_INCREMENT  ((float)0.1875)
  52.  
  53. // conversion constants from radians to degrees and vicversa
  54.  
  55. #define DEG_TO_RAD         ((float)3.1415926/(float)180)
  56. #define RAD_TO_DEG         ((float)180/(float)3.1415926)
  57.  
  58. // G L O B A L S  ////////////////////////////////////////////////////////////
  59.  
  60. pcx_picture image_pcx;        // general pcx image
  61.  
  62. int play_x=1000,              // the current world x of player
  63.     play_y=1000,              // the current world y of player
  64.     play_z=150,
  65.     play_ang=ANGLE_90,        // the current viewing angle of player
  66.     play_dist = 70,
  67.     mountain_scale=10;        // scaling factor for mountains
  68.  
  69. float play_dir_x,              // the direction the player is pointing in
  70.       play_dir_y,
  71.       play_dir_z,
  72.       cos_look[ANGLE_360],     // cosine look up table
  73.       sin_look[ANGLE_360],     // sin look up table
  74.       sphere_cancel[ANGLE_60]; // cancels fish eye distortion
  75.  
  76. // F U N C T I O N S ////////////////////////////////////////////////////////
  77.  
  78. void Line_VDB(int y1,int y2,int x,int color)
  79. {
  80. // draw a vertical line, note that a memset function can no longer be
  81. // used since the pixel addresses are no longer contiguous in memory
  82. // note that the end points of the line must be on the screen
  83.  
  84. unsigned char far *start_offset; // starting memory offset of line
  85.  
  86. int index, // loop index
  87.     temp;  // used for temporary storage during swap
  88.  
  89. // make sure y2 > y1
  90.  
  91. if (y1>y2)
  92.    {
  93.    temp = y1;
  94.    y1   = y2;
  95.    y2   = temp;
  96.    } // end swap
  97.  
  98. // compute starting position
  99.  
  100. start_offset = double_buffer + ((y1<<8) + (y1<<6)) + x;
  101.  
  102. for (index=0; index<=y2-y1; index++)
  103.     {
  104.     // set the pixel
  105.  
  106.     *start_offset = (unsigned char)color;
  107.  
  108.     // move downward to next line
  109.  
  110.     start_offset+=320;
  111.  
  112.     } // end for index
  113.  
  114. } // end Line_VDB
  115.  
  116. //////////////////////////////////////////////////////////////////////////////
  117.  
  118. int Initialize(char *filename)
  119. {
  120. // this function builds all the look up tables for the terrain generator and
  121. // loads in the terrain texture map
  122.  
  123. int ang;           // looping variable
  124.  
  125. float rad_angle;   // current angle in radians
  126.  
  127. // create sin and cos look up first
  128.  
  129. for (ang=0; ang<ANGLE_360; ang++)
  130.     {
  131.     // compute current angle in radians
  132.  
  133.     rad_angle = (float)ang*ANGULAR_INCREMENT*DEG_TO_RAD;
  134.  
  135.     // now compute the sin and cos
  136.  
  137.     sin_look[ang] = sin(rad_angle);
  138.     cos_look[ang] = cos(rad_angle);
  139.  
  140.     } // end for ang
  141.  
  142. // create inverse cosine viewing distortion filter
  143.  
  144. for (ang=0; ang<ANGLE_30; ang++)
  145.     {
  146.     // compute current angle in radians
  147.  
  148.     rad_angle = (float)ang*ANGULAR_INCREMENT*DEG_TO_RAD;
  149.  
  150.     // now compute the sin and cos
  151.  
  152.     sphere_cancel[ang+ANGLE_30] = 1/cos(rad_angle);
  153.     sphere_cancel[ANGLE_30-ang] = 1/cos(rad_angle);
  154.  
  155.     } // end for ang
  156.  
  157. // intialize the pcx structure
  158.  
  159. PCX_Init((pcx_picture_ptr)&image_pcx);
  160.  
  161. // load in the textures
  162.  
  163. return(PCX_Load(filename, (pcx_picture_ptr)&image_pcx,1));
  164.  
  165. } // end Initialize
  166.  
  167. /////////////////////////////////////////////////////////////////////////////
  168.  
  169. void Draw_Terrain(int play_x,
  170.                   int play_y,
  171.                   int play_z,
  172.                   int play_ang,
  173.                   int play_dist)
  174. {
  175. // this function draws the entire terrain based on the location and orientation
  176. // of the player's viewpoint
  177.  
  178. int curr_ang,       // current angle being processed
  179.     xr,yr,          // location of ray in world coords
  180.     x_fine,y_fine,  // the texture coordinates the ray hit
  181.     pixel_color,    // the color of textel
  182.     ray,            // looping variable
  183.     row,            // the current video row begin processed
  184.     row_inv,        // the inverted row to make upward positive
  185.     scale,          // the scale of the current strip
  186.  
  187.     top,            // top of strip
  188.     bottom;         // bottom of strip
  189.  
  190. float ray_length;   // the length of the ray after distortion compensation
  191.  
  192. // start the current angle off -30 degrees to the left of the player's
  193. // current viewing direction
  194.  
  195. curr_ang = play_ang - ANGLE_30;
  196.  
  197. // test for underflow
  198.  
  199. if (curr_ang < 0)
  200.    curr_ang+=ANGLE_360;
  201.  
  202. // cast a series of rays for every column of the screen
  203.  
  204. for (ray=1; ray<320; ray++)
  205.     {
  206.  
  207.     // for each column compute the pixels that should be displayed
  208.     // for each screen pixel, process from top to bottom
  209.  
  210.     for (row = 100; row<150; row++)
  211.         {
  212.  
  213.         // compute length of ray
  214.  
  215.         row_inv = 200-row;
  216.  
  217.         // use the current height and distance to compute length of ray.
  218.  
  219.         ray_length = sphere_cancel[ray] * ((float)(play_dist*play_z)/
  220.                                            (float)(play_z-row_inv));
  221.  
  222.         // rotate ray into position of sample
  223.  
  224.         xr = (int)((float)play_x + ray_length * cos_look[curr_ang]);
  225.         yr = (int)((float)play_y - ray_length * sin_look[curr_ang]);
  226.  
  227.         // compute texture coords
  228.  
  229.         x_fine = xr % WORLD_X_SIZE;
  230.         y_fine = yr % WORLD_Y_SIZE;
  231.  
  232.         // using texture index locate texture pixel in textures
  233.  
  234.         pixel_color = image_pcx.buffer[x_fine + (y_fine*320)];
  235.  
  236.         // draw the strip
  237.  
  238.         scale = (int)mountain_scale*pixel_color/(int)(ray_length+1);
  239.  
  240.         top        = 50+row-scale;
  241.  
  242.         bottom     = top + scale;
  243.  
  244.         Line_VDB(top,bottom,ray,pixel_color);
  245.  
  246.         } // end for row
  247.  
  248.     // move to next angle
  249.  
  250.     if (++curr_ang >= ANGLE_360)
  251.        curr_ang=ANGLE_0;
  252.  
  253.     } // end for ray
  254.  
  255. } // end Draw_Terrain
  256.  
  257. // M A I N //////////////////////////////////////////////////////////////////
  258.  
  259. void main(int argc, char **argv)
  260. {
  261. char buffer[80];
  262.  
  263. int done=0; // exit flag
  264.  
  265. float speed=0;  // speed of player
  266.  
  267. // check to see if command line parms are correct
  268.  
  269. if (argc<=2)
  270.    {
  271.    // not enough parms
  272.  
  273.    printf("\nUsage: voxel.exe filename.pcx height");
  274.    printf("\nExample: voxel voxterr4.pcx 10\n");
  275.  
  276.    // return to DOS
  277.  
  278.    exit(1);
  279.  
  280.    } // end if
  281.  
  282. // set the graphics mode to mode 13h
  283.  
  284. Set_Graphics_Mode(GRAPHICS_MODE13);
  285.  
  286. // create a double buffer
  287.  
  288. Create_Double_Buffer(200);
  289.  
  290. // create look up tables and load textures
  291.  
  292. if (!Initialize(argv[1]))
  293.    {
  294.  
  295.    printf("\nError loading file %s",argv[1]);
  296.    exit(1);
  297.  
  298.    } // end if
  299.  
  300.  
  301. // install keyboard driver
  302.  
  303. Keyboard_Install_Driver();
  304.  
  305. // set scale of mountains
  306.  
  307. mountain_scale = atoi(argv[2]);
  308.  
  309. // draw the first frame
  310.  
  311. Draw_Terrain(play_x,
  312.              play_y,
  313.              play_z,
  314.              play_ang,
  315.              play_dist);
  316.  
  317. Display_Double_Buffer(double_buffer,0);
  318.  
  319. // main event loop
  320.  
  321. while(!done)
  322.      {
  323.  
  324.      // reset velocity
  325.  
  326.      speed = 0;
  327.  
  328.      // test if user is hitting keyboard
  329.  
  330.      if (keys_active)
  331.         {
  332.         // what is user trying to do
  333.  
  334.         // change viewing distance
  335.  
  336.         if (keyboard_state[MAKE_F])
  337.            play_dist+=10;
  338.  
  339.         if (keyboard_state[MAKE_C])
  340.            play_dist-=10;
  341.  
  342.         // change viewing height
  343.  
  344.         if (keyboard_state[MAKE_U])
  345.            play_z+=10;
  346.  
  347.         if (keyboard_state[MAKE_D])
  348.            play_z-=10;
  349.  
  350.  
  351.         // change viewing position
  352.  
  353.         if (keyboard_state[MAKE_RIGHT])
  354.             if ((play_ang+=ANGLE_5) >= ANGLE_360)
  355.                play_ang-=ANGLE_360;
  356.  
  357.         if (keyboard_state[MAKE_LEFT])
  358.             if ((play_ang-=ANGLE_5) < 0)
  359.                play_ang+=ANGLE_360;
  360.  
  361.         // move foward
  362.  
  363.         if (keyboard_state[MAKE_UP])
  364.            speed=20;
  365.  
  366.         // move backward
  367.  
  368.         if (keyboard_state[MAKE_DOWN])
  369.            speed=-20;
  370.  
  371.         // exit demo
  372.  
  373.         if (keyboard_state[MAKE_ESC])
  374.            done=1;
  375.  
  376.  
  377.         // compute trajectory vector for this view angle
  378.  
  379.         play_dir_x = cos_look[play_ang];
  380.         play_dir_y = -sin_look[play_ang];
  381.         play_dir_z = 0;
  382.  
  383.         // translate viewpoint
  384.  
  385.         play_x+=speed*play_dir_x;
  386.         play_y+=speed*play_dir_y;
  387.         play_z+=speed*play_dir_z;
  388.  
  389.         // draw the terrain
  390.  
  391.         Fill_Double_Buffer(0);
  392.  
  393.         Draw_Terrain(play_x,
  394.                      play_y,
  395.                      play_z,
  396.                      play_ang,
  397.                      play_dist);
  398.  
  399.         // draw tactical
  400.  
  401.         sprintf(buffer,"Height = %d Distance = %d     ",play_z,play_dist);
  402.         Print_String_DB(0,0,10,buffer,0);
  403.  
  404.         sprintf(buffer,"Pos: X=%d, Y=%d, Z=%d    ",play_x,play_y,play_z);
  405.         Print_String_DB(0,10,10,buffer,0);
  406.  
  407.         Display_Double_Buffer(double_buffer,0);
  408.  
  409.         } // end if
  410.  
  411.      } // end while
  412.  
  413. // reset back to text mode
  414.  
  415. Set_Graphics_Mode(TEXT_MODE);
  416.  
  417. // remove the keyboard handler
  418.  
  419. Keyboard_Remove_Driver();
  420.  
  421. } // end main
  422.  
  423.  
  424.  
  425.