Subversion Repositories Games.Descent

Rev

Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Portions of this file are copyright Rebirth contributors and licensed as
  3.  * described in COPYING.txt.
  4.  * Portions of this file are copyright Parallax Software and licensed
  5.  * according to the Parallax license below.
  6.  * See COPYING.txt for license details.
  7.  
  8. THE COMPUTER CODE CONTAINED HEREIN IS THE SOLE PROPERTY OF PARALLAX
  9. SOFTWARE CORPORATION ("PARALLAX").  PARALLAX, IN DISTRIBUTING THE CODE TO
  10. END-USERS, AND SUBJECT TO ALL OF THE TERMS AND CONDITIONS HEREIN, GRANTS A
  11. ROYALTY-FREE, PERPETUAL LICENSE TO SUCH END-USERS FOR USE BY SUCH END-USERS
  12. IN USING, DISPLAYING,  AND CREATING DERIVATIVE WORKS THEREOF, SO LONG AS
  13. SUCH USE, DISPLAY OR CREATION IS FOR NON-COMMERCIAL, ROYALTY OR REVENUE
  14. FREE PURPOSES.  IN NO EVENT SHALL THE END-USER USE THE COMPUTER CODE
  15. CONTAINED HEREIN FOR REVENUE-BEARING PURPOSES.  THE END-USER UNDERSTANDS
  16. AND AGREES TO THE TERMS HEREIN AND ACCEPTS THE SAME BY USE OF THIS FILE.
  17. COPYRIGHT 1993-1998 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  18. */
  19.  
  20. /*
  21.  *
  22.  * Med drawing functions.
  23.  *
  24.  */
  25.  
  26. #include <algorithm>
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <stdarg.h>
  30. #include <string.h>
  31. #include "inferno.h"
  32. #include "segment.h"
  33. #include "segpoint.h"
  34. #include "gameseg.h"
  35. #include "gr.h"
  36. #include "ui.h"
  37. #include "editor/editor.h"
  38. #include "editor/esegment.h"
  39. #include "wall.h"
  40. #include "switch.h"
  41. #include "key.h"
  42. #include "mouse.h"
  43. #include "dxxerror.h"
  44. #include "medlisp.h"
  45. #include "u_mem.h"
  46. #include "render.h"
  47. #include "game.h"
  48. #include "kdefs.h"
  49. #include "func.h"
  50. #include "textures.h"
  51. #include "screens.h"
  52. #include "texmap.h"
  53. #include "object.h"
  54. #include "fuelcen.h"
  55. #include "meddraw.h"
  56. #include "d_enumerate.h"
  57. #include "d_range.h"
  58. #include "compiler-range_for.h"
  59. #include "segiter.h"
  60. #include "d_range.h"
  61. #include "d_zip.h"
  62.  
  63. #if DXX_USE_OGL
  64. #include "ogl_init.h"
  65. #endif
  66.  
  67. using std::min;
  68.  
  69. //      Colors used in editor for indicating various kinds of segments.
  70. #define SELECT_COLOR            BM_XRGB( 63/2 , 41/2 ,  0/2)
  71. #define FOUND_COLOR                     BM_XRGB(  0/2 , 30/2 , 45/2)
  72. #define WARNING_COLOR           BM_XRGB( 63/2 ,  0/2 ,  0/2)
  73. #define AXIS_COLOR                      BM_XRGB( 63/2 ,  0/2 , 63/2)
  74. #define PLAINSEG_COLOR          BM_XRGB( 45/2 , 45/2 , 45/2)
  75. #define MARKEDSEG_COLOR BM_XRGB(  0/2 , 63/2 ,  0/2)
  76. #define MARKEDSIDE_COLOR        BM_XRGB(  0/2 , 63/2 , 63/2)
  77. #define CURSEG_COLOR            BM_XRGB( 63/2 , 63/2 , 63/2)
  78. #define CURSIDE_COLOR           BM_XRGB( 63/2 , 63/2 ,  0/2)
  79. #define CUREDGE_COLOR           BM_XRGB(  0   , 63/2 ,  0  )
  80. #define GROUPSEG_COLOR          BM_XRGB(         0/2 ,  0/2 , 63/2)
  81. #define  GROUPSIDE_COLOR        BM_XRGB(        63/2 ,  0/2 , 45/2)
  82. #define         GROUP_COLOR                     BM_XRGB(  0/2 , 45/2 ,  0/2)   
  83. #define ROBOT_COLOR                     BM_XRGB( 31   ,  0   ,  0  )
  84. #define PLAYER_COLOR            BM_XRGB(  0   ,  0   , 31  )
  85.  
  86. constexpr std::integral_constant<unsigned, MAX_VERTICES * 4> MAX_EDGES{};
  87.  
  88. static int     Search_mode=0;                      //if true, searching for segments at given x,y
  89. static int Search_x,Search_y;
  90. static int      Automap_test=0;         //      Set to 1 to show wireframe in automap mode.
  91.  
  92. static void draw_seg_objects(grs_canvas &canvas, const unique_segment &seg)
  93. {
  94.         auto &Objects = LevelUniqueObjectState.Objects;
  95.         auto &vcobjptridx = Objects.vcptridx;
  96.         range_for (const auto obj, objects_in(seg, vcobjptridx, vcsegptr))
  97.         {
  98.                 auto sphere_point = g3_rotate_point(obj->pos);
  99.                 const uint8_t color = (obj->type == OBJ_PLAYER && static_cast<icobjptridx_t::index_type>(obj) > 0)
  100.                         ? BM_XRGB(0,  25, 0)
  101.                         : (obj == ConsoleObject
  102.                                 ? PLAYER_COLOR
  103.                                 : ROBOT_COLOR
  104.                         );
  105.                 g3_draw_sphere(canvas, sphere_point, obj->size, color);
  106.         }
  107. }
  108.  
  109. #if DXX_USE_OGL
  110. #define draw_line(C,P0,P1,c)    draw_line(P0,P1,c)
  111. #define draw_segment(C,S,c)     draw_segment(S,c)
  112. #define draw_listed_segments(C,S,c)     draw_listed_segments(S,c)
  113. #endif
  114. static void draw_line(grs_canvas &canvas, const unsigned pnum0, const unsigned pnum1, const color_palette_index color)
  115. {
  116.         g3_draw_line(canvas, Segment_points[pnum0], Segment_points[pnum1], color);
  117. }
  118.  
  119. // ----------------------------------------------------------------------------
  120. static void draw_segment(grs_canvas &canvas, const shared_segment &seg, const color_palette_index color)
  121. {
  122.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  123.         auto &Vertices = LevelSharedVertexState.get_vertices();
  124.         if (seg.segnum == segment_none)         //this segment doesn't exitst
  125.                 return;
  126.  
  127.         auto &svp = seg.verts;
  128.         auto &vcvertptr = Vertices.vcptr;
  129.         if (!rotate_list(vcvertptr, svp).uand)
  130.         {               //all off screen?
  131.                 range_for (const unsigned i, xrange(4u))
  132.                         draw_line(canvas, svp[i], svp[i+4], color);
  133.  
  134.                 range_for (const unsigned i, xrange(3u))
  135.                 {
  136.                         draw_line(canvas, svp[i], svp[i+1], color);
  137.                         draw_line(canvas, svp[i+4], svp[i+4+1], color);
  138.                 }
  139.  
  140.                 draw_line(canvas, svp[0], svp[3], color);
  141.                 draw_line(canvas, svp[4], svp[3+4], color);
  142.         }
  143. }
  144.  
  145. //for looking for segment under a mouse click
  146. static void check_segment(const vmsegptridx_t seg)
  147. {
  148.         auto &svp = seg->verts;
  149.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  150.         auto &Vertices = LevelSharedVertexState.get_vertices();
  151.         auto &vcvertptr = Vertices.vcptr;
  152.         if (!rotate_list(vcvertptr, svp).uand)
  153.         {               //all off screen?
  154. #if DXX_USE_OGL
  155.                 g3_end_frame();
  156. #endif
  157.                 {
  158.                 uint8_t color = 0;
  159.                 gr_pixel(grd_curcanv->cv_bitmap, Search_x, Search_y, color);    //set our search pixel to color zero
  160.                 }
  161. #if DXX_USE_OGL
  162.                 g3_start_frame(*grd_curcanv);
  163. #endif
  164.                 {
  165.                 const uint8_t color = 1;
  166.                 //and render in color one
  167.  
  168.                 range_for (auto &fn, Side_to_verts)
  169.                 {
  170.                         std::array<cg3s_point *, 3> vert_list;
  171.                         vert_list[0] = &Segment_points[seg->verts[fn[0]]];
  172.                         vert_list[1] = &Segment_points[seg->verts[fn[1]]];
  173.                         vert_list[2] = &Segment_points[seg->verts[fn[2]]];
  174.                         g3_check_and_draw_poly(*grd_curcanv, vert_list, color);
  175.  
  176.                         vert_list[1] = &Segment_points[seg->verts[fn[2]]];
  177.                         vert_list[2] = &Segment_points[seg->verts[fn[3]]];
  178.                         g3_check_and_draw_poly(*grd_curcanv, vert_list, color);
  179.                 }
  180.                 }
  181.  
  182.                 if (gr_ugpixel(grd_curcanv->cv_bitmap,Search_x,Search_y) == 1)
  183.                  {
  184.                                          Found_segs.emplace_back(seg);
  185.                  }
  186.         }
  187. }
  188.  
  189. // ----------------------------------------------------------------------------
  190. static void draw_seg_side(const shared_segment &seg, const unsigned side, const color_palette_index color)
  191. {
  192.         auto &svp = seg.verts;
  193.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  194.         auto &Vertices = LevelSharedVertexState.get_vertices();
  195.         auto &vcvertptr = Vertices.vcptr;
  196.         if (!rotate_list(vcvertptr, svp).uand)
  197.         {               //all off screen?
  198.                 int i;
  199.  
  200.                 auto &stv = Side_to_verts[side];
  201.                 for (i=0;i<3;i++)
  202.                         draw_line(*grd_curcanv, svp[stv[i]], svp[stv[i+1]], color);
  203.  
  204.                 draw_line(*grd_curcanv, svp[stv[i]], svp[stv[0]], color);
  205.         }
  206. }
  207.  
  208. static void draw_side_edge(const shared_segment &seg, const unsigned side, const unsigned edge, const color_palette_index color)
  209. {
  210.         auto &svp = seg.verts;
  211.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  212.         auto &Vertices = LevelSharedVertexState.get_vertices();
  213.         auto &vcvertptr = Vertices.vcptr;
  214.         if (!rotate_list(vcvertptr, svp).uand)          //on screen?
  215.         {
  216.                 auto &stv = Side_to_verts[side];
  217.                 draw_line(*grd_curcanv, svp[stv[edge]], svp[stv[(edge + 1) % 4]], color);
  218.         }
  219. }
  220.  
  221. int Show_triangulations=0;
  222.  
  223. //edge types - lower number types have precedence
  224. #define ET_FACING               0       //this edge on a facing face
  225. #define ET_NOTFACING    1       //this edge on a non-facing face
  226. #define ET_NOTUSED      2       //no face uses this edge
  227. #define ET_NOTEXTANT    3       //would exist if side were triangulated
  228.  
  229. #define ET_EMPTY                255     //this entry in array is empty
  230.  
  231. //colors for those types
  232. //int edge_colors[] = {BM_RGB(45/2,45/2,45/2),
  233. //                                                      BM_RGB(45/3,45/3,45/3),         //BM_RGB(0,0,45),       //
  234. //                                                      BM_RGB(45/4,45/4,45/4)};        //BM_RGB(0,45,0)};      //
  235.  
  236. static
  237. #if defined(DXX_BUILD_DESCENT_I)
  238. const
  239. #endif
  240. std::array<color_palette_index, 3> edge_colors{{54, 59, 64}};
  241.  
  242. namespace {
  243.  
  244. struct seg_edge
  245. {
  246.         union {
  247.                 struct {int v0,v1;} __pack__ n;
  248.                 long vv;
  249.         }v;
  250.         ushort  type;
  251.         ubyte           face_count, backface_count;
  252. };
  253.  
  254. }
  255.  
  256. static std::array<seg_edge, MAX_EDGES> edge_list;
  257. static std::array<int, MAX_EDGES> used_list;    //which entries in edge_list have been used
  258. static int n_used;
  259.  
  260. static unsigned edge_list_size;         //set each frame
  261.  
  262. #define HASH(a,b)  ((a*5+b) % edge_list_size)
  263.  
  264. //define edge numberings
  265. constexpr int edges[] = {
  266.                 0*8+1// edge  0
  267.                 0*8+3// edge  1
  268.                 0*8+4// edge  2
  269.                 1*8+2// edge  3
  270.                 1*8+5//      edge  4
  271.                 2*8+3//      edge  5
  272.                 2*8+6//      edge  6
  273.                 3*8+7//      edge  7
  274.                 4*8+5//      edge  8
  275.                 4*8+7//      edge  9
  276.                 5*8+6//      edge 10
  277.                 6*8+7//      edge 11
  278.  
  279.                 0*8+5//      right cross
  280.                 0*8+7// top cross
  281.                 1*8+3//      front  cross
  282.                 2*8+5// bottom cross
  283.                 2*8+7// left cross
  284.                 4*8+6//      back cross
  285.  
  286. //crosses going the other way
  287.  
  288.                 1*8+4//      other right cross
  289.                 3*8+4// other top cross
  290.                 0*8+2//      other front  cross
  291.                 1*8+6// other bottom cross
  292.                 3*8+6// other left cross
  293.                 5*8+7//      other back cross
  294. };
  295.  
  296. #define N_NORMAL_EDGES                  12              //the normal edges of a box
  297. #define N_EXTRA_EDGES                   12              //ones created by triangulation
  298. #define N_EDGES_PER_SEGMENT (N_NORMAL_EDGES+N_EXTRA_EDGES)
  299.  
  300. using std::swap;
  301.  
  302. //given two vertex numbers on a segment (range 0..7), tell what edge number it is
  303. static int find_edge_num(int v0,int v1)
  304. {
  305.         int             i;
  306.         int             vv;
  307.         const int               *edgep = edges;
  308.  
  309.         if (v0 > v1) swap(v0,v1);
  310.  
  311.         vv = v0*8+v1;
  312.  
  313. //      for (i=0;i<N_EDGES_PER_SEGMENT;i++)
  314. //              if (edges[i]==vv) return i;
  315.  
  316.         for (i=N_EDGES_PER_SEGMENT; i; i--)
  317.                 if (*edgep++ == vv)
  318.                         return (N_EDGES_PER_SEGMENT-i);
  319.  
  320.         Error("Could not find edge for %d,%d",v0,v1);
  321.  
  322.         //return -1;
  323. }
  324.  
  325.  
  326. //finds edge, filling in edge_ptr. if found old edge, returns index, else return -1
  327. static int find_edge(int v0,int v1,seg_edge **edge_ptr)
  328. {
  329.         long vv;
  330.         int hash,oldhash;
  331.         int ret;
  332.  
  333.         vv = (v1<<16) + v0;
  334.  
  335.         oldhash = hash = HASH(v0,v1);
  336.  
  337.         ret = -1;
  338.  
  339.         while (ret==-1) {
  340.  
  341.                 if (edge_list[hash].type == ET_EMPTY) ret=0;
  342.                 else if (edge_list[hash].v.vv == vv) ret=1;
  343.                 else {
  344.                         if (++hash==edge_list_size) hash=0;
  345.                         if (hash==oldhash) Error("Edge list full!");
  346.                 }
  347.         }
  348.  
  349.         *edge_ptr = &edge_list[hash];
  350.  
  351.         if (ret == 0)
  352.                 return -1;
  353.         else
  354.                 return hash;
  355.  
  356. }
  357.  
  358. //adds an edge to the edge list
  359. static void add_edge(int v0,int v1,ubyte type)
  360. {
  361.         int found;
  362.  
  363.         seg_edge *e;
  364.  
  365.         if (v0 > v1) swap(v0,v1);
  366.  
  367.         found = find_edge(v0,v1,&e);
  368.  
  369.         if (found == -1) {
  370.                 e->v.n.v0 = v0;
  371.                 e->v.n.v1 = v1;
  372.                 e->type = type;
  373.                 used_list[n_used] = e - edge_list.begin();
  374.                 if (type == ET_FACING)
  375.                         edge_list[used_list[n_used]].face_count++;
  376.                 else if (type == ET_NOTFACING)
  377.                         edge_list[used_list[n_used]].backface_count++;
  378.                 n_used++;
  379.         } else {
  380.                 if (type < e->type)
  381.                         e->type = type;
  382.                 if (type == ET_FACING)
  383.                         edge_list[found].face_count++;
  384.                 else if (type == ET_NOTFACING)
  385.                         edge_list[found].backface_count++;
  386.         }
  387. }
  388.  
  389. //adds a segment's edges to the edge list
  390. static void add_edges(const shared_segment &seg)
  391. {
  392.         auto &svp = seg.verts;
  393.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  394.         auto &Vertices = LevelSharedVertexState.get_vertices();
  395.         auto &vcvertptr = Vertices.vcptr;
  396.         if (!rotate_list(vcvertptr, svp).uand)
  397.         {               //all off screen?
  398.                 int     i,fn,vn;
  399.                 int     flag;
  400.                 ubyte   edge_flags[N_EDGES_PER_SEGMENT];
  401.  
  402.                 for (i=0;i<N_NORMAL_EDGES;i++) edge_flags[i]=ET_NOTUSED;
  403.                 for (;i<N_EDGES_PER_SEGMENT;i++) edge_flags[i]=ET_NOTEXTANT;
  404.  
  405.                 range_for (auto &&e, enumerate(seg.sides))
  406.                 {
  407.                         auto &sidep = e.value;
  408.                         int     num_vertices;
  409.                         const auto v = create_all_vertex_lists(seg, sidep, e.idx);
  410.                         const auto &num_faces = v.first;
  411.                         const auto &vertex_list = v.second;
  412.                         if (num_faces == 1)
  413.                                 num_vertices = 4;
  414.                         else
  415.                                 num_vertices = 3;
  416.  
  417.                         for (fn=0; fn<num_faces; fn++) {
  418.                                 int     en;
  419.  
  420.                                 //Note: normal check appears to be the wrong way since the normals points in, but we're looking from the outside
  421.                                 if (g3_check_normal_facing(vcvertptr(seg.verts[vertex_list[fn*3]]), sidep.normals[fn]))
  422.                                         flag = ET_NOTFACING;
  423.                                 else
  424.                                         flag = ET_FACING;
  425.  
  426.                                 auto v0 = &vertex_list[fn*3];
  427.                                 for (vn=0; vn<num_vertices-1; vn++) {
  428.  
  429.                                         // en = find_edge_num(vertex_list[fn*3 + vn], vertex_list[fn*3 + (vn+1)%num_vertices]);
  430.                                         en = find_edge_num(*v0, *(v0+1));
  431.                                        
  432.                                         if (en!=edge_none)
  433.                                                 if (flag < edge_flags[en]) edge_flags[en] = flag;
  434.  
  435.                                         v0++;
  436.                                 }
  437.                                 en = find_edge_num(*v0, vertex_list[fn*3]);
  438.                                 if (en!=edge_none)
  439.                                         if (flag < edge_flags[en]) edge_flags[en] = flag;
  440.                         }
  441.                 }
  442.  
  443.                 for (i=0; i<N_EDGES_PER_SEGMENT; i++)
  444.                         if (i<N_NORMAL_EDGES || (edge_flags[i]!=ET_NOTEXTANT && Show_triangulations))
  445.                                 add_edge(seg.verts[edges[i] / 8], seg.verts[edges[i] & 7], edge_flags[i]);
  446.         }
  447. }
  448.  
  449. // ----------------------------------------------------------------------------
  450. static void draw_trigger_side(const shared_segment &seg, const unsigned side, const color_palette_index color)
  451. {
  452.         auto &svp = seg.verts;
  453.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  454.         auto &Vertices = LevelSharedVertexState.get_vertices();
  455.         auto &vcvertptr = Vertices.vcptr;
  456.         if (!rotate_list(vcvertptr, svp).uand)
  457.         {               //all off screen?
  458.                 // Draw diagonals
  459.                 auto &stv = Side_to_verts[side];
  460.                 draw_line(*grd_curcanv, svp[stv[0]], svp[stv[2]], color);
  461.         }
  462. }
  463.  
  464. // ----------------------------------------------------------------------------
  465. static void draw_wall_side(const shared_segment &seg, const unsigned side, const color_palette_index color)
  466. {
  467.         auto &svp = seg.verts;
  468.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  469.         auto &Vertices = LevelSharedVertexState.get_vertices();
  470.         auto &vcvertptr = Vertices.vcptr;
  471.         if (!rotate_list(vcvertptr, svp).uand)
  472.         {               //all off screen?
  473.                 // Draw diagonals
  474.                 auto &stv = Side_to_verts[side];
  475.                 draw_line(*grd_curcanv, svp[stv[0]], svp[stv[2]], color);
  476.                 draw_line(*grd_curcanv, svp[stv[1]], svp[stv[3]], color);
  477.         }
  478. }
  479.  
  480. #define WALL_BLASTABLE_COLOR            rgb_t{31, 0, 0}  // RED
  481. #define WALL_DOOR_COLOR                         rgb_t{0, 0, 31} // DARK BLUE
  482. #define WALL_DOOR_LOCKED_COLOR          rgb_t{0, 0, 63} // BLUE
  483. #define WALL_AUTO_DOOR_COLOR            rgb_t{0, 31, 0} //      DARK GREEN
  484. #define WALL_AUTO_DOOR_LOCKED_COLOR     rgb_t{0, 63, 0} // GREEN
  485. #define WALL_ILLUSION_COLOR                     rgb_t{63, 0, 63}        // PURPLE
  486.  
  487. #define TRIGGER_COLOR                                           BM_XRGB( 63/2 , 63/2 ,  0/2)    // YELLOW
  488.  
  489. // ----------------------------------------------------------------------------------------------------------------
  490. // Draws special walls (for now these are just removable walls.)
  491. static void draw_special_wall(const shared_segment &seg, const unsigned side)
  492. {
  493.         auto &Walls = LevelUniqueWallSubsystemState.Walls;
  494.         auto &vcwallptr = Walls.vcptr;
  495.         auto &w = *vcwallptr(seg.sides[side].wall_num);
  496.         const auto get_color = [=]() {
  497.                 const auto type = w.type;
  498.                 if (type != WALL_OPEN)
  499.                 {
  500.                         const auto flags = w.flags;
  501.                         if (flags & WALL_DOOR_LOCKED)
  502.                                 return (flags & WALL_DOOR_AUTO) ? WALL_AUTO_DOOR_LOCKED_COLOR : WALL_DOOR_LOCKED_COLOR;
  503.                         if (flags & WALL_DOOR_AUTO)
  504.                                 return WALL_AUTO_DOOR_COLOR;
  505.                         if (type == WALL_BLASTABLE)
  506.                                 return WALL_BLASTABLE_COLOR;
  507.                         if (type == WALL_DOOR)
  508.                                 return WALL_DOOR_COLOR;
  509.                         if (type == WALL_ILLUSION)
  510.                                 return WALL_ILLUSION_COLOR;
  511.                 }
  512.                 return rgb_t{45, 45, 45};
  513.         };
  514.         const auto color = get_color();
  515.         draw_wall_side(seg,side, gr_find_closest_color(color.r, color.g, color.b));
  516.  
  517.         if (w.trigger != trigger_none)
  518.         {
  519.                 draw_trigger_side(seg,side, TRIGGER_COLOR);
  520.         }
  521. }
  522.  
  523.  
  524. // ----------------------------------------------------------------------------------------------------------------
  525. // Recursively parse mine structure, drawing segments.
  526. static void draw_mine_sub(const vmsegptridx_t segnum,int depth, visited_segment_bitarray_t &visited)
  527. {
  528.         if (visited[segnum]) return;            // If segment already drawn, return.
  529.         visited[segnum] = true;         // Say that this segment has been drawn.
  530.         auto mine_ptr = segnum;
  531.         // If this segment is active, process it, else skip it.
  532.  
  533.         if (mine_ptr->segnum != segment_none) {
  534.  
  535.                 if (Search_mode) check_segment(mine_ptr);
  536.                 else add_edges(mine_ptr);       //add this segments edges to list
  537.  
  538.                 if (depth != 0) {
  539.                         const shared_segment &sseg = *mine_ptr;
  540.                         for (const auto &&[idx, child_segnum, sside] : enumerate(zip(sseg.children, sseg.sides)))
  541.                         {
  542.                                 if (IS_CHILD(child_segnum))
  543.                                 {
  544.                                         if (sside.wall_num != wall_none)
  545.                                                 draw_special_wall(mine_ptr, idx);
  546.                                         draw_mine_sub(segnum.absolute_sibling(child_segnum), depth-1, visited);
  547.                                 }
  548.                         }
  549.                 }
  550.         }
  551. }
  552.  
  553. static void draw_mine_edges(int automap_flag)
  554. {
  555.         int i,type;
  556.         seg_edge *e;
  557.  
  558.         for (type=ET_NOTUSED;type>=ET_FACING;type--) {
  559.                 const auto color = edge_colors[type];
  560.                 for (i=0;i<n_used;i++) {
  561.                         e = &edge_list[used_list[i]];
  562.                         if (e->type == type)
  563.                                 if ((!automap_flag) || (e->face_count == 1))
  564.                                         draw_line(*grd_curcanv, e->v.n.v0, e->v.n.v1, color);
  565.                 }
  566.         }
  567. }
  568.  
  569. static void clear_edge_list()
  570. {
  571.         range_for (auto &i, partial_range(edge_list, edge_list_size))
  572.         {
  573.                 i.type = ET_EMPTY;
  574.                 i.face_count = 0;
  575.                 i.backface_count = 0;
  576.         }
  577. }
  578.  
  579. //draws an entire mine
  580. static void draw_mine(const vmsegptridx_t mine_ptr,int depth)
  581. {
  582.         visited_segment_bitarray_t visited;
  583.  
  584.         edge_list_size = min(LevelSharedSegmentState.Num_segments * 12, MAX_EDGES.value);               //make maybe smaller than max
  585.  
  586.         // clear edge list
  587.         clear_edge_list();
  588.  
  589.         n_used = 0;
  590.  
  591.         draw_mine_sub(mine_ptr,depth, visited);
  592.  
  593.         draw_mine_edges(0);
  594.  
  595. }
  596.  
  597. // -----------------------------------------------------------------------------
  598. //      Draw all segments, ignoring connectivity.
  599. //      A segment is drawn if its segnum != -1.
  600. static void draw_mine_all(int automap_flag)
  601. {
  602.         edge_list_size = min(LevelSharedSegmentState.Num_segments * 12, MAX_EDGES.value);               //make maybe smaller than max
  603.  
  604.         // clear edge list
  605.         clear_edge_list();
  606.  
  607.         n_used = 0;
  608.  
  609.         range_for (const auto &&segp, vmsegptridx)
  610.         {
  611.                 if (segp->segnum != segment_none)
  612.                 {
  613.                         range_for (auto &&e, enumerate(segp->shared_segment::sides))
  614.                                 if (e.value.wall_num != wall_none)
  615.                                         draw_special_wall(segp, e.idx);
  616.                         if (Search_mode)
  617.                                 check_segment(segp);
  618.                         else {
  619.                                 add_edges(segp);
  620.                                 draw_seg_objects(*grd_curcanv, segp);
  621.                         }
  622.                 }
  623.         }
  624.  
  625.         draw_mine_edges(automap_flag);
  626.  
  627. }
  628.  
  629. static void draw_listed_segments(grs_canvas &canvas, count_segment_array_t &s, const uint8_t color)
  630. {
  631.         range_for (const auto &ss, s)
  632.         {
  633.                 const auto &&segp = vcsegptr(ss);
  634.                 if (segp->segnum != segment_none)
  635.                         draw_segment(canvas, segp, color);
  636.         }
  637. }
  638.  
  639. static void draw_selected_segments(void)
  640. {
  641.         draw_listed_segments(*grd_curcanv, Selected_segs, SELECT_COLOR);
  642. }
  643.  
  644. static void draw_found_segments(void)
  645. {
  646.         draw_listed_segments(*grd_curcanv, Found_segs, FOUND_COLOR);
  647. }
  648.  
  649. static void draw_warning_segments(void)
  650. {
  651.         draw_listed_segments(*grd_curcanv, Warning_segs, WARNING_COLOR);
  652. }
  653.  
  654. static void draw_group_segments(void)
  655. {
  656.         if (current_group > -1) {
  657.                 draw_listed_segments(*grd_curcanv, GroupList[current_group].segments, GROUP_COLOR);
  658.                 }
  659. }
  660.  
  661.  
  662. static void draw_special_segments(void)
  663. {
  664.         // Highlight matcens, fuelcens, etc.
  665.         range_for (const auto &&segp, vcsegptr)
  666.         {
  667.                 if (segp->segnum != segment_none)
  668.                 {
  669.                         unsigned r, g, b;
  670.                         switch(segp->special)
  671.                         {
  672.                         case SEGMENT_IS_FUELCEN:
  673.                                         r = 29 * 2, g = 27 * 2, b = 13 * 2;
  674.                                 break;
  675.                         case SEGMENT_IS_CONTROLCEN:
  676.                                         r = 29 * 2, g = 0, b = 0;
  677.                                 break;
  678.                         case SEGMENT_IS_ROBOTMAKER:
  679.                                         r = 29 * 2, g = 0, b = 31 * 2;
  680.                                 break;
  681.                                 default:
  682.                                         continue;
  683.                         }
  684.                         const auto color = gr_find_closest_color(r, g, b);
  685.                         draw_segment(*grd_curcanv, segp, color);
  686.                 }
  687.         }
  688. }
  689.                
  690.  
  691. //find a free vertex. returns the vertex number
  692. static int alloc_vert()
  693. {
  694.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  695.         int vn;
  696.  
  697.         const auto Num_vertices = LevelSharedVertexState.Num_vertices;
  698.         assert(Num_vertices < MAX_SEGMENT_VERTICES);
  699.  
  700.         auto &Vertex_active = LevelSharedVertexState.get_vertex_active();
  701.         for (vn=0; (vn < Num_vertices) && Vertex_active[vn]; vn++) ;
  702.  
  703.         Vertex_active[vn] = 1;
  704.  
  705.         ++LevelSharedVertexState.Num_vertices;
  706.  
  707.         return vn;
  708. }
  709.  
  710. //frees a vertex
  711. static void free_vert(int vert_num)
  712. {
  713.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  714.         auto &Vertex_active = LevelSharedVertexState.get_vertex_active();
  715.         Vertex_active[vert_num] = 0;
  716.         --LevelSharedVertexState.Num_vertices;
  717. }
  718.  
  719. // -----------------------------------------------------------------------------
  720. static void draw_coordinate_axes(void)
  721. {
  722.         auto &LevelSharedVertexState = LevelSharedSegmentState.get_vertex_state();
  723.         auto &Vertices = LevelSharedVertexState.get_vertices();
  724.         std::array<unsigned, 16> Axes_verts;
  725.         vms_vector      tvec;
  726.  
  727.         range_for (auto &i, Axes_verts)
  728.                 i = alloc_vert();
  729.  
  730.         create_coordinate_axes_from_segment(Cursegp,Axes_verts);
  731.  
  732.         auto &vcvertptr = Vertices.vcptr;
  733.         auto &vmvertptr = Vertices.vmptr;
  734.         const auto &&av0 = vcvertptr(Axes_verts[0]);
  735.         const auto &&av1 = vcvertptr(Axes_verts[1]);
  736.         const auto &&av2 = vcvertptr(Axes_verts[2]);
  737.         const auto &&av3 = vcvertptr(Axes_verts[3]);
  738.         const auto &&av4 = vmvertptr(Axes_verts[4]);
  739.         const auto &&av6 = vmvertptr(Axes_verts[6]);
  740.         const auto &&av9 = vmvertptr(Axes_verts[9]);
  741.         const auto &&av10 = vmvertptr(Axes_verts[10]);
  742.         const auto &&av11 = vmvertptr(Axes_verts[11]);
  743.         const auto &&av12 = vmvertptr(Axes_verts[12]);
  744.         const auto &&av14 = vmvertptr(Axes_verts[14]);
  745.         const auto &&xvec = vm_vec_sub(av1, av0);
  746.         const auto &&yvec = vm_vec_sub(av2, av0);
  747.         const auto &&zvec = vm_vec_sub(av3, av0);
  748.  
  749.         // Create the letter X
  750.         tvec = xvec;
  751.         vm_vec_add(av4, av1, vm_vec_scale(tvec, F1_0 / 16));
  752.         tvec = yvec;
  753.         vm_vec_add2(av4, vm_vec_scale(tvec, F1_0 / 8));
  754.         vm_vec_sub(av6, av4, vm_vec_scale(tvec, F2_0));
  755.         tvec = xvec;
  756.         vm_vec_scale(tvec, F1_0 / 8);
  757.         vm_vec_add(vmvertptr(Axes_verts[7]), av4, tvec);
  758.         vm_vec_add(vmvertptr(Axes_verts[5]), av6, tvec);
  759.  
  760.         //      Create the letter Y
  761.         tvec = yvec;
  762.         vm_vec_add(av11, av2, vm_vec_scale(tvec, F1_0 / 16));
  763.         vm_vec_add(vmvertptr(Axes_verts[8]), av11, tvec);
  764.         vm_vec_add(av9, av11, vm_vec_scale(tvec, F1_0 * 2));
  765.         vm_vec_add(av10, av11, tvec);
  766.         tvec = xvec;
  767.         vm_vec_scale(tvec, F1_0 / 16);
  768.         vm_vec_sub2(av9, tvec);
  769.         vm_vec_add2(av10, tvec);
  770.  
  771.         // Create the letter Z
  772.         tvec = zvec;
  773.         vm_vec_add(av12, av3, vm_vec_scale(tvec, F1_0 / 16));
  774.         tvec = yvec;
  775.         vm_vec_add2(av12, vm_vec_scale(tvec, F1_0 / 8));
  776.         vm_vec_sub(av14, av12, vm_vec_scale(tvec, F2_0));
  777.         tvec = zvec;
  778.         vm_vec_scale(tvec, F1_0 / 8);
  779.         vm_vec_add(vmvertptr(Axes_verts[13]), av12, tvec);
  780.         vm_vec_add(vmvertptr(Axes_verts[15]), av14, tvec);
  781.  
  782.         rotate_list(vcvertptr, Axes_verts);
  783.  
  784.         const color_palette_index color = AXIS_COLOR;
  785.  
  786.         draw_line(*grd_curcanv, Axes_verts[0], Axes_verts[1], color);
  787.         draw_line(*grd_curcanv, Axes_verts[0], Axes_verts[2], color);
  788.         draw_line(*grd_curcanv, Axes_verts[0], Axes_verts[3], color);
  789.  
  790.         // draw the letter X
  791.         draw_line(*grd_curcanv, Axes_verts[4], Axes_verts[5], color);
  792.         draw_line(*grd_curcanv, Axes_verts[6], Axes_verts[7], color);
  793.  
  794.         // draw the letter Y
  795.         draw_line(*grd_curcanv, Axes_verts[8], Axes_verts[9], color);
  796.         draw_line(*grd_curcanv, Axes_verts[8], Axes_verts[10], color);
  797.         draw_line(*grd_curcanv, Axes_verts[8], Axes_verts[11], color);
  798.  
  799.         // draw the letter Z
  800.         draw_line(*grd_curcanv, Axes_verts[12], Axes_verts[13], color);
  801.         draw_line(*grd_curcanv, Axes_verts[13], Axes_verts[14], color);
  802.         draw_line(*grd_curcanv, Axes_verts[14], Axes_verts[15], color);
  803.  
  804.         range_for (auto &i, Axes_verts)
  805.                 free_vert(i);
  806. }
  807.  
  808. void draw_world(grs_canvas *screen_canvas,editor_view *v,const vmsegptridx_t mine_ptr,int depth)
  809. {
  810.         vms_vector viewer_position;
  811.  
  812.         gr_set_current_canvas(screen_canvas);
  813.  
  814.         viewer_position = v->ev_matrix.fvec;
  815.         vm_vec_scale(viewer_position,-v->ev_dist);
  816.  
  817.         vm_vec_add2(viewer_position,Ed_view_target);
  818.  
  819.         gr_clear_canvas(*grd_curcanv, 0);
  820.         g3_start_frame(*grd_curcanv);
  821.         g3_set_view_matrix(viewer_position,v->ev_matrix,v->ev_zoom);
  822.  
  823.         render_start_frame();
  824.  
  825.         // Draw all segments or only connected segments.
  826.         // We might want to draw all segments if we have broken the mine into pieces.
  827.         if (Draw_all_segments)
  828.                 draw_mine_all(Automap_test);
  829.         else
  830.                 draw_mine(mine_ptr,depth);
  831.  
  832.         // Draw the found segments
  833.         if (!Automap_test) {
  834.                 draw_warning_segments();
  835.                 draw_group_segments();
  836.                 draw_found_segments();
  837.                 draw_selected_segments();
  838.                 draw_special_segments();
  839.  
  840.                 // Highlight group segment and side.
  841.                 if (current_group > -1)
  842.                 if (Groupsegp[current_group]) {
  843.                         draw_segment(*grd_curcanv, vcsegptr(Groupsegp[current_group]), GROUPSEG_COLOR);
  844.                         draw_seg_side(vcsegptr(Groupsegp[current_group]), Groupside[current_group], GROUPSIDE_COLOR);
  845.                 }
  846.  
  847.                 // Highlight marked segment and side.
  848.                 if (Markedsegp) {
  849.                         draw_segment(*grd_curcanv, Markedsegp, MARKEDSEG_COLOR);
  850.                         draw_seg_side(Markedsegp,Markedside, MARKEDSIDE_COLOR);
  851.                 }
  852.  
  853.                 // Highlight current segment and current side.
  854.                 draw_segment(*grd_curcanv, Cursegp, CURSEG_COLOR);
  855.  
  856.                 draw_seg_side(Cursegp,Curside, CURSIDE_COLOR);
  857.                 draw_side_edge(Cursegp,Curside,Curedge, CUREDGE_COLOR);
  858.  
  859.                 // Draw coordinate axes if we are rendering the large view.
  860.                 if (Show_axes_flag)
  861.                         if (screen_canvas == LargeViewBox->canvas.get())
  862.                                 draw_coordinate_axes();
  863.  
  864.                 // Label the window
  865.                 gr_set_fontcolor(*grd_curcanv, (v==current_view)?CRED:CWHITE, -1);
  866.                 if ( screen_canvas == LargeViewBox->canvas.get() ) {
  867.                         gr_ustring(*grd_curcanv, *grd_curcanv->cv_font, 5, 5, "USER VIEW");
  868.                         switch (Large_view_index) {
  869.                                 case 0: gr_ustring(*grd_curcanv, *grd_curcanv->cv_font, 85, 5, "-- TOP");       break;
  870.                                 case 1: gr_ustring(*grd_curcanv, *grd_curcanv->cv_font, 85, 5, "-- FRONT");     break;
  871.                                 case 2: gr_ustring(*grd_curcanv, *grd_curcanv->cv_font, 85, 5, "-- RIGHT");     break;
  872.                         }                      
  873.                 } else
  874. #if ORTHO_VIEWS
  875.                  else if ( screen_canvas == TopViewBox->canvas )
  876.                         gr_ustring(*grd_curcanv, *grd_curcanv->cv_font, 5, 5, "TOP");
  877.                 else if ( screen_canvas == FrontViewBox->canvas )
  878.                         gr_ustring(*grd_curcanv, *grd_curcanv->cv_font, 5, 5, "FRONT");
  879.                 else if ( screen_canvas == RightViewBox->canvas )
  880.                         gr_ustring(*grd_curcanv, *grd_curcanv->cv_font, 5, 5, "RIGHT");
  881. #else
  882.                         Error("Ortho views have been removed, what gives?\n");
  883. #endif
  884.  
  885.         }
  886.  
  887.         g3_end_frame();
  888.  
  889. }
  890.  
  891. //find the segments that render at a given screen x,y
  892. //parms other than x,y are like draw_world
  893. //fills in globals N_found_segs & Found_segs
  894. void find_segments(short x,short y,grs_canvas *screen_canvas,editor_view *v,const vmsegptridx_t mine_ptr,int depth)
  895. {
  896.         vms_vector viewer_position;
  897.  
  898.         gr_set_current_canvas(screen_canvas);
  899.  
  900.         viewer_position = v->ev_matrix.fvec;
  901.         vm_vec_scale(viewer_position,-v->ev_dist);
  902.  
  903.         vm_vec_add2(viewer_position,Ed_view_target);
  904.  
  905.         g3_start_frame(*grd_curcanv);
  906.         g3_set_view_matrix(viewer_position,v->ev_matrix,v->ev_zoom);
  907.  
  908.         render_start_frame();
  909.  
  910. #if DXX_USE_OGL
  911.         g3_end_frame();
  912. #endif
  913.         uint8_t color = 0;
  914.         gr_pixel(grd_curcanv->cv_bitmap, x, y, color);  //set our search pixel to color zero
  915. #if DXX_USE_OGL
  916.         g3_start_frame(*grd_curcanv);
  917. #endif
  918.  
  919.         Search_mode = -1;
  920.         Found_segs.clear();
  921.         Search_x = x; Search_y = y;
  922.  
  923.         if (Draw_all_segments)
  924.                 draw_mine_all(0);
  925.         else
  926.                 draw_mine(mine_ptr,depth);
  927.  
  928.         g3_end_frame();
  929.  
  930.         Search_mode = 0;
  931.  
  932. }
  933.  
  934. namespace dsx {
  935. void meddraw_init_views( grs_canvas * canvas)
  936. {
  937. #if defined(DXX_BUILD_DESCENT_II)
  938.         // sticking these here so the correct D2 colors are used
  939.         edge_colors[0] = BM_XRGB(45/2,45/2,45/2);
  940.         edge_colors[1] = BM_XRGB(45/3,45/3,45/3);               //BM_RGB(0,0,45),       //
  941.         edge_colors[2] = BM_XRGB(45/4,45/4,45/4);       //BM_RGB(0,45,0)};      //
  942. #endif
  943.  
  944.         Views[0]->ev_canv = canvas;
  945. #if ORTHO_VIEWS
  946.         Views[1]->ev_canv = TopViewBox->canvas;
  947.         Views[2]->ev_canv = FrontViewBox->canvas;
  948.         Views[3]->ev_canv = RightViewBox->canvas;
  949. #endif
  950. }
  951. }
  952.