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.  * Hacked-in polygon objects
  23.  *
  24.  */
  25.  
  26.  
  27. #include <stdio.h>
  28. #include <stdlib.h>
  29. #include <string.h>
  30.  
  31. #include "inferno.h"
  32. #include "robot.h"
  33. #include "vecmat.h"
  34. #include "cntrlcen.h"
  35. #include "interp.h"
  36. #include "dxxerror.h"
  37. #include "u_mem.h"
  38. #include "args.h"
  39. #include "physfs-serial.h"
  40. #include "physfsx.h"
  41. #ifndef DRIVE
  42. #include "texmap.h"
  43. #include "bm.h"
  44. #include "textures.h"
  45. #include "object.h"
  46. #include "lighting.h"
  47. #include "piggy.h"
  48. #endif
  49. #include "render.h"
  50. #if DXX_USE_OGL
  51. #include "ogl_init.h"
  52. #endif
  53. #include "bm.h"
  54.  
  55. #include "d_zip.h"
  56. #include "partial_range.h"
  57. #include <memory>
  58.  
  59. namespace dcx {
  60. unsigned N_polygon_models = 0;
  61. }
  62.  
  63. #define PM_COMPATIBLE_VERSION 6
  64. #define PM_OBJFILE_VERSION 8
  65.  
  66. static unsigned Pof_file_end;
  67. static unsigned Pof_addr;
  68.  
  69. #define MODEL_BUF_SIZE  32768
  70.  
  71. static void _pof_cfseek(int len,int type)
  72. {
  73.         switch (type) {
  74.                 case SEEK_SET:  Pof_addr = len; break;
  75.                 case SEEK_CUR:  Pof_addr += len;        break;
  76.                 case SEEK_END:
  77.                         Assert(len <= 0);       //      seeking from end, better be moving back.
  78.                         Pof_addr = Pof_file_end + len;
  79.                         break;
  80.         }
  81.  
  82.         if (Pof_addr > MODEL_BUF_SIZE)
  83.                 Int3();
  84. }
  85.  
  86. #define pof_cfseek(_buf,_len,_type) _pof_cfseek((_len),(_type))
  87.  
  88. static int pof_read_int(ubyte *bufp)
  89. {
  90.         int i;
  91.  
  92.         i = *(reinterpret_cast<int *>(&bufp[Pof_addr]));
  93.         Pof_addr += 4;
  94.         return INTEL_INT(i);
  95.  
  96. //      if (PHYSFS_read(f,&i,sizeof(i),1) != 1)
  97. //              Error("Unexpected end-of-file while reading object");
  98. //
  99. //      return i;
  100. }
  101.  
  102. static size_t pof_cfread(void *dst, size_t elsize, size_t nelem, ubyte *bufp)
  103. {
  104.         if (Pof_addr + nelem*elsize > Pof_file_end)
  105.                 return 0;
  106.  
  107.         memcpy(dst, &bufp[Pof_addr], elsize*nelem);
  108.  
  109.         Pof_addr += elsize*nelem;
  110.  
  111.         if (Pof_addr > MODEL_BUF_SIZE)
  112.                 Int3();
  113.  
  114.         return nelem;
  115. }
  116.  
  117. // #define new_read_int(i,f) PHYSFS_read((f),&(i),sizeof(i),1)
  118. #define new_pof_read_int(i,f) pof_cfread(&(i),sizeof(i),1,(f))
  119.  
  120. static short pof_read_short(ubyte *bufp)
  121. {
  122.         short s;
  123.  
  124.         s = *(reinterpret_cast<int16_t *>(&bufp[Pof_addr]));
  125.         Pof_addr += 2;
  126.         return INTEL_SHORT(s);
  127. //      if (PHYSFS_read(f,&s,sizeof(s),1) != 1)
  128. //              Error("Unexpected end-of-file while reading object");
  129. //
  130. //      return s;
  131. }
  132.  
  133. static void pof_read_string(char *buf,int max_char, ubyte *bufp)
  134. {
  135.         for (int i=0; i<max_char; i++) {
  136.                 if ((*buf++ = bufp[Pof_addr++]) == 0)
  137.                         break;
  138.         }
  139.  
  140. //      while (max_char-- && (*buf=PHYSFSX_fgetc(f)) != 0) buf++;
  141.  
  142. }
  143.  
  144. static void pof_read_vecs(vms_vector *vecs,int n,ubyte *bufp)
  145. {
  146. //      PHYSFS_read(f,vecs,sizeof(vms_vector),n);
  147.         for (int i = 0; i < n; i++)
  148.         {
  149.                 vecs[i].x = pof_read_int(bufp);
  150.                 vecs[i].y = pof_read_int(bufp);
  151.                 vecs[i].z = pof_read_int(bufp);
  152.         }
  153.  
  154.         if (Pof_addr > MODEL_BUF_SIZE)
  155.                 Int3();
  156. }
  157.  
  158. static void pof_read_angs(vms_angvec *angs,int n,ubyte *bufp)
  159. {
  160.         for (int i = 0; i < n; i++)
  161.         {
  162.                 angs[i].p = pof_read_short(bufp);
  163.                 angs[i].b = pof_read_short(bufp);
  164.                 angs[i].h = pof_read_short(bufp);
  165.         }
  166.  
  167.         if (Pof_addr > MODEL_BUF_SIZE)
  168.                 Int3();
  169. }
  170.  
  171. #define ID_OHDR 0x5244484f // 'RDHO'  //Object header
  172. #define ID_SOBJ 0x4a424f53 // 'JBOS'  //Subobject header
  173. #define ID_GUNS 0x534e5547 // 'SNUG'  //List of guns on this object
  174. #define ID_ANIM 0x4d494e41 // 'MINA'  //Animation data
  175. #define ID_IDTA 0x41544449 // 'ATDI'  //Interpreter data
  176. #define ID_TXTR 0x52545854 // 'RTXT'  //Texture filename list
  177.  
  178. static std::array<std::array<vms_angvec, MAX_SUBMODELS>, N_ANIM_STATES> anim_angs;
  179.  
  180. //set the animation angles for this robot.  Gun fields of robot info must
  181. //be filled in.
  182.  
  183. //reads a binary file containing a 3d model
  184. static polymodel *read_model_file(polymodel *pm,const char *filename,robot_info *r)
  185. {
  186.         short version;
  187.         int len, next_chunk;
  188.         ubyte   model_buf[MODEL_BUF_SIZE];
  189.  
  190.         auto ifile = PHYSFSX_openReadBuffered(filename);
  191.         if (!ifile)
  192.                 Error("Can't open file <%s>",filename);
  193.  
  194.         Assert(PHYSFS_fileLength(ifile) <= MODEL_BUF_SIZE);
  195.  
  196.         Pof_addr = 0;
  197.         Pof_file_end = PHYSFS_read(ifile, model_buf, 1, PHYSFS_fileLength(ifile));
  198.         ifile.reset();
  199.         const int model_id = pof_read_int(model_buf);
  200.  
  201.         if (model_id != 0x4f505350) /* 'OPSP' */
  202.                 Error("Bad ID in model file <%s>",filename);
  203.  
  204.         version = pof_read_short(model_buf);
  205.        
  206.         if (version < PM_COMPATIBLE_VERSION || version > PM_OBJFILE_VERSION)
  207.                 Error("Bad version (%d) in model file <%s>",version,filename);
  208.  
  209.         int pof_id;
  210.         while (new_pof_read_int(pof_id, model_buf) == 1)
  211.         {
  212.                 pof_id = INTEL_INT(pof_id);
  213.                 //id  = pof_read_int(model_buf);
  214.                 len = pof_read_int(model_buf);
  215.                 next_chunk = Pof_addr + len;
  216.  
  217.                 switch (pof_id)
  218.                 {
  219.                         case ID_OHDR: {         //Object header
  220.                                 vms_vector pmmin,pmmax;
  221.  
  222.                                 pm->n_models = pof_read_int(model_buf);
  223.                                 pm->rad = pof_read_int(model_buf);
  224.  
  225.                                 Assert(pm->n_models <= MAX_SUBMODELS);
  226.  
  227.                                 pof_read_vecs(&pmmin,1,model_buf);
  228.                                 pof_read_vecs(&pmmax,1,model_buf);
  229.  
  230.                                 break;
  231.                         }
  232.                        
  233.                         case ID_SOBJ: {         //Subobject header
  234.                                 int n;
  235.  
  236.                                 n = pof_read_short(model_buf);
  237.  
  238.                                 Assert(n < MAX_SUBMODELS);
  239.  
  240.                                 pm->submodel_parents[n] = pof_read_short(model_buf);
  241.  
  242.                                 pof_read_vecs(&pm->submodel_norms[n],1,model_buf);
  243.                                 pof_read_vecs(&pm->submodel_pnts[n],1,model_buf);
  244.                                 pof_read_vecs(&pm->submodel_offsets[n],1,model_buf);
  245.  
  246.                                 pm->submodel_rads[n] = pof_read_int(model_buf);         //radius
  247.  
  248.                                 pm->submodel_ptrs[n] = pof_read_int(model_buf); //offset
  249.  
  250.                                 break;
  251.  
  252.                         }
  253.                        
  254.                         #ifndef DRIVE
  255.                         case ID_GUNS: {         //List of guns on this object
  256.  
  257.                                 if (r) {
  258.                                         vms_vector gun_dir;
  259.  
  260.                                         r->n_guns = pof_read_int(model_buf);
  261.  
  262.                                         Assert(r->n_guns <= MAX_GUNS);
  263.  
  264.                                         for (int i=0;i<r->n_guns;i++) {
  265.                                                 const uint_fast32_t gun_id = pof_read_short(model_buf);
  266.                                                 /*
  267.                                                  * D1 v1.0 boss02.pof has id=4 and r->n_guns==4.
  268.                                                  * Relax the assert to check only for memory
  269.                                                  * corruption.
  270.                                                  */
  271.                                                 assert(gun_id < std::size(r->gun_submodels));
  272.                                                 auto &submodel = r->gun_submodels[gun_id];
  273.                                                 submodel = pof_read_short(model_buf);
  274.                                                 Assert(submodel != 0xff);
  275.                                                 pof_read_vecs(&r->gun_points[gun_id], 1, model_buf);
  276.  
  277.                                                 if (version >= 7)
  278.                                                         pof_read_vecs(&gun_dir,1,model_buf);
  279.                                         }
  280.                                 }
  281.                                 else
  282.                                         pof_cfseek(model_buf,len,SEEK_CUR);
  283.  
  284.                                 break;
  285.                         }
  286.                        
  287.                         case ID_ANIM:           //Animation data
  288.                                 if (r) {
  289.                                         unsigned n_frames;
  290.  
  291.                                         n_frames = pof_read_short(model_buf);
  292.  
  293.                                         Assert(n_frames == N_ANIM_STATES);
  294.  
  295.                                         for (int m=0;m<pm->n_models;m++)
  296.                                                 range_for (auto &f, partial_range(anim_angs, n_frames))
  297.                                                         pof_read_angs(&f[m], 1, model_buf);
  298.  
  299.  
  300.                                         robot_set_angles(r,pm,anim_angs);
  301.                                
  302.                                 }
  303.                                 else
  304.                                         pof_cfseek(model_buf,len,SEEK_CUR);
  305.  
  306.                                 break;
  307.                         #endif
  308.                        
  309.                         case ID_TXTR: {         //Texture filename list
  310.                                 int n;
  311.                                 char name_buf[128];
  312.  
  313.                                 n = pof_read_short(model_buf);
  314.                                 while (n--) {
  315.                                         pof_read_string(name_buf,128,model_buf);
  316.                                 }
  317.  
  318.                                 break;
  319.                         }
  320.                        
  321.                         case ID_IDTA:           //Interpreter data
  322.                                 pm->model_data_size = len;
  323.                                 pm->model_data = std::make_unique<uint8_t[]>(pm->model_data_size);
  324.  
  325.                                 pof_cfread(pm->model_data.get(),1,len,model_buf);
  326.  
  327.                                 break;
  328.  
  329.                         default:
  330.                                 pof_cfseek(model_buf,len,SEEK_CUR);
  331.                                 break;
  332.  
  333.                 }
  334.                 if ( version >= 8 )             // Version 8 needs 4-byte alignment!!!
  335.                         pof_cfseek(model_buf,next_chunk,SEEK_SET);
  336.         }
  337.  
  338. #if DXX_WORDS_NEED_ALIGNMENT
  339.         align_polygon_model_data(pm);
  340. #endif
  341.         if constexpr (words_bigendian)
  342.                 swap_polygon_model_data(pm->model_data.get());
  343.         return pm;
  344. }
  345.  
  346. //reads the gun information for a model
  347. //fills in arrays gun_points & gun_dirs, returns the number of guns read
  348. void read_model_guns(const char *filename, reactor &r)
  349. {
  350.         auto &gun_points = r.gun_points;
  351.         auto &gun_dirs = r.gun_dirs;
  352.         short version;
  353.         int len;
  354.         int n_guns=0;
  355.         ubyte   model_buf[MODEL_BUF_SIZE];
  356.  
  357.         auto ifile = PHYSFSX_openReadBuffered(filename);
  358.         if (!ifile)
  359.                 Error("Can't open file <%s>",filename);
  360.  
  361.         Assert(PHYSFS_fileLength(ifile) <= MODEL_BUF_SIZE);
  362.  
  363.         Pof_addr = 0;
  364.         Pof_file_end = PHYSFS_read(ifile, model_buf, 1, PHYSFS_fileLength(ifile));
  365.         ifile.reset();
  366.  
  367.         const int model_id = pof_read_int(model_buf);
  368.  
  369.         if (model_id != 0x4f505350) /* 'OPSP' */
  370.                 Error("Bad ID in model file <%s>",filename);
  371.  
  372.         version = pof_read_short(model_buf);
  373.  
  374.         Assert(version >= 7);           //must be 7 or higher for this data
  375.  
  376.         if (version < PM_COMPATIBLE_VERSION || version > PM_OBJFILE_VERSION)
  377.                 Error("Bad version (%d) in model file <%s>",version,filename);
  378.  
  379.         int pof_id;
  380.         while (new_pof_read_int(pof_id,model_buf) == 1)
  381.         {
  382.                 pof_id = INTEL_INT(pof_id);
  383.                 //id  = pof_read_int(model_buf);
  384.                 len = pof_read_int(model_buf);
  385.  
  386.                 if (pof_id == ID_GUNS)
  387.                 {               //List of guns on this object
  388.                         n_guns = pof_read_int(model_buf);
  389.  
  390.                         for (int i=0;i<n_guns;i++) {
  391.                                 int sm;
  392.  
  393.                                 const int gun_id = pof_read_short(model_buf);
  394.                                 sm = pof_read_short(model_buf);
  395.                                 if (sm!=0)
  396.                                         Error("Invalid gun submodel in file <%s>",filename);
  397.                                 pof_read_vecs(&gun_points[gun_id], 1, model_buf);
  398.                                 pof_read_vecs(&gun_dirs[gun_id], 1, model_buf);
  399.                         }
  400.  
  401.                 }
  402.                 else
  403.                         pof_cfseek(model_buf,len,SEEK_CUR);
  404.  
  405.         }
  406.         r.n_guns = n_guns;
  407. }
  408.  
  409. //free up a model, getting rid of all its memory
  410. #if defined(DXX_BUILD_DESCENT_I)
  411. static
  412. #endif
  413. void free_model(polymodel &po)
  414. {
  415.         po.model_data.reset();
  416. }
  417.  
  418. //draw a polygon model
  419.  
  420. namespace dsx {
  421.  
  422. void draw_polygon_model(grs_canvas &canvas, const vms_vector &pos, const vms_matrix &orient, const submodel_angles anim_angles, const unsigned model_num, unsigned flags, const g3s_lrgb light, const glow_values_t *const glow_values, alternate_textures alt_textures)
  423. {
  424.         Assert(model_num < N_polygon_models);
  425.  
  426.         auto &Polygon_models = LevelSharedPolygonModelState.Polygon_models;
  427.         const polymodel *po = &Polygon_models[model_num];
  428.  
  429.         //check if should use simple model
  430.         if (po->simpler_model )                                 //must have a simpler model
  431.                 if (flags==0)                                                   //can't switch if this is debris
  432.                         //alt textures might not match, but in the one case we're using this
  433.                         //for on 11/14/94, they do match.  So we leave it in.
  434.                         {
  435.                                 int cnt=1;
  436.                                 const auto depth = g3_calc_point_depth(pos);            //gets 3d depth
  437.                                 while (po->simpler_model && depth > cnt++ * Simple_model_threshhold_scale * po->rad)
  438.                                         po = &Polygon_models[po->simpler_model-1];
  439.                         }
  440.  
  441.         std::array<grs_bitmap *, MAX_POLYOBJ_TEXTURES> texture_list;
  442.         {
  443.                 const unsigned n_textures = po->n_textures;
  444.                 std::array<bitmap_index, MAX_POLYOBJ_TEXTURES> texture_list_index;
  445.                 auto &&tlir = partial_range(texture_list_index, n_textures);
  446.                 if (alt_textures)
  447.                 {
  448.                         for (auto &&[at, tli] : zip(unchecked_partial_range(static_cast<const bitmap_index *>(alt_textures), n_textures), tlir))
  449.                                 tli = at;
  450.                 }
  451.                 else
  452.                 {
  453.                         const unsigned first_texture = po->first_texture;
  454.                         for (auto &&[obp, tli] : zip(partial_range(ObjBitmapPtrs, first_texture, first_texture + n_textures), tlir))
  455.                                 tli = ObjBitmaps[obp];
  456.                 }
  457.  
  458.         // Make sure the textures for this object are paged in...
  459.                 for (auto &&[tli, tl] : zip(tlir, partial_range(texture_list, n_textures)))
  460.                 {
  461.                         tl = &GameBitmaps[tli.index];
  462.                         PIGGY_PAGE_IN(tli);
  463.                 }
  464.         }
  465.         // Hmmm... cache got flushed in the middle of paging all these in,
  466.         // so we need to reread them all in.
  467.         // Make sure that they can all fit in memory.
  468.  
  469.         g3_start_instance_matrix(pos, orient);
  470.  
  471.         polygon_model_points robot_points;
  472.  
  473.         if (flags == 0)         //draw entire object
  474.  
  475.                 g3_draw_polygon_model(&texture_list[0], robot_points, canvas, anim_angles, light, glow_values, po->model_data.get());
  476.  
  477.         else {
  478.                 for (int i=0;flags;flags>>=1,i++)
  479.                         if (flags & 1) {
  480.                                 Assert(i < po->n_models);
  481.  
  482.                                 //if submodel, rotate around its center point, not pivot point
  483.        
  484.                                 g3_start_instance_matrix();
  485.        
  486.                                 g3_draw_polygon_model(&texture_list[0], robot_points, canvas, anim_angles, light, glow_values, &po->model_data[po->submodel_ptrs[i]]);
  487.        
  488.                                 g3_done_instance();
  489.                         }      
  490.         }
  491.  
  492.         g3_done_instance();
  493. }
  494.  
  495. void free_polygon_models()
  496. {
  497.         auto &Polygon_models = LevelSharedPolygonModelState.Polygon_models;
  498.         range_for (auto &i, partial_range(Polygon_models, N_polygon_models))
  499.                 free_model(i);
  500. #if defined(DXX_BUILD_DESCENT_II)
  501.         Exit_models_loaded = false;
  502. #endif
  503. }
  504.  
  505. }
  506.  
  507. namespace dcx {
  508.  
  509. static void assign_max(fix &a, const fix &b)
  510. {
  511.         a = std::max(a, b);
  512. }
  513.  
  514. static void assign_min(fix &a, const fix &b)
  515. {
  516.         a = std::min(a, b);
  517. }
  518.  
  519. template <fix vms_vector::*p>
  520. static void update_bounds(vms_vector &minv, vms_vector &maxv, const vms_vector &vp)
  521. {
  522.         auto &mx = maxv.*p;
  523.         assign_max(mx, vp.*p);
  524.         auto &mn = minv.*p;
  525.         assign_min(mn, vp.*p);
  526. }
  527.  
  528. static void assign_minmax(vms_vector &minv, vms_vector &maxv, const vms_vector &v)
  529. {
  530.         update_bounds<&vms_vector::x>(minv, maxv, v);
  531.         update_bounds<&vms_vector::y>(minv, maxv, v);
  532.         update_bounds<&vms_vector::z>(minv, maxv, v);
  533. }
  534.  
  535. static void polyobj_find_min_max(polymodel *pm)
  536. {
  537.         auto &big_mn = pm->mins;
  538.         auto &big_mx = pm->maxs;
  539.         for (int m=0;m<pm->n_models;m++) {
  540.                 auto &mn = pm->submodel_mins[m];
  541.                 auto &mx = pm->submodel_maxs[m];
  542.                 const auto &ofs = pm->submodel_offsets[m];
  543.  
  544.                 auto data = reinterpret_cast<const uint16_t *>(&pm->model_data[pm->submodel_ptrs[m]]);
  545.        
  546.                 const auto type = *data++;
  547.        
  548.                 Assert(type == 7 || type == 1);
  549.        
  550.                 const uint16_t nverts = *data++ - 1;
  551.        
  552.                 if (type==7)
  553.                         data+=2;                //skip start & pad
  554.        
  555.                 auto vp = reinterpret_cast<const vms_vector *>(data);
  556.        
  557.                 mn = mx = *vp++;
  558.  
  559.                 if (m==0)
  560.                         big_mn = big_mx = mn;
  561.        
  562.                 range_for (auto &v, unchecked_partial_range(vp, nverts))
  563.                 {
  564.                         assign_minmax(mn, mx, v);
  565.                         assign_minmax(big_mn, big_mx, vm_vec_add(v, ofs));
  566.                 }
  567.         }
  568. }
  569.  
  570. }
  571.  
  572. namespace dsx {
  573.  
  574. std::array<char[FILENAME_LEN], MAX_POLYGON_MODELS> Pof_names;
  575.  
  576. //returns the number of this model
  577. int load_polygon_model(const char *filename,int n_textures,int first_texture,robot_info *r)
  578. {
  579.         Assert(N_polygon_models < MAX_POLYGON_MODELS);
  580.         Assert(n_textures < MAX_POLYOBJ_TEXTURES);
  581.  
  582.         Assert(strlen(filename) <= 12);
  583.         const auto n_models = N_polygon_models;
  584.         strcpy(Pof_names[n_models], filename);
  585.  
  586.         auto &Polygon_models = LevelSharedPolygonModelState.Polygon_models;
  587.         auto &model = Polygon_models[n_models];
  588.         read_model_file(&model, filename, r);
  589.  
  590.         polyobj_find_min_max(&model);
  591.  
  592.         const auto highest_texture_num = g3_init_polygon_model(model.model_data.get(), model.model_data_size);
  593.  
  594.         if (highest_texture_num+1 != n_textures)
  595.                 Error("Model <%s> references %d textures but specifies %d.",filename,highest_texture_num+1,n_textures);
  596.  
  597.         model.n_textures = n_textures;
  598.         model.first_texture = first_texture;
  599.         model.simpler_model = 0;
  600.  
  601. //      Assert(polygon_models[N_polygon_models]!=NULL);
  602.  
  603.         N_polygon_models++;
  604.  
  605.         return N_polygon_models-1;
  606.  
  607. }
  608.  
  609. }
  610.  
  611. namespace dcx {
  612.  
  613. void init_polygon_models()
  614. {
  615.         N_polygon_models = 0;
  616. }
  617.  
  618. }
  619.  
  620. //compare against this size when figuring how far to place eye for picture
  621. #define BASE_MODEL_SIZE 0x28000
  622.  
  623. #define DEFAULT_VIEW_DIST 0x60000
  624.  
  625. //draws the given model in the current canvas.  The distance is set to
  626. //more-or-less fill the canvas.  Note that this routine actually renders
  627. //into an off-screen canvas that it creates, then copies to the current
  628. //canvas.
  629. void draw_model_picture(grs_canvas &canvas, const uint_fast32_t mn, const vms_angvec &orient_angles)
  630. {
  631.         g3s_lrgb        lrgb = { f1_0, f1_0, f1_0 };
  632.  
  633.         Assert(mn<N_polygon_models);
  634.  
  635.         gr_clear_canvas(canvas, BM_XRGB(0,0,0));
  636.         g3_start_frame(canvas);
  637.         vms_vector temp_pos{};
  638.         g3_set_view_matrix(temp_pos,vmd_identity_matrix,0x9000);
  639.  
  640.         auto &Polygon_models = LevelSharedPolygonModelState.Polygon_models;
  641.         if (Polygon_models[mn].rad != 0)
  642.                 temp_pos.z = fixmuldiv(DEFAULT_VIEW_DIST,Polygon_models[mn].rad,BASE_MODEL_SIZE);
  643.         else
  644.                 temp_pos.z = DEFAULT_VIEW_DIST;
  645.  
  646.         const auto &&temp_orient = vm_angles_2_matrix(orient_angles);
  647.         draw_polygon_model(canvas, temp_pos, temp_orient, nullptr, mn, 0, lrgb, nullptr, nullptr);
  648.         g3_end_frame();
  649. }
  650.  
  651. namespace dcx {
  652.  
  653. DEFINE_SERIAL_VMS_VECTOR_TO_MESSAGE();
  654. DEFINE_SERIAL_UDT_TO_MESSAGE(polymodel, p, (p.n_models, p.model_data_size, serial::pad<4>(), p.submodel_ptrs, p.submodel_offsets, p.submodel_norms, p.submodel_pnts, p.submodel_rads, p.submodel_parents, p.submodel_mins, p.submodel_maxs, p.mins, p.maxs, p.rad, p.n_textures, p.first_texture, p.simpler_model));
  655. ASSERT_SERIAL_UDT_MESSAGE_SIZE(polymodel, 12 + (10 * 4) + (10 * 3 * sizeof(vms_vector)) + (10 * sizeof(fix)) + 10 + (10 * 2 * sizeof(vms_vector)) + (2 * sizeof(vms_vector)) + 8);
  656.  
  657. /*
  658.  * reads a polymodel structure from a PHYSFS_File
  659.  */
  660. void polymodel_read(polymodel *pm, PHYSFS_File *fp)
  661. {
  662.         pm->model_data.reset();
  663.         PHYSFSX_serialize_read(fp, *pm);
  664. }
  665.  
  666. }
  667.  
  668. #if 0
  669. void polymodel_write(PHYSFS_File *fp, const polymodel &pm)
  670. {
  671.         PHYSFSX_serialize_write(fp, pm);
  672. }
  673. #endif
  674.  
  675. /*
  676.  * routine which allocates, reads, and inits a polymodel's model_data
  677.  */
  678. namespace dsx {
  679. void polygon_model_data_read(polymodel *pm, PHYSFS_File *fp)
  680. {
  681.         auto model_data_size = pm->model_data_size;
  682.         pm->model_data = std::make_unique<uint8_t[]>(model_data_size);
  683.         PHYSFS_read(fp, pm->model_data, sizeof(uint8_t), model_data_size);
  684. #if DXX_WORDS_NEED_ALIGNMENT
  685.         /* Aligning model data changes pm->model_data_size.  Reload it
  686.          * afterward.
  687.          */
  688.         align_polygon_model_data(pm);
  689.         model_data_size = pm->model_data_size;
  690. #endif
  691.         if constexpr (words_bigendian)
  692.                 swap_polygon_model_data(pm->model_data.get());
  693. #if defined(DXX_BUILD_DESCENT_I)
  694.         g3_validate_polygon_model(pm->model_data.get(), model_data_size);
  695. #elif defined(DXX_BUILD_DESCENT_II)
  696.         g3_init_polygon_model(pm->model_data.get(), model_data_size);
  697. #endif
  698. }
  699. }
  700.