Subversion Repositories eduke32

Rev

Rev 5035 | Rev 5056 | 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)
5 Plagman 7
 
8
 
9
#define ENGINE
10
 
3687 terminx 11
#if (PNG_LIBPNG_VER > 10599)
12
# include <string.h>
13
#endif
5 Plagman 14
#include "compat.h"
15
#include "build.h"
4890 terminx 16
#include "editor.h"
5 Plagman 17
#include "pragmas.h"
18
#include "cache1d.h"
19
#include "a.h"
20
#include "osd.h"
21
#include "crc32.h"
4387 terminx 22
#include "xxhash.h"
4316 hendricks2 23
#include "lz4.h"
5 Plagman 24
 
25
#include "baselayer.h"
1155 terminx 26
#include "scriptfile.h"
5 Plagman 27
 
1820 terminx 28
#ifdef USE_OPENGL
2060 hendricks2 29
# include "glbuild.h"
30
# include "mdsprite.h"
31
# ifdef POLYMER
32
#  include "polymer.h"
1173 terminx 33
# endif
34
# include "hightile.h"
35
# include "polymost.h"
5 Plagman 36
# ifdef _WIN32
37
#  define WIN32_LEAN_AND_MEAN
38
#  include <windows.h>
39
# endif
40
#endif
41
 
1852 helixhorne 42
#ifdef USE_LIBPNG
43
//# include <setjmp.h>
44
# include <png.h>
45
#endif
46
 
2985 helixhorne 47
#include <math.h>  // pow
5 Plagman 48
 
1173 terminx 49
#include "engine_priv.h"
5 Plagman 50
 
3733 helixhorne 51
#ifdef LUNATIC
52
# include "lunatic.h"
53
L_State g_engState;
54
#endif
55
 
1658 terminx 56
#define CACHEAGETIME 16
57
 
4960 helixhorne 58
//////////
59
// Compilation switches for optional/extended engine features
60
 
4606 terminx 61
#if !defined(__arm__) && !defined(GEKKO)
4960 helixhorne 62
# define HIGH_PRECISION_SPRITE
4606 terminx 63
#endif
64
 
4960 helixhorne 65
#if !defined EDUKE32_TOUCH_DEVICES && !defined GEKKO && !defined __OPENDINGUX__
66
// Handle absolute z difference of floor/ceiling to camera >= 1<<24.
5017 helixhorne 67
// Also: higher precision view-relative x and y for drawvox().
4960 helixhorne 68
# define CLASSIC_Z_DIFF_64
69
#endif
70
 
3311 helixhorne 71
#define MULTI_COLUMN_VLINE
3310 helixhorne 72
//#define DEBUG_TILESIZY_512
3777 helixhorne 73
//#define DEBUG_TILEOFFSETS
4960 helixhorne 74
//////////
3310 helixhorne 75
 
3932 helixhorne 76
#ifdef LUNATIC
77
# if !defined DEBUG_MAIN_ARRAYS
78
LUNATIC_EXTERN const int32_t engine_main_arrays_are_static = 0;  // for Lunatic
79
# else
80
LUNATIC_EXTERN const int32_t engine_main_arrays_are_static = 1;
81
# endif
2270 helixhorne 82
 
2668 helixhorne 83
#if MAXSECTORS==MAXSECTORSV8
3932 helixhorne 84
LUNATIC_EXTERN const int32_t engine_v8 = 1;
2668 helixhorne 85
#else
3932 helixhorne 86
LUNATIC_EXTERN const int32_t engine_v8 = 0;
2668 helixhorne 87
#endif
4315 hendricks2 88
#endif
2668 helixhorne 89
 
3349 terminx 90
#ifdef DEBUGGINGAIDS
1702 plagman 91
float debug1, debug2;
3349 terminx 92
#endif
1702 plagman 93
 
3841 helixhorne 94
int32_t mapversion=7; // JBF 20040211: default mapversion to 7
3911 helixhorne 95
int32_t g_loadedMapVersion = -1;  // -1: none (e.g. started new)
4933 helixhorne 96
usermaphack_t g_loadedMapHack;  // used only for the MD4 part
3841 helixhorne 97
 
4884 hendricks2 98
int32_t compare_usermaphacks(const void *a, const void *b)
99
{
100
    return Bmemcmp(((usermaphack_t*) a)->md4, ((usermaphack_t*) b)->md4, 16);
101
}
102
usermaphack_t *usermaphacks;
103
int32_t num_usermaphacks;
104
 
3841 helixhorne 105
static int32_t get_mapversion(void);
106
 
3926 helixhorne 107
// Handle nonpow2-ysize walls the old way?
3841 helixhorne 108
static inline int32_t oldnonpow2(void)
109
{
110
#if !defined CLASSIC_NONPOW2_YSIZE_WALLS
111
    return 1;
112
#else
3926 helixhorne 113
    return (g_loadedMapVersion < 10);
3841 helixhorne 114
#endif
115
}
116
 
1762 terminx 117
static void drawpixel_safe(void *s, char a)
1718 helixhorne 118
{
1733 helixhorne 119
#if defined __GNUC__
120
    if (__builtin_expect((intptr_t)s >= frameplace && (intptr_t)s < frameplace+bytesperline*ydim, 1))
121
#else
1718 helixhorne 122
    if ((intptr_t)s >= frameplace && (intptr_t)s < frameplace+bytesperline*ydim)
1733 helixhorne 123
#endif
1718 helixhorne 124
        drawpixel(s, a);
125
#ifdef DEBUGGINGAIDS
126
    else
127
    {
2501 helixhorne 128
        const char c = editorcolors[15];
129
 
130
        drawpixel((intptr_t *)frameplace, c);
131
        drawpixel((intptr_t *)frameplace+1, c);
132
        drawpixel((intptr_t *)frameplace+2, c);
133
        drawpixel((intptr_t *)frameplace+bytesperline, c);
134
        drawpixel((intptr_t *)frameplace+bytesperline+1, c);
135
        drawpixel((intptr_t *)frameplace+bytesperline+2, c);
136
        drawpixel((intptr_t *)frameplace+2*bytesperline, c);
137
        drawpixel((intptr_t *)frameplace+2*bytesperline+1, c);
138
        drawpixel((intptr_t *)frameplace+2*bytesperline+2, c);
1718 helixhorne 139
    }
140
#endif
141
}
142
 
2079 helixhorne 143
//void loadvoxel(int32_t voxindex) { UNREFERENCED_PARAMATER(voxindex); }
2266 helixhorne 144
int16_t tiletovox[MAXTILES];
1205 terminx 145
int32_t usevoxels = 1;
4836 helixhorne 146
#ifdef USE_OPENGL
147
static char *voxfilenames[MAXVOXELS], g_haveVoxels=0;  // for deferred voxel->model conversion
148
#endif
2079 helixhorne 149
//#define kloadvoxel loadvoxel
5 Plagman 150
 
1908 helixhorne 151
int32_t novoxmips = 1;
1205 terminx 152
int32_t editorgridextent = 131072;
5 Plagman 153
 
109 terminx 154
//These variables need to be copied into BUILD
5 Plagman 155
#define MAXXSIZ 256
156
#define MAXYSIZ 256
157
#define MAXZSIZ 255
158
#define MAXVOXMIPS 5
4881 helixhorne 159
#ifdef EDUKE32_TOUCH_DEVICES
160
# define DISTRECIPSIZ (65536+256)
161
#else
162
# define DISTRECIPSIZ 131072
163
#endif
4555 hendricks2 164
intptr_t voxoff[MAXVOXELS][MAXVOXMIPS]; // used in KenBuild
2463 helixhorne 165
static char voxlock[MAXVOXELS][MAXVOXMIPS];
1205 terminx 166
int32_t voxscale[MAXVOXELS];
5 Plagman 167
 
1205 terminx 168
static int32_t ggxinc[MAXXSIZ+1], ggyinc[MAXXSIZ+1];
4658 terminx 169
static int32_t lowrecip[1024], nytooclose;
4881 helixhorne 170
static const int32_t nytoofar = DISTRECIPSIZ*16384ull - 1048576;
4695 terminx 171
static uint32_t *distrecip;
5 Plagman 172
 
2701 helixhorne 173
static int32_t *lookups = NULL;
2391 helixhorne 174
static int32_t dommxoverlay = 1, beforedrawrooms = 1;
175
int32_t indrawroomsandmasks = 0;
5 Plagman 176
 
1205 terminx 177
static int32_t oxdimen = -1, oviewingrange = -1, oxyaspect = -1;
5 Plagman 178
 
1712 helixhorne 179
// r_usenewaspect is the cvar, newaspect_enable to trigger the new behaviour in the code
1957 helixhorne 180
int32_t r_usenewaspect = 1, newaspect_enable=0;
2959 helixhorne 181
uint32_t r_screenxy = 0;
1712 helixhorne 182
 
1205 terminx 183
int32_t curbrightness = 0, gammabrightness = 0;
5 Plagman 184
 
4606 terminx 185
float vid_gamma = DEFAULT_GAMMA;
186
float vid_contrast = DEFAULT_CONTRAST;
187
float vid_brightness = DEFAULT_BRIGHTNESS;
877 terminx 188
 
109 terminx 189
//Textured Map variables
5 Plagman 190
static char globalpolytype;
4695 terminx 191
static int16_t **dotp1, **dotp2;
5 Plagman 192
 
1205 terminx 193
static int8_t tempbuf[MAXWALLS];
5 Plagman 194
 
3172 helixhorne 195
// referenced from asm
4324 hendricks2 196
#if !defined(NOASM) && defined __cplusplus
197
extern "C" {
198
#endif
1205 terminx 199
int32_t ebpbak, espbak;
3172 helixhorne 200
int32_t reciptable[2048], fpuasm;
201
intptr_t asm1, asm2, asm3, asm4, palookupoffse[4];
202
uint32_t vplce[4];
203
int32_t vince[4];
204
intptr_t bufplce[4];
205
int32_t globaltilesizy;
206
int32_t globalx1, globaly2, globalx3, globaly3;
4324 hendricks2 207
#if !defined(NOASM) && defined __cplusplus
4766 hendricks2 208
}
4324 hendricks2 209
#endif
3172 helixhorne 210
 
4714 terminx 211
int32_t sloptable[16384];
1969 helixhorne 212
static intptr_t slopalookup[16384];    // was 2048
5 Plagman 213
#if defined(USE_OPENGL)
1173 terminx 214
palette_t palookupfog[MAXPALOOKUPS];
5 Plagman 215
#endif
216
 
4811 helixhorne 217
// For every pal number, whether tsprite pal should not be taken over from
218
// floor pal.
219
// NOTE: g_noFloorPal[0] is irrelevant as it's never checked.
220
int8_t g_noFloorPal[MAXPALOOKUPS];
221
 
1969 helixhorne 222
static void *pic = NULL;
4223 helixhorne 223
 
224
// The tile file number (tilesXXX <- this) of each tile:
4257 helixhorne 225
// 0 <= . < MAXARTFILES_BASE: tile is in a "base" ART file
226
// MAXARTFILES_BASE <= . < MAXARTFILES_TOTAL: tile is in a map-specific ART file
4223 helixhorne 227
static uint8_t tilefilenum[MAXTILES];
4257 helixhorne 228
EDUKE32_STATIC_ASSERT(MAXARTFILES_TOTAL <= 256);
4223 helixhorne 229
 
1969 helixhorne 230
static int32_t tilefileoffs[MAXTILES];
231
static int32_t lastageclock;
5 Plagman 232
 
4257 helixhorne 233
// Backup tilefilenum[] and tilefileoffs[]. These get allocated only when
234
// necessary (have per-map ART files).
235
static uint8_t *g_bakTileFileNum;
236
static int32_t *g_bakTileFileOffs;
4623 terminx 237
static vec2_t *g_bakTileSiz;
4257 helixhorne 238
static picanm_t *g_bakPicAnm;
239
// NOTE: picsiz[] is not backed up, but recalculated when necessary.
5 Plagman 240
 
4257 helixhorne 241
//static int32_t artsize = 0;
242
static int32_t cachesize = 0;
243
 
2463 helixhorne 244
// Whole ART file contents loaded from ZIPs in memory.
4257 helixhorne 245
static char *artptrs[MAXARTFILES_TOTAL];
1586 terminx 246
 
2990 helixhorne 247
static int32_t no_radarang2 = 0;
4695 terminx 248
static int16_t radarang[1280], *radarang2;
3116 hendricks2 249
 
250
uint16_t ATTRIBUTE((used)) sqrtable[4096], ATTRIBUTE((used)) shlookup[4096+256];
3326 helixhorne 251
const char pow2char[8] = {1,2,4,8,16,32,64,128};
252
const int32_t pow2long[32] =
584 terminx 253
{
3326 helixhorne 254
    1, 2, 4, 8,
255
    16, 32, 64, 128,
256
    256, 512, 1024, 2048,
257
    4096, 8192, 16384, 32768,
258
    65536, 131072, 262144, 524288,
259
    1048576, 2097152, 4194304, 8388608,
260
    16777216, 33554432, 67108864, 134217728,
261
    268435456, 536870912, 1073741824, 2147483647
262
};
3116 hendricks2 263
 
5 Plagman 264
char britable[16][256]; // JBF 20040207: full 8bit precision
265
 
1173 terminx 266
extern char textfont[2048], smalltextfont[2048];
267
 
5 Plagman 268
static char kensmessage[128];
1799 helixhorne 269
const char *engineerrstr = "No error";
5 Plagman 270
 
1544 terminx 271
int32_t showfirstwall=0;
4007 helixhorne 272
int32_t showheightindicators=1;
1544 terminx 273
int32_t circlewall=-1;
274
 
1647 terminx 275
int32_t whitecol;
276
 
1760 helixhorne 277
#ifdef POLYMER
278
static int16_t maphacklightcnt=0;
279
static int16_t maphacklight[PR_MAXLIGHTS];
280
#endif
1719 helixhorne 281
 
1830 helixhorne 282
// forward refs
4766 hendricks2 283
#ifdef __cplusplus
284
extern "C" {
285
#endif
286
void setblendtab(int32_t blend, const char *tab);
287
#ifdef LUNATIC
288
extern const char *(getblendtab)(int32_t blend);
289
int32_t setpalookup(int32_t palnum, const uint8_t *shtab);
290
#endif
291
void setup_sideview_sincos(void);
3137 Plagman 292
int32_t getscreenvdisp(int32_t bz, int32_t zoome);
1830 helixhorne 293
void screencoords(int32_t *xres, int32_t *yres, int32_t x, int32_t y, int32_t zoome);
4766 hendricks2 294
int32_t scalescreeny(int32_t sy);
295
#ifdef YAX_ENABLE
296
void yax_tweakpicnums(int32_t bunchnum, int32_t cf, int32_t restore);
297
#endif
298
int32_t getinvdisplacement(int32_t *dx, int32_t *dy, int32_t dz);
299
#ifdef __cplusplus
300
}
301
#endif
1816 helixhorne 302
 
4454 helixhorne 303
static void scansector(int16_t startsectnum);
2513 helixhorne 304
static void draw_rainbow_background(void);
1874 helixhorne 305
 
1843 helixhorne 306
int16_t editstatus = 0;
2880 helixhorne 307
static int32_t global100horiz;  // (-100..300)-scale horiz (the one passed to drawrooms)
1830 helixhorne 308
 
1843 helixhorne 309
 
1816 helixhorne 310
////////// YAX //////////
1843 helixhorne 311
 
1899 helixhorne 312
int32_t numgraysects = 0;
1877 helixhorne 313
uint8_t graysectbitmap[MAXSECTORS>>3];
314
uint8_t graywallbitmap[MAXWALLS>>3];
1928 helixhorne 315
int32_t autogray = 0, showinnergray = 1;
1877 helixhorne 316
 
2740 helixhorne 317
//#define YAX_DEBUG_YMOSTS
318
 
2026 helixhorne 319
#ifdef YAX_DEBUG
3935 helixhorne 320
// XXX: This could be replaced with the use of gethiticks().
3934 helixhorne 321
double u64tickspersec;
2026 helixhorne 322
#endif
1877 helixhorne 323
#ifdef ENGINE_SCREENSHOT_DEBUG
324
int32_t engine_screenshot = 0;
325
#endif
326
 
3623 helixhorne 327
int32_t get_alwaysshowgray(void)
328
{
329
    return showinnergray || !(editorzrange[0]==INT32_MIN && editorzrange[1]==INT32_MAX);
330
}
331
 
1877 helixhorne 332
void yax_updategrays(int32_t posze)
333
{
334
    int32_t i, j, k=1;
1890 helixhorne 335
#ifdef YAX_ENABLE
336
    int32_t mingoodz=INT32_MAX, maxgoodz=INT32_MIN;
337
#else
1877 helixhorne 338
    UNREFERENCED_PARAMETER(posze);
339
#endif
1890 helixhorne 340
 
1877 helixhorne 341
    Bmemset(graysectbitmap, 0, sizeof(graysectbitmap));
342
    Bmemset(graywallbitmap, 0, sizeof(graywallbitmap));
343
 
344
    for (i=0; i<numsectors; i++)
345
    {
1843 helixhorne 346
#ifdef YAX_ENABLE
1877 helixhorne 347
        int16_t cb, fb;
348
 
349
        yax_getbunches(i, &cb, &fb);
1890 helixhorne 350
        // update grayouts due to yax  --v-- has to be half-open  --v--
351
        // because only one level should v  be ever active          v
1877 helixhorne 352
        k = ((cb<0 || sector[i].ceilingz < posze) && (fb<0 || posze <= sector[i].floorz));
1890 helixhorne 353
        if (autogray && (cb>=0 || fb>=0) && (sector[i].ceilingz <= posze && posze <= sector[i].floorz))
354
        {
355
            mingoodz = min(mingoodz, sector[i].ceilingz);
356
            maxgoodz = max(maxgoodz, sector[i].floorz);
357
        }
1877 helixhorne 358
#endif
1886 helixhorne 359
        // update grayouts due to editorzrange
1877 helixhorne 360
        k &= (sector[i].ceilingz >= editorzrange[0] && sector[i].floorz <= editorzrange[1]);
361
 
362
        if (!k)  // outside bounds, gray out!
363
            graysectbitmap[i>>3] |= (1<<(i&7));
1890 helixhorne 364
    }
365
 
366
#ifdef YAX_ENABLE
367
    if (autogray && mingoodz<=maxgoodz)
368
    {
369
        for (i=0; i<numsectors; i++)
370
            if (!(mingoodz <= sector[i].ceilingz && sector[i].floorz <= maxgoodz))
371
                graysectbitmap[i>>3] |= (1<<(i&7));
372
    }
373
#endif
374
 
1899 helixhorne 375
    numgraysects = 0;
1890 helixhorne 376
    for (i=0; i<numsectors; i++)
377
    {
378
        if (graysectbitmap[i>>3]&(1<<(i&7)))
1899 helixhorne 379
        {
380
            numgraysects++;
1877 helixhorne 381
            for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
382
                graywallbitmap[j>>3] |= (1<<(j&7));
1899 helixhorne 383
        }
1877 helixhorne 384
    }
385
}
386
 
387
 
2204 helixhorne 388
#if !defined YAX_ENABLE
389
# warning Non-TROR builds are supported only for debugging. Expect savegame breakage etc...
390
#endif
391
 
1877 helixhorne 392
#ifdef YAX_ENABLE
1843 helixhorne 393
// all references to floor/ceiling bunchnums should be through the
394
// get/set functions!
395
 
2002 helixhorne 396
int32_t g_nodraw = 0;
1892 helixhorne 397
int32_t scansector_retfast = 0;
1877 helixhorne 398
static int32_t scansector_collectsprites = 1;
2024 helixhorne 399
int32_t yax_globalcf = -1, yax_nomaskpass=0, yax_nomaskdidit;  // engine internal
400
int32_t r_tror_nomaskpass = 1;  // cvar
2018 helixhorne 401
int32_t yax_globallev = YAX_MAXDRAWS;
402
int32_t yax_globalbunch = -1;
1874 helixhorne 403
 
1877 helixhorne 404
// duplicated tsprites
405
//  [i]:
406
//   i==MAXDRAWS: base level
407
//   i<MAXDRAWS: MAXDRAWS-i-1 is level towards ceiling
408
//   i>MAXDRAWS: i-MAXDRAWS-1 is level towards floor
409
static int16_t yax_spritesortcnt[1 + 2*YAX_MAXDRAWS];
2046 helixhorne 410
static uint16_t yax_tsprite[1 + 2*YAX_MAXDRAWS][MAXSPRITESONSCREEN];
411
static uint8_t yax_tsprfrombunch[1 + 2*YAX_MAXDRAWS][MAXSPRITESONSCREEN];
1877 helixhorne 412
 
2024 helixhorne 413
// drawn sectors
414
uint8_t yax_gotsector[MAXSECTORS>>3];  // engine internal
415
 
3658 helixhorne 416
# if !defined NEW_MAP_FORMAT
417
// Game-time YAX data structures, V7-V9 map formats.
1882 helixhorne 418
int16_t yax_bunchnum[MAXSECTORS][2];
419
int16_t yax_nextwall[MAXWALLS][2];
1843 helixhorne 420
 
4984 terminx 421
static inline int32_t yax_islockededge(int32_t line, int32_t cf)
1865 helixhorne 422
{
423
    return !!(wall[line].cstat&(YAX_NEXTWALLBIT(cf)));
424
}
425
 
2349 helixhorne 426
#define YAX_PTRBUNCHNUM(Ptr, Sect, Cf) (*(&Ptr[Sect].ceilingxpanning + 8*Cf))
427
#define YAX_BUNCHNUM(Sect, Cf) YAX_PTRBUNCHNUM(sector, Sect, Cf)
1865 helixhorne 428
 
429
//// bunch getters/setters
1816 helixhorne 430
int16_t yax_getbunch(int16_t i, int16_t cf)
431
{
1843 helixhorne 432
    if (editstatus==0)
433
        return yax_bunchnum[i][cf];
434
 
1816 helixhorne 435
    if (((*(&sector[i].ceilingstat + cf))&YAX_BIT)==0)
436
        return -1;
437
 
438
    return YAX_BUNCHNUM(i, cf);
439
}
3658 helixhorne 440
# else
441
#  define YAX_PTRBUNCHNUM(Ptr, Sect, Cf) (*((Cf) ? &(Ptr)[Sect].floorbunch : &(Ptr)[Sect].ceilingbunch))
442
#  define YAX_BUNCHNUM(Sect, Cf) YAX_PTRBUNCHNUM(sector, Sect, Cf)
1843 helixhorne 443
 
3658 helixhorne 444
#  if !defined NEW_MAP_FORMAT
4984 terminx 445
static inline int32_t yax_islockededge(int32_t line, int32_t cf)
3658 helixhorne 446
{
447
    return (yax_getnextwall(line, cf) >= 0);
448
}
449
#  endif
450
# endif
451
 
2136 helixhorne 452
// bunchnum: -1: also clear yax-nextwalls (forward and reverse)
453
//           -2: don't clear reverse yax-nextwalls
454
//           -3: don't clear either forward or reverse yax-nextwalls
1816 helixhorne 455
void yax_setbunch(int16_t i, int16_t cf, int16_t bunchnum)
456
{
1843 helixhorne 457
    if (editstatus==0)
1865 helixhorne 458
    {
3658 helixhorne 459
#ifdef NEW_MAP_FORMAT
460
        YAX_BUNCHNUM(i, cf) = bunchnum;
461
#else
1843 helixhorne 462
        yax_bunchnum[i][cf] = bunchnum;
3658 helixhorne 463
#endif
1865 helixhorne 464
        return;
465
    }
1843 helixhorne 466
 
2136 helixhorne 467
    if (bunchnum < 0)
1816 helixhorne 468
    {
1869 helixhorne 469
        int32_t j;
1892 helixhorne 470
        int16_t ynw;
471
 
2136 helixhorne 472
        if (bunchnum > -3)
1869 helixhorne 473
        {
2136 helixhorne 474
            // TODO: for in-game too?
475
            for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
1892 helixhorne 476
            {
2136 helixhorne 477
                ynw = yax_getnextwall(j, cf);
478
                if (ynw >= 0)
479
                {
480
                    if (bunchnum > -2)
481
                        yax_setnextwall(ynw, !cf, -1);
482
                    yax_setnextwall(j, cf, -1);
483
                }
1892 helixhorne 484
            }
1869 helixhorne 485
        }
486
 
3658 helixhorne 487
#if !defined NEW_MAP_FORMAT
1816 helixhorne 488
        *(&sector[i].ceilingstat + cf) &= ~YAX_BIT;
4275 helixhorne 489
        // NOTE: Don't reset xpanning-as-index, since we can be called from
490
        // e.g. Mapster32's "Inner loop made into new sector" functionality.
491
//        YAX_BUNCHNUM(i, cf) = 0;
3841 helixhorne 492
#else
493
        YAX_BUNCHNUM(i, cf) = -1;
3658 helixhorne 494
#endif
1816 helixhorne 495
        return;
496
    }
497
 
3658 helixhorne 498
#if !defined NEW_MAP_FORMAT
1816 helixhorne 499
    *(&sector[i].ceilingstat + cf) |= YAX_BIT;
3658 helixhorne 500
#endif
1816 helixhorne 501
    YAX_BUNCHNUM(i, cf) = bunchnum;
502
}
503
 
1843 helixhorne 504
void yax_setbunches(int16_t i, int16_t cb, int16_t fb)
505
{
506
    yax_setbunch(i, YAX_CEILING, cb);
507
    yax_setbunch(i, YAX_FLOOR, fb);
508
}
1816 helixhorne 509
 
3658 helixhorne 510
# if !defined NEW_MAP_FORMAT
1865 helixhorne 511
//// nextwall getters/setters
512
int16_t yax_getnextwall(int16_t wal, int16_t cf)
513
{
514
    if (editstatus==0)
515
        return yax_nextwall[wal][cf];
516
 
517
    if (!yax_islockededge(wal, cf))
518
        return -1;
519
 
520
    return YAX_NEXTWALL(wal, cf);
521
}
522
 
523
// unchecked!
524
void yax_setnextwall(int16_t wal, int16_t cf, int16_t thenextwall)
525
{
526
    if (editstatus==0)
527
    {
528
        yax_nextwall[wal][cf] = thenextwall;
529
        return;
530
    }
531
 
532
    if (thenextwall >= 0)
1866 helixhorne 533
    {
1865 helixhorne 534
        wall[wal].cstat |= YAX_NEXTWALLBIT(cf);
1866 helixhorne 535
        YAX_NEXTWALL(wal, cf) = thenextwall;
536
    }
1865 helixhorne 537
    else
1866 helixhorne 538
    {
1865 helixhorne 539
        wall[wal].cstat &= ~YAX_NEXTWALLBIT(cf);
2965 helixhorne 540
        YAX_NEXTWALL(wal, cf) = YAX_NEXTWALLDEFAULT(cf);
1866 helixhorne 541
    }
1865 helixhorne 542
}
3658 helixhorne 543
# endif
1865 helixhorne 544
 
2018 helixhorne 545
// make one step in the vertical direction, and if the wall we arrive at
546
// is red, return its nextsector.
547
int16_t yax_vnextsec(int16_t line, int16_t cf)
548
{
4984 terminx 549
    int16_t const ynw = yax_getnextwall(line, cf);
550
    return (ynw < 0) ? -1 : wall[ynw].nextsector;
2018 helixhorne 551
}
552
 
553
 
1886 helixhorne 554
//// in-struct --> array transfer (only resetstat==0); list construction
1882 helixhorne 555
// resetstat:  0: reset and read data from structs and construct linked lists etc.
556
//             1: only reset
557
//             2: read data from game-time arrays and construct linked lists etc.
558
void yax_update(int32_t resetstat)
1854 helixhorne 559
{
3658 helixhorne 560
    int32_t i;
561
#if !defined NEW_MAP_FORMAT
562
    int32_t j;
563
    const int32_t oeditstatus=editstatus;
564
#endif
565
    int16_t cb, fb;
1854 helixhorne 566
 
1886 helixhorne 567
    if (resetstat != 2)
568
        numyaxbunches = 0;
1854 helixhorne 569
 
570
    for (i=0; i<MAXSECTORS; i++)
571
    {
3658 helixhorne 572
#if !defined NEW_MAP_FORMAT
1882 helixhorne 573
        if (resetstat != 2 || i>=numsectors)
574
            yax_bunchnum[i][0] = yax_bunchnum[i][1] = -1;
3658 helixhorne 575
#endif
1854 helixhorne 576
        nextsectbunch[0][i] = nextsectbunch[1][i] = -1;
577
    }
578
    for (i=0; i<YAX_MAXBUNCHES; i++)
579
        headsectbunch[0][i] = headsectbunch[1][i] = -1;
3658 helixhorne 580
#if !defined NEW_MAP_FORMAT
1865 helixhorne 581
    for (i=0; i<MAXWALLS; i++)
1882 helixhorne 582
        if (resetstat != 2 || i>=numwalls)
583
            yax_nextwall[i][0] = yax_nextwall[i][1] = -1;
3658 helixhorne 584
#endif
1854 helixhorne 585
 
1882 helixhorne 586
    if (resetstat==1)
1854 helixhorne 587
        return;
588
 
3658 helixhorne 589
    // Constuct singly linked list of sectors-of-bunch.
1886 helixhorne 590
 
3658 helixhorne 591
#if !defined NEW_MAP_FORMAT
592
    // Read bunchnums directly from the sector struct in yax_[gs]etbunch{es}!
2349 helixhorne 593
    editstatus = (resetstat==0);
3658 helixhorne 594
    // NOTE: Use oeditstatus to check for in-gamedness from here on!
595
#endif
2349 helixhorne 596
 
1886 helixhorne 597
    if (resetstat==0)
598
    {
599
        // make bunchnums consecutive
600
        uint8_t *const havebunch = (uint8_t *)tempbuf;
601
        uint8_t *const bunchmap = havebunch + (YAX_MAXBUNCHES>>3);
602
        int32_t dasub = 0;
603
 
604
        Bmemset(havebunch, 0, YAX_MAXBUNCHES>>3);
605
        for (i=0; i<numsectors; i++)
606
        {
607
            yax_getbunches(i, &cb, &fb);
608
            if (cb>=0)
609
                havebunch[cb>>3] |= (1<<(cb&7));
610
            if (fb>=0)
611
                havebunch[fb>>3] |= (1<<(fb&7));
612
        }
613
 
614
        for (i=0; i<YAX_MAXBUNCHES; i++)
615
        {
616
            if ((havebunch[i>>3]&(1<<(i&7)))==0)
617
            {
618
                bunchmap[i] = 255;
619
                dasub++;
620
                continue;
621
            }
622
 
623
            bunchmap[i] = i-dasub;
624
        }
625
 
626
        for (i=0; i<numsectors; i++)
627
        {
628
            yax_getbunches(i, &cb, &fb);
629
            if (cb>=0)
630
                yax_setbunch(i, YAX_CEILING, bunchmap[cb]);
2068 helixhorne 631
            if (fb>=0)
1886 helixhorne 632
                yax_setbunch(i, YAX_FLOOR, bunchmap[fb]);
633
        }
634
    }
635
 
3658 helixhorne 636
    // In-struct --> array transfer (resetstat==0 and !defined NEW_MAP_FORMAT)
637
    // and list construction.
1854 helixhorne 638
    for (i=numsectors-1; i>=0; i--)
639
    {
640
        yax_getbunches(i, &cb, &fb);
3658 helixhorne 641
#if !defined NEW_MAP_FORMAT
1882 helixhorne 642
        if (resetstat==0)
643
        {
644
            yax_bunchnum[i][0] = cb;
645
            yax_bunchnum[i][1] = fb;
646
        }
3658 helixhorne 647
#endif
1854 helixhorne 648
 
649
        if (cb >= 0)
650
        {
3658 helixhorne 651
#if !defined NEW_MAP_FORMAT
1882 helixhorne 652
            if (resetstat==0)
653
                for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
654
                {
655
                    if (yax_islockededge(j,YAX_CEILING))
2349 helixhorne 656
                    {
1882 helixhorne 657
                        yax_nextwall[j][0] = YAX_NEXTWALL(j,0);
2349 helixhorne 658
                        if (oeditstatus==0)
659
                            YAX_NEXTWALL(j,0) = 0;  // reset lotag!
660
                    }
1882 helixhorne 661
                }
3658 helixhorne 662
#endif
1854 helixhorne 663
            if (headsectbunch[0][cb] == -1)
664
            {
665
                headsectbunch[0][cb] = i;
666
                // not duplicated in floors, since every extended ceiling
667
                // must have a corresponding floor:
1882 helixhorne 668
                if (resetstat==0)
669
                    numyaxbunches++;
1854 helixhorne 670
            }
671
            else
672
            {
3658 helixhorne 673
                int32_t tmpsect = headsectbunch[0][cb];
1854 helixhorne 674
                headsectbunch[0][cb] = i;
675
                nextsectbunch[0][i] = tmpsect;
676
            }
677
        }
678
 
679
        if (fb >= 0)
680
        {
3658 helixhorne 681
#if !defined NEW_MAP_FORMAT
1882 helixhorne 682
            if (resetstat==0)
683
                for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
684
                {
685
                    if (yax_islockededge(j,YAX_FLOOR))
2349 helixhorne 686
                    {
1882 helixhorne 687
                        yax_nextwall[j][1] = YAX_NEXTWALL(j,1);
2349 helixhorne 688
                        if (oeditstatus==0)
689
                            YAX_NEXTWALL(j,1) = -1;  // reset extra!
690
                    }
1882 helixhorne 691
                }
3658 helixhorne 692
#endif
1854 helixhorne 693
            if (headsectbunch[1][fb] == -1)
694
                headsectbunch[1][fb] = i;
695
            else
696
            {
3658 helixhorne 697
                int32_t tmpsect = headsectbunch[1][fb];
1854 helixhorne 698
                headsectbunch[1][fb] = i;
699
                nextsectbunch[1][i] = tmpsect;
700
            }
701
        }
702
    }
2349 helixhorne 703
 
3658 helixhorne 704
#if !defined NEW_MAP_FORMAT
1854 helixhorne 705
    editstatus = oeditstatus;
3841 helixhorne 706
#else
4368 helixhorne 707
    mapversion = get_mapversion();
3658 helixhorne 708
#endif
1854 helixhorne 709
}
1869 helixhorne 710
 
3039 helixhorne 711
int32_t yax_getneighborsect(int32_t x, int32_t y, int32_t sectnum, int32_t cf)
1869 helixhorne 712
{
713
    int16_t bunchnum = yax_getbunch(sectnum, cf);
714
    int32_t i;
715
 
716
    if (bunchnum < 0)
717
        return -1;
718
 
1886 helixhorne 719
    for (SECTORS_OF_BUNCH(bunchnum, !cf, i))
1869 helixhorne 720
        if (inside(x, y, i)==1)
721
            return i;
722
 
723
    return -1;
724
}
725
 
1886 helixhorne 726
// indexed as a list:
727
static int16_t bunches[2][YAX_MAXBUNCHES];
728
// indexed with bunchnums directly:
729
static int16_t bunchsec[YAX_MAXBUNCHES], bunchdist[YAX_MAXBUNCHES];
1882 helixhorne 730
 
1886 helixhorne 731
static int32_t ymostallocsize = 0;  // numyaxbunches*xdimen (no sizeof(int16_t) here!)
732
static int16_t *yumost=NULL, *ydmost=NULL;  // used as if [numyaxbunches][xdimen]
2002 helixhorne 733
uint8_t haveymost[YAX_MAXBUNCHES>>3];
1886 helixhorne 734
 
735
// adapted from build.c
736
static void yax_getclosestpointonwall(int32_t dawall, int32_t *closestx, int32_t *closesty)
1869 helixhorne 737
{
1886 helixhorne 738
    int64_t i, j, wx,wy, wx2,wy2, dx, dy;
1882 helixhorne 739
 
1886 helixhorne 740
    wx = wall[dawall].x;
741
    wy = wall[dawall].y;
742
    wx2 = wall[wall[dawall].point2].x;
743
    wy2 = wall[wall[dawall].point2].y;
1869 helixhorne 744
 
1886 helixhorne 745
    dx = wx2 - wx;
746
    dy = wy2 - wy;
747
    i = dx*(globalposx-wx) + dy*(globalposy-wy);
748
    if (i <= 0) { *closestx = wx; *closesty = wy; return; }
749
    j = dx*dx + dy*dy;
750
    if (i >= j) { *closestx = wx2; *closesty = wy2; return; }
751
    i=((i<<15)/j)<<15;
752
    *closestx = wx + ((dx*i)>>30);
753
    *closesty = wy + ((dy*i)>>30);
754
}
1869 helixhorne 755
 
1886 helixhorne 756
static inline int32_t yax_walldist(int32_t w)
757
{
758
    int32_t closestx, closesty;
1882 helixhorne 759
 
1886 helixhorne 760
    yax_getclosestpointonwall(w, &closestx, &closesty);
761
    return klabs(closestx-globalposx) + klabs(closesty-globalposy);
1882 helixhorne 762
 
1886 helixhorne 763
//    return klabs(wall[w].x-globalposx) + klabs(wall[w].y-globalposy);
1869 helixhorne 764
}
765
 
1886 helixhorne 766
// calculate distances to bunches and best start-drawing sectors
767
static void yax_scanbunches(int32_t bbeg, int32_t numhere, const uint8_t *lastgotsector)
1869 helixhorne 768
{
1887 helixhorne 769
    int32_t bnchcnt, bunchnum, j, k;
1886 helixhorne 770
    int32_t startwall, endwall;
1869 helixhorne 771
 
1887 helixhorne 772
    UNREFERENCED_PARAMETER(lastgotsector);
773
 
1886 helixhorne 774
    scansector_retfast = 1;
775
    scansector_collectsprites = 0;
1882 helixhorne 776
 
1886 helixhorne 777
    for (bnchcnt=bbeg; bnchcnt<bbeg+numhere; bnchcnt++)
1877 helixhorne 778
    {
1886 helixhorne 779
        int32_t walldist, bestsec=-1;
780
        int32_t bestwalldist=INT32_MAX, bestbestdist=INT32_MAX;
1869 helixhorne 781
 
1886 helixhorne 782
        bunchnum = bunches[yax_globalcf][bnchcnt];
783
 
784
        for (SECTORS_OF_BUNCH(bunchnum,!yax_globalcf, k))
1877 helixhorne 785
        {
1886 helixhorne 786
            int32_t checkthisec = 0;
787
 
788
            if (inside(globalposx, globalposy, k)==1)
789
            {
790
                bestsec = k;
791
                bestbestdist = 0;
792
                break;
793
            }
794
 
1882 helixhorne 795
            startwall = sector[k].wallptr;
796
            endwall = startwall+sector[k].wallnum;
797
 
798
            for (j=startwall; j<endwall; j++)
799
            {
800
/*
1886 helixhorne 801
                if ((w=yax_getnextwall(j,!yax_globalcf))>=0)
802
                    if ((ns=wall[w].nextsector)>=0)
803
                        if ((lastgotsector[ns>>3]&(1<<(ns&7)))==0)
804
                            continue;
1882 helixhorne 805
*/
806
                walldist = yax_walldist(j);
807
                if (walldist < bestwalldist)
808
                {
1886 helixhorne 809
                    checkthisec = 1;
1882 helixhorne 810
                    bestwalldist = walldist;
811
                }
812
            }
813
 
1886 helixhorne 814
            if (checkthisec)
1882 helixhorne 815
            {
816
                numscans = numbunches = 0;
3346 terminx 817
                if (getrendermode() == REND_CLASSIC)
1892 helixhorne 818
                    scansector(k);
819
#ifdef USE_OPENGL
820
                else
821
                    polymost_scansector(k);
822
#endif
1882 helixhorne 823
                if (numbunches > 0)
1886 helixhorne 824
                {
1882 helixhorne 825
                    bestsec = k;
1886 helixhorne 826
                    bestbestdist = bestwalldist;
827
                }
1882 helixhorne 828
            }
1877 helixhorne 829
        }
1869 helixhorne 830
 
1886 helixhorne 831
        bunchsec[bunchnum] = bestsec;
832
        bunchdist[bunchnum] = bestbestdist;
833
    }
1882 helixhorne 834
 
1886 helixhorne 835
    scansector_collectsprites = 1;
836
    scansector_retfast = 0;
1877 helixhorne 837
}
1869 helixhorne 838
 
4068 helixhorne 839
static int yax_cmpbunches(const void *b1, const void *b2)
1886 helixhorne 840
{
4068 helixhorne 841
    return (bunchdist[*(int16_t *)b2] - bunchdist[*(int16_t *)b1]);
1886 helixhorne 842
}
843
 
2350 helixhorne 844
 
845
void yax_tweakpicnums(int32_t bunchnum, int32_t cf, int32_t restore)
1877 helixhorne 846
{
2349 helixhorne 847
    // for polymer, this is called before polymer_drawrooms() with restore==0
848
    // and after polymer_drawmasks() with restore==1
849
 
2350 helixhorne 850
    int32_t i, dastat;
1877 helixhorne 851
    static int16_t opicnum[2][MAXSECTORS];
2350 helixhorne 852
#ifdef DEBUGGINGAIDS
853
    static uint8_t expect_restore[2][YAX_MAXBUNCHES];
1869 helixhorne 854
 
2350 helixhorne 855
    // must call this with restore == 0, 1,  0, 1,  0, 1,  ...
2547 helixhorne 856
    Bassert(expect_restore[cf][bunchnum] == restore);
2350 helixhorne 857
    expect_restore[cf][bunchnum] = !expect_restore[cf][bunchnum];
858
#endif
859
 
1886 helixhorne 860
    for (SECTORS_OF_BUNCH(bunchnum, cf, i))
1890 helixhorne 861
    {
1895 helixhorne 862
        dastat = (SECTORFLD(i,stat, cf)&(128+256));
2066 helixhorne 863
 
2349 helixhorne 864
        // only consider non-masked ceilings/floors
2066 helixhorne 865
        if (dastat==0 || (restore==1 && opicnum[cf][i]&0x8000))
1877 helixhorne 866
        {
867
            if (!restore)
868
            {
869
                opicnum[cf][i] = SECTORFLD(i,picnum, cf);
870
                if (editstatus && showinvisibility)
1895 helixhorne 871
                    SECTORFLD(i,picnum, cf) = MAXTILES-1;
2066 helixhorne 872
                else //if ((dastat&(128+256))==0)
1877 helixhorne 873
                    SECTORFLD(i,picnum, cf) = 13; //FOF;
874
            }
875
            else
876
            {
877
                SECTORFLD(i,picnum, cf) = opicnum[cf][i];
878
            }
2066 helixhorne 879
#ifdef POLYMER
880
            // will be called only in editor
3784 terminx 881
            if (getrendermode() == REND_POLYMER)
2066 helixhorne 882
            {
883
                if (!restore)
884
                {
885
                    SECTORFLD(i,stat, cf) |= 128;
886
                    opicnum[cf][i] |= 0x8000;
887
                }
888
                else
889
                {
890
                    SECTORFLD(i,stat, cf) &= ~128;
891
                    SECTORFLD(i,picnum, cf) &= 0x7fff;
892
                    opicnum[cf][i] = 0;
893
                }
894
            }
895
#endif
1877 helixhorne 896
        }
1890 helixhorne 897
    }
1877 helixhorne 898
}
1869 helixhorne 899
 
2046 helixhorne 900
static void yax_copytsprites()
1877 helixhorne 901
{
2046 helixhorne 902
    int32_t i, spritenum, gotthrough, sectnum;
1877 helixhorne 903
    int32_t sortcnt = yax_spritesortcnt[yax_globallev];
904
    const spritetype *spr;
905
 
906
    for (i=0; i<sortcnt; i++)
1869 helixhorne 907
    {
1877 helixhorne 908
        spritenum = yax_tsprite[yax_globallev][i];
1869 helixhorne 909
 
2046 helixhorne 910
        gotthrough = spritenum&(MAXSPRITES|(MAXSPRITES<<1));
911
 
1877 helixhorne 912
        spritenum &= MAXSPRITES-1;
913
        spr = &sprite[spritenum];
914
        sectnum = spr->sectnum;
915
 
2046 helixhorne 916
        if (gotthrough == (MAXSPRITES|(MAXSPRITES<<1)))
1869 helixhorne 917
        {
2046 helixhorne 918
            if (yax_globalbunch != yax_tsprfrombunch[yax_globallev][i])
1877 helixhorne 919
                continue;
1869 helixhorne 920
        }
2046 helixhorne 921
        else
922
        {
923
            int32_t cf = -1;
1877 helixhorne 924
 
2046 helixhorne 925
            if (gotthrough == MAXSPRITES)
926
                cf = YAX_CEILING;  // sprite got here through the ceiling of lower sector
927
            else if (gotthrough == (MAXSPRITES<<1))
928
                cf = YAX_FLOOR;  // sprite got here through the floor of upper sector
929
 
930
            if (cf != -1)
931
            {
932
                if ((yax_globallev-YAX_MAXDRAWS)*(-1 + 2*cf) > 0)
933
                    if (yax_getbunch(sectnum, cf) != yax_globalbunch)
934
                        continue;
935
 
3039 helixhorne 936
                sectnum = yax_getneighborsect(spr->x, spr->y, sectnum, cf);
2046 helixhorne 937
                if (sectnum < 0)
938
                    continue;
939
            }
940
        }
941
 
1882 helixhorne 942
        if (spritesortcnt >= MAXSPRITESONSCREEN)
943
            break;
944
 
1877 helixhorne 945
        Bmemcpy(&tsprite[spritesortcnt], spr, sizeof(spritetype));
946
        tsprite[spritesortcnt].owner = spritenum;
947
 
2046 helixhorne 948
        tsprite[spritesortcnt].sectnum = sectnum;  // potentially tweak sectnum!
1877 helixhorne 949
        spritesortcnt++;
1869 helixhorne 950
    }
1877 helixhorne 951
}
1869 helixhorne 952
 
1892 helixhorne 953
 
1877 helixhorne 954
void yax_preparedrawrooms(void)
955
{
3346 terminx 956
    if (getrendermode() == REND_POLYMER || numyaxbunches==0)
1877 helixhorne 957
        return;
1869 helixhorne 958
 
1877 helixhorne 959
    g_nodraw = 1;
960
    Bmemset(yax_spritesortcnt, 0, sizeof(yax_spritesortcnt));
1886 helixhorne 961
    Bmemset(haveymost, 0, (numyaxbunches+7)>>3);
962
 
3346 terminx 963
    if (getrendermode() == REND_CLASSIC && ymostallocsize < xdimen*numyaxbunches)
1886 helixhorne 964
    {
965
        ymostallocsize = xdimen*numyaxbunches;
4491 helixhorne 966
        yumost = (int16_t *)Xrealloc(yumost, ymostallocsize*sizeof(int16_t));
967
        ydmost = (int16_t *)Xrealloc(ydmost, ymostallocsize*sizeof(int16_t));
1886 helixhorne 968
    }
1877 helixhorne 969
}
970
 
2880 helixhorne 971
void yax_drawrooms(void (*SpriteAnimFunc)(int32_t,int32_t,int32_t,int32_t),
972
                   int16_t sectnum, int32_t didmirror, int32_t smoothr)
1877 helixhorne 973
{
974
    static uint8_t havebunch[YAX_MAXBUNCHES>>3];
975
 
2880 helixhorne 976
    const int32_t horiz = global100horiz;
977
 
2024 helixhorne 978
    int32_t i, j, k, lev, cf, nmp;
1877 helixhorne 979
    int32_t bnchcnt, bnchnum[2] = {0,0}, maxlev[2];
980
    int16_t ourbunch[2] = {-1,-1}, osectnum=sectnum;
981
    int32_t bnchbeg[YAX_MAXDRAWS][2], bnchend[YAX_MAXDRAWS][2];
982
    int32_t bbeg, numhere;
983
 
984
    // original (1st-draw) and accumulated ('per-level') gotsector bitmaps
985
    static uint8_t ogotsector[MAXSECTORS>>3], lgotsector[MAXSECTORS>>3];
1882 helixhorne 986
#ifdef YAX_DEBUG
2026 helixhorne 987
    uint64_t t;
1882 helixhorne 988
#endif
1877 helixhorne 989
 
3346 terminx 990
    if (getrendermode() == REND_POLYMER || numyaxbunches==0)
1877 helixhorne 991
    {
992
#ifdef ENGINE_SCREENSHOT_DEBUG
993
        engine_screenshot = 0;
994
#endif
995
        return;
996
    }
997
 
998
    // if we're here, there was just a drawrooms() call with g_nodraw=1
999
 
1000
    Bmemcpy(ogotsector, gotsector, (numsectors+7)>>3);
1001
 
1002
    if (sectnum >= 0)
1003
        yax_getbunches(sectnum, &ourbunch[0], &ourbunch[1]);
1004
    Bmemset(&havebunch, 0, (numyaxbunches+7)>>3);
1005
 
1006
    // first scan all bunches above, then all below...
1869 helixhorne 1007
    for (cf=0; cf<2; cf++)
1008
    {
1877 helixhorne 1009
        yax_globalcf = cf;
1869 helixhorne 1010
 
1877 helixhorne 1011
        if (cf==1)
1012
        {
1013
            sectnum = osectnum;
1014
            Bmemcpy(gotsector, ogotsector, (numsectors+7)>>3);
1015
        }
1869 helixhorne 1016
 
1877 helixhorne 1017
        for (lev=0; /*lev<YAX_MAXDRAWS*/; lev++)
1869 helixhorne 1018
        {
1877 helixhorne 1019
            yax_globallev = YAX_MAXDRAWS + (-1 + 2*cf)*(lev+1);
1869 helixhorne 1020
 
1877 helixhorne 1021
            bbeg = bnchbeg[lev][cf] = bnchend[lev][cf] = bnchnum[cf];
1022
            numhere = 0;
1023
 
1024
            for (i=0; i<numsectors; i++)
1869 helixhorne 1025
            {
1877 helixhorne 1026
                if (!(gotsector[i>>3]&(1<<(i&7))))
1869 helixhorne 1027
                    continue;
1877 helixhorne 1028
 
1029
                j = yax_getbunch(i, cf);
1030
                if (j >= 0 && !(havebunch[j>>3]&(1<<(j&7))))
1031
                {
3346 terminx 1032
                    if (getrendermode() == REND_CLASSIC && (haveymost[j>>3]&(1<<(j&7)))==0)
1886 helixhorne 1033
                    {
1034
                        yaxdebug("%s, l %d: skipped bunch %d (no *most)", cf?"v":"^", lev, j);
1035
                        continue;
1036
                    }
1037
 
1882 helixhorne 1038
                    if ((SECTORFLD(i,stat, cf)&2) ||
1039
                            (cf==0 && globalposz > sector[i].ceilingz) ||
1040
                            (cf==1 && globalposz < sector[i].floorz))
1041
                    {
1042
                        havebunch[j>>3] |= (1<<(j&7));
1043
                        bunches[cf][bnchnum[cf]++] = j;
1044
                        bnchend[lev][cf]++;
1045
                        numhere++;
1046
                    }
1877 helixhorne 1047
                }
1869 helixhorne 1048
            }
1877 helixhorne 1049
 
1050
            if (numhere > 0)
1874 helixhorne 1051
            {
1877 helixhorne 1052
                // found bunches -- need to fake-draw
1053
 
1886 helixhorne 1054
                yax_scanbunches(bbeg, numhere, (uint8_t *)gotsector);
1055
 
4068 helixhorne 1056
                qsort(&bunches[cf][bbeg], numhere, sizeof(int16_t), &yax_cmpbunches);
1877 helixhorne 1057
 
1886 helixhorne 1058
                if (numhere > 1 && lev != YAX_MAXDRAWS-1)
1059
                    Bmemset(lgotsector, 0, (numsectors+7)>>3);
1060
 
1877 helixhorne 1061
                for (bnchcnt=bbeg; bnchcnt < bbeg+numhere; bnchcnt++)
1874 helixhorne 1062
                {
1877 helixhorne 1063
                    j = bunches[cf][bnchcnt];  // the actual bunchnum...
1886 helixhorne 1064
                    yax_globalbunch = j;
1882 helixhorne 1065
#ifdef YAX_DEBUG
3934 helixhorne 1066
                    t=getu64ticks();
1882 helixhorne 1067
#endif
1886 helixhorne 1068
                    k = bunchsec[j];
1069
 
1877 helixhorne 1070
                    if (k < 0)
1071
                    {
1886 helixhorne 1072
                        yaxprintf("%s, l %d: skipped bunch %d\n", cf?"v":"^", lev, j);
1877 helixhorne 1073
                        continue;
1074
                    }
1075
 
1076
                    if (lev != YAX_MAXDRAWS-1)
1077
                    {
2046 helixhorne 1078
#ifdef YAX_DEBUG
1079
                        int32_t odsprcnt = yax_spritesortcnt[yax_globallev];
1080
#endif
1877 helixhorne 1081
                        // +MAXSECTORS: force
1082
                        drawrooms(globalposx,globalposy,globalposz,globalang,horiz,k+MAXSECTORS);
1083
                        if (numhere > 1)
1084
                            for (i=0; i<(numsectors+7)>>3; i++)
1085
                                lgotsector[i] |= gotsector[i];
1086
 
2046 helixhorne 1087
                        yaxdebug("l%d: faked (bn %2d) sec %4d,%3d dspr, ob=[%2d,%2d], sn=%4d, %.3f ms",
1088
                                 yax_globallev-YAX_MAXDRAWS, j, k, yax_spritesortcnt[yax_globallev]-odsprcnt,
2026 helixhorne 1089
                                 ourbunch[0],ourbunch[1],sectnum,
3934 helixhorne 1090
                                 (double)(1000*(getu64ticks()-t))/u64tickspersec);
1877 helixhorne 1091
                    }
1882 helixhorne 1092
 
1093
                    if (ourbunch[cf]==j)
1094
                    {
1095
                        ourbunch[cf] = yax_getbunch(k, cf);
1096
                        sectnum = k;
1097
                    }
1874 helixhorne 1098
                }
1869 helixhorne 1099
 
1877 helixhorne 1100
                if (numhere > 1 && lev != YAX_MAXDRAWS-1)
1101
                    Bmemcpy(gotsector, lgotsector, (numsectors+7)>>3);
1874 helixhorne 1102
            }
1103
 
1877 helixhorne 1104
            if (numhere==0 || lev==YAX_MAXDRAWS-1)
1874 helixhorne 1105
            {
1877 helixhorne 1106
                // no new bunches or max level reached
1107
                maxlev[cf] = lev - (numhere==0);
1108
                break;
1874 helixhorne 1109
            }
1877 helixhorne 1110
        }
1111
    }
1869 helixhorne 1112
 
1886 helixhorne 1113
//    yax_globalcf = -1;
1869 helixhorne 1114
 
1877 helixhorne 1115
    // now comes the real drawing!
1116
    g_nodraw = 0;
1117
    scansector_collectsprites = 0;
1869 helixhorne 1118
 
1901 helixhorne 1119
    if (editstatus==1)
1890 helixhorne 1120
    {
3346 terminx 1121
        if (getrendermode() == REND_CLASSIC)
1901 helixhorne 1122
        {
1123
            begindrawing();
2513 helixhorne 1124
            draw_rainbow_background();
1901 helixhorne 1125
            enddrawing();
1126
        }
1892 helixhorne 1127
#ifdef USE_OPENGL
1901 helixhorne 1128
        else
1129
        {
1130
            bglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
1131
        }
1132
#endif
1892 helixhorne 1133
    }
1869 helixhorne 1134
 
1877 helixhorne 1135
    for (cf=0; cf<2; cf++)
1136
    {
1886 helixhorne 1137
        yax_globalcf = cf;
1138
 
1877 helixhorne 1139
        for (lev=maxlev[cf]; lev>=0; lev--)
1140
        {
1141
            yax_globallev = YAX_MAXDRAWS + (-1 + 2*cf)*(lev+1);
1882 helixhorne 1142
            scansector_collectsprites = (lev == YAX_MAXDRAWS-1);
1877 helixhorne 1143
 
1144
            for (bnchcnt=bnchbeg[lev][cf]; bnchcnt<bnchend[lev][cf]; bnchcnt++)
1145
            {
1146
                j = bunches[cf][bnchcnt];  // the actual bunchnum...
1886 helixhorne 1147
                k = bunchsec[j];  // best start-drawing sector
1148
                yax_globalbunch = j;
1882 helixhorne 1149
#ifdef YAX_DEBUG
3934 helixhorne 1150
                t=getu64ticks();
1882 helixhorne 1151
#endif
1877 helixhorne 1152
                yax_tweakpicnums(j, cf, 0);
1153
                if (k < 0)
1154
                    continue;
1155
 
2024 helixhorne 1156
                yax_nomaskdidit = 0;
1157
                for (nmp=r_tror_nomaskpass; nmp>=0; nmp--)
1158
                {
1159
                    yax_nomaskpass = nmp;
1160
                    drawrooms(globalposx,globalposy,globalposz,globalang,horiz,k+MAXSECTORS);  // +MAXSECTORS: force
1877 helixhorne 1161
 
2024 helixhorne 1162
                    if (nmp==1)
1163
                    {
2046 helixhorne 1164
                        yaxdebug("nm1 l%d: DRAWN (bn %2d) sec %4d,          %.3f ms",
1165
                                 yax_globallev-YAX_MAXDRAWS, j, k,
3934 helixhorne 1166
                                 (double)(1000*(getu64ticks()-t))/u64tickspersec);
2046 helixhorne 1167
 
2024 helixhorne 1168
                        if (!yax_nomaskdidit)
1169
                        {
1170
                            yax_nomaskpass = 0;
1171
                            break;  // no need to draw the same stuff twice
1172
                        }
1173
                        Bmemcpy(yax_gotsector, gotsector, (numsectors+7)>>3);
1174
                    }
1175
                }
1176
 
2046 helixhorne 1177
                if (!scansector_collectsprites)
1178
                    spritesortcnt = 0;
1179
                yax_copytsprites();
1180
                yaxdebug("nm0 l%d: DRAWN (bn %2d) sec %4d,%3d tspr, %.3f ms",
1181
                         yax_globallev-YAX_MAXDRAWS, j, k, spritesortcnt,
3934 helixhorne 1182
                         (double)(1000*(getu64ticks()-t))/u64tickspersec);
1877 helixhorne 1183
 
2880 helixhorne 1184
                SpriteAnimFunc(globalposx, globalposy, globalang, smoothr);
1877 helixhorne 1185
                drawmasks();
1186
            }
1187
 
1188
            if (lev < maxlev[cf])
1189
                for (bnchcnt=bnchbeg[lev+1][cf]; bnchcnt<bnchend[lev+1][cf]; bnchcnt++)
1190
                    yax_tweakpicnums(bunches[cf][bnchcnt], cf, 1);  // restore picnums
1869 helixhorne 1191
        }
1192
    }
1193
 
1882 helixhorne 1194
#ifdef YAX_DEBUG
3934 helixhorne 1195
    t=getu64ticks();
1882 helixhorne 1196
#endif
2024 helixhorne 1197
    yax_globalcf = -1;
1886 helixhorne 1198
    yax_globalbunch = -1;
1877 helixhorne 1199
    yax_globallev = YAX_MAXDRAWS;
1882 helixhorne 1200
    scansector_collectsprites = 0;
1869 helixhorne 1201
 
1877 helixhorne 1202
    // draw base level
2810 helixhorne 1203
    drawrooms(globalposx,globalposy,globalposz,globalang,horiz,
1204
              osectnum + MAXSECTORS*didmirror);
2046 helixhorne 1205
//    if (scansector_collectsprites)
1206
//        spritesortcnt = 0;
1207
    yax_copytsprites();
1208
    yaxdebug("DRAWN base level sec %d,%3d tspr, %.3f ms", osectnum,
3934 helixhorne 1209
             spritesortcnt, (double)(1000*(getu64ticks()-t))/u64tickspersec);
1877 helixhorne 1210
    scansector_collectsprites = 1;
1211
 
1212
    for (cf=0; cf<2; cf++)
1213
        if (maxlev[cf] >= 0)
1214
            for (bnchcnt=bnchbeg[0][cf]; bnchcnt<bnchend[0][cf]; bnchcnt++)
1215
                yax_tweakpicnums(bunches[cf][bnchcnt], cf, 1);  // restore picnums
1216
 
1217
#ifdef ENGINE_SCREENSHOT_DEBUG
1218
    engine_screenshot = 0;
1219
#endif
1886 helixhorne 1220
 
1221
#ifdef YAX_DEBUG_YMOSTS
3346 terminx 1222
    if (getrendermode() == REND_CLASSIC && numyaxbunches>0)
1886 helixhorne 1223
    {
1908 helixhorne 1224
        char purple = getclosestcol(63, 0, 63);
1225
        char yellow = getclosestcol(63, 63, 0);
1226
 
1890 helixhorne 1227
        begindrawing();
1228
        for (i=0; i<numyaxbunches; i++)
1229
        {
1230
            int32_t x, x1;
1886 helixhorne 1231
 
1890 helixhorne 1232
            if ((haveymost[i>>3]&(1<<i&7))==0)
1233
                continue;
1886 helixhorne 1234
 
1890 helixhorne 1235
            x1 = i*xdimen;
1886 helixhorne 1236
 
1890 helixhorne 1237
            for (x=x1; x<x1+xdimen; x++)
1238
            {
1908 helixhorne 1239
                if (yumost[x] >= 0 && yumost[x] < ydim && (x&1))
1890 helixhorne 1240
                    *((char *)frameplace + yumost[x]*bytesperline + x-x1) = purple;
1886 helixhorne 1241
 
1908 helixhorne 1242
                if (ydmost[x]-1 >= 0 && ydmost[x]-1 < ydim && !(x&1))
1890 helixhorne 1243
                    *((char *)frameplace + (ydmost[x]-1)*bytesperline + x-x1) = yellow;
1244
            }
1886 helixhorne 1245
        }
1890 helixhorne 1246
        enddrawing();
1886 helixhorne 1247
    }
1248
#endif
1869 helixhorne 1249
}
1250
 
2513 helixhorne 1251
#endif  // defined YAX_ENABLE
1843 helixhorne 1252
 
2513 helixhorne 1253
// must have writable frame buffer, i.e. done begindrawing()
1254
static void draw_rainbow_background(void)
1255
{
3721 helixhorne 1256
    int32_t y, i;
1257
    const int32_t N = 240;  // don't use fullbright colors
1258
    const int32_t numfull=bytesperline/N, numrest=bytesperline%N;
2513 helixhorne 1259
 
3721 helixhorne 1260
    const char *const src = palookup[0] + 256*18;
1261
    char *dst = (char *)frameplace;
1262
 
1263
    for (y=0; y<ydim; y++)
2513 helixhorne 1264
    {
3721 helixhorne 1265
        for (i=0; i<numfull; i++)
1266
            Bmemcpy(&dst[N*i], src, N);
1267
        if (numrest > 0)
1268
            Bmemcpy(&dst[N*i], src, numrest);
1269
 
1270
        dst += bytesperline;
2513 helixhorne 1271
    }
1272
}
3721 helixhorne 1273
 
1866 helixhorne 1274
//
1275
// setslope
1276
//
1277
void setslope(int32_t sectnum, int32_t cf, int16_t slope)
1278
{
1279
    if (slope==0)
1280
    {
1281
        SECTORFLD(sectnum,stat, cf) &= ~2;
1282
        SECTORFLD(sectnum,heinum, cf) = 0;
1283
    }
1284
    else
1285
    {
1286
        SECTORFLD(sectnum,stat, cf) |= 2;
1287
        SECTORFLD(sectnum,heinum, cf) = slope;
1288
    }
1289
}
1290
 
1730 helixhorne 1291
////////// editor side view //////////
1292
int32_t m32_sideview = 0;
1293
int32_t m32_sideelev = 256;  // elevation in BUILD degrees, 0..512
1294
int16_t m32_sideang = 200;  // azimuth, 0..2047
1295
 
1296
int32_t m32_sidecos, m32_sidesin;
1297
int32_t m32_swcnt;
1865 helixhorne 1298
int32_t m32_wallscreenxy[MAXWALLS][2];
1299
int16_t m32_wallsprite[MAXWALLS+MAXSPRITES];
1300
static int32_t m32_sidedist[MAXWALLS+MAXSPRITES];
1730 helixhorne 1301
static vec3_t m32_viewplane;
1302
 
1303
 
1719 helixhorne 1304
////// sector-like clipping for sprites //////
2270 helixhorne 1305
#ifdef HAVE_CLIPSHAPE_FEATURE
1719 helixhorne 1306
typedef struct
1307
{
1308
    int16_t numsectors, numwalls;
4984 terminx 1309
    tsectortype *sector;
1310
    twalltype *wall;
1719 helixhorne 1311
} mapinfo_t;
1312
 
3116 hendricks2 1313
static void mapinfo_set(mapinfo_t *bak, mapinfo_t *newmap)
1719 helixhorne 1314
{
1315
    if (bak)
1316
    {
1317
        bak->numsectors = numsectors;
1318
        bak->numwalls = numwalls;
4984 terminx 1319
        bak->sector = (tsectortype *)sector;
1320
        bak->wall = (twalltype *)wall;
1719 helixhorne 1321
    }
1322
 
3116 hendricks2 1323
    if (newmap)
1719 helixhorne 1324
    {
3116 hendricks2 1325
        numsectors = newmap->numsectors;
1326
        numwalls = newmap->numwalls;
4984 terminx 1327
        sector = (sectortype *)newmap->sector;
1328
        wall = (walltype *)newmap->wall;
1719 helixhorne 1329
    }
1330
}
1331
 
1332
static mapinfo_t origmapinfo, clipmapinfo;
1333
static int32_t quickloadboard=0;
1334
 
1335
 
1336
#define CM_MAX 256  // must be a power of 2
1337
 
1338
typedef struct
1339
{
1340
    int16_t qbeg, qend;  // indices into sectq
1341
    int16_t picnum, next;
1342
    int32_t maxdist;
1343
} clipinfo_t;
1344
 
1345
static int32_t numclipmaps;
1346
static clipinfo_t clipinfo[CM_MAX];
1347
 
1348
static int32_t numclipsects;  // number in sectq[]
1349
static int16_t *sectoidx, *sectq;  // [numsectors]
1350
static int16_t pictoidx[MAXTILES];  // maps tile num to clipinfo[] index
1351
static int16_t *tempictoidx;
1352
 
4984 terminx 1353
static tsectortype *loadsector;
1354
static twalltype *loadwall, *loadwallinv;
1355
static tspritetype *loadsprite;
1722 helixhorne 1356
 
1719 helixhorne 1357
// sectoidx bits
3172 helixhorne 1358
#undef CM_NONE
1719 helixhorne 1359
#define CM_NONE (CM_MAX<<1)
1360
#define CM_SOME (CM_NONE-1)
1361
#define CM_OUTER (CM_MAX)   // sector surrounds clipping sector
1362
 
1363
// sprite -> sector tag mappings
1364
#define CM_XREPEAT floorpal
1365
#define CM_YREPEAT floorxpanning
1366
#define CM_XOFFSET ceilingshade
1367
#define CM_YOFFSET floorshade
1368
#define CM_CSTAT hitag
1369
#define CM_ANG extra
1370
#define CM_FLOORZ(Sec) (*(int32_t *)&sector[Sec].ceilingxpanning)  // ceilingxpanning,ceilingypanning,floorpicnum
4416 helixhorne 1371
#define CM_CEILINGZ(Sec) (*(int32_t *)&sector[Sec].visibility)  // visibility,fogpal,lotag
1719 helixhorne 1372
 
1373
// backup of original normalized coordinates
3188 helixhorne 1374
#define CM_WALL_X(Wal) (*(int32_t *)&wall[Wal].picnum)  // picnum, overpicnum
1375
#define CM_WALL_Y(Wal) (*(int32_t *)&wall[Wal].lotag)  // lotag, hitag
1719 helixhorne 1376
 
1377
// don't rotate when applying clipping, for models with rotational symmetry
1378
#define CM_NOROT(Spri) (sprite[Spri].cstat&2)
1379
#define CM_NOROTS(Sect) (sector[Sect].CM_CSTAT&2)
1380
 
1381
 
1382
static void clipmapinfo_init()
1383
{
1384
    numclipmaps = 0;
1385
    numclipsects = 0;
1386
 
4984 terminx 1387
    DO_FREE_AND_NULL(sectq);
1388
    DO_FREE_AND_NULL(sectoidx);
1389
    DO_FREE_AND_NULL(tempictoidx);
1390
    DO_FREE_AND_NULL(loadsector);
1391
    DO_FREE_AND_NULL(loadwall);
1392
    DO_FREE_AND_NULL(loadwallinv);
1393
    DO_FREE_AND_NULL(loadsprite);
1719 helixhorne 1394
 
4984 terminx 1395
    // two's complement trick, -1 = 0xff
1396
    Bmemset(&pictoidx, -1, sizeof(pictoidx));
1397
    Bmemset(&clipmapinfo, 0, sizeof(mapinfo_t));
1722 helixhorne 1398
 
1728 helixhorne 1399
    numsectors = 0;
1400
    numwalls = 0;
1719 helixhorne 1401
}
1402
 
2495 hendricks2 1403
// loads the clip maps.
1728 helixhorne 1404
// this should be called before any real map is loaded.
2495 hendricks2 1405
int32_t clipmapinfo_load(void)
1719 helixhorne 1406
{
3042 helixhorne 1407
    int32_t i,k,w;
1719 helixhorne 1408
 
2495 hendricks2 1409
    int32_t lwcp = 0;
1410
    int32_t fi;
1411
 
1412
    int32_t *fisec = NULL;
1413
    int32_t *fispr = NULL;
1414
 
2478 helixhorne 1415
    int32_t ournumsectors=0, ournumwalls=0, ournumsprites=0;
1722 helixhorne 1416
 
1719 helixhorne 1417
    clipmapinfo_init();
1418
 
4984 terminx 1419
    loadsector = (tsectortype *)Xmalloc(MAXSECTORS * sizeof(sectortype));
1420
    loadwall = (twalltype *)Xmalloc(MAXWALLS * sizeof(walltype));
1421
    loadsprite = (tspritetype *)Xmalloc(MAXSPRITES * sizeof(spritetype));
1722 helixhorne 1422
 
2502 helixhorne 1423
    if (g_clipMapFilesNum)
4491 helixhorne 1424
        fisec = (int32_t *)Xcalloc(g_clipMapFilesNum, sizeof (int32_t));
2502 helixhorne 1425
    if (g_clipMapFilesNum)
4491 helixhorne 1426
        fispr = (int32_t *)Xcalloc(g_clipMapFilesNum, sizeof (int32_t));
1722 helixhorne 1427
 
1719 helixhorne 1428
    quickloadboard = 1;
2495 hendricks2 1429
    for (fi = 0; fi < g_clipMapFilesNum; ++fi)
1722 helixhorne 1430
    {
3042 helixhorne 1431
        int16_t ang,cs;
1432
        vec3_t tmppos;
1433
 
2495 hendricks2 1434
        fisec[fi] = ournumsectors;
1435
        fispr[fi] = ournumsprites;
1722 helixhorne 1436
 
4212 helixhorne 1437
        i = loadboard(g_clipMapFiles[fi], 8, &tmppos, &ang, &cs);
1722 helixhorne 1438
        if (i<0)
1439
            continue;
2478 helixhorne 1440
        // Numsprites will now be set!
1722 helixhorne 1441
 
2495 hendricks2 1442
        initprintf("Loading clip map: %s\n", g_clipMapFiles[fi]);
1443
 
1722 helixhorne 1444
        if (ournumsectors+numsectors>MAXSECTORS ||
1762 terminx 1445
                ournumwalls+numwalls>MAXWALLS ||
2478 helixhorne 1446
                ournumsprites+Numsprites>MAXSPRITES)
1722 helixhorne 1447
        {
2495 hendricks2 1448
            initprintf("clip map: warning: exceeded limits when loading %s, aborting.\n", g_clipMapFiles[fi]);
1722 helixhorne 1449
            break;
1450
        }
1451
 
1452
        Bmemcpy(loadsector+ournumsectors, sector, numsectors*sizeof(sectortype));
1453
        Bmemcpy(loadwall+ournumwalls, wall, numwalls*sizeof(walltype));
2478 helixhorne 1454
        Bmemcpy(loadsprite+ournumsprites, sprite, Numsprites*sizeof(spritetype));
1722 helixhorne 1455
        for (i=ournumsectors; i<ournumsectors+numsectors; i++)
1456
            loadsector[i].wallptr += ournumwalls;
1457
        for (i=ournumwalls; i<ournumwalls+numwalls; i++)
1458
        {
1459
            if (loadwall[i].point2>=0)
1460
                loadwall[i].point2 += ournumwalls;
1461
            if (loadwall[i].nextwall>=0)
1462
            {
1463
                loadwall[i].nextwall += ournumwalls;
1464
                loadwall[i].nextsector += ournumsectors;
1465
            }
1466
        }
2478 helixhorne 1467
        for (i=ournumsprites; i<ournumsprites+Numsprites; i++)
1722 helixhorne 1468
            if (loadsprite[i].sectnum>=0)
1469
                loadsprite[i].sectnum += ournumsectors;
1470
        ournumsectors += numsectors;
1471
        ournumwalls += numwalls;
2478 helixhorne 1472
        ournumsprites += Numsprites;
1728 helixhorne 1473
 
2495 hendricks2 1474
        ++lwcp;
1722 helixhorne 1475
    }
1719 helixhorne 1476
    quickloadboard = 0;
1477
 
1722 helixhorne 1478
    if (ournumsectors==0 || ournumwalls==0 || ournumsprites==0)  // nothing loaded
1479
    {
1480
        clipmapinfo_init();
2495 hendricks2 1481
 
2502 helixhorne 1482
        Bfree(fisec);
1483
        Bfree(fispr);
2495 hendricks2 1484
 
1722 helixhorne 1485
        return -1;
1486
    }
1487
 
1728 helixhorne 1488
    // shrink
4984 terminx 1489
    loadsector = (tsectortype *)Xrealloc(loadsector, ournumsectors*sizeof(sectortype));
1490
    loadwall = (twalltype *)Xrealloc(loadwall, ournumwalls*sizeof(walltype));
1722 helixhorne 1491
 
1492
    Bmemcpy(sector, loadsector, ournumsectors*sizeof(sectortype));
1493
    Bmemcpy(wall, loadwall, ournumwalls*sizeof(walltype));
1494
    Bmemcpy(sprite, loadsprite, ournumsprites*sizeof(spritetype));
1495
    numsectors = ournumsectors;
1496
    numwalls = ournumwalls;
1497
 
1498
    //  vvvv    don't use headsprite[sect,stat]!   vvvv
1499
 
4491 helixhorne 1500
    sectoidx = (int16_t *)Xmalloc(numsectors*sizeof(sectoidx[0]));
2495 hendricks2 1501
 
1719 helixhorne 1502
    for (i=0; i<numsectors; i++)
1503
        sectoidx[i] = CM_NONE;
1504
 
1505
    // determine outer sectors
1506
    for (i=0; i<numsectors; i++)
1507
    {
1508
        for (w=sector[i].wallptr; w<sector[i].wallptr+sector[i].wallnum; w++)
1509
            if (wall[w].nextsector<0)
1510
            {
1511
                sectoidx[i] = CM_OUTER;
1512
                break;
1513
            }
1514
    }
1515
    // break connections between outer sectors
1516
    for (i=0; i<numsectors; i++)
1517
    {
1518
        if (sectoidx[i] == CM_OUTER)
1519
            for (w=sector[i].wallptr; w<sector[i].wallptr+sector[i].wallnum; w++)
1520
            {
1521
                k = wall[w].nextwall;
1522
                if (k>=0 && sectoidx[wall[w].nextsector]==CM_OUTER)
1523
                {
1524
                    wall[k].nextwall = wall[k].nextsector = -1;
1525
                    wall[w].nextwall = wall[w].nextsector = -1;
1526
                }
1527
            }
1528
    }
1529
 
1530
    {
1531
        int16_t ns, outersect;
1532
        int32_t pn,scnt, x,y,z, maxdist;
1533
 
4491 helixhorne 1534
        sectq = (int16_t *)Xmalloc(numsectors*sizeof(sectq[0]));
1535
        tempictoidx = (int16_t *)Xmalloc(MAXTILES*sizeof(tempictoidx[0]));
2495 hendricks2 1536
 
1719 helixhorne 1537
        for (i=0; i<MAXTILES; i++)
1538
            tempictoidx[i]=-1;
1539
 
1540
        // collect sprite picnums
1541
        for (i=0; i<MAXSPRITES && sprite[i].statnum<MAXSTATUS; i++)
1542
        {
1543
            pn = sprite[i].picnum;
1544
            k = sprite[i].sectnum;
1545
            //    -v-  note the <=                         ignore sprites in outer sectors
1546
            if (pn<=0 || pn>=MAXTILES || k<0 || k>=numsectors || (sectoidx[k]&CM_OUTER))
1547
                continue;
1548
 
1934 helixhorne 1549
            if (numclipmaps >= CM_MAX)
1550
            {
1551
                initprintf("warning: reached max clip map number %d, not processing any more\n", CM_MAX);
1552
                break;
1553
            }
1554
 
1719 helixhorne 1555
            // chain
1556
            if (pictoidx[pn]>=0)
1557
            {
1558
                if (sectoidx[k]&CM_SOME)
1559
                {
2495 hendricks2 1560
                    for (fi = 0; fi < g_clipMapFilesNum; ++fi)
1722 helixhorne 1561
                        if (k>=fisec[fi])
1562
                            break;
2495 hendricks2 1563
                    initprintf("clip map \"%s\": error: tried to chain picnum %d (sprite %d) in sector %d which"
1564
                               " already belongs to picnum %d.\n", g_clipMapFiles[fi], pn, i-fispr[fi], k-fisec[fi],
1722 helixhorne 1565
                               clipinfo[sectoidx[k]].picnum);
1719 helixhorne 1566
                    clipmapinfo_init();
2495 hendricks2 1567
 
2502 helixhorne 1568
                    Bfree(fisec);
1569
                    Bfree(fispr);
2495 hendricks2 1570
 
1719 helixhorne 1571
                    return 2;
1572
                }
1573
 
1574
                // new one is front
1575
                clipinfo[numclipmaps].next = pictoidx[pn];
1576
                pictoidx[pn] = numclipmaps;
1577
            }
1578
            else
1579
            {
1580
                clipinfo[numclipmaps].next = -1;
1581
                pictoidx[pn] = numclipmaps;
1582
            }
1583
 
1584
            if (!CM_NOROT(i))
1585
            {
1586
                if (sprite[i].ang!=1536 && sprite[i].ang!=512)
1587
                {
2495 hendricks2 1588
                    for (fi = 0; fi < g_clipMapFilesNum; ++fi)
1722 helixhorne 1589
                        if (i>=fispr[fi])
1590
                            break;
2495 hendricks2 1591
                    initprintf("clip map \"%s\": warning: sprite %d pointing neither northward nor southward. %s will be wrong.\n",
1592
                               g_clipMapFiles[fi], i-fispr[fi], (sprite[i].cstat&48)==32 ? "Scaling and flipping" : "X-flipping");
1719 helixhorne 1593
                }
1594
            }
1595
 
1596
            clipinfo[numclipmaps].picnum = pn;
1597
 
1598
            // collect sectors
1599
            scnt = numclipsects;
1600
            sectq[numclipsects++] = k;
1601
            sectoidx[k] = numclipmaps;
1602
 
1603
            clipinfo[numclipmaps].qbeg = scnt;
1604
 
1605
            outersect = -1;
1606
 
1607
            do
1608
            {
1609
                k = sectq[scnt];
1610
 
1611
                for (w=sector[k].wallptr; w<sector[k].wallptr+sector[k].wallnum; w++)
1612
                {
1613
                    ns = wall[w].nextsector;
1614
                    if (ns>=0)
1615
                    {
1616
                        if (sectoidx[ns]==CM_NONE)
1617
                        {
1618
                            sectoidx[ns] = numclipmaps;
1619
                            sectq[numclipsects++] = ns;
1620
                        }
1621
                        else if (sectoidx[ns]&CM_OUTER)
1622
                        {
1623
                            if (outersect>=0 && ns!=outersect)
1624
                            {
2495 hendricks2 1625
                                for (fi = 0; fi < g_clipMapFilesNum; ++fi)
1722 helixhorne 1626
                                    if (ns>=fisec[fi])
1627
                                        break;
2495 hendricks2 1628
                                initprintf("clip map \"%s\": error: encountered more than one outer sector (%d and %d)"
1629
                                           " for sprite %d.\n", g_clipMapFiles[fi], outersect-fisec[fi], ns-fisec[fi], i-fispr[fi]);
1719 helixhorne 1630
                                clipmapinfo_init();
2495 hendricks2 1631
 
2502 helixhorne 1632
                                Bfree(fisec);
1633
                                Bfree(fispr);
2495 hendricks2 1634
 
1719 helixhorne 1635
                                return 3;
1636
                            }
1637
 
1638
                            outersect = ns;
1639
                            sectoidx[outersect] |= numclipmaps;
1640
                        }
1641
                        else if (sectoidx[ns]!=numclipmaps)
1642
                        {
2495 hendricks2 1643
                            for (fi = 0; fi < g_clipMapFilesNum; ++fi)
1722 helixhorne 1644
                                if (ns>=fisec[fi])
1645
                                    break;
2495 hendricks2 1646
                            initprintf("clip map \"%s\": error: encountered sector %d belonging to index %d"
1719 helixhorne 1647
                                       " while collecting sectors for sprite %d (index %d).\n",
2495 hendricks2 1648
                                       g_clipMapFiles[fi], ns-fisec[fi], sectoidx[ns], i-fispr[fi], numclipmaps);
1719 helixhorne 1649
                            clipmapinfo_init();
2495 hendricks2 1650
 
2502 helixhorne 1651
                            Bfree(fisec);
1652
                            Bfree(fispr);
2495 hendricks2 1653
 
1719 helixhorne 1654
                            return 4;
1655
                        }
1656
                    }
1657
                }
1762 terminx 1658
            }
1659
            while (++scnt < numclipsects);
1719 helixhorne 1660
 
1722 helixhorne 1661
            if (outersect==-1)
1662
            {
1663
                initprintf("clip map: INTERNAL ERROR: outersect==-1!\n");
1664
                clipmapinfo_init();
2495 hendricks2 1665
 
2502 helixhorne 1666
                Bfree(fisec);
1667
                Bfree(fispr);
2495 hendricks2 1668
 
1722 helixhorne 1669
                return 5;
1670
            }
1671
 
1719 helixhorne 1672
            sectq[numclipsects++] = outersect;  // last is outer
1673
            clipinfo[numclipmaps].qend = numclipsects-1;
1674
 
1675
            // normalize
1676
            maxdist = 0;
1677
 
1678
            for (scnt=clipinfo[numclipmaps].qbeg; scnt<=clipinfo[numclipmaps].qend; scnt++)
1679
            {
1680
                k = sectq[scnt];
1681
 
1682
                x = sprite[i].x;
1683
                y = sprite[i].y;
1684
                z = sprite[i].z;
1685
 
1722 helixhorne 1686
                sector[k].floorz -= z;
1687
                sector[k].ceilingz -= z;
1688
 
1719 helixhorne 1689
                if (scnt==clipinfo[numclipmaps].qbeg)
1690
                {
1691
                    // backup sprite tags since we'll discard sprites later
1692
                    sector[k].CM_XREPEAT = sprite[i].xrepeat;
1693
                    sector[k].CM_YREPEAT = sprite[i].yrepeat;
1694
                    sector[k].CM_XOFFSET = sprite[i].xoffset;
1695
                    sector[k].CM_YOFFSET = sprite[i].yoffset;
1696
                    sector[k].CM_CSTAT = sprite[i].cstat;
1697
                    sector[k].CM_ANG = sprite[i].ang;
1698
                }
1699
 
1700
                // backup floor and ceiling z
1701
                CM_FLOORZ(k) = sector[k].floorz;
1702
                CM_CEILINGZ(k) = sector[k].ceilingz;
1703
 
1704
                for (w=sector[k].wallptr; w<sector[k].wallptr+sector[k].wallnum; w++)
1705
                {
1706
                    wall[w].x -= x;
1707
                    wall[w].y -= y;
1708
 
1709
                    if (scnt!=clipinfo[numclipmaps].qend)
1710
                    {
1711
                        if (CM_NOROT(i))
1712
                        {
1713
                            if (klabs(wall[w].x) > maxdist)
1714
                                maxdist = klabs(wall[w].x);
1715
                            if (klabs(wall[w].y) > maxdist)
1716
                                maxdist = klabs(wall[w].y);
1717
                        }
1718
                        else
1719
                        {
2791 helixhorne 1720
                            int32_t tmp = ksqrt(uhypsq(wall[w].x, wall[w].y));
1719 helixhorne 1721
                            if (tmp > maxdist)
1722
                                maxdist = tmp;
1723
                        }
1724
                    }
1725
 
1726
                    // aliasing
1727
                    if (wall[w].lotag>0 || wall[w].hitag>0)
1728
                    {
1729
                        int32_t ii;
1730
 
1731
                        if (wall[w].lotag>0 && wall[w].hitag>0)
1732
                        {
1733
                            if (wall[w].lotag > wall[w].hitag)
1734
                                swapshort(&wall[w].lotag, &wall[w].hitag);
1735
 
1777 helixhorne 1736
                            for (ii=wall[w].lotag; ii<wall[w].hitag; ii++)
1719 helixhorne 1737
                                tempictoidx[ii] = numclipmaps;
1738
                        }
1739
                        else if (wall[w].lotag>0)
1740
                        {
1741
                            if (wall[w].lotag<MAXTILES)
1742
                                tempictoidx[wall[w].lotag] = numclipmaps;
1743
                        }
1744
                        else
1745
                        {
1746
                            if (wall[w].hitag<MAXTILES)
1762 terminx 1747
                                tempictoidx[wall[w].hitag] = numclipmaps;
1719 helixhorne 1748
                        }
1749
                    }
1750
 
1751
                    CM_WALL_X(w) = wall[w].x;
1752
                    CM_WALL_Y(w) = wall[w].y;
1753
                }
1754
            }
1755
 
1756
            clipinfo[numclipmaps].maxdist = maxdist;
1757
            numclipmaps++;
1758
        }
1759
    }
1760
 
1722 helixhorne 1761
    // yes, too much copying, but better than ugly code
1762
    Bmemcpy(loadsector, sector, ournumsectors*sizeof(sectortype));
1763
    Bmemcpy(loadwall, wall, ournumwalls*sizeof(walltype));
1764
 
1760 helixhorne 1765
    // loadwallinv will contain all walls with inverted orientation for x/y-flip handling
4984 terminx 1766
    loadwallinv = (twalltype *)Xmalloc(ournumwalls*sizeof(walltype));
2495 hendricks2 1767
 
1760 helixhorne 1768
    {
1769
        int32_t j, loopstart, loopend, numloopwalls;
1770
 
1771
        // invert walls!
1772
        loopstart = 0;
1773
        for (j=0; j<ournumwalls; j++)
1774
        {
1775
            wall[j].nextsector = wall[j].nextwall = -1;
1776
 
1777
            if (wall[j].point2 < j)
1778
            {
1779
                loopend = j+1;
1780
                numloopwalls = loopend-loopstart;
1781
 
1782
                if (numloopwalls<3)
1783
                {
1784
                    loopstart = loopend;
1785
                    continue;
1786
                }
1787
 
1788
                for (k=0; k<numloopwalls; k++)
1789
                {
1790
                    wall[loopstart+k].x = loadwall[loopstart + (numloopwalls+1-k)%numloopwalls].x;
1791
                    wall[loopstart+k].y = loadwall[loopstart + (numloopwalls+1-k)%numloopwalls].y;
1792
 
1793
                    CM_WALL_X(loopstart+k) = wall[loopstart+k].x;
1794
                    CM_WALL_Y(loopstart+k) = wall[loopstart+k].y;
1795
                }
1796
 
1797
                loopstart = loopend;
1798
            }
1799
        }
1800
 
1801
        // reconstruct wall connections
1802
        for (i=0; i<ournumsectors; i++)
1803
        {
1804
            for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
1805
                checksectorpointer(j, i);
1806
        }
1807
    }
1808
    Bmemcpy(loadwallinv, wall, ournumwalls*sizeof(walltype));
1809
 
1719 helixhorne 1810
    clipmapinfo.numsectors = numsectors;
1722 helixhorne 1811
    clipmapinfo.sector = loadsector;
1719 helixhorne 1812
    clipmapinfo.numwalls = numwalls;
1722 helixhorne 1813
    clipmapinfo.wall = loadwall;
1719 helixhorne 1814
 
1815
    for (i=0; i<MAXTILES; i++)
1816
    {
1817
        if (pictoidx[i]==-1 && tempictoidx[i]>=0)
1818
            pictoidx[i]=tempictoidx[i];
1819
    }
1820
 
1722 helixhorne 1821
    Bfree(loadsprite); loadsprite=NULL;
1822
    Bfree(tempictoidx); tempictoidx=NULL;
1719 helixhorne 1823
 
1728 helixhorne 1824
    // don't let other code be distracted by the temporary map we constructed
1825
    numsectors = 0;
1826
    numwalls = 0;
1760 helixhorne 1827
    initspritelists();
1728 helixhorne 1828
 
2495 hendricks2 1829
    if (lwcp > 0)
1830
        initprintf("Loaded clip map%s.\n", lwcp==1?"":"s");
1728 helixhorne 1831
 
2502 helixhorne 1832
    Bfree(fisec);
1833
    Bfree(fispr);
2495 hendricks2 1834
 
1719 helixhorne 1835
    return 0;
1836
}
4574 helixhorne 1837
 
1838
 
1839
int32_t clipshape_idx_for_sprite(spritetype *curspr, int32_t curidx)
1840
{
1841
    if (curidx < 0)  // per-sprite init
1842
        curidx = pictoidx[curspr->picnum];
1843
    else
1844
        curidx = clipinfo[curidx].next;
1845
 
1846
    while (curidx>=0 && (curspr->cstat&32) != (sector[sectq[clipinfo[curidx].qbeg]].CM_CSTAT&32))
1847
        curidx = clipinfo[curidx].next;
1848
 
1849
    return curidx;
1850
}
1851
#else
1852
int32_t clipshape_idx_for_sprite(spritetype *curspr, int32_t curidx)
1853
{
1854
    UNREFERENCED_PARAMETER(curspr);
1855
    UNREFERENCED_PARAMETER(curidx);
1856
    return -1;
1857
}
1858
#endif  // HAVE_CLIPSHAPE_FEATURE
1719 helixhorne 1859
////// //////
1860
 
1886 helixhorne 1861
#define WALLS_ARE_CONSISTENT(k) ((wall[k].x == x2 && wall[k].y == y2)   \
1862
                                 && ((wall[wall[k].point2]).x == x1 && (wall[wall[k].point2]).y == y1))
1719 helixhorne 1863
 
1901 helixhorne 1864
static int32_t getscore(int32_t w1c, int32_t w1f, int32_t w2c, int32_t w2f)
1865
{
1866
    if (w1c > w1f)
1867
        swaplong(&w1c, &w1f);
1868
    if (w2c > w2f)
1869
        swaplong(&w2c, &w2f);
1870
 
1871
    // now: c <= f for each "wall-vline"
1872
 
4984 terminx 1873
    int32_t maxceil = max(w1c, w2c);
1874
    int32_t minflor = min(w1f, w2f);
1901 helixhorne 1875
 
1876
    return minflor-maxceil;
1877
}
1878
 
1886 helixhorne 1879
const int16_t *chsecptr_onextwall = NULL;
1880
 
1760 helixhorne 1881
int32_t checksectorpointer(int16_t i, int16_t sectnum)
1882
{
2048 helixhorne 1883
    int32_t startsec, endsec;
1760 helixhorne 1884
    int32_t j, k, startwall, endwall, x1, y1, x2, y2, numnewwalls=0;
1901 helixhorne 1885
    int32_t bestnextwall=-1, bestnextsec=-1, bestwallscore=INT32_MIN;
1886
    int32_t cz[4], fz[4], tmp[2], tmpscore=0;
1887
#ifdef YAX_ENABLE
1888
    int16_t cb[2], fb[2];
1889
#endif
1760 helixhorne 1890
 
1891
#if 0
1892
    if (checksectorpointer_warn && (i<0 || i>=max(numwalls,newnumwalls)))
1893
    {
1894
        char buf[128];
1895
        Bsprintf(buf, "WARN: checksectorpointer called with i=%d but (new)numwalls=%d", i, max(numwalls,newnumwalls));
1896
        OSD_Printf("%s\n", buf);
1897
        printmessage16("%s", buf);
1898
        return 0;
1899
    }
1900
#endif
1901
 
1902
    x1 = wall[i].x;
1903
    y1 = wall[i].y;
1904
    x2 = (wall[wall[i].point2]).x;
1905
    y2 = (wall[wall[i].point2]).y;
1906
 
1866 helixhorne 1907
    k = wall[i].nextwall;
1908
    if (k >= 0)          //Check for early exit
1760 helixhorne 1909
    {
1886 helixhorne 1910
        if (WALLS_ARE_CONSISTENT(k))
1911
            return 0;
1866 helixhorne 1912
 
1913
        wall[k].nextwall = wall[k].nextsector = -1;
1760 helixhorne 1914
    }
1915
 
2048 helixhorne 1916
    if ((unsigned)wall[i].nextsector < (unsigned)numsectors && wall[i].nextwall < 0)
1917
    {
1918
        // if we have a nextsector but no nextwall, take this as a hint
1919
        // to search only the walls of that sector
1920
        startsec = wall[i].nextsector;
1921
        endsec = startsec+1;
1922
    }
1923
    else
1924
    {
1925
        startsec = 0;
1926
        endsec = numsectors;
1927
    }
1928
 
1866 helixhorne 1929
    wall[i].nextsector = wall[i].nextwall = -1;
1930
 
1886 helixhorne 1931
    if (chsecptr_onextwall && (k=chsecptr_onextwall[i])>=0 && wall[k].nextwall<0)
1932
    {
1901 helixhorne 1933
        // old next wall found
1886 helixhorne 1934
        if (WALLS_ARE_CONSISTENT(k))
1935
        {
1936
            j = sectorofwall(k);
1937
 
1938
            wall[i].nextsector = j;
1939
            wall[i].nextwall = k;
1940
            wall[k].nextsector = sectnum;
1941
            wall[k].nextwall = i;
1942
 
1943
            return 1;
1944
        }
1945
    }
1946
 
2048 helixhorne 1947
    for (j=startsec; j<endsec; j++)
1760 helixhorne 1948
    {
1875 helixhorne 1949
        if (j == sectnum)
1950
            continue;
1951
 
1869 helixhorne 1952
        YAX_SKIPSECTOR(j);
1953
 
1760 helixhorne 1954
        startwall = sector[j].wallptr;
1886 helixhorne 1955
        endwall = startwall + sector[j].wallnum;
1956
        for (k=startwall; k<endwall; k++)
1760 helixhorne 1957
        {
1886 helixhorne 1958
            if (!WALLS_ARE_CONSISTENT(k))
1866 helixhorne 1959
                continue;
1790 helixhorne 1960
 
1866 helixhorne 1961
            // Don't create link if the other side is connected to another wall.
1962
            // The nextwall relation should be definitely one-to-one at all times!
1963
            if (wall[k].nextwall>=0 && wall[k].nextwall != i)
1964
                continue;
1901 helixhorne 1965
#ifdef YAX_ENABLE
1966
            yax_getbunches(sectnum, &cb[0], &fb[0]);
1967
            yax_getbunches(j, &cb[1], &fb[1]);
1866 helixhorne 1968
 
1901 helixhorne 1969
            if ((cb[0]>=0 && cb[0]==cb[1]) || (fb[0]>=0 && fb[0]==fb[1]))
1866 helixhorne 1970
            {
1901 helixhorne 1971
                tmpscore = INT32_MAX;
1866 helixhorne 1972
            }
1901 helixhorne 1973
            else
1974
#endif
1975
            {
1976
                getzsofslope(sectnum, x1,y1, &cz[0],&fz[0]);
1977
                getzsofslope(sectnum, x2,y2, &cz[1],&fz[1]);
1978
                getzsofslope(j, x1,y1, &cz[2],&fz[2]);
1979
                getzsofslope(j, x2,y2, &cz[3],&fz[3]);
1866 helixhorne 1980
 
1901 helixhorne 1981
                tmp[0] = getscore(cz[0],fz[0], cz[2],fz[2]);
1982
                tmp[1] = getscore(cz[1],fz[1], cz[3],fz[3]);
1983
 
1984
                if ((tmp[0]^tmp[1]) >= 0)
1985
                    tmpscore = tmp[0]+tmp[1];
1986
                else
1987
                    tmpscore = max(tmp[0], tmp[1]);
1988
            }
1989
 
1990
            if (bestnextwall == -1 || tmpscore > bestwallscore)
1991
            {
1992
                bestwallscore = tmpscore;
1993
                bestnextwall = k;
1994
                bestnextsec = j;
1995
            }
1996
 
1997
            numnewwalls++;
1760 helixhorne 1998
        }
1999
    }
1886 helixhorne 2000
 
1901 helixhorne 2001
    // sectnum -2 means dry run
2002
    if (bestnextwall >= 0 && sectnum!=-2)
2003
#ifdef YAX_ENABLE
2048 helixhorne 2004
        // for walls with TROR neighbors, be conservative in case if score <=0
2005
        // (meaning that no wall area is mutually visible) -- it could be that
2006
        // another sector is a better candidate later on
1901 helixhorne 2007
        if ((yax_getnextwall(i, 0)<0 && yax_getnextwall(i, 1)<0) || bestwallscore>0)
2008
#endif
2009
        {
2010
//    initprintf("w%d new nw=%d (score %d)\n", i, bestnextwall, bestwallscore)
2011
            wall[i].nextsector = bestnextsec;
2012
            wall[i].nextwall = bestnextwall;
2013
            wall[bestnextwall].nextsector = sectnum;
2014
            wall[bestnextwall].nextwall = i;
2015
        }
2016
 
1886 helixhorne 2017
    return numnewwalls;
1760 helixhorne 2018
}
2019
 
1886 helixhorne 2020
#undef WALLS_ARE_CONSISTENT
1760 helixhorne 2021
 
1886 helixhorne 2022
 
1454 terminx 2023
#if defined(_MSC_VER) && !defined(NOASM)
5 Plagman 2024
 
2025
//
2026
// Microsoft C Inline Assembly Routines
2027
//
2028
 
1205 terminx 2029
static inline int32_t nsqrtasm(int32_t a)
5 Plagman 2030
{
584 terminx 2031
    _asm
2032
    {
5 Plagman 2033
        push ebx
2034
        mov eax, a
2035
        test eax, 0xff000000
2036
        mov ebx, eax
1206 terminx 2037
        jnz short over24
5 Plagman 2038
        shr ebx, 12
2039
        mov cx, word ptr shlookup[ebx*2]
1206 terminx 2040
        jmp short under24
1762 terminx 2041
        over24:
5 Plagman 2042
        shr ebx, 24
2043
        mov cx, word ptr shlookup[ebx*2+8192]
1762 terminx 2044
        under24:
5 Plagman 2045
        shr eax, cl
2046
        mov cl, ch
2047
        mov ax, word ptr sqrtable[eax*2]
2048
        shr eax, cl
2049
        pop ebx
2050
    }
2051
}
2052
 
1205 terminx 2053
static inline int32_t msqrtasm(int32_t c)
5 Plagman 2054
{
584 terminx 2055
    _asm
2056
    {
5 Plagman 2057
        push ebx
2058
        mov ecx, c
2059
        mov eax, 0x40000000
2060
        mov ebx, 0x20000000
1762 terminx 2061
        begit:
5 Plagman 2062
        cmp ecx, eax
2063
        jl skip
2064
        sub ecx, eax
2065
        lea eax, [eax+ebx*4]
1762 terminx 2066
        skip:
5 Plagman 2067
        sub eax, ebx
2068
        shr eax, 1
2069
        shr ebx, 2
2070
        jnz begit
2071
        cmp ecx, eax
2072
        sbb eax, -1
2073
        shr eax, 1
2074
        pop ebx
2075
    }
2076
}
2077
 
1205 terminx 2078
static inline int32_t getclipmask(int32_t a, int32_t b, int32_t c, int32_t d)
5 Plagman 2079
{
584 terminx 2080
    _asm
2081
    {
5 Plagman 2082
        push ebx
2083
        mov eax, a
2084
        mov ebx, b
2085
        mov ecx, c
2086
        mov edx, d
2087
        sar eax, 31
2088
        add ebx, ebx
584 terminx 2089
        adc eax, eax
2090
        add ecx, ecx
2091
        adc eax, eax
2092
        add edx, edx
2093
        adc eax, eax
2094
        mov ebx, eax
2095
        shl ebx, 4
2096
        or al, 0xf0
2097
        xor eax, ebx
2098
        pop ebx
2099
    }
2100
}
5 Plagman 2101
 
1205 terminx 2102
static inline int32_t getkensmessagecrc(void *b)
5 Plagman 2103
{
584 terminx 2104
    _asm
2105
    {
5 Plagman 2106
        push ebx
2107
        mov ebx, b
2108
        xor eax, eax
2109
        mov ecx, 32
1762 terminx 2110
        beg:
5 Plagman 2111
        mov edx, dword ptr [ebx+ecx*4-4]
2112
        ror edx, cl
2113
        adc eax, edx
2114
        bswap eax
1206 terminx 2115
        loop short beg
5 Plagman 2116
        pop ebx
2117
    }
2118
}
2119
 
194 terminx 2120
#elif defined(__GNUC__) && defined(__i386__) && !defined(NOASM) // _MSC_VER
5 Plagman 2121
 
2122
//
2123
// GCC "Inline" Assembly Routines
2124
//
2125
 
2126
#define nsqrtasm(a) \
1205 terminx 2127
    ({ int32_t __r, __a=(a); \
5 Plagman 2128
       __asm__ __volatile__ ( \
2129
        "testl $0xff000000, %%eax\n\t" \
2130
        "movl %%eax, %%ebx\n\t" \
2131
        "jnz 0f\n\t" \
2132
        "shrl $12, %%ebx\n\t" \
4321 hendricks2 2133
        "movw " ASMSYM("shlookup") "(,%%ebx,2), %%cx\n\t" \
5 Plagman 2134
        "jmp 1f\n\t" \
2135
        "0:\n\t" \
2136
        "shrl $24, %%ebx\n\t" \
4321 hendricks2 2137
        "movw (" ASMSYM("shlookup") "+8192)(,%%ebx,2), %%cx\n\t" \
5 Plagman 2138
        "1:\n\t" \
2139
        "shrl %%cl, %%eax\n\t" \
2140
        "movb %%ch, %%cl\n\t" \
4321 hendricks2 2141
        "movw " ASMSYM("sqrtable") "(,%%eax,2), %%ax\n\t" \
5 Plagman 2142
        "shrl %%cl, %%eax" \
2143
        : "=a" (__r) : "a" (__a) : "ebx", "ecx", "cc"); \
2144
     __r; })
2145
 
109 terminx 2146
// edx is blown by this code somehow?!
5 Plagman 2147
#define msqrtasm(c) \
1205 terminx 2148
    ({ int32_t __r, __c=(c); \
5 Plagman 2149
       __asm__ __volatile__ ( \
2150
        "movl $0x40000000, %%eax\n\t" \
2151
        "movl $0x20000000, %%ebx\n\t" \
2152
        "0:\n\t" \
2153
        "cmpl %%eax, %%ecx\n\t" \
2154
        "jl 1f\n\t" \
2155
        "subl %%eax, %%ecx\n\t" \
2156
        "leal (%%eax,%%ebx,4), %%eax\n\t" \
2157
        "1:\n\t" \
2158
        "subl %%ebx, %%eax\n\t" \
2159
        "shrl $1, %%eax\n\t" \
2160
        "shrl $2, %%ebx\n\t" \
2161
        "jnz 0b\n\t" \
2162
        "cmpl %%eax, %%ecx\n\t" \
2163
        "sbbl $-1, %%eax\n\t" \
2164
        "shrl $1, %%eax" \
2165
        : "=a" (__r) : "c" (__c) : "edx","ebx", "cc"); \
2166
     __r; })
2167
 
2168
#define getclipmask(a,b,c,d) \
1205 terminx 2169
    ({ int32_t __a=(a), __b=(b), __c=(c), __d=(d); \
5 Plagman 2170
       __asm__ __volatile__ ("sarl $31, %%eax; addl %%ebx, %%ebx; adcl %%eax, %%eax; " \
2171
                "addl %%ecx, %%ecx; adcl %%eax, %%eax; addl %%edx, %%edx; " \
2172
                "adcl %%eax, %%eax; movl %%eax, %%ebx; shl $4, %%ebx; " \
2173
                "orb $0xf0, %%al; xorl %%ebx, %%eax" \
2174
        : "=a" (__a), "=b" (__b), "=c" (__c), "=d" (__d) \
2175
        : "a" (__a), "b" (__b), "c" (__c), "d" (__d) : "cc"); \
2176
     __a; })
2177
 
2178
 
2179
#define getkensmessagecrc(b) \
1205 terminx 2180
    ({ int32_t __a, __b=(b); \
5 Plagman 2181
       __asm__ __volatile__ ( \
2182
        "xorl %%eax, %%eax\n\t" \
2183
        "movl $32, %%ecx\n\t" \
2184
        "0:\n\t" \
2185
        "movl -4(%%ebx,%%ecx,4), %%edx\n\t" \
2186
        "rorl %%cl, %%edx\n\t" \
2187
        "adcl %%edx, %%eax\n\t" \
2188
        "bswapl %%eax\n\t" \
2189
        "loop 0b" \
2190
        : "=a" (__a) : "b" (__b) : "ecx", "edx" \
2191
     __a; })
2192
 
2193
#else   // __GNUC__ && __i386__
2194
 
2793 helixhorne 2195
static inline int32_t nsqrtasm(uint32_t a)
584 terminx 2196
{
2197
    // JBF 20030901: This was a damn lot simpler to reverse engineer than
194 terminx 2198
    // msqrtasm was. Really, it was just like simplifying an algebra equation.
1205 terminx 2199
    uint16_t c;
5 Plagman 2200
 
584 terminx 2201
    if (a & 0xff000000)                         // test eax, 0xff000000  /  jnz short over24
2202
    {
194 terminx 2203
        c = shlookup[(a >> 24) + 4096]; // mov ebx, eax
2204
        // over24: shr ebx, 24
2205
        // mov cx, word ptr shlookup[ebx*2+8192]
584 terminx 2206
    }
2207
    else
2208
    {
194 terminx 2209
        c = shlookup[a >> 12];          // mov ebx, eax
2210
        // shr ebx, 12
2211
        // mov cx, word ptr shlookup[ebx*2]
2212
        // jmp short under24
2213
    }
2214
    a >>= c&0xff;                               // under24: shr eax, cl
2215
    a = (a&0xffff0000)|(sqrtable[a]);   // mov ax, word ptr sqrtable[eax*2]
2216
    a >>= ((c&0xff00) >> 8);            // mov cl, ch
2217
    // shr eax, cl
2218
    return a;
2219
}
2220
 
1205 terminx 2221
static inline int32_t msqrtasm(uint32_t c)
194 terminx 2222
{
1205 terminx 2223
    uint32_t a,b;
194 terminx 2224
 
2225
    a = 0x40000000l;            // mov eax, 0x40000000
2226
    b = 0x20000000l;            // mov ebx, 0x20000000
584 terminx 2227
    do                                  // begit:
2228
    {
2229
        if (c >= a)             // cmp ecx, eax  /  jl skip
2230
        {
194 terminx 2231
            c -= a;             // sub ecx, eax
2232
            a += b*4;   // lea eax, [eax+ebx*4]
2233
        }                       // skip:
2234
        a -= b;                 // sub eax, ebx
2235
        a >>= 1;                // shr eax, 1
2236
        b >>= 2;                // shr ebx, 2
584 terminx 2237
    }
2238
    while (b);                  // jnz begit
194 terminx 2239
    if (c >= a)                 // cmp ecx, eax
2240
        a++;                    // sbb eax, -1
2241
    a >>= 1;                    // shr eax, 1
2242
    return a;
2243
}
2244
 
1205 terminx 2245
static inline int32_t getclipmask(int32_t a, int32_t b, int32_t c, int32_t d)
584 terminx 2246
{
2247
    // Ken did this
4984 terminx 2248
    d = ((a<0)<<3) + ((b<0)<<2) + ((c<0)<<1) + (d<0);
194 terminx 2249
    return(((d<<4)^0xf0)|d);
2250
}
2251
 
1205 terminx 2252
inline int32_t getkensmessagecrc(int32_t b)
194 terminx 2253
{
2287 helixhorne 2254
    UNREFERENCED_PARAMETER(b);
194 terminx 2255
    return 0x56c764d4l;
2256
}
2257
 
5 Plagman 2258
#endif
2259
 
2260
 
2020 helixhorne 2261
int32_t xb1[MAXWALLSB];  // Polymost uses this as a temp array
2262
static int32_t yb1[MAXWALLSB], xb2[MAXWALLSB], yb2[MAXWALLSB];
2263
int32_t rx1[MAXWALLSB], ry1[MAXWALLSB];
2264
static int32_t rx2[MAXWALLSB], ry2[MAXWALLSB];
4623 terminx 2265
int16_t bunchp2[MAXWALLSB], thesector[MAXWALLSB];
5 Plagman 2266
 
1205 terminx 2267
int16_t bunchfirst[MAXWALLSB], bunchlast[MAXWALLSB];
5 Plagman 2268
 
4695 terminx 2269
static int32_t nodesperline, ysavecnt;
2270
static int16_t *smost, *umost, *dmost, *bakumost, *bakdmost;
2271
static int16_t *uplc, *dplc, *uwall, *dwall;
2272
static int32_t *swplc, *lplc, *swall, *lwall;
2273
#ifdef HIGH_PRECISION_SPRITE
2274
static float *swallf;
2275
#endif
2276
 
1932 helixhorne 2277
static int32_t smostcnt;
2216 helixhorne 2278
static int32_t smoststart[MAXWALLSB];
5 Plagman 2279
static char smostwalltype[MAXWALLSB];
2024 helixhorne 2280
static int32_t smostwall[MAXWALLSB], smostwallcnt = -1;
5 Plagman 2281
 
4696 terminx 2282
static vec3_t spritesxyz[MAXSPRITESONSCREEN+1];
5 Plagman 2283
 
1205 terminx 2284
int32_t xdimen = -1, xdimenrecip, halfxdimen, xdimenscale, xdimscale;
4768 hendricks2 2285
float fxdimen = -1.f;
2281 helixhorne 2286
int32_t ydimen;
2020 helixhorne 2287
static int32_t wx1, wy1, wx2, wy2;
3400 helixhorne 2288
intptr_t frameoffset;
5 Plagman 2289
 
1205 terminx 2290
static int32_t nrx1[8], nry1[8], nrx2[8], nry2[8]; // JBF 20031206: Thanks Ken
5 Plagman 2291
 
1205 terminx 2292
static int32_t rxi[8], ryi[8], rzi[8], rxi2[8], ryi2[8], rzi2[8];
2293
static int32_t xsi[8], ysi[8], horizycent;
2701 helixhorne 2294
static int32_t *horizlookup=0, *horizlookup2=0;
5 Plagman 2295
 
1205 terminx 2296
int32_t globalposx, globalposy, globalposz, globalhoriz;
4667 terminx 2297
float fglobalposx, fglobalposy, fglobalposz;
1205 terminx 2298
int16_t globalang, globalcursectnum;
2299
int32_t globalpal, cosglobalang, singlobalang;
4301 helixhorne 2300
static int32_t globalblend;
1205 terminx 2301
int32_t cosviewingrangeglobalang, sinviewingrangeglobalang;
2281 helixhorne 2302
static char *globalpalwritten;
3763 terminx 2303
static int32_t globaluclip, globaldclip;
2304
int32_t globvis, globalvisibility;
2305
int32_t globalhisibility, globalpisibility, globalcisibility;
2281 helixhorne 2306
//char globparaceilclip, globparaflorclip;
5 Plagman 2307
 
2281 helixhorne 2308
int32_t xyaspect;
2309
static int32_t viewingrangerecip;
5 Plagman 2310
 
2281 helixhorne 2311
static char globalxshift, globalyshift;
2312
static int32_t globalxpanning, globalypanning;
2313
int32_t globalshade, globalorientation;
2314
int16_t globalpicnum;
2315
static int16_t globalshiftval;
3483 helixhorne 2316
#ifdef HIGH_PRECISION_SPRITE
2317
static int64_t globalzd;
2318
#else
2319
static int32_t globalzd;
2320
#endif
2321
static int32_t globalyscale;
1866 helixhorne 2322
static int32_t globalxspan, globalyspan, globalispow2=1;  // true if texture has power-of-two x and y size
2281 helixhorne 2323
static intptr_t globalbufplc;
5 Plagman 2324
 
4413 helixhorne 2325
static int32_t globaly1, globalx2;
2281 helixhorne 2326
 
4454 helixhorne 2327
int16_t sectorborder[256];
2272 helixhorne 2328
int32_t ydim16, qsetmode = 0;
1843 helixhorne 2329
int16_t pointhighlight=-1, linehighlight=-1, highlightcnt=0;
4695 terminx 2330
static int32_t *lastx;
5 Plagman 2331
 
2281 helixhorne 2332
static char paletteloaded = 0;
2333
 
1205 terminx 2334
int32_t halfxdim16, midydim16;
5 Plagman 2335
 
2336
#define FASTPALGRIDSIZ 8
1205 terminx 2337
static int32_t rdist[129], gdist[129], bdist[129];
5 Plagman 2338
static char colhere[((FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2))>>3];
2339
static char colhead[(FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2)*(FASTPALGRIDSIZ+2)];
1205 terminx 2340
static int32_t colnext[256];
5 Plagman 2341
static char coldist[8] = {0,1,2,3,4,3,2,1};
1205 terminx 2342
static int32_t colscan[27];
5 Plagman 2343
 
4874 helixhorne 2344
static int16_t clipnum;
2345
static const int32_t hitscangoalx = (1<<29)-1, hitscangoaly = (1<<29)-1;
1820 terminx 2346
#ifdef USE_OPENGL
1205 terminx 2347
int32_t hitallsprites = 0;
5 Plagman 2348
#endif
2349
 
1205 terminx 2350
typedef struct { int32_t x1, y1, x2, y2; } linetype;
5 Plagman 2351
static linetype clipit[MAXCLIPNUM];
3206 helixhorne 2352
static int32_t clipsectnum, origclipsectnum, clipspritenum;
2353
static int16_t clipsectorlist[MAXCLIPNUM], origclipsectorlist[MAXCLIPNUM];
4048 helixhorne 2354
#ifdef HAVE_CLIPSHAPE_FEATURE
3206 helixhorne 2355
static int16_t clipspritelist[MAXCLIPNUM];  // sector-like sprite clipping
4048 helixhorne 2356
#endif
1205 terminx 2357
static int16_t clipobjectval[MAXCLIPNUM];
5 Plagman 2358
 
2359
typedef struct
2360
{
1205 terminx 2361
    int32_t sx, sy, z;
2362
    int16_t a, picnum;
2363
    int8_t dashade;
3609 hendricks2 2364
    char dapalnum, dastat;
4360 helixhorne 2365
    uint8_t daalpha, dablend;
3609 hendricks2 2366
    char pagesleft;
1205 terminx 2367
    int32_t cx1, cy1, cx2, cy2;
2368
    int32_t uniqid;    //JF extension
5 Plagman 2369
} permfifotype;
2370
static permfifotype permfifo[MAXPERMS];
1205 terminx 2371
static int32_t permhead = 0, permtail = 0;
5 Plagman 2372
 
4451 helixhorne 2373
EDUKE32_STATIC_ASSERT(MAXWALLSB < INT16_MAX);
2281 helixhorne 2374
int16_t numscans, numbunches;
2375
static int16_t numhits;
1205 terminx 2376
int16_t capturecount = 0;
5 Plagman 2377
 
2378
char vgapal16[4*256] =
584 terminx 2379
{
2380
    00,00,00,00, 42,00,00,00, 00,42,00,00, 42,42,00,00, 00,00,42,00,
2381
    42,00,42,00, 00,21,42,00, 42,42,42,00, 21,21,21,00, 63,21,21,00,
2382
    21,63,21,00, 63,63,21,00, 21,21,63,00, 63,21,63,00, 21,63,63,00,
2383
    63,63,63,00
2384
};
5 Plagman 2385
 
1205 terminx 2386
int16_t searchit;
2387
int32_t searchx = -1, searchy;                          //search input
2388
int16_t searchsector, searchwall, searchstat;     //search output
1706 helixhorne 2389
 
1848 helixhorne 2390
// SEARCHBOTTOMWALL:
2391
//   When aiming at a the bottom part of a 2-sided wall whose bottom part
2392
//   is swapped (.cstat&2), searchbottomwall equals that wall's .nextwall. In all
2393
//   other cases (when aiming at a wall), searchbottomwall equals searchwall.
2394
//
2395
// SEARCHISBOTTOM:
2396
//  When aiming at a 2-sided wall, 1 if aiming at the bottom part, 0 else
2397
int16_t searchbottomwall, searchisbottom;
1706 helixhorne 2398
 
5 Plagman 2399
static char artfilename[20];
4257 helixhorne 2400
static char mapartfilename[BMAX_PATH];  // map-specific ART file name
2401
static int32_t mapartfnXXofs;  // byte offset to 'XX' (the number part) in the above
1969 helixhorne 2402
static int32_t artfil = -1, artfilnum, artfilplc;
5 Plagman 2403
 
1173 terminx 2404
char inpreparemirror = 0;
1205 terminx 2405
static int32_t mirrorsx1, mirrorsy1, mirrorsx2, mirrorsy2;
5 Plagman 2406
 
1205 terminx 2407
static int32_t setviewcnt = 0; // interface layers use this now
2408
static int32_t bakframeplace[4], bakxsiz[4], bakysiz[4];
2409
static int32_t bakwindowx1[4], bakwindowy1[4];
2410
static int32_t bakwindowx2[4], bakwindowy2[4];
1820 terminx 2411
#ifdef USE_OPENGL
4606 terminx 2412
static int32_t bakrendmode;