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-1999 PARALLAX SOFTWARE CORPORATION.  ALL RIGHTS RESERVED.
  18. */
  19.  
  20. /*
  21.  *
  22.  * Include file for functions which need to access segment data structure.
  23.  *
  24.  */
  25.  
  26. #pragma once
  27.  
  28. #include <physfs.h>
  29. #include <type_traits>
  30. #include "pstypes.h"
  31. #include "maths.h"
  32. #include "vecmat.h"
  33. #include "dxxsconf.h"
  34. #include "dsx-ns.h"
  35.  
  36. #ifdef __cplusplus
  37. #include <cassert>
  38. #include <cstdint>
  39. #include <stdexcept>
  40. #include "fwd-segment.h"
  41. #include "countarray.h"
  42. #include "valptridx.h"
  43. #include "objnum.h"
  44. #include "pack.h"
  45.  
  46.  
  47. #ifdef dsx
  48. namespace dsx {
  49. // Returns true if segnum references a child, else returns false.
  50. // Note that -1 means no connection, -2 means a connection to the outside world.
  51. static inline bool IS_CHILD(segnum_t s)
  52. {
  53.         return s != segment_none && s != segment_exit;
  54. }
  55. }
  56. #endif
  57.  
  58. namespace dcx {
  59.  
  60. //Structure for storing u,v,light values.
  61. //NOTE: this structure should be the same as the one in 3d.h
  62. struct uvl
  63. {
  64.         fix u, v, l;
  65. };
  66.  
  67. enum class side_type : uint8_t
  68. {
  69.         quad = 1,       // render side as quadrilateral
  70.         tri_02 = 2,     // render side as two triangles, triangulated along edge from 0 to 2
  71.         tri_13 = 3,     // render side as two triangles, triangulated along edge from 1 to 3
  72. };
  73.  
  74. #if 0
  75. struct wallnum_t : prohibit_void_ptr<wallnum_t>
  76. {
  77.         typedef int16_t integral_type;
  78.         integral_type value;
  79.         wallnum_t() = default;
  80.         wallnum_t(const integral_type &v) : value(v)
  81.         {
  82. #ifdef DXX_HAVE_BUILTIN_CONSTANT_P
  83.                 if (__builtin_constant_p(v))
  84.                         DXX_ALWAYS_ERROR_FUNCTION(dxx_trap_constant_wall, "constant wall number constructed");
  85. #endif
  86.         }
  87.         wallnum_t &operator=(integral_type v)
  88.         {
  89. #ifdef DXX_HAVE_BUILTIN_CONSTANT_P
  90.                 if (__builtin_constant_p(v))
  91.                         DXX_ALWAYS_ERROR_FUNCTION(dxx_trap_constant_wall, "constant wall number assigned");
  92. #endif
  93.                 value = v;
  94.                 return *this;
  95.         }
  96.         template <integral_type I>
  97.                 wallnum_t &operator=(const wall_magic_constant_t<I> &)
  98.                 {
  99.                         value = I;
  100.                         return *this;
  101.                 }
  102.         bool operator==(const wallnum_t &v) const { return value == v.value; }
  103.         bool operator==(const int &v) const
  104.         {
  105. #ifdef DXX_HAVE_BUILTIN_CONSTANT_P
  106.                 if (__builtin_constant_p(v))
  107.                         DXX_ALWAYS_ERROR_FUNCTION(dxx_trap_constant_wall, "constant wall number compared");
  108. #endif
  109.                 return value == v;
  110.         }
  111.         template <integral_type I>
  112.                 bool operator==(const wall_magic_constant_t<I> &) const { return value == I; }
  113.         template <typename T>
  114.                 bool operator!=(const T &v) const { return !(*this == v); }
  115.         template <typename T>
  116.                 bool operator==(const T &v) const = delete;
  117.         template <typename T>
  118.                 bool operator<(const T &v) const
  119.                 {
  120.                         static_assert(std::is_integral<T>::value, "non-integral wall number compared");
  121. #ifdef DXX_HAVE_BUILTIN_CONSTANT_P
  122.                         if (__builtin_constant_p(v))
  123.                                 DXX_ALWAYS_ERROR_FUNCTION(dxx_trap_constant_wall, "constant wall number compared");
  124. #endif
  125.                         return value < v;
  126.                 }
  127.         template <typename T>
  128.                 bool operator>(const T &v) const
  129.                 {
  130.                         return v < *this;
  131.                 }
  132.         template <typename T>
  133.                 bool operator<=(const T &) const = delete;
  134.         template <typename T>
  135.                 bool operator>=(const T &) const = delete;
  136.         constexpr operator integral_type() const { return value; }
  137.         operator integral_type &() { return value; }
  138. };
  139. #endif
  140.  
  141. struct shared_side
  142. {
  143.         struct illegal_type;
  144.         side_type m_type;           // replaces num_faces and tri_edge, 1 = quad, 2 = 0:2 triangulation, 3 = 1:3 triangulation
  145.         const side_type &get_type() const { return m_type; }
  146.         void set_type(side_type t) { m_type = t; }
  147.         wallnum_t wall_num;
  148.         std::array<vms_vector, 2> normals;  // 2 normals, if quadrilateral, both the same.
  149. };
  150.  
  151. struct unique_side
  152. {
  153.         int16_t tmap_num;
  154.         int16_t tmap_num2;
  155.         std::array<uvl, 4>     uvls;
  156. };
  157.  
  158. #ifdef dsx
  159. struct shared_segment
  160. {
  161. #if DXX_USE_EDITOR
  162.         segnum_t   segnum;     // segment number, not sure what it means
  163.         short   group;      // group number to which the segment belongs.
  164. #endif
  165.         std::array<segnum_t, MAX_SIDES_PER_SEGMENT>   children;    // indices of 6 children segments, front, left, top, right, bottom, back
  166.         std::array<unsigned, MAX_VERTICES_PER_SEGMENT> verts;    // vertex ids of 4 front and 4 back vertices
  167.         uint8_t special;    // what type of center this is
  168.         int8_t matcen_num; // which center segment is associated with.
  169.         uint8_t station_idx;
  170.         /* if DXX_BUILD_DESCENT_II */
  171.         uint8_t s2_flags;
  172.         /* endif */
  173.         std::array<shared_side, MAX_SIDES_PER_SEGMENT> sides;
  174. };
  175.  
  176. struct unique_segment
  177. {
  178.         objnum_t objects;    // pointer to objects in this segment
  179.         //      If bit n (1 << n) is set, then side #n in segment has had light subtracted from original (editor-computed) value.
  180.         uint8_t light_subtracted;
  181.         /* if DXX_BUILD_DESCENT_II */
  182.         uint8_t slide_textures;
  183.         /* endif */
  184.         fix     static_light;
  185.         std::array<unique_side, MAX_SIDES_PER_SEGMENT> sides;
  186. };
  187.  
  188. struct segment : unique_segment, shared_segment
  189. {
  190. };
  191.  
  192. template <typename S, typename U>
  193. struct susegment
  194. {
  195.         using qualified_segment = typename std::conditional<std::is_const<S>::value && std::is_const<U>::value, const segment, segment>::type;
  196.         S &s;
  197.         U &u;
  198.         constexpr susegment(qualified_segment &b) :
  199.                 s(b), u(b)
  200.         {
  201.         }
  202.         constexpr susegment(const susegment &) = default;
  203.         constexpr susegment(susegment &&) = default;
  204.         template <typename S2, typename U2, typename std::enable_if<std::is_convertible<S2 &, S &>::value && std::is_convertible<U2 &, U &>::value, int>::type = 0>
  205.                 constexpr susegment(const susegment<S2, U2> &r) :
  206.                         s(r.s), u(r.u)
  207.         {
  208.         }
  209.         template <typename T, typename std::enable_if<std::is_convertible<T &&, qualified_segment &>::value, int>::type = 0>
  210.                 constexpr susegment(T &&t) :
  211.                         susegment(static_cast<qualified_segment &>(t))
  212.         {
  213.         }
  214.         operator S &() const
  215.         {
  216.                 return s;
  217.         }
  218.         operator U &() const
  219.         {
  220.                 return u;
  221.         }
  222. };
  223. #endif
  224.  
  225. struct count_segment_array_t : public count_array_t<segnum_t, MAX_SEGMENTS> {};
  226.  
  227. struct group
  228. {
  229.         struct segment_array_type_t : public count_segment_array_t {};
  230.         struct vertex_array_type_t : public count_array_t<unsigned, MAX_VERTICES> {};
  231.         segment_array_type_t segments;
  232.         vertex_array_type_t vertices;
  233.         void clear()
  234.         {
  235.                 segments.clear();
  236.                 vertices.clear();
  237.         }
  238. };
  239.  
  240. #ifdef dsx
  241. #define Highest_segment_index (Segments.get_count() - 1)
  242. DXX_VALPTRIDX_DEFINE_GLOBAL_FACTORIES(segment, seg, Segments);
  243. #endif
  244.  
  245. // Globals from mglobal.c
  246. struct vertex : vms_vector
  247. {
  248.         vertex() = default;
  249.         vertex(const fix &a, const fix &b, const fix &c) :
  250.                 vms_vector{a, b, c}
  251.         {
  252.         }
  253.         explicit vertex(const vms_vector &v) :
  254.                 vms_vector(v)
  255.         {
  256.         }
  257. };
  258. }
  259.  
  260. #ifdef dsx
  261. struct shared_side::illegal_type : std::runtime_error
  262. {
  263.         const shared_segment *const m_segment;
  264.         const shared_side *const m_side;
  265.         illegal_type(const shared_segment &seg, const shared_side &s) :
  266.                 runtime_error("illegal side type"),
  267.                 m_segment(&seg), m_side(&s)
  268.         {
  269.         }
  270.         illegal_type(const shared_side &s) :
  271.                 runtime_error("illegal side type"),
  272.                 m_segment(nullptr), m_side(&s)
  273.         {
  274.         }
  275. };
  276.  
  277. namespace dsx {
  278.  
  279. #if defined(DXX_BUILD_DESCENT_II)
  280. // New stuff, 10/14/95: For shooting out lights and monitors.
  281. // Light cast upon vert_light vertices in segnum:sidenum by some light
  282. struct delta_light : prohibit_void_ptr<delta_light>
  283. {
  284.         segnum_t   segnum;
  285.         uint8_t   sidenum;
  286.         std::array<ubyte, 4>   vert_light;
  287. };
  288.  
  289. // Light at segnum:sidenum casts light on count sides beginning at index (in array Delta_lights)
  290. struct dl_index {
  291.         segnum_t   segnum;
  292.         uint8_t   sidenum;
  293.         uint8_t count;
  294.         uint16_t index;
  295.         bool operator<(const dl_index &rhs) const
  296.         {
  297.                 if (segnum < rhs.segnum)
  298.                         return true;
  299.                 if (segnum > rhs.segnum)
  300.                         return false;
  301.                 return sidenum < rhs.sidenum;
  302.         }
  303. };
  304.  
  305. struct d_level_shared_destructible_light_state
  306. {
  307.         valptridx<dl_index>::array_managed_type Dl_indices;
  308.         d_delta_light_array Delta_lights;
  309. };
  310. #endif
  311.  
  312. }
  313. #endif
  314.  
  315. namespace dcx {
  316.  
  317. #ifdef dsx
  318. struct d_level_shared_vertex_state
  319. {
  320.         unsigned Num_vertices;
  321. private:
  322.         vertex_array Vertices;
  323. #if DXX_USE_EDITOR
  324.         std::array<uint8_t, MAX_VERTICES> Vertex_active; // !0 means vertex is in use, 0 means not in use.
  325. #endif
  326. public:
  327.         auto &get_vertices()
  328.         {
  329.                 return Vertices;
  330.         }
  331.         const auto &get_vertices() const
  332.         {
  333.                 return Vertices;
  334.         }
  335. #if DXX_USE_EDITOR
  336.         auto &get_vertex_active()
  337.         {
  338.                 return Vertex_active;
  339.         }
  340.         const auto &get_vertex_active() const
  341.         {
  342.                 return Vertex_active;
  343.         }
  344. #endif
  345. };
  346.  
  347. struct d_level_shared_segment_state
  348. {
  349.         unsigned Num_segments;
  350.         d_level_shared_vertex_state LevelSharedVertexState;
  351.         auto &get_segments()
  352.         {
  353.                 return Segments;
  354.         }
  355.         const auto &get_segments() const
  356.         {
  357.                 return Segments;
  358.         }
  359.         auto &get_vertex_state()
  360.         {
  361.                 return LevelSharedVertexState;
  362.         }
  363.         const auto &get_vertex_state() const
  364.         {
  365.                 return LevelSharedVertexState;
  366.         }
  367. };
  368.  
  369. struct d_level_unique_automap_state
  370. {
  371.         std::array<uint8_t, MAX_SEGMENTS> Automap_visited;
  372. };
  373.  
  374. struct d_level_unique_segment_state
  375. {
  376.         auto &get_segments()
  377.         {
  378.                 return Segments;
  379.         }
  380.         const auto &get_segments() const
  381.         {
  382.                 return Segments;
  383.         }
  384. };
  385.  
  386. extern d_level_unique_automap_state LevelUniqueAutomapState;
  387. extern d_level_unique_segment_state LevelUniqueSegmentState;
  388. #endif
  389.  
  390. template <unsigned bits>
  391. class visited_segment_mask_base
  392. {
  393.         static_assert(bits == 1 || bits == 2 || bits == 4, "bits must align in bytes");
  394. protected:
  395.         enum
  396.         {
  397.                 divisor = 8 / bits,
  398.         };
  399.         using array_t = std::array<uint8_t, (MAX_SEGMENTS + (divisor - 1)) / divisor>;
  400.         typedef typename array_t::size_type size_type;
  401.         array_t a;
  402.         struct maskproxy_shift_count_type
  403.         {
  404.                 using bitmask_low_aligned = std::integral_constant<unsigned, (1 << bits) - 1>;
  405.                 const unsigned m_shift;
  406.                 unsigned shift() const
  407.                 {
  408.                         return m_shift;
  409.                 }
  410.                 typename array_t::value_type mask() const
  411.                 {
  412.                         return bitmask_low_aligned() << shift();
  413.                 }
  414.                 maskproxy_shift_count_type(const unsigned s) :
  415.                         m_shift(s * bits)
  416.                 {
  417.                 }
  418.         };
  419.         template <typename R>
  420.         struct maskproxy_byte_reference : public maskproxy_shift_count_type
  421.         {
  422.                 R m_byte;
  423.                 maskproxy_byte_reference(R byte, const unsigned s) :
  424.                         maskproxy_shift_count_type(s), m_byte(byte)
  425.                 {
  426.                 }
  427.                 operator uint8_t() const
  428.                 {
  429.                         return (this->m_byte >> this->shift()) & typename maskproxy_shift_count_type::bitmask_low_aligned();
  430.                 }
  431.         };
  432.         template <typename R>
  433.         struct maskproxy_assignable_type : maskproxy_byte_reference<R>
  434.         {
  435.                 DXX_INHERIT_CONSTRUCTORS(maskproxy_assignable_type, maskproxy_byte_reference<R>);
  436.                 using typename maskproxy_shift_count_type::bitmask_low_aligned;
  437.                 maskproxy_assignable_type &operator=(const uint8_t u)
  438.                 {
  439.                         assert(!(u & ~bitmask_low_aligned()));
  440.                         auto &byte = this->m_byte;
  441.                         byte = (byte & ~this->mask()) | (u << this->shift());
  442.                         return *this;
  443.                 }
  444.                 maskproxy_assignable_type &operator|=(const uint8_t u)
  445.                 {
  446.                         assert(!(u & ~bitmask_low_aligned()));
  447.                         this->m_byte |= (u << this->shift());
  448.                         return *this;
  449.                 }
  450.         };
  451.         template <typename R, typename A>
  452.         static R make_maskproxy(A &a, const size_type segnum)
  453.         {
  454.                 const size_type idx = segnum / divisor;
  455.                 if (idx >= a.size())
  456.                         throw std::out_of_range("index exceeds segment range");
  457.                 const size_type bit = segnum % divisor;
  458.                 return R(a[idx], bit);
  459.         }
  460. public:
  461.         /* Explicitly invoke the default constructor for `a` so that the
  462.          * storage is cleared.
  463.          */
  464.         visited_segment_mask_base() :
  465.                 a()
  466.         {
  467.         }
  468.         void clear()
  469.         {
  470.                 a = {};
  471.         }
  472. };
  473.  
  474. template <>
  475. template <typename R>
  476. struct visited_segment_mask_base<1>::maskproxy_assignable_type : maskproxy_byte_reference<R>
  477. {
  478.         DXX_INHERIT_CONSTRUCTORS(maskproxy_assignable_type, maskproxy_byte_reference<R>);
  479.         maskproxy_assignable_type &operator=(const bool b)
  480.         {
  481.                 const auto m = this->mask();
  482.                 auto &byte = this->m_byte;
  483.                 if (b)
  484.                         byte |= m;
  485.                 else
  486.                         byte &= ~m;
  487.                 return *this;
  488.         }
  489. };
  490.  
  491. /* This type must be separate so that its members are defined after the
  492.  * specialization of maskproxy_assignable_type.  If these are defined
  493.  * inline in visited_segment_mask_base, gcc crashes.
  494.  * Known bad:
  495.  *      gcc-4.9.4
  496.  *      gcc-5.4.0
  497.  *      gcc-6.4.0
  498.  *      gcc-7.2.0
  499.  */
  500. template <unsigned bits>
  501. class visited_segment_mask_t : visited_segment_mask_base<bits>
  502. {
  503.         using base_type = visited_segment_mask_base<bits>;
  504. public:
  505.         auto operator[](const typename base_type::size_type segnum)
  506.         {
  507.                 return this->template make_maskproxy<typename base_type::template maskproxy_assignable_type<typename base_type::array_t::reference>>(this->a, segnum);
  508.         }
  509.         auto operator[](const typename base_type::size_type segnum) const
  510.         {
  511.                 return this->template make_maskproxy<typename base_type::template maskproxy_assignable_type<typename base_type::array_t::const_reference>>(this->a, segnum);
  512.         }
  513. };
  514.  
  515. }
  516.  
  517. #ifdef dsx
  518. namespace dsx {
  519.  
  520. #if defined(DXX_BUILD_DESCENT_II)
  521. struct d_level_shared_segment_state : ::dcx::d_level_shared_segment_state
  522. {
  523.         d_level_shared_destructible_light_state DestructibleLights;
  524.         segnum_t Secret_return_segment;
  525.         vms_matrix Secret_return_orient;
  526. };
  527. #endif
  528.  
  529. extern d_level_shared_segment_state LevelSharedSegmentState;
  530.  
  531. }
  532. #endif
  533. #endif
  534.