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