Subversion Repositories Games.Descent

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
1 pmbaty 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
}