1 // "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
2 // Ken Silverman's official web site: "http://www.advsys.net/ken"
3 // See the included license file "BUILDLIC.TXT" for license info.
4 //
5 // This file has been modified from Ken Silverman's original release
6 // by Jonathon Fowler (jf@jonof.id.au)
7 // by the EDuke32 team (development@voidpoint.com)
8 
9 #pragma once
10 
11 #ifndef build_h_
12 #define build_h_
13 
14 #if !defined __cplusplus || (__cplusplus < 201103L && !defined _MSC_VER)
15 # error C++11 or greater is required.
16 #endif
17 
18 #if defined _MSC_VER && _MSC_VER < 1800
19 # error Visual Studio 2013 is the minimum supported version.
20 #endif
21 
22 #include "collections.h"
23 #include "compat.h"
24 #include "glad/glad.h"
25 #include "glbuild.h"
26 #include "palette.h"
27 #include "pragmas.h"
28 
29 #include "vfs.h"
30 #include "cache1d.h"
31 
32 #ifdef __cplusplus
33 extern "C" {
34 #endif
35 
36 enum rendmode_t {
37     REND_CLASSIC,
38     REND_POLYMOST = 3,
39     REND_POLYMER
40 };
41 
42 #define PI 3.14159265358979323846
43 #define fPI 3.14159265358979323846f
44 
45 #define BANG2RAD (fPI * (1.f/1024.f))
46 
47 #define MAXSECTORSV8 4096
48 #define MAXWALLSV8 16384
49 #define MAXSPRITESV8 16384
50 
51 #define MAXSECTORSV7 1024
52 #define MAXWALLSV7 8192
53 #define MAXSPRITESV7 4096
54 
55 #define MAXVOXMIPS 5
56 
57 #if !defined GEKKO && !defined __OPENDINGUX__
58 # define MAXSECTORS MAXSECTORSV8
59 # define MAXWALLS MAXWALLSV8
60 # define MAXSPRITES MAXSPRITESV8
61 
62 # define MAXXDIM 7680
63 # define MAXYDIM 3200
64 # define MINXDIM 640
65 # define MINYDIM 480
66 
67 // additional space beyond wall, in walltypes:
68 # define M32_FIXME_WALLS 512
69 # define M32_FIXME_SECTORS 2
70 #else
71 # define MAXSECTORS MAXSECTORSV7
72 # define MAXWALLS MAXWALLSV7
73 # define MAXSPRITES MAXSPRITESV7
74 
75 #ifdef GEKKO
76 #  define MAXXDIM 860
77 #  define MAXYDIM 490
78 # else
79 #  define MAXXDIM 320
80 #  define MAXYDIM 200
81 # endif
82 
83 # define MINXDIM MAXXDIM
84 # define MINYDIM MAXYDIM
85 # define M32_FIXME_WALLS 0
86 # define M32_FIXME_SECTORS 0
87 #endif
88 
89 //define NEW_MAP_FORMAT
90 
91 #define MAXWALLSB ((MAXWALLS>>2)+(MAXWALLS>>3))
92 
93 #define MAXTILES 30720
94 #define MAXUSERTILES (MAXTILES-16)  // reserve 16 tiles at the end
95 
96 #define MAXVOXELS 1024
97 #define MAXSTATUS 1024
98 #define MAXPLAYERS 16
99 // Maximum number of component tiles in a multi-psky:
100 #define MAXPSKYTILES 16
101 #define MAXSPRITESONSCREEN 2560
102 #define MAXUNIQHUDID 256 //Extra slots so HUD models can store animation state without messing game sprites
103 
104 #define TSPR_TEMP 99
105 
106 #define PR_LIGHT_PRIO_MAX       0
107 #define PR_LIGHT_PRIO_MAX_GAME  1
108 #define PR_LIGHT_PRIO_HIGH      2
109 #define PR_LIGHT_PRIO_HIGH_GAME 3
110 #define PR_LIGHT_PRIO_LOW       4
111 #define PR_LIGHT_PRIO_LOW_GAME  5
112 
113 #define CLOCKTICKSPERSECOND 120
114 
115 // Convenient sprite iterators, must not be used if any sprites inside the loop
116 // are potentially deleted or their sector changed...
117 #define SPRITES_OF(Statnum, Iter)  Iter=headspritestat[Statnum]; Iter>=0; Iter=nextspritestat[Iter]
118 #define SPRITES_OF_SECT(Sectnum, Iter)  Iter=headspritesect[Sectnum]; Iter>=0; Iter=nextspritesect[Iter]
119 // ... in which case this iterator may be used:
120 #define SPRITES_OF_SECT_SAFE(Sectnum, Iter, Next)  Iter=headspritesect[Sectnum]; \
121     Iter>=0 && (Next=nextspritesect[Iter], 1); Iter=Next
122 #define SPRITES_OF_STAT_SAFE(Statnum, Iter, Next)  Iter=headspritestat[Statnum]; \
123     Iter>=0 && (Next=nextspritestat[Iter], 1); Iter=Next
124 
125 #define CLEARLINES2D(Startline, Numlines, Color) \
126     clearbuf((char *)(frameplace + ((Startline)*bytesperline)), (bytesperline*(Numlines))>>2, (Color))
127 
128 
129 ////////// True Room over Room (YAX == rot -17 of "PRO") //////////
130 #define YAX_ENABLE
131 //#define YAX_DEBUG
132 //#define ENGINE_SCREENSHOT_DEBUG
133 
134 #ifdef YAX_ENABLE
135 # if !defined NEW_MAP_FORMAT
136 #  define YAX_ENABLE__COMPAT
137 # endif
138 #endif
139 
140 ////////// yax defs //////////
141 #define SECTORFLD(Sect,Fld, Cf) (*((Cf) ? (&sector[Sect].floor##Fld) : (&sector[Sect].ceiling##Fld)))
142 
143 #define YAX_CEILING 0  // don't change!
144 #define YAX_FLOOR 1  // don't change!
145 
146 # ifdef NEW_MAP_FORMAT
147 #  define YAX_MAXBUNCHES 512
148 #  define YAX_BIT__COMPAT 1024
149 #  define YAX_NEXTWALLBIT__COMPAT(Cf) (1<<(10+Cf))
150 #  define YAX_NEXTWALLBITS__COMPAT (YAX_NEXTWALLBIT__COMPAT(0)|YAX_NEXTWALLBIT__COMPAT(1))
151 # else
152 #  define YAX_MAXBUNCHES 256
153 #  define YAX_BIT 1024
154    // "has next wall when constrained"-bit (1<<10: ceiling, 1<<11: floor)
155 #  define YAX_NEXTWALLBIT(Cf) (1<<(10+Cf))
156 #  define YAX_NEXTWALLBITS (YAX_NEXTWALLBIT(0)|YAX_NEXTWALLBIT(1))
157 # endif
158 
159 int32_t get_alwaysshowgray(void);  // editor only
160 void yax_updategrays(int32_t posze);
161 
162 #ifdef YAX_ENABLE
163 # ifdef NEW_MAP_FORMAT
164    // New map format -- no hijacking of otherwise used members.
165 #  define YAX_PTRNEXTWALL(Ptr, Wall, Cf) (*(&Ptr[Wall].upwall + Cf))
166 #  define YAX_NEXTWALLDEFAULT(Cf) (-1)
167 # else
168    // More user tag hijacking: lotag/extra. :/
169 #  define YAX_PTRNEXTWALL(Ptr, Wall, Cf) (*(int16_t *)(&Ptr[Wall].lotag + (bloodhack ? 1 : 2)*Cf))
170 #  define YAX_NEXTWALLDEFAULT(Cf) (bloodhack ? 0 : ((Cf)==YAX_CEILING) ? 0 : -1)
171    extern int16_t yax_bunchnum[MAXSECTORS][2];
172    extern int16_t yax_nextwall[MAXWALLS][2];
173 # endif
174 
175 # define YAX_NEXTWALL(Wall, Cf) YAX_PTRNEXTWALL(wall, Wall, Cf)
176 
177 # define YAX_ITER_WALLS(Wal, Itervar, Cfvar) Cfvar=0, Itervar=(Wal); Itervar!=-1; \
178     Itervar=yax_getnextwall(Itervar, Cfvar), \
179         (void)(Itervar==-1 && Cfvar==0 && (Cfvar=1) && (Itervar=yax_getnextwall((Wal), Cfvar)))
180 
181 # define SECTORS_OF_BUNCH(Bunchnum, Cf, Itervar) Itervar = headsectbunch[Cf][Bunchnum]; \
182     Itervar != -1; Itervar = nextsectbunch[Cf][Itervar]
183 
184 extern int32_t r_tror_nomaskpass;
185 
186 # ifdef NEW_MAP_FORMAT
187 // Moved below declarations of sector, wall, sprite.
188 # else
189 int16_t yax_getbunch(int16_t i, int16_t cf);
yax_getbunches(int16_t i,int16_t * cb,int16_t * fb)190 static FORCE_INLINE void yax_getbunches(int16_t i, int16_t *cb, int16_t *fb)
191 {
192     *cb = yax_getbunch(i, YAX_CEILING);
193     *fb = yax_getbunch(i, YAX_FLOOR);
194 }
195 int16_t yax_getnextwall(int16_t wal, int16_t cf);
196 void yax_setnextwall(int16_t wal, int16_t cf, int16_t thenextwall);
197 # endif
198 
199 void yax_setbunch(int16_t i, int16_t cf, int16_t bunchnum);
200 void yax_setbunches(int16_t i, int16_t cb, int16_t fb);
201 int16_t yax_vnextsec(int16_t line, int16_t cf);
202 void yax_update(int32_t resetstat);
203 int32_t yax_getneighborsect(int32_t x, int32_t y, int32_t sectnum, int32_t cf);
204 
yax_waltosecmask(int32_t const walclipmask)205 static FORCE_INLINE CONSTEXPR int32_t yax_waltosecmask(int32_t const walclipmask)
206 {
207     // blocking: walstat&1 --> secstat&512
208     // hitscan: walstat&64 --> secstat&2048
209     return ((walclipmask&1)<<9) | ((walclipmask&64)<<5);
210 }
211 void yax_preparedrawrooms(void);
212 void yax_drawrooms(void (*SpriteAnimFunc)(int32_t,int32_t,int32_t,int32_t,int32_t),
213                    int16_t sectnum, int32_t didmirror, int32_t smoothr);
214 # define YAX_SKIPSECTOR(i) if (graysectbitmap[(i)>>3]&pow2char[(i)&7]) continue
215 # define YAX_SKIPWALL(i) if (graywallbitmap[(i)>>3]&pow2char[(i)&7]) continue
216 #else
217 # define yax_preparedrawrooms()
218 # define yax_drawrooms(SpriteAnimFunc, sectnum, didmirror, smoothr)
219 # define YAX_SKIPSECTOR(i) (i)=(i)
220 # define YAX_SKIPWALL(i) (i)=(i)
221 #endif
222 
223 #define CLIPMASK0 (((1L)<<16)+1L)
224 #define CLIPMASK1 (((256L)<<16)+64L)
225 
226 #define NEXTWALL(i) (wall[wall[i].nextwall])
227 #define POINT2(i) (wall[wall[i].point2])
228 
229 // max x/y val (= max editorgridextent in Mapster32)
230 #define BXY_MAX 524288
231 
232 // rotatesprite 'orientation' (actually much more) bits
233 enum {
234     RS_TRANS1 = 1,
235     RS_AUTO = 2,
236     RS_YFLIP = 4,
237     RS_NOCLIP = 8,
238     RS_TOPLEFT = 16,
239     RS_TRANS2 = 32,
240     RS_NOMASK = 64,
241     RS_PERM = 128,
242 
243     RS_ALIGN_L = 256,
244     RS_ALIGN_R = 512,
245     RS_ALIGN_MASK = 768,
246     RS_STRETCH = 1024,
247 
248     ROTATESPRITE_FULL16 = 2048,
249     // ROTATESPRITE_MAX-1 is the mask of all externally available orientation bits
250     ROTATESPRITE_MAX = 4096,
251 
252     RS_CENTERORIGIN = (1<<30),
253 };
254 
255     //Make all variables in BUILD.H defined in the ENGINE,
256     //and externed in GAME
257 #ifdef engine_c_
258 #  define EXTERN
259 #else
260 #  define EXTERN extern
261 #endif
262 
263 #ifdef __cplusplus
264 }
265 #endif
266 
267 #if defined __cplusplus && (defined USE_OPENGL || defined POLYMER)
268 # define USE_STRUCT_TRACKERS
269 #endif
270 
271 #ifdef USE_STRUCT_TRACKERS
272 
273 extern "C" {
274 static FORCE_INLINE void sector_tracker_hook__(intptr_t address);
275 static FORCE_INLINE void wall_tracker_hook__(intptr_t address);
276 static FORCE_INLINE void sprite_tracker_hook__(intptr_t address);
277 }
278 
279 #define TRACKER_NAME__ SectorTracker
280 #define TRACKER_HOOK_ sector_tracker_hook__
281 #include "tracker.hpp"
282 #undef TRACKER_NAME__
283 #undef TRACKER_HOOK_
284 
285 #define TRACKER_NAME__ WallTracker
286 #define TRACKER_HOOK_ wall_tracker_hook__
287 #include "tracker.hpp"
288 #undef TRACKER_NAME__
289 #undef TRACKER_HOOK_
290 
291 #define TRACKER_NAME__ SpriteTracker
292 #define TRACKER_HOOK_ sprite_tracker_hook__
293 #include "tracker.hpp"
294 #undef TRACKER_NAME__
295 #undef TRACKER_HOOK_
296 
297 #define Tracker(Container, Type) Container##Tracker<Type>
298 #define TrackerCast(x) x.cast()
299 
300 #else
301 
302 #define Tracker(Container, Type) Type
303 #define TrackerCast(x) x
304 
305 #endif // __cplusplus
306 
307 // Links to various ABIs specifying (or documenting non-normatively) the
308 // alignment requirements of aggregates:
309 //
310 //  System V AMD64: http://www.x86-64.org/documentation/abi-0.99.pdf
311 //   (x86-64.org down as of 2013-02-02?)
312 //  "An array uses the same alignment as its elements, except that a local or global
313 //   array variable of length at least 16 bytes or a C99 variable-length array variable
314 //   always has alignment of at least 16 bytes."
315 //   (Not reproducible with GCC or LuaJIT on Ubuntu)
316 //
317 //  Win64: http://msdn.microsoft.com/en-us/library/9dbwhz68.aspx
318 //
319 //  x86: http://en.wikipedia.org/wiki/Data_structure_alignment#Typical_alignment_of_C_structs_on_x86
320 
321 enum {
322     SPR_XFLIP = 4,
323     SPR_YFLIP = 8,
324 
325     SPR_WALL = 16,
326     SPR_FLOOR = 32,
327     SPR_ALIGN_MASK = 32+16,
328 };
329 
330 #define UNTRACKED_STRUCTS__
331 #include "buildtypes.h"
332 #undef UNTRACKED_STRUCTS__
333 #undef buildtypes_h__
334 #include "buildtypes.h"
335 
336 #if !defined NEW_MAP_FORMAT
337 using sectortype  = sectortypev7;
338 using usectortype = usectortypev7;
339 
340 using walltype  = walltypev7;
341 using uwalltype = uwalltypev7;
342 #else
343 using sectortype  = sectortypevx;
344 using usectortype = usectortypevx;
345 
346 using walltype  = walltypevx;
347 using uwalltype = uwalltypevx;
348 #endif
349 
350 using spritetype  = spritetypev7;
351 using uspritetype = uspritetypev7;
352 
353 using uspriteptr_t = uspritetype const *;
354 using uwallptr_t   = uwalltype const *;
355 using usectorptr_t = usectortype const *;
356 using tspriteptr_t = tspritetype *;
357 
358 // this is probably never going to be necessary
359 EDUKE32_STATIC_ASSERT(sizeof(sectortype) == sizeof(usectortype));
360 EDUKE32_STATIC_ASSERT(sizeof(walltype) == sizeof(uwalltype));
361 EDUKE32_STATIC_ASSERT(sizeof(spritetype) == sizeof(uspritetype));
362 
363 #ifdef NEW_MAP_FORMAT
364 
365 # define SECTORVX_SZ1 offsetof(sectortypevx, ceilingpicnum)
366 # define SECTORVX_SZ4 sizeof(sectortypevx)-offsetof(sectortypevx, visibility)
367 
copy_v7_from_vx_sector(usectortypev7 * v7sec,const sectortypevx * vxsec)368 static inline void copy_v7_from_vx_sector(usectortypev7 *v7sec, const sectortypevx *vxsec)
369 {
370     /* [wallptr..wallnum] */
371     Bmemcpy(v7sec, vxsec, SECTORVX_SZ1);
372 
373     /* ceiling* */
374     v7sec->ceilingpicnum = vxsec->ceilingpicnum;
375     v7sec->ceilingheinum = vxsec->ceilingheinum;
376     v7sec->ceilingstat = vxsec->ceilingstat;
377     v7sec->ceilingz = vxsec->ceilingz;
378     v7sec->ceilingshade = vxsec->ceilingshade;
379     v7sec->ceilingpal = vxsec->ceilingpal;
380     v7sec->ceilingxpanning = vxsec->ceilingxpanning;
381     v7sec->ceilingypanning = vxsec->ceilingypanning;
382 
383     /* floor* */
384     v7sec->floorpicnum = vxsec->floorpicnum;
385     v7sec->floorheinum = vxsec->floorheinum;
386     v7sec->floorstat = vxsec->floorstat;
387     v7sec->floorz = vxsec->floorz;
388     v7sec->floorshade = vxsec->floorshade;
389     v7sec->floorpal = vxsec->floorpal;
390     v7sec->floorxpanning = vxsec->floorxpanning;
391     v7sec->floorypanning = vxsec->floorypanning;
392 
393     /* [visibility..extra] */
394     Bmemcpy(&v7sec->visibility, &vxsec->visibility, SECTORVX_SZ4);
395 
396     /* Clear YAX_BIT of ceiling and floor. (New-map format build saves TROR
397      * maps as map-text.) */
398     v7sec->ceilingstat &= ~YAX_BIT__COMPAT;
399     v7sec->floorstat &= ~YAX_BIT__COMPAT;
400 }
401 
inplace_vx_from_v7_sector(sectortypevx * vxsec)402 static inline void inplace_vx_from_v7_sector(sectortypevx *vxsec)
403 {
404     const sectortypev7 *v7sec = (sectortypev7 *)vxsec;
405     usectortypev7 bakv7sec;
406 
407     // Can't do this in-place since the members were rearranged.
408     Bmemcpy(&bakv7sec, v7sec, sizeof(sectortypev7));
409 
410     /* [wallptr..wallnum] is already at the right place */
411 
412     /* ceiling* */
413     vxsec->ceilingpicnum = bakv7sec.ceilingpicnum;
414     vxsec->ceilingheinum = bakv7sec.ceilingheinum;
415     vxsec->ceilingstat = bakv7sec.ceilingstat;
416     vxsec->ceilingz = bakv7sec.ceilingz;
417     vxsec->ceilingshade = bakv7sec.ceilingshade;
418     vxsec->ceilingpal = bakv7sec.ceilingpal;
419     vxsec->ceilingxpanning = bakv7sec.ceilingxpanning;
420     vxsec->ceilingypanning = bakv7sec.ceilingypanning;
421 
422     /* floor* */
423     vxsec->floorpicnum = bakv7sec.floorpicnum;
424     vxsec->floorheinum = bakv7sec.floorheinum;
425     vxsec->floorstat = bakv7sec.floorstat;
426     vxsec->floorz = bakv7sec.floorz;
427     vxsec->floorshade = bakv7sec.floorshade;
428     vxsec->floorpal = bakv7sec.floorpal;
429     vxsec->floorxpanning = bakv7sec.floorxpanning;
430     vxsec->floorypanning = bakv7sec.floorypanning;
431 
432     /* [visibility..extra] */
433     Bmemmove(&vxsec->visibility, &bakv7sec.visibility, SECTORVX_SZ4);
434 }
435 
inplace_vx_tweak_sector(sectortypevx * vxsec,int32_t yaxp)436 static inline void inplace_vx_tweak_sector(sectortypevx *vxsec, int32_t yaxp)
437 {
438     if (yaxp)
439     {
440         int32_t cisext = (vxsec->ceilingstat&YAX_BIT__COMPAT);
441         int32_t fisext = (vxsec->floorstat&YAX_BIT__COMPAT);
442 
443         vxsec->ceilingbunch = cisext ? vxsec->ceilingxpanning : -1;
444         vxsec->floorbunch = fisext ? vxsec->floorxpanning : -1;
445 
446         if (cisext)
447             vxsec->ceilingxpanning = 0;
448         if (fisext)
449             vxsec->floorxpanning = 0;
450     }
451     else
452     {
453         vxsec->ceilingbunch = vxsec->floorbunch = -1;
454     }
455 
456     /* Clear YAX_BIT of ceiling and floor (map-int VX doesn't use it). */
457     vxsec->ceilingstat &= ~YAX_BIT__COMPAT;
458     vxsec->floorstat &= ~YAX_BIT__COMPAT;
459 }
460 
461 # undef SECTORVX_SZ1
462 # undef SECTORVX_SZ4
463 
464 # define WALLVX_SZ2 offsetof(walltypevx, blend)-offsetof(walltypevx, cstat)
465 
copy_v7_from_vx_wall(uwalltypev7 * v7wal,const walltypevx * vxwal)466 static inline void copy_v7_from_vx_wall(uwalltypev7 *v7wal, const walltypevx *vxwal)
467 {
468     /* [x..nextsector] */
469     Bmemcpy(v7wal, vxwal, offsetof(walltypevx, upwall));
470     /* [cstat..extra] */
471     Bmemcpy(&v7wal->cstat, &vxwal->cstat, WALLVX_SZ2);
472     /* Clear YAX_NEXTWALLBITS. */
473     v7wal->cstat &= ~YAX_NEXTWALLBITS__COMPAT;
474 }
475 
inplace_vx_from_v7_wall(walltypevx * vxwal)476 static inline void inplace_vx_from_v7_wall(walltypevx *vxwal)
477 {
478     const walltypev7 *v7wal = (walltypev7 *)vxwal;
479 
480     /* [cstat..extra] */
481     Bmemmove(&vxwal->cstat, &v7wal->cstat, WALLVX_SZ2);
482 
483     vxwal->blend = vxwal->filler_ = 0;
484 }
485 
inplace_vx_tweak_wall(walltypevx * vxwal,int32_t yaxp)486 static inline void inplace_vx_tweak_wall(walltypevx *vxwal, int32_t yaxp)
487 {
488     if (yaxp)
489     {
490         int32_t haveupwall = (vxwal->cstat & YAX_NEXTWALLBIT__COMPAT(YAX_CEILING));
491         int32_t havednwall = (vxwal->cstat & YAX_NEXTWALLBIT__COMPAT(YAX_FLOOR));
492 
493         vxwal->upwall = haveupwall ? vxwal->lotag : -1;
494         vxwal->dnwall = havednwall ? vxwal->extra : -1;
495 
496         if (haveupwall)
497             vxwal->lotag = 0;
498         if (havednwall)
499             vxwal->extra = -1;
500     }
501     else
502     {
503         vxwal->upwall = vxwal->dnwall = -1;
504     }
505 
506     /* Clear YAX_NEXTWALLBITS (map-int VX doesn't use it). */
507     vxwal->cstat &= ~YAX_NEXTWALLBITS__COMPAT;
508 }
509 
510 # undef WALLVX_SZ2
511 
512 #endif
513 
514 #include "clip.h"
515 
516 int32_t getwalldist(vec2_t const in, int const wallnum);
517 int32_t getwalldist(vec2_t const in, int const wallnum, vec2_t * const out);
518 
519 #ifdef __cplusplus
520 extern "C" {
521 #endif
522 
523 #pragma pack(push,1)
524 typedef struct {
525     union
526     {
527         tspriteptr_t tspr;
528 #if !defined UINTPTR_MAX
529 # error Need UINTPTR_MAX define to select between 32- and 64-bit structs
530 #endif
531 #if UINTPTR_MAX != UINT64_MAX
532         /* On a 32-bit build, pad the struct so it has the same size everywhere. */
533         uint64_t ptrfill;
534 #endif
535     };
536 
537     float    alpha;
538     uint16_t flags;
539 
540     // this is organized so that most of the bytes that will usually be zero are adjacent
541     int16_t  mdanimcur;
542     uint32_t mdanimtims;
543     int16_t  mdangoff;
544     uint8_t  xpanning, ypanning;
545     int16_t  mdpitch, mdroll;
546     vec3_t   mdpivot_offset, mdposition_offset;
547 
548     // since this goes into savegames, pad to 64 bytes for future usage
549     uint8_t  filler[12];
550 } spriteext_t;
551 
552 EDUKE32_STATIC_ASSERT(offsetof(spriteext_t, flags) % 4 == 0);
553 EDUKE32_STATIC_ASSERT(offsetof(spriteext_t, mdangoff) % 4 == 0);
554 EDUKE32_STATIC_ASSERT(offsetof(spriteext_t, mdanimtims) % 4 == 0);
555 EDUKE32_STATIC_ASSERT(offsetof(spriteext_t, mdposition_offset) % 4 == 0);
556 EDUKE32_STATIC_ASSERT(sizeof(spriteext_t) == 64);
557 
558 typedef struct {
559     float smoothduration;
560     int16_t mdcurframe, mdoldframe;
561     int16_t mdsmooth;
562 } spritesmooth_t;
563 
564 #ifndef NEW_MAP_FORMAT
565 typedef struct {
566     uint8_t blend;
567 } wallext_t;
568 #endif
569 #pragma pack(pop)
570 
571 #define SPREXT_NOTMD 1
572 #define SPREXT_NOMDANIM 2
573 #define SPREXT_AWAY1 4
574 #define SPREXT_AWAY2 8
575 #define SPREXT_TSPRACCESS 16
576 #define SPREXT_TEMPINVISIBLE 32
577 
578 #define NEG_ALPHA_TO_BLEND(alpha, blend, orientation) do { \
579     if ((alpha) < 0) { (blend) = -(alpha); (alpha) = 0; (orientation) |= RS_TRANS1; } \
580 } while (0)
581 
582 // using the clipdist field
583 enum
584 {
585     TSPR_FLAGS_MDHACK = 1u<<0u,
586     TSPR_FLAGS_DRAW_LAST = 1u<<1u,
587     TSPR_FLAGS_NO_SHADOW = 1u<<2u,
588     TSPR_FLAGS_INVISIBLE_WITH_SHADOW = 1u<<3u,
589     TSPR_FLAGS_SLOPE_SPRITE = 1u<<4u,
590 };
591 
592 EXTERN int32_t guniqhudid;
593 EXTERN int32_t spritesortcnt;
594 extern int32_t g_loadedMapVersion;
595 
596 typedef struct {
597     char *mhkfile;
598     char *title;
599     uint8_t md4[16];
600 } usermaphack_t;
601 
602 extern usermaphack_t g_loadedMapHack;
603 extern int compare_usermaphacks(const void *, const void *);
604 extern usermaphack_t *usermaphacks;
605 extern int32_t num_usermaphacks;
606 
607 #if !defined DEBUG_MAIN_ARRAYS
608 EXTERN spriteext_t *spriteext;
609 EXTERN spritesmooth_t *spritesmooth;
610 # ifndef NEW_MAP_FORMAT
611 EXTERN wallext_t *wallext;
612 # endif
613 
614 EXTERN sectortype *sector;
615 EXTERN walltype *wall;
616 EXTERN spritetype *sprite;
617 EXTERN tspriteptr_t tsprite;
618 #else
619 EXTERN spriteext_t spriteext[MAXSPRITES+MAXUNIQHUDID];
620 EXTERN spritesmooth_t spritesmooth[MAXSPRITES+MAXUNIQHUDID];
621 # ifndef NEW_MAP_FORMAT
622 EXTERN wallext_t wallext[MAXWALLS];
623 # endif
624 
625 EXTERN sectortype sector[MAXSECTORS + M32_FIXME_SECTORS];
626 EXTERN walltype wall[MAXWALLS + M32_FIXME_WALLS];
627 EXTERN spritetype sprite[MAXSPRITES];
628 EXTERN uspritetype tsprite[MAXSPRITESONSCREEN];
629 #endif
630 
631 #ifdef USE_STRUCT_TRACKERS
632 EXTERN uint32_t sectorchanged[MAXSECTORS + M32_FIXME_SECTORS];
633 EXTERN uint32_t wallchanged[MAXWALLS + M32_FIXME_WALLS];
634 EXTERN uint32_t spritechanged[MAXSPRITES];
635 #endif
636 
637 #ifdef NEW_MAP_FORMAT
yax_getbunch(int16_t i,int16_t cf)638 static FORCE_INLINE int16_t yax_getbunch(int16_t i, int16_t cf)
639 {
640     return cf ? sector[i].floorbunch : sector[i].ceilingbunch;
641 }
642 
yax_getbunches(int16_t i,int16_t * cb,int16_t * fb)643 static FORCE_INLINE void yax_getbunches(int16_t i, int16_t *cb, int16_t *fb)
644 {
645     *cb = yax_getbunch(i, YAX_CEILING);
646     *fb = yax_getbunch(i, YAX_FLOOR);
647 }
648 
yax_getnextwall(int16_t wal,int16_t cf)649 static FORCE_INLINE int16_t yax_getnextwall(int16_t wal, int16_t cf)
650 {
651     return cf ? wall[wal].dnwall : wall[wal].upwall;
652 }
653 
yax_setnextwall(int16_t wal,int16_t cf,int16_t thenextwall)654 static FORCE_INLINE void yax_setnextwall(int16_t wal, int16_t cf, int16_t thenextwall)
655 {
656     YAX_NEXTWALL(wal, cf) = thenextwall;
657 }
658 #endif
659 
660 #ifdef USE_STRUCT_TRACKERS
sector_tracker_hook__(intptr_t const address)661 static FORCE_INLINE void sector_tracker_hook__(intptr_t const address)
662 {
663     intptr_t const sectnum = (address - (intptr_t)sector) / sizeof(sectortype);
664 
665 #if DEBUGGINGAIDS>=2
666     Bassert((unsigned)sectnum < ((MAXSECTORS + M32_FIXME_SECTORS)));
667 #endif
668 
669     ++sectorchanged[sectnum];
670 }
671 
wall_tracker_hook__(intptr_t const address)672 static FORCE_INLINE void wall_tracker_hook__(intptr_t const address)
673 {
674     intptr_t const wallnum = (address - (intptr_t)wall) / sizeof(walltype);
675 
676 #if DEBUGGINGAIDS>=2
677     Bassert((unsigned)wallnum < ((MAXWALLS + M32_FIXME_WALLS)));
678 #endif
679 
680     ++wallchanged[wallnum];
681 }
682 
sprite_tracker_hook__(intptr_t const address)683 static FORCE_INLINE void sprite_tracker_hook__(intptr_t const address)
684 {
685     intptr_t const spritenum = (address - (intptr_t)sprite) / sizeof(spritetype);
686 
687 #if DEBUGGINGAIDS>=2
688     Bassert((unsigned)spritenum < MAXSPRITES);
689 #endif
690 
691     ++spritechanged[spritenum];
692 }
693 #endif
694 
renderMakeTSpriteFromSprite(tspriteptr_t const tspr,uint16_t const spritenum)695 static inline tspriteptr_t renderMakeTSpriteFromSprite(tspriteptr_t const tspr, uint16_t const spritenum)
696 {
697     auto const spr = (uspriteptr_t)&sprite[spritenum];
698 
699     tspr->pos = spr->pos;
700     tspr->cstat = spr->cstat;
701     tspr->picnum = spr->picnum;
702     tspr->shade = spr->shade;
703     tspr->pal = spr->pal;
704     tspr->blend = spr->blend;
705     tspr->xrepeat = spr->xrepeat;
706     tspr->yrepeat = spr->yrepeat;
707     tspr->xoffset = spr->xoffset;
708     tspr->yoffset = spr->yoffset;
709     tspr->sectnum = spr->sectnum;
710     tspr->statnum = spr->statnum;
711     tspr->ang = spr->ang;
712     tspr->vel = spr->vel;
713     tspr->lotag = spr->lotag;
714     tspr->hitag = spr->hitag;
715     tspr->extra = spr->extra;
716 
717     tspr->clipdist = 0;
718     tspr->owner = spritenum;
719 
720     if ((tspr->cstat & CSTAT_SPRITE_ALIGNMENT_MASK) == CSTAT_SPRITE_ALIGNMENT_SLOPE)
721     {
722         tspr->cstat &= ~CSTAT_SPRITE_ALIGNMENT_MASK;
723         tspr->cstat |= CSTAT_SPRITE_ALIGNMENT_FLOOR;
724         tspr->clipdist |= TSPR_FLAGS_SLOPE_SPRITE;
725     }
726 
727     return tspr;
728 }
729 
renderAddTSpriteFromSprite(uint16_t const spritenum)730 static inline tspriteptr_t renderAddTSpriteFromSprite(uint16_t const spritenum)
731 {
732     return renderMakeTSpriteFromSprite(&tsprite[spritesortcnt++], spritenum);
733 }
734 
spriteSetSlope(uint16_t const spritenum,int16_t const heinum)735 static inline void spriteSetSlope(uint16_t const spritenum, int16_t const heinum)
736 {
737     auto const spr = &sprite[spritenum];
738     uint16_t const cstat = spr->cstat & CSTAT_SPRITE_ALIGNMENT_MASK;
739     if (cstat != CSTAT_SPRITE_ALIGNMENT_FLOOR && cstat != CSTAT_SPRITE_ALIGNMENT_SLOPE)
740         return;
741 
742     spr->xoffset = heinum & 255;
743     spr->yoffset = (heinum >> 8) & 255;
744     spr->cstat &= ~CSTAT_SPRITE_ALIGNMENT_MASK;
745     spr->cstat |= heinum != 0 ? CSTAT_SPRITE_ALIGNMENT_SLOPE : CSTAT_SPRITE_ALIGNMENT_FLOOR;
746 }
747 
spriteGetSlope(uint16_t const spritenum)748 static inline int16_t spriteGetSlope(uint16_t const spritenum)
749 {
750     auto const spr = &sprite[spritenum];
751     uint16_t const cstat = spr->cstat & CSTAT_SPRITE_ALIGNMENT_MASK;
752     if (cstat != CSTAT_SPRITE_ALIGNMENT_SLOPE)
753         return 0;
754     return uint8_t(spr->xoffset) + (uint8_t(spr->yoffset) << 8);
755 }
756 
757 extern int32_t animateoffs(int const tilenum, int fakevar);
758 
759 EXTERN int16_t maskwall[MAXWALLSB], maskwallcnt;
760 EXTERN int16_t thewall[MAXWALLSB];
761 EXTERN tspriteptr_t tspriteptr[MAXSPRITESONSCREEN + 1];
762 
763 EXTERN int32_t wx1, wy1, wx2, wy2;
764 EXTERN int32_t xdim, ydim, numpages, upscalefactor;
765 EXTERN int32_t yxaspect, viewingrange;
766 EXTERN intptr_t *ylookup;
767 
768 EXTERN int32_t rotatesprite_y_offset;
769 EXTERN int32_t rotatesprite_yxaspect;
770 
771 #ifndef GEKKO
772 #define MAXVALIDMODES 256
773 #else
774 #define MAXVALIDMODES 16
775 #endif
776 EXTERN int32_t validmodecnt;
777 struct validmode_t {
778     int32_t xdim,ydim;
779     char bpp;
780     char fs;    // bit 0 = fullscreen flag
781     char filler[2];
782     int32_t extra; // internal use
783 };
784 EXTERN struct validmode_t validmode[MAXVALIDMODES];
785 
786 EXTERN int32_t numyaxbunches;
787 #ifdef YAX_ENABLE
788 // Singly-linked list of sectnums grouped by bunches and ceiling (0)/floor (1)
789 // Usage e.g.:
790 //   int16_t bunchnum = yax_getbunch(somesector, YAX_CEILING);
791 // Iteration over all sectors whose floor bunchnum equals 'bunchnum' (i.e. "all
792 // floors of the other side"):
793 //   for (i=headsectbunch[1][bunchnum]; i!=-1; i=nextsectbunch[1][i])
794 //       <do stuff with sector i...>
795 
796 EXTERN int16_t headsectbunch[2][YAX_MAXBUNCHES], nextsectbunch[2][MAXSECTORS];
797 #endif
798 
799 EXTERN int32_t Numsprites;
800 EXTERN int16_t numsectors, numwalls;
801 EXTERN int32_t display_mirror;
802 // totalclocklock: the totalclock value that is backed up once on each
803 // drawrooms() and is used for animateoffs().
804 EXTERN ClockTicks totalclock, totalclocklock;
BGetTime(void)805 static inline int32_t BGetTime(void) { return (int32_t) totalclock; }
806 
807 EXTERN int32_t numframes, randomseed;
808 EXTERN int16_t sintable[2048];
809 
810 EXTERN uint8_t palette[768];
811 EXTERN int16_t numshades;
812 EXTERN char *palookup[MAXPALOOKUPS];
813 extern uint8_t *basepaltable[MAXBASEPALS];
814 EXTERN uint8_t paletteloaded;
815 EXTERN char *blendtable[MAXBLENDTABS];
816 EXTERN uint8_t whitecol, redcol, blackcol;
817 
818 EXTERN int32_t maxspritesonscreen;
819 
820 enum {
821     PALETTE_MAIN = 1<<0,
822     PALETTE_SHADE = 1<<1,
823     PALETTE_TRANSLUC = 1<<2,
824 };
825 
826 EXTERN char showinvisibility;
827 EXTERN int32_t g_visibility, parallaxvisibility;
828 EXTERN int32_t g_rotatespriteNoWidescreen;
829 
830 // blendtable[1] to blendtable[numalphatabs] are considered to be
831 // alpha-blending tables:
832 EXTERN uint8_t numalphatabs;
833 
834 EXTERN vec2_t windowxy1, windowxy2;
835 EXTERN int16_t *startumost, *startdmost;
836 
837 // The maximum tile offset ever used in any tiled parallaxed multi-sky.
838 #define PSKYOFF_MAX 16
839 #define DEFAULTPSKY -1
840 
841 typedef struct {
842     // The proportion at which looking up/down affects the apparent 'horiz' of
843     // a parallaxed sky, scaled by 65536 (so, a value of 65536 makes it align
844     // with the drawn surrounding scene):
845     int32_t horizfrac;
846 
847     // The texel index offset in the y direction of a parallaxed sky:
848     // XXX: currently always 0.
849     int32_t yoffs;
850 
851     int8_t lognumtiles;  // 1<<lognumtiles: number of tiles in multi-sky
852     int8_t tileofs[MAXPSKYTILES];  // for 0 <= j < (1<<lognumtiles): tile offset relative to basetile
853 
854     int32_t yscale;
855 } psky_t;
856 
857 // Index of map-global (legacy) multi-sky:
858 EXTERN int32_t g_pskyidx;
859 // New multi-psky
860 EXTERN int32_t pskynummultis;
861 EXTERN psky_t * multipsky;
862 // Mapping of multi-sky index to base sky tile number:
863 EXTERN int32_t * multipskytile;
864 
getpskyidx(int32_t picnum)865 static FORCE_INLINE int32_t getpskyidx(int32_t picnum)
866 {
867     int32_t j;
868 
869     for (j=pskynummultis-1; j>0; j--)  // NOTE: j==0 on non-early loop end
870         if (picnum == multipskytile[j])
871             break;  // Have a match.
872 
873     return j;
874 }
875 
876 EXTERN psky_t * tileSetupSky(int32_t tilenum);
877 
878 EXTERN char parallaxtype;
879 EXTERN int32_t parallaxyoffs_override, parallaxyscale_override;
880 extern int16_t pskybits_override;
881 
882 // last sprite in the freelist, that is the spritenum for which
883 //   .statnum==MAXSTATUS && nextspritestat[spritenum]==-1
884 // (or -1 if freelist is empty):
885 EXTERN int16_t tailspritefree;
886 
887 EXTERN int16_t headspritesect[MAXSECTORS+1], headspritestat[MAXSTATUS+1];
888 EXTERN int16_t prevspritesect[MAXSPRITES], prevspritestat[MAXSPRITES];
889 EXTERN int16_t nextspritesect[MAXSPRITES], nextspritestat[MAXSPRITES];
890 
891 EXTERN vec2_16_t tilesiz[MAXTILES];
892 
893 EXTERN char picsiz[MAXTILES];
894 EXTERN char walock[MAXTILES];
895 
896 extern const char pow2char_[];
897 static CONSTEXPR const int32_t pow2long[32] =
898 {
899     1, 2, 4, 8,
900     16, 32, 64, 128,
901     256, 512, 1024, 2048,
902     4096, 8192, 16384, 32768,
903     65536, 131072, 262144, 524288,
904     1048576, 2097152, 4194304, 8388608,
905     16777216, 33554432, 67108864, 134217728,
906     268435456, 536870912, 1073741824, 2147483647
907 };
908 
909 // picanm[].sf:
910 // |bit(1<<7)
911 // |animtype|animtype|texhitscan|nofullbright|speed|speed|speed|speed|
912 enum {
913     PICANM_ANIMTYPE_NONE = 0,
914     PICANM_ANIMTYPE_OSC = (1<<6),
915     PICANM_ANIMTYPE_FWD = (2<<6),
916     PICANM_ANIMTYPE_BACK = (3<<6),
917 
918     PICANM_ANIMTYPE_SHIFT = 6,
919     PICANM_ANIMTYPE_MASK = (3<<6),  // must be 192
920     PICANM_MISC_MASK = (3<<4),
921     PICANM_TEXHITSCAN_BIT = (2<<4),
922     PICANM_NOFULLBRIGHT_BIT = (1<<4),
923     PICANM_ANIMSPEED_MASK = 15,  // must be 15
924 };
925 
926 enum {
927     TILEFLAGS_NONE = 0,
928     TILEFLAGS_TRUENPOT = (1<<1),
929 };
930 
931 // NOTE: If the layout of this struct is changed, loadpics() must be modified
932 // accordingly.
933 typedef struct {
934     uint8_t num;  // animate number
935     int8_t xofs, yofs;
936     uint8_t sf;  // anim. speed and flags
937     uint8_t tileflags; // tile-specific flags, such as true non-power-of-2 drawing.
938     uint8_t extra;
939 } picanm_t;
940 EXTERN picanm_t picanm[MAXTILES];
941 typedef struct { int16_t newtile; int16_t owner; } rottile_t;
942 EXTERN rottile_t rottile[MAXTILES];
943 EXTERN intptr_t waloff[MAXTILES];  // stores pointers to cache  -- SA
944 
945 EXTERN int32_t windowpos, windowx, windowy;
946 
947     //These variables are for auto-mapping with the draw2dscreen function.
948     //When you load a new board, these bits are all set to 0 - since
949     //you haven't mapped out anything yet.  Note that these arrays are
950     //bit-mapped.
951     //If you want draw2dscreen() to show sprite #54 then you say:
952     //   spritenum = 54;
953     //   show2dsprite[spritenum>>3] |= (1<<(spritenum&7));
954     //And if you want draw2dscreen() to not show sprite #54 then you say:
955     //   spritenum = 54;
956     //   show2dsprite[spritenum>>3] &= ~(1<<(spritenum&7));
957 
958 EXTERN int automapping;
959 EXTERN char show2dsector[(MAXSECTORS+7)>>3];
960 EXTERN char show2dwall[(MAXWALLS+7)>>3];
961 EXTERN char show2dsprite[(MAXSPRITES+7)>>3];
962 
963 // In the editor, gotpic is only referenced from inline assembly;
964 // the compiler needs that hint or building with LTO will discard it.
965 #if !defined __clang__ && !defined NOASM
966 # define GOTPIC_USED ATTRIBUTE((used))
967 #else
968 # define GOTPIC_USED
969 #endif
970 
971 EXTERN char GOTPIC_USED gotpic[(MAXTILES+7)>>3];
972 EXTERN char gotsector[(MAXSECTORS+7)>>3];
973 
974 EXTERN char editorcolors[256];
975 EXTERN char editorcolorsdef[256];
976 
977 EXTERN char faketile[(MAXTILES+7)>>3];
978 EXTERN char *faketiledata[MAXTILES];
979 EXTERN int faketilesize[MAXTILES];
980 
981 EXTERN char spritecol2d[MAXTILES][2];
982 EXTERN uint8_t tilecols[MAXTILES];
983 
984 EXTERN char editwall[(MAXWALLS+7)>>3];
985 
986 extern uint8_t vgapal16[4*256];
987 
988 extern uint32_t drawlinepat;
989 
990 extern void faketimerhandler(void);
991 
992 extern char apptitle[256];
993 
994 extern int32_t novoxmips;
995 
996 #ifdef DEBUGGINGAIDS
997 extern float debug1, debug2;
998 #endif
999 
1000 extern int16_t tiletovox[MAXTILES];
1001 extern int32_t usevoxels, voxscale[MAXVOXELS];
1002 extern char g_haveVoxels;
1003 
1004 #ifdef USE_OPENGL
1005 extern int32_t usemodels, usehightile;
1006 extern int32_t rendmode;
1007 #endif
1008 extern uint8_t globalr, globalg, globalb;
1009 EXTERN uint16_t h_xsize[MAXTILES], h_ysize[MAXTILES];
1010 EXTERN int8_t h_xoffs[MAXTILES], h_yoffs[MAXTILES];
1011 
1012 EXTERN char *globalpalwritten;
1013 
1014 enum {
1015     GLOBAL_NO_GL_TILESHADES = 1<<0,
1016     GLOBAL_NO_GL_FULLBRIGHT = 1<<1,
1017     GLOBAL_NO_GL_FOGSHADE = 1<<2,
1018 };
1019 
1020 extern int32_t globalflags;
1021 
1022 extern const char *engineerrstr;
1023 
1024 EXTERN int32_t editorzrange[2];
1025 
videoGetRenderMode(void)1026 static FORCE_INLINE int32_t videoGetRenderMode(void)
1027 {
1028 #ifndef USE_OPENGL
1029     return REND_CLASSIC;
1030 #else
1031     return rendmode;
1032 #endif
1033 }
1034 
1035 extern int32_t bloodhack;
1036 enum
1037 {
1038     ENGINE_19950829 = 19950829,  // Powerslave/Exhumed
1039     ENGINE_19960925 = 19960925,  // Blood v1.21
1040     ENGINE_19961112 = 19961112,  // Duke 3D v1.5, Redneck Rampage
1041     ENGINE_EDUKE32  = INT_MAX,
1042 };
1043 
1044 #ifndef EDUKE32_STANDALONE
1045 extern int32_t enginecompatibilitymode;
1046 #else
1047 static CONSTEXPR int32_t const enginecompatibilitymode = ENGINE_EDUKE32;
1048 #endif
1049 
1050 EXTERN int32_t duke64;
1051 extern bool (*rt_tileload_callback)(int16_t tileNum);
1052 
1053 /*************************************************************************
1054 POSITION VARIABLES:
1055 
1056         POSX is your x - position ranging from 0 to 65535
1057         POSY is your y - position ranging from 0 to 65535
1058             (the length of a side of the grid in EDITBORD would be 1024)
1059         POSZ is your z - position (height) ranging from 0 to 65535, 0 highest.
1060         ANG is your angle ranging from 0 to 2047.  Instead of 360 degrees, or
1061              2 * PI radians, I use 2048 different angles, so 90 degrees would
1062              be 512 in my system.
1063 
1064 SPRITE VARIABLES:
1065 
1066     EXTERN short headspritesect[MAXSECTORS+1], headspritestat[MAXSTATUS+1];
1067     EXTERN short prevspritesect[MAXSPRITES], prevspritestat[MAXSPRITES];
1068     EXTERN short nextspritesect[MAXSPRITES], nextspritestat[MAXSPRITES];
1069 
1070     Example: if the linked lists look like the following:
1071          ????????????????
1072                Sector lists:               Status lists:
1073          ????????????????J
1074            Sector0:  4, 5, 8             Status0:  2, 0, 8
1075            Sector1:  16, 2, 0, 7         Status1:  4, 5, 16, 7, 3, 9
1076            Sector2:  3, 9
1077          ????????????????
1078     Notice that each number listed above is shown exactly once on both the
1079         left and right side.  This is because any sprite that exists must
1080         be in some sector, and must have some kind of status that you define.
1081 
1082 
1083 Coding example #1:
1084     To go through all the sprites in sector 1, the code can look like this:
1085 
1086         sectnum = 1;
1087         i = headspritesect[sectnum];
1088         while (i != -1)
1089         {
1090             nexti = nextspritesect[i];
1091 
1092             //your code goes here
1093             //ex: printf("Sprite %d is in sector %d\n",i,sectnum);
1094 
1095             i = nexti;
1096         }
1097 
1098 Coding example #2:
1099     To go through all sprites with status = 1, the code can look like this:
1100 
1101         statnum = 1;        //status 1
1102         i = headspritestat[statnum];
1103         while (i != -1)
1104         {
1105             nexti = nextspritestat[i];
1106 
1107             //your code goes here
1108             //ex: printf("Sprite %d has a status of 1 (active)\n",i,statnum);
1109 
1110             i = nexti;
1111         }
1112 
1113              insertsprite(short sectnum, short statnum);
1114              deletesprite(short spritenum);
1115              changespritesect(short spritenum, short newsectnum);
1116              changespritestat(short spritenum, short newstatnum);
1117 
1118 TILE VARIABLES:
1119         NUMTILES - the number of tiles found TILES.DAT.
1120         TILESIZX[MAXTILES] - simply the x-dimension of the tile number.
1121         TILESIZY[MAXTILES] - simply the y-dimension of the tile number.
1122         WALOFF[MAXTILES] - the actual address pointing to the top-left
1123                                  corner of the tile.
1124         PICANM[MAXTILES] - flags for animating the tile.
1125 
1126 TIMING VARIABLES:
1127         TOTALCLOCK - When the engine is initialized, TOTALCLOCK is set to zero.
1128             From then on, it is incremented 120 times a second by 1.  That
1129             means that the number of seconds elapsed is totalclock / 120.
1130         NUMFRAMES - The number of times the draw3dscreen function was called
1131             since the engine was initialized.  This helps to determine frame
1132             rate.  (Frame rate = numframes * 120 / totalclock.)
1133 
1134 OTHER VARIABLES:
1135 
1136         STARTUMOST[320] is an array of the highest y-coordinates on each column
1137                 that my engine is allowed to write to.  You need to set it only
1138                 once.
1139         STARTDMOST[320] is an array of the lowest y-coordinates on each column
1140                 that my engine is allowed to write to.  You need to set it only
1141                 once.
1142         SINTABLE[2048] is a sin table with 2048 angles rather than the
1143             normal 360 angles for higher precision.  Also since SINTABLE is in
1144             all integers, the range is multiplied by 16383, so instead of the
1145             normal -1<sin(x)<1, the range of sintable is -16383<sintable[]<16383
1146             If you use this sintable, you can possibly speed up your code as
1147             well as save space in memory.  If you plan to use sintable, 2
1148             identities you may want to keep in mind are:
1149                 sintable[ang&2047]       = sin(ang * (3.141592/1024)) * 16383
1150                 sintable[(ang+512)&2047] = cos(ang * (3.141592/1024)) * 16383
1151         NUMSECTORS - the total number of existing sectors.  Modified every time
1152             you call the loadboard function.
1153 ***************************************************************************/
1154 
1155 typedef struct {
1156     vec3_t pos;
1157     int16_t sprite, wall, sect;
1158 } hitdata_t;
1159 
1160 typedef struct artheader_t {
1161     int32_t tilestart, tileend, numtiles;
1162 } artheader_t;
1163 #define ARTv1_UNITOFFSET ((signed)(4*sizeof(int32_t) + 2*sizeof(int16_t) + sizeof(picanm_t)))
1164 
1165 int32_t    enginePreInit(void);	// a partial setup of the engine used for launch windows
1166 int32_t    engineInit(void);
1167 int32_t enginePostInit(void);
1168 void   engineUnInit(void);
1169 void   initspritelists(void);
1170 int32_t engineFatalError(char const * msg);
1171 
1172 int32_t   engineLoadBoard(const char *filename, char flags, vec3_t *dapos, int16_t *daang, int16_t *dacursectnum);
1173 int32_t   engineLoadMHK(const char *filename);
1174 void engineClearLightsFromMHK();
1175 #ifdef HAVE_CLIPSHAPE_FEATURE
1176 int32_t engineLoadClipMaps(void);
1177 #endif
1178 int32_t   saveboard(const char *filename, const vec3_t *dapos, int16_t daang, int16_t dacursectnum);
1179 
1180 void    tileSetupDummy(int32_t tile);
1181 void    tileSetData(int32_t tile, int32_t tsiz, char const *buffer);
1182 void    tileDelete(int32_t tile);
1183 void    tileSetSize(int32_t picnum, int16_t dasizx, int16_t dasizy);
1184 int32_t artReadHeader(buildvfs_kfd fil, char const *fn, artheader_t *local);
1185 int32_t artReadHeaderFromBuffer(uint8_t const *buf, artheader_t *local);
1186 int32_t artCheckUnitFileHeader(uint8_t const *buf, int32_t length);
1187 void    tileConvertAnimFormat(int32_t picnum, uint32_t const picanmdisk);
1188 void    artReadManifest(buildvfs_kfd fil, artheader_t const *local);
1189 void    artPreloadFile(buildvfs_kfd fil, artheader_t const *local);
1190 int32_t artLoadFiles(const char *filename, int32_t askedsize);
1191 void    artClearMapArt(void);
1192 void    artSetupMapArt(const char *filename);
1193 bool    tileLoad(int16_t tilenume);
1194 void    tileLoadData(int16_t tilenume, int32_t dasiz, char *buffer);
1195 int32_t tileGetCRC32(int16_t tileNum);
1196 vec2_16_t tileGetSize(int16_t tileNum);
1197 void    artConvertRGB(palette_t *pic, uint8_t const *buf, int32_t bufsizx, int32_t sizx, int32_t sizy);
1198 void    tileUpdatePicSiz(int32_t picnum);
1199 
1200 int32_t   qloadkvx(int32_t voxindex, const char *filename);
1201 void vox_undefine(int32_t const);
1202 intptr_t   tileCreate(int16_t tilenume, int32_t xsiz, int32_t ysiz);
1203 void   tileCopySection(int32_t tilenume1, int32_t sx1, int32_t sy1, int32_t xsiz, int32_t ysiz, int32_t tilenume2, int32_t sx2, int32_t sy2);
1204 void   squarerotatetile(int16_t tilenume);
1205 
1206 int32_t   videoSetGameMode(char davidoption, int32_t daupscaledxdim, int32_t daupscaledydim, int32_t dabpp, int32_t daupscalefactor);
1207 void   videoNextPage(void);
1208 void   videoSetCorrectedAspect();
1209 void   videoSetViewableArea(int32_t x1, int32_t y1, int32_t x2, int32_t y2);
1210 void   renderSetAspect(int32_t daxrange, int32_t daaspect);
1211 void   renderFlushPerms(void);
1212 
1213 void plotlines2d(const int32_t *xx, const int32_t *yy, int32_t numpoints, int col) ATTRIBUTE((nonnull(1,2)));
1214 
1215 void   plotpixel(int32_t x, int32_t y, char col);
1216 void   renderSetTarget(int16_t tilenume, int32_t xsiz, int32_t ysiz);
1217 void   renderRestoreTarget(void);
1218 void   renderPrepareMirror(int32_t dax, int32_t day, int32_t daz, fix16_t daang, fix16_t dahoriz, int16_t dawall,
1219                            int32_t *tposx, int32_t *tposy, fix16_t *tang);
1220 void   renderCompleteMirror(void);
1221 
1222 int32_t renderDrawRoomsQ16(int32_t daposx, int32_t daposy, int32_t daposz, fix16_t daang, fix16_t dahoriz, int16_t dacursectnum);
1223 
drawrooms(int32_t daposx,int32_t daposy,int32_t daposz,int16_t daang,int16_t dahoriz,int16_t dacursectnum)1224 static FORCE_INLINE int32_t drawrooms(int32_t daposx, int32_t daposy, int32_t daposz, int16_t daang, int16_t dahoriz, int16_t dacursectnum)
1225 {
1226     return renderDrawRoomsQ16(daposx, daposy, daposz, fix16_from_int(daang), fix16_from_int(dahoriz), dacursectnum);
1227 }
1228 
1229 void   renderDrawMasks(void);
1230 void   videoClearViewableArea(int32_t dacol);
1231 void   videoClearScreen(int32_t dacol);
1232 void   renderDrawMapView(int32_t dax, int32_t day, int32_t zoome, int16_t ang);
1233 void   rotatesprite_(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum,
1234                      int8_t dashade, char dapalnum, int32_t dastat, uint8_t daalpha, uint8_t dablend,
1235                      int32_t cx1, int32_t cy1, int32_t cx2, int32_t cy2);
1236 void   renderDrawLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, char col);
1237 void   drawlinergb(int32_t x1, int32_t y1, int32_t x2, int32_t y2, palette_t p);
1238 int32_t    printext16(int32_t xpos, int32_t ypos, int16_t col, int16_t backcol,
1239                       const char *name, char fontsize) ATTRIBUTE((nonnull(5)));
1240 void   printext256(int32_t xpos, int32_t ypos, int16_t col, int16_t backcol,
1241                    const char *name, char fontsize) ATTRIBUTE((nonnull(5)));
1242 void   Buninitart(void);
1243 
1244 ////////// specialized rotatesprite wrappers for (very) often used cases //////////
rotatesprite(int32_t sx,int32_t sy,int32_t z,int16_t a,int16_t picnum,int8_t dashade,char dapalnum,int32_t dastat,int32_t cx1,int32_t cy1,int32_t cx2,int32_t cy2)1245 static FORCE_INLINE void rotatesprite(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum,
1246                                 int8_t dashade, char dapalnum, int32_t dastat,
1247                                 int32_t cx1, int32_t cy1, int32_t cx2, int32_t cy2)
1248 {
1249     rotatesprite_(sx, sy, z, a, picnum, dashade, dapalnum, dastat, 0, 0, cx1, cy1, cx2, cy2);
1250 }
1251 // Don't clip at all, i.e. the whole screen real estate is available:
rotatesprite_fs(int32_t sx,int32_t sy,int32_t z,int16_t a,int16_t picnum,int8_t dashade,char dapalnum,int32_t dastat)1252 static FORCE_INLINE void rotatesprite_fs(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum,
1253                                    int8_t dashade, char dapalnum, int32_t dastat)
1254 {
1255     rotatesprite_(sx, sy, z, a, picnum, dashade, dapalnum, dastat, 0, 0, 0,0,xdim-1,ydim-1);
1256 }
1257 
rotatesprite_fs_alpha(int32_t sx,int32_t sy,int32_t z,int16_t a,int16_t picnum,int8_t dashade,char dapalnum,int32_t dastat,uint8_t alpha)1258 static FORCE_INLINE void rotatesprite_fs_alpha(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum,
1259                                   int8_t dashade, char dapalnum, int32_t dastat, uint8_t alpha)
1260 {
1261     rotatesprite_(sx, sy, z, a, picnum, dashade, dapalnum, dastat, alpha, 0, 0, 0, xdim-1, ydim-1);
1262 }
1263 
rotatesprite_win(int32_t sx,int32_t sy,int32_t z,int16_t a,int16_t picnum,int8_t dashade,char dapalnum,int32_t dastat)1264 static FORCE_INLINE void rotatesprite_win(int32_t sx, int32_t sy, int32_t z, int16_t a, int16_t picnum,
1265                                     int8_t dashade, char dapalnum, int32_t dastat)
1266 {
1267     rotatesprite_(sx, sy, z, a, picnum, dashade, dapalnum, dastat, 0, 0, windowxy1.x,windowxy1.y,windowxy2.x,windowxy2.y);
1268 }
1269 
1270 void   getzrange(const vec3_t *pos, int16_t sectnum, int32_t *ceilz, int32_t *ceilhit, int32_t *florz,
1271                  int32_t *florhit, int32_t walldist, uint32_t cliptype) ATTRIBUTE((nonnull(1,3,4,5,6)));
1272 extern vec2_t hitscangoal;
1273 int32_t   hitscan(const vec3_t *sv, int16_t sectnum, int32_t vx, int32_t vy, int32_t vz,
1274                   hitdata_t *hitinfo, uint32_t cliptype) ATTRIBUTE((nonnull(1,6)));
1275 void   neartag(int32_t xs, int32_t ys, int32_t zs, int16_t sectnum, int16_t ange,
1276                int16_t *neartagsector, int16_t *neartagwall, int16_t *neartagsprite,
1277                int32_t *neartaghitdist, int32_t neartagrange, uint8_t tagsearch,
1278                int32_t (*blacklist_sprite_func)(int32_t)) ATTRIBUTE((nonnull(6,7,8)));
1279 int32_t   cansee(int32_t x1, int32_t y1, int32_t z1, int16_t sect1,
1280                  int32_t x2, int32_t y2, int32_t z2, int16_t sect2);
1281 int32_t   inside(int32_t x, int32_t y, int16_t sectnum);
1282 void   dragpoint(int16_t pointhighlight, int32_t dax, int32_t day, uint8_t flags);
1283 void   setfirstwall(int16_t sectnum, int16_t newfirstwall);
1284 int32_t try_facespr_intersect(uspriteptr_t const spr, vec3_t const in,
1285                                      int32_t vx, int32_t vy, int32_t vz,
1286                                      vec3_t * const intp, int32_t strictly_smaller_than_p);
1287 
1288 #define MAXUPDATESECTORDIST 1536
1289 #define INITIALUPDATESECTORDIST 256
1290 void updatesector(int32_t const x, int32_t const y, int16_t * const sectnum) ATTRIBUTE((nonnull(3)));
1291 void updatesectorexclude(int32_t const x, int32_t const y, int16_t * const sectnum,
1292                          const uint8_t * const excludesectbitmap) ATTRIBUTE((nonnull(3,4)));
1293 void updatesectorz(int32_t const x, int32_t const y, int32_t const z, int16_t * const sectnum) ATTRIBUTE((nonnull(4)));
1294 void updatesectorneighbor(int32_t const x, int32_t const y, int16_t * const sectnum, int32_t initialMaxDistance = INITIALUPDATESECTORDIST, int32_t maxDistance = MAXUPDATESECTORDIST) ATTRIBUTE((nonnull(3)));
1295 void updatesectorneighborz(int32_t const x, int32_t const y, int32_t const z, int16_t * const sectnum, int32_t initialMaxDistance = INITIALUPDATESECTORDIST, int32_t maxDistance = MAXUPDATESECTORDIST) ATTRIBUTE((nonnull(4)));
1296 
1297 int findwallbetweensectors(int sect1, int sect2);
sectoradjacent(int sect1,int sect2)1298 static FORCE_INLINE int sectoradjacent(int sect1, int sect2) { return findwallbetweensectors(sect1, sect2) != -1; }
1299 int32_t getsectordist(vec2_t const in, int const sectnum, vec2_t * const out = nullptr);
1300 extern const int16_t *chsecptr_onextwall;
1301 int32_t checksectorpointer(int16_t i, int16_t sectnum);
1302 
1303 void   mouseGetValues(int32_t *mousx, int32_t *mousy, int32_t *bstatus) ATTRIBUTE((nonnull(1,2,3)));
1304 
1305 #if !KRANDDEBUG
krand(void)1306 static FORCE_INLINE int32_t krand(void)
1307 {
1308     randomseed = (randomseed * 1664525ul) + 221297ul;
1309     return ((uint32_t) randomseed)>>16;
1310 }
1311 #else
1312 int32_t    krand(void);
1313 #endif
1314 
1315 int32_t   ksqrt(uint32_t num);
1316 int32_t   __fastcall getangle(int32_t xvect, int32_t yvect);
1317 fix16_t   __fastcall gethiq16angle(int32_t xvect, int32_t yvect);
1318 
getq16angle(int32_t xvect,int32_t yvect)1319 static FORCE_INLINE fix16_t __fastcall getq16angle(int32_t xvect, int32_t yvect)
1320 {
1321     return fix16_from_int(getangle(xvect, yvect));
1322 }
1323 
uhypsq(int32_t const dx,int32_t const dy)1324 static FORCE_INLINE CONSTEXPR uint32_t uhypsq(int32_t const dx, int32_t const dy)
1325 {
1326     return (uint32_t)dx*dx + (uint32_t)dy*dy;
1327 }
1328 
logapproach(int32_t const val,int32_t const targetval)1329 static FORCE_INLINE int32_t logapproach(int32_t const val, int32_t const targetval)
1330 {
1331     int32_t const dif = targetval - val;
1332     return (dif>>1) ? val + (dif>>1) : targetval;
1333 }
1334 
1335 void rotatepoint(vec2_t const pivot, vec2_t p, int16_t const daang, vec2_t * const p2) ATTRIBUTE((nonnull(4)));
1336 
rotatevec(vec2_t p,int16_t const daang,vec2_t * const p2)1337 static inline void rotatevec(vec2_t p, int16_t const daang, vec2_t * const p2)
1338 {
1339     int const dacos = sintable[(daang+2560)&2047];
1340     int const dasin = sintable[(daang+2048)&2047];
1341     *p2 = { dmulscale14(p.x, dacos, -p.y, dasin), dmulscale14(p.y, dacos, p.x, dasin) };
1342 }
1343 
1344 
1345 int32_t   lastwall(int16_t point);
1346 int32_t   nextsectorneighborz(int16_t sectnum, int32_t refz, int16_t topbottom, int16_t direction);
1347 
1348 int32_t   getceilzofslopeptr(usectorptr_t sec, int32_t dax, int32_t day) ATTRIBUTE((nonnull(1)));
1349 int32_t   getflorzofslopeptr(usectorptr_t sec, int32_t dax, int32_t day) ATTRIBUTE((nonnull(1)));
1350 void   getzsofslopeptr(usectorptr_t sec, int32_t dax, int32_t day,
1351                        int32_t *ceilz, int32_t *florz) ATTRIBUTE((nonnull(1,4,5)));
1352 void yax_getzsofslope(int sectNum, int playerX, int playerY, int32_t* pCeilZ, int32_t* pFloorZ);
1353 
1354 int32_t yax_getceilzofslope(int const sectnum, vec2_t const vect);
1355 int32_t yax_getflorzofslope(int const sectnum, vec2_t const vect);
1356 
getceilzofslope(int16_t sectnum,int32_t dax,int32_t day)1357 static FORCE_INLINE int32_t getceilzofslope(int16_t sectnum, int32_t dax, int32_t day)
1358 {
1359     return getceilzofslopeptr((usectorptr_t)&sector[sectnum], dax, day);
1360 }
1361 
getflorzofslope(int16_t sectnum,int32_t dax,int32_t day)1362 static FORCE_INLINE int32_t getflorzofslope(int16_t sectnum, int32_t dax, int32_t day)
1363 {
1364     return getflorzofslopeptr((usectorptr_t)&sector[sectnum], dax, day);
1365 }
1366 
getzsofslope(int16_t sectnum,int32_t dax,int32_t day,int32_t * ceilz,int32_t * florz)1367 static FORCE_INLINE void getzsofslope(int16_t sectnum, int32_t dax, int32_t day, int32_t *ceilz, int32_t *florz)
1368 {
1369     getzsofslopeptr((usectorptr_t)&sector[sectnum], dax, day, ceilz, florz);
1370 }
1371 
getcorrectzsofslope(int16_t sectnum,int32_t dax,int32_t day,int32_t * ceilz,int32_t * florz)1372 static FORCE_INLINE void getcorrectzsofslope(int16_t sectnum, int32_t dax, int32_t day, int32_t *ceilz, int32_t *florz)
1373 {
1374     vec2_t closest = { dax, day };
1375     getsectordist(closest, sectnum, &closest);
1376     getzsofslopeptr((usectorptr_t)&sector[sectnum], closest.x, closest.y, ceilz, florz);
1377 }
1378 
getcorrectceilzofslope(int16_t sectnum,int32_t dax,int32_t day)1379 static FORCE_INLINE int32_t getcorrectceilzofslope(int16_t sectnum, int32_t dax, int32_t day)
1380 {
1381     vec2_t closest = { dax, day };
1382     getsectordist(closest, sectnum, &closest);
1383     return getceilzofslopeptr((usectorptr_t)&sector[sectnum], closest.x, closest.y);
1384 }
1385 
getcorrectflorzofslope(int16_t sectnum,int32_t dax,int32_t day)1386 static FORCE_INLINE int32_t getcorrectflorzofslope(int16_t sectnum, int32_t dax, int32_t day)
1387 {
1388     vec2_t closest = { dax, day };
1389     getsectordist(closest, sectnum, &closest);
1390     return getflorzofslopeptr((usectorptr_t)&sector[sectnum], closest.x, closest.y);
1391 }
1392 
1393 // Is <wal> a red wall in a safe fashion, i.e. only if consistency invariant
1394 // ".nextsector >= 0 iff .nextwall >= 0" holds.
redwallp(uwallptr_t wal)1395 static FORCE_INLINE CONSTEXPR int32_t redwallp(uwallptr_t wal)
1396 {
1397     return (wal->nextwall >= 0 && wal->nextsector >= 0);
1398 }
1399 
E_SpriteIsValid(const int32_t i)1400 static FORCE_INLINE CONSTEXPR int32_t E_SpriteIsValid(const int32_t i)
1401 {
1402     return ((unsigned)i < MAXSPRITES && sprite[i].statnum != MAXSTATUS);
1403 }
1404 
1405 int clipshape_idx_for_sprite(uspriteptr_t curspr, int curidx);
1406 
1407 void   alignceilslope(int16_t dasect, int32_t x, int32_t y, int32_t z);
1408 void   alignflorslope(int16_t dasect, int32_t x, int32_t y, int32_t z);
1409 int32_t sectorofwall(int16_t wallNum);
1410 int32_t sectorofwall_noquick(int16_t wallNum);
1411 int32_t   loopnumofsector(int16_t sectnum, int16_t wallnum);
1412 void setslope(int32_t sectnum, int32_t cf, int16_t slope);
1413 
1414 int32_t lintersect(int32_t originX, int32_t originY, int32_t originZ,
1415                    int32_t destX, int32_t destY, int32_t destZ,
1416                    int32_t lineStartX, int32_t lineStartY, int32_t lineEndX, int32_t lineEndY,
1417                    int32_t *intersectionX, int32_t *intersectionY, int32_t *intersectionZ);
1418 
1419 int32_t rayintersect(int32_t x1, int32_t y1, int32_t z1, int32_t vx, int32_t vy, int32_t vz, int32_t x3,
1420                      int32_t y3, int32_t x4, int32_t y4, int32_t *intx, int32_t *inty, int32_t *intz);
1421 #if !defined NETCODE_DISABLE
1422 void do_insertsprite_at_headofstat(int16_t spritenum, int16_t statnum);
1423 int32_t insertspritestat(int16_t statnum);
1424 void do_deletespritestat(int16_t deleteme);
1425 void do_insertsprite_at_headofsect(int16_t spritenum, int16_t sectnum);
1426 void do_deletespritesect(int16_t deleteme);
1427 #endif
1428 int32_t insertsprite(int16_t sectnum, int16_t statnum);
1429 int32_t deletesprite(int16_t spritenum);
1430 
1431 int32_t   changespritesect(int16_t spritenum, int16_t newsectnum);
1432 int32_t   changespritestat(int16_t spritenum, int16_t newstatnum);
1433 int32_t   setsprite(int16_t spritenum, const vec3_t *) ATTRIBUTE((nonnull(2)));
1434 int32_t   setspritez(int16_t spritenum, const vec3_t *) ATTRIBUTE((nonnull(2)));
1435 
1436 int32_t spriteheightofsptr(uspriteptr_t spr, int32_t *height, int32_t alsotileyofs);
spriteheightofs(int16_t i,int32_t * height,int32_t alsotileyofs)1437 static FORCE_INLINE int32_t spriteheightofs(int16_t i, int32_t *height, int32_t alsotileyofs)
1438 {
1439     return spriteheightofsptr((uspriteptr_t)&sprite[i], height, alsotileyofs);
1440 }
1441 
1442 int videoCaptureScreen(const char *filename, char inverseit) ATTRIBUTE((nonnull(1)));
1443 int videoCaptureScreenTGA(const char *filename, char inverseit) ATTRIBUTE((nonnull(1)));
1444 
1445 struct OutputFileCounter {
1446     uint16_t count = 0;
1447     buildvfs_FILE opennextfile(char *, char *);
1448     buildvfs_FILE opennextfile_withext(char *, const char *);
1449 };
1450 
1451 // PLAG: line utility functions
1452 typedef struct s_equation
1453 {
1454     float a, b, c;
1455 } _equation;
1456 
1457 int32_t wallvisible(int32_t const x, int32_t const y, int16_t const wallnum);
1458 
1459 #define STATUS2DSIZ 144
1460 #define STATUS2DSIZ2 26
1461 
1462 //void   qsetmode640350(void);
1463 //void   qsetmode640480(void);
1464 void   videoSet2dMode(int32_t,int32_t);
1465 void   clear2dscreen(void);
1466 void   editorDraw2dGrid(int32_t posxe, int32_t posye, int32_t posze, int16_t cursectnum,
1467                   int16_t ange, int32_t zoome, int16_t gride);
1468 void   editorDraw2dScreen(const vec3_t *pos, int16_t cursectnum,
1469                     int16_t ange, int32_t zoome, int16_t gride) ATTRIBUTE((nonnull(1)));
1470 int32_t   editorDraw2dLine(int32_t x1, int32_t y1, int32_t x2, int32_t y2, int col);
1471 void   editorDraw2dCircle(int32_t x1, int32_t y1, int32_t r, int32_t eccen, char col);
1472 
1473 int32_t   videoSetRenderMode(int32_t renderer);
1474 
1475 #ifdef USE_OPENGL
1476 void    renderSetRollAngle(int32_t rolla);
1477 #endif
1478 
1479 //  pal: pass -1 to invalidate all palettes for the tile, or >=0 for a particular palette
1480 //  how: pass -1 to invalidate all instances of the tile in texture memory, or a bitfield
1481 //         bit 0: opaque or masked (non-translucent) texture, using repeating
1482 //         bit 1: ignored
1483 //         bit 2: 33% translucence, using repeating
1484 //         bit 3: 67% translucence, using repeating
1485 //         bit 4: opaque or masked (non-translucent) texture, using clamping
1486 //         bit 5: ignored
1487 //         bit 6: 33% translucence, using clamping
1488 //         bit 7: 67% translucence, using clamping
1489 //       clamping is for sprites, repeating is for walls
1490 void tileInvalidate(int16_t tilenume, int32_t pal, int32_t how);
1491 
1492 void polymostSet2dView(void);   // sets up GL for 2D drawing
1493 
1494 int32_t polymost_drawtilescreen(int32_t tilex, int32_t tiley, int32_t wallnum, int32_t dimen, int32_t tilezoom,
1495                                 int32_t usehitile, uint8_t *loadedhitile);
1496 void polymost_glreset(void);
1497 void polymost_precache(int32_t dapicnum, int32_t dapalnum, int32_t datype);
1498 
1499 typedef uint16_t polytintflags_t;
1500 
1501 enum cutsceneflags {
1502     CUTSCENE_FORCEFILTER = 1,
1503     CUTSCENE_FORCENOFILTER = 2,
1504     CUTSCENE_TEXTUREFILTER = 4,
1505 };
1506 
1507 extern int32_t benchmarkScreenshot;
1508 
1509 #ifdef USE_OPENGL
1510 extern int32_t glanisotropy;
1511 extern int32_t glusetexcompr;
1512 extern int32_t gltexfiltermode;
1513 extern int32_t r_useindexedcolortextures;
1514 
1515 enum {
1516     TEXFILTER_OFF = 0, // GL_NEAREST
1517     TEXFILTER_ON = 5, // GL_LINEAR_MIPMAP_LINEAR
1518 };
1519 
1520 extern int32_t glusetexcache, glusememcache;
1521 extern int32_t glprojectionhacks;
1522 extern int32_t gltexmaxsize;
1523 void gltexapplyprops (void);
1524 void texcache_invalidate(void);
1525 
1526 # ifdef USE_GLEXT
1527 extern int32_t r_detailmapping;
1528 extern int32_t r_glowmapping;
1529 # endif
1530 
1531 extern int32_t r_vertexarrays;
1532 # ifdef USE_GLEXT
1533 extern int32_t r_vbos;
1534 extern int32_t r_vbocount;
1535 # endif
1536 extern int32_t r_animsmoothing;
1537 extern int32_t r_parallaxskyclamping;
1538 extern int32_t r_parallaxskypanning;
1539 extern int32_t r_fullbrights;
1540 extern int32_t r_downsize;
1541 extern int32_t r_downsizevar;
1542 extern int32_t mdtims, omdtims;
1543 extern int32_t glrendmode;
1544 
1545 extern int32_t r_rortexture;
1546 extern int32_t r_rortexturerange;
1547 extern int32_t r_rorphase;
1548 #endif
1549 
1550 void hicinit(void);
1551 void hicsetpalettetint(int32_t palnum, char r, char g, char b, char sr, char sg, char sb, polytintflags_t effect);
1552 // flags bitset: 1 = don't compress
1553 int32_t hicsetsubsttex(int32_t picnum, int32_t palnum, const char *filen, float alphacut,
1554                        float xscale, float yscale, float specpower, float specfactor, char flags);
1555 int32_t hicsetskybox(int32_t picnum, int32_t palnum, char *faces[6], int32_t flags);
1556 int32_t hicclearsubst(int32_t picnum, int32_t palnum);
1557 
1558 int32_t Ptile2tile(int32_t tile, int32_t palette) ATTRIBUTE((pure));
1559 int32_t md_loadmodel(const char *fn);
1560 int32_t md_setmisc(int32_t modelid, float scale, int32_t shadeoff, float zadd, float yoffset, int32_t flags);
1561 // int32_t md_tilehasmodel(int32_t tilenume, int32_t pal);
1562 
1563 extern const char *G_DefaultDefFile(void);
1564 extern const char *G_DefFile(void);
1565 extern char *g_defNamePtr;
1566 
1567 extern GrowArray<char *> g_defModules;
1568 
1569 #ifdef HAVE_CLIPSHAPE_FEATURE
1570 extern GrowArray<char *> g_clipMapFiles;
1571 #endif
1572 
1573 EXTERN int32_t nextvoxid;
1574 EXTERN intptr_t voxoff[MAXVOXELS][MAXVOXMIPS]; // used in KenBuild
1575 EXTERN int8_t voxreserve[(MAXVOXELS+7)>>3];
1576 EXTERN int8_t voxrotate[(MAXVOXELS+7)>>3];
1577 
1578 #ifdef USE_OPENGL
1579 // TODO: dynamically allocate this
1580 
1581 typedef struct { vec3f_t add; int16_t angadd, flags, fov; } hudtyp;
1582 
1583 typedef struct
1584 {
1585     // maps build tiles to particular animation frames of a model
1586     int16_t     modelid;
1587     int16_t     framenum;   // calculate the number from the name when declaring
1588     int16_t     nexttile;
1589     uint16_t    smoothduration;
1590     hudtyp      *hudmem[2];
1591     int8_t      skinnum;
1592     char        pal;
1593 } tile2model_t;
1594 
1595 # define EXTRATILES (MAXTILES/8)
1596 
1597 EXTERN int32_t mdinited;
1598 EXTERN tile2model_t tile2model[MAXTILES+EXTRATILES];
1599 
md_tilehasmodel(int32_t const tilenume,int32_t const pal)1600 static FORCE_INLINE int32_t md_tilehasmodel(int32_t const tilenume, int32_t const pal)
1601 {
1602     return mdinited ? tile2model[Ptile2tile(tilenume,pal)].modelid : -1;
1603 }
1604 #endif  // defined USE_OPENGL
1605 
tilehasmodelorvoxel(int const tilenume,int pal)1606 static FORCE_INLINE int tilehasmodelorvoxel(int const tilenume, int pal)
1607 {
1608     UNREFERENCED_PARAMETER(pal);
1609     return
1610 #ifdef USE_OPENGL
1611     (videoGetRenderMode() >= REND_POLYMOST && mdinited && usemodels && tile2model[Ptile2tile(tilenume, pal)].modelid != -1) ||
1612 #endif
1613     (videoGetRenderMode() <= REND_POLYMOST && usevoxels && tiletovox[tilenume] != -1);
1614 }
1615 
1616 int32_t md_defineframe(int32_t modelid, const char *framename, int32_t tilenume,
1617                        int32_t skinnum, float smoothduration, int32_t pal);
1618 int32_t md_defineanimation(int32_t modelid, const char *framestart, const char *frameend,
1619                            int32_t fps, int32_t flags);
1620 int32_t md_defineskin(int32_t modelid, const char *skinfn, int32_t palnum, int32_t skinnum,
1621                       int32_t surfnum, float param, float specpower, float specfactor, int32_t flags);
1622 int32_t md_definehud (int32_t modelid, int32_t tilex, vec3f_t add,
1623                       int32_t angadd, int32_t flags, int32_t fov);
1624 int32_t md_undefinetile(int32_t tile);
1625 int32_t md_undefinemodel(int32_t modelid);
1626 
1627 int32_t loaddefinitionsfile(const char *fn);
1628 
1629 // if loadboard() fails with -2 return, try loadoldboard(). if it fails with
1630 // -2, board is dodgy
1631 int32_t engineLoadBoardV5V6(const char *filename, char fromwhere, vec3_t *dapos, int16_t *daang, int16_t *dacursectnum);
1632 
1633 #ifdef __cplusplus
1634 }
1635 #endif
1636 
1637 #include "hash.h"
1638 
1639 #ifdef POLYMER
1640 # include "polymer.h"
1641 #endif
1642 #ifdef USE_OPENGL
1643 # include "polymost.h"
1644 #endif
1645 
1646 #ifdef __cplusplus
1647 extern "C" {
1648 #endif
1649 
renderDisableFog(void)1650 static FORCE_INLINE void renderDisableFog(void)
1651 {
1652 #ifdef USE_OPENGL
1653     if (videoGetRenderMode() >= REND_POLYMOST)
1654     {
1655         polymost_setFogEnabled(false);
1656     }
1657 #endif
1658 }
1659 
renderEnableFog(void)1660 static FORCE_INLINE void renderEnableFog(void)
1661 {
1662 #ifdef USE_OPENGL
1663     if (videoGetRenderMode() >= REND_POLYMOST && !nofog)
1664         polymost_setFogEnabled(true);
1665 #endif
1666 }
1667 
inside_p(int32_t const x,int32_t const y,int const sectnum)1668 static FORCE_INLINE CONSTEXPR int inside_p(int32_t const x, int32_t const y, int const sectnum) { return (sectnum >= 0 && inside(x, y, sectnum) == 1); }
1669 
1670 #define SET_AND_RETURN(Lval, Rval) \
1671     do                             \
1672     {                              \
1673         (Lval) = (Rval);           \
1674         return;                    \
1675     } while (0)
1676 
compat_maybe_truncate_to_int32(int64_t val)1677 static FORCE_INLINE int64_t compat_maybe_truncate_to_int32(int64_t val)
1678 {
1679     return enginecompatibilitymode != ENGINE_EDUKE32 ? (int32_t)val : val;
1680 }
1681 
1682 static inline int32_t clipmove_old(int32_t *x, int32_t *y, int32_t *z, int16_t *sectnum, int32_t xvect, int32_t yvect, int32_t walldist,
1683                    int32_t ceildist, int32_t flordist, uint32_t cliptype) ATTRIBUTE((nonnull(1,2,3,4)));
1684 
clipmove_old(int32_t * x,int32_t * y,int32_t * z,int16_t * sectnum,int32_t xvect,int32_t yvect,int32_t walldist,int32_t ceildist,int32_t flordist,uint32_t cliptype)1685 static inline int32_t clipmove_old(int32_t *x, int32_t *y, int32_t *z, int16_t *sectnum, int32_t xvect, int32_t yvect, int32_t walldist,
1686                    int32_t ceildist, int32_t flordist, uint32_t cliptype)
1687 {
1688     vec3_t vector = { *x, *y, *z };
1689 
1690     int32_t result = clipmove(&vector, sectnum, xvect, yvect, walldist, ceildist, flordist, cliptype);
1691 
1692     *x = vector.x;
1693     *y = vector.y;
1694     *z = vector.z;
1695 
1696     return result;
1697 }
1698 
1699 static inline int32_t pushmove_old(int32_t *x, int32_t *y, int32_t *z, int16_t *sectnum, int32_t walldist,
1700                    int32_t ceildist, int32_t flordist, uint32_t cliptype) ATTRIBUTE((nonnull(1,2,3,4)));
1701 
pushmove_old(int32_t * x,int32_t * y,int32_t * z,int16_t * sectnum,int32_t walldist,int32_t ceildist,int32_t flordist,uint32_t cliptype)1702 static inline int32_t pushmove_old(int32_t *x, int32_t *y, int32_t *z, int16_t *sectnum, int32_t walldist,
1703                    int32_t ceildist, int32_t flordist, uint32_t cliptype)
1704 {
1705     vec3_t vector = { *x, *y, *z };
1706 
1707     int32_t result = pushmove(&vector, sectnum, walldist, ceildist, flordist, cliptype);
1708 
1709     *x = vector.x;
1710     *y = vector.y;
1711     *z = vector.z;
1712 
1713     return result;
1714 }
1715 
1716 static inline void getzrange_old(int32_t x, int32_t y, int32_t z, int16_t sectnum, int32_t *ceilz, int32_t *ceilhit, int32_t *florz,
1717                  int32_t *florhit, int32_t walldist, uint32_t cliptype) ATTRIBUTE((nonnull(5,6,7,8)));
1718 
getzrange_old(int32_t x,int32_t y,int32_t z,int16_t sectnum,int32_t * ceilz,int32_t * ceilhit,int32_t * florz,int32_t * florhit,int32_t walldist,uint32_t cliptype)1719 static inline void getzrange_old(int32_t x, int32_t y, int32_t z, int16_t sectnum, int32_t *ceilz, int32_t *ceilhit, int32_t *florz,
1720                  int32_t *florhit, int32_t walldist, uint32_t cliptype)
1721 {
1722     const vec3_t vector = { x, y, z };
1723     getzrange(&vector, sectnum, ceilz, ceilhit, florz, florhit, walldist, cliptype);
1724 }
1725 
setspritez_old(int16_t spritenum,int32_t x,int32_t y,int32_t z)1726 static inline int32_t setspritez_old(int16_t spritenum, int32_t x, int32_t y, int32_t z)
1727 {
1728     const vec3_t vector = { x, y, z };
1729     return setspritez(spritenum, &vector);
1730 }
1731 
1732 extern int32_t rintersect(int32_t x1, int32_t y1, int32_t z1,
1733     int32_t vx_, int32_t vy_, int32_t vz,
1734     int32_t x3, int32_t y3, int32_t x4, int32_t y4,
1735     int32_t *intx, int32_t *inty, int32_t *intz);
1736 
1737 extern int32_t(*animateoffs_replace)(int const tilenum, int fakevar);
1738 extern void(*paletteLoadFromDisk_replace)(void);
1739 extern int32_t(*getpalookup_replace)(int32_t davis, int32_t dashade);
1740 extern void(*initspritelists_replace)(void);
1741 extern int32_t(*insertsprite_replace)(int16_t sectnum, int16_t statnum);
1742 extern int32_t(*deletesprite_replace)(int16_t spritenum);
1743 extern int32_t(*changespritesect_replace)(int16_t spritenum, int16_t newsectnum);
1744 extern int32_t(*changespritestat_replace)(int16_t spritenum, int16_t newstatnum);
1745 extern void(*loadvoxel_replace)(int32_t voxel);
1746 extern int32_t(*loadboard_replace)(const char *filename, char flags, vec3_t *dapos, int16_t *daang, int16_t *dacursectnum);
1747 extern int32_t(*saveboard_replace)(const char *filename, const vec3_t *dapos, int16_t daang, int16_t dacursectnum);
1748 #ifdef USE_OPENGL
1749 extern void(*PolymostProcessVoxels_Callback)(void);
1750 #endif
1751 
tspriteGetSlope(tspriteptr_t const tspr)1752 static inline int16_t tspriteGetSlope(tspriteptr_t const tspr)
1753 {
1754     if (!(tspr->clipdist & TSPR_FLAGS_SLOPE_SPRITE))
1755         return 0;
1756     return uint8_t(tspr->xoffset) + (uint8_t(tspr->yoffset) << 8);
1757 }
1758 
spriteGetZOfSlope(uint16_t const spritenum,int32_t dax,int32_t day)1759 static inline int32_t spriteGetZOfSlope(uint16_t const spritenum, int32_t dax, int32_t day)
1760 {
1761     auto const spr = &sprite[spritenum];
1762     int16_t const heinum = spriteGetSlope(spritenum);
1763     if (heinum == 0)
1764         return spr->z;
1765 
1766     int const j = dmulscale4(sintable[(spr->ang+1024)&2047], day-spr->y,
1767                             -sintable[(spr->ang+512)&2047], dax-spr->x);
1768     return spr->z + mulscale18(heinum,j);
1769 }
1770 
tspriteGetZOfSlope(tspriteptr_t const tspr,int32_t dax,int32_t day)1771 static inline int32_t tspriteGetZOfSlope(tspriteptr_t const tspr, int32_t dax, int32_t day)
1772 {
1773     int16_t const heinum = tspriteGetSlope(tspr);
1774     if (heinum == 0)
1775         return tspr->z;
1776 
1777     int const j = dmulscale4(sintable[(tspr->ang+1024)&2047], day-tspr->y,
1778                             -sintable[(tspr->ang+512)&2047], dax-tspr->x);
1779     return tspr->z + mulscale18(heinum,j);
1780 }
1781 
tspriteGetZOfSlopeFloat(tspriteptr_t const tspr,float dax,float day)1782 static inline float tspriteGetZOfSlopeFloat(tspriteptr_t const tspr, float dax, float day)
1783 {
1784     int16_t const heinum = tspriteGetSlope(tspr);
1785     if (heinum == 0)
1786         return float(tspr->z);
1787 
1788     float const f = sintable[(tspr->ang+1024)&2047] * (day-tspr->y) - sintable[(tspr->ang+512)&2047] * (dax-tspr->x);
1789     return float(tspr->z) + heinum * f * (1.f/4194304.f);
1790 }
1791 
1792 #ifdef __cplusplus
1793 }
1794 #endif
1795 
1796 #endif // build_h_
1797