engine.cpp 460 KB
Newer Older
1
2
3
4
5
// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
// Ken Silverman's official web site: "http://www.advsys.net/ken"
// See the included license file "BUILDLIC.TXT" for license info.
//
// This file has been modified from Ken Silverman's original release
Evan Ramos's avatar
Evan Ramos committed
6
// by Jonathon Fowler (jf@jonof.id.au)
7
// by the EDuke32 team (development@voidpoint.com)
8

Richard Gobeille's avatar
Richard Gobeille committed
9
#define engine_c_
10

Richard Gobeille's avatar
Richard Gobeille committed
11
12
#include "a.h"
#include "baselayer.h"
13
14
#include "build.h"
#include "cache1d.h"
Richard Gobeille's avatar
Richard Gobeille committed
15
#include "colmatch.h"
16
#include "common.h"
17
#include "communityapi.h"
Richard Gobeille's avatar
Richard Gobeille committed
18
#include "compat.h"
19
#include "crc32.h"
Richard Gobeille's avatar
Richard Gobeille committed
20
21
#include "editor.h"
#include "engine_priv.h"
22
#include "hightile.h"
23
#include "kplib.h"
Evan Ramos's avatar
Evan Ramos committed
24
#include "lz4.h"
25
#include "microprofile.h"
Richard Gobeille's avatar
Richard Gobeille committed
26
27
28
#include "osd.h"
#include "palette.h"
#include "pragmas.h"
Richard Gobeille's avatar
Richard Gobeille committed
29
#include "scriptfile.h"
30
#include "softsurface.h"
31
#include "vfs.h"
Richard Gobeille's avatar
Richard Gobeille committed
32

33
#ifdef USE_OPENGL
34
# include "glad/glad.h"
35
# include "glsurface.h"
36
37
38
# include "mdsprite.h"
# ifdef POLYMER
#  include "polymer.h"
39
40
# endif
# include "polymost.h"
Richard Gobeille's avatar
Richard Gobeille committed
41
#endif
42

43
44
45
//////////
// Compilation switches for optional/extended engine features

46
#if !defined(__arm__) && !defined(GEKKO)
47
48
49
50
51
# define HIGH_PRECISION_SPRITE
#endif

#if !defined EDUKE32_TOUCH_DEVICES && !defined GEKKO && !defined __OPENDINGUX__
// Handle absolute z difference of floor/ceiling to camera >= 1<<24.
52
// Also: higher precision view-relative x and y for drawvox().
53
# define CLASSIC_Z_DIFF_64
54
55
#endif

56
#define MULTI_COLUMN_VLINE
57
//#define DEBUG_TILESIZY_512
58
//#define DEBUG_TILEOFFSETS
59
//////////
60

61
#ifdef DEBUGGINGAIDS
62
float debug1, debug2;
63
#endif
64

65
int32_t mapversion=7; // JBF 20040211: default mapversion to 7
66
int32_t g_loadedMapVersion = -1;  // -1: none (e.g. started new)
67
68
69

static int32_t get_mapversion(void);

70
// Handle nonpow2-ysize walls the old way?
71
static FORCE_INLINE int32_t oldnonpow2(void)
72
73
74
75
{
#if !defined CLASSIC_NONPOW2_YSIZE_WALLS
    return 1;
#else
76
    return ((g_loadedMapVersion < 10) && !(picanm[globalpicnum].tileflags & TILEFLAGS_TRUENPOT));
77
78
79
#endif
}

80
81
uint8_t globalr = 255, globalg = 255, globalb = 255;

Evan Ramos's avatar
Evan Ramos committed
82
83
int16_t pskybits_override = -1;

84
//void loadvoxel(int32_t voxindex) { UNREFERENCED_PARAMATER(voxindex); }
Philipp Kutin's avatar
Philipp Kutin committed
85
int16_t tiletovox[MAXTILES];
Richard Gobeille's avatar
Richard Gobeille committed
86
int32_t usevoxels = 1;
87
#ifdef USE_OPENGL
88
static char *voxfilenames[MAXVOXELS];
89
#endif
90
char g_haveVoxels;
91
//#define kloadvoxel loadvoxel
92

93
int32_t novoxmips = 0;
94

Richard Gobeille's avatar
Richard Gobeille committed
95
//These variables need to be copied into BUILD
96
97
98
#define MAXXSIZ 256
#define MAXYSIZ 256
#define MAXZSIZ 255
99
100
101
102
103
#ifdef EDUKE32_TOUCH_DEVICES
# define DISTRECIPSIZ (65536+256)
#else
# define DISTRECIPSIZ 131072
#endif
104
static char voxlock[MAXVOXELS][MAXVOXMIPS];
Richard Gobeille's avatar
Richard Gobeille committed
105
int32_t voxscale[MAXVOXELS];
106
uint8_t voxflags[MAXVOXELS];
107

Richard Gobeille's avatar
Richard Gobeille committed
108
static int32_t ggxinc[MAXXSIZ+1], ggyinc[MAXXSIZ+1];
109
static int32_t lowrecip[1024], nytooclose;
110
static const int32_t nytoofar = DISTRECIPSIZ*16384ull - 1048576;
111
static uint32_t *distrecip;
Richard Gobeille's avatar
Richard Gobeille committed
112
113
114
115
116
117
118
#define DISTRECIPCACHESIZE 3
static struct {
    uint32_t *distrecip;
    int32_t xdimen;
    int32_t age;
} distrecipcache[DISTRECIPCACHESIZE];
static int32_t distrecipagecnt = 0;
119

120
static int32_t *lookups = NULL;
121
static int32_t beforedrawrooms = 1;
122

123
124
int32_t benchmarkScreenshot = 0;

125
126
static int32_t oxdimen = -1, oviewingrange = -1;
int32_t oxyaspect = -1;
127

128
// r_usenewaspect is the cvar, newaspect_enable to trigger the new behaviour in the code
129
int32_t r_usenewaspect = 1, newaspect_enable=0;
130
uint32_t r_screenxy = 0;
131

132
int32_t r_rotatespriteinterp = 1;
133
int32_t r_fpgrouscan = 1;
134
135
int32_t r_displayindex = 0;
int32_t r_borderless = 2;
136
int32_t r_windowpositioning = 1;
137
138
int32_t globalflags;

139
140
float g_videoGamma = DEFAULT_GAMMA;
float g_videoContrast = DEFAULT_CONTRAST;
141
float g_videoSaturation = DEFAULT_SATURATION;
142

Richard Gobeille's avatar
Richard Gobeille committed
143
//Textured Map variables
144
static char globalpolytype;
145
static int16_t **dotp1, **dotp2;
146

Richard Gobeille's avatar
Richard Gobeille committed
147
static int8_t tempbuf[MAXWALLS];
148

149
// referenced from asm
150
151
152
#if !defined(NOASM) && defined __cplusplus
extern "C" {
#endif
Richard Gobeille's avatar
Richard Gobeille committed
153
int32_t ebpbak, espbak;
154
155
156
157
158
159
160
int32_t reciptable[2048], fpuasm;
intptr_t asm1, asm2, asm3, asm4, palookupoffse[4];
uint32_t vplce[4];
int32_t vince[4];
intptr_t bufplce[4];
int32_t globaltilesizy;
int32_t globalx1, globaly2, globalx3, globaly3;
161
#if !defined(NOASM) && defined __cplusplus
162
}
163
#endif
164

165
int32_t sloptable[SLOPTABLESIZ];
166
#define SLOPALOOKUPSIZ 16384
167
static intptr_t slopalookup[SLOPALOOKUPSIZ];    // was 2048
168

169
static int32_t no_radarang2 = 0;
170
171
static int16_t radarang[1280];
static int32_t qradarang[10240], *radarang2;
172
const char ATTRIBUTE((used)) pow2char_[8] = {1,2,4,8,16,32,64,128};
173

174
uint16_t ATTRIBUTE((used)) sqrtable[4096], ATTRIBUTE((used)) shlookup[4096+256], ATTRIBUTE((used)) sqrtable_old[2048];
175

176
char britable[16][256]; // JBF 20040207: full 8bit precision
177
178

extern char textfont[2048], smalltextfont[2048];
179
180

static char kensmessage[128];
181
const char *engineerrstr = "No error";
182

183
int32_t showfirstwall=0;
184
int32_t showheightindicators=1;
185
186
int32_t circlewall=-1;

Richard Gobeille's avatar
Richard Gobeille committed
187
static void classicScanSector(int16_t startsectnum);
188
static void draw_rainbow_background(void);
189

190
int16_t editstatus = 0;
191
static fix16_t global100horiz;  // (-100..300)-scale horiz (the one passed to drawrooms)
192

193
194
195
196
#ifndef EDUKE32_STANDALONE
int32_t enginecompatibilitymode = ENGINE_EDUKE32;
#endif

197
classicht_t *tileLoadHigh(int dapicnum)
198
{
199
#ifdef WITHKPLIB
200
201
202
203
204
205
206
    auto tsiz = tilesiz[dapicnum];
    auto si   = hicfindsubst(dapicnum, 0, 0);
    auto cht  = &classicht[dapicnum];

    if ((!usehightile) |
        ((paletteloaded & PALETTE_MAIN) != PALETTE_MAIN) |
        (tsiz.x <= 0) | (tsiz.y <= 0) |
207
        (!si || (si->flags & HICR_NOCHT) == HICR_NOCHT) |
208
        (cht->lock == 254))
209
210
        return NULL;

211
    if (!cht->ptr)
212
213
    {
        int32_t xsiz = 0, ysiz = 0;
214
        int32_t const length = kpzbufload(si->filename);
215

216
        if (EDUKE32_PREDICT_FALSE(length <= 0))
217
        {
218
invalid:
219
            cht->lock = 254;
220
221
            return NULL;
        }
222
223
224
225
226
        
        kpgetdim(kpzbuf, length, &xsiz, &ysiz);

        if (EDUKE32_PREDICT_FALSE((xsiz <= 0) | (ysiz <= 0)))
            goto invalid;
227

228
        vec2_16_t upscale = {};
229

230
231
232
        while (tsiz.x < xsiz) { tsiz.x <<= 1; upscale.x++; }
        while (tsiz.y < ysiz) { tsiz.y <<= 1; upscale.y++; }

233
234
235
236
237
238
239
        if ((tsiz.x != xsiz) | (tsiz.y != ysiz) | !(upscale.x | upscale.y))
            goto invalid;

        auto picptr = (palette_t *)Xmalloc(ysiz * (xsiz << 2));
        int  result = kprender(kpzbuf, length, (intptr_t)picptr, (xsiz << 2), xsiz, ysiz);

        if (EDUKE32_PREDICT_FALSE(result < 0))
240
241
        {
            Xfree(picptr);
242
            goto invalid;
243
        }
244
        
245
        cht->upscale = upscale;
246
247
        cht->lock    = CACHE1D_UNLOCKED;
        
248
        g_cache.allocateBlock(&cht->ptr, xsiz * ysiz, &cht->lock);
249

250
        //paletteFlushClosestColor();
251

252
        auto buf = (char*)cht->ptr;
253
254
255
256
        
        Bmemset(buf, 255, xsiz * ysiz);
        
        int const alphacut = clamp((int)(255.f - 255.f * si->alphacut), 0, 255);
257
258
259
260
261
262

        for (int j = 0; j < ysiz; ++j)
        {
            int const ofs = j * xsiz;
            for (int i = 0; i < xsiz; ++i)
            {
263
264
265
                auto col = &picptr[ofs + i];
                if (col->f >= alphacut)
                    buf[(i * ysiz) + j] = paletteGetClosestColorUpToIndex(col->b, col->g, col->r, 254);
266
267
            }
        }
268
269
        
        Xfree(picptr);
270
271
272
273
274
275
276
277
278
279
280
281
    }
    else if (cht->lock < CACHE1D_UNLOCKED)
        cht->lock = CACHE1D_UNLOCKED;

    return cht;
#else
    return NULL;
#endif
}

static classicht_t *globalht;

282
283
284
static uint8_t *reachablesectors;
int16_t wallsect[MAXWALLS];

285
286
287
288
289
290
291
292
293
294
295
296
297
298
void initcrc16()
{
    int i, j, k, a;
    for (j=0;j<256;j++)
    {
        for (i=7,k=(j<<8),a=0;i>=0;i--,k=((k<<1)&65535))
        {
            if ((k^a)&0x8000) a = ((a<<1)&65535)^0x1021;
            else a = ((a<<1)&65535);
        }
        crctab16[j] = (a&65535);
    }
}

299
// adapted from build.c
Richard Gobeille's avatar
Richard Gobeille committed
300
static void getclosestpointonwall_internal(vec2_t const p, int32_t const dawall, vec2_t *const closest)
301
{
302
303
    vec2_t const w  = wall[dawall].xy;
    vec2_t const w2 = wall[wall[dawall].point2].xy;
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
    vec2_t const d  = { w2.x - w.x, w2.y - w.y };

    int64_t i = d.x * ((int64_t)p.x - w.x) + d.y * ((int64_t)p.y - w.y);

    if (i <= 0)
    {
        *closest = w;
        return;
    }

    int64_t const j = (int64_t)d.x * d.x + (int64_t)d.y * d.y;

    if (i >= j)
    {
        *closest = w2;
        return;
    }

    i = tabledivide64((i << 15), j) << 15;

    *closest = { (int32_t)(w.x + ((d.x * i) >> 30)), (int32_t)(w.y + ((d.y * i) >> 30)) };
}
326
327
328

////////// YAX //////////

329
int32_t numgraysects = 0;
330
331
uint8_t graysectbitmap[(MAXSECTORS+7)>>3];
uint8_t graywallbitmap[(MAXWALLS+7)>>3];
332
int32_t autogray = 0, showinnergray = 1;
Philipp Kutin's avatar
Philipp Kutin committed
333

334
335
//#define YAX_DEBUG_YMOSTS

336
#ifdef YAX_DEBUG
337
// XXX: This could be replaced with the use of gethiticks().
338
double u64tickspersec;
339
#endif
Philipp Kutin's avatar
Philipp Kutin committed
340
341
342
343
#ifdef ENGINE_SCREENSHOT_DEBUG
int32_t engine_screenshot = 0;
#endif

344
345
346
347
348
int32_t get_alwaysshowgray(void)
{
    return showinnergray || !(editorzrange[0]==INT32_MIN && editorzrange[1]==INT32_MAX);
}

Philipp Kutin's avatar
Philipp Kutin committed
349
350
void yax_updategrays(int32_t posze)
{
351
    int32_t i, j;
352
353
354
#ifdef YAX_ENABLE
    int32_t mingoodz=INT32_MAX, maxgoodz=INT32_MIN;
#else
Philipp Kutin's avatar
Philipp Kutin committed
355
356
    UNREFERENCED_PARAMETER(posze);
#endif
357

Philipp Kutin's avatar
Philipp Kutin committed
358
359
360
361
362
363
364
365
    Bmemset(graysectbitmap, 0, sizeof(graysectbitmap));
    Bmemset(graywallbitmap, 0, sizeof(graywallbitmap));

    for (i=0; i<numsectors; i++)
    {
#ifdef YAX_ENABLE
        int16_t cb, fb;
        yax_getbunches(i, &cb, &fb);
366
367
368
369
370

        // Update grayouts due to TROR, has to be --v--       half-open      --v--
        // because only one level should ever be    v                          v
        // active.                                  v                          v
        int32_t keep = ((cb<0 || sector[i].ceilingz < posze) && (fb<0 || posze <= sector[i].floorz));
371
372
        if (autogray && (cb>=0 || fb>=0) && (sector[i].ceilingz <= posze && posze <= sector[i].floorz))
        {
373
374
            mingoodz = min(mingoodz, TrackerCast(sector[i].ceilingz));
            maxgoodz = max(maxgoodz, TrackerCast(sector[i].floorz));
375
        }
Philipp Kutin's avatar
Philipp Kutin committed
376
#endif
377
        // update grayouts due to editorzrange
378
379
        keep &= (sector[i].ceilingz >= editorzrange[0] && sector[i].floorz <= editorzrange[1]);
        if (!keep)  // outside bounds, gray out!
380
            bitmap_set(graysectbitmap, i);
381
382
383
384
385
386
387
    }

#ifdef YAX_ENABLE
    if (autogray && mingoodz<=maxgoodz)
    {
        for (i=0; i<numsectors; i++)
            if (!(mingoodz <= sector[i].ceilingz && sector[i].floorz <= maxgoodz))
388
                bitmap_set(graysectbitmap, i);
389
390
391
    }
#endif

392
    numgraysects = 0;
393
394
    for (i=0; i<numsectors; i++)
    {
395
        if (bitmap_test(graysectbitmap, i))
396
397
        {
            numgraysects++;
Philipp Kutin's avatar
Philipp Kutin committed
398
            for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
399
                bitmap_set(graywallbitmap, j);
400
        }
Philipp Kutin's avatar
Philipp Kutin committed
401
402
403
404
    }
}


405
406
407
408
#if !defined YAX_ENABLE
# warning Non-TROR builds are supported only for debugging. Expect savegame breakage etc...
#endif

409
410
411
412
#ifdef YAX_ENABLE
// all references to floor/ceiling bunchnums should be through the
// get/set functions!

413
int32_t g_nodraw = 0;
Philipp Kutin's avatar
Philipp Kutin committed
414
int32_t scansector_retfast = 0;
415
int32_t scansector_collectsprites = 1;
416
417
int32_t yax_globalcf = -1, yax_nomaskpass=0, yax_nomaskdidit;  // engine internal
int32_t r_tror_nomaskpass = 1;  // cvar
418
419
int32_t yax_globallev = YAX_MAXDRAWS;
int32_t yax_globalbunch = -1;
420
int32_t yax_polymostclearzbuffer = 1;
Philipp Kutin's avatar
Philipp Kutin committed
421
422
423
424
425
426
427

// duplicated tsprites
//  [i]:
//   i==MAXDRAWS: base level
//   i<MAXDRAWS: MAXDRAWS-i-1 is level towards ceiling
//   i>MAXDRAWS: i-MAXDRAWS-1 is level towards floor
static int16_t yax_spritesortcnt[1 + 2*YAX_MAXDRAWS];
428
429
static uint16_t yax_tsprite[1 + 2*YAX_MAXDRAWS][MAXSPRITESONSCREEN];
static uint8_t yax_tsprfrombunch[1 + 2*YAX_MAXDRAWS][MAXSPRITESONSCREEN];
430
static int16_t yax_updown[MAXSECTORS][2];
431

432
// drawn sectors
433
uint8_t yax_gotsector[(MAXSECTORS+7)>>3];  // engine internal
434

435
436
# if !defined NEW_MAP_FORMAT
// Game-time YAX data structures, V7-V9 map formats.
Philipp Kutin's avatar
Philipp Kutin committed
437
438
int16_t yax_bunchnum[MAXSECTORS][2];
int16_t yax_nextwall[MAXWALLS][2];
439

440
static FORCE_INLINE int32_t yax_islockededge(int32_t line, int32_t cf)
441
442
443
{
    return !!(wall[line].cstat&(YAX_NEXTWALLBIT(cf)));
}
444

445
446
#define YAX_PTRBUNCHNUM(Ptr, Sect, Cf) (*(&Ptr[Sect].ceilingxpanning + 8*Cf))
#define YAX_BUNCHNUM(Sect, Cf) YAX_PTRBUNCHNUM(sector, Sect, Cf)
447
448

//// bunch getters/setters
449
450
int16_t yax_getbunch(int16_t i, int16_t cf)
{
451
452
453
    if (editstatus==0)
        return yax_bunchnum[i][cf];

454
    return (*(&sector[i].ceilingstat + cf) & YAX_BIT) ? YAX_BUNCHNUM(i, cf) : -1;
455
}
456
457
458
459
460
# else
#  define YAX_PTRBUNCHNUM(Ptr, Sect, Cf) (*((Cf) ? &(Ptr)[Sect].floorbunch : &(Ptr)[Sect].ceilingbunch))
#  define YAX_BUNCHNUM(Sect, Cf) YAX_PTRBUNCHNUM(sector, Sect, Cf)

#  if !defined NEW_MAP_FORMAT
461
static FORCE_INLINE int32_t yax_islockededge(int32_t line, int32_t cf)
462
463
464
465
466
{
    return (yax_getnextwall(line, cf) >= 0);
}
#  endif
# endif
467

468
469
470
// bunchnum: -1: also clear yax-nextwalls (forward and reverse)
//           -2: don't clear reverse yax-nextwalls
//           -3: don't clear either forward or reverse yax-nextwalls
471
472
void yax_setbunch(int16_t i, int16_t cf, int16_t bunchnum)
{
473
    if (editstatus==0)
474
    {
475
476
477
#ifdef NEW_MAP_FORMAT
        YAX_BUNCHNUM(i, cf) = bunchnum;
#else
478
        yax_bunchnum[i][cf] = bunchnum;
479
#endif
480
481
        return;
    }
482

483
    if (bunchnum < 0)
484
    {
485
        if (bunchnum > -3)
486
        {
487
            // TODO: for in-game too?
488
            for (bssize_t ynw, j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
Philipp Kutin's avatar
Philipp Kutin committed
489
            {
490
491
492
493
494
495
496
                ynw = yax_getnextwall(j, cf);
                if (ynw >= 0)
                {
                    if (bunchnum > -2)
                        yax_setnextwall(ynw, !cf, -1);
                    yax_setnextwall(j, cf, -1);
                }
Philipp Kutin's avatar
Philipp Kutin committed
497
            }
498
499
        }

500
#if !defined NEW_MAP_FORMAT
501
        *(&sector[i].ceilingstat + cf) &= ~YAX_BIT;
502
503
504
        // NOTE: Don't reset xpanning-as-index, since we can be called from
        // e.g. Mapster32's "Inner loop made into new sector" functionality.
//        YAX_BUNCHNUM(i, cf) = 0;
505
506
507
#else
        YAX_BUNCHNUM(i, cf) = -1;
#endif
508
509
510
        return;
    }

511
#if !defined NEW_MAP_FORMAT
512
    *(&sector[i].ceilingstat + cf) |= YAX_BIT;
513
#endif
514
515
516
    YAX_BUNCHNUM(i, cf) = bunchnum;
}

517
518
519
520
521
522
void yax_setbunches(int16_t i, int16_t cb, int16_t fb)
{
    yax_setbunch(i, YAX_CEILING, cb);
    yax_setbunch(i, YAX_FLOOR, fb);
}

523
# if !defined NEW_MAP_FORMAT
524
525
526
527
528
529
//// nextwall getters/setters
int16_t yax_getnextwall(int16_t wal, int16_t cf)
{
    if (editstatus==0)
        return yax_nextwall[wal][cf];

530
    return yax_islockededge(wal, cf) ? YAX_NEXTWALL(wal, cf) : -1;
531
532
533
534
535
536
537
538
539
540
541
542
}

// unchecked!
void yax_setnextwall(int16_t wal, int16_t cf, int16_t thenextwall)
{
    if (editstatus==0)
    {
        yax_nextwall[wal][cf] = thenextwall;
        return;
    }

    if (thenextwall >= 0)
543
    {
544
        wall[wal].cstat |= YAX_NEXTWALLBIT(cf);
545
546
        YAX_NEXTWALL(wal, cf) = thenextwall;
    }
547
    else
548
    {
549
        wall[wal].cstat &= ~YAX_NEXTWALLBIT(cf);
550
        YAX_NEXTWALL(wal, cf) = YAX_NEXTWALLDEFAULT(cf);
551
    }
552
}
553
# endif
554

555
556
557
558
// make one step in the vertical direction, and if the wall we arrive at
// is red, return its nextsector.
int16_t yax_vnextsec(int16_t line, int16_t cf)
{
Richard Gobeille's avatar
Richard Gobeille committed
559
560
    int16_t const ynw = yax_getnextwall(line, cf);
    return (ynw < 0) ? -1 : wall[ynw].nextsector;
561
562
563
}


564
//// in-struct --> array transfer (only resetstat==0); list construction
Philipp Kutin's avatar
Philipp Kutin committed
565
566
567
568
// resetstat:  0: reset and read data from structs and construct linked lists etc.
//             1: only reset
//             2: read data from game-time arrays and construct linked lists etc.
void yax_update(int32_t resetstat)
569
{
570
571
572
573
574
575
    int32_t i;
#if !defined NEW_MAP_FORMAT
    int32_t j;
    const int32_t oeditstatus=editstatus;
#endif
    int16_t cb, fb;
576

577
578
    if (resetstat != 2)
        numyaxbunches = 0;
579
580
581

    for (i=0; i<MAXSECTORS; i++)
    {
582
#if !defined NEW_MAP_FORMAT
Philipp Kutin's avatar
Philipp Kutin committed
583
584
        if (resetstat != 2 || i>=numsectors)
            yax_bunchnum[i][0] = yax_bunchnum[i][1] = -1;
585
#endif
586
587
        nextsectbunch[0][i] = nextsectbunch[1][i] = -1;
    }
588
589
590

    Bmemset(yax_updown, -1, sizeof(yax_updown));

591
592
    for (i=0; i<YAX_MAXBUNCHES; i++)
        headsectbunch[0][i] = headsectbunch[1][i] = -1;
593
#if !defined NEW_MAP_FORMAT
594
    for (i=0; i<MAXWALLS; i++)
Philipp Kutin's avatar
Philipp Kutin committed
595
596
        if (resetstat != 2 || i>=numwalls)
            yax_nextwall[i][0] = yax_nextwall[i][1] = -1;
597
#endif
598

Philipp Kutin's avatar
Philipp Kutin committed
599
    if (resetstat==1)
600
601
        return;

602
    // Constuct singly linked list of sectors-of-bunch.
603

604
605
#if !defined NEW_MAP_FORMAT
    // Read bunchnums directly from the sector struct in yax_[gs]etbunch{es}!
606
    editstatus = (resetstat==0);
607
608
    // NOTE: Use oeditstatus to check for in-gamedness from here on!
#endif
609
610
611
612
613

    if (resetstat==0)
    {
        // make bunchnums consecutive
        uint8_t *const havebunch = (uint8_t *)tempbuf;
614
        uint8_t *const bunchmap = havebunch + ((YAX_MAXBUNCHES+7)>>3);
615
616
        int32_t dasub = 0;

617
        Bmemset(havebunch, 0, (YAX_MAXBUNCHES+7)>>3);
618
619
620
621
        for (i=0; i<numsectors; i++)
        {
            yax_getbunches(i, &cb, &fb);
            if (cb>=0)
622
                bitmap_set(havebunch, cb);
623
            if (fb>=0)
624
                bitmap_set(havebunch, fb);
625
626
627
628
        }

        for (i=0; i<YAX_MAXBUNCHES; i++)
        {
629
            if (bitmap_test(havebunch, i)==0)
630
631
632
633
634
635
636
637
638
639
640
641
642
643
            {
                bunchmap[i] = 255;
                dasub++;
                continue;
            }

            bunchmap[i] = i-dasub;
        }

        for (i=0; i<numsectors; i++)
        {
            yax_getbunches(i, &cb, &fb);
            if (cb>=0)
                yax_setbunch(i, YAX_CEILING, bunchmap[cb]);
644
            if (fb>=0)
645
646
647
648
                yax_setbunch(i, YAX_FLOOR, bunchmap[fb]);
        }
    }

649
650
    // In-struct --> array transfer (resetstat==0 and !defined NEW_MAP_FORMAT)
    // and list construction.
651
652
653
    for (i=numsectors-1; i>=0; i--)
    {
        yax_getbunches(i, &cb, &fb);
654
#if !defined NEW_MAP_FORMAT
Philipp Kutin's avatar
Philipp Kutin committed
655
656
657
658
659
        if (resetstat==0)
        {
            yax_bunchnum[i][0] = cb;
            yax_bunchnum[i][1] = fb;
        }
660
#endif
661
662
663

        if (cb >= 0)
        {
664
#if !defined NEW_MAP_FORMAT
Philipp Kutin's avatar
Philipp Kutin committed
665
666
667
668
            if (resetstat==0)
                for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
                {
                    if (yax_islockededge(j,YAX_CEILING))
669
                    {
Philipp Kutin's avatar
Philipp Kutin committed
670
                        yax_nextwall[j][0] = YAX_NEXTWALL(j,0);
671
672
673
                        if (oeditstatus==0)
                            YAX_NEXTWALL(j,0) = 0;  // reset lotag!
                    }
Philipp Kutin's avatar
Philipp Kutin committed
674
                }
675
#endif
676
677
678
679
680
            if (headsectbunch[0][cb] == -1)
            {
                headsectbunch[0][cb] = i;
                // not duplicated in floors, since every extended ceiling
                // must have a corresponding floor:
Philipp Kutin's avatar
Philipp Kutin committed
681
682
                if (resetstat==0)
                    numyaxbunches++;
683
684
685
            }
            else
            {
686
                int32_t tmpsect = headsectbunch[0][cb];
687
688
689
690
691
692
693
                headsectbunch[0][cb] = i;
                nextsectbunch[0][i] = tmpsect;
            }
        }

        if (fb >= 0)
        {
694
#if !defined NEW_MAP_FORMAT
Philipp Kutin's avatar
Philipp Kutin committed
695
696
697
698
            if (resetstat==0)
                for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
                {
                    if (yax_islockededge(j,YAX_FLOOR))
699
                    {
Philipp Kutin's avatar
Philipp Kutin committed
700
                        yax_nextwall[j][1] = YAX_NEXTWALL(j,1);
701
702
703
                        if (oeditstatus==0)
                            YAX_NEXTWALL(j,1) = -1;  // reset extra!
                    }
Philipp Kutin's avatar
Philipp Kutin committed
704
                }
705
#endif
706
707
708
709
            if (headsectbunch[1][fb] == -1)
                headsectbunch[1][fb] = i;
            else
            {
710
                int32_t tmpsect = headsectbunch[1][fb];
711
712
713
714
715
                headsectbunch[1][fb] = i;
                nextsectbunch[1][i] = tmpsect;
            }
        }
    }
716

717
#if !defined NEW_MAP_FORMAT
718
    editstatus = oeditstatus;
719
#else
720
    mapversion = get_mapversion();
721
#endif
722
}
723

724
int32_t yax_getneighborsect(int32_t x, int32_t y, int32_t sectnum, int32_t cf)
725
{
726
    // yax_updown is initialized to -1, but inside() checks it so don't check it here
727
    if (!editstatus && inside(x, y, yax_updown[sectnum][!cf])==1)
728
729
        return yax_updown[sectnum][!cf];

730
731
732
733
734
    int16_t bunchnum = yax_getbunch(sectnum, cf);

    if (bunchnum < 0)
        return -1;

735
    for (bssize_t SECTORS_OF_BUNCH(bunchnum, !cf, i))
736
        if (inside(x, y, i)==1)
737
738
739
        {
            yax_updown[i][cf] = sectnum;
            yax_updown[sectnum][!cf] = i;
740
            return i;
741
        }
742
743
744
745

    return -1;
}

746
747
748
749
// indexed as a list:
static int16_t bunches[2][YAX_MAXBUNCHES];
// indexed with bunchnums directly:
static int16_t bunchsec[YAX_MAXBUNCHES], bunchdist[YAX_MAXBUNCHES];
Philipp Kutin's avatar
Philipp Kutin committed
750

751
752
static int32_t ymostallocsize = 0;  // numyaxbunches*xdimen (no sizeof(int16_t) here!)
static int16_t *yumost=NULL, *ydmost=NULL;  // used as if [numyaxbunches][xdimen]
753
uint8_t haveymost[(YAX_MAXBUNCHES+7)>>3];
754
755
756

static inline int32_t yax_walldist(int32_t w)
{
757
758
759
    vec2_t closest;
    getclosestpointonwall_internal({ globalposx, globalposy }, w, &closest);
    return klabs(closest.x-globalposx) + klabs(closest.y-globalposy);
760
761
}

762
763
// calculate distances to bunches and best start-drawing sectors
static void yax_scanbunches(int32_t bbeg, int32_t numhere, const uint8_t *lastgotsector)
764
{
765
    int32_t bnchcnt, bunchnum, j, k;
766
    int32_t startwall, endwall;
767

768
769
    UNREFERENCED_PARAMETER(lastgotsector);

770
    scansector_collectsprites = 0;
Philipp Kutin's avatar
Philipp Kutin committed
771

772
    for (bnchcnt=bbeg; bnchcnt<bbeg+numhere; bnchcnt++)
Philipp Kutin's avatar
Philipp Kutin committed
773
    {
774
        int32_t walldist, bestsec=-1;
775
        int32_t bestwalldist=INT32_MAX;
776
777

        bunchnum = bunches[yax_globalcf][bnchcnt];
778

779
        for (SECTORS_OF_BUNCH(bunchnum,!yax_globalcf, k))
Philipp Kutin's avatar
Philipp Kutin committed
780
        {
781
782
783
            if (inside(globalposx, globalposy, k)==1)
            {
                bestsec = k;
784
                bestwalldist = 0;
785
786
787
                break;
            }

Philipp Kutin's avatar
Philipp Kutin committed
788
789
790
791
792
793
            startwall = sector[k].wallptr;
            endwall = startwall+sector[k].wallnum;

            for (j=startwall; j<endwall; j++)
            {
/*
794
795
                if ((w=yax_getnextwall(j,!yax_globalcf))>=0)
                    if ((ns=wall[w].nextsector)>=0)
796
                        if ((lastgotsector[ns>>3]&pow2char[ns&7])==0)
797
                            continue;
Philipp Kutin's avatar
Philipp Kutin committed
798
799
800
*/
                walldist = yax_walldist(j);
                if (walldist < bestwalldist)
801
                {
Philipp Kutin's avatar
Philipp Kutin committed
802
                    bestsec = k;
803
                    bestwalldist = walldist;
804
                }
Philipp Kutin's avatar
Philipp Kutin committed
805
            }
806
                }
Philipp Kutin's avatar
Philipp Kutin committed
807

808
        bunchsec[bunchnum] = bestsec;
809
        bunchdist[bunchnum] = bestwalldist;
Philipp Kutin's avatar
Philipp Kutin committed
810
    }
811
812
813
814

    scansector_collectsprites = 1;
}

815
static int yax_cmpbunches(const void *b1, const void *b2)
816
{
817
    return (bunchdist[B_UNBUF16(b2)] - bunchdist[B_UNBUF16(b1)]);
Philipp Kutin's avatar
Philipp Kutin committed
818
}
819

820
821

void yax_tweakpicnums(int32_t bunchnum, int32_t cf, int32_t restore)
Philipp Kutin's avatar
Philipp Kutin committed
822
{
823
824
825
    // for polymer, this is called before polymer_drawrooms() with restore==0
    // and after polymer_drawmasks() with restore==1

826
    int32_t i, dastat;
827
828
829
830
831
    static int16_t opicnum[2][MAXSECTORS];
#ifdef DEBUGGINGAIDS
    static uint8_t expect_restore[2][YAX_MAXBUNCHES];

    // must call this with restore == 0, 1,  0, 1,  0, 1,  ...
832
    Bassert(expect_restore[cf][bunchnum] == restore);
833
834
    expect_restore[cf][bunchnum] = !expect_restore[cf][bunchnum];
#endif
835

836
    for (SECTORS_OF_BUNCH(bunchnum, cf, i))
837
    {
838
        dastat = (SECTORFLD(i,stat, cf)&(128+256));
839

840
        // only consider non-masked ceilings/floors
841
        if (dastat==0 || (restore==1 && opicnum[cf][i]&0x8000))
Philipp Kutin's avatar
Philipp Kutin committed
842
843
844
845
846
        {
            if (!restore)
            {
                opicnum[cf][i] = SECTORFLD(i,picnum, cf);
                if (editstatus && showinvisibility)
847
                    SECTORFLD(i,picnum, cf) = MAXTILES-1;
848
                else //if ((dastat&(128+256))==0)
Philipp Kutin's avatar
Philipp Kutin committed
849
850
851
852
853
854
                    SECTORFLD(i,picnum, cf) = 13; //FOF;
            }
            else
            {
                SECTORFLD(i,picnum, cf) = opicnum[cf][i];
            }
855
856
#ifdef POLYMER
            // will be called only in editor
857
            if (videoGetRenderMode() == REND_POLYMER)
858
859
860
861
862
863
864
865
866
867
868
869
870
871
            {
                if (!restore)
                {
                    SECTORFLD(i,stat, cf) |= 128;
                    opicnum[cf][i] |= 0x8000;
                }
                else
                {
                    SECTORFLD(i,stat, cf) &= ~128;
                    SECTORFLD(i,picnum, cf) &= 0x7fff;
                    opicnum[cf][i] = 0;
                }
            }
#endif