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

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