home *** CD-ROM | disk | FTP | other *** search
/ Black Art of 3D Game Programming / Black_Art_of_3D_Game_Programming.iso / source / borland / chap_17 / blaze3d.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-04-07  |  13.5 KB  |  589 lines

  1.  
  2. // Starblazer 3-D
  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. #include <search.h>             // this one is needed for qsort()
  18.  
  19. // include all of our stuff
  20.  
  21. #include "black3.h"
  22. #include "black4.h"
  23. #include "black5.h"
  24. #include "black6.h"
  25. #include "black8.h"
  26. #include "black9.h"
  27. #include "black17.h"
  28.  
  29. // D E F I N E S /////////////////////////////////////////////////////////////
  30.  
  31. #define NUM_ASTEROIDS  18       // total number of asteroids in demo
  32.  
  33. #define SCANNER_X      121      // position of scanner
  34. #define SCANNER_Y      151
  35.  
  36. // T Y P E D E F S ///////////////////////////////////////////////////////////
  37.  
  38. typedef struct asteroid_typ
  39.         {
  40.         int state;           // state of asteroid
  41.         int xv,yv,zv;        // velocity of asteroid
  42.         int rx,ry,rz;        // rotation rate of asteroid
  43.  
  44.         } asteroid, *asteroid_ptr;
  45.  
  46. // G L O B A L S /////////////////////////////////////////////////////////////
  47.  
  48. object test_objects[NUM_ASTEROIDS];  // objects in universe, need to be in global
  49.                                      // data segement to make things easier
  50.  
  51. // F U N C T I O N S /////////////////////////////////////////////////////////
  52.  
  53. void Draw_Speedo(int speed)
  54. {
  55. // this function draws the digital speedometer
  56.  
  57. int mark_x=258, // starting tick mark
  58.     index,      // looping variable
  59.     color;      // color of tick mark
  60.  
  61. // compute number of iterations
  62.  
  63. speed/=5;
  64.  
  65. if (speed>=0)
  66.    {
  67.    // select foward color
  68.  
  69.    color=10;
  70.    }
  71. else
  72.    {
  73.    // set color to backward
  74.  
  75.    color=12;
  76.  
  77.    // take abs of speed
  78.  
  79.    speed=-speed;
  80.  
  81.    } // end else
  82.  
  83. // draw the ticks
  84.  
  85. for (index=0; index<speed; index++,mark_x+=6)
  86.     {
  87.     // draw a vertical line
  88.  
  89.     Line_V(4,14,mark_x,color);
  90.  
  91.     } // end for index
  92.  
  93. // erase remaining tick marks
  94.  
  95. for (; index<10; index++,mark_x+=6)
  96.     {
  97.     // draw a vertical line
  98.  
  99.     Line_V(4,14,mark_x,0);
  100.  
  101.     } // end for index
  102.  
  103. } // end Draw_Speedo
  104.  
  105. ///////////////////////////////////////////////////////////////////////////////
  106.  
  107. void Draw_Scanner(asteroid_ptr asteroids,int draw)
  108. {
  109. // this function erases or draws the blips on the scanner
  110.  
  111. int index, // looping variable
  112.     xb,yb, // position of blip in screen coordinates on scanner
  113.     cb;    // color of blip
  114.  
  115. static int blip_x[NUM_ASTEROIDS+1], // position 0 holds the ship
  116.            blip_y[NUM_ASTEROIDS+1], // position 0 holds the ship
  117.            active_blips;            // number of active blips this cycle
  118.  
  119. // should the scanner image be erased or drawn
  120.  
  121. if (!draw)
  122.    {
  123.    // erase all the blips
  124.  
  125.    for (index=0; index<=active_blips; index++)
  126.        Write_Pixel(SCANNER_X+blip_x[index], SCANNER_Y+blip_y[index],0);
  127.  
  128.    } // end if erase
  129. else
  130.    {
  131.    // draw the scanner blips
  132.  
  133.    // draw asteroids above player as red, below as blue and player as green
  134.    // the asteroids exits in positions 1..n and the player at 0
  135.  
  136.    active_blips=0;
  137.  
  138.    for (index=0; index<NUM_ASTEROIDS; index++)
  139.        {
  140.        // test if asteroids is alive, if so, draw it, and save it in record
  141.  
  142.        if (asteroids[index].state)
  143.           {
  144.           // increase active number of blips
  145.  
  146.           active_blips++;
  147.  
  148.           // compute screen coordinates of blip
  149.  
  150.           xb = (test_objects[index].world_pos.x+2500)/63;
  151.           yb = (2500-test_objects[index].world_pos.z)/139;
  152.  
  153.           // compute color
  154.  
  155.           if (test_objects[index].world_pos.y<view_point.y)
  156.              cb = 12;
  157.           else
  158.              cb = 9;
  159.  
  160.           // save the blip
  161.  
  162.           blip_x[active_blips]=xb;
  163.           blip_y[active_blips]=yb;
  164.  
  165.           // draw the blip
  166.  
  167.           Write_Pixel(SCANNER_X+xb,SCANNER_Y+yb,cb);
  168.  
  169.           } // end if asteroid alive
  170.  
  171.        } // end for index
  172.  
  173.    // now process the ship blip
  174.  
  175.    blip_x[0]=(view_point.x+2500)/63;
  176.    blip_y[0]=(2500-view_point.z)/139;
  177.  
  178.    Write_Pixel(SCANNER_X+blip_x[0],SCANNER_Y+blip_y[0],10);
  179.  
  180.    } // end else
  181.  
  182. } // end Draw_Scanner
  183.  
  184. // M A I N ////////////////////////////////////////////////////////////////////
  185.  
  186. void main(int argc,char **argv)
  187. {
  188.  
  189. int done=0,         // exit flag
  190.     index,          // looping variable
  191.     ship_pitch=0,   // current direction of ship
  192.     ship_yaw=0,
  193.     ship_roll=0,
  194.     ship_speed = 0;
  195.  
  196. vector_3d unit_z          = {0,0,1,1},  // a unit vector in the Z direction
  197.           ship_direction  = {0,0,1,1};  // the ships direction
  198.  
  199. asteroid asteroids[NUM_ASTEROIDS];   // the asteroid field
  200. char buffer[80];                     // output string buffer
  201. pcx_picture image_pcx;               // used to load in the background imagery
  202.  
  203. matrix_4x4 rotate;                   // used to build up rotation matrix
  204.  
  205. // set 2-D clipping region to take into consideration the instrument panels
  206.  
  207. poly_clip_min_y  = 0;
  208. poly_clip_max_y  = 121;
  209.  
  210. // set up viewing and 3D clipping parameters
  211.  
  212. clip_near_z      = 100,
  213. clip_far_z       = 4000,
  214. viewing_distance = 250;
  215.  
  216. // turn the damn light up a bit!
  217.  
  218. ambient_light    = 8;
  219.  
  220. light_source.x   = 0.918926;
  221. light_source.y   = 0.248436;
  222. light_source.z   = -0.306359;
  223.  
  224. // build all look up tables
  225.  
  226. Build_Look_Up_Tables();
  227.  
  228. // load in small asteroids
  229.  
  230. for (index=0; index<6; index++)
  231.     {
  232.     if (PLG_Load_Object(&test_objects[index],"pyramid.plg",2))
  233.        printf("\nplg loaded.");
  234.     else
  235.        printf("\nCouldn't load file");
  236.  
  237.     } // end for index
  238.  
  239. // load in medium asteroids
  240.  
  241. for (index=6; index<12; index++)
  242.     {
  243.     if (PLG_Load_Object(&test_objects[index],"diamond.plg",3))
  244.        printf("\nplg loaded.");
  245.     else
  246.        printf("\nCouldn't load file");
  247.  
  248.     } // end for index
  249.  
  250. // load in large asteroids
  251.  
  252. for (index=12; index<18; index++)
  253.     {
  254.     if (PLG_Load_Object(&test_objects[index],"cube.plg",4))
  255.        printf("\nplg loaded.");
  256.     else
  257.        printf("\nCouldn't load file");
  258.  
  259.     } // end for index
  260.  
  261. // position and set velocity of all asteroids
  262.  
  263. for (index=0; index<NUM_ASTEROIDS; index++)
  264.     {
  265.     // set position
  266.  
  267.     test_objects[index].world_pos.x = -1000 + rand()%2000;
  268.     test_objects[index].world_pos.y = -1000 + rand()%2000;
  269.     test_objects[index].world_pos.z = -1000 + rand()%2000;
  270.  
  271.     // set velocity
  272.  
  273.     asteroids[index].xv = -20+rand()%40;
  274.     asteroids[index].yv = -20+rand()%40;
  275.     asteroids[index].zv = -20+rand()%40;
  276.  
  277.     // set angular rotation rate
  278.  
  279.     asteroids[index].rx = rand()%10;
  280.     asteroids[index].ry = rand()%10;
  281.     asteroids[index].rz = rand()%10;
  282.  
  283.     // set state to alive
  284.  
  285.     asteroids[index].state = 1;
  286.  
  287.     } // end for
  288.  
  289. // set graphics to mode 13h
  290.  
  291. Set_Graphics_Mode(GRAPHICS_MODE13);
  292.  
  293. // read the 3D color palette off disk
  294.  
  295. Load_Palette_Disk("standard.pal",(RGB_palette_ptr)&color_palette_3d);
  296. Write_Palette(0,255,(RGB_palette_ptr)&color_palette_3d);
  297.  
  298. // allocate double buffer
  299.  
  300. Create_Double_Buffer(122);
  301.  
  302. // load in background image
  303.  
  304. PCX_Init((pcx_picture_ptr)&image_pcx);
  305. PCX_Load("blz3dcoc.pcx", (pcx_picture_ptr)&image_pcx,1);
  306. PCX_Show_Buffer((pcx_picture_ptr)&image_pcx);
  307.  
  308. // install the isr keyboard driver
  309.  
  310. Keyboard_Install_Driver();
  311.  
  312. // scan the asteroid field
  313.  
  314. Draw_Scanner((asteroid_ptr)&asteroids[0],1);
  315.  
  316. // main event loop
  317.  
  318. while(!done)
  319.      {
  320.  
  321.      // compute starting time of this frame
  322.  
  323.      starting_time = Timer_Query();
  324.  
  325.      // erase all objects
  326.  
  327.      // Draw_Poly_List(1);
  328.  
  329.      Fill_Double_Buffer_32(0);
  330.  
  331.      // erase the scanner
  332.  
  333.      Draw_Scanner((asteroid_ptr)&asteroids[0],0);
  334.  
  335.      // test what user is doing
  336.  
  337.  
  338.      // change ship velocity
  339.  
  340.      if (keyboard_state[MAKE_RGT_BRACKET])
  341.         {
  342.         // speed up
  343.  
  344.         if ((ship_speed+=5)>50)
  345.             ship_speed=50;
  346.  
  347.         } // end if speed increase
  348.  
  349.      if (keyboard_state[MAKE_LFT_BRACKET])
  350.         {
  351.         // slow down
  352.  
  353.         if ((ship_speed-=5)<-50)
  354.             ship_speed=-50;
  355.  
  356.         } // end if speed decrease
  357.  
  358.      // test for turns
  359.  
  360.      if (keyboard_state[MAKE_RIGHT])
  361.         {
  362.         // rotate ship to right
  363.  
  364.         if ((ship_yaw+=4)>=360)
  365.            ship_yaw-=360;
  366.  
  367.         } // end if
  368.  
  369.      if (keyboard_state[MAKE_LEFT])
  370.         {
  371.  
  372.         // rotate ship to left
  373.  
  374.         if ((ship_yaw-=4)<0)
  375.            ship_yaw+=360;
  376.  
  377.         } // end if
  378.  
  379.      // test for up and down
  380.  
  381.      if (keyboard_state[MAKE_UP])
  382.         {
  383.  
  384.         view_point.y-=25;
  385.  
  386.         } // end if
  387.  
  388.      if (keyboard_state[MAKE_DOWN])
  389.         {
  390.  
  391.         view_point.y+=25;
  392.  
  393.         } // end if
  394.  
  395.      // test for exit
  396.  
  397.      if (keyboard_state[MAKE_ESC])
  398.         done=1;
  399.  
  400.      // rotate trajectory vector to align with view direction
  401.  
  402.      Mat_Identity_4x4(rotate);
  403.  
  404.      rotate[0][0] = ( cos_look[ship_yaw]);
  405.      rotate[0][2] = (-sin_look[ship_yaw]);
  406.      rotate[2][0] = ( sin_look[ship_yaw]);
  407.      rotate[2][2] = ( cos_look[ship_yaw]);
  408.  
  409.      // x component
  410.  
  411.      ship_direction.x =
  412.  
  413.               unit_z.x * rotate[0][0] +
  414.               unit_z.z * rotate[2][0];
  415.  
  416.      // y component
  417.  
  418.      ship_direction.y =
  419.  
  420.               unit_z.y * rotate[1][1];
  421.  
  422.      // z component
  423.  
  424.      ship_direction.z =
  425.  
  426.               unit_z.x * rotate[0][2] +
  427.               unit_z.z * rotate[2][2];
  428.  
  429.      // move viewpoint based on ship trajectory
  430.  
  431.      view_point.x+=ship_direction.x*ship_speed;
  432.      view_point.y+=ship_direction.y*ship_speed;
  433.      view_point.z+=ship_direction.z*ship_speed;
  434.  
  435.      // test ship against universe boundaries
  436.  
  437.      if (view_point.x>2500)
  438.          view_point.x=-2500;
  439.      else
  440.      if (view_point.x<-2500)
  441.          view_point.x=2500;
  442.  
  443.      if (view_point.y>2500)
  444.          view_point.y=-2500;
  445.      else
  446.      if (view_point.y<-2500)
  447.          view_point.y=2500;
  448.  
  449.      if (view_point.z>2500)
  450.          view_point.z=-2500;
  451.      else
  452.      if (view_point.z<-2500)
  453.          view_point.z=2500;
  454.  
  455.      // set view angles based on trajectory of ship
  456.  
  457.      view_angle.ang_x = ship_pitch;
  458.      view_angle.ang_y = ship_yaw;
  459.      view_angle.ang_z = ship_roll;
  460.  
  461.      // rotate asteroids
  462.  
  463.      for (index=0; index<NUM_ASTEROIDS; index++)
  464.           {
  465.           // rotate object based on rotation rates
  466.  
  467.           Rotate_Object(&test_objects[index],asteroids[index].rx,
  468.                                              asteroids[index].ry,
  469.                                              asteroids[index].rz);
  470.  
  471.           } // end for index
  472.  
  473.      // translate asteroids
  474.  
  475.      for (index=0; index<NUM_ASTEROIDS; index++)
  476.          {
  477.  
  478.          // translate each asteroids world position
  479.  
  480.          test_objects[index].world_pos.x+=asteroids[index].xv;
  481.          test_objects[index].world_pos.y+=asteroids[index].yv;
  482.          test_objects[index].world_pos.z+=asteroids[index].zv;
  483.  
  484.          // test if the asteroid has gone off the screen anywhere
  485.  
  486.          if (test_objects[index].world_pos.x > 2500 ||
  487.              test_objects[index].world_pos.x < -2500)
  488.             asteroids[index].xv=-asteroids[index].xv;
  489.  
  490.          if (test_objects[index].world_pos.y > 2500 ||
  491.              test_objects[index].world_pos.y < -2500)
  492.             asteroids[index].yv=-asteroids[index].yv;
  493.  
  494.          if (test_objects[index].world_pos.z > 2500 ||
  495.              test_objects[index].world_pos.z < -2500)
  496.             asteroids[index].zv=-asteroids[index].zv;
  497.  
  498.          }  // end motion
  499.  
  500.      // now that user has possible moved viewpoint, create the global
  501.      // world to camera transformation matrix
  502.  
  503.      Create_World_To_Camera();
  504.  
  505.      // reset the polygon list
  506.  
  507.      Generate_Poly_List(NULL,RESET_POLY_LIST);
  508.  
  509.      // perform general 3-D pipeline
  510.  
  511.      for (index=0; index<NUM_ASTEROIDS; index++)
  512.          {
  513.          // test if object is visible
  514.  
  515.          if (!Remove_Object(&test_objects[index],OBJECT_CULL_XYZ_MODE))
  516.             {
  517.             // convert object local coordinates to world coordinate
  518.  
  519.             Local_To_World_Object(&test_objects[index]);
  520.  
  521.             // remove the backfaces and shade object
  522.  
  523.             Remove_Backfaces_And_Shade(&test_objects[index]);
  524.  
  525.             // convert world coordinates to camera coordinate
  526.  
  527.             World_To_Camera_Object(&test_objects[index]);
  528.  
  529.             // clip the objects polygons against viewing volume
  530.  
  531.             Clip_Object_3D(&test_objects[index],CLIP_Z_MODE);
  532.  
  533.             // generate the final polygon list
  534.  
  535.             Generate_Poly_List(&test_objects[index],ADD_TO_POLY_LIST);
  536.             }
  537.  
  538.          }  // end for
  539.  
  540.      // sort the polygons
  541.  
  542.      Sort_Poly_List();
  543.  
  544.      // draw the polygon list
  545.  
  546.      Draw_Poly_List();
  547.  
  548.      // display the pitch yaw and row of ship
  549.  
  550.      sprintf(buffer,"%4d",ship_pitch);
  551.      Print_String(80,6,10,buffer,0);
  552.  
  553.      sprintf(buffer,"%4d",ship_yaw);
  554.      Print_String(144,6,10,buffer,0);
  555.  
  556.      sprintf(buffer,"%4d",ship_roll);
  557.      Print_String(208,6,10,buffer,0);
  558.  
  559.      // draw speedo
  560.  
  561.      Draw_Speedo(ship_speed);
  562.  
  563.      // draw the scanner
  564.  
  565.      Draw_Scanner((asteroid_ptr)&asteroids[0],1);
  566.  
  567.      // display double buffer
  568.  
  569.      Display_Double_Buffer_32(double_buffer,18);
  570.  
  571.      // lock onto 18 frames per second max
  572.  
  573.      while((Timer_Query()-starting_time)<1);
  574.  
  575.      } // end while
  576.  
  577. // restore graphics mode back to text
  578.  
  579. Set_Graphics_Mode(TEXT_MODE);
  580.  
  581. // restore the old keyboard driver
  582.  
  583. Keyboard_Remove_Driver();
  584.  
  585. } // end main
  586.  
  587.  
  588.  
  589.