home *** CD-ROM | disk | FTP | other *** search
/ io Programmo 23 / IOPROG_23.ISO / SOFT / RAYCAST.ZIP / RAYCAST.CPP < prev    next >
Encoding:
C/C++ Source or Header  |  1995-10-25  |  33.1 KB  |  1,177 lines

  1.  
  2. /*********************
  3.  
  4. Portions of this code taken from Programming Gurus book by Waite Group
  5.  
  6. Most written for super speed game on '040 by Joshua Glazer
  7. Those portions are Copyright Joshua Glazer c1994
  8.  
  9. Lightening fast two-level Fixed Point Routines Copyright Joshua Glazer c1994
  10.  
  11. These routines may be used by one Matthew Howard, but 
  12. credit must be given to Joshua Glazer c1994
  13.  
  14. **** Yea, well I wrote some nice asm routines for IBM so, you can give Matt Howard -1994
  15. a little credit too! ****
  16.  
  17. I like writing Joshua Glazer c1994
  18.  
  19. Violaters of the Copyright law violated by violating this source-code
  20. will be hunted down and castrated (or spayed) by Joshua Glazer c1994
  21.  
  22. This means you!
  23.  
  24. Actually, 'This' is a pronoun used to refer to a subject being talked about
  25. which is closer to the speaker than some other object.
  26.  
  27. Oh Shut Up.
  28.  
  29. Copyright Joshua Glazer c1994
  30. *********************/
  31.  
  32. #include "asm.h"
  33. #include "ray.h"
  34. #include "rayrend.h"
  35. #include "raycl.h"
  36. #include "rayvb.h"
  37. #include "assert.h"
  38. #include "globals.h"
  39. #include "fixed.h"
  40. #include <mem.h>
  41. #include "mymem.h"
  42. #include <math.h>
  43. #include "asm.h"
  44. #include "prevarr.h"
  45. #include "voxinter.h"
  46. #include "texconst.h"
  47. #include "scrconf.h"
  48. #include "ldattrib.h"
  49. #include <stdio.h>
  50. #include <stdlib.h>
  51.  
  52.  
  53. #define BLACK_COLOR 240  
  54. #define SS_NO_VISIBLE -1
  55. #define SS_VISIBLE 0
  56.  
  57. #define LOW_WALL 0
  58. #define HIGH_WALL 1
  59. #define MID_WALL 2
  60.  
  61. #define CLIP
  62. #define CHECK_HIGH_LOW_CLIP_OUT
  63. #define CLIPVERT
  64. #define DO_FLOORS
  65.  
  66. #define BAR_LENGTH 10
  67. #define RED_COLOR 79
  68.  
  69. typedef struct WALL_MOVE_INFO {
  70.    MYFIXED top_start, bottom_start;
  71.    MYFIXED top_increment, bottom_increment;
  72.    ptexture texture;
  73.    short type;
  74.    long v_height;
  75.    vb_node * cur_bounds;
  76. } wall_move_info;
  77.  
  78. typedef struct INTERSECT_STRUCT {
  79.    long distance, xpos;
  80.    MYFIXED increment;
  81. } intersect_struct;
  82.  
  83. intersect_struct * intersects;
  84.  
  85. MYFIXED * floor_offsets_x;
  86. MYFIXED * floor_offsets_y;
  87. long v_angle_plus_90;
  88. MYFIXED floor_trans_x, floor_trans_y;
  89. short prev_win_top, prev_win_bottom,
  90. prev_wall_top, prev_wall_bottom, proj_left, proj_right;
  91.  
  92. short floor_ray, floor_start, floor_end, cur_height_diff;
  93. Byte * floor_texture;
  94. Byte * cur_sky_texture;
  95.  
  96. sector * Cur_Sec;
  97.  
  98. long ssetup_count;
  99.  
  100. void Seg_Setup(wall_move_info & mid_walls);
  101. void Get_Intersects(pvector2 base_v, angle_type angle_diff);
  102. void Draw_Seg(seg * cur_seg);
  103.  
  104. /*
  105.    Draw_Health
  106.    Draws a bar for player's health
  107. */
  108.  
  109. void Draw_Health() {
  110. long the_health=the_player->stats.current_health;
  111. long start_pos=Get_Phys_Screen_Width()*(Get_Phys_Screen_Height()-BAR_LENGTH);
  112. for (short cur_vert=0; cur_vert<BAR_LENGTH; cur_vert++) {
  113.   memset(buff+start_pos+(cur_vert*Get_Phys_Screen_Width()), RED_COLOR, the_health);
  114. }
  115. }
  116. /*
  117.    Win_Bounds_Setup
  118.    Just initializes bounding values before a draw to all 0's for top and
  119.    WINDOW_HEIGHT for bottom
  120. */
  121.  
  122. inline void Win_Bounds_Setup()
  123. {
  124.    memset(win_tops, 0, WINDOW_WIDTH * sizeof(short));
  125.    memsetshort(win_bottoms, WINDOW_HEIGHT, WINDOW_WIDTH);
  126. }
  127.  
  128. /*
  129.    Init_Floor_Values
  130.    Initializes values used for floor drawing
  131.    Notes: None
  132. */
  133.  
  134. inline void Init_Floor_Values()
  135. {
  136.  
  137.    // might as well calculate an angle that is used all the time for drawing floors
  138.  
  139.    v_angle_plus_90=Get_Angle_Difference(render_view_angle, ANGLE_90);
  140.  
  141.    floor_trans_x=fixedmult(x_inv_trans, rcos_table[v_angle_plus_90]);
  142.    floor_trans_y=fixedmult(x_inv_trans, rsin_table[v_angle_plus_90]);
  143.  
  144.    long floor_adder_x=floor_trans_x >> X_TRANS_SHIFT;
  145.    long floor_adder_y=floor_trans_y >> X_TRANS_SHIFT;
  146.  
  147.    long floor_sum_x=floor_adder_x * (-WINDOW_MIDDLEW);
  148.    long floor_sum_y=floor_adder_y * (-WINDOW_MIDDLEW);
  149.  
  150.    for (short cur_ray=0; cur_ray < (WINDOW_WIDTH); cur_ray++) {
  151.       floor_offsets_x[cur_ray]=floor_sum_x;
  152.       floor_offsets_y[cur_ray]=floor_sum_y;
  153.  
  154.       floor_sum_x+=floor_adder_x;
  155.       floor_sum_y+=floor_adder_y;
  156.       }
  157.  
  158. }
  159.  
  160. /*
  161.    Start_Tex
  162.    Marks starts of texture lines on rows from "start" up to but not including "end at x position "ray"
  163.    Notes: Assumes floor_texture already points to the floor texture to draw
  164. */
  165.                        
  166. inline void Start_Tex() {
  167.    short row;
  168.  
  169.    for (row=floor_start; row<floor_end; row++) {
  170.       tex_mark_table[row]=floor_ray;
  171.       }
  172.  
  173. }
  174.  
  175.  
  176. /*
  177.    Finish_Tex
  178.    Draws the previously marked floor textures on rows from "start" up to but no including "end"
  179.    Ends lines at "ray"
  180.    Notes: Assumes floor_texture already points to the floor texture to draw
  181. */
  182.  
  183. inline void Finish_Tex() {
  184.  
  185.  
  186.    short row, start_ray;
  187.    long tempLight;
  188.    MYFIXED distance_fixed;
  189.    floor_run_info * cur_floor_run;
  190.  
  191.    for (row=floor_start; row<floor_end; row++) {
  192.  
  193.       start_ray=tex_mark_table[row];
  194.  
  195.       if (floor_ray<=start_ray)
  196.          continue;
  197.  
  198.       if (floor_run_count>=MAX_FLOOR_RUNS)
  199.          break;
  200.  
  201.       cur_floor_run=floor_runs+floor_run_count;
  202.       floor_run_count++;
  203.  
  204.       // Set row to draw on
  205.  
  206.       cur_floor_run->screen_y=row;
  207.  
  208.       // Get starting x and width of texture
  209.  
  210.       cur_floor_run->scale=(short)(floor_ray-start_ray);
  211.  
  212.       cur_floor_run->screen_x=start_ray;
  213.  
  214.       // Get distance to floor
  215.  
  216.       distance_fixed=cur_height_diff *distance_table[row];
  217.       Assert(distance_fixed < 0, "Negative floor row distance");
  218.  
  219.       // Get map starting positions
  220.  
  221.       cur_floor_run->map_x=fixedmult(rcos_table[render_view_angle] + 
  222.         floor_offsets_x[start_ray], distance_fixed)+(render_x);
  223.       cur_floor_run->map_y=fixedmult(rsin_table[render_view_angle] +
  224.         floor_offsets_y[start_ray], distance_fixed)+(render_y);
  225.  
  226.       // Get increments by multiplying the increment along the  actual line by sin & cos of line angle
  227.  
  228.       cur_floor_run->x_inc=fixedmult(distance_fixed,
  229.          floor_trans_x) >> X_TRANS_SHIFT;
  230.       cur_floor_run->y_inc=fixedmult(distance_fixed,
  231.          floor_trans_y) >> X_TRANS_SHIFT;
  232.  
  233.       // do light calculation
  234.       // In getting the light value, we take into account that distance_fixed
  235.       // is a fixed point number and add to the right shift the fixed point conversion
  236.       // number
  237.  
  238.       tempLight=(SecLight(Cur_Sec)-
  239.          (distance_fixed >> (SHIFT+SecLTSpeed(Cur_Sec))) );
  240.       if (tempLight<0) tempLight=0;
  241.       if (tempLight>MAX_LIGHT) tempLight=MAX_LIGHT;
  242.  
  243.       Assert(((tempLight <0) || (tempLight >MAX_LIGHT)), "Bad Lighting Value");
  244.       cur_floor_run->light=pal_table[tempLight];
  245.  
  246.        cur_floor_run->texture=floor_texture;
  247.  
  248.    } /* endfor */
  249. }
  250.  
  251.  
  252. /*
  253.   Draw_Sky_Column
  254.   Draws one column of the sky texture from "top" down to but not including "bottom"
  255.   Notes: This is a hack. Code is cryptic. Should be improved upon. For example, it should
  256.   not require that sky texture be length of screen. Requires a theoretical
  257.   understanding of screen rays intersecting a circle on the horizon that I don't have
  258. */
  259.  
  260. inline void Draw_Sky_Column()
  261. {
  262.  
  263.    // Was the programmer such an idiot that he tried to draw column of length 0?
  264.    if (floor_start>=floor_end)
  265.       return;
  266.  
  267.    if (wall_run_count>=MAX_WALL_RUNS) {
  268.       return;
  269.    } /* endif */
  270.    wall_run_info * cur_wall_run=wall_runs+wall_run_count;
  271.    wall_run_count++;
  272.  
  273.    // Setup the render constants, pretty standard
  274.    cur_wall_run->bound_val=SKY_HEIGHT-1;
  275.    cur_wall_run->texture=cur_sky_texture;
  276.    cur_wall_run->ray=floor_ray;
  277.    cur_wall_run->top=floor_start;
  278.    cur_wall_run->scale=floor_end-floor_start;
  279.    cur_wall_run->clip=floor_start << SLIVER_SHIFT;
  280.    cur_wall_run->light=pal_table[MAX_LIGHT];
  281.    cur_wall_run->increment=SLIVER_ONE;
  282.    cur_wall_run->width_shift=SKY_SHIFT;
  283.  
  284.    // Do a whole lot of stupid calculations to get the column in the texture to draw
  285.  
  286.    long temp_column;
  287.  
  288.    long temp_ray=floor_ray*HORIZ_VIEW_RANGE/WINDOW_WIDTH;
  289.    long tempAngle;
  290.    if (temp_ray<(HORIZ_VIEW_RANGE>>1))
  291.       tempAngle=temp_ray;
  292.    else tempAngle=Get_Angle_Difference(HORIZ_VIEW_RANGE, temp_ray);
  293.    MYFIXED tempdiv=fixeddiv(tan_table[tempAngle],
  294.         tan_table[HORIZ_VIEW_RANGE>>1]);
  295.    tempdiv=convtoLONG((HORIZ_VIEW_RANGE>>1)*tempdiv);
  296.    if (temp_ray>=(HORIZ_VIEW_RANGE>>1))
  297.       tempdiv=HORIZ_VIEW_RANGE-tempdiv;
  298.    // div by 2 to stretch out backround a little
  299.    temp_column=(((HORIZ_VIEW_RANGE>>1)-tempdiv)+(render_view_angle));
  300.   
  301.    if (temp_column<0) {
  302.       cur_wall_run->column=SKY_WIDTH-((-temp_column) % SKY_WIDTH);
  303.    } else {
  304.       cur_wall_run->column=temp_column % SKY_WIDTH;
  305.    } /* endif */
  306.  
  307. }
  308.  
  309. /*
  310.    Close_Textures
  311.    Finishes up whatever textures were running in a given visible section
  312.    Notes: Uses proj_right and the "prev" globals
  313. */
  314.  
  315. inline void Close_Textures(short closing_ray)
  316. {
  317.  
  318. long floor_height_diff=render_z-Cur_Sec->floor_height;
  319. long ceil_height_diff=Cur_Sec->ceil_height-render_z;
  320.  
  321. floor_ray=closing_ray;
  322.  
  323. floor_texture=Get_Floor_Texture(Cur_Sec->ceil_tex);
  324. floor_start=prev_win_top; floor_end=prev_wall_top;
  325.  
  326. if ( ceil_height_diff>0 && floor_texture!=cur_sky_texture ) {
  327.    Finish_Tex();
  328. } /* endif */
  329.  
  330. floor_texture=Get_Floor_Texture(Cur_Sec->floor_tex);
  331. floor_start=prev_wall_bottom; floor_end=prev_win_bottom;
  332.  
  333. if ( floor_height_diff>0 && floor_texture!=cur_sky_texture ) {
  334.    Finish_Tex();
  335. } /* endif */
  336.  
  337. }
  338.  
  339. /*
  340.    SegVisible
  341.    Decides if a seg is (a) visible and (b) facing you
  342. */
  343.  
  344. inline BOOL SegVisible(seg * cur_seg)
  345. {
  346. long x1, x2, y1, y2;
  347. pvector2 v1, v2;
  348. v1=Vector_List+cur_seg->v[0];
  349. v2=Vector_List+cur_seg->v[1];
  350. x1=v1->x;
  351. x2=v2->x;
  352. y1=v1->y;
  353. y2=v2->y;
  354. if ( fixedmult((x1-x2),(render_y-(y2<<SHIFT))) >= fixedmult((y1-y2),(render_x-(x2<<SHIFT))) ) {
  355.    return TRUE;
  356. } else {
  357.    return FALSE;
  358. } /* endif */
  359. }
  360.  
  361. /////////////////////////////////////////////////////////////////////////////
  362.  
  363. /*
  364.    Ray_Caster
  365.    The all powerful function that renders the screen
  366.    Notes: Well, it isn't really all powerful. After all, it's just a routine,
  367.    not some sort of diety. It dosen't even do that much, just calls other routines
  368. */
  369.  
  370. void Ray_Caster(long x, long y, long z, long view_angle)
  371. {
  372.  
  373. ssetup_count=0;
  374.  
  375. // setup rendering constants
  376. render_x=x; render_y=y; render_z=z; render_view_angle=view_angle;
  377.  
  378. // setup constants for floor drawing
  379.  
  380. Init_Floor_Values();
  381.  
  382. // save the current frame of the sky animation 
  383. // (we will say that sky texture cannot change while rendering)
  384.  
  385. cur_sky_texture=sky_texture->images[sky_texture->cur_image];
  386.  
  387. // Initialize the clipping structures
  388.  
  389. Win_Bounds_Setup();
  390. VB_InitList();
  391.  
  392. // Set starting wall & floor run count to 0
  393.  
  394. wall_run_count=0;
  395. floor_run_count=0;
  396.  
  397. // initialize voxel colors
  398. memset((PUCHAR)prev_colors, BLACK_COLOR, Get_Phys_Screen_Width());
  399. // Turn over control to the bsp tracer
  400.  
  401. BSP_Recursion_Draw();
  402.  
  403. // If we have any floors, it's probably a good idea to render them
  404.  
  405. if (floor_run_count>0) {
  406.    Render_Floor_asm();
  407. } /* endif */
  408.  
  409. // If we have any walls, its probably a good idea to render them too...
  410.  
  411. if (wall_run_count>0) {
  412.    Render_Sliver_asm();
  413. } /* endif */
  414.  
  415. Draw_Health();
  416. }
  417.  
  418. /*
  419.   Draw_Sub_Sector
  420.   Big time importance in this routine. Basically, it draws a sub sector (i.e. portion that cannot
  421.   obscure any of itself). Does most of the hard calculations. Well, not anymore, Draw_Seg does
  422.   now
  423.   Notes: Still has problems, may crash system if you run it on sub sectors that are behind the player
  424. */
  425.  
  426. void Draw_Sub_Sector(pssector cur_ss)
  427. {
  428. short cur_seg, num_segs, counter;
  429.  
  430. // do dem sprites
  431. if (cur_ss->flags & VOXEL_SSECTOR) {
  432.    Render_Voxel_Sub_Sector(cur_ss);
  433. } else {
  434. Draw_SS_Sprites(cur_ss);
  435. }
  436.  
  437. cur_seg=cur_ss->seg_start;
  438. num_segs=cur_ss->seg_end-cur_ss->seg_start+1;
  439. for (counter=0; counter<num_segs; counter++) {
  440.    if (SegVisible(Seg_List+cur_seg)) {
  441.       Draw_Seg(Seg_List+cur_seg);
  442.    } /* endif */
  443.    if (VB_EmptyList())
  444.       return;
  445.    cur_seg++;
  446. } /* endfor */
  447. }
  448.  
  449. /*
  450.    Draw_Seg
  451.    Just what it sounds like. Draws a seg. Calls Seg_Setup & Get_Intersects.
  452.    Does some vector translation
  453.    Notes: Not proven to always work. But then again, neither is nutrisweet.
  454. */
  455.  
  456. void Draw_Seg(seg * cur_seg)
  457. {
  458.  
  459.    LONG abs_proj_left, abs_proj_right;
  460.  
  461.    LONG distance_left, distance_right;
  462.  
  463.    sector * Opp_Sec;
  464.    
  465.    sidedef * cur_sd;
  466.  
  467.    pvector2 v1,v2;
  468.    vector2 vtrans1, vtrans2;
  469.  
  470.    pvb_node cur_bounds, next_bounds;
  471.  
  472.    wall_move_info low_wall, mid_wall, high_wall;
  473.  
  474.    BOOL mid_wall_exists, low_wall_exists, high_wall_exists, any_wall_exists;
  475.  
  476.    MYFIXED
  477.    end_seg_top,
  478.    end_seg_bottom,
  479.    low_seg_top,
  480.    high_seg_bottom;
  481.  
  482.    BOOL found;
  483.  
  484.    SHORT bounds_to_draw, bounds_done;
  485.  
  486.    short wall_height;
  487.  
  488.    angle_type seg_angle_diff;
  489.  
  490.    cur_bounds=VB_GetFirstNode();
  491.  
  492.    // Get the sector
  493.  
  494.    Cur_Sec=GetSecFromSeg(cur_seg);
  495.  
  496.    Assert(((Cur_Sec < Sector_List)||(Cur_Sec >= (Sector_List+Number_Of_Sectors))),
  497.         "Invalid sector in Draw_Seg");
  498.  
  499.    v1=Vector_List+cur_seg->v[0];
  500.    v2=Vector_List+cur_seg->v[1];
  501.  
  502.    // Translate Vectors
  503.    // I use y for distance, but technically it ought to be x, so I switch x and y when translated
  504.    rotate_angle=render_view_angle;
  505.  
  506.    rotate_x=(v1->x<<SHIFT) - render_x;
  507.    rotate_y=(v1->y<<SHIFT) - render_y;
  508.    vtrans1.x=FixedRotateY();
  509.    vtrans1.y=FixedRotateX();
  510.  
  511.    rotate_x=(v2->x<<SHIFT) - render_x;
  512.    rotate_y=(v2->y<<SHIFT) - render_y;
  513.    vtrans2.x=FixedRotateY();
  514.    vtrans2.y=FixedRotateX();
  515.  
  516.    // clip for lines in back of and in front of view window
  517.  
  518.    if ((vtrans1.y<=0)&&(vtrans2.y<=0))
  519.       return;
  520.  
  521.    if ((vtrans1.y>= (MAXDIS<<SHIFT) ) || (vtrans2.y>= (MAXDIS<<SHIFT) ))
  522.       return;
  523.  
  524.    // Get projected screen coordinates
  525.  
  526.    if (vtrans1.y>0) {
  527.       abs_proj_left=(fixedmd(-vtrans1.x, SCALE_FACTOR, vtrans1.y) )
  528.                 +WINDOW_MIDDLEW;
  529.    } /* endif */
  530.  
  531.    if (vtrans2.y>0) {
  532.       abs_proj_right=(fixedmd(-vtrans2.x, SCALE_FACTOR, vtrans2.y) )
  533.                 +WINDOW_MIDDLEW;
  534.    } /* endif */
  535.  
  536.    // Is this seg past the bounding window
  537.  
  538.    if (vtrans1.y>0) {
  539.       found=FALSE;
  540.       while ( (cur_bounds!=NULL) ) {
  541.          if (abs_proj_left < cur_bounds->right) {
  542.             found=TRUE;
  543.             break;
  544.          } /* endif */
  545.          cur_bounds=VB_GetNextNode(cur_bounds);
  546.       }
  547.       if (!found) {
  548.          return;
  549.       }
  550.    }
  551.  
  552.    // count number of bounding windows to draw in
  553.  
  554.    if (vtrans2.y<=0)
  555.       abs_proj_right=WINDOW_WIDTH;
  556.  
  557.    next_bounds=cur_bounds;
  558.    bounds_to_draw=0;
  559.  
  560.    while (next_bounds!=NULL) {
  561.       if (abs_proj_right <= next_bounds->left)
  562.          break;
  563.       bounds_to_draw++;
  564.       next_bounds=VB_GetNextNode(next_bounds);
  565.    } /* endwhile */
  566.  
  567.    if (bounds_to_draw==0)
  568.       return;
  569.       
  570.    Opp_Sec=GetOppSec(cur_seg);
  571.  
  572.    cur_sd=cur_seg->ld->s[cur_seg->left_sidedef];
  573.  
  574.    // Necessary to get intersections on seg
  575.  
  576.    seg_angle_diff=Get_Angle_Difference(cur_seg->angle, render_view_angle);
  577.  
  578.    Setup_Intersection(&vtrans1, &vtrans2);
  579.  
  580.    next_bounds=cur_bounds;
  581.  
  582.    // Do we have a middle texture
  583.  
  584.    if ( (cur_sd->texture_normal!=TEXTURE_NULL) ) {
  585.       mid_wall_exists=TRUE;
  586.    } else mid_wall_exists=FALSE;
  587.  
  588.    if ( (Opp_Sec!=NULL) && 
  589.       (cur_sd->texture_low!=TEXTURE_NULL) &&
  590.       (Opp_Sec->floor_height > Cur_Sec->floor_height) )
  591.       low_wall_exists=TRUE;
  592.    else low_wall_exists=FALSE;
  593.  
  594.  
  595.    if ( (Opp_Sec!=NULL) &&
  596.       (cur_sd->texture_high!=TEXTURE_NULL) &&
  597.       (Opp_Sec->ceil_height < Cur_Sec->ceil_height) )
  598.       high_wall_exists=TRUE;
  599.    else high_wall_exists=FALSE;
  600.  
  601.    any_wall_exists=(((mid_wall_exists) || (low_wall_exists) || (high_wall_exists)) ? TRUE : FALSE);
  602.  
  603.    wall_height=Cur_Sec->ceil_height-Cur_Sec->floor_height;
  604.  
  605.    if (wall_height<=0) {
  606.       return;
  607.    } /* endif */
  608.  
  609.    for (bounds_done=0; bounds_done <bounds_to_draw; bounds_done++) {
  610.  
  611.       cur_bounds=next_bounds;
  612.       next_bounds=VB_GetNextNode(next_bounds);
  613.  
  614.       Assert( ((cur_bounds < bounds) || (cur_bounds >= (bounds+WINDOW_WIDTH))),
  615.          "Attempting to draw to invalid bounds area");
  616.  
  617.       // Setup up distance and projection values we will derive line movements from
  618.  
  619.       if ( (vtrans1.y <= 0) || (abs_proj_left < cur_bounds->left) ) {
  620.          proj_left=cur_bounds->left;
  621.          distance_left=Get_Intersection_Y(cur_bounds->left);
  622.       } else {
  623.          proj_left=abs_proj_left;
  624.          distance_left=vtrans1.y;
  625.       } /* endif */
  626.  
  627.       if ( (vtrans2.y <= 0) || (abs_proj_right > cur_bounds->right) ) {
  628.          proj_right=cur_bounds->right;
  629.          distance_right=Get_Intersection_Y(cur_bounds->right);
  630.       } else {
  631.          proj_right=abs_proj_right;
  632.          distance_right=vtrans2.y;
  633.       } /* endif */
  634.  
  635.       Assert( (proj_right < proj_left), "Try to draw seg of negative length");
  636.  
  637.       Assert( ((proj_left < 0)||(proj_right<0)||(proj_left>WINDOW_WIDTH)||
  638.         (proj_right>WINDOW_WIDTH)), "Corrected seg bounds still illegal");
  639.  
  640.       if (proj_left==proj_right) {
  641.          continue;
  642.       }
  643.  
  644.       // Get distances and columns for each intersection along seg
  645.      
  646.       if (any_wall_exists)
  647.          Get_Intersects(&vtrans1, seg_angle_diff);
  648.  
  649.       // Setup mid wall. Even if there is no mid wall, these values are still used
  650.  
  651.       mid_wall.bottom_start=GetFloorScVal(Cur_Sec, distance_left);
  652.       end_seg_bottom=GetFloorScVal(Cur_Sec, distance_right);
  653.       mid_wall.bottom_increment=(end_seg_bottom-mid_wall.bottom_start)
  654.          / (proj_right-proj_left);
  655.  
  656.       mid_wall.top_start=GetCeilScVal(Cur_Sec, distance_left);
  657.       end_seg_top=GetCeilScVal(Cur_Sec, distance_right);
  658.       mid_wall.top_increment=(end_seg_top-mid_wall.top_start)
  659.          / (proj_right-proj_left);
  660.  
  661.       if (!(cur_seg->ld->attributes & CLEAR_LD)) {
  662. #ifdef CLIP
  663.          VB_CoverSection(cur_bounds, proj_left, proj_right);
  664. #endif
  665.       }
  666.       if (mid_wall_exists) {
  667.  
  668.             // Run setup procedure for the middle wall
  669.  
  670.          mid_wall.type=MID_WALL;
  671.          mid_wall.texture=cur_sd->texture_normal;
  672.          mid_wall.v_height=Cur_Sec->ceil_height-Cur_Sec->floor_height;
  673.          mid_wall.cur_bounds=cur_bounds;
  674.  
  675.          Seg_Setup(mid_wall);
  676.  
  677.       } else {
  678.  
  679.          // Setup a bottom wall
  680.  
  681.          low_wall.bottom_start=mid_wall.bottom_start;
  682.          low_wall.bottom_increment=mid_wall.bottom_increment;
  683.          low_wall.type=LOW_WALL;
  684.          low_wall.cur_bounds=cur_bounds;
  685.  
  686.          if (low_wall_exists) {
  687.             low_wall.top_start=GetFloorScVal(Opp_Sec, distance_left);
  688.             low_seg_top=GetFloorScVal(Opp_Sec, distance_right);
  689.             low_wall.top_increment=(low_seg_top - low_wall.top_start)
  690.                / (proj_right - proj_left);
  691.             low_wall.v_height=Opp_Sec->floor_height-Cur_Sec->floor_height;
  692.             low_wall.texture=cur_sd->texture_low;
  693.          } else {              
  694.             low_wall.top_start=mid_wall.bottom_start;
  695.             low_wall.top_increment=mid_wall.bottom_increment;
  696.             low_wall.v_height=0;
  697.             low_wall.texture=NULL;
  698.          } /* endif */
  699.  
  700.          Seg_Setup(low_wall);
  701.  
  702.          high_wall.top_start=mid_wall.top_start;
  703.          high_wall.top_increment=mid_wall.top_increment;
  704.          high_wall.type=HIGH_WALL;
  705.          high_wall.cur_bounds=cur_bounds;
  706.  
  707.          if (high_wall_exists) {
  708.             high_wall.bottom_start=GetCeilScVal(Opp_Sec, distance_left);
  709.             high_seg_bottom=GetCeilScVal(Opp_Sec, distance_right);
  710.             high_wall.bottom_increment=(high_seg_bottom - high_wall.bottom_start)
  711.                / (proj_right - proj_left);
  712.             high_wall.v_height=Cur_Sec->ceil_height-Opp_Sec->ceil_height;
  713.             high_wall.texture=cur_sd->texture_high;
  714.          } else {
  715.             high_wall.bottom_start=mid_wall.top_start;
  716.             high_wall.bottom_increment=mid_wall.top_increment;
  717.             high_wall.texture=NULL;
  718.             high_wall.v_height=0;
  719.          } /* endif */
  720.  
  721.          Seg_Setup(high_wall);
  722.  
  723.       }
  724.  
  725.    } /* endwhile */
  726.  
  727. }
  728.  
  729. /*
  730.   Seg_Setup
  731.   Setup wall runs that are used when drawing walls
  732.   Also manages most floor and ceiling drawing
  733.   Notes: adds to wall_runs array & wall_run_count
  734. */
  735.  
  736. void Seg_Setup(wall_move_info & mid_walls)
  737. {
  738.    ssetup_count++;
  739.  
  740.    wall_run_info * cur_wall_run;
  741.    short cur_ray;
  742.    MYFIXED mid_sum_top, mid_sum_bottom;
  743.    MYFIXED top_increment, bottom_increment;
  744.    short mid_top, mid_bottom, no_clip_top, no_clip_bottom;
  745.    short cur_win_top, cur_win_bottom;
  746.    short floor_height_diff, ceil_height_diff;
  747.    long temp_light, long_distance, base_light, lt_speed;
  748.    BOOL norm_floor, norm_ceiling, do_lower, do_upper;
  749.    long cur_column;
  750.    long cur_increment, cur_clip;
  751.    Byte * cur_light;
  752.    Byte * wall_texture;
  753.    short texture_and_width, texture_and_height;
  754.    Byte texture_width_shift;
  755.    short wall_type;
  756.    MYFIXED seg_height;
  757.    short cov_mode_start;
  758.    vb_node * cur_bounds;
  759.    BOOL covering_mode;
  760.    Ptr sec_floor_texture, sec_ceil_texture;
  761.  
  762.    wall_texture=Get_Wall_Texture(mid_walls.texture);
  763.    texture_and_width=Get_Wall_Texture_Width(mid_walls.texture)-1;
  764.    texture_and_height=Get_Wall_Texture_Height(mid_walls.texture)-1;
  765.    texture_width_shift=Get_Wall_Texture_Shift(mid_walls.texture);
  766.  
  767.    wall_type=mid_walls.type;
  768.    seg_height=mid_walls.v_height<<(SLIVER_SHIFT+W_TEX_SHIFT);
  769.  
  770.    // Get some constant lighting values
  771.  
  772.    base_light=SecLight(Cur_Sec);
  773.    lt_speed=SecLTSpeed(Cur_Sec);
  774.  
  775.    // Setup floors and ceilings;
  776.  
  777.    sec_floor_texture=Get_Floor_Texture(Cur_Sec->floor_tex);
  778.    sec_ceil_texture=Get_Floor_Texture(Cur_Sec->ceil_tex);
  779.  
  780.    floor_height_diff=render_z-Cur_Sec->floor_height;
  781.    ceil_height_diff=Cur_Sec->ceil_height-render_z;
  782.  
  783.    if ((wall_type==HIGH_WALL) || (wall_type==MID_WALL)) {
  784.  
  785.       do_upper=TRUE;
  786.  
  787.       if (ceil_height_diff>0 && sec_ceil_texture!=cur_sky_texture)
  788.          norm_ceiling=TRUE;
  789.       else norm_ceiling=FALSE;
  790.  
  791.    } else do_upper=FALSE;
  792.                                                 
  793.    if ((wall_type==LOW_WALL) || (wall_type==MID_WALL) && (!(Cur_Sec->flags & VOXEL_SECTOR))) {
  794.  
  795.       do_lower=TRUE;
  796.  
  797.       if (floor_height_diff>0 && sec_floor_texture!=cur_sky_texture)
  798.          norm_floor=TRUE;
  799.       else norm_floor=FALSE;
  800.  
  801.    } else do_lower=FALSE;
  802.  
  803.    // Set initial fixed point sums
  804.  
  805.    mid_sum_top=mid_walls.top_start; mid_sum_bottom=mid_walls.bottom_start;
  806.    top_increment=mid_walls.top_increment; bottom_increment=mid_walls.bottom_increment;
  807.  
  808.    prev_win_top=prev_wall_top=win_tops[proj_left];
  809.    prev_win_bottom=prev_wall_bottom=win_bottoms[proj_left];
  810.  
  811.    // init covering mode used to correct bounds with upper & lower textures
  812.  
  813.    covering_mode=FALSE;
  814.    cur_bounds=mid_walls.cur_bounds;
  815.  
  816.    for (cur_ray=proj_left; cur_ray<proj_right; cur_ray++) {
  817.  
  818.       // Get the short values for actual screen coordinates
  819.  
  820.       mid_top=mid_sum_top>>SHIFT;
  821.       mid_bottom=mid_sum_bottom>>SHIFT;
  822.  
  823.       // Increment fixed point sums
  824.  
  825.       mid_sum_top+=top_increment;
  826.       mid_sum_bottom+=bottom_increment;
  827.  
  828.       // Adjust against window bounds
  829.  
  830.       cur_win_top=win_tops[cur_ray];
  831.       cur_win_bottom=win_bottoms[cur_ray];
  832.  
  833.       // save non clipped bounds
  834.  
  835.       no_clip_top=mid_top;
  836.       no_clip_bottom=mid_bottom;
  837.  
  838.       Assert(no_clip_top>no_clip_bottom, "Bad Seg! at ssetup_count= " << ssetup_count);
  839.       // Adjust against window top
  840.  
  841.       if (mid_top < cur_win_top) {
  842.          mid_top=cur_win_top;
  843.       } /* endif */
  844.       if (mid_bottom < cur_win_top) {
  845.          mid_bottom=cur_win_top;
  846.       } /* endif */
  847.  
  848.       // Adjust against window bottom
  849.  
  850.       if (mid_bottom > cur_win_bottom) {
  851.          mid_bottom=cur_win_bottom;
  852.       } /* endif */
  853.       if (mid_top > cur_win_bottom) {
  854.          mid_top=cur_win_bottom;
  855.       } /* endif */
  856.  
  857.       // Do the floor and ceiling
  858.  
  859. #ifdef DO_FLOORS
  860.  
  861.       floor_ray=cur_ray;
  862.  
  863.       if (do_upper) {
  864.  
  865.          floor_texture=sec_ceil_texture;
  866.          if (norm_ceiling) {
  867.  
  868.             cur_height_diff=ceil_height_diff;
  869.  
  870.             if (prev_win_top < cur_win_top) {
  871.                floor_start=prev_win_top; floor_end=MIN(cur_win_top, prev_wall_top);
  872.                Finish_Tex();
  873.             } else {
  874.                floor_start=cur_win_top; floor_end=MIN(prev_win_top, mid_top);
  875.                Start_Tex();
  876.             }
  877.  
  878.             if (mid_top < prev_wall_top) {
  879.                floor_start=MAX(mid_top, prev_win_top); floor_end=prev_wall_top;
  880.                Finish_Tex();
  881.             } else {
  882.                floor_start=MAX(prev_wall_top, cur_win_top); floor_end=mid_top;
  883.                Start_Tex();
  884.             } /* endif */
  885.  
  886.          } else {
  887.             floor_start=cur_win_top; floor_end=mid_top;
  888.             Draw_Sky_Column();
  889.          }
  890.  
  891.          prev_win_top=cur_win_top;
  892.          prev_wall_top=mid_top;
  893.  
  894.       } /* end of if "do_upper"*/
  895.  
  896.       if (do_lower) {
  897.  
  898.          floor_texture=sec_floor_texture;
  899.          
  900.          if ( norm_floor ) {
  901.            
  902.             cur_height_diff=floor_height_diff;
  903.  
  904.             if (cur_win_bottom < prev_win_bottom) {
  905.                floor_start=MAX(cur_win_bottom, prev_wall_bottom); floor_end=prev_win_bottom;
  906.                Finish_Tex();
  907.             } else {
  908.                floor_start=MAX(mid_bottom, prev_win_bottom); floor_end=cur_win_bottom;
  909.                Start_Tex();
  910.             }
  911.  
  912.             if (prev_wall_bottom < mid_bottom) {
  913.                floor_start=prev_wall_bottom; floor_end=MIN(prev_win_bottom, mid_bottom);
  914.                Finish_Tex();
  915.             } else {
  916.                floor_start=mid_bottom; floor_end=MIN(prev_wall_bottom, cur_win_bottom);
  917.                Start_Tex();
  918.             } /* endif */
  919.  
  920.          } else {
  921.             floor_start=mid_bottom; floor_end=cur_win_bottom;
  922.             Draw_Sky_Column();
  923.          }
  924.  
  925.          prev_win_bottom=cur_win_bottom;
  926.          prev_wall_bottom=mid_bottom;
  927.  
  928.       } /* end of if "do_lower" */
  929.  
  930. #endif
  931.  
  932. #ifdef CLIPVERT
  933.  
  934.       // Update bounding windows
  935.  
  936.       //Note: Since upper and lower textures define the difference between two
  937.       //sectors, you bound the top of a window with an upper texture's bottom,
  938.       //and the bottom of a window with a lower texture's top
  939.  
  940.       if (wall_type == MID_WALL) {
  941.          win_tops[cur_ray]=mid_top;
  942.          win_bottoms[cur_ray]=mid_bottom;
  943.       }
  944.  
  945.       if (wall_type == LOW_WALL) {
  946.           win_bottoms[cur_ray]=mid_top;
  947. #ifdef CHECK_HIGH_LOW_CLIP_OUT
  948.           if (covering_mode) {
  949.              if (no_clip_top > cur_win_top) {
  950.                 VB_CoverSection(cur_bounds, cov_mode_start, cur_ray);
  951.                 covering_mode=FALSE;
  952.                 }
  953.           } else {
  954.              if (no_clip_top <= cur_win_top) {
  955.                 cov_mode_start=cur_ray;
  956.                 covering_mode=TRUE;
  957.              }
  958.           }
  959. #endif
  960.       }
  961.  
  962.       if (wall_type == HIGH_WALL) {
  963.           win_tops[cur_ray]=mid_bottom;
  964. #ifdef CHECK_HIGH_LOW_CLIP_OUT
  965.           if (covering_mode) {
  966.              if (no_clip_bottom < cur_win_bottom) {
  967.                 VB_CoverSection(cur_bounds, cov_mode_start, cur_ray);
  968.                 covering_mode=FALSE;
  969.                 }
  970.           } else {
  971.              if (no_clip_bottom >= cur_win_bottom) {
  972.                 cov_mode_start=cur_ray;
  973.                 covering_mode=TRUE;
  974.              }
  975.           }
  976. #endif
  977.       }
  978.  
  979. #endif
  980.  
  981.       // Do we even have a wall?
  982.  
  983.       if (mid_top >= mid_bottom)
  984.          continue;
  985.  
  986.       // Setup light & column
  987.  
  988.       cur_increment=fixeddiv(seg_height, mid_sum_bottom-mid_sum_top);
  989.  
  990.       cur_clip=fixedmult(cur_increment, (mid_top<<SHIFT)-mid_sum_top);
  991.  
  992.       long_distance=intersects[cur_ray].distance>>SHIFT;
  993.  
  994.       temp_light=base_light-(long_distance >> lt_speed);
  995.       if (temp_light <0) temp_light=0;
  996.       if (temp_light > MAX_LIGHT) temp_light=MAX_LIGHT;
  997.  
  998.       cur_light=pal_table[temp_light];
  999.  
  1000.       cur_column=intersects[cur_ray].xpos;
  1001.  
  1002.       if (cur_column<0) 
  1003.          cur_column=texture_and_width-((-cur_column)&texture_and_width);
  1004.       else cur_column&=texture_and_width;
  1005.  
  1006.       // And setup wall run
  1007.  
  1008.       if (wall_run_count>=MAX_WALL_RUNS) {
  1009.          break;
  1010.       } /* endif */
  1011.  
  1012.       cur_wall_run=wall_runs+wall_run_count;
  1013.       wall_run_count++;
  1014.  
  1015.       cur_wall_run->width_shift=texture_width_shift;
  1016.       cur_wall_run->bound_val=texture_and_height;
  1017.       cur_wall_run->texture=wall_texture;
  1018.       cur_wall_run->top=mid_top;
  1019.       cur_wall_run->scale=mid_bottom-mid_top;
  1020.       cur_wall_run->ray=cur_ray;
  1021.       cur_wall_run->increment=cur_increment;
  1022.       cur_wall_run->clip=cur_clip;
  1023.       cur_wall_run->light=cur_light;
  1024.       cur_wall_run->column=(Byte)cur_column;
  1025.  
  1026.    } /* endfor */
  1027.  
  1028. #ifdef CHECK_HIGH_LOW_CLIP_OUT
  1029. if (covering_mode)
  1030.    VB_CoverSection(cur_bounds, cov_mode_start, proj_right);
  1031. #endif
  1032.  
  1033. if (do_upper && norm_ceiling) {
  1034.    cur_height_diff=ceil_height_diff;
  1035.    floor_texture=sec_ceil_texture;
  1036.    floor_ray=proj_right;
  1037.    floor_start=prev_win_top; floor_end=prev_wall_top;
  1038.    Finish_Tex();
  1039. } /* endif */
  1040.  
  1041. if (do_lower && norm_floor) {
  1042.    cur_height_diff=floor_height_diff;
  1043.    floor_texture=sec_floor_texture;
  1044.    floor_ray=proj_right;
  1045.    floor_start=prev_wall_bottom; floor_end=prev_win_bottom;
  1046.    Finish_Tex();
  1047. } /* endif */
  1048.  
  1049. }
  1050.  
  1051. /*
  1052.    Get_Intersects
  1053.    This is the third time I am writing this routine. I do not know why I keep losing it
  1054.    In any case, this routine gets the intersection values along the seg for each ray
  1055.    Notes: It modifies global array intersects and require setup intersection to have been
  1056.    called previously
  1057. */
  1058.  
  1059. void Get_Intersects(pvector2 base_v, angle_type angle_diff)
  1060. {
  1061.  
  1062.    intersect_struct * cur_intersect;
  1063.    long test_angle;
  1064.  
  1065.    // Decide whether deriving columns from x or y coordinate is more accurate
  1066.  
  1067.    test_angle=angle_diff;
  1068.    if (test_angle > ANGLE_180) test_angle-=ANGLE_180;
  1069.  
  1070.    BOOL is_y_angle=( ((test_angle <= ANGLE_45) || (test_angle >=ANGLE_135)) ? TRUE : FALSE);
  1071.  
  1072.    // based on that decision, run two different loops to get distance and column values
  1073.  
  1074.    if (is_y_angle) {
  1075.       MYFIXED base_y, subs_y;
  1076.  
  1077.       base_y=base_v->y;
  1078.  
  1079.       for (short cur_ray=proj_left; cur_ray < proj_right; cur_ray++) {
  1080.          
  1081.          cur_intersect=intersects+cur_ray;
  1082.  
  1083.          cur_intersect->distance=Get_Intersection_Y(cur_ray);
  1084.  
  1085.          Assert((cur_intersect->distance <= 0), "Negative column distance");
  1086.  
  1087.          subs_y=cur_intersect->distance-base_y;
  1088.                              
  1089.          cur_intersect->xpos=convtoLONG(fixeddiv(subs_y << W_TEX_SHIFT,
  1090.                 rcos_table[angle_diff]));
  1091.  
  1092.          cur_intersect->increment=fixedmult(cur_intersect->distance, y_inv_trans);
  1093.  
  1094.       } /* endfor */
  1095.    } else {
  1096.  
  1097.       MYFIXED base_x, subs_x;
  1098.  
  1099.       base_x=base_v->x;
  1100.  
  1101.       for (short cur_ray=proj_left; cur_ray < proj_right; cur_ray++) {
  1102.          
  1103.          cur_intersect=intersects+cur_ray;
  1104.  
  1105.          cur_intersect->distance=Get_Intersection_Y(cur_ray);
  1106.  
  1107.          Assert((cur_intersect->distance <=0), "Negative column distance");
  1108.  
  1109.          subs_x=Get_Intersection_X()-base_x;
  1110.  
  1111.          cur_intersect->xpos=convtoLONG(fixeddiv(subs_x << W_TEX_SHIFT,
  1112.                 rsin_table[angle_diff]));
  1113.  
  1114.          cur_intersect->increment=fixedmult(cur_intersect->distance, y_inv_trans);
  1115.  
  1116.       } /* endfor */
  1117.  
  1118.    } /* endif */
  1119.  
  1120. }
  1121.  
  1122. void Draw_Sub_Sector_Setup()
  1123. {                    
  1124.    intersects=(intersect_struct *)NewPtr(Get_Phys_Screen_Width() * sizeof(intersect_struct));
  1125.    floor_offsets_x=(MYFIXED *)NewPtr((Get_Phys_Screen_Width()) * sizeof(MYFIXED));
  1126.    floor_offsets_y=(MYFIXED *)NewPtr((Get_Phys_Screen_Width()) * sizeof(MYFIXED));
  1127. }
  1128.  
  1129. void Draw_Sub_Sector_Close()
  1130. {
  1131.    DelPtr(intersects);
  1132.    DelPtr(floor_offsets_x);
  1133.    DelPtr(floor_offsets_y);
  1134. }
  1135.  
  1136. /*
  1137. Ok, if you had the patience to read all the way down here, I feel obligated
  1138. to tell you that an international communist revolution is going on right
  1139. now. You are the only one who can save America. I am now dead.
  1140.  
  1141. Some Tips:
  1142.  
  1143. 1. Trust no one, and shoot most people on sight.
  1144. 2. Try to disregard issues of morality, and instead protect national
  1145.    security.
  1146. 3. Shoot first, then ask questions.
  1147. 4. Your enemy has no respect whatsoever for human life.
  1148.  
  1149. Right now, I'm being taken in by the communist leader, to be brainwashed.
  1150. Except that I'm already dead. So this is somewhat irrelevant.
  1151. Some details on the revolution:
  1152.  
  1153. 1. The communist goal is to make the U.S. capsize. They are going to
  1154. bomb only one side of the U.S. in hopes that they can make the weight
  1155. distribution of the country so lopsided that it tips over.
  1156.  
  1157. 2. They will drop pianos on everyone in Cleveland because the strained
  1158. Soviet budget cannot afford missiles.
  1159.  
  1160. 3. Soviets claim to have a weapon with the power to wipe out an entire
  1161. continent. As proof of this, they will demonstrate the weapon on the
  1162. plains of Siberia.
  1163.  
  1164. 4. The Soviet amphibious forces are out of date. However, they have
  1165. discovered that a large group of hypnotized frogs makes for an effective
  1166. amphibian weapon.
  1167.  
  1168. 5. They will shoot Jay Leno and give Letterman the NBC spot he deserves.
  1169. Note: We actually want them to succeed here
  1170.  
  1171. In any case, I have now been knocked unconcious by an unknown assailant.
  1172. Except that I was already taken in by the communist leader. And that
  1173. I'm already dead. But don't worry about me. Save your country. You'll
  1174. be paid handsomely.
  1175.  
  1176. */
  1177.