Subversion Repositories eduke32

Rev

Rev 8088 | Rev 8109 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
5 Plagman 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
2456 hendricks2 6
// by Jonathon Fowler (jf@jonof.id.au)
7139 hendricks2 7
// by the EDuke32 team (development@voidpoint.com)
5 Plagman 8
 
7186 terminx 9
#define engine_c_
5 Plagman 10
 
7186 terminx 11
#include "a.h"
12
#include "baselayer.h"
5 Plagman 13
#include "build.h"
14
#include "cache1d.h"
7186 terminx 15
#include "colmatch.h"
16
#include "compat.h"
5 Plagman 17
#include "crc32.h"
7186 terminx 18
#include "editor.h"
19
#include "engine_priv.h"
4316 hendricks2 20
#include "lz4.h"
7186 terminx 21
#include "osd.h"
22
#include "palette.h"
23
#include "pragmas.h"
1155 terminx 24
#include "scriptfile.h"
7186 terminx 25
#include "softsurface.h"
5 Plagman 26
 
1820 terminx 27
#ifdef USE_OPENGL
6656 pogokeen 28
# include "glad/glad.h"
6919 pogokeen 29
# include "glsurface.h"
7186 terminx 30
# include "hightile.h"
2060 hendricks2 31
# include "mdsprite.h"
32
# ifdef POLYMER
33
#  include "polymer.h"
1173 terminx 34
# endif
35
# include "polymost.h"
5 Plagman 36
#endif
37
 
3733 helixhorne 38
#ifdef LUNATIC
39
# include "lunatic.h"
40
L_State g_engState;
41
#endif
42
 
7359 hendricks2 43
#include "vfs.h"
44
 
8094 hendricks2 45
#include "communityapi.h"
46
 
4960 helixhorne 47
//////////
48
// Compilation switches for optional/extended engine features
49
 
4606 terminx 50
#if !defined(__arm__) && !defined(GEKKO)
4960 helixhorne 51
# define HIGH_PRECISION_SPRITE
4606 terminx 52
#endif
53
 
4960 helixhorne 54
#if !defined EDUKE32_TOUCH_DEVICES && !defined GEKKO && !defined __OPENDINGUX__
55
// Handle absolute z difference of floor/ceiling to camera >= 1<<24.
5017 helixhorne 56
// Also: higher precision view-relative x and y for drawvox().
4960 helixhorne 57
# define CLASSIC_Z_DIFF_64
58
#endif
59
 
3311 helixhorne 60
#define MULTI_COLUMN_VLINE
3310 helixhorne 61
//#define DEBUG_TILESIZY_512
3777 helixhorne 62
//#define DEBUG_TILEOFFSETS
4960 helixhorne 63
//////////
3310 helixhorne 64
 
3932 helixhorne 65
#ifdef LUNATIC
66
# if !defined DEBUG_MAIN_ARRAYS
67
LUNATIC_EXTERN const int32_t engine_main_arrays_are_static = 0;  // for Lunatic
68
# else
69
LUNATIC_EXTERN const int32_t engine_main_arrays_are_static = 1;
70
# endif
2270 helixhorne 71
 
2668 helixhorne 72
#if MAXSECTORS==MAXSECTORSV8
3932 helixhorne 73
LUNATIC_EXTERN const int32_t engine_v8 = 1;
2668 helixhorne 74
#else
3932 helixhorne 75
LUNATIC_EXTERN const int32_t engine_v8 = 0;
2668 helixhorne 76
#endif
4315 hendricks2 77
#endif
2668 helixhorne 78
 
3349 terminx 79
#ifdef DEBUGGINGAIDS
1702 plagman 80
float debug1, debug2;
3349 terminx 81
#endif
1702 plagman 82
 
3841 helixhorne 83
int32_t mapversion=7; // JBF 20040211: default mapversion to 7
3911 helixhorne 84
int32_t g_loadedMapVersion = -1;  // -1: none (e.g. started new)
3841 helixhorne 85
 
86
static int32_t get_mapversion(void);
87
 
3926 helixhorne 88
// Handle nonpow2-ysize walls the old way?
7606 terminx 89
static FORCE_INLINE int32_t oldnonpow2(void)
3841 helixhorne 90
{
91
#if !defined CLASSIC_NONPOW2_YSIZE_WALLS
92
    return 1;
93
#else
3926 helixhorne 94
    return (g_loadedMapVersion < 10);
3841 helixhorne 95
#endif
96
}
97
 
6651 hendricks2 98
uint8_t globalr = 255, globalg = 255, globalb = 255;
99
 
5211 hendricks2 100
int16_t pskybits_override = -1;
101
 
2079 helixhorne 102
//void loadvoxel(int32_t voxindex) { UNREFERENCED_PARAMATER(voxindex); }
2266 helixhorne 103
int16_t tiletovox[MAXTILES];
1205 terminx 104
int32_t usevoxels = 1;
4836 helixhorne 105
#ifdef USE_OPENGL
7961 hendricks2 106
static char *voxfilenames[MAXVOXELS];
4836 helixhorne 107
#endif
7961 hendricks2 108
char g_haveVoxels;
2079 helixhorne 109
//#define kloadvoxel loadvoxel
5 Plagman 110
 
1908 helixhorne 111
int32_t novoxmips = 1;
5 Plagman 112
 
109 terminx 113
//These variables need to be copied into BUILD
5 Plagman 114
#define MAXXSIZ 256
115
#define MAXYSIZ 256
116
#define MAXZSIZ 255
117
#define MAXVOXMIPS 5
4881 helixhorne 118
#ifdef EDUKE32_TOUCH_DEVICES
119
# define DISTRECIPSIZ (65536+256)
120
#else
121
# define DISTRECIPSIZ 131072
122
#endif
4555 hendricks2 123
intptr_t voxoff[MAXVOXELS][MAXVOXMIPS]; // used in KenBuild
2463 helixhorne 124
static char voxlock[MAXVOXELS][MAXVOXMIPS];
1205 terminx 125
int32_t voxscale[MAXVOXELS];
5 Plagman 126
 
1205 terminx 127
static int32_t ggxinc[MAXXSIZ+1], ggyinc[MAXXSIZ+1];
4658 terminx 128
static int32_t lowrecip[1024], nytooclose;
4881 helixhorne 129
static const int32_t nytoofar = DISTRECIPSIZ*16384ull - 1048576;
4695 terminx 130
static uint32_t *distrecip;
7866 terminx 131
#define DISTRECIPCACHESIZE 3
132
static struct {
133
    uint32_t *distrecip;
134
    int32_t xdimen;
135
    int32_t age;
136
} distrecipcache[DISTRECIPCACHESIZE];
137
static int32_t distrecipagecnt = 0;
5 Plagman 138
 
2701 helixhorne 139
static int32_t *lookups = NULL;
6229 terminx 140
static int32_t beforedrawrooms = 1;
5 Plagman 141
 
7729 pogokeen 142
int32_t benchmarkScreenshot = 0;
143
 
1205 terminx 144
static int32_t oxdimen = -1, oviewingrange = -1, oxyaspect = -1;
5 Plagman 145
 
1712 helixhorne 146
// r_usenewaspect is the cvar, newaspect_enable to trigger the new behaviour in the code
1957 helixhorne 147
int32_t r_usenewaspect = 1, newaspect_enable=0;
2959 helixhorne 148
uint32_t r_screenxy = 0;
1712 helixhorne 149
 
7755 terminx 150
int32_t r_fpgrouscan = 1;
8063 terminx 151
int32_t r_displayindex = 0;
152
int32_t r_borderless = 2;
5056 hendricks2 153
int32_t globalflags;
154
 
6828 terminx 155
float g_videoGamma = DEFAULT_GAMMA;
156
float g_videoContrast = DEFAULT_CONTRAST;
157
float g_videoBrightness = DEFAULT_BRIGHTNESS;
877 terminx 158
 
109 terminx 159
//Textured Map variables
5 Plagman 160
static char globalpolytype;
4695 terminx 161
static int16_t **dotp1, **dotp2;
5 Plagman 162
 
1205 terminx 163
static int8_t tempbuf[MAXWALLS];
5 Plagman 164
 
3172 helixhorne 165
// referenced from asm
4324 hendricks2 166
#if !defined(NOASM) && defined __cplusplus
167
extern "C" {
168
#endif
1205 terminx 169
int32_t ebpbak, espbak;
3172 helixhorne 170
int32_t reciptable[2048], fpuasm;
171
intptr_t asm1, asm2, asm3, asm4, palookupoffse[4];
172
uint32_t vplce[4];
173
int32_t vince[4];
174
intptr_t bufplce[4];
175
int32_t globaltilesizy;
176
int32_t globalx1, globaly2, globalx3, globaly3;
4324 hendricks2 177
#if !defined(NOASM) && defined __cplusplus
4766 hendricks2 178
}
4324 hendricks2 179
#endif
3172 helixhorne 180
 
7718 terminx 181
int32_t sloptable[SLOPTABLESIZ];
1969 helixhorne 182
static intptr_t slopalookup[16384];    // was 2048
5 Plagman 183
 
2990 helixhorne 184
static int32_t no_radarang2 = 0;
7713 terminx 185
static int16_t radarang[1280];
186
static int32_t qradarang[10240], *radarang2;
7146 terminx 187
const char ATTRIBUTE((used)) pow2char_[8] = {1,2,4,8,16,32,64,128};
3116 hendricks2 188
 
189
uint16_t ATTRIBUTE((used)) sqrtable[4096], ATTRIBUTE((used)) shlookup[4096+256];
190
 
5 Plagman 191
char britable[16][256]; // JBF 20040207: full 8bit precision
192
 
1173 terminx 193
extern char textfont[2048], smalltextfont[2048];
194
 
5 Plagman 195
static char kensmessage[128];
1799 helixhorne 196
const char *engineerrstr = "No error";
5 Plagman 197
 
1544 terminx 198
int32_t showfirstwall=0;
4007 helixhorne 199
int32_t showheightindicators=1;
1544 terminx 200
int32_t circlewall=-1;
201
 
6832 terminx 202
static void classicScanSector(int16_t startsectnum);
2513 helixhorne 203
static void draw_rainbow_background(void);
1874 helixhorne 204
 
1843 helixhorne 205
int16_t editstatus = 0;
6724 terminx 206
static fix16_t global100horiz;  // (-100..300)-scale horiz (the one passed to drawrooms)
1830 helixhorne 207
 
7591 terminx 208
// adapted from build.c
8048 terminx 209
static void getclosestpointonwall_internal(vec2_t const p, int32_t const dawall, vec2_t *const closest)
7591 terminx 210
{
7697 terminx 211
    vec2_t const w  = wall[dawall].pos;
212
    vec2_t const w2 = wall[wall[dawall].point2].pos;
7591 terminx 213
    vec2_t const d  = { w2.x - w.x, w2.y - w.y };
1843 helixhorne 214
 
7591 terminx 215
    int64_t i = d.x * ((int64_t)p.x - w.x) + d.y * ((int64_t)p.y - w.y);
216
 
217
    if (i <= 0)
218
    {
219
        *closest = w;
220
        return;
221
    }
222
 
223
    int64_t const j = (int64_t)d.x * d.x + (int64_t)d.y * d.y;
224
 
225
    if (i >= j)
226
    {
227
        *closest = w2;
228
        return;
229
    }
230
 
231
    i = tabledivide64((i << 15), j) << 15;
232
 
233
    *closest = { (int32_t)(w.x + ((d.x * i) >> 30)), (int32_t)(w.y + ((d.y * i) >> 30)) };
234
}
235
 
1816 helixhorne 236
////////// YAX //////////
1843 helixhorne 237
 
1899 helixhorne 238
int32_t numgraysects = 0;
7594 terminx 239
uint8_t graysectbitmap[(MAXSECTORS+7)>>3];
240
uint8_t graywallbitmap[(MAXWALLS+7)>>3];
1928 helixhorne 241
int32_t autogray = 0, showinnergray = 1;
1877 helixhorne 242
 
2740 helixhorne 243
//#define YAX_DEBUG_YMOSTS
244
 
2026 helixhorne 245
#ifdef YAX_DEBUG
3935 helixhorne 246
// XXX: This could be replaced with the use of gethiticks().
3934 helixhorne 247
double u64tickspersec;
2026 helixhorne 248
#endif
1877 helixhorne 249
#ifdef ENGINE_SCREENSHOT_DEBUG
250
int32_t engine_screenshot = 0;
251
#endif
252
 
3623 helixhorne 253
int32_t get_alwaysshowgray(void)
254
{
255
    return showinnergray || !(editorzrange[0]==INT32_MIN && editorzrange[1]==INT32_MAX);
256
}
257
 
1877 helixhorne 258
void yax_updategrays(int32_t posze)
259
{
5413 helixhorne 260
    int32_t i, j;
1890 helixhorne 261
#ifdef YAX_ENABLE
262
    int32_t mingoodz=INT32_MAX, maxgoodz=INT32_MIN;
263
#else
1877 helixhorne 264
    UNREFERENCED_PARAMETER(posze);
265
#endif
1890 helixhorne 266
 
1877 helixhorne 267
    Bmemset(graysectbitmap, 0, sizeof(graysectbitmap));
268
    Bmemset(graywallbitmap, 0, sizeof(graywallbitmap));
269
 
270
    for (i=0; i<numsectors; i++)
271
    {
1843 helixhorne 272
#ifdef YAX_ENABLE
1877 helixhorne 273
        int16_t cb, fb;
5413 helixhorne 274
        yax_getbunches(i, &cb, &fb);
1877 helixhorne 275
 
5413 helixhorne 276
        // Update grayouts due to TROR, has to be --v--       half-open      --v--
277
        // because only one level should ever be    v                          v
278
        // active.                                  v                          v
279
        int32_t keep = ((cb<0 || sector[i].ceilingz < posze) && (fb<0 || posze <= sector[i].floorz));
1890 helixhorne 280
        if (autogray && (cb>=0 || fb>=0) && (sector[i].ceilingz <= posze && posze <= sector[i].floorz))
281
        {
7078 terminx 282
            mingoodz = min(mingoodz, TrackerCast(sector[i].ceilingz));
283
            maxgoodz = max(maxgoodz, TrackerCast(sector[i].floorz));
1890 helixhorne 284
        }
1877 helixhorne 285
#endif
1886 helixhorne 286
        // update grayouts due to editorzrange
5413 helixhorne 287
        keep &= (sector[i].ceilingz >= editorzrange[0] && sector[i].floorz <= editorzrange[1]);
1877 helixhorne 288
 
5413 helixhorne 289
        if (!keep)  // outside bounds, gray out!
7876 terminx 290
            graysectbitmap[i>>3] |= pow2char[i&7];
1890 helixhorne 291
    }
292
 
293
#ifdef YAX_ENABLE
294
    if (autogray && mingoodz<=maxgoodz)
295
    {
296
        for (i=0; i<numsectors; i++)
297
            if (!(mingoodz <= sector[i].ceilingz && sector[i].floorz <= maxgoodz))
7876 terminx 298
                graysectbitmap[i>>3] |= pow2char[i&7];
1890 helixhorne 299
    }
300
#endif
301
 
1899 helixhorne 302
    numgraysects = 0;
1890 helixhorne 303
    for (i=0; i<numsectors; i++)
304
    {
7876 terminx 305
        if (graysectbitmap[i>>3]&pow2char[i&7])
1899 helixhorne 306
        {
307
            numgraysects++;
1877 helixhorne 308
            for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
7876 terminx 309
                graywallbitmap[j>>3] |= pow2char[j&7];
1899 helixhorne 310
        }
1877 helixhorne 311
    }
312
}
313
 
314
 
2204 helixhorne 315
#if !defined YAX_ENABLE
316
# warning Non-TROR builds are supported only for debugging. Expect savegame breakage etc...
317
#endif
318
 
1877 helixhorne 319
#ifdef YAX_ENABLE
1843 helixhorne 320
// all references to floor/ceiling bunchnums should be through the
321
// get/set functions!
322
 
2002 helixhorne 323
int32_t g_nodraw = 0;
1892 helixhorne 324
int32_t scansector_retfast = 0;
7400 terminx 325
int32_t scansector_collectsprites = 1;
2024 helixhorne 326
int32_t yax_globalcf = -1, yax_nomaskpass=0, yax_nomaskdidit;  // engine internal
327
int32_t r_tror_nomaskpass = 1;  // cvar
2018 helixhorne 328
int32_t yax_globallev = YAX_MAXDRAWS;
329
int32_t yax_globalbunch = -1;
7400 terminx 330
int32_t yax_polymostclearzbuffer = 1;
1874 helixhorne 331
 
1877 helixhorne 332
// duplicated tsprites
333
//  [i]:
334
//   i==MAXDRAWS: base level
335
//   i<MAXDRAWS: MAXDRAWS-i-1 is level towards ceiling
336
//   i>MAXDRAWS: i-MAXDRAWS-1 is level towards floor
337
static int16_t yax_spritesortcnt[1 + 2*YAX_MAXDRAWS];
2046 helixhorne 338
static uint16_t yax_tsprite[1 + 2*YAX_MAXDRAWS][MAXSPRITESONSCREEN];
339
static uint8_t yax_tsprfrombunch[1 + 2*YAX_MAXDRAWS][MAXSPRITESONSCREEN];
1877 helixhorne 340
 
2024 helixhorne 341
// drawn sectors
7594 terminx 342
uint8_t yax_gotsector[(MAXSECTORS+7)>>3];  // engine internal
2024 helixhorne 343
 
3658 helixhorne 344
# if !defined NEW_MAP_FORMAT
345
// Game-time YAX data structures, V7-V9 map formats.
1882 helixhorne 346
int16_t yax_bunchnum[MAXSECTORS][2];
347
int16_t yax_nextwall[MAXWALLS][2];
1843 helixhorne 348
 
6076 hendricks2 349
static FORCE_INLINE int32_t yax_islockededge(int32_t line, int32_t cf)
1865 helixhorne 350
{
351
    return !!(wall[line].cstat&(YAX_NEXTWALLBIT(cf)));
352
}
353
 
2349 helixhorne 354
#define YAX_PTRBUNCHNUM(Ptr, Sect, Cf) (*(&Ptr[Sect].ceilingxpanning + 8*Cf))
355
#define YAX_BUNCHNUM(Sect, Cf) YAX_PTRBUNCHNUM(sector, Sect, Cf)
1865 helixhorne 356
 
357
//// bunch getters/setters
1816 helixhorne 358
int16_t yax_getbunch(int16_t i, int16_t cf)
359
{
1843 helixhorne 360
    if (editstatus==0)
361
        return yax_bunchnum[i][cf];
362
 
5800 terminx 363
    return (*(&sector[i].ceilingstat + cf) & YAX_BIT) ? YAX_BUNCHNUM(i, cf) : -1;
1816 helixhorne 364
}
3658 helixhorne 365
# else
366
#  define YAX_PTRBUNCHNUM(Ptr, Sect, Cf) (*((Cf) ? &(Ptr)[Sect].floorbunch : &(Ptr)[Sect].ceilingbunch))
367
#  define YAX_BUNCHNUM(Sect, Cf) YAX_PTRBUNCHNUM(sector, Sect, Cf)
1843 helixhorne 368
 
3658 helixhorne 369
#  if !defined NEW_MAP_FORMAT
6076 hendricks2 370
static FORCE_INLINE int32_t yax_islockededge(int32_t line, int32_t cf)
3658 helixhorne 371
{
372
    return (yax_getnextwall(line, cf) >= 0);
373
}
374
#  endif
375
# endif
376
 
2136 helixhorne 377
// bunchnum: -1: also clear yax-nextwalls (forward and reverse)
378
//           -2: don't clear reverse yax-nextwalls
379
//           -3: don't clear either forward or reverse yax-nextwalls
1816 helixhorne 380
void yax_setbunch(int16_t i, int16_t cf, int16_t bunchnum)
381
{
1843 helixhorne 382
    if (editstatus==0)
1865 helixhorne 383
    {
3658 helixhorne 384
#ifdef NEW_MAP_FORMAT
385
        YAX_BUNCHNUM(i, cf) = bunchnum;
386
#else
1843 helixhorne 387
        yax_bunchnum[i][cf] = bunchnum;
3658 helixhorne 388
#endif
1865 helixhorne 389
        return;
390
    }
1843 helixhorne 391
 
2136 helixhorne 392
    if (bunchnum < 0)
1816 helixhorne 393
    {
2136 helixhorne 394
        if (bunchnum > -3)
1869 helixhorne 395
        {
2136 helixhorne 396
            // TODO: for in-game too?
5829 terminx 397
            for (bssize_t ynw, j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
1892 helixhorne 398
            {
2136 helixhorne 399
                ynw = yax_getnextwall(j, cf);
400
                if (ynw >= 0)
401
                {
402
                    if (bunchnum > -2)
403
                        yax_setnextwall(ynw, !cf, -1);
404
                    yax_setnextwall(j, cf, -1);
405
                }
1892 helixhorne 406
            }
1869 helixhorne 407
        }
408
 
3658 helixhorne 409
#if !defined NEW_MAP_FORMAT
1816 helixhorne 410
        *(&sector[i].ceilingstat + cf) &= ~YAX_BIT;
4275 helixhorne 411
        // NOTE: Don't reset xpanning-as-index, since we can be called from
412
        // e.g. Mapster32's "Inner loop made into new sector" functionality.
413
//        YAX_BUNCHNUM(i, cf) = 0;
3841 helixhorne 414
#else
415
        YAX_BUNCHNUM(i, cf) = -1;
3658 helixhorne 416
#endif
1816 helixhorne 417
        return;
418
    }
419
 
3658 helixhorne 420
#if !defined NEW_MAP_FORMAT
1816 helixhorne 421
    *(&sector[i].ceilingstat + cf) |= YAX_BIT;
3658 helixhorne 422
#endif
1816 helixhorne 423
    YAX_BUNCHNUM(i, cf) = bunchnum;
424
}
425
 
1843 helixhorne 426
void yax_setbunches(int16_t i, int16_t cb, int16_t fb)
427
{
428
    yax_setbunch(i, YAX_CEILING, cb);
429
    yax_setbunch(i, YAX_FLOOR, fb);
430
}
1816 helixhorne 431
 
3658 helixhorne 432
# if !defined NEW_MAP_FORMAT
1865 helixhorne 433
//// nextwall getters/setters
434
int16_t yax_getnextwall(int16_t wal, int16_t cf)
435
{
436
    if (editstatus==0)
437
        return yax_nextwall[wal][cf];
438
 
5800 terminx 439
    return yax_islockededge(wal, cf) ? YAX_NEXTWALL(wal, cf) : -1;
1865 helixhorne 440
}
441
 
442
// unchecked!
443
void yax_setnextwall(int16_t wal, int16_t cf, int16_t thenextwall)
444
{
445
    if (editstatus==0)
446
    {
447
        yax_nextwall[wal][cf] = thenextwall;
448
        return;
449
    }
450
 
451
    if (thenextwall >= 0)
1866 helixhorne 452
    {
1865 helixhorne 453
        wall[wal].cstat |= YAX_NEXTWALLBIT(cf);
1866 helixhorne 454
        YAX_NEXTWALL(wal, cf) = thenextwall;
455
    }
1865 helixhorne 456
    else
1866 helixhorne 457
    {
1865 helixhorne 458
        wall[wal].cstat &= ~YAX_NEXTWALLBIT(cf);
2965 helixhorne 459
        YAX_NEXTWALL(wal, cf) = YAX_NEXTWALLDEFAULT(cf);
1866 helixhorne 460
    }
1865 helixhorne 461
}
3658 helixhorne 462
# endif
1865 helixhorne 463
 
2018 helixhorne 464
// make one step in the vertical direction, and if the wall we arrive at
465
// is red, return its nextsector.
466
int16_t yax_vnextsec(int16_t line, int16_t cf)
467
{
4984 terminx 468
    int16_t const ynw = yax_getnextwall(line, cf);
469
    return (ynw < 0) ? -1 : wall[ynw].nextsector;
2018 helixhorne 470
}
471
 
472
 
1886 helixhorne 473
//// in-struct --> array transfer (only resetstat==0); list construction
1882 helixhorne 474
// resetstat:  0: reset and read data from structs and construct linked lists etc.
475
//             1: only reset
476
//             2: read data from game-time arrays and construct linked lists etc.
477
void yax_update(int32_t resetstat)
1854 helixhorne 478
{
3658 helixhorne 479
    int32_t i;
480
#if !defined NEW_MAP_FORMAT
481
    int32_t j;
482
    const int32_t oeditstatus=editstatus;
483
#endif
484
    int16_t cb, fb;
1854 helixhorne 485
 
1886 helixhorne 486
    if (resetstat != 2)
487
        numyaxbunches = 0;
1854 helixhorne 488
 
489
    for (i=0; i<MAXSECTORS; i++)
490
    {
3658 helixhorne 491
#if !defined NEW_MAP_FORMAT
1882 helixhorne 492
        if (resetstat != 2 || i>=numsectors)
493
            yax_bunchnum[i][0] = yax_bunchnum[i][1] = -1;
3658 helixhorne 494
#endif
1854 helixhorne 495
        nextsectbunch[0][i] = nextsectbunch[1][i] = -1;
496
    }
497
    for (i=0; i<YAX_MAXBUNCHES; i++)
498
        headsectbunch[0][i] = headsectbunch[1][i] = -1;
3658 helixhorne 499
#if !defined NEW_MAP_FORMAT
1865 helixhorne 500
    for (i=0; i<MAXWALLS; i++)
1882 helixhorne 501
        if (resetstat != 2 || i>=numwalls)
502
            yax_nextwall[i][0] = yax_nextwall[i][1] = -1;
3658 helixhorne 503
#endif
1854 helixhorne 504
 
1882 helixhorne 505
    if (resetstat==1)
1854 helixhorne 506
        return;
507
 
3658 helixhorne 508
    // Constuct singly linked list of sectors-of-bunch.
1886 helixhorne 509
 
3658 helixhorne 510
#if !defined NEW_MAP_FORMAT
511
    // Read bunchnums directly from the sector struct in yax_[gs]etbunch{es}!
2349 helixhorne 512
    editstatus = (resetstat==0);
3658 helixhorne 513
    // NOTE: Use oeditstatus to check for in-gamedness from here on!
514
#endif
2349 helixhorne 515
 
1886 helixhorne 516
    if (resetstat==0)
517
    {
518
        // make bunchnums consecutive
519
        uint8_t *const havebunch = (uint8_t *)tempbuf;
7806 terminx 520
        uint8_t *const bunchmap = havebunch + ((YAX_MAXBUNCHES+7)>>3);
1886 helixhorne 521
        int32_t dasub = 0;
522
 
7806 terminx 523
        Bmemset(havebunch, 0, (YAX_MAXBUNCHES+7)>>3);
1886 helixhorne 524
        for (i=0; i<numsectors; i++)
525
        {
526
            yax_getbunches(i, &cb, &fb);
527
            if (cb>=0)
7876 terminx 528
                havebunch[cb>>3] |= pow2char[cb&7];
1886 helixhorne 529
            if (fb>=0)
7876 terminx 530
                havebunch[fb>>3] |= pow2char[fb&7];
1886 helixhorne 531
        }
532
 
533
        for (i=0; i<YAX_MAXBUNCHES; i++)
534
        {
7876 terminx 535
            if ((havebunch[i>>3]&pow2char[i&7])==0)
1886 helixhorne 536
            {
537
                bunchmap[i] = 255;
538
                dasub++;
539
                continue;
540
            }
541
 
542
            bunchmap[i] = i-dasub;
543
        }
544
 
545
        for (i=0; i<numsectors; i++)
546
        {
547
            yax_getbunches(i, &cb, &fb);
548
            if (cb>=0)
549
                yax_setbunch(i, YAX_CEILING, bunchmap[cb]);
2068 helixhorne 550
            if (fb>=0)
1886 helixhorne 551
                yax_setbunch(i, YAX_FLOOR, bunchmap[fb]);
552
        }
553
    }
554
 
3658 helixhorne 555
    // In-struct --> array transfer (resetstat==0 and !defined NEW_MAP_FORMAT)
556
    // and list construction.
1854 helixhorne 557
    for (i=numsectors-1; i>=0; i--)
558
    {
559
        yax_getbunches(i, &cb, &fb);
3658 helixhorne 560
#if !defined NEW_MAP_FORMAT
1882 helixhorne 561
        if (resetstat==0)
562
        {
563
            yax_bunchnum[i][0] = cb;
564
            yax_bunchnum[i][1] = fb;
565
        }
3658 helixhorne 566
#endif
1854 helixhorne 567
 
568
        if (cb >= 0)
569
        {
3658 helixhorne 570
#if !defined NEW_MAP_FORMAT
1882 helixhorne 571
            if (resetstat==0)
572
                for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
573
                {
574
                    if (yax_islockededge(j,YAX_CEILING))
2349 helixhorne 575
                    {
1882 helixhorne 576
                        yax_nextwall[j][0] = YAX_NEXTWALL(j,0);
2349 helixhorne 577
                        if (oeditstatus==0)
578
                            YAX_NEXTWALL(j,0) = 0;  // reset lotag!
579
                    }
1882 helixhorne 580
                }
3658 helixhorne 581
#endif
1854 helixhorne 582
            if (headsectbunch[0][cb] == -1)
583
            {
584
                headsectbunch[0][cb] = i;
585
                // not duplicated in floors, since every extended ceiling
586
                // must have a corresponding floor:
1882 helixhorne 587
                if (resetstat==0)
588
                    numyaxbunches++;
1854 helixhorne 589
            }
590
            else
591
            {
3658 helixhorne 592
                int32_t tmpsect = headsectbunch[0][cb];
1854 helixhorne 593
                headsectbunch[0][cb] = i;
594
                nextsectbunch[0][i] = tmpsect;
595
            }
596
        }
597
 
598
        if (fb >= 0)
599
        {
3658 helixhorne 600
#if !defined NEW_MAP_FORMAT
1882 helixhorne 601
            if (resetstat==0)
602
                for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
603
                {
604
                    if (yax_islockededge(j,YAX_FLOOR))
2349 helixhorne 605
                    {
1882 helixhorne 606
                        yax_nextwall[j][1] = YAX_NEXTWALL(j,1);
2349 helixhorne 607
                        if (oeditstatus==0)
608
                            YAX_NEXTWALL(j,1) = -1;  // reset extra!
609
                    }
1882 helixhorne 610
                }
3658 helixhorne 611
#endif
1854 helixhorne 612
            if (headsectbunch[1][fb] == -1)
613
                headsectbunch[1][fb] = i;
614
            else
615
            {
3658 helixhorne 616
                int32_t tmpsect = headsectbunch[1][fb];
1854 helixhorne 617
                headsectbunch[1][fb] = i;
618
                nextsectbunch[1][i] = tmpsect;
619
            }
620
        }
621
    }
2349 helixhorne 622
 
3658 helixhorne 623
#if !defined NEW_MAP_FORMAT
1854 helixhorne 624
    editstatus = oeditstatus;
3841 helixhorne 625
#else
4368 helixhorne 626
    mapversion = get_mapversion();
3658 helixhorne 627
#endif
1854 helixhorne 628
}
1869 helixhorne 629
 
3039 helixhorne 630
int32_t yax_getneighborsect(int32_t x, int32_t y, int32_t sectnum, int32_t cf)
1869 helixhorne 631
{
632
    int16_t bunchnum = yax_getbunch(sectnum, cf);
633
 
634
    if (bunchnum < 0)
635
        return -1;
636
 
5829 terminx 637
    for (bssize_t SECTORS_OF_BUNCH(bunchnum, !cf, i))
1869 helixhorne 638
        if (inside(x, y, i)==1)
639
            return i;
640
 
641
    return -1;
642
}
643
 
1886 helixhorne 644
// indexed as a list:
645
static int16_t bunches[2][YAX_MAXBUNCHES];
646
// indexed with bunchnums directly:
647
static int16_t bunchsec[YAX_MAXBUNCHES], bunchdist[YAX_MAXBUNCHES];
1882 helixhorne 648
 
1886 helixhorne 649
static int32_t ymostallocsize = 0;  // numyaxbunches*xdimen (no sizeof(int16_t) here!)
650
static int16_t *yumost=NULL, *ydmost=NULL;  // used as if [numyaxbunches][xdimen]
7806 terminx 651
uint8_t haveymost[(YAX_MAXBUNCHES+7)>>3];
1886 helixhorne 652
 
653
static inline int32_t yax_walldist(int32_t w)
654
{
7591 terminx 655
    vec2_t closest;
656
    getclosestpointonwall_internal({ globalposx, globalposy }, w, &closest);
657
    return klabs(closest.x-globalposx) + klabs(closest.y-globalposy);
1869 helixhorne 658
}
659
 
1886 helixhorne 660
// calculate distances to bunches and best start-drawing sectors
661
static void yax_scanbunches(int32_t bbeg, int32_t numhere, const uint8_t *lastgotsector)
1869 helixhorne 662
{
1887 helixhorne 663
    int32_t bnchcnt, bunchnum, j, k;
1886 helixhorne 664
    int32_t startwall, endwall;
1869 helixhorne 665
 
1887 helixhorne 666
    UNREFERENCED_PARAMETER(lastgotsector);
667
 
1886 helixhorne 668
    scansector_retfast = 1;
669
    scansector_collectsprites = 0;
1882 helixhorne 670
 
1886 helixhorne 671
    for (bnchcnt=bbeg; bnchcnt<bbeg+numhere; bnchcnt++)
1877 helixhorne 672
    {
1886 helixhorne 673
        int32_t walldist, bestsec=-1;
674
        int32_t bestwalldist=INT32_MAX, bestbestdist=INT32_MAX;
1869 helixhorne 675
 
1886 helixhorne 676
        bunchnum = bunches[yax_globalcf][bnchcnt];
677
 
678
        for (SECTORS_OF_BUNCH(bunchnum,!yax_globalcf, k))
1877 helixhorne 679
        {
1886 helixhorne 680
            int32_t checkthisec = 0;
681
 
682
            if (inside(globalposx, globalposy, k)==1)
683
            {
684
                bestsec = k;
685
                bestbestdist = 0;
686
                break;
687
            }
688
 
1882 helixhorne 689
            startwall = sector[k].wallptr;
690
            endwall = startwall+sector[k].wallnum;
691
 
692
            for (j=startwall; j<endwall; j++)
693
            {
694
/*
1886 helixhorne 695
                if ((w=yax_getnextwall(j,!yax_globalcf))>=0)
696
                    if ((ns=wall[w].nextsector)>=0)
7876 terminx 697
                        if ((lastgotsector[ns>>3]&pow2char[ns&7])==0)
1886 helixhorne 698
                            continue;
1882 helixhorne 699
*/
700
                walldist = yax_walldist(j);
701
                if (walldist < bestwalldist)
702
                {
1886 helixhorne 703
                    checkthisec = 1;
1882 helixhorne 704
                    bestwalldist = walldist;
705
                }
706
            }
707
 
1886 helixhorne 708
            if (checkthisec)
1882 helixhorne 709
            {
710
                numscans = numbunches = 0;
6829 terminx 711
                if (videoGetRenderMode() == REND_CLASSIC)
6832 terminx 712
                    classicScanSector(k);
1892 helixhorne 713
#ifdef USE_OPENGL
714
                else
715
                    polymost_scansector(k);
716
#endif
1882 helixhorne 717
                if (numbunches > 0)
1886 helixhorne 718
                {
1882 helixhorne 719
                    bestsec = k;
1886 helixhorne 720
                    bestbestdist = bestwalldist;
721
                }
1882 helixhorne 722
            }
1877 helixhorne 723
        }
1869 helixhorne 724
 
1886 helixhorne 725
        bunchsec[bunchnum] = bestsec;
726
        bunchdist[bunchnum] = bestbestdist;
727
    }
1882 helixhorne 728
 
1886 helixhorne 729
    scansector_collectsprites = 1;
730
    scansector_retfast = 0;
1877 helixhorne 731
}
1869 helixhorne 732
 
4068 helixhorne 733
static int yax_cmpbunches(const void *b1, const void *b2)
1886 helixhorne 734
{
5174 hendricks2 735
    return (bunchdist[B_UNBUF16(b2)] - bunchdist[B_UNBUF16(b1)]);
1886 helixhorne 736
}
737
 
2350 helixhorne 738
 
739
void yax_tweakpicnums(int32_t bunchnum, int32_t cf, int32_t restore)
1877 helixhorne 740
{
2349 helixhorne 741
    // for polymer, this is called before polymer_drawrooms() with restore==0
742
    // and after polymer_drawmasks() with restore==1
743
 
2350 helixhorne 744
    int32_t i, dastat;
1877 helixhorne 745
    static int16_t opicnum[2][MAXSECTORS];
2350 helixhorne 746
#ifdef DEBUGGINGAIDS
747
    static uint8_t expect_restore[2][YAX_MAXBUNCHES];
1869 helixhorne 748
 
2350 helixhorne 749
    // must call this with restore == 0, 1,  0, 1,  0, 1,  ...
2547 helixhorne 750
    Bassert(expect_restore[cf][bunchnum] == restore);
2350 helixhorne 751
    expect_restore[cf][bunchnum] = !expect_restore[cf][bunchnum];
752
#endif
753
 
1886 helixhorne 754
    for (SECTORS_OF_BUNCH(bunchnum, cf, i))
1890 helixhorne 755
    {
1895 helixhorne 756
        dastat = (SECTORFLD(i,stat, cf)&(128+256));
2066 helixhorne 757
 
2349 helixhorne 758
        // only consider non-masked ceilings/floors
2066 helixhorne 759
        if (dastat==0 || (restore==1 && opicnum[cf][i]&0x8000))
1877 helixhorne 760
        {
761
            if (!restore)
762
            {
763
                opicnum[cf][i] = SECTORFLD(i,picnum, cf);
764
                if (editstatus && showinvisibility)
1895 helixhorne 765
                    SECTORFLD(i,picnum, cf) = MAXTILES-1;
2066 helixhorne 766
                else //if ((dastat&(128+256))==0)
1877 helixhorne 767
                    SECTORFLD(i,picnum, cf) = 13; //FOF;
768
            }
769
            else
770
            {
771
                SECTORFLD(i,picnum, cf) = opicnum[cf][i];
772
            }
2066 helixhorne 773
#ifdef POLYMER
774
            // will be called only in editor
6829 terminx 775
            if (videoGetRenderMode() == REND_POLYMER)
2066 helixhorne 776
            {
777
                if (!restore)
778
                {
779
                    SECTORFLD(i,stat, cf) |= 128;
780
                    opicnum[cf][i] |= 0x8000;
781
                }
782
                else
783
                {
784
                    SECTORFLD(i,stat, cf) &= ~128;
785
                    SECTORFLD(i,picnum, cf) &= 0x7fff;
786
                    opicnum[cf][i] = 0;
787
                }
788
            }
789
#endif
1877 helixhorne 790
        }
1890 helixhorne 791
    }
1877 helixhorne 792
}
1869 helixhorne 793
 
2046 helixhorne 794
static void yax_copytsprites()
1877 helixhorne 795
{
2046 helixhorne 796
    int32_t i, spritenum, gotthrough, sectnum;
1877 helixhorne 797
    int32_t sortcnt = yax_spritesortcnt[yax_globallev];
7603 terminx 798
    uspriteptr_t spr;
1877 helixhorne 799
 
800
    for (i=0; i<sortcnt; i++)
1869 helixhorne 801
    {
1877 helixhorne 802
        spritenum = yax_tsprite[yax_globallev][i];
1869 helixhorne 803
 
2046 helixhorne 804
        gotthrough = spritenum&(MAXSPRITES|(MAXSPRITES<<1));
805
 
1877 helixhorne 806
        spritenum &= MAXSPRITES-1;
7603 terminx 807
        spr = (uspriteptr_t)&sprite[spritenum];
1877 helixhorne 808
        sectnum = spr->sectnum;
809
 
2046 helixhorne 810
        if (gotthrough == (MAXSPRITES|(MAXSPRITES<<1)))
1869 helixhorne 811
        {
2046 helixhorne 812
            if (yax_globalbunch != yax_tsprfrombunch[yax_globallev][i])
1877 helixhorne 813
                continue;
1869 helixhorne 814
        }
2046 helixhorne 815
        else
816
        {
817
            int32_t cf = -1;
1877 helixhorne 818
 
2046 helixhorne 819
            if (gotthrough == MAXSPRITES)
820
                cf = YAX_CEILING;  // sprite got here through the ceiling of lower sector
821
            else if (gotthrough == (MAXSPRITES<<1))
822
                cf = YAX_FLOOR;  // sprite got here through the floor of upper sector
823
 
824
            if (cf != -1)
825
            {
826
                if ((yax_globallev-YAX_MAXDRAWS)*(-1 + 2*cf) > 0)
827
                    if (yax_getbunch(sectnum, cf) != yax_globalbunch)
828
                        continue;
829
 
3039 helixhorne 830
                sectnum = yax_getneighborsect(spr->x, spr->y, sectnum, cf);
2046 helixhorne 831
                if (sectnum < 0)
832
                    continue;
833
            }
834
        }
835
 
6347 terminx 836
        if (spritesortcnt >= maxspritesonscreen)
1882 helixhorne 837
            break;
838
 
1877 helixhorne 839
        Bmemcpy(&tsprite[spritesortcnt], spr, sizeof(spritetype));
840
        tsprite[spritesortcnt].owner = spritenum;
5400 terminx 841
        tsprite[spritesortcnt].extra = 0;
2046 helixhorne 842
        tsprite[spritesortcnt].sectnum = sectnum;  // potentially tweak sectnum!
1877 helixhorne 843
        spritesortcnt++;
1869 helixhorne 844
    }
1877 helixhorne 845
}
1869 helixhorne 846
 
1892 helixhorne 847
 
1877 helixhorne 848
void yax_preparedrawrooms(void)
849
{
6829 terminx 850
    if (videoGetRenderMode() == REND_POLYMER || numyaxbunches==0)
1877 helixhorne 851
        return;
1869 helixhorne 852
 
1877 helixhorne 853
    g_nodraw = 1;
854
    Bmemset(yax_spritesortcnt, 0, sizeof(yax_spritesortcnt));
1886 helixhorne 855
    Bmemset(haveymost, 0, (numyaxbunches+7)>>3);
856
 
6829 terminx 857
    if (videoGetRenderMode() == REND_CLASSIC && ymostallocsize < xdimen*numyaxbunches)
1886 helixhorne 858
    {
859
        ymostallocsize = xdimen*numyaxbunches;
4491 helixhorne 860
        yumost = (int16_t *)Xrealloc(yumost, ymostallocsize*sizeof(int16_t));
861
        ydmost = (int16_t *)Xrealloc(ydmost, ymostallocsize*sizeof(int16_t));
1886 helixhorne 862
    }
1877 helixhorne 863
}
864
 
2880 helixhorne 865
void yax_drawrooms(void (*SpriteAnimFunc)(int32_t,int32_t,int32_t,int32_t),
866
                   int16_t sectnum, int32_t didmirror, int32_t smoothr)
1877 helixhorne 867
{
7806 terminx 868
    static uint8_t havebunch[(YAX_MAXBUNCHES+7)>>3];
1877 helixhorne 869
 
6724 terminx 870
    const fix16_t horiz = global100horiz;
2880 helixhorne 871
 
2024 helixhorne 872
    int32_t i, j, k, lev, cf, nmp;
1877 helixhorne 873
    int32_t bnchcnt, bnchnum[2] = {0,0}, maxlev[2];
874
    int16_t ourbunch[2] = {-1,-1}, osectnum=sectnum;
875
    int32_t bnchbeg[YAX_MAXDRAWS][2], bnchend[YAX_MAXDRAWS][2];
876
    int32_t bbeg, numhere;
877
 
878
    // original (1st-draw) and accumulated ('per-level') gotsector bitmaps
7594 terminx 879
    static uint8_t ogotsector[(MAXSECTORS+7)>>3], lgotsector[(MAXSECTORS+7)>>3];
1882 helixhorne 880
#ifdef YAX_DEBUG
2026 helixhorne 881
    uint64_t t;
1882 helixhorne 882
#endif
1877 helixhorne 883
 
6829 terminx 884
    if (videoGetRenderMode() == REND_POLYMER || numyaxbunches==0)
1877 helixhorne 885
    {
886
#ifdef ENGINE_SCREENSHOT_DEBUG
887
        engine_screenshot = 0;
888
#endif
889
        return;
890
    }
891
 
892
    // if we're here, there was just a drawrooms() call with g_nodraw=1
893
 
894
    Bmemcpy(ogotsector, gotsector, (numsectors+7)>>3);
895
 
896
    if (sectnum >= 0)
897
        yax_getbunches(sectnum, &ourbunch[0], &ourbunch[1]);
898
    Bmemset(&havebunch, 0, (numyaxbunches+7)>>3);
899
 
900
    // first scan all bunches above, then all below...
1869 helixhorne 901
    for (cf=0; cf<2; cf++)
902
    {
1877 helixhorne 903
        yax_globalcf = cf;
1869 helixhorne 904
 
1877 helixhorne 905
        if (cf==1)
906
        {
907
            sectnum = osectnum;
908
            Bmemcpy(gotsector, ogotsector, (numsectors+7)>>3);
909
        }
1869 helixhorne 910
 
1877 helixhorne 911
        for (lev=0; /*lev<YAX_MAXDRAWS*/; lev++)
1869 helixhorne 912
        {
1877 helixhorne 913
            yax_globallev = YAX_MAXDRAWS + (-1 + 2*cf)*(lev+1);
1869 helixhorne 914
 
1877 helixhorne 915
            bbeg = bnchbeg[lev][cf] = bnchend[lev][cf] = bnchnum[cf];
916
            numhere = 0;
917
 
918
            for (i=0; i<numsectors; i++)
1869 helixhorne 919
            {
7876 terminx 920
                if (!(gotsector[i>>3]&pow2char[i&7]))
1869 helixhorne 921
                    continue;
1877 helixhorne 922
 
923
                j = yax_getbunch(i, cf);
7876 terminx 924
                if (j >= 0 && !(havebunch[j>>3]&pow2char[j&7]))
1877 helixhorne 925
                {
7876 terminx 926
                    if (videoGetRenderMode() == REND_CLASSIC && (haveymost[j>>3]&pow2char[j&7])==0)
1886 helixhorne 927
                    {
928
                        yaxdebug("%s, l %d: skipped bunch %d (no *most)", cf?"v":"^", lev, j);
929
                        continue;
930
                    }
931
 
1882 helixhorne 932
                    if ((SECTORFLD(i,stat, cf)&2) ||
7858 terminx 933
                            (cf==0 && globalposz >= sector[i].ceilingz) ||
934
                            (cf==1 && globalposz <= sector[i].floorz))
1882 helixhorne 935
                    {
7876 terminx 936
                        havebunch[j>>3] |= pow2char[j&7];
1882 helixhorne 937
                        bunches[cf][bnchnum[cf]++] = j;
938
                        bnchend[lev][cf]++;
939
                        numhere++;
940
                    }
1877 helixhorne 941
                }
1869 helixhorne 942
            }
1877 helixhorne 943
 
944
            if (numhere > 0)
1874 helixhorne 945
            {
1877 helixhorne 946
                // found bunches -- need to fake-draw
947
 
1886 helixhorne 948
                yax_scanbunches(bbeg, numhere, (uint8_t *)gotsector);
949
 
4068 helixhorne 950
                qsort(&bunches[cf][bbeg], numhere, sizeof(int16_t), &yax_cmpbunches);
1877 helixhorne 951
 
1886 helixhorne 952
                if (numhere > 1 && lev != YAX_MAXDRAWS-1)
8073 terminx 953
                    Bmemset(lgotsector, 0, sizeof(lgotsector));
1886 helixhorne 954
 
1877 helixhorne 955
                for (bnchcnt=bbeg; bnchcnt < bbeg+numhere; bnchcnt++)
1874 helixhorne 956
                {
1877 helixhorne 957
                    j = bunches[cf][bnchcnt];  // the actual bunchnum...
1886 helixhorne 958
                    yax_globalbunch = j;
1882 helixhorne 959
#ifdef YAX_DEBUG
6828 terminx 960
                    t=timerGetTicksU64();
1882 helixhorne 961
#endif
1886 helixhorne 962
                    k = bunchsec[j];
963
 
1877 helixhorne 964
                    if (k < 0)
965
                    {
1886 helixhorne 966
                        yaxprintf("%s, l %d: skipped bunch %d\n", cf?"v":"^", lev, j);
1877 helixhorne 967
                        continue;
968
                    }
969
 
970
                    if (lev != YAX_MAXDRAWS-1)
971
                    {
2046 helixhorne 972
#ifdef YAX_DEBUG
973
                        int32_t odsprcnt = yax_spritesortcnt[yax_globallev];
974
#endif
1877 helixhorne 975
                        // +MAXSECTORS: force
6831 terminx 976
                        renderDrawRoomsQ16(globalposx,globalposy,globalposz,qglobalang,horiz,k+MAXSECTORS);
1877 helixhorne 977
                        if (numhere > 1)
978
                            for (i=0; i<(numsectors+7)>>3; i++)
979
                                lgotsector[i] |= gotsector[i];
980
 
2046 helixhorne 981
                        yaxdebug("l%d: faked (bn %2d) sec %4d,%3d dspr, ob=[%2d,%2d], sn=%4d, %.3f ms",
982
                                 yax_globallev-YAX_MAXDRAWS, j, k, yax_spritesortcnt[yax_globallev]-odsprcnt,
2026 helixhorne 983
                                 ourbunch[0],ourbunch[1],sectnum,
6828 terminx 984
                                 (double)(1000*(timerGetTicksU64()-t))/u64tickspersec);
1877 helixhorne 985
                    }
1882 helixhorne 986
 
987
                    if (ourbunch[cf]==j)
988
                    {
989
                        ourbunch[cf] = yax_getbunch(k, cf);
990
                        sectnum = k;
991
                    }
1874 helixhorne 992
                }
1869 helixhorne 993
 
1877 helixhorne 994
                if (numhere > 1 && lev != YAX_MAXDRAWS-1)
995
                    Bmemcpy(gotsector, lgotsector, (numsectors+7)>>3);
1874 helixhorne 996
            }
997
 
1877 helixhorne 998
            if (numhere==0 || lev==YAX_MAXDRAWS-1)
1874 helixhorne 999
            {
1877 helixhorne 1000
                // no new bunches or max level reached
1001
                maxlev[cf] = lev - (numhere==0);
1002
                break;
1874 helixhorne 1003
            }
1877 helixhorne 1004
        }
1005
    }
1869 helixhorne 1006
 
1886 helixhorne 1007
//    yax_globalcf = -1;
1869 helixhorne 1008
 
1877 helixhorne 1009
    // now comes the real drawing!
1010
    g_nodraw = 0;
1011
    scansector_collectsprites = 0;
1869 helixhorne 1012
 
5286 terminx 1013
    if (editstatus==1 && in3dmode())
1890 helixhorne 1014
    {
6829 terminx 1015
        if (videoGetRenderMode() == REND_CLASSIC)
1901 helixhorne 1016
        {
6828 terminx 1017
            videoBeginDrawing();
2513 helixhorne 1018
            draw_rainbow_background();
6828 terminx 1019
            videoEndDrawing();
1901 helixhorne 1020
        }
1892 helixhorne 1021
#ifdef USE_OPENGL
1901 helixhorne 1022
        else
1023
        {
6656 pogokeen 1024
            glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
1901 helixhorne 1025
        }
1026
#endif
1892 helixhorne 1027
    }
1869 helixhorne 1028
 
7400 terminx 1029
#ifdef USE_OPENGL
1030
    if (videoGetRenderMode() == REND_POLYMOST)
1031
    {
1032
        glClear(GL_DEPTH_BUFFER_BIT);
1033
        yax_polymostclearzbuffer = 0;
1034
    }
1035
#endif
1036
 
1877 helixhorne 1037
    for (cf=0; cf<2; cf++)
1038
    {
1886 helixhorne 1039
        yax_globalcf = cf;
1040
 
1877 helixhorne 1041
        for (lev=maxlev[cf]; lev>=0; lev--)
1042
        {
1043
            yax_globallev = YAX_MAXDRAWS + (-1 + 2*cf)*(lev+1);
1882 helixhorne 1044
            scansector_collectsprites = (lev == YAX_MAXDRAWS-1);
1877 helixhorne 1045
 
1046
            for (bnchcnt=bnchbeg[lev][cf]; bnchcnt<bnchend[lev][cf]; bnchcnt++)
1047
            {
1048
                j = bunches[cf][bnchcnt];  // the actual bunchnum...
1886 helixhorne 1049
                k = bunchsec[j];  // best start-drawing sector
1050
                yax_globalbunch = j;
1882 helixhorne 1051
#ifdef YAX_DEBUG
6828 terminx 1052
                t=timerGetTicksU64();
1882 helixhorne 1053
#endif
1877 helixhorne 1054
                yax_tweakpicnums(j, cf, 0);
1055
                if (k < 0)
1056
                    continue;
1057
 
2024 helixhorne 1058
                yax_nomaskdidit = 0;
1059
                for (nmp=r_tror_nomaskpass; nmp>=0; nmp--)
1060
                {
1061
                    yax_nomaskpass = nmp;
6831 terminx 1062
                    renderDrawRoomsQ16(globalposx,globalposy,globalposz,qglobalang,horiz,k+MAXSECTORS);  // +MAXSECTORS: force
1877 helixhorne 1063
 
2024 helixhorne 1064
                    if (nmp==1)
1065
                    {
2046 helixhorne 1066
                        yaxdebug("nm1 l%d: DRAWN (bn %2d) sec %4d,          %.3f ms",
1067
                                 yax_globallev-YAX_MAXDRAWS, j, k,
6828 terminx 1068
                                 (double)(1000*(timerGetTicksU64()-t))/u64tickspersec);
2046 helixhorne 1069
 
2024 helixhorne 1070
                        if (!yax_nomaskdidit)
1071
                        {
1072
                            yax_nomaskpass = 0;
1073
                            break;  // no need to draw the same stuff twice
1074
                        }
1075
                        Bmemcpy(yax_gotsector, gotsector, (numsectors+7)>>3);
1076
                    }
1077
                }
1078
 
2046 helixhorne 1079
                if (!scansector_collectsprites)
1080
                    spritesortcnt = 0;
1081
                yax_copytsprites();
1082
                yaxdebug("nm0 l%d: DRAWN (bn %2d) sec %4d,%3d tspr, %.3f ms",
1083
                         yax_globallev-YAX_MAXDRAWS, j, k, spritesortcnt,
6828 terminx 1084
                         (double)(1000*(timerGetTicksU64()-t))/u64tickspersec);
1877 helixhorne 1085
 
2880 helixhorne 1086
                SpriteAnimFunc(globalposx, globalposy, globalang, smoothr);
6831 terminx 1087
                renderDrawMasks();
1877 helixhorne 1088
            }
1089
 
1090
            if (lev < maxlev[cf])
1091
                for (bnchcnt=bnchbeg[lev+1][cf]; bnchcnt<bnchend[lev+1][cf]; bnchcnt++)
1092
                    yax_tweakpicnums(bunches[cf][bnchcnt], cf, 1);  // restore picnums
1869 helixhorne 1093
        }
1094
    }
1095
 
1882 helixhorne 1096
#ifdef YAX_DEBUG
6828 terminx 1097
    t=timerGetTicksU64();
1882 helixhorne 1098
#endif
2024 helixhorne 1099
    yax_globalcf = -1;
1886 helixhorne 1100
    yax_globalbunch = -1;
1877 helixhorne 1101
    yax_globallev = YAX_MAXDRAWS;
1882 helixhorne 1102
    scansector_collectsprites = 0;
1869 helixhorne 1103
 
1877 helixhorne 1104
    // draw base level
6831 terminx 1105
    renderDrawRoomsQ16(globalposx,globalposy,globalposz,qglobalang,horiz,
2810 helixhorne 1106
              osectnum + MAXSECTORS*didmirror);
2046 helixhorne 1107
//    if (scansector_collectsprites)
1108
//        spritesortcnt = 0;
1109
    yax_copytsprites();
1110
    yaxdebug("DRAWN base level sec %d,%3d tspr, %.3f ms", osectnum,
6828 terminx 1111
             spritesortcnt, (double)(1000*(timerGetTicksU64()-t))/u64tickspersec);
1877 helixhorne 1112
    scansector_collectsprites = 1;
1113
 
1114
    for (cf=0; cf<2; cf++)
1115
        if (maxlev[cf] >= 0)
1116
            for (bnchcnt=bnchbeg[0][cf]; bnchcnt<bnchend[0][cf]; bnchcnt++)
1117
                yax_tweakpicnums(bunches[cf][bnchcnt], cf, 1);  // restore picnums
1118
 
1119
#ifdef ENGINE_SCREENSHOT_DEBUG
1120
    engine_screenshot = 0;
1121
#endif
1886 helixhorne 1122
 
1123
#ifdef YAX_DEBUG_YMOSTS
6829 terminx 1124
    if (videoGetRenderMode() == REND_CLASSIC && numyaxbunches>0)
1886 helixhorne 1125
    {
6831 terminx 1126
        char purple = paletteGetClosestColor(255, 0, 255);
1127
        char yellow = paletteGetClosestColor(255, 255, 0);
1908 helixhorne 1128
 
6828 terminx 1129
        videoBeginDrawing();
1890 helixhorne 1130
        for (i=0; i<numyaxbunches; i++)
1131
        {
1132
            int32_t x, x1;
1886 helixhorne 1133
 
1890 helixhorne 1134
            if ((haveymost[i>>3]&(1<<i&7))==0)
1135
                continue;
1886 helixhorne 1136
 
1890 helixhorne 1137
            x1 = i*xdimen;
1886 helixhorne 1138
 
1890 helixhorne 1139
            for (x=x1; x<x1+xdimen; x++)
1140
            {
1908 helixhorne 1141
                if (yumost[x] >= 0 && yumost[x] < ydim && (x&1))
1890 helixhorne 1142
                    *((char *)frameplace + yumost[x]*bytesperline + x-x1) = purple;
1886 helixhorne 1143
 
1908 helixhorne 1144
                if (ydmost[x]-1 >= 0 && ydmost[x]-1 < ydim && !(x&1))
1890 helixhorne 1145
                    *((char *)frameplace + (ydmost[x]-1)*bytesperline + x-x1) = yellow;
1146
            }
1886 helixhorne 1147
        }
6828 terminx 1148
        videoEndDrawing();
1886 helixhorne 1149
    }
1150
#endif
7400 terminx 1151
#ifdef USE_OPENGL
1152
    if (videoGetRenderMode() == REND_POLYMOST)
1153
        yax_polymostclearzbuffer = 1;
1154
#endif
1869 helixhorne 1155
}
1156
 
2513 helixhorne 1157
#endif  // defined YAX_ENABLE
1843 helixhorne 1158
 
2513 helixhorne 1159
// must have writable frame buffer, i.e. done begindrawing()
1160
static void draw_rainbow_background(void)
1161
{
3721 helixhorne 1162
    int32_t y, i;
1163
    const int32_t N = 240;  // don't use fullbright colors
1164
    const int32_t numfull=bytesperline/N, numrest=bytesperline%N;
2513 helixhorne 1165
 
3721 helixhorne 1166
    const char *const src = palookup[0] + 256*18;
1167
    char *dst = (char *)frameplace;
1168
 
1169
    for (y=0; y<ydim; y++)
2513 helixhorne 1170
    {
3721 helixhorne 1171
        for (i=0; i<numfull; i++)
1172
            Bmemcpy(&dst[N*i], src, N);
1173
        if (numrest > 0)
1174
            Bmemcpy(&dst[N*i], src, numrest);
1175
 
1176
        dst += bytesperline;
2513 helixhorne 1177
    }
1178
}
3721 helixhorne 1179
 
1866 helixhorne 1180
//
1181
// setslope
1182
//
1183
void setslope(int32_t sectnum, int32_t cf, int16_t slope)
1184
{
1185
    if (slope==0)
1186
    {
1187
        SECTORFLD(sectnum,stat, cf) &= ~2;
1188
        SECTORFLD(sectnum,heinum, cf) = 0;
1189
    }
1190
    else
1191
    {
1192
        SECTORFLD(sectnum,stat, cf) |= 2;
1193
        SECTORFLD(sectnum,heinum, cf) = slope;
1194
    }
1195
}
1196
 
1886 helixhorne 1197
#define WALLS_ARE_CONSISTENT(k) ((wall[k].x == x2 && wall[k].y == y2)   \
1198
                                 && ((wall[wall[k].point2]).x == x1 && (wall[wall[k].point2]).y == y1))
1719 helixhorne 1199
 
1901 helixhorne 1200
static int32_t getscore(int32_t w1c, int32_t w1f, int32_t w2c, int32_t w2f)
1201
{
1202
    if (w1c > w1f)
1203
        swaplong(&w1c, &w1f);
1204
    if (w2c > w2f)
1205
        swaplong(&w2c, &w2f);
1206
 
1207
    // now: c <= f for each "wall-vline"
1208
 
4984 terminx 1209
    int32_t maxceil = max(w1c, w2c);
1210
    int32_t minflor = min(w1f, w2f);
1901 helixhorne 1211
 
1212
    return minflor-maxceil;
1213
}
1214
 
1886 helixhorne 1215
const int16_t *chsecptr_onextwall = NULL;
1216
 
1760 helixhorne 1217
int32_t checksectorpointer(int16_t i, int16_t sectnum)
1218
{
2048 helixhorne 1219
    int32_t startsec, endsec;
1760 helixhorne 1220
    int32_t j, k, startwall, endwall, x1, y1, x2, y2, numnewwalls=0;
1901 helixhorne 1221
    int32_t bestnextwall=-1, bestnextsec=-1, bestwallscore=INT32_MIN;
1222
    int32_t cz[4], fz[4], tmp[2], tmpscore=0;
1223
#ifdef YAX_ENABLE
1224
    int16_t cb[2], fb[2];
1225
#endif
1760 helixhorne 1226
 
1227
#if 0
1228
    if (checksectorpointer_warn && (i<0 || i>=max(numwalls,newnumwalls)))
1229
    {
1230
        char buf[128];
1231
        Bsprintf(buf, "WARN: checksectorpointer called with i=%d but (new)numwalls=%d", i, max(numwalls,newnumwalls));
1232
        OSD_Printf("%s\n", buf);
1233
        printmessage16("%s", buf);
1234
        return 0;
1235
    }
1236
#endif
1237
 
1238
    x1 = wall[i].x;
1239
    y1 = wall[i].y;
1240
    x2 = (wall[wall[i].point2]).x;
1241
    y2 = (wall[wall[i].point2]).y;
1242
 
1866 helixhorne 1243
    k = wall[i].nextwall;
1244
    if (k >= 0)          //Check for early exit
1760 helixhorne 1245
    {
1886 helixhorne 1246
        if (WALLS_ARE_CONSISTENT(k))
1247
            return 0;
1866 helixhorne 1248
 
1249
        wall[k].nextwall = wall[k].nextsector = -1;
1760 helixhorne 1250
    }
1251
 
2048 helixhorne 1252
    if ((unsigned)wall[i].nextsector < (unsigned)numsectors && wall[i].nextwall < 0)
1253
    {
1254
        // if we have a nextsector but no nextwall, take this as a hint
1255
        // to search only the walls of that sector
1256
        startsec = wall[i].nextsector;
1257
        endsec = startsec+1;
1258
    }
1259
    else
1260
    {
1261
        startsec = 0;
1262
        endsec = numsectors;
1263
    }
1264
 
1866 helixhorne 1265
    wall[i].nextsector = wall[i].nextwall = -1;
1266
 
1886 helixhorne 1267
    if (chsecptr_onextwall && (k=chsecptr_onextwall[i])>=0 && wall[k].nextwall<0)
1268
    {
1901 helixhorne 1269
        // old next wall found
1886 helixhorne 1270
        if (WALLS_ARE_CONSISTENT(k))
1271
        {
1272
            j = sectorofwall(k);
1273
 
1274
            wall[i].nextsector = j;
1275
            wall[i].nextwall = k;
1276
            wall[k].nextsector = sectnum;
1277
            wall[k].nextwall = i;
1278
 
1279
            return 1;
1280
        }
1281
    }
1282
 
2048 helixhorne 1283
    for (j=startsec; j<endsec; j++)
1760 helixhorne 1284
    {
1875 helixhorne 1285
        if (j == sectnum)
1286
            continue;
1287
 
1869 helixhorne 1288
        YAX_SKIPSECTOR(j);
1289
 
1760 helixhorne 1290
        startwall = sector[j].wallptr;
1886 helixhorne 1291
        endwall = startwall + sector[j].wallnum;
1292
        for (k=startwall; k<endwall; k++)
1760 helixhorne 1293
        {
1886 helixhorne 1294
            if (!WALLS_ARE_CONSISTENT(k))
1866 helixhorne 1295
                continue;
1790 helixhorne 1296
 
1866 helixhorne 1297
            // Don't create link if the other side is connected to another wall.
1298
            // The nextwall relation should be definitely one-to-one at all times!
1299
            if (wall[k].nextwall>=0 && wall[k].nextwall != i)
1300
                continue;
1901 helixhorne 1301
#ifdef YAX_ENABLE
1302
            yax_getbunches(sectnum, &cb[0], &fb[0]);
1303
            yax_getbunches(j, &cb[1], &fb[1]);
1866 helixhorne 1304
 
1901 helixhorne 1305
            if ((cb[0]>=0 && cb[0]==cb[1]) || (fb[0]>=0 && fb[0]==fb[1]))
1866 helixhorne 1306
            {
1901 helixhorne 1307
                tmpscore = INT32_MAX;
1866 helixhorne 1308
            }
1901 helixhorne 1309
            else
1310
#endif
1311
            {
1312
                getzsofslope(sectnum, x1,y1, &cz[0],&fz[0]);
1313
                getzsofslope(sectnum, x2,y2, &cz[1],&fz[1]);
1314
                getzsofslope(j, x1,y1, &cz[2],&fz[2]);
1315
                getzsofslope(j, x2,y2, &cz[3],&fz[3]);
1866 helixhorne 1316
 
1901 helixhorne 1317
                tmp[0] = getscore(cz[0],fz[0], cz[2],fz[2]);
1318
                tmp[1] = getscore(cz[1],fz[1], cz[3],fz[3]);
1319
 
1320
                if ((tmp[0]^tmp[1]) >= 0)
1321
                    tmpscore = tmp[0]+tmp[1];
1322
                else
1323
                    tmpscore = max(tmp[0], tmp[1]);
1324
            }
1325
 
1326
            if (bestnextwall == -1 || tmpscore > bestwallscore)
1327
            {
1328
                bestwallscore = tmpscore;
1329
                bestnextwall = k;
1330
                bestnextsec = j;
1331
            }
1332
 
1333
            numnewwalls++;
1760 helixhorne 1334
        }
1335
    }
1886 helixhorne 1336
 
1901 helixhorne 1337
    // sectnum -2 means dry run
1338
    if (bestnextwall >= 0 && sectnum!=-2)
1339
#ifdef YAX_ENABLE
2048 helixhorne 1340
        // for walls with TROR neighbors, be conservative in case if score <=0
1341
        // (meaning that no wall area is mutually visible) -- it could be that
1342
        // another sector is a better candidate later on
1901 helixhorne 1343
        if ((yax_getnextwall(i, 0)<0 && yax_getnextwall(i, 1)<0) || bestwallscore>0)
1344
#endif
1345
        {
1346
//    initprintf("w%d new nw=%d (score %d)\n", i, bestnextwall, bestwallscore)
1347
            wall[i].nextsector = bestnextsec;
1348
            wall[i].nextwall = bestnextwall;
1349
            wall[bestnextwall].nextsector = sectnum;
1350
            wall[bestnextwall].nextwall = i;
1351
        }
1352
 
1886 helixhorne 1353
    return numnewwalls;
1760 helixhorne 1354
}
1355
 
1886 helixhorne 1356
#undef WALLS_ARE_CONSISTENT
1760 helixhorne 1357
 
2020 helixhorne 1358
int32_t xb1[MAXWALLSB];  // Polymost uses this as a temp array
1359
static int32_t yb1[MAXWALLSB], xb2[MAXWALLSB], yb2[MAXWALLSB];
1360
int32_t rx1[MAXWALLSB], ry1[MAXWALLSB];
1361
static int32_t rx2[MAXWALLSB], ry2[MAXWALLSB];
4623 terminx 1362
int16_t bunchp2[MAXWALLSB], thesector[MAXWALLSB];
5 Plagman 1363
 
1205 terminx 1364
int16_t bunchfirst[MAXWALLSB], bunchlast[MAXWALLSB];
5 Plagman 1365
 
4695 terminx 1366
static int32_t nodesperline, ysavecnt;
1367
static int16_t *smost, *umost, *dmost, *bakumost, *bakdmost;
1368
static int16_t *uplc, *dplc, *uwall, *dwall;
1369
static int32_t *swplc, *lplc, *swall, *lwall;
1370
#ifdef HIGH_PRECISION_SPRITE
1371
static float *swallf;
1372
#endif
1373
 
7733 pogokeen 1374
uint8_t* mirrorBuffer;
1375
 
1932 helixhorne 1376
static int32_t smostcnt;
2216 helixhorne 1377
static int32_t smoststart[MAXWALLSB];
5 Plagman 1378
static char smostwalltype[MAXWALLSB];
2024 helixhorne 1379
static int32_t smostwall[MAXWALLSB], smostwallcnt = -1;
5 Plagman 1380
 
4696 terminx 1381
static vec3_t spritesxyz[MAXSPRITESONSCREEN+1];
5 Plagman 1382
 
1205 terminx 1383
int32_t xdimen = -1, xdimenrecip, halfxdimen, xdimenscale, xdimscale;
4768 hendricks2 1384
float fxdimen = -1.f;
2281 helixhorne 1385
int32_t ydimen;
3400 helixhorne 1386
intptr_t frameoffset;
5 Plagman 1387
 
1205 terminx 1388
static int32_t nrx1[8], nry1[8], nrx2[8], nry2[8]; // JBF 20031206: Thanks Ken
5 Plagman 1389
 
5792 terminx 1390
int32_t rxi[8], ryi[8];
1391
static int32_t rzi[8], rxi2[8], ryi2[8], rzi2[8];
1205 terminx 1392
static int32_t xsi[8], ysi[8], horizycent;
2701 helixhorne 1393
static int32_t *horizlookup=0, *horizlookup2=0;
5 Plagman 1394
 
1205 terminx 1395
int32_t globalposx, globalposy, globalposz, globalhoriz;
6724 terminx 1396
fix16_t qglobalhoriz;
4667 terminx 1397
float fglobalposx, fglobalposy, fglobalposz;
1205 terminx 1398
int16_t globalang, globalcursectnum;
6725 terminx 1399
fix16_t qglobalang;
1205 terminx 1400
int32_t globalpal, cosglobalang, singlobalang;
1401
int32_t cosviewingrangeglobalang, sinviewingrangeglobalang;
3763 terminx 1402
static int32_t globaluclip, globaldclip;
1403
int32_t globvis, globalvisibility;
1404
int32_t globalhisibility, globalpisibility, globalcisibility;
7412 terminx 1405
#ifdef USE_OPENGL
1406
int32_t globvis2, globalvisibility2, globalhisibility2, globalpisibility2, globalcisibility2;
1407
#endif
2281 helixhorne 1408
//char globparaceilclip, globparaflorclip;
5 Plagman 1409
 
2281 helixhorne 1410
int32_t xyaspect;
1411
static int32_t viewingrangerecip;
5 Plagman 1412
 
2281 helixhorne 1413
static char globalxshift, globalyshift;
1414
static int32_t globalxpanning, globalypanning;
1415
int32_t globalshade, globalorientation;
1416
int16_t globalpicnum;
1417
static int16_t globalshiftval;
3483 helixhorne 1418
#ifdef HIGH_PRECISION_SPRITE
1419
static int64_t globalzd;
1420
#else
1421
static int32_t globalzd;
1422
#endif
1423
static int32_t globalyscale;
1866 helixhorne 1424
static int32_t globalxspan, globalyspan, globalispow2=1;  // true if texture has power-of-two x and y size
2281 helixhorne 1425
static intptr_t globalbufplc;
5 Plagman 1426
 
4413 helixhorne 1427
static int32_t globaly1, globalx2;
2281 helixhorne 1428
 
4454 helixhorne 1429
int16_t sectorborder[256];
2272 helixhorne 1430
int32_t ydim16, qsetmode = 0;
1843 helixhorne 1431
int16_t pointhighlight=-1, linehighlight=-1, highlightcnt=0;
4695 terminx 1432
static int32_t *lastx;
5 Plagman 1433
 
1205 terminx 1434
int32_t halfxdim16, midydim16;
5 Plagman 1435
 
1436
typedef struct
1437
{
1205 terminx 1438
    int32_t sx, sy, z;
1439
    int16_t a, picnum;
1440
    int8_t dashade;
3609 hendricks2 1441
    char dapalnum, dastat;
4360 helixhorne 1442
    uint8_t daalpha, dablend;
3609 hendricks2 1443
    char pagesleft;
1205 terminx 1444
    int32_t cx1, cy1, cx2, cy2;
1445
    int32_t uniqid;    //JF extension
5 Plagman 1446
} permfifotype;
1447
static permfifotype permfifo[MAXPERMS];
1205 terminx 1448
static int32_t permhead = 0, permtail = 0;
5 Plagman 1449
 
4451 helixhorne 1450
EDUKE32_STATIC_ASSERT(MAXWALLSB < INT16_MAX);
2281 helixhorne 1451
int16_t numscans, numbunches;
1452
static int16_t numhits;
5 Plagman 1453
 
5349 hendricks2 1454
uint8_t vgapal16[4*256] =
584 terminx 1455
{
5349 hendricks2 1456
    0,0,0,0, 170,0,0,0, 0,170,0,0, 170,170,0,0, 0,0,170,0,
1457
    170,0,170,0, 0,85,170,0, 170,170,170,0, 85,85,85,0, 255,85,85,0,
1458
    85,255,85,0, 255,255,85,0, 85,85,255,0, 255,85,255,0, 85,255,255,0,
1459
    255,255,255,0
584 terminx 1460
};
5 Plagman 1461
 
1205 terminx 1462
int16_t searchit;
1463
int32_t searchx = -1, searchy;                          //search input
1464
int16_t searchsector, searchwall, searchstat;     //search output
1706 helixhorne 1465
 
1848 helixhorne 1466
// SEARCHBOTTOMWALL:
1467
//   When aiming at a the bottom part of a 2-sided wall whose bottom part
1468
//   is swapped (.cstat&2), searchbottomwall equals that wall's .nextwall. In all
1469
//   other cases (when aiming at a wall), searchbottomwall equals searchwall.
1470
//
1471
// SEARCHISBOTTOM:
1472
//  When aiming at a 2-sided wall, 1 if aiming at the bottom part, 0 else
1473
int16_t searchbottomwall, searchisbottom;
1706 helixhorne 1474
 
7733 pogokeen 1475
char inpreparemirror = 0;
1205 terminx 1476
static int32_t mirrorsx1, mirrorsy1, mirrorsx2, mirrorsy2;
5 Plagman 1477
 
7593 terminx 1478
#define MAXSETVIEW 4
1479
 
1205 terminx 1480
static int32_t setviewcnt = 0; // interface layers use this now
7593 terminx 1481
static intptr_t bakframeplace[MAXSETVIEW];
1482
static int32_t bakxsiz[MAXSETVIEW], bakysiz[MAXSETVIEW];
1483
static vec2_t bakwindowxy1[MAXSETVIEW], bakwindowxy2[MAXSETVIEW];
1820 terminx 1484
#ifdef USE_OPENGL
4606 terminx 1485
static int32_t bakrendmode;
5 Plagman 1486
#endif
4606 terminx 1487
static int32_t baktile;
5 Plagman 1488
 
7921 terminx 1489
#ifdef APPNAME
1490
char apptitle[256] = APPNAME;
1491
#else
5 Plagman 1492
char apptitle[256] = "Build Engine";
7921 terminx 1493
#endif
1781 plagman 1494
 
5 Plagman 1495
//
1496
// Internal Engine Functions
1497
//
4301 helixhorne 1498
 
1908 helixhorne 1499
// returns: 0=continue sprite collecting;
1500
//          1=break out of sprite collecting;
6832 terminx 1501
int32_t renderAddTsprite(int16_t z, int16_t sectnum)
1892 helixhorne 1502
{
7603 terminx 1503
    auto const spr = (uspriteptr_t)&sprite[z];
1892 helixhorne 1504
#ifdef YAX_ENABLE
1505
    if (g_nodraw==0)
1506
    {
2024 helixhorne 1507
        if (numyaxbunches==0)
1508
        {
1892 helixhorne 1509
#endif
6347 terminx 1510
            if (spritesortcnt >= maxspritesonscreen)
2024 helixhorne 1511
                return 1;
1512
 
3448 helixhorne 1513
            Bmemcpy(&tsprite[spritesortcnt], spr, sizeof(spritetype));
5400 terminx 1514
            tsprite[spritesortcnt].extra = 0;
2024 helixhorne 1515
            tsprite[spritesortcnt++].owner = z;
1516
 
1892 helixhorne 1517
#ifdef YAX_ENABLE
2024 helixhorne 1518
        }
1892 helixhorne 1519
    }
1520
    else
2024 helixhorne 1521
        if (yax_nomaskpass==0)
1892 helixhorne 1522
    {
5300 terminx 1523
        int16_t *sortcnt = &yax_spritesortcnt[yax_globallev];
1524
 
6347 terminx 1525
        if (*sortcnt >= maxspritesonscreen)
2183 helixhorne 1526
            return 1;
1892 helixhorne 1527
 
1528
        yax_tsprite[yax_globallev][*sortcnt] = z;
2046 helixhorne 1529
        if (yax_globalbunch >= 0)
1530
        {
1531
            yax_tsprite[yax_globallev][*sortcnt] |= (MAXSPRITES|(MAXSPRITES<<1));
1532
            yax_tsprfrombunch[yax_globallev][*sortcnt] = yax_globalbunch;
1533
        }
1892 helixhorne 1534
        (*sortcnt)++;
1535
 
1536
        // now check whether the tsprite needs duplication into another level
1537
        if ((spr->cstat&48)==32)
1538
            return 0;
1539
 
5300 terminx 1540
        int16_t cb, fb;
1541
 
1892 helixhorne 1542
        yax_getbunches(sectnum, &cb, &fb);
1543
        if (cb < 0 && fb < 0)
1544
            return 0;
1545
 
5300 terminx 1546
        int32_t spheight;
1547
        int16_t spzofs = spriteheightofs(z, &spheight, 1);
1892 helixhorne 1548
 
1549
        // TODO: get*zofslope?
1550
        if (cb>=0 && spr->z+spzofs-spheight < sector[sectnum].ceilingz)
1551
        {
1552
            sortcnt = &yax_spritesortcnt[yax_globallev-1];
6347 terminx 1553
            if (*sortcnt < maxspritesonscreen)
1892 helixhorne 1554
            {
1555
                yax_tsprite[yax_globallev-1][*sortcnt] = z|MAXSPRITES;
1556
                (*sortcnt)++;
1557
            }
1558
        }
1559
        if (fb>=0 && spr->z+spzofs > sector[sectnum].floorz)
1560
        {
1561
            sortcnt = &yax_spritesortcnt[yax_globallev+1];
6347 terminx 1562
            if (*sortcnt < maxspritesonscreen)
1892 helixhorne 1563
            {
1564
                yax_tsprite[yax_globallev+1][*sortcnt] = z|(MAXSPRITES<<1);
1565
                (*sortcnt)++;
1566
            }
1567
        }
1568
    }
1569
#endif
1570
 
1571
    return 0;
1572
}
1573
 
7606 terminx 1574
static FORCE_INLINE vec2_t get_rel_coords(int32_t const x, int32_t const y)
4875 helixhorne 1575
{
7606 terminx 1576
    return { dmulscale6(y, cosglobalang, -x, singlobalang),
1577
             dmulscale6(x, cosviewingrangeglobalang, y, sinviewingrangeglobalang) };
4875 helixhorne 1578
}
1579
 
1580
// Note: the returned y coordinates are not actually screen coordinates, but
1581
// potentially clipped player-relative y coordinates.
7027 terminx 1582
static int get_screen_coords(const vec2_t &p1, const vec2_t &p2,
4875 helixhorne 1583
                             int32_t *sx1ptr, int32_t *sy1ptr,
1584
                             int32_t *sx2ptr, int32_t *sy2ptr)
1585
{
1586
    int32_t sx1, sy1, sx2, sy2;
1587
 
1588
    // First point.
1589
 
1590
    if (p1.x >= -p1.y)
1591
    {
1592
        if (p1.x > p1.y || p1.y == 0)
1593
            return 0;
1594
 
1595
        sx1 = halfxdimen + scale(p1.x, halfxdimen, p1.y)
1596
            + (p1.x >= 0);  // Fix for SIGNED divide
1597
        if (sx1 >= xdimen)
1598
            sx1 = xdimen-1;
1599
 
1600
        sy1 = p1.y;
1601
    }
1602
    else
1603
    {
1604
        if (p2.x < -p2.y)
1605
            return 0;
1606
 
1607
        sx1 = 0;
1608
 
1609
        int32_t tempint = (p1.x + p1.y) - (p2.x + p2.y);
1610
        if (tempint == 0)
1611
            return 0;
1612
        sy1 = p1.y + scale(p2.y-p1.y, p1.x+p1.y, tempint);
1613
    }
1614
 
1615
    if (sy1 < 256)
1616
        return 0;
1617
 
1618
    // Second point.
1619
 
1620
    if (p2.x <= p2.y)
1621
    {
1622
        if (p2.x < -p2.y || p2.y == 0)
1623
            return 0;
1624
 
1625
        sx2 = halfxdimen + scale(p2.x,halfxdimen,p2.y) - 1
1626
            + (p2.x >= 0);  // Fix for SIGNED divide
1627
        if (sx2 >= xdimen)
1628
            sx2 = xdimen-1;
1629
 
1630
        sy2 = p2.y;
1631
    }
1632
    else
1633
    {
1634
        if (p1.x > p1.y)
1635
            return 0;
1636
 
1637
        sx2 = xdimen-1;
1638
 
7057 terminx 1639
        int32_t const tempint = (p1.y - p1.x) + (p2.x - p2.y);
1640
 
4875 helixhorne 1641
        sy2 = p1.y + scale(p2.y-p1.y, p1.y-p1.x, tempint);
1642
    }
1643
 
1644
    if (sy2 < 256 || sx1 > sx2)
1645
        return 0;
1646
 
1647
    *sx1ptr = sx1; *sy1ptr = sy1;
1648
    *sx2ptr = sx2; *sy2ptr = sy2;
1649
 
1650
    return 1;
1651
}
1652
 
7226 terminx 1653
 
1654
static inline int findUnusedTile(void)
1655
{
7606 terminx 1656
    static int lastUnusedTile = MAXUSERTILES-1;
1657
 
7240 terminx 1658
    for (; lastUnusedTile >= 0; --lastUnusedTile)
7606 terminx 1659
        if ((tilesiz[lastUnusedTile].x|tilesiz[lastUnusedTile].y) == 0)
7226 terminx 1660
            return lastUnusedTile;
1661
 
7240 terminx 1662
    return -1;
7226 terminx 1663
}
1664
 
5 Plagman 1665
//
1666
// scansector (internal)
1667
//
6832 terminx 1668
static void classicScanSector(int16_t startsectnum)
5 Plagman 1669
{
4454 helixhorne 1670
    if (startsectnum < 0)
1671
        return;
5 Plagman 1672
 
7873 terminx 1673
    if (automapping)
1674
        show2dsector[startsectnum>>3] |= pow2char[startsectnum&7];
1675
 
5856 hendricks2 1676
    sectorborder[0] = startsectnum;
1677
    int32_t sectorbordercnt = 1;
4454 helixhorne 1678
 
5 Plagman 1679
    do
1680
    {
4454 helixhorne 1681
        const int32_t sectnum = sectorborder[--sectorbordercnt];
1682
 
1877 helixhorne 1683
#ifdef YAX_ENABLE
1684
        if (scansector_collectsprites)
1685
#endif
5829 terminx 1686
        for (bssize_t i=headspritesect[sectnum]; i>=0; i=nextspritesect[i])
5 Plagman 1687
        {
7603 terminx 1688
            auto const spr = (uspriteptr_t)&sprite[i];
4454 helixhorne 1689
 
5856 hendricks2 1690
            if (((spr->cstat & 0x8000) && !showinvisibility) || spr->xrepeat == 0 || spr->yrepeat == 0)
1691
                continue;
4454 helixhorne 1692
 
5856 hendricks2 1693
            vec2_t const s = { spr->x-globalposx, spr->y-globalposy };
1694
 
1695
            if ((spr->cstat&48) || ((coord_t)s.x*cosglobalang+(coord_t)s.y*singlobalang > 0))
1696
                if ((spr->cstat&(64+48))!=(64+16) || dmulscale6(sintable[(spr->ang+512)&2047],-s.x, sintable[spr->ang&2047],-s.y) > 0)
6832 terminx 1697
                    if (renderAddTsprite(i, sectnum))
5856 hendricks2 1698
                        break;
5 Plagman 1699
        }
1700
 
1701
        gotsector[sectnum>>3] |= pow2char[sectnum&7];
1702
 
4875 helixhorne 1703
        const int32_t onumbunches = numbunches;
1704
        const int32_t onumscans = numscans;
5 Plagman 1705
 
4875 helixhorne 1706
        const int32_t startwall = sector[sectnum].wallptr;
1707
        const int32_t endwall = startwall + sector[sectnum].wallnum;
1708
        int32_t scanfirst = numscans;
1709
 
1710
        vec2_t p1, p2 = { 0, 0 };
1711
 
5829 terminx 1712
        for (bssize_t w=startwall; w<endwall; w++)
5 Plagman 1713
        {
7603 terminx 1714
            auto const wal = (uwallptr_t)&wall[w];
4454 helixhorne 1715
            const int32_t nextsectnum = wal->nextsector;
7603 terminx 1716
            auto const wal2 = (uwallptr_t)&wall[wal->point2];
5 Plagman 1717
 
4454 helixhorne 1718
            const int32_t x1 = wal->x-globalposx, y1 = wal->y-globalposy;
1719
            const int32_t x2 = wal2->x-globalposx, y2 = wal2->y-globalposy;
4877 helixhorne 1720
 
1721
            // The following block checks for a potential collection of a
1722
            // sector that is "thin" in screen space. This is necessary because
1723
            // not all sectors that are needed to be drawn may be collected via
1724
            // drawalls() -> scansector() (although those are the majority).
1725
            // Example: standing at exactly the intersection of a large sector
1726
            // into four quadrant sub-sectors.
4875 helixhorne 1727
#if 1
4877 helixhorne 1728
            if (nextsectnum >= 0 && (wal->cstat&32) == 0 && sectorbordercnt < ARRAY_SSIZE(sectorborder))
2024 helixhorne 1729
#ifdef YAX_ENABLE
4875 helixhorne 1730
                if (yax_nomaskpass==0 || !yax_isislandwall(w, !yax_globalcf) || (yax_nomaskdidit=1, 0))
2024 helixhorne 1731
#endif
5 Plagman 1732
                if ((gotsector[nextsectnum>>3]&pow2char[nextsectnum&7]) == 0)
1733
                {
2784 helixhorne 1734
                    // OV: E2L10
4578 helixhorne 1735
                    coord_t temp = (coord_t)x1*y2-(coord_t)x2*y1;
4875 helixhorne 1736
                    int32_t tempint = temp;
2784 helixhorne 1737
                    if (((uint64_t)tempint+262144) < 524288)  // BXY_MAX?
584 terminx 1738
                        if (mulscale5(tempint,tempint) <= (x2-x1)*(x2-x1)+(y2-y1)*(y2-y1))
4877 helixhorne 1739
                        {
5 Plagman 1740
                            sectorborder[sectorbordercnt++] = nextsectnum;
4877 helixhorne 1741
                            gotsector[nextsectnum>>3] |= pow2char[nextsectnum&7];
1742
                        }
5 Plagman 1743
                }
4875 helixhorne 1744
#endif
4984 terminx 1745
            p1 = (w == startwall || wall[w - 1].point2 != w) ? get_rel_coords(x1, y1) : p2;
4875 helixhorne 1746
            p2 = get_rel_coords(x2, y2);
4623 terminx 1747
 
4875 helixhorne 1748
            if (p1.y < 256 && p2.y < 256)
1749
                goto skipitaddwall;
5 Plagman 1750
 
4875 helixhorne 1751
            // If wall's NOT facing you
1752
            if (dmulscale32(p1.x, p2.y, -p2.x, p1.y) >= 0)
1753
                goto skipitaddwall;
5 Plagman 1754
 
7447 terminx 1755
            if (numscans >= MAXWALLSB-1)
1756
            {
1757
                OSD_Printf("!!numscans\n");
1758
                return;
1759
            }
1760
 
4875 helixhorne 1761
            if (get_screen_coords(p1, p2, &xb1[numscans], &yb1[numscans], &xb2[numscans], &yb2[numscans]))
5 Plagman 1762
            {
4875 helixhorne 1763
                // Made it all the way!
1764
                thesector[numscans] = sectnum; thewall[numscans] = w;
1765
                rx1[numscans] = p1.x; ry1[numscans] = p1.y;
1766
                rx2[numscans] = p2.x; ry2[numscans] = p2.y;
1767
                bunchp2[numscans] = numscans+1;
1768
                numscans++;
5 Plagman 1769
            }
1770
 
1866 helixhorne 1771
skipitaddwall:
4875 helixhorne 1772
            if (wall[w].point2 < w && scanfirst < numscans)
4623 terminx 1773
                bunchp2[numscans-1] = scanfirst, scanfirst = numscans;
5 Plagman 1774
        }
1775
 
5829 terminx 1776
        for (bssize_t s=onumscans; s<numscans; s++)
4875 helixhorne 1777
            if (wall[thewall[s]].point2 != thewall[bunchp2[s]] || xb2[s] >= xb1[bunchp2[s]])
1874 helixhorne 1778
            {
4875 helixhorne 1779
                bunchfirst[numbunches++] = bunchp2[s], bunchp2[s] = -1;
1874 helixhorne 1780
#ifdef YAX_ENABLE
1781
                if (scansector_retfast)
1782
                    return;
1783
#endif
1784
            }
5 Plagman 1785
 
5829 terminx 1786
        for (bssize_t bn=onumbunches; bn<numbunches; bn++)
5 Plagman 1787
        {
4875 helixhorne 1788
            int32_t s;
1789
            for (s=bunchfirst[bn]; bunchp2[s]>=0; s=bunchp2[s])
1790
                /* do nothing */;
1791
            bunchlast[bn] = s;
5 Plagman 1792
        }
584 terminx 1793
    }
1794
    while (sectorbordercnt > 0);
5 Plagman 1795
}
1796
 
4877 helixhorne 1797
#if DEBUGGINGAIDS >= 2
1798
// Printing functions for collected scans (called "wall proxies" by
1799
// http://fabiensanglard.net/duke3d/build_engine_internals.php) and
1800
// bunches. For use from within the debugger.
3482 helixhorne 1801
 
4877 helixhorne 1802
void printscans(void)
1803
{
1804
    static uint8_t didscan[(MAXWALLSB+7)>>3];
1805
 
1806
    Bmemset(didscan, 0, sizeof(didscan));
1807
 
5829 terminx 1808
    for (bssize_t s=0; s<numscans; s++)
4877 helixhorne 1809
    {
7876 terminx 1810
        if (bunchp2[s] >= 0 && (didscan[s>>3] & pow2char[s&7])==0)
4877 helixhorne 1811
        {
1812
            printf("scan ");
1813
 
1814
            int z = s;
1815
            do
1816
            {
1817
                const int cond = (wall[thewall[z]].point2 != thewall[bunchp2[z]] ||
1818
                                  xb2[z] >= xb1[bunchp2[z]]);
1819
 
1820
                printf("%s%d(%d) ", cond ? "!" : "", z, thewall[z]);
1821
 
7876 terminx 1822
                if (didscan[z>>3] & pow2char[z&7])
4877 helixhorne 1823
                {
1824
                    printf("*");
1825
                    break;
1826
                }
1827
 
7876 terminx 1828
                didscan[z>>3] |= pow2char[z&7];
4877 helixhorne 1829
                z = bunchp2[z];
1830
            } while (z >= 0);
1831
 
1832
            printf("\n");
1833
        }
1834
    }
1835
}
1836
 
1837
void printbunches(void)
1838
{
5829 terminx 1839
    for (bssize_t bn=0; bn<numbunches; bn++)
4877 helixhorne 1840
    {
1841
        printf("bunch %d: ", bn);
5829 terminx 1842
        for (bssize_t s=bunchfirst[bn]; s>=0; s=bunchp2[s])
4877 helixhorne 1843
            printf("%d(%d) ", s, thewall[s]);
1844
        printf("\n");
1845
    }
1846
}
1847
#endif
1848
 
3482 helixhorne 1849
////////// *WALLSCAN HELPERS //////////
1850
 
1851
#define WSHELPER_DECL inline //ATTRIBUTE((always_inline))
1852
 
7694 terminx 1853
static WSHELPER_DECL void tweak_tsizes(vec2_16_t *tsiz)
3482 helixhorne 1854
{
4623 terminx 1855
    if (pow2long[picsiz[globalpicnum]&15] == tsiz->x)
1856
        tsiz->x--;
3482 helixhorne 1857
    else
4623 terminx 1858
        tsiz->x = -tsiz->x;
3482 helixhorne 1859
 
4623 terminx 1860
    if (pow2long[picsiz[globalpicnum]>>4] == tsiz->y)
1861
        tsiz->y = (picsiz[globalpicnum]>>4);
3482 helixhorne 1862
    else
4623 terminx 1863
        tsiz->y = -tsiz->y;
3482 helixhorne 1864
}
1865
 
7694 terminx 1866
static WSHELPER_DECL void calc_bufplc(intptr_t *bufplc, int32_t lw, vec2_16_t tsiz)
3482 helixhorne 1867
{
4292 helixhorne 1868
    // CAUTION: lw can be negative!
3482 helixhorne 1869
    int32_t i = lw + globalxpanning;
1870
 
4292 helixhorne 1871
//    if (i >= tsizx)
3482 helixhorne 1872
    {
4623 terminx 1873
        if (tsiz.x < 0)
1874
            i = (uint32_t)i % -tsiz.x;
3482 helixhorne 1875
        else
4623 terminx 1876
            i &= tsiz.x;
3482 helixhorne 1877
    }
1878
 
4623 terminx 1879
    if (tsiz.y < 0)
1880
        i *= -tsiz.y;
3482 helixhorne 1881
    else
4623 terminx 1882
        i <<= tsiz.y;
3482 helixhorne 1883
 
4623 terminx 1884
//    Bassert(i >= 0 && i < tilesiz[globalpicnum].x*tilesiz[globalpicnum].y);
4293 helixhorne 1885
 
3482 helixhorne 1886
    // Address is at the first row of tile storage (which is column-major).
1887
    *bufplc = waloff[globalpicnum] + i;
1888
}
1889
 
4578 helixhorne 1890
static WSHELPER_DECL void calc_vplcinc_wall(uint32_t *vplc, int32_t *vinc, inthi_t sw, int32_t y1v)
3482 helixhorne 1891
{
1892
    *vinc = sw*globalyscale;
1893
    *vplc = globalzd + (uint32_t)(*vinc)*(y1v-globalhoriz+1);
1894
}
1895
 
3483 helixhorne 1896
#ifdef HIGH_PRECISION_SPRITE
1897
static WSHELPER_DECL void calc_vplcinc_sprite(uint32_t *vplc, int32_t *vinc, int32_t x, int32_t y1v)
1898
{
6378 hendricks2 1899
    inthi_t const tmpvinc = inthi_rintf(swallf[x]);
5300 terminx 1900
    inthi_t const tmpvplc = globalzd + tmpvinc*(y1v-globalhoriz+1);
3483 helixhorne 1901
 
1902
    *vinc = tmpvinc;
1903
    // Clamp the vertical texture coordinate!
7111 terminx 1904
    *vplc = min<inthi_t>(max<inthi_t>(0, tmpvplc), UINT32_MAX);
3483 helixhorne 1905
}
1906
#endif
1907
 
1908
static int32_t drawing_sprite = 0;
1909
 
1910
static WSHELPER_DECL void calc_vplcinc(uint32_t *vplc, int32_t *vinc, const int32_t *swal, int32_t x, int32_t y1v)
1911
{
1912
#if !defined HIGH_PRECISION_SPRITE
1913
    (void)drawing_sprite;
1914
#else
1915
    if (drawing_sprite)
1916
        calc_vplcinc_sprite(vplc, vinc, x, y1v);
1917
    else
1918
#endif
1919
        calc_vplcinc_wall(vplc, vinc, swal[x], y1v);
1920
}
1921
 
3031 helixhorne 1922
#undef NONPOW2_YSIZE_ASM
3034 helixhorne 1923
#if !defined ENGINE_USING_A_C
1924
# if defined CLASSIC_NONPOW2_YSIZE_WALLS || defined CLASSIC_NONPOW2_YSIZE_SPRITES
1925
#  define NONPOW2_YSIZE_ASM
1926
# endif
3031 helixhorne 1927
#endif
5 Plagman 1928
 
3031 helixhorne 1929
 
5 Plagman 1930
//
1931
// maskwallscan (internal)
1932
//
4161 helixhorne 1933
static void maskwallscan(int32_t x1, int32_t x2, int32_t saturatevplc)
5 Plagman 1934
{
5300 terminx 1935
    if (globalshiftval < 0) return;
3481 helixhorne 1936
    if ((uwall[x1] > ydimen) && (uwall[x2] > ydimen)) return;
1937
    if ((dwall[x1] < 0) && (dwall[x2] < 0)) return;
5 Plagman 1938
 
7694 terminx 1939
    vec2_16_t tsiz = tilesiz[globalpicnum];
5300 terminx 1940
    if ((tsiz.x <= 0) || (tsiz.y <= 0)) return;
1941
 
1942
    setgotpic(globalpicnum);
1943
 
6830 terminx 1944
    if (waloff[globalpicnum] == 0) tileLoad(globalpicnum);
5 Plagman 1945
 
4623 terminx 1946
    tweak_tsizes(&tsiz);
5 Plagman 1947
 
4680 terminx 1948
    if (EDUKE32_PREDICT_FALSE(palookup[globalpal] == NULL))
355 terminx 1949
        globalpal = 0;
1950
 
5300 terminx 1951
    intptr_t const fpalookup = FP_OFF(palookup[globalpal]);
5 Plagman 1952
 
4161 helixhorne 1953
    setupmvlineasm(globalshiftval, saturatevplc);
5 Plagman 1954
 
5300 terminx 1955
    int32_t x = x1;
5800 terminx 1956
    while ((x <= x2) && (startumost[x+windowxy1.x] > startdmost[x+windowxy1.x]))
3472 helixhorne 1957
        x++;
5 Plagman 1958
 
5300 terminx 1959
    intptr_t p = x+frameoffset;
5 Plagman 1960
 
5300 terminx 1961
    int32_t y1ve[4], y2ve[4];
1962
 
3031 helixhorne 1963
#ifdef NONPOW2_YSIZE_ASM
2807 helixhorne 1964
    if (globalshiftval==0)
1965
        goto do_mvlineasm1;
1966
#endif
1967
 
3311 helixhorne 1968
#ifdef MULTI_COLUMN_VLINE
1229 terminx 1969
    for (; (x<=x2)&&(p&3); x++,p++)
5 Plagman 1970
    {
7078 terminx 1971
        y1ve[0] = max<int>(uwall[x],startumost[x+windowxy1.x]-windowxy1.y);
1972
        y2ve[0] = min<int>(dwall[x],startdmost[x+windowxy1.x]-windowxy1.y);
5 Plagman 1973
        if (y2ve[0] <= y1ve[0]) continue;
1974
 
3481 helixhorne 1975
        palookupoffse[0] = fpalookup + getpalookupsh(mulscale16(swall[x],globvis));
5 Plagman 1976
 
4623 terminx 1977
        calc_bufplc(&bufplce[0], lwall[x], tsiz);
3483 helixhorne 1978
        calc_vplcinc(&vplce[0], &vince[0], swall, x, y1ve[0]);
5 Plagman 1979
 
3482 helixhorne 1980
        mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0],p+ylookup[y1ve[0]]);
5 Plagman 1981
    }
1229 terminx 1982
    for (; x<=x2-3; x+=4,p+=4)
5 Plagman 1983
    {
5300 terminx 1984
        char bad = 0;
3311 helixhorne 1985
 
5829 terminx 1986
        for (bssize_t z=3,dax=x+3; z>=0; z--,dax--)
5 Plagman 1987
        {
7078 terminx 1988
            y1ve[z] = max<int>(uwall[dax],startumost[dax+windowxy1.x]-windowxy1.y);
1989
            y2ve[z] = min<int>(dwall[dax],startdmost[dax+windowxy1.x]-windowxy1.y)-1;
5 Plagman 1990
            if (y2ve[z] < y1ve[z]) { bad += pow2char[z]; continue; }
1991
 
4623 terminx 1992
            calc_bufplc(&bufplce[z], lwall[dax], tsiz);
3483 helixhorne 1993
            calc_vplcinc(&vplce[z], &vince[z], swall, dax, y1ve[z]);
5 Plagman 1994
        }
1995
        if (bad == 15) continue;
1996
 
3481 helixhorne 1997
        palookupoffse[0] = fpalookup + getpalookupsh(mulscale16(swall[x],globvis));
1998
        palookupoffse[3] = fpalookup + getpalookupsh(mulscale16(swall[x+3],globvis));
5 Plagman 1999
 
2000
        if ((palookupoffse[0] == palookupoffse[3]) && ((bad&0x9) == 0))
2001
        {
2002
            palookupoffse[1] = palookupoffse[0];
2003
            palookupoffse[2] = palookupoffse[0];
2004
        }
2005
        else
2006
        {
3481 helixhorne 2007
            palookupoffse[1] = fpalookup + getpalookupsh(mulscale16(swall[x+1],globvis));
2008
            palookupoffse[2] = fpalookup + getpalookupsh(mulscale16(swall[x+2],globvis));
5 Plagman 2009
        }
2010
 
5300 terminx 2011
        int32_t const u4 = max(max(y1ve[0],y1ve[1]),max(y1ve[2],y1ve[3]));
2012
        int32_t const d4 = min(min(y2ve[0],y2ve[1]),min(y2ve[2],y2ve[3]));
5 Plagman 2013
 
2014
        if ((bad > 0) || (u4 >= d4))
2015
        {
2016
            if (!(bad&1)) mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0],vplce[0],bufplce[0],ylookup[y1ve[0]]+p+0);
2017
            if (!(bad&2)) mvlineasm1(vince[1],palookupoffse[1],y2ve[1]-y1ve[1],vplce[1],bufplce[1],ylookup[y1ve[1]]+p+1);
2018
            if (!(bad&4)) mvlineasm1(vince[2],palookupoffse[2],y2ve[2]-y1ve[2],vplce[2],bufplce[2],ylookup[y1ve[2]]+p+2);
2019
            if (!(bad&8)) mvlineasm1(vince[3],palookupoffse[3],y2ve[3]-y1ve[3],vplce[3],bufplce[3],ylookup[y1ve[3]]+p+3);
2020
            continue;
2021
        }
2022
 
2023
        if (u4 > y1ve[0]) vplce[0] = mvlineasm1(vince[0],palookupoffse[0],u4-y1ve[0]-1,vplce[0],bufplce[0],ylookup[y1ve[0]]+p+0);
2024
        if (u4 > y1ve[1]) vplce[1] = mvlineasm1(vince[1],palookupoffse[1],u4-y1ve[1]-1,vplce[1],bufplce[1],ylookup[y1ve[1]]+p+1);
2025
        if (u4 > y1ve[2]) vplce[2] = mvlineasm1(vince[2],palookupoffse[2],u4-y1ve[2]-1,vplce[2],bufplce[2],ylookup[y1ve[2]]+p+2);
2026
        if (u4 > y1ve[3]) vplce[3] = mvlineasm1(vince[3],palookupoffse[3],u4-y1ve[3]-1,vplce[3],bufplce[3],ylookup[y1ve[3]]+p+3);
2027
 
3114 helixhorne 2028
        if (d4 >= u4) mvlineasm4(d4-u4+1, (char *)(ylookup[u4]+p));
5 Plagman 2029
 
5300 terminx 2030
        intptr_t const pp = p+ylookup[d4+1];
2031
 
2497 helixhorne 2032
        if (y2ve[0] > d4) mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-d4-1,vplce[0],bufplce[0],pp+0);
2033
        if (y2ve[1] > d4) mvlineasm1(vince[1],palookupoffse[1],y2ve[1]-d4-1,vplce[1],bufplce[1],pp+1);
2034
        if (y2ve[2] > d4) mvlineasm1(vince[2],palookupoffse[2],y2ve[2]-d4-1,vplce[2],bufplce[2],pp+2);
2035
        if (y2ve[3] > d4) mvlineasm1(vince[3],palookupoffse[3],y2ve[3]-d4-1,vplce[3],bufplce[3],pp+3);
5 Plagman 2036
    }
3311 helixhorne 2037
#endif
2038
 
3031 helixhorne 2039
#ifdef NONPOW2_YSIZE_ASM
2807 helixhorne 2040
do_mvlineasm1:
2041
#endif
1229 terminx 2042
    for (; x<=x2; x++,p++)
5 Plagman 2043
    {
7078 terminx 2044
        y1ve[0] = max<int>(uwall[x],startumost[x+windowxy1.x]-windowxy1.y);
2045
        y2ve[0] = min<int>(dwall[x],startdmost[x+windowxy1.x]-windowxy1.y);
5 Plagman 2046
        if (y2ve[0] <= y1ve[0]) continue;
2047
 
3481 helixhorne 2048
        palookupoffse[0] = fpalookup + getpalookupsh(mulscale16(swall[x],globvis));
5 Plagman 2049
 
4623 terminx 2050
        calc_bufplc(&bufplce[0], lwall[x], tsiz);
3483 helixhorne 2051
        calc_vplcinc(&vplce[0], &vince[0], swall, x, y1ve[0]);
5 Plagman 2052
 
3031 helixhorne 2053
#ifdef NONPOW2_YSIZE_ASM
2807 helixhorne 2054
        if (globalshiftval==0)
3482 helixhorne 2055
            mvlineasm1nonpow2(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0],p+ylookup[y1ve[0]]);
2807 helixhorne 2056
        else
2057
#endif
3482 helixhorne 2058
        mvlineasm1(vince[0],palookupoffse[0],y2ve[0]-y1ve[0]-1,vplce[0],bufplce[0],p+ylookup[y1ve[0]]);
5 Plagman 2059
    }
2060
 
2061
    faketimerhandler();
2062
}
2063
 
2064
 
2065
//
2066
// wallfront (internal)
2067
//
1205 terminx 2068
int32_t wallfront(int32_t l1, int32_t l2)
5 Plagman 2069
{
7697 terminx 2070
    vec2_t const l1vect   = wall[thewall[l1]].pos;
2071
    vec2_t const l1p2vect = wall[wall[thewall[l1]].point2].pos;
2072
    vec2_t const l2vect   = wall[thewall[l2]].pos;
2073
    vec2_t const l2p2vect = wall[wall[thewall[l2]].point2].pos;
5079 terminx 2074
    vec2_t d = { l1p2vect.x - l1vect.x, l1p2vect.y - l1vect.y };
2075
    int32_t t1 = dmulscale2(l2vect.x-l1vect.x, d.y, -d.x, l2vect.y-l1vect.y); //p1(l2) vs. l1
2076
    int32_t t2 = dmulscale2(l2p2vect.x-l1vect.x, d.y, -d.x, l2p2vect.y-l1vect.y); //p2(l2) vs. l1
5 Plagman 2077
 
4675 terminx 2078
    if (t1 == 0) { if (t2 == 0) return -1; t1 = t2; }
2079
    if (t2 == 0) t2 = t1;
5 Plagman 2080
 
4675 terminx 2081
    if ((t1^t2) >= 0) //pos vs. l1
5079 terminx 2082
        return (dmulscale2(globalposx-l1vect.x, d.y, -d.x, globalposy-l1vect.y) ^ t1) >= 0;
4675 terminx 2083
 
5079 terminx 2084
    d.x = l2p2vect.x-l2vect.x;
2085
    d.y = l2p2vect.y-l2vect.y;
4675 terminx 2086
 
5079 terminx 2087
    t1 = dmulscale2(l1vect.x-l2vect.x, d.y, -d.x, l1vect.y-l2vect.y); //p1(l1) vs. l2
2088
    t2 = dmulscale2(l1p2vect.x-l2vect.x, d.y, -d.x, l1p2vect.y-l2vect.y); //p2(l1) vs. l2
4675 terminx 2089
 
2090
    if (t1 == 0) { if (t2 == 0) return -1; t1 = t2; }
5 Plagman 2091
    if (t2 == 0) t2 = t1;
2092
 
4675 terminx 2093
    if ((t1^t2) >= 0) //pos vs. l2
5079 terminx 2094
        return (dmulscale2(globalposx-l2vect.x,d.y,-d.x,globalposy-l2vect.y) ^ t1) < 0;
4675 terminx 2095
 
2096
    return -2;
5 Plagman 2097
}
2098
 
2099
//
2100
// spritewallfront (internal)
2101
//
7603 terminx 2102
static inline int32_t spritewallfront(uspriteptr_t s, int32_t w)
5 Plagman 2103
{
7603 terminx 2104
    auto const wal = (uwallptr_t)&wall[w];
2105
    auto const wal2 = (uwallptr_t)&wall[wal->point2];
5079 terminx 2106
    const vec2_t v = { wal->x, wal->y };
5 Plagman 2107
 
5079 terminx 2108
    return dmulscale32(wal2->x - v.x, s->y - v.y, -(s->x - v.x), wal2->y - v.y) >= 0;
5 Plagman 2109
}
2110
 
2111
//
2112
//  spritebehindwall(internal)
2113
//
654 terminx 2114
#if 0
1205 terminx 2115
static int32_t spriteobstructswall(spritetype *s, int32_t w)
5 Plagman 2116
{
2117
    walltype *wal;
1205 terminx 2118
    int32_t x, y;
2119
    int32_t x1, y1;
2120
    int32_t x2, y2;
5 Plagman 2121
    double a1, b1, c1;
2122
    double a2, b2, c2;
2123
    double d1, d2;
2124
 
2125
    // wall line equation
2126
    wal = &wall[w]; x1 = wal->x - globalposx; y1 = wal->y - globalposy;
2127
    wal = &wall[wal->point2]; x2 = wal->x - globalposx; y2 = wal->y - globalposy;
2128
    if ((x2 - x1) != 0)
2129
        a1 = (float)(y2 - y1)/(x2 - x1);
2130
    else
2131
        a1 = 1e+37; // not infinite, but almost ;)
2132
    b1 = -1;
2133
    c1 = (y1 - (a1 * x1));
109 terminx 2134
 
5 Plagman 2135
    // player to sprite line equation
2136
    if ((s->x - globalposx) != 0)
2137
        a2 = (float)(s->y - globalposy)/(s->x - globalposx);
2138
    else
2139
        a2 = 1e+37;
2140
    b2 = -1;
2141
    c2 = 0;
109 terminx 2142
 
5 Plagman 2143
    // intersection point
2144
    d1 = (float)(1) / (a1*b2 - a2*b1);
2145
    x = ((b1*c2 - b2*c1) * d1);
2146
    y = ((a2*c1 - a1*c2) * d1);
2147
 
2148
    // distance between the sprite and the player
2149
    a1 = s->x - globalposx;
2150
    b1 = s->y - globalposy;
2151
    d1 = (a1 * a1 + b1 * b1);
109 terminx 2152
 
5 Plagman 2153
    // distance between the intersection point and the player
2154
    d2 = (x * x + y * y);
109 terminx 2155
 
5 Plagman 2156
    // check if the sprite obstructs the wall
2157
    if ((d1 < d2) && (min(x1, x2) <= x) && (x <= max(x1, x2)) && (min(y1, y2) <= y) && (y <= max(y1, y2)))
5803 terminx 2158
        return 1;
5 Plagman 2159
    else
5803 terminx 2160
        return 0;
5 Plagman 2161
}
654 terminx 2162
#endif
5 Plagman 2163
//
2164
// bunchfront (internal)
2165
//
1221 terminx 2166
static inline int32_t bunchfront(int32_t b1, int32_t b2)
5 Plagman 2167
{
5079 terminx 2168
    int b1f = bunchfirst[b1];
2169
    int const x1b1 = xb1[b1f];
2170
    int const x2b2 = xb2[bunchlast[b2]] + 1;
5 Plagman 2171
 
5079 terminx 2172
    if (x1b1 >= x2b2)
5803 terminx 2173
        return -1;
5 Plagman 2174
 
5079 terminx 2175
    int b2f = bunchfirst[b2];
2176
    int const x1b2 = xb1[b2f];
2177
    int const x2b1 = xb2[bunchlast[b1]] + 1;
2178
 
2179
    if (x1b2 >= x2b1)
5803 terminx 2180
        return -1;
5079 terminx 2181
 
5 Plagman 2182
    if (x1b1 >= x1b2)
2183
    {
5556 hendricks2 2184
        for (; xb2[b2f] < x1b1; b2f = bunchp2[b2f]) { }
5079 terminx 2185
        return wallfront(b1f, b2f);
5 Plagman 2186
    }
5079 terminx 2187
 
5556 hendricks2 2188
    for (; xb2[b1f] < x1b2; b1f = bunchp2[b1f]) { }
5079 terminx 2189
    return wallfront(b1f, b2f);
5 Plagman 2190
}
2191
 
2192
 
2193
//
2194
// hline (internal)
2195
//
1221 terminx 2196
static inline void hline(int32_t xr, int32_t yp)
5 Plagman 2197
{
5300 terminx 2198
    int32_t const xl = lastx[yp];
2199
    if (xl > xr) return;
2200
    int32_t const r = horizlookup2[yp-globalhoriz+horizycent];
7714 terminx 2201
    asm1 = (inthi_t)mulscale6(globalx1, r);
2202
    asm2 = (inthi_t)mulscale6(globaly2, r);
2203
    int32_t const s = getpalookupsh(mulscale22(r,globvis));
5 Plagman 2204
 
7714 terminx 2205
    hlineasm4(xr-xl,0,s,(uint32_t)mulscale6(globalx2,r)+globalypanning,(uint32_t)mulscale6(globaly1,r)+globalxpanning,
109 terminx 2206
              ylookup[yp]+xr+frameoffset);
5 Plagman 2207
}
2208
 
2209
 
2210
//
2211
// slowhline (internal)
2212
//
1221 terminx 2213
static inline void slowhline(int32_t xr, int32_t yp)
5 Plagman 2214
{
5300 terminx 2215
    int32_t const xl = lastx[yp]; if (xl > xr) return;
2216
    int32_t const r = horizlookup2[yp-globalhoriz+horizycent];
7714 terminx 2217
    asm1 = (inthi_t)mulscale6(globalx1, r);
2218
    asm2 = (inthi_t)mulscale6(globaly2, r);
5 Plagman 2219
 
7714 terminx 2220
    asm3 = (intptr_t)globalpalwritten + getpalookupsh(mulscale22(r,globvis));
5 Plagman 2221
    if (!(globalorientation&256))
2222
    {
7714 terminx 2223
        mhline(globalbufplc,(uint32_t)mulscale6(globaly1,r)+globalxpanning-asm1*(xr-xl),(xr-xl)<<16,0L,
2224
               (uint32_t)mulscale6(globalx2,r)+globalypanning-asm2*(xr-xl),ylookup[yp]+xl+frameoffset);
5 Plagman 2225
        return;
2226
    }
7714 terminx 2227
    thline(globalbufplc,(uint32_t)mulscale6(globaly1,r)+globalxpanning-asm1*(xr-xl),(xr-xl)<<16,0L,
2228
           (uint32_t)mulscale6(globalx2,r)+globalypanning-asm2*(xr-xl),ylookup[yp]+xl+frameoffset);
5 Plagman 2229
}
2230
 
2231
 
2232
//
2233
// prepwall (internal)
2234
//
7603 terminx 2235
static void prepwall(int32_t z, uwallptr_t wal)
5 Plagman 2236
{
2740 helixhorne 2237
    int32_t l=0, ol=0, x;
5 Plagman 2238
 
2740 helixhorne 2239
    int32_t walxrepeat = (wal->xrepeat<<3);
5 Plagman 2240
 
109 terminx 2241
    //lwall calculation
2740 helixhorne 2242
    int32_t tmpx = xb1[z]-halfxdimen;
5 Plagman 2243
 
2740 helixhorne 2244
    const int32_t topinc = -(ry1[z]>>2);
2245
    const int32_t botinc = (ry2[z]-ry1[z])>>8;
2246
    int32_t top = mulscale5(rx1[z],xdimen) + mulscale2(topinc,tmpx);
2247
    int32_t bot = mulscale11(rx1[z]-rx2[z],xdimen) + mulscale2(botinc,tmpx);
5 Plagman 2248
 
2740 helixhorne 2249
    const int32_t splc = mulscale19(ry1[z],xdimscale);
2250
    const int32_t sinc = mulscale16(ry2[z]-ry1[z],xdimscale);
2251
 
5 Plagman 2252
    x = xb1[z];
2253
    if (bot != 0)
2254
    {
2255
        l = divscale12(top,bot);
2256
        swall[x] = mulscale21(l,sinc)+splc;
2257
        l *= walxrepeat;
2258
        lwall[x] = (l>>18);
2259
    }
2260
    while (x+4 <= xb2[z])
2261
    {
2740 helixhorne 2262
        int32_t i;
2263
 
5 Plagman 2264
        top += topinc; bot += botinc;
2265
        if (bot != 0)
2266
        {
2267
            ol = l; l = divscale12(top,bot);
2268
            swall[x+4] = mulscale21(l,sinc)+splc;
2269
            l *= walxrepeat;
2270
            lwall[x+4] = (l>>18);
2271
        }
2740 helixhorne 2272
 
2273
        i = (ol+l)>>1;
2274
 
2275
        lwall[x+2] = i>>18;
2276
        lwall[x+1] = (ol+i)>>19;
2277
        lwall[x+3] = (l+i)>>19;
2278
 
2279
        swall[x+2] = (swall[x]+swall[x+4])>>1;
2280
        swall[x+1] = (swall[x]+swall[x+2])>>1;
2281
        swall[x+3] = (swall[x+4]+swall[x+2])>>1;
2282
 
5 Plagman 2283
        x += 4;
2284
    }
2285
    if (x+2 <= xb2[z])
2286
    {
2287
        top += (topinc>>1); bot += (botinc>>1);
2288
        if (bot != 0)
2289
        {
2290
            ol = l; l = divscale12(top,bot);
2291
            swall[x+2] = mulscale21(l,sinc)+splc;
2292
            l *= walxrepeat;
2293
            lwall[x+2] = (l>>18);
2294
        }
2740 helixhorne 2295
        lwall[x+1] = (l+ol)>>19;
2296
        swall[x+1] = (swall[x]+swall[x+2])>>1;
5 Plagman 2297
        x += 2;
2298
    }
2299