home *** CD-ROM | disk | FTP | other *** search
/ Black Art of 3D Game Programming / Black_Art_of_3D_Game_Programming.iso / source / borland / chap_15 / bspdemo.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-02-21  |  24.5 KB  |  879 lines

  1.  
  2. // I N C L U D E S ///////////////////////////////////////////////////////////
  3.  
  4. #include <io.h>
  5. #include <conio.h>
  6. #include <stdio.h>
  7. #include <stdlib.h>
  8. #include <dos.h>
  9. #include <bios.h>
  10. #include <fcntl.h>
  11. #include <memory.h>
  12. #include <malloc.h>
  13. #include <math.h>
  14. #include <string.h>
  15. #include <search.h>             // this one is needed for qsort()
  16.  
  17. // include all of our stuff
  18.  
  19. #include "black3.h"
  20. #include "black4.h"
  21. #include "black5.h"
  22. #include "black6.h"
  23. #include "black8.h"
  24. #include "black9.h"
  25. #include "black11.h"
  26. #include "black15.h"
  27.  
  28. // D E F I N E S /////////////////////////////////////////////////////////////
  29.  
  30. #define MAX_LINES        64   // this is the maximum number of lines in the demo
  31.                               // these lines will later become 3-D walls
  32.  
  33.  
  34. #define LINE_INVALID     0    // constants that define the state of a line
  35. #define LINE_VALID       1
  36.  
  37.  
  38. #define ACTION_STARTING_LINE    0 // used to determine if user is starting a new line
  39. #define ACTION_ENDING_LINE      1 // or ending one
  40. #define ACTION_DELETE_LINE           2 // deleting a line
  41.  
  42. #define GADGET_WIDTH     64 // size of the gadgets (buttons)
  43. #define GADGET_HEIGHT    12
  44.  
  45. // the pointers
  46.  
  47. #define POINTER_CROSS  0  // the cross hair pointer used to draw walls
  48. #define POINTER_END    1  // the modified cross hair that indicates the end of
  49.                           // a line is being drawn
  50. #define POINTER_DEL    2  // this is a modified cross hair that indicates a line
  51.                           // is to be deleted
  52. #define POINTER_HAND   3  // the hand pointer used to make selections
  53.  
  54. // the control buttons sprite values
  55.  
  56. #define CONTROL_CLEAR             0
  57. #define CONTROL_DEL_WALL          1
  58. #define CONTROL_BUILD_BSP         2
  59. #define CONTROL_PRINT_BSP         3
  60. #define CONTROL_VIEW              4
  61. #define CONTROL_EXIT              5
  62. #define CONTROL_EDITOR            6
  63.  
  64. // the control buttons interface values
  65.  
  66. #define CONTROL_ID_CLEAR          0
  67. #define CONTROL_ID_DEL_WALL       1
  68. #define CONTROL_ID_BUILD_BSP      2
  69. #define CONTROL_ID_PRINT_BSP      3
  70. #define CONTROL_ID_VIEW           4
  71. #define CONTROL_ID_EXIT           5
  72. #define CONTROL_ID_EDITOR         6
  73.  
  74. // control areas of GUI
  75.  
  76. #define BSP_MIN_X           0     // the bounding rectangle of the
  77. #define BSP_MAX_X           222   // BSP editor area
  78. #define BSP_MIN_Y           0
  79. #define BSP_MAX_Y           199
  80.  
  81. #define INTERFACE_MIN_X     226   // the bounding rectangle of the control
  82. #define INTERFACE_MAX_X     319   // button area to the right of editor
  83. #define INTERFACE_MIN_Y     0
  84. #define INTERFACE_MAX_Y     199
  85.  
  86. // S T R U C T U R E S ///////////////////////////////////////////////////////
  87.  
  88. // this holds the ultra simple "gadget" basically a button
  89.  
  90. typedef struct gadget_typ
  91.         {
  92.  
  93.         int x,y;   // position of gadget
  94.         int id;    // id number of gadget
  95.  
  96.         } gadget, *gadget_ptr;
  97.  
  98. // this structure holds the 2-D line that is used to represent vertical walls
  99. // later in the BSP creation process
  100.  
  101. typedef struct line_2d_typ
  102.         {
  103.  
  104.         int sx,sy;       // starting point
  105.         int ex,ey;       // ending point
  106.         int valid;       // flags of this line is valid
  107.  
  108.         } line_2d, *line_2d_ptr;
  109.  
  110. // P R O T O T Y P E S ///////////////////////////////////////////////////////
  111.  
  112. void Convert_Lines_To_Walls(void);
  113.  
  114. int Delete_Line(int x,int y);
  115.  
  116. void Wait_For_Mouse_Up(void);
  117.  
  118. int Button_Pressed(gadget_ptr gadgets, int num_gadgets,int pos_x,int pos_y);
  119.  
  120.  
  121. // G L O B A L S  ////////////////////////////////////////////////////////////
  122.  
  123. pcx_picture image_pcx,     // general PCX image used to load background and imagery
  124.             interface_pcx; // holds interface
  125.  
  126.  
  127. sprite controls_spr,         // the sprite that holds the control buttons
  128.        pointer_spr;
  129.  
  130. // gadget lists
  131.  
  132. gadget bsp_controls[6] = { {240,94, CONTROL_ID_CLEAR},
  133.                            {240,111,CONTROL_ID_DEL_WALL},
  134.                            {240,128,CONTROL_ID_BUILD_BSP},
  135.                            {240,145,CONTROL_ID_PRINT_BSP},
  136.                            {240,162,CONTROL_ID_VIEW},
  137.                            {240,179,CONTROL_ID_EXIT} };
  138.  
  139. line_2d lines[MAX_LINES]; // this holds the lines in the system, we could
  140.                           // use a linked list, but let's not make this harder
  141.                           // than it already is!
  142.  
  143. int total_lines=0;        // number of lines that have been defined
  144.  
  145. wall_ptr wall_list=NULL,  // pointer to the linked list of walls
  146.          bsp_root=NULL;   // pointer to root of BSP tree
  147.  
  148. // F U N C T I O N S ////////////////////////////////////////////////////////
  149.  
  150. void Convert_Lines_To_Walls(void)
  151. {
  152. // this function converts the list of 2-D lines into a linked list of 3-D
  153. // walls, computes the normal of each wall and sets the pointers up
  154. // also the function labels the lines on the screen so the user can see them
  155.  
  156.  
  157. int index; // looping index
  158.  
  159. wall_ptr last_wall, // used to track the last wall processed
  160.          temp_wall; // used as a temporary to build a wall up
  161.  
  162. vector_3d u,v;  // working vectors
  163.  
  164. float length;   // a general length var
  165.  
  166. char buffer[80];
  167.  
  168. // process each 2-d line and convert it into a 3-d wall
  169.  
  170. for (index=0; index<total_lines; index++)
  171.     {
  172.     // draw a numeric label near the line
  173.  
  174.     sprintf(buffer,"%d",index);
  175.  
  176.     Print_String((lines[index].sx+lines[index].ex)/2,
  177.                  (lines[index].sy+lines[index].ey)/2,
  178.                  10,
  179.                  buffer,
  180.                  1);
  181.  
  182.     // allocate the memory for the wall
  183.  
  184.     temp_wall = (wall_ptr)malloc(sizeof(wall));
  185.  
  186.     // set up links
  187.  
  188.     temp_wall->link =NULL;
  189.     temp_wall->front=NULL;
  190.     temp_wall->back =NULL;
  191.  
  192.     // assign points, note how y and z are transposed and the y's of the
  193.     // walls are fixed, this is because we ae looking down on the universe
  194.     // from an aerial view and the wall height is arbitrary, however, with
  195.     // the constants we have selected the walls are 20 units tall centered
  196.     // about the x-z plane
  197.  
  198.     // vertex 0
  199.  
  200.     temp_wall->wall_world[0].x = WORLD_SCALE_X*(SCREEN_TO_WORLD_X+lines[index].sx);
  201.     temp_wall->wall_world[0].y = WALL_CEILING;
  202.     temp_wall->wall_world[0].z = WORLD_SCALE_Z*(SCREEN_TO_WORLD_Z+lines[index].sy);
  203.  
  204.     // vertex 1
  205.  
  206.     temp_wall->wall_world[1].x = WORLD_SCALE_X*(SCREEN_TO_WORLD_X+lines[index].ex);
  207.     temp_wall->wall_world[1].y = WALL_CEILING;
  208.     temp_wall->wall_world[1].z = WORLD_SCALE_Z*(SCREEN_TO_WORLD_Z+lines[index].ey);
  209.  
  210.     // vertex 2
  211.  
  212.     temp_wall->wall_world[2].x = WORLD_SCALE_X*(SCREEN_TO_WORLD_X+lines[index].ex);
  213.     temp_wall->wall_world[2].y = WALL_FLOOR;
  214.     temp_wall->wall_world[2].z = WORLD_SCALE_Z*(SCREEN_TO_WORLD_Z+lines[index].ey);
  215.  
  216.     // vertex 3
  217.  
  218.     temp_wall->wall_world[3].x = WORLD_SCALE_X*(SCREEN_TO_WORLD_X+lines[index].sx);
  219.     temp_wall->wall_world[3].y = WALL_FLOOR;
  220.     temp_wall->wall_world[3].z = WORLD_SCALE_Z*(SCREEN_TO_WORLD_Z+lines[index].sy);
  221.  
  222.     // compute normal to wall
  223.  
  224.     // find two vectors co-planer in the wall
  225.  
  226.     Make_Vector_3D((point_3d_ptr)&temp_wall->wall_world[0],
  227.                    (point_3d_ptr)&temp_wall->wall_world[1],
  228.                    (vector_3d_ptr)&u);
  229.  
  230.     Make_Vector_3D((point_3d_ptr)&temp_wall->wall_world[0],
  231.                    (point_3d_ptr)&temp_wall->wall_world[3],
  232.                    (vector_3d_ptr)&v);
  233.  
  234.     // use cross product to compute normal
  235.  
  236.     Cross_Product_3D((vector_3d_ptr)&u,
  237.                      (vector_3d_ptr)&v,
  238.                      (vector_3d_ptr)&temp_wall->normal);
  239.  
  240.     // normalize the normal vector
  241.  
  242.     length = Vector_Mag_3D((vector_3d_ptr)&temp_wall->normal);
  243.  
  244.     temp_wall->normal.x/=length;
  245.     temp_wall->normal.y/=length;
  246.     temp_wall->normal.z/=length;
  247.  
  248.     // set id number for debugging
  249.  
  250.     temp_wall->id = index;
  251.  
  252.     // test if this is first wall
  253.  
  254.     if (index==0)
  255.        {
  256.        // set head of list pointer and last wall pointer
  257.  
  258.        wall_list = temp_wall;
  259.        last_wall = temp_wall;
  260.  
  261.        } // end if first wall
  262.     else
  263.        {
  264.        // the first wall has been taken care of
  265.  
  266.        // link the last wall to the next wall
  267.  
  268.        last_wall->link = temp_wall;
  269.  
  270.        // move the last wall to the next wall
  271.  
  272.        last_wall = temp_wall;
  273.  
  274.        } // end else
  275.  
  276.     } // end for index
  277.  
  278. } // end Convert_Lines_To_Walls
  279.  
  280. /////////////////////////////////////////////////////////////////////////////
  281.  
  282. int Delete_Line(int x,int y)
  283. {
  284. // this function hunts thru the lines and deletes the one closest to
  285. // the sent position (which is the center of the cross hairs
  286.  
  287. int curr_line,    // current line being processed
  288.     sx,sy,        // starting coordinates of test line
  289.     ex,ey,        // ending coordinates of test line
  290.     length_line,  // total length of line being tested
  291.     length_1,     // length of lines from endpoints of test line to target area
  292.     length_2,
  293.     min_x,max_x,  // bounding box of test line
  294.     min_y,max_y,
  295.     best_line=-1; // the best match so far in process
  296.  
  297. float best_error=10000, // start error off really large
  298.       test_error;       // current error being processed
  299.  
  300. // process each line and find best fit
  301.  
  302. for (curr_line=0; curr_line < total_lines; curr_line++)
  303.     {
  304.     // extract line parameters
  305.  
  306.     sx=lines[curr_line].sx;
  307.     sy=lines[curr_line].sy;
  308.  
  309.     ex=lines[curr_line].ex;
  310.     ey=lines[curr_line].ey;
  311.  
  312.     // first compute length of line
  313.  
  314.     length_line = sqrt((ex-sx)*(ex-sx)+(ey-sy)*(ey-sy));
  315.  
  316.     // compute length of first endpoint to selected position
  317.  
  318.     length_1 = sqrt((x-sx)*(x-sx)+(y-sy)*(y-sy));
  319.  
  320.     // compute length of second endpoint to selected position
  321.  
  322.     length_2 = sqrt((ex-x)*(ex-x)+(ey-y)*(ey-y));
  323.  
  324.     // compute the bounding box of line
  325.  
  326.     min_x = __min(sx,ex);
  327.     min_y = __min(sy,ey);
  328.     max_x = __max(sx,ex);
  329.     max_y = __max(sy,ey);
  330.  
  331.     // if the selection position is within bounding box then compute distance
  332.     // errors and save this line as a possibility
  333.  
  334.     if (x>=min_x && x<=max_x && y>=min_y && y<=max_y)
  335.        {
  336.        // compute percent error of total length to length of lines
  337.        // from endpoint to selected position
  338.  
  339.        test_error = (float)(100*abs((length_1+length_2)-length_line))
  340.                     /(float)length_line;
  341.  
  342.        // test if this line is a better selection than the last
  343.  
  344.        if (test_error < best_error)
  345.           {
  346.           // make this line the "best selection" so far
  347.  
  348.           best_error = test_error;
  349.           best_line  = curr_line;
  350.  
  351.           } // end if
  352.  
  353.        } // end if in bounding box
  354.  
  355.     } // end for curr_line
  356.  
  357. // did we get a line to delete?
  358.  
  359. if (best_line!=-1)
  360.    {
  361.    // delete the line from the line array by copying another line into
  362.    // the position
  363.  
  364.    // test for special cases
  365.  
  366.    if (total_lines==1) // a single line
  367.       total_lines=0;
  368.    else
  369.    if (best_line==total_lines-1)  // the line to delete is the last in array
  370.       total_lines--;
  371.    else
  372.       {
  373.       // the line to delete must be in the 0th to total_lines-1 position
  374.       // so copy the last line into the deleted one and decrement the
  375.       // number of lines in system
  376.  
  377.       lines[best_line] = lines[--total_lines];
  378.  
  379.       } // end else
  380.  
  381.    // redraw the interface
  382.  
  383.    PCX_Copy_To_Buffer((pcx_picture_ptr)&interface_pcx,double_buffer);
  384.  
  385.    // redraw the remaining lines
  386.  
  387.    for (curr_line=0; curr_line<total_lines; curr_line++)
  388.        {
  389.        // draw a line between points
  390.  
  391.        Draw_Line(lines[curr_line].sx,lines[curr_line].sy,
  392.                  lines[curr_line].ex,lines[curr_line].ey,
  393.                  13,
  394.                  double_buffer);
  395.  
  396.        // plot endpoint pixels
  397.  
  398.        Write_Pixel_DB(lines[curr_line].sx,lines[curr_line].sy,15);
  399.        Write_Pixel_DB(lines[curr_line].ex,lines[curr_line].ey,15);
  400.  
  401.        } // end for curr_line
  402.  
  403.    // return the line number that was deleted
  404.  
  405.    return(curr_line);
  406.  
  407.    } // end if
  408. else
  409.     return(-1);
  410.  
  411. } // end Delete_Line
  412.  
  413. //////////////////////////////////////////////////////////////////////////////
  414.  
  415. void Wait_For_Mouse_Up(void)
  416. {
  417. // this function waits for the mouse buttons to be released
  418.  
  419. int mx,my,      // mouse position dummy variables
  420.     buttons=1;  // mouse buttons
  421.  
  422. // loop until mouse is released
  423.  
  424. while(buttons)
  425.      Mouse_Control(MOUSE_POSITION_BUTTONS,&mx,&my,&buttons);
  426.  
  427. } // end Wait_For_Mouse_Release
  428.  
  429. ////////////////////////////////////////////////////////////////////////////
  430.  
  431. int Button_Pressed(gadget_ptr gadgets, int num_gadgets,int pos_x,int pos_y)
  432. {
  433. // this function takes as input an array of gadgets (buttons) and determines
  434. // which button is pressed, then the function returns the id number of the
  435. // gadget or -1 if there isn't a hit
  436.  
  437. int curr_gadget; // looping variable
  438.  
  439. // loop thru all gadgets in list and try to find the right one
  440.  
  441. for (curr_gadget=0; curr_gadget<num_gadgets; curr_gadget++)
  442.     {
  443.     // test if sent selection position is within bounding box of one of the
  444.     // gadgets
  445.  
  446.     if (pos_x >  gadgets[curr_gadget].x                 &&
  447.         pos_x < (gadgets[curr_gadget].x + GADGET_WIDTH) &&
  448.         pos_y >  gadgets[curr_gadget].y                 &&
  449.         pos_y < (gadgets[curr_gadget].y + GADGET_HEIGHT) )
  450.        {
  451.        // click the button
  452.  
  453.        controls_spr.x          = gadgets[curr_gadget].x;
  454.        controls_spr.y          = gadgets[curr_gadget].y;
  455.  
  456.        controls_spr.curr_frame = gadgets[curr_gadget].id+7;
  457.        Sprite_Draw_Clip((sprite_ptr)&controls_spr,video_buffer,1);
  458.        Sprite_Draw_Clip((sprite_ptr)&pointer_spr,video_buffer,1);
  459.  
  460.        // wait for user to release buttons on mouse
  461.  
  462.        Wait_For_Mouse_Up();
  463.  
  464.        controls_spr.curr_frame = gadgets[curr_gadget].id;
  465.        Sprite_Draw_Clip((sprite_ptr)&controls_spr,video_buffer,1);
  466.  
  467.        // return the id number of the gadget
  468.  
  469.        return(gadgets[curr_gadget].id);
  470.  
  471.        } // end if hit
  472.  
  473.     } // end for curr_gadget
  474.  
  475. // return no hit
  476.  
  477. return(-1);
  478.  
  479. } // end Button_Pressed
  480.  
  481. // M A I N //////////////////////////////////////////////////////////////////
  482.  
  483. void main(void)
  484. {
  485. int index,            // loop variable
  486.     mouse_x,          // mouse position
  487.     mouse_y,
  488.     buttons,          // state of buttons
  489.     button_down = 0,
  490.     exit=0,           // system exit flag
  491.     sel,
  492.     action = ACTION_STARTING_LINE; // this is used to track the current action the
  493.                                    // user is in the middle of
  494.  
  495. char buffer[80];      // string input buffer
  496.  
  497. // build all look up tables for standard poly 3-d engine
  498.  
  499. Build_Look_Up_Tables();
  500.  
  501. // set the graphics mode to mode 13h
  502.  
  503. Set_Graphics_Mode(GRAPHICS_MODE13);
  504.  
  505. // create the double buffer
  506.  
  507. Create_Double_Buffer(200);
  508.  
  509. // load the imagery for control buttons
  510.  
  511. PCX_Init((pcx_picture_ptr)&image_pcx);
  512. PCX_Load("bspbutt.pcx", (pcx_picture_ptr)&image_pcx,1);
  513.  
  514. // intialize the controls  sprite
  515.  
  516. Sprite_Init((sprite_ptr)&controls_spr,0,0,64,12,0,0,0,0,0,0);
  517.  
  518. // extract the bitmaps for control buttons
  519.  
  520. for (index=0; index<14; index++)
  521.     PCX_Get_Sprite((pcx_picture_ptr)&image_pcx,
  522.                    (sprite_ptr)&controls_spr,index,index/7,index%7);
  523.  
  524. // done with this PCX file so delete memory associated with it
  525.  
  526. PCX_Delete((pcx_picture_ptr)&image_pcx);
  527.  
  528. // load the imagery for pointer
  529.  
  530. PCX_Init((pcx_picture_ptr)&image_pcx);
  531. PCX_Load("bsppoint.pcx", (pcx_picture_ptr)&image_pcx,1);
  532.  
  533. // intialize the pointer sprite
  534.  
  535. Sprite_Init((sprite_ptr)&pointer_spr,0,0,9,9,0,0,0,0,0,0);
  536.  
  537. // extract the bitmaps for pointer
  538.  
  539. for (index=0; index<4; index++)
  540.     PCX_Get_Sprite((pcx_picture_ptr)&image_pcx,
  541.                    (sprite_ptr)&pointer_spr,index,index,0);
  542.  
  543. // done with this PCX file so delete memory associated with it
  544.  
  545. PCX_Delete((pcx_picture_ptr)&image_pcx);
  546.  
  547. // set pointer to cross hair
  548.  
  549. pointer_spr.curr_frame=POINTER_CROSS;
  550.  
  551. // load the imagery for interface
  552.  
  553. PCX_Init((pcx_picture_ptr)&interface_pcx);
  554. PCX_Load("bspint.pcx", (pcx_picture_ptr)&interface_pcx,1);
  555.  
  556. // copy PCX image to double buffer
  557.  
  558. PCX_Copy_To_Buffer((pcx_picture_ptr)&interface_pcx,double_buffer);
  559.  
  560. // reset the mouse and hide the pointer
  561.  
  562. Mouse_Control(MOUSE_RESET,NULL,NULL,&buttons);
  563. Mouse_Control(MOUSE_HIDE,NULL,NULL,NULL);
  564.  
  565. // scan under the pointer
  566.  
  567. Sprite_Under_Clip((sprite_ptr)&pointer_spr,double_buffer);
  568.  
  569. // main event loop, process until keyboard hit
  570.  
  571. while(!exit)
  572.      {
  573.      // erase the pointer
  574.  
  575.      Sprite_Erase_Clip((sprite_ptr)&pointer_spr,double_buffer);
  576.  
  577.      Mouse_Control(MOUSE_POSITION_BUTTONS,&mouse_x,&mouse_y,&buttons);
  578.  
  579.      // map the mouse position to the screen and assign it to pointer
  580.  
  581.      mouse_x = pointer_spr.x = (mouse_x >> 1)-16;
  582.      mouse_y = pointer_spr.y = mouse_y;
  583.  
  584.      // test if pointer icon needs to be changed
  585.  
  586.      if (pointer_spr.x > BSP_MAX_X)
  587.         pointer_spr.curr_frame = POINTER_HAND;
  588.      else
  589.         {
  590.         // pointer must be in bsp editor section
  591.  
  592.         // test if a line is being deleted
  593.  
  594.         if (action==ACTION_DELETE_LINE)
  595.             pointer_spr.curr_frame = POINTER_DEL;
  596.         else
  597.         if (action==ACTION_STARTING_LINE)
  598.             pointer_spr.curr_frame = POINTER_CROSS;
  599.         else
  600.         if (action==ACTION_ENDING_LINE)
  601.             pointer_spr.curr_frame = POINTER_END;
  602.  
  603.         } // end else
  604.  
  605.      // test if player is trying to do something
  606.  
  607.      if (buttons==MOUSE_LEFT_BUTTON)
  608.         {
  609.  
  610.         // figure out which area this is happening in
  611.  
  612.         if (mouse_x>=BSP_MIN_X && mouse_x<=BSP_MAX_X &&
  613.             mouse_y>=BSP_MIN_Y && mouse_y<=BSP_MAX_Y)
  614.            {
  615.            // process bsp editor area click
  616.  
  617.            // test if this is starting point or endpoint
  618.  
  619.            if (action == ACTION_STARTING_LINE)
  620.               {
  621.               // set starting field, note the offsets to center the
  622.               // starting point in middle of cross hairs
  623.  
  624.               lines[total_lines].sx = mouse_x + 4;
  625.               lines[total_lines].sy = mouse_y + 4;
  626.  
  627.               // set point type to ending point
  628.  
  629.               action = ACTION_ENDING_LINE;
  630.  
  631.               // plot pixel
  632.  
  633.               Write_Pixel_DB(lines[total_lines].sx,lines[total_lines].sy,15);
  634.  
  635.               // wait for mouse button release
  636.  
  637.               Wait_For_Mouse_Up();
  638.  
  639.               } // end if start of wall
  640.            else
  641.            if (action == ACTION_ENDING_LINE)
  642.               {
  643.               // must be the end of a wall or ending point
  644.  
  645.               lines[total_lines].ex = mouse_x + 4;
  646.               lines[total_lines].ey = mouse_y + 4;
  647.  
  648.               // set point type to ending point
  649.  
  650.               action = ACTION_STARTING_LINE;
  651.  
  652.               // draw a line between points
  653.  
  654.               Draw_Line(lines[total_lines].sx,lines[total_lines].sy,
  655.                         lines[total_lines].ex,lines[total_lines].ey,
  656.                         13,
  657.                         double_buffer);
  658.  
  659.               // plot endpoint pixels
  660.  
  661.               Write_Pixel_DB(lines[total_lines].sx,lines[total_lines].sy,15);
  662.               Write_Pixel_DB(lines[total_lines].ex,lines[total_lines].ey,15);
  663.  
  664.               // advance number of lines
  665.  
  666.               if (++total_lines>=64)
  667.                  total_lines=64;
  668.  
  669.               // wait for mouse button release
  670.  
  671.               Wait_For_Mouse_Up();
  672.  
  673.               } // end else if
  674.            else
  675.            if (action==ACTION_DELETE_LINE)
  676.               {
  677.               // try and delete the line nearest selected point
  678.  
  679.               Delete_Line(mouse_x+4,mouse_y+4);
  680.  
  681.               // wait for mouse release
  682.  
  683.               Wait_For_Mouse_Up();
  684.  
  685.               // reset action to starting line
  686.  
  687.               action=ACTION_STARTING_LINE;
  688.  
  689.               } // end if
  690.  
  691.            } // end if in bsp editor area
  692.         else
  693.            {
  694.            // must be a click in the interface control area
  695.  
  696.            sel = Button_Pressed((gadget_ptr)bsp_controls,6,mouse_x,mouse_y);
  697.  
  698.            // which button was pressed
  699.  
  700.            switch(sel)
  701.                  {
  702.  
  703.                  case CONTROL_ID_CLEAR: // clear the screen and delete all lines
  704.                       {
  705.                       // reset number of lines
  706.  
  707.                       total_lines=0;
  708.  
  709.                       // reset state
  710.  
  711.                       action = ACTION_STARTING_LINE;
  712.  
  713.                       // refresh screen
  714.  
  715.                       PCX_Copy_To_Buffer((pcx_picture_ptr)&interface_pcx,double_buffer);
  716.  
  717.                       // delete BPS tree of there is one
  718.  
  719.                       if (bsp_root)
  720.                          {
  721.                          // delete the bsp tree
  722.  
  723.                          Bsp_Delete(bsp_root);
  724.  
  725.                          // reset pointers
  726.  
  727.                          wall_list = bsp_root = NULL;
  728.  
  729.                          } // end if
  730.  
  731.                       } break;
  732.  
  733.                  case CONTROL_ID_DEL_WALL:  // delete a single line (wall)
  734.                       {
  735.  
  736.                       action = ACTION_DELETE_LINE;
  737.  
  738.                       } break;
  739.  
  740.                  case CONTROL_ID_BUILD_BSP: // show the building of bsp
  741.                       {
  742.                       // delete the last bsp tree if there is one
  743.  
  744.                       Bsp_Delete(bsp_root);
  745.  
  746.                       // convert 2-d lines to 3-d walls
  747.  
  748.                       Convert_Lines_To_Walls();
  749.  
  750.                       // build the 3-D bsp tree
  751.  
  752.                       Build_Bsp_Tree(wall_list);
  753.  
  754.                       // alias the bsp tree to the wall list first node
  755.                       // which has now become the root of the tree
  756.  
  757.                       bsp_root = wall_list;
  758.  
  759.                       // translate the walls in the bsp tree out on the
  760.                       // z axis a bit
  761.  
  762.                       Bsp_Translate(bsp_root,WORLD_POS_X,WORLD_POS_Y,WORLD_POS_Z);
  763.  
  764.                       // shade the walls in the bsp
  765.  
  766.                       Bsp_Shade(bsp_root);
  767.  
  768.                       // wait for user to key keyboard to continue
  769.  
  770.                       getch();
  771.  
  772.                       } break;
  773.  
  774.                  case CONTROL_ID_PRINT_BSP: // print the bsp data stucture
  775.                       {
  776.                       // open output file
  777.  
  778.                       fp_out = fopen("bspdemo.out","w");
  779.  
  780.                       fprintf(fp_out,"\nPrinting BSP tree:\n");
  781.  
  782.                       Bsp_Print(bsp_root);
  783.  
  784.                       fclose(fp_out);
  785.  
  786.                       } break;
  787.  
  788.                  case CONTROL_ID_VIEW: // fly thru 3-d bsp world
  789.                       {
  790.                       // call the self contained viewing function
  791.  
  792.                       Bsp_View(bsp_root);
  793.  
  794.                       // clear the editor out for a new bsp
  795.  
  796.                       // reset number of lines
  797.  
  798.                       total_lines=0;
  799.  
  800.                       // reset state
  801.  
  802.                       action = ACTION_STARTING_LINE;
  803.  
  804.                       // refresh screen
  805.  
  806.                       PCX_Copy_To_Buffer((pcx_picture_ptr)&interface_pcx,double_buffer);
  807.  
  808.                       // delete BPS tree of there is one
  809.  
  810.                       if (bsp_root)
  811.                          {
  812.                          // delete the bsp tree
  813.  
  814.                          Bsp_Delete(bsp_root);
  815.  
  816.                          // reset pointers
  817.  
  818.                          wall_list = bsp_root = NULL;
  819.  
  820.                          } // end if
  821.  
  822.                       } break;
  823.  
  824.                  case CONTROL_ID_EXIT: // exit system
  825.                       {
  826.                       // set exit flag
  827.  
  828.                       exit=1;
  829.  
  830.                       } break;
  831.  
  832.                  default:break;
  833.  
  834.                  } // end switch
  835.  
  836.            } // end else
  837.  
  838.         } // end if button pressed
  839.  
  840.     if (buttons==MOUSE_RIGHT_BUTTON)
  841.        {
  842.        // reset system to starting line
  843.  
  844.        action = ACTION_STARTING_LINE;
  845.  
  846.        } // end if
  847.  
  848.      // scan under pointer
  849.  
  850.      Sprite_Under_Clip((sprite_ptr)&pointer_spr,double_buffer);
  851.  
  852.      // draw the pointer
  853.  
  854.      Sprite_Draw_Clip((sprite_ptr)&pointer_spr,double_buffer,1);
  855.  
  856.      // draw the coordinates
  857.  
  858.      sprintf(buffer,"(%d,%d) ",(mouse_x+4)+SCREEN_TO_WORLD_X,
  859.                               -((mouse_y+4)+SCREEN_TO_WORLD_Z));
  860.  
  861.      Print_String_DB(228,56,10,buffer,0);
  862.  
  863.      // display double buffer
  864.  
  865.      Display_Double_Buffer(double_buffer,0);
  866.  
  867.      } // end while
  868.  
  869. // free up all resources
  870.  
  871. Delete_Double_Buffer();
  872.  
  873. // restore graphics to text mode
  874.  
  875. Set_Graphics_Mode(TEXT_MODE);
  876.  
  877. } // end main
  878.  
  879.