Subversion Repositories Games.Descent

Rev

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

  1. /*
  2.  * This file is part of the DXX-Rebirth project <https://www.dxx-rebirth.com/>.
  3.  * It is copyright by its individual contributors, as recorded in the
  4.  * project's Git history.  See COPYING.txt at the top level for license
  5.  * terms and a link to the Git history.
  6.  */
  7.  
  8. /*
  9.  *
  10.  * Polygon object interpreter
  11.  *
  12.  */
  13.  
  14. #include <stdexcept>
  15. #include <stdlib.h>
  16. #include "dxxsconf.h"
  17. #include "dsx-ns.h"
  18. #include "dxxerror.h"
  19.  
  20. #include "interp.h"
  21. #include "console.h"
  22. #include "common/3d/globvars.h"
  23. #include "polyobj.h"
  24. #include "gr.h"
  25. #include "byteutil.h"
  26. #include "u_mem.h"
  27.  
  28. #include "compiler-range_for.h"
  29. #include "d_range.h"
  30. #include "d_zip.h"
  31. #include "partial_range.h"
  32.  
  33. namespace dcx {
  34.  
  35. constexpr std::integral_constant<unsigned, 0> OP_EOF{};   //eof
  36. constexpr std::integral_constant<unsigned, 1> OP_DEFPOINTS{};   //defpoints
  37. constexpr std::integral_constant<unsigned, 2> OP_FLATPOLY{};   //flat-shaded polygon
  38. constexpr std::integral_constant<unsigned, 3> OP_TMAPPOLY{};   //texture-mapped polygon
  39. constexpr std::integral_constant<unsigned, 4> OP_SORTNORM{};   //sort by normal
  40. constexpr std::integral_constant<unsigned, 5> OP_RODBM{};   //rod bitmap
  41. constexpr std::integral_constant<unsigned, 6> OP_SUBCALL{};   //call a subobject
  42. constexpr std::integral_constant<unsigned, 7> OP_DEFP_START{};   //defpoints with start
  43. constexpr std::integral_constant<unsigned, 8> OP_GLOW{};   //glow value for next poly
  44.  
  45. #if DXX_USE_EDITOR
  46. int g3d_interp_outline;
  47. #endif
  48.  
  49. }
  50.  
  51. namespace dsx {
  52.  
  53. static int16_t init_model_sub(uint8_t *model_sub_ptr, const uint8_t *model_base_ptr, std::size_t model_size);
  54. #if defined(DXX_BUILD_DESCENT_I)
  55. static void validate_model_sub(uint8_t *model_sub_ptr, const uint8_t *model_base_ptr, std::size_t model_size);
  56. #endif
  57.  
  58. static inline int16_t *wp(uint8_t *p)
  59. {
  60.         return reinterpret_cast<int16_t *>(p);
  61. }
  62.  
  63. static inline const int16_t *wp(const uint8_t *p)
  64. {
  65.         return reinterpret_cast<const int16_t *>(p);
  66. }
  67.  
  68. static inline const vms_vector *vp(const uint8_t *p)
  69. {
  70.         return reinterpret_cast<const vms_vector *>(p);
  71. }
  72.  
  73. static inline int16_t w(const uint8_t *p)
  74. {
  75.         return *wp(p);
  76. }
  77.  
  78. static void rotate_point_list(const zip<g3s_point * /* dest */, const vms_vector * /* src */> zr)
  79. {
  80.         range_for (auto &&z, zr)
  81.         {
  82.                 auto &dest = std::get<0>(z);
  83.                 auto &src = std::get<1>(z);
  84.                 g3_rotate_point(dest, src);
  85.         }
  86. }
  87.  
  88. constexpr vms_angvec zero_angles = {0,0,0};
  89.  
  90. namespace {
  91.  
  92. class interpreter_ignore_op_defpoints
  93. {
  94. public:
  95.         static void op_defpoints(const uint8_t *, uint16_t)
  96.         {
  97.         }
  98. };
  99.  
  100. class interpreter_ignore_op_defp_start
  101. {
  102. public:
  103.         static void op_defp_start(const uint8_t *, uint16_t)
  104.         {
  105.         }
  106. };
  107.  
  108. class interpreter_ignore_op_flatpoly
  109. {
  110. public:
  111.         static void op_flatpoly(const uint8_t *, uint16_t)
  112.         {
  113.         }
  114. };
  115.  
  116. class interpreter_ignore_op_tmappoly
  117. {
  118. public:
  119.         static void op_tmappoly(const uint8_t *, uint16_t)
  120.         {
  121.         }
  122. };
  123.  
  124. class interpreter_ignore_op_rodbm
  125. {
  126. public:
  127.         static void op_rodbm(const uint8_t *)
  128.         {
  129.         }
  130. };
  131.  
  132. class interpreter_ignore_op_glow
  133. {
  134. public:
  135.         static void op_glow(const uint8_t *)
  136.         {
  137.         }
  138. };
  139.  
  140. class interpreter_track_model_extent
  141. {
  142. protected:
  143.         const uint8_t *const model_base;
  144.         const std::size_t model_length;
  145. public:
  146.         constexpr interpreter_track_model_extent(const uint8_t *const b, const std::size_t l) :
  147.                 model_base(b), model_length(l)
  148.         {
  149.         }
  150.         uint8_t truncate_invalid_model(const unsigned line, uint8_t *const p, const std::ptrdiff_t d, const std::size_t size) const
  151.         {
  152.                 const std::ptrdiff_t offset_from_base = p - model_base;
  153.                 const std::ptrdiff_t offset_of_value = offset_from_base + d;
  154.                 if (offset_of_value >= model_length || offset_of_value + size >= model_length)
  155.                 {
  156.                         auto &opref = *wp(p);
  157.                         const auto badop = opref;
  158.                         opref = OP_EOF;
  159.                         const unsigned long uml = model_length;
  160.                         const long ofb = offset_from_base;
  161.                         const long oov = offset_of_value;
  162.                         con_printf(CON_URGENT, "%s:%u: warning: invalid polymodel at %p with length %lu; opcode %u at offset %li references invalid offset %li; replacing invalid operation with EOF", __FILE__, line, model_base, uml, badop, ofb, oov);
  163.                         return 1;
  164.                 }
  165.                 return 0;
  166.         }
  167. };
  168.  
  169. class interpreter_base
  170. {
  171. public:
  172.         static uint16_t get_raw_opcode(const uint8_t *const p)
  173.         {
  174.                 return w(p);
  175.         }
  176.         static uint_fast32_t translate_opcode(const uint8_t *, const uint16_t op)
  177.         {
  178.                 return op;
  179.         }
  180.         static uint16_t get_op_subcount(const uint8_t *const p)
  181.         {
  182.                 return w(p + 2);
  183.         }
  184.         __attribute_cold
  185.         static void op_default(const unsigned op, const uint8_t *const p)
  186.         {
  187.                 char buf[64];
  188.                 snprintf(buf, sizeof(buf), "invalid polygon model opcode %u at %p", op, p);
  189.                 throw std::runtime_error(buf);
  190.         }
  191. };
  192.  
  193. class g3_poly_get_color_state :
  194.         public interpreter_ignore_op_defpoints,
  195.         public interpreter_ignore_op_defp_start,
  196.         public interpreter_ignore_op_tmappoly,
  197.         public interpreter_ignore_op_rodbm,
  198.         public interpreter_ignore_op_glow,
  199.         public interpreter_base
  200. {
  201. public:
  202.         int color = 0;
  203.         void op_flatpoly(const uint8_t *const p, const uint_fast32_t nv)
  204.         {
  205.                 if (nv > MAX_POINTS_PER_POLY)
  206.                         return;
  207.                 if (g3_check_normal_facing(*vp(p+4),*vp(p+16)) > 0) {
  208. #if defined(DXX_BUILD_DESCENT_I)
  209.                         color = (w(p+28));
  210. #elif defined(DXX_BUILD_DESCENT_II)
  211.                         color = gr_find_closest_color_15bpp(w(p + 28));
  212. #endif
  213.                 }
  214.         }
  215.         void op_sortnorm(const uint8_t *const p)
  216.         {
  217.                 const bool facing = g3_check_normal_facing(*vp(p+16),*vp(p+4)) > 0;
  218.                 color = g3_poly_get_color(facing ? p + w(p + 28) : p + w(p + 30));
  219.         }
  220.         void op_subcall(const uint8_t *const p)
  221.         {
  222. #if defined(DXX_BUILD_DESCENT_I)
  223.                 color = g3_poly_get_color(p+w(p+16));
  224. #elif defined(DXX_BUILD_DESCENT_II)
  225.                 (void)p;
  226. #endif
  227.         }
  228. };
  229.  
  230. class g3_interpreter_draw_base
  231. {
  232. protected:
  233.         grs_bitmap *const *const model_bitmaps;
  234.         polygon_model_points &Interp_point_list;
  235.         grs_canvas &canvas;
  236.         const submodel_angles anim_angles;
  237.         const g3s_lrgb model_light;
  238. private:
  239.         void rotate(uint_fast32_t i, const vms_vector *const src, const uint_fast32_t n)
  240.         {
  241.                 rotate_point_list(zip(partial_range(Interp_point_list, i, i + n), unchecked_partial_range(src, n)));
  242.         }
  243.         void set_color_by_model_light(fix g3s_lrgb::*const c, g3s_lrgb &o, const fix color) const
  244.         {
  245.                 o.*c = fixmul(color, model_light.*c);
  246.         }
  247. protected:
  248.         template <std::size_t N>
  249.                 std::array<cg3s_point *, N> prepare_point_list(const uint_fast32_t nv, const uint8_t *const p)
  250.                 {
  251.                         std::array<cg3s_point *, N> point_list;
  252.                         for (uint_fast32_t i = 0; i < nv; ++i)
  253.                                 point_list[i] = &Interp_point_list[wp(p + 30)[i]];
  254.                         return point_list;
  255.                 }
  256.         g3s_lrgb get_noglow_light(const uint8_t *const p) const
  257.         {
  258.                 g3s_lrgb light;
  259.                 const auto negdot = -vm_vec_dot(View_matrix.fvec, *vp(p + 16));
  260.                 const auto color = (f1_0 / 4) + ((negdot * 3) / 4);
  261.                 set_color_by_model_light(&g3s_lrgb::r, light, color);
  262.                 set_color_by_model_light(&g3s_lrgb::g, light, color);
  263.                 set_color_by_model_light(&g3s_lrgb::b, light, color);
  264.                 return light;
  265.         }
  266.         g3_interpreter_draw_base(grs_bitmap *const *const mbitmaps, polygon_model_points &plist, grs_canvas &ccanvas, const submodel_angles aangles, const g3s_lrgb &mlight) :
  267.                 model_bitmaps(mbitmaps), Interp_point_list(plist),
  268.                 canvas(ccanvas),
  269.                 anim_angles(aangles), model_light(mlight)
  270.         {
  271.         }
  272.         void op_defpoints(const vms_vector *const src, const uint_fast32_t n)
  273.         {
  274.                 rotate(0, src, n);
  275.         }
  276.         void op_defp_start(const uint8_t *const p, const vms_vector *const src, const uint_fast32_t n)
  277.         {
  278.                 rotate(static_cast<int>(w(p + 4)), src, n);
  279.         }
  280.         static std::pair<uint16_t, uint16_t> get_sortnorm_offsets(const uint8_t *const p)
  281.         {
  282.                 const uint16_t a = w(p + 30), b = w(p + 28);
  283.                 return (g3_check_normal_facing(*vp(p + 16), *vp(p + 4)) > 0)
  284.                         ? std::make_pair(a, b)  //draw back then front
  285.                         : std::make_pair(b, a)  //not facing.  draw front then back
  286.                 ;
  287.         }
  288.         void op_rodbm(const uint8_t *const p)
  289.         {
  290.                 const auto &&rod_bot_p = g3_rotate_point(*vp(p + 20));
  291.                 const auto &&rod_top_p = g3_rotate_point(*vp(p + 4));
  292.                 const g3s_lrgb rodbm_light{
  293.                         f1_0, f1_0, f1_0
  294.                 };
  295.                 g3_draw_rod_tmap(canvas, *model_bitmaps[w(p + 2)], rod_bot_p, w(p + 16), rod_top_p, w(p + 32), rodbm_light);
  296.         }
  297.         void op_subcall(const uint8_t *const p, const glow_values_t *const glow_values)
  298.         {
  299.                 g3_start_instance_angles(*vp(p + 4), anim_angles ? anim_angles[w(p + 2)] : zero_angles);
  300.                 g3_draw_polygon_model(model_bitmaps, Interp_point_list, canvas, anim_angles, model_light, glow_values, p + w(p + 16));
  301.                 g3_done_instance();
  302.         }
  303. };
  304.  
  305. class g3_draw_polygon_model_state :
  306.         public interpreter_base,
  307.         g3_interpreter_draw_base
  308. {
  309.         const glow_values_t *const glow_values;
  310.         unsigned glow_num = ~0u;                //glow off by default
  311. public:
  312.         g3_draw_polygon_model_state(grs_bitmap *const *const mbitmaps, polygon_model_points &plist, grs_canvas &ccanvas, const submodel_angles aangles, const g3s_lrgb &mlight, const glow_values_t *const glvalues) :
  313.                 g3_interpreter_draw_base(mbitmaps, plist, ccanvas, aangles, mlight),
  314.                 glow_values(glvalues)
  315.         {
  316.         }
  317.         void op_defpoints(const uint8_t *const p, const uint_fast32_t n)
  318.         {
  319.                 g3_interpreter_draw_base::op_defpoints(vp(p + 4), n);
  320.         }
  321.         void op_defp_start(const uint8_t *const p, const uint_fast32_t n)
  322.         {
  323.                 g3_interpreter_draw_base::op_defp_start(p, vp(p + 8), n);
  324.         }
  325.         void op_flatpoly(const uint8_t *const p, const uint_fast32_t nv)
  326.         {
  327.                 if (nv > MAX_POINTS_PER_POLY)
  328.                         return;
  329.                 if (g3_check_normal_facing(*vp(p+4),*vp(p+16)) > 0)
  330.                 {
  331. #if defined(DXX_BUILD_DESCENT_II)
  332.                         if (!glow_values || !(glow_num < glow_values->size()) || (*glow_values)[glow_num] != -3)
  333. #endif
  334.                         {
  335.                                 //                                      DPH: Now we treat this color as 15bpp
  336. #if defined(DXX_BUILD_DESCENT_I)
  337.                                 const uint8_t color = w(p + 28);
  338. #elif defined(DXX_BUILD_DESCENT_II)
  339.                                 const uint8_t color = (glow_values && glow_num < glow_values->size() && (*glow_values)[glow_num] == -2)
  340.                                         ? 255
  341.                                         : gr_find_closest_color_15bpp(w(p + 28));
  342. #endif
  343.                                 const auto point_list = prepare_point_list<MAX_POINTS_PER_POLY>(nv, p);
  344.                                 g3_draw_poly(*grd_curcanv, nv, point_list, color);
  345.                         }
  346.                 }
  347.         }
  348.         static g3s_lrgb get_glow_light(const fix c)
  349.         {
  350.                 return {c, c, c};
  351.         }
  352.         void op_tmappoly(const uint8_t *const p, const uint_fast32_t nv)
  353.         {
  354.                 if (nv > MAX_POINTS_PER_POLY)
  355.                         return;
  356.                 if (!(g3_check_normal_facing(*vp(p+4),*vp(p+16)) > 0))
  357.                         return;
  358.                 //calculate light from surface normal
  359.                 const auto &&light = (glow_values && glow_num < glow_values->size())
  360.                         ? get_glow_light((*glow_values)[std::exchange(glow_num, -1)]) //yes glow
  361.                         : get_noglow_light(p); //no glow
  362.                 //now poke light into l values
  363.                 std::array<g3s_uvl, MAX_POINTS_PER_POLY> uvl_list;
  364.                 std::array<g3s_lrgb, MAX_POINTS_PER_POLY> lrgb_list;
  365.                 const fix average_light = (light.r + light.g + light.b) / 3;
  366.                 range_for (const uint_fast32_t i, xrange(nv))
  367.                 {
  368.                         lrgb_list[i] = light;
  369.                         uvl_list[i] = (reinterpret_cast<const g3s_uvl *>(p+30+((nv&~1)+1)*2))[i];
  370.                         uvl_list[i].l = average_light;
  371.                 }
  372.                 const auto point_list = prepare_point_list<MAX_POINTS_PER_POLY>(nv, p);
  373.                 g3_draw_tmap(canvas, nv, point_list, uvl_list, lrgb_list, *model_bitmaps[w(p + 28)]);
  374.         }
  375.         void op_sortnorm(const uint8_t *const p)
  376.         {
  377.                 const auto &&offsets = get_sortnorm_offsets(p);
  378.                 const auto a = offsets.first;
  379.                 const auto b = offsets.second;
  380.                 g3_draw_polygon_model(model_bitmaps, Interp_point_list, canvas, anim_angles, model_light, glow_values, p + a);
  381.                 g3_draw_polygon_model(model_bitmaps, Interp_point_list, canvas, anim_angles, model_light, glow_values, p + b);
  382.         }
  383.         using g3_interpreter_draw_base::op_rodbm;
  384.         void op_subcall(const uint8_t *const p)
  385.         {
  386.                 g3_interpreter_draw_base::op_subcall(p, glow_values);
  387.         }
  388.         void op_glow(const uint8_t *const p)
  389.         {
  390.                 glow_num = w(p+2);
  391.         }
  392. };
  393.  
  394. class g3_draw_morphing_model_state :
  395.         public interpreter_ignore_op_glow,
  396.         public interpreter_base,
  397.         g3_interpreter_draw_base
  398. {
  399.         const vms_vector *const new_points;
  400.         static constexpr const glow_values_t *glow_values = nullptr;
  401. public:
  402.         g3_draw_morphing_model_state(grs_bitmap *const *const mbitmaps, polygon_model_points &plist, grs_canvas &ccanvas, const submodel_angles aangles, const g3s_lrgb &mlight, const vms_vector *const npoints) :
  403.                 g3_interpreter_draw_base(mbitmaps, plist, ccanvas, aangles, mlight),
  404.                 new_points(npoints)
  405.         {
  406.         }
  407.         void op_defpoints(const uint8_t *, const uint_fast32_t n)
  408.         {
  409.                 g3_interpreter_draw_base::op_defpoints(new_points, n);
  410.         }
  411.         void op_defp_start(const uint8_t *const p, const uint_fast32_t n)
  412.         {
  413.                 g3_interpreter_draw_base::op_defp_start(p, new_points, n);
  414.         }
  415.         void op_flatpoly(const uint8_t *const p, const uint_fast32_t nv)
  416.         {
  417.                 int ntris;
  418.                 const uint8_t color = w(p+28);
  419.                 unsigned i;
  420.                 auto point_list = prepare_point_list<3>(i = 2, p);
  421.                 for (ntris=nv-2;ntris;ntris--) {
  422.                         point_list[2] = &Interp_point_list[wp(p+30)[i++]];
  423.                         g3_check_and_draw_poly(canvas, point_list, color);
  424.                         point_list[1] = point_list[2];
  425.                 }
  426.         }
  427.         void op_tmappoly(const uint8_t *const p, const uint_fast32_t nv)
  428.         {
  429.                 if (nv > MAX_POINTS_PER_POLY)
  430.                         return;
  431.                 std::array<g3s_uvl, MAX_POINTS_PER_POLY> uvl_list;
  432.                 std::array<g3s_lrgb, MAX_POINTS_PER_POLY> lrgb_list;
  433.                 lrgb_list.fill(get_noglow_light(p));
  434.                 range_for (const uint_fast32_t i, xrange(nv))
  435.                         uvl_list[i] = (reinterpret_cast<const g3s_uvl *>(p+30+((nv&~1)+1)*2))[i];
  436.                 const auto point_list = prepare_point_list<MAX_POINTS_PER_POLY>(nv, p);
  437.                 g3_draw_tmap(canvas, nv, point_list, uvl_list, lrgb_list, *model_bitmaps[w(p + 28)]);
  438.         }
  439.         void op_sortnorm(const uint8_t *const p)
  440.         {
  441.                 const auto &&offsets = get_sortnorm_offsets(p);
  442.                 auto &a = offsets.first;
  443.                 auto &b = offsets.second;
  444.                 g3_draw_morphing_model(canvas, p + a, model_bitmaps, anim_angles, model_light, new_points, Interp_point_list);
  445.                 g3_draw_morphing_model(canvas, p + b, model_bitmaps, anim_angles, model_light, new_points, Interp_point_list);
  446.         }
  447.         using g3_interpreter_draw_base::op_rodbm;
  448.         void op_subcall(const uint8_t *const p)
  449.         {
  450.                 g3_interpreter_draw_base::op_subcall(p, glow_values);
  451.         }
  452. };
  453.  
  454. template <typename T>
  455. class model_load_state :
  456.         public interpreter_track_model_extent,
  457.         public interpreter_ignore_op_defpoints,
  458.         public interpreter_ignore_op_defp_start,
  459.         public interpreter_ignore_op_rodbm,
  460.         public interpreter_ignore_op_glow,
  461.         public interpreter_base
  462. {
  463. public:
  464.         using interpreter_track_model_extent::interpreter_track_model_extent;
  465.         int16_t init_bounded_model_sub(const unsigned line, uint8_t *const p, const std::ptrdiff_t d) const
  466.         {
  467.                 if (truncate_invalid_model(line, p, d, sizeof(uint16_t)))
  468.                         return 0;
  469.                 return static_cast<const T *>(this)->init_sub_model(p + d);
  470.         }
  471.         void op_tmappoly(uint8_t *const p, const uint_fast32_t nv)
  472.         {
  473.                 constexpr unsigned offset_texture = 28;
  474.                 (void)nv;
  475.                 Assert(nv > 2);         //must have 3 or more points
  476.                 if (truncate_invalid_model(__LINE__, p, offset_texture, sizeof(uint16_t)))
  477.                         return;
  478.                 static_cast<T *>(this)->update_texture(w(p + offset_texture));
  479.         }
  480.         void op_sortnorm(uint8_t *const p)
  481.         {
  482.                 constexpr unsigned offset_submodel0 = 28;
  483.                 constexpr unsigned offset_submodel1 = offset_submodel0 + sizeof(uint16_t);
  484.                 if (truncate_invalid_model(__LINE__, p, offset_submodel1, sizeof(uint16_t)))
  485.                         return;
  486.                 const auto n0 = w(p + offset_submodel0);
  487.                 const auto h0 = init_bounded_model_sub(__LINE__, p, n0);
  488.                 const auto n1 = w(p + offset_submodel1);
  489.                 const auto h1 = init_bounded_model_sub(__LINE__, p, n1);
  490.                 const auto hm = std::max(h0, h1);
  491.                 static_cast<T *>(this)->update_texture(hm);
  492.         }
  493.         void op_subcall(uint8_t *const p)
  494.         {
  495.                 constexpr unsigned offset_displacement = 16;
  496.                 if (truncate_invalid_model(__LINE__, p, offset_displacement, sizeof(uint16_t)))
  497.                         return;
  498.                 const auto n0 = w(p + offset_displacement);
  499.                 const auto h0 = init_bounded_model_sub(__LINE__, p, n0);
  500.                 static_cast<T *>(this)->update_texture(h0);
  501.         }
  502. };
  503.  
  504. class init_model_sub_state :
  505.         public model_load_state<init_model_sub_state>
  506. #if defined(DXX_BUILD_DESCENT_II)
  507.         , public interpreter_ignore_op_flatpoly
  508. #endif
  509. {
  510. public:
  511.         int16_t highest_texture_num = -1;
  512.         using model_load_state::model_load_state;
  513.         int16_t init_sub_model(uint8_t *const p) const
  514.         {
  515.                 return init_model_sub(p, model_base, model_length);
  516.         }
  517.         void update_texture(const int16_t t)
  518.         {
  519.                 if (highest_texture_num < t)
  520.                         highest_texture_num = t;
  521.         }
  522. #if defined(DXX_BUILD_DESCENT_I)
  523.         void op_flatpoly(uint8_t *const p, const uint_fast32_t nv) const
  524.         {
  525.                 //must have 3 or more points
  526.                 if (nv <= 2)
  527.                         return;
  528.                 const auto p16 = wp(p + 28);
  529.                 *p16 = static_cast<short>(gr_find_closest_color_15bpp(*p16));
  530.         }
  531. #endif
  532. };
  533.  
  534. #if defined(DXX_BUILD_DESCENT_I)
  535. class validate_model_sub_state :
  536.         public model_load_state<validate_model_sub_state>,
  537.         public interpreter_ignore_op_flatpoly
  538. {
  539. public:
  540.         using model_load_state::model_load_state;
  541.         unsigned init_sub_model(uint8_t *const p) const
  542.         {
  543.                 validate_model_sub(p, model_base, model_length);
  544.                 return 0;
  545.         }
  546.         void update_texture(int16_t)
  547.         {
  548.         }
  549. };
  550. #endif
  551.  
  552. constexpr const glow_values_t *g3_draw_morphing_model_state::glow_values;
  553.  
  554. }
  555.  
  556. template <typename P, typename State>
  557. static std::size_t dispatch_polymodel_op(const P p, State &state, const uint_fast32_t op)
  558. {
  559.         switch (op)
  560.         {
  561.                 case OP_DEFPOINTS: {
  562.                         const auto n = state.get_op_subcount(p);
  563.                         const std::size_t record_size = n * sizeof(vms_vector) + 4;
  564.                         state.op_defpoints(p, n);
  565.                         return record_size;
  566.                 }
  567.                 case OP_DEFP_START: {
  568.                         const auto n = state.get_op_subcount(p);
  569.                         const std::size_t record_size = n * sizeof(vms_vector) + 8;
  570.                         state.op_defp_start(p, n);
  571.                         return record_size;
  572.                 }
  573.                 case OP_FLATPOLY: {
  574.                         const auto n = state.get_op_subcount(p);
  575.                         const std::size_t record_size = 30 + ((n & ~1) + 1) * 2;
  576.                         state.op_flatpoly(p, n);
  577.                         return record_size;
  578.                 }
  579.                 case OP_TMAPPOLY: {
  580.                         const auto n = state.get_op_subcount(p);
  581.                         const std::size_t record_size = 30 + ((n & ~1) + 1) * 2 + n * 12;
  582.                         state.op_tmappoly(p, n);
  583.                         return record_size;
  584.                 }
  585.                 case OP_SORTNORM: {
  586.                         const std::size_t record_size = 32;
  587.                         state.op_sortnorm(p);
  588.                         return record_size;
  589.                 }
  590.                 case OP_RODBM: {
  591.                         const std::size_t record_size = 36;
  592.                         state.op_rodbm(p);
  593.                         return record_size;
  594.                 }
  595.                 case OP_SUBCALL: {
  596.                         const std::size_t record_size = 20;
  597.                         state.op_subcall(p);
  598.                         return record_size;
  599.                 }
  600.                 case OP_GLOW: {
  601.                         const std::size_t record_size = 4;
  602.                         state.op_glow(p);
  603.                         return record_size;
  604.                 }
  605.                 default:
  606.                         state.op_default(op, p);
  607.                         return 2;
  608.         }
  609. }
  610.  
  611. template <typename P, typename State>
  612. static P iterate_polymodel(P p, State &state)
  613. {
  614.         for (uint16_t op; (op = state.get_raw_opcode(p)) != OP_EOF;)
  615.                 p += dispatch_polymodel_op(p, state, state.translate_opcode(p, op));
  616.         return p;
  617. }
  618.  
  619. }
  620.  
  621. #if DXX_WORDS_BIGENDIAN
  622. namespace dcx {
  623.  
  624. static inline fix *fp(uint8_t *p)
  625. {
  626.         return reinterpret_cast<fix *>(p);
  627. }
  628.  
  629. static inline vms_vector *vp(uint8_t *p)
  630. {
  631.         return reinterpret_cast<vms_vector *>(p);
  632. }
  633.  
  634. static void short_swap(short *s)
  635. {
  636.         *s = SWAPSHORT(*s);
  637. }
  638.  
  639. static void fix_swap(fix &f)
  640. {
  641.         f = SWAPINT(f);
  642. }
  643.  
  644. static void fix_swap(fix *f)
  645. {
  646.         fix_swap(*f);
  647. }
  648.  
  649. static void vms_vector_swap(vms_vector &v)
  650. {
  651.         fix_swap(v.x);
  652.         fix_swap(v.y);
  653.         fix_swap(v.z);
  654. }
  655.  
  656. namespace {
  657.  
  658. class swap_polygon_model_data_state : public interpreter_base
  659. {
  660. public:
  661.         static uint_fast32_t translate_opcode(uint8_t *const p, const uint16_t op)
  662.         {
  663.                 return *wp(p) = INTEL_SHORT(op);
  664.         }
  665.         static uint16_t get_op_subcount(const uint8_t *const p)
  666.         {
  667.                 return SWAPSHORT(w(p + 2));
  668.         }
  669.         static void op_defpoints(uint8_t *const p, const uint_fast32_t n)
  670.         {
  671.                 *wp(p + 2) = n;
  672.                 range_for (const uint_fast32_t i, xrange(n))
  673.                         vms_vector_swap(*vp((p + 4) + (i * sizeof(vms_vector))));
  674.         }
  675.         static void op_defp_start(uint8_t *const p, const uint_fast32_t n)
  676.         {
  677.                 *wp(p + 2) = n;
  678.                 short_swap(wp(p + 4));
  679.                 range_for (const uint_fast32_t i, xrange(n))
  680.                         vms_vector_swap(*vp((p + 8) + (i * sizeof(vms_vector))));
  681.         }
  682.         static void op_flatpoly(uint8_t *const p, const uint_fast32_t n)
  683.         {
  684.                 *wp(p + 2) = n;
  685.                 vms_vector_swap(*vp(p + 4));
  686.                 vms_vector_swap(*vp(p + 16));
  687.                 short_swap(wp(p+28));
  688.                 for (uint_fast32_t i = 0; i < n; ++i)
  689.                         short_swap(wp(p + 30 + (i * 2)));
  690.         }
  691.         static void op_tmappoly(uint8_t *const p, const uint_fast32_t n)
  692.         {
  693.                 *wp(p + 2) = n;
  694.                 vms_vector_swap(*vp(p + 4));
  695.                 vms_vector_swap(*vp(p + 16));
  696.                 range_for (const uint_fast32_t i, xrange(n)) {
  697.                         const auto uvl_val = reinterpret_cast<g3s_uvl *>((p+30+((n&~1)+1)*2) + (i * sizeof(g3s_uvl)));
  698.                         fix_swap(&uvl_val->u);
  699.                         fix_swap(&uvl_val->v);
  700.                 }
  701.                 short_swap(wp(p+28));
  702.                 range_for (const uint_fast32_t i, xrange(n))
  703.                         short_swap(wp(p + 30 + (i * 2)));
  704.         }
  705.         void op_sortnorm(uint8_t *const p)
  706.         {
  707.                 vms_vector_swap(*vp(p + 4));
  708.                 vms_vector_swap(*vp(p + 16));
  709.                 short_swap(wp(p + 28));
  710.                 short_swap(wp(p + 30));
  711.                 swap_polygon_model_data(p + w(p+28));
  712.                 swap_polygon_model_data(p + w(p+30));
  713.         }
  714.         static void op_rodbm(uint8_t *const p)
  715.         {
  716.                 vms_vector_swap(*vp(p + 20));
  717.                 vms_vector_swap(*vp(p + 4));
  718.                 short_swap(wp(p+2));
  719.                 fix_swap(fp(p + 16));
  720.                 fix_swap(fp(p + 32));
  721.         }
  722.         void op_subcall(uint8_t *const p)
  723.         {
  724.                 short_swap(wp(p+2));
  725.                 vms_vector_swap(*vp(p+4));
  726.                 short_swap(wp(p+16));
  727.                 swap_polygon_model_data(p + w(p+16));
  728.         }
  729.         static void op_glow(uint8_t *const p)
  730.         {
  731.                 short_swap(wp(p + 2));
  732.         }
  733. };
  734.  
  735. }
  736.  
  737. void swap_polygon_model_data(ubyte *data)
  738. {
  739.         swap_polygon_model_data_state state;
  740.         iterate_polymodel(data, state);
  741. }
  742.  
  743. }
  744. #endif
  745.  
  746. #if DXX_WORDS_NEED_ALIGNMENT
  747.  
  748. #if DXX_WORDS_NEED_ALIGNMENT
  749. #define MAX_CHUNKS 100 // increase if insufficent
  750. #endif //def WORDS_NEED_ALIGNMENT
  751. namespace dcx {
  752.  
  753. namespace {
  754.  
  755. /*
  756.  * A chunk struct (as used for alignment) contains all relevant data
  757.  * concerning a piece of data that may need to be aligned.
  758.  * To align it, we need to copy it to an aligned position,
  759.  * and update all pointers  to it.
  760.  * (Those pointers are actually offsets
  761.  * relative to start of model_data) to it.
  762.  */
  763. struct chunk
  764. {
  765.         const uint8_t *old_base; // where the offset sets off from (relative to beginning of model_data)
  766.         uint8_t *new_base; // where the base is in the aligned structure
  767.         short offset; // how much to add to base to get the address of the offset
  768.         short correction; // how much the value of the offset must be shifted for alignment
  769. };
  770.  
  771. static void add_chunk(const uint8_t *old_base, uint8_t *new_base, int offset,
  772.                chunk *chunk_list, int *no_chunks)
  773. {
  774.         Assert(*no_chunks + 1 < MAX_CHUNKS); //increase MAX_CHUNKS if you get this
  775.         chunk_list[*no_chunks].old_base = old_base;
  776.         chunk_list[*no_chunks].new_base = new_base;
  777.         chunk_list[*no_chunks].offset = offset;
  778.         chunk_list[*no_chunks].correction = 0;
  779.         (*no_chunks)++;
  780. }
  781.  
  782. class get_chunks_state :
  783.         public interpreter_ignore_op_defpoints,
  784.         public interpreter_ignore_op_defp_start,
  785.         public interpreter_ignore_op_flatpoly,
  786.         public interpreter_ignore_op_tmappoly,
  787.         public interpreter_ignore_op_rodbm,
  788.         public interpreter_ignore_op_glow,
  789.         public interpreter_base
  790. {
  791.         const uint8_t *const data;
  792.         uint8_t *const new_data;
  793.         chunk *const list;
  794.         int *const no;
  795. public:
  796.         get_chunks_state(const uint8_t *const p, uint8_t *const ndata, chunk *const l, int *const n) :
  797.                 data(p), new_data(ndata), list(l), no(n)
  798.         {
  799.         }
  800.         static uint_fast32_t translate_opcode(const uint8_t *, const uint16_t op)
  801.         {
  802.                 return INTEL_SHORT(op);
  803.         }
  804.         static uint16_t get_op_subcount(const uint8_t *const p)
  805.         {
  806.                 return GET_INTEL_SHORT(p + 2);
  807.         }
  808.         void op_sortnorm(const uint8_t *const p)
  809.         {
  810.                 add_chunk(p, p - data + new_data, 28, list, no);
  811.                 add_chunk(p, p - data + new_data, 30, list, no);
  812.         }
  813.         void op_subcall(const uint8_t *const p)
  814.         {
  815.                 add_chunk(p, p - data + new_data, 16, list, no);
  816.         }
  817. };
  818.  
  819. /*
  820.  * finds what chunks the data points to, adds them to the chunk_list,
  821.  * and returns the length of the current chunk
  822.  */
  823. int get_chunks(const uint8_t *data, uint8_t *new_data, chunk *list, int *no)
  824. {
  825.         get_chunks_state state(data, new_data, list, no);
  826.         auto p = iterate_polymodel(data, state);
  827.         return p + 2 - data;
  828. }
  829.  
  830. static const uint8_t *old_dest(const chunk &o) // return where chunk is (in unaligned struct)
  831. {
  832.         return GET_INTEL_SHORT(&o.old_base[o.offset]) + o.old_base;
  833. }
  834. static uint8_t *new_dest(const chunk &o) // return where chunk is (in aligned struct)
  835. {
  836.         return GET_INTEL_SHORT(&o.old_base[o.offset]) + o.new_base + o.correction;
  837. }
  838.  
  839. /*
  840.  * find chunk with smallest address
  841.  */
  842. static int get_first_chunks_index(chunk *chunk_list, int no_chunks)
  843. {
  844.         int first_index = 0;
  845.         Assert(no_chunks >= 1);
  846.         for (int i = 1; i < no_chunks; i++)
  847.                 if (old_dest(chunk_list[i]) < old_dest(chunk_list[first_index]))
  848.                         first_index = i;
  849.         return first_index;
  850. }
  851.  
  852. }
  853.  
  854. void align_polygon_model_data(polymodel *pm)
  855. {
  856.         int chunk_len;
  857.         int total_correction = 0;
  858.         chunk cur_ch;
  859.         chunk ch_list[MAX_CHUNKS];
  860.         int no_chunks = 0;
  861.         constexpr unsigned SHIFT_SPACE = 500;   // increase if insufficient
  862.         int tmp_size = pm->model_data_size + SHIFT_SPACE;
  863.         RAIIdmem<uint8_t[]> tmp;
  864.         MALLOC(tmp, uint8_t[], tmp_size); // where we build the aligned version of pm->model_data
  865.  
  866.         Assert(tmp != NULL);
  867.         //start with first chunk (is always aligned!)
  868.         const uint8_t *cur_old = pm->model_data.get();
  869.         auto cur_new = tmp.get();
  870.         chunk_len = get_chunks(cur_old, cur_new, ch_list, &no_chunks);
  871.         memcpy(cur_new, cur_old, chunk_len);
  872.         while (no_chunks > 0) {
  873.                 int first_index = get_first_chunks_index(ch_list, no_chunks);
  874.                 cur_ch = ch_list[first_index];
  875.                 // remove first chunk from array:
  876.                 no_chunks--;
  877.                 for (int i = first_index; i < no_chunks; i++)
  878.                         ch_list[i] = ch_list[i + 1];
  879.                 // if (new) address unaligned:
  880.                 const uintptr_t u = reinterpret_cast<uintptr_t>(new_dest(cur_ch));
  881.                 if (u % 4L != 0) {
  882.                         // calculate how much to move to be aligned
  883.                         short to_shift = 4 - u % 4L;
  884.                         // correct chunks' addresses
  885.                         cur_ch.correction += to_shift;
  886.                         for (int i = 0; i < no_chunks; i++)
  887.                                 ch_list[i].correction += to_shift;
  888.                         total_correction += to_shift;
  889.                         Assert(reinterpret_cast<uintptr_t>(new_dest(cur_ch)) % 4L == 0);
  890.                         Assert(total_correction <= SHIFT_SPACE); // if you get this, increase SHIFT_SPACE
  891.                 }
  892.                 //write (corrected) chunk for current chunk:
  893.                 *(reinterpret_cast<short *>(cur_ch.new_base + cur_ch.offset))
  894.                         = INTEL_SHORT(static_cast<short>(cur_ch.correction + GET_INTEL_SHORT(cur_ch.old_base + cur_ch.offset)));
  895.                 //write (correctly aligned) chunk:
  896.                 cur_old = old_dest(cur_ch);
  897.                 cur_new = new_dest(cur_ch);
  898.                 chunk_len = get_chunks(cur_old, cur_new, ch_list, &no_chunks);
  899.                 memcpy(cur_new, cur_old, chunk_len);
  900.                 //correct submodel_ptr's for pm, too
  901.                 for (auto &sp : pm->submodel_ptrs)
  902.                         if (&pm->model_data[sp] >= cur_old &&
  903.                                 &pm->model_data[sp] < cur_old + chunk_len)
  904.                                 sp += (cur_new - tmp.get()) - (cur_old - pm->model_data.get());
  905.         }
  906.         pm->model_data_size += total_correction;
  907.         pm->model_data = std::make_unique<uint8_t[]>(pm->model_data_size);
  908.         memcpy(pm->model_data.get(), tmp.get(), pm->model_data_size);
  909. }
  910.  
  911. }
  912. #endif //def WORDS_NEED_ALIGNMENT
  913.  
  914. namespace dsx {
  915.  
  916. // check a polymodel for it's color and return it
  917. int g3_poly_get_color(const uint8_t *p)
  918. {
  919.         g3_poly_get_color_state state;
  920.         iterate_polymodel(p, state);
  921.         return state.color;
  922. }
  923.  
  924. //calls the object interpreter to render an object.  The object renderer
  925. //is really a seperate pipeline. returns true if drew
  926. void g3_draw_polygon_model(grs_bitmap *const *const model_bitmaps, polygon_model_points &Interp_point_list, grs_canvas &canvas, const submodel_angles anim_angles, const g3s_lrgb model_light, const glow_values_t *const glow_values, const uint8_t *const p)
  927. {
  928.         g3_draw_polygon_model_state state(model_bitmaps, Interp_point_list, canvas, anim_angles, model_light, glow_values);
  929.         iterate_polymodel(p, state);
  930. }
  931.  
  932. #ifndef NDEBUG
  933. static int nest_count;
  934. #endif
  935.  
  936. //alternate interpreter for morphing object
  937. void g3_draw_morphing_model(grs_canvas &canvas, const uint8_t *const p, grs_bitmap *const *const model_bitmaps, const submodel_angles anim_angles, const g3s_lrgb model_light, const vms_vector *new_points, polygon_model_points &Interp_point_list)
  938. {
  939.         g3_draw_morphing_model_state state(model_bitmaps, Interp_point_list, canvas, anim_angles, model_light, new_points);
  940.         iterate_polymodel(p, state);
  941. }
  942.  
  943. static int16_t init_model_sub(uint8_t *const model_sub_ptr, const uint8_t *const model_base_ptr, const std::size_t model_size)
  944. {
  945.         init_model_sub_state state(model_base_ptr, model_size);
  946.         Assert(++nest_count < 1000);
  947.         iterate_polymodel(model_sub_ptr, state);
  948.         return state.highest_texture_num;
  949. }
  950.  
  951. //init code for bitmap models
  952. int16_t g3_init_polygon_model(uint8_t *const model_ptr, const std::size_t model_size)
  953. {
  954.         #ifndef NDEBUG
  955.         nest_count = 0;
  956.         #endif
  957.         return init_model_sub(model_ptr, model_ptr, model_size);
  958. }
  959.  
  960. #if defined(DXX_BUILD_DESCENT_I)
  961. static void validate_model_sub(uint8_t *const model_sub_ptr, const uint8_t *const model_base_ptr, const std::size_t model_size)
  962. {
  963.         validate_model_sub_state state(model_base_ptr, model_size);
  964.         assert(++nest_count < 1000);
  965.         iterate_polymodel(model_sub_ptr, state);
  966. }
  967.  
  968. void g3_validate_polygon_model(uint8_t *const model_ptr, const std::size_t model_size)
  969. {
  970. #ifndef NDEBUG
  971.         nest_count = 0;
  972. #endif
  973.         return validate_model_sub(model_ptr, model_ptr, model_size);
  974. }
  975. #endif
  976.  
  977. }
  978.