Subversion Repositories eduke32

Rev

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