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

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