r_bsp.c
上传用户:xuyinpeng
上传日期:2021-05-12
资源大小:455k
文件大小:12k
源码类别:

射击游戏

开发平台:

Visual C++

  1. // Emacs style mode select   -*- C++ -*- 
  2. //-----------------------------------------------------------------------------
  3. //
  4. // $Id:$
  5. //
  6. // Copyright (C) 1993-1996 by id Software, Inc.
  7. //
  8. // This source is available for distribution and/or modification
  9. // only under the terms of the DOOM Source Code License as
  10. // published by id Software. All rights reserved.
  11. //
  12. // The source is distributed in the hope that it will be useful,
  13. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. // FITNESS FOR A PARTICULAR PURPOSE. See the DOOM Source Code License
  15. // for more details.
  16. //
  17. // $Log:$
  18. //
  19. // DESCRIPTION:
  20. // BSP traversal, handling of LineSegs for rendering.
  21. //
  22. //-----------------------------------------------------------------------------
  23. static const char
  24. rcsid[] = "$Id: r_bsp.c,v 1.4 1997/02/03 22:45:12 b1 Exp $";
  25. #include "doomdef.h"
  26. #include "m_bbox.h"
  27. #include "i_system.h"
  28. #include "r_main.h"
  29. #include "r_plane.h"
  30. #include "r_things.h"
  31. // State.
  32. #include "doomstat.h"
  33. #include "r_state.h"
  34. //#include "r_local.h"
  35. char MsgText[256];
  36. void WriteDebug(char *);
  37. seg_t* curline;
  38. side_t* sidedef;
  39. line_t* linedef;
  40. sector_t* frontsector;
  41. sector_t* backsector;
  42. drawseg_t drawsegs[MAXDRAWSEGS];
  43. drawseg_t* ds_p;
  44. void
  45. R_StoreWallRange
  46. ( int start,
  47.   int stop );
  48. //
  49. // R_ClearDrawSegs
  50. //
  51. void R_ClearDrawSegs (void)
  52. {
  53.     ds_p = drawsegs;
  54. }
  55. //
  56. // ClipWallSegment
  57. // Clips the given range of columns
  58. // and includes it in the new clip list.
  59. //
  60. typedef struct
  61. {
  62.     int first;
  63.     int last;
  64.     
  65. } cliprange_t;
  66. #define MAXSEGS 32
  67. // newend is one past the last valid seg
  68. cliprange_t* newend;
  69. cliprange_t solidsegs[MAXSEGS];
  70. //
  71. // R_ClipSolidWallSegment
  72. // Does handle solid walls,
  73. //  e.g. single sided LineDefs (middle texture)
  74. //  that entirely block the view.
  75. // 
  76. void
  77. R_ClipSolidWallSegment
  78. ( int first,
  79.   int last )
  80. {
  81.     cliprange_t* next;
  82.     cliprange_t* start;
  83.     // Find the first range that touches the range
  84.     //  (adjacent pixels are touching).
  85.     start = solidsegs;
  86.     while (start->last < first-1)
  87. start++;
  88.     if (first < start->first)
  89.     {
  90. if (last < start->first-1)
  91. {
  92.     // Post is entirely visible (above start),
  93.     //  so insert a new clippost.
  94.     R_StoreWallRange (first, last);
  95.     next = newend;
  96.     newend++;
  97.     
  98.     while (next != start)
  99.     {
  100. *next = *(next-1);
  101. next--;
  102.     }
  103.     next->first = first;
  104.     next->last = last;
  105.     return;
  106. }
  107. // There is a fragment above *start.
  108. R_StoreWallRange (first, start->first - 1);
  109. // Now adjust the clip size.
  110. start->first = first;
  111.     }
  112.     // Bottom contained in start?
  113.     if (last <= start->last)
  114. return;
  115.     next = start;
  116.     while (last >= (next+1)->first-1)
  117.     {
  118. // There is a fragment between two posts.
  119. R_StoreWallRange (next->last + 1, (next+1)->first - 1);
  120. next++;
  121. if (last <= next->last)
  122. {
  123.     // Bottom is contained in next.
  124.     // Adjust the clip size.
  125.     start->last = next->last;
  126.     goto crunch;
  127. }
  128.     }
  129.     // There is a fragment after *next.
  130.     R_StoreWallRange (next->last + 1, last);
  131.     // Adjust the clip size.
  132.     start->last = last;
  133.     // Remove start+1 to next from the clip list,
  134.     // because start now covers their area.
  135.   crunch:
  136.     if (next == start)
  137.     {
  138. // Post just extended past the bottom of one post.
  139. return;
  140.     }
  141.     
  142.     while (next++ != newend)
  143.     {
  144. // Remove a post.
  145. *++start = *next;
  146.     }
  147.     newend = start+1;
  148. }
  149. //
  150. // R_ClipPassWallSegment
  151. // Clips the given range of columns,
  152. //  but does not includes it in the clip list.
  153. // Does handle windows,
  154. //  e.g. LineDefs with upper and lower texture.
  155. //
  156. void R_ClipPassWallSegment( int first, int last )
  157.    {
  158.     cliprange_t* start;
  159.     // Find the first range that touches the range
  160.     //  (adjacent pixels are touching).
  161.     start = solidsegs;
  162.     while (start->last < first-1)
  163.         start++;
  164.     if (first < start->first)
  165.        {
  166.         if (last < start->first-1)
  167.            {
  168.             // Post is entirely visible (above start).
  169.             R_StoreWallRange (first, last);
  170.             return;
  171.            }
  172.         // There is a fragment above *start.
  173.         R_StoreWallRange (first, start->first - 1);
  174.        }
  175.     // Bottom contained in start?
  176.     if (last <= start->last)
  177.    return;
  178.     while (last >= (start+1)->first-1)
  179.        {
  180.         // There is a fragment between two posts.
  181.         R_StoreWallRange (start->last + 1, (start+1)->first - 1);
  182.         start++;
  183.         if (last <= start->last)
  184.             return;
  185.        }
  186.     // There is a fragment after *next.
  187.     R_StoreWallRange (start->last + 1, last);
  188. }
  189. //
  190. // R_ClearClipSegs
  191. //
  192. void R_ClearClipSegs (void)
  193. {
  194.     solidsegs[0].first = -(0x7fffffff);
  195.     solidsegs[0].last = -1;
  196.     solidsegs[1].first = viewwidth;
  197.     solidsegs[1].last = 0x7fffffff;
  198.     newend = solidsegs+2;
  199. }
  200. //
  201. // R_AddLine
  202. // Clips the given segment
  203. // and adds any visible pieces to the line list.
  204. //
  205. void R_AddLine (seg_t* line)
  206.    {
  207.     int x1;
  208.     int x2;
  209.     angle_t angle1;
  210.     angle_t angle2;
  211.     angle_t span;
  212.     angle_t tspan;
  213.     
  214.     curline = line;
  215.     // OPTIMIZE: quickly reject orthogonal back sides.
  216.     angle1 = R_PointToAngle (line->v1->x, line->v1->y);
  217.     angle2 = R_PointToAngle (line->v2->x, line->v2->y);
  218.     
  219.     // Clip to view edges.
  220.     // OPTIMIZE: make constant out of 2*clipangle (FIELDOFVIEW).
  221.     span = angle1 - angle2;
  222.     
  223.     // Back side? I.e. backface culling?
  224.     if (span >= ANG180)
  225.        {
  226.         //WriteDebug("Back face culled...n");
  227.         return;
  228.        }
  229.     // Global angle needed by segcalc.
  230.     rw_angle1 = angle1;
  231.     angle1 -= viewangle;
  232.     angle2 -= viewangle;
  233.     tspan = angle1 + clipangle;
  234.     if (tspan > 2*clipangle)
  235.        {
  236.         tspan -= 2*clipangle;
  237.         // Totally off the left edge?
  238.         if (tspan >= span)
  239.            {
  240.             //WriteDebug("Off the left edge...n");
  241.             return;
  242.            }
  243.     angle1 = clipangle;
  244.        }
  245.     tspan = clipangle - angle2;
  246.     if (tspan > 2*clipangle)
  247.        {
  248.         tspan -= 2*clipangle;
  249.         // Totally off the left edge?
  250.         if (tspan >= span)
  251.            {
  252.             //WriteDebug("Off the left edge...n");
  253.             return;
  254.            }
  255.         angle2 = (clipangle * -1);
  256.        }
  257.     
  258.     // The seg is in the view range,
  259.     // but not necessarily visible.
  260.     angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT;
  261.     angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT;
  262.     x1 = viewangletox[angle1];
  263.     x2 = viewangletox[angle2];
  264.     // Does not cross a pixel?
  265.     if (x1 == x2)
  266.        {
  267.         //WriteDebug("No pixel spanned...n");
  268.         return;
  269.        }
  270.     backsector = line->backsector;
  271.     // Single sided line?
  272.     if (!backsector)
  273.        {
  274.         //WriteDebug("Wall...n");
  275.         goto clipsolid;
  276.        }
  277.     // Closed door.
  278.     if (backsector->ceilingheight <= frontsector->floorheight || backsector->floorheight >= frontsector->ceilingheight)
  279.        {
  280.         //WriteDebug("Closed door...n");
  281.         goto clipsolid;
  282.        }
  283.     // Window.
  284.     if (backsector->ceilingheight != frontsector->ceilingheight || backsector->floorheight != frontsector->floorheight)
  285.        {
  286.         //WriteDebug("Window (portal)...n");
  287.         goto clippass;
  288.        }
  289.     // Reject empty lines used for triggers and special events.
  290.     // Identical floor and ceiling on both sides,
  291.     // identical light levels on both sides,
  292.     // and no middle texture.
  293.     if (backsector->ceilingpic == frontsector->ceilingpic && backsector->floorpic == frontsector->floorpic &&
  294.         backsector->lightlevel == frontsector->lightlevel && curline->sidedef->midtexture == 0)
  295.        {
  296.         //WriteDebug("Trip line...n");
  297.         return;
  298.        }
  299.     clippass:
  300.        R_ClipPassWallSegment (x1, x2-1);
  301.        return;
  302.     clipsolid:
  303.        R_ClipSolidWallSegment (x1, x2-1);
  304.        return;
  305.    }
  306. //
  307. // R_CheckBBox
  308. // Checks BSP node/subtree bounding box.
  309. // Returns true
  310. //  if some part of the bbox might be visible.
  311. //
  312. int checkcoord[12][4] =
  313. {
  314.     {3,0,2,1},
  315.     {3,0,2,0},
  316.     {3,1,2,0},
  317.     {0},
  318.     {2,0,2,1},
  319.     {0,0,0,0},
  320.     {3,1,3,0},
  321.     {0},
  322.     {2,0,3,1},
  323.     {2,1,3,1},
  324.     {2,1,3,0}
  325. };
  326. boolean R_CheckBBox (fixed_t* bspcoord)
  327. {
  328.     int boxx;
  329.     int boxy;
  330.     int boxpos;
  331.     fixed_t x1;
  332.     fixed_t y1;
  333.     fixed_t x2;
  334.     fixed_t y2;
  335.     
  336.     angle_t angle1;
  337.     angle_t angle2;
  338.     angle_t span;
  339.     angle_t tspan;
  340.     
  341.     cliprange_t* start;
  342.     int sx1;
  343.     int sx2;
  344.     
  345.     // Find the corners of the box
  346.     // that define the edges from current viewpoint.
  347.     if (viewx <= bspcoord[BOXLEFT])
  348. boxx = 0;
  349.     else if (viewx < bspcoord[BOXRIGHT])
  350. boxx = 1;
  351.     else
  352. boxx = 2;
  353.     if (viewy >= bspcoord[BOXTOP])
  354. boxy = 0;
  355.     else if (viewy > bspcoord[BOXBOTTOM])
  356. boxy = 1;
  357.     else
  358. boxy = 2;
  359.     boxpos = (boxy<<2)+boxx;
  360.     if (boxpos == 5)
  361. return true;
  362.     x1 = bspcoord[checkcoord[boxpos][0]];
  363.     y1 = bspcoord[checkcoord[boxpos][1]];
  364.     x2 = bspcoord[checkcoord[boxpos][2]];
  365.     y2 = bspcoord[checkcoord[boxpos][3]];
  366.     
  367.     // check clip list for an open space
  368.     angle1 = R_PointToAngle (x1, y1) - viewangle;
  369.     angle2 = R_PointToAngle (x2, y2) - viewangle;
  370.     span = angle1 - angle2;
  371.     // Sitting on a line?
  372.     if (span >= ANG180)
  373. return true;
  374.     
  375.     tspan = angle1 + clipangle;
  376.     if (tspan > 2*clipangle)
  377.     {
  378. tspan -= 2*clipangle;
  379. // Totally off the left edge?
  380. if (tspan >= span)
  381.     return false;
  382. angle1 = clipangle;
  383.     }
  384.     tspan = clipangle - angle2;
  385.     if (tspan > 2*clipangle)
  386.     {
  387. tspan -= 2*clipangle;
  388. // Totally off the left edge?
  389. if (tspan >= span)
  390.     return false;
  391. angle2 = (clipangle * -1);
  392.     }
  393.     // Find the first clippost
  394.     //  that touches the source post
  395.     //  (adjacent pixels are touching).
  396.     angle1 = (angle1+ANG90)>>ANGLETOFINESHIFT;
  397.     angle2 = (angle2+ANG90)>>ANGLETOFINESHIFT;
  398.     sx1 = viewangletox[angle1];
  399.     sx2 = viewangletox[angle2];
  400.     // Does not cross a pixel.
  401.     if (sx1 == sx2)
  402. return false;
  403.     sx2--;
  404.     start = solidsegs;
  405.     while (start->last < sx2)
  406. start++;
  407.     
  408.     if (sx1 >= start->first
  409. && sx2 <= start->last)
  410.     {
  411. // The clippost contains the new span.
  412. return false;
  413.     }
  414.     return true;
  415. }
  416. //
  417. // R_Subsector
  418. // Determine floor/ceiling planes.
  419. // Add sprites of things in sector.
  420. // Draw one or more line segments.
  421. //
  422. void R_Subsector (int num)
  423. {
  424.     int count;
  425.     seg_t* line;
  426.     subsector_t* sub;
  427. #ifdef RANGECHECK
  428.     if (num >= numsubsectors)
  429.     I_Error ("R_Subsector: ss %i with numss = %i", num, numsubsectors);
  430. #endif
  431.     sscount++;
  432.     sub = &subsectors[num];
  433.     frontsector = sub->sector;
  434.     count = sub->numlines;
  435.     line = &segs[sub->firstline];
  436.     if (frontsector->floorheight < viewz)
  437.        {
  438.         floorplane = R_FindPlane (frontsector->floorheight, frontsector->floorpic, frontsector->lightlevel);
  439.        }
  440.     else
  441.         floorplane = NULL;
  442.   
  443.     if (frontsector->ceilingheight > viewz || frontsector->ceilingpic == skyflatnum)
  444.        {
  445.         ceilingplane = R_FindPlane (frontsector->ceilingheight, frontsector->ceilingpic, frontsector->lightlevel);
  446.        }
  447.     else
  448.         ceilingplane = NULL;
  449.     R_AddSprites (frontsector);
  450.     while (count--)
  451.        {
  452.         R_AddLine (line);
  453.         line++;
  454.        }
  455.    }
  456. //
  457. // RenderBSPNode
  458. // Renders all subsectors below a given node,
  459. //  traversing subtree recursively.
  460. // Just call with BSP root.
  461. void R_RenderBSPNode (int bspnum)
  462.    {
  463.     node_t* bsp;
  464.     int side;
  465.     // Found a subsector?
  466.     if (bspnum & NF_SUBSECTOR)
  467.        {
  468.         if (bspnum == -1)
  469.             R_Subsector (0);
  470.         else
  471.             R_Subsector (bspnum&(~NF_SUBSECTOR));
  472.         return;
  473.        }
  474.     bsp = &nodes[bspnum];
  475.     
  476.     // Decide which side the view point is on.
  477.     side = R_PointOnSide(viewx, viewy, bsp);
  478.     // Recursively divide front space.
  479.     R_RenderBSPNode (bsp->children[side]); 
  480.     // Possibly divide back space.
  481.     if (R_CheckBBox (bsp->bbox[side^1]))
  482. R_RenderBSPNode (bsp->children[side^1]);
  483. }