Subversion Repositories eduke32

Rev

Rev 5056 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 5056 Rev 5071
1
// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
1
// "Build Engine & Tools" Copyright (c) 1993-1997 Ken Silverman
2
// Ken Silverman's official web site: "http://www.advsys.net/ken"
2
// Ken Silverman's official web site: "http://www.advsys.net/ken"
3
// See the included license file "BUILDLIC.TXT" for license info.
3
// See the included license file "BUILDLIC.TXT" for license info.
4
//
4
//
5
// This file has been modified from Ken Silverman's original release
5
// This file has been modified from Ken Silverman's original release
6
// by Jonathon Fowler (jf@jonof.id.au)
6
// by Jonathon Fowler (jf@jonof.id.au)
7
7
8
8
9
#define ENGINE
9
#define ENGINE
10
10
11
#if (PNG_LIBPNG_VER > 10599)
11
#if (PNG_LIBPNG_VER > 10599)
12
# include <string.h>
12
# include <string.h>
13
#endif
13
#endif
14
#include "compat.h"
14
#include "compat.h"
15
#include "build.h"
15
#include "build.h"
16
#include "editor.h"
16
#include "editor.h"
17
#include "pragmas.h"
17
#include "pragmas.h"
18
#include "cache1d.h"
18
#include "cache1d.h"
19
#include "a.h"
19
#include "a.h"
20
#include "osd.h"
20
#include "osd.h"
21
#include "crc32.h"
21
#include "crc32.h"
22
#include "xxhash.h"
22
#include "xxhash.h"
23
#include "lz4.h"
23
#include "lz4.h"
24
24
25
#include "baselayer.h"
25
#include "baselayer.h"
26
#include "scriptfile.h"
26
#include "scriptfile.h"
27
27
28
#ifdef USE_OPENGL
28
#ifdef USE_OPENGL
29
# include "glbuild.h"
29
# include "glbuild.h"
30
# include "mdsprite.h"
30
# include "mdsprite.h"
31
# ifdef POLYMER
31
# ifdef POLYMER
32
#  include "polymer.h"
32
#  include "polymer.h"
33
# endif
33
# endif
34
# include "hightile.h"
34
# include "hightile.h"
35
# include "polymost.h"
35
# include "polymost.h"
36
# ifdef _WIN32
36
# ifdef _WIN32
37
#  define WIN32_LEAN_AND_MEAN
37
#  define WIN32_LEAN_AND_MEAN
38
#  include <windows.h>
38
#  include <windows.h>
39
# endif
39
# endif
40
#endif
40
#endif
41
41
42
#ifdef USE_LIBPNG
42
#ifdef USE_LIBPNG
43
//# include <setjmp.h>
43
//# include <setjmp.h>
44
# include <png.h>
44
# include <png.h>
45
#endif
45
#endif
46
46
47
#include <math.h>  // pow
47
#include <math.h>  // pow
48
48
49
#include "engine_priv.h"
49
#include "engine_priv.h"
50
50
51
#ifdef LUNATIC
51
#ifdef LUNATIC
52
# include "lunatic.h"
52
# include "lunatic.h"
53
L_State g_engState;
53
L_State g_engState;
54
#endif
54
#endif
55
55
56
#define CACHEAGETIME 16
56
#define CACHEAGETIME 16
57
57
58
//////////
58
//////////
59
// Compilation switches for optional/extended engine features
59
// Compilation switches for optional/extended engine features
60
60
61
#if !defined(__arm__) && !defined(GEKKO)
61
#if !defined(__arm__) && !defined(GEKKO)
62
# define HIGH_PRECISION_SPRITE
62
# define HIGH_PRECISION_SPRITE
63
#endif
63
#endif
64
64
65
#if !defined EDUKE32_TOUCH_DEVICES && !defined GEKKO && !defined __OPENDINGUX__
65
#if !defined EDUKE32_TOUCH_DEVICES && !defined GEKKO && !defined __OPENDINGUX__
66
// Handle absolute z difference of floor/ceiling to camera >= 1<<24.
66
// Handle absolute z difference of floor/ceiling to camera >= 1<<24.
67
// Also: higher precision view-relative x and y for drawvox().
67
// Also: higher precision view-relative x and y for drawvox().
68
# define CLASSIC_Z_DIFF_64
68
# define CLASSIC_Z_DIFF_64
69
#endif
69
#endif
70
70
71
#define MULTI_COLUMN_VLINE
71
#define MULTI_COLUMN_VLINE
72
//#define DEBUG_TILESIZY_512
72
//#define DEBUG_TILESIZY_512
73
//#define DEBUG_TILEOFFSETS
73
//#define DEBUG_TILEOFFSETS
74
//////////
74
//////////
75
75
76
#ifdef LUNATIC
76
#ifdef LUNATIC
77
# if !defined DEBUG_MAIN_ARRAYS
77
# if !defined DEBUG_MAIN_ARRAYS
78
LUNATIC_EXTERN const int32_t engine_main_arrays_are_static = 0;  // for Lunatic
78
LUNATIC_EXTERN const int32_t engine_main_arrays_are_static = 0;  // for Lunatic
79
# else
79
# else
80
LUNATIC_EXTERN const int32_t engine_main_arrays_are_static = 1;
80
LUNATIC_EXTERN const int32_t engine_main_arrays_are_static = 1;
81
# endif
81
# endif
82
82
83
#if MAXSECTORS==MAXSECTORSV8
83
#if MAXSECTORS==MAXSECTORSV8
84
LUNATIC_EXTERN const int32_t engine_v8 = 1;
84
LUNATIC_EXTERN const int32_t engine_v8 = 1;
85
#else
85
#else
86
LUNATIC_EXTERN const int32_t engine_v8 = 0;
86
LUNATIC_EXTERN const int32_t engine_v8 = 0;
87
#endif
87
#endif
88
#endif
88
#endif
89
89
90
#ifdef DEBUGGINGAIDS
90
#ifdef DEBUGGINGAIDS
91
float debug1, debug2;
91
float debug1, debug2;
92
#endif
92
#endif
93
93
94
int32_t mapversion=7; // JBF 20040211: default mapversion to 7
94
int32_t mapversion=7; // JBF 20040211: default mapversion to 7
95
int32_t g_loadedMapVersion = -1;  // -1: none (e.g. started new)
95
int32_t g_loadedMapVersion = -1;  // -1: none (e.g. started new)
96
usermaphack_t g_loadedMapHack;  // used only for the MD4 part
96
usermaphack_t g_loadedMapHack;  // used only for the MD4 part
97
97
98
int32_t compare_usermaphacks(const void *a, const void *b)
98
int32_t compare_usermaphacks(const void *a, const void *b)
99
{
99
{
100
    return Bmemcmp(((usermaphack_t*) a)->md4, ((usermaphack_t*) b)->md4, 16);
100
    return Bmemcmp(((usermaphack_t*) a)->md4, ((usermaphack_t*) b)->md4, 16);
101
}
101
}
102
usermaphack_t *usermaphacks;
102
usermaphack_t *usermaphacks;
103
int32_t num_usermaphacks;
103
int32_t num_usermaphacks;
104
104
105
static int32_t get_mapversion(void);
105
static int32_t get_mapversion(void);
106
106
107
// Handle nonpow2-ysize walls the old way?
107
// Handle nonpow2-ysize walls the old way?
108
static inline int32_t oldnonpow2(void)
108
static inline int32_t oldnonpow2(void)
109
{
109
{
110
#if !defined CLASSIC_NONPOW2_YSIZE_WALLS
110
#if !defined CLASSIC_NONPOW2_YSIZE_WALLS
111
    return 1;
111
    return 1;
112
#else
112
#else
113
    return (g_loadedMapVersion < 10);
113
    return (g_loadedMapVersion < 10);
114
#endif
114
#endif
115
}
115
}
116
116
117
static void drawpixel_safe(void *s, char a)
117
static void drawpixel_safe(void *s, char a)
118
{
118
{
119
#if defined __GNUC__
119
#if defined __GNUC__
120
    if (__builtin_expect((intptr_t)s >= frameplace && (intptr_t)s < frameplace+bytesperline*ydim, 1))
120
    if (__builtin_expect((intptr_t)s >= frameplace && (intptr_t)s < frameplace+bytesperline*ydim, 1))
121
#else
121
#else
122
    if ((intptr_t)s >= frameplace && (intptr_t)s < frameplace+bytesperline*ydim)
122
    if ((intptr_t)s >= frameplace && (intptr_t)s < frameplace+bytesperline*ydim)
123
#endif
123
#endif
124
        drawpixel(s, a);
124
        drawpixel(s, a);
125
#ifdef DEBUGGINGAIDS
125
#ifdef DEBUGGINGAIDS
126
    else
126
    else
127
    {
127
    {
128
        const char c = editorcolors[15];
128
        const char c = editorcolors[15];
129
129
130
        drawpixel((intptr_t *)frameplace, c);
130
        drawpixel((intptr_t *)frameplace, c);
131
        drawpixel((intptr_t *)frameplace+1, c);
131
        drawpixel((intptr_t *)frameplace+1, c);
132
        drawpixel((intptr_t *)frameplace+2, c);
132
        drawpixel((intptr_t *)frameplace+2, c);
133
        drawpixel((intptr_t *)frameplace+bytesperline, c);
133
        drawpixel((intptr_t *)frameplace+bytesperline, c);
134
        drawpixel((intptr_t *)frameplace+bytesperline+1, c);
134
        drawpixel((intptr_t *)frameplace+bytesperline+1, c);
135
        drawpixel((intptr_t *)frameplace+bytesperline+2, c);
135
        drawpixel((intptr_t *)frameplace+bytesperline+2, c);
136
        drawpixel((intptr_t *)frameplace+2*bytesperline, c);
136
        drawpixel((intptr_t *)frameplace+2*bytesperline, c);
137
        drawpixel((intptr_t *)frameplace+2*bytesperline+1, c);
137
        drawpixel((intptr_t *)frameplace+2*bytesperline+1, c);
138
        drawpixel((intptr_t *)frameplace+2*bytesperline+2, c);
138
        drawpixel((intptr_t *)frameplace+2*bytesperline+2, c);
139
    }
139
    }
140
#endif
140
#endif
141
}
141
}
142
142
143
//void loadvoxel(int32_t voxindex) { UNREFERENCED_PARAMATER(voxindex); }
143
//void loadvoxel(int32_t voxindex) { UNREFERENCED_PARAMATER(voxindex); }
144
int16_t tiletovox[MAXTILES];
144
int16_t tiletovox[MAXTILES];
145
int32_t usevoxels = 1;
145
int32_t usevoxels = 1;
146
#ifdef USE_OPENGL
146
#ifdef USE_OPENGL
147
static char *voxfilenames[MAXVOXELS], g_haveVoxels=0;  // for deferred voxel->model conversion
147
static char *voxfilenames[MAXVOXELS], g_haveVoxels=0;  // for deferred voxel->model conversion
148
#endif
148
#endif
149
//#define kloadvoxel loadvoxel
149
//#define kloadvoxel loadvoxel
150
150
151
int32_t novoxmips = 1;
151
int32_t novoxmips = 1;
152
int32_t editorgridextent = 131072;
152
int32_t editorgridextent = 131072;
153
153
154
//These variables need to be copied into BUILD
154
//These variables need to be copied into BUILD
155
#define MAXXSIZ 256
155
#define MAXXSIZ 256
156
#define MAXYSIZ 256
156
#define MAXYSIZ 256
157
#define MAXZSIZ 255
157
#define MAXZSIZ 255
158
#define MAXVOXMIPS 5
158
#define MAXVOXMIPS 5
159
#ifdef EDUKE32_TOUCH_DEVICES
159
#ifdef EDUKE32_TOUCH_DEVICES
160
# define DISTRECIPSIZ (65536+256)
160
# define DISTRECIPSIZ (65536+256)
161
#else
161
#else
162
# define DISTRECIPSIZ 131072
162
# define DISTRECIPSIZ 131072
163
#endif
163
#endif
164
intptr_t voxoff[MAXVOXELS][MAXVOXMIPS]; // used in KenBuild
164
intptr_t voxoff[MAXVOXELS][MAXVOXMIPS]; // used in KenBuild
165
static char voxlock[MAXVOXELS][MAXVOXMIPS];
165
static char voxlock[MAXVOXELS][MAXVOXMIPS];
166
int32_t voxscale[MAXVOXELS];
166
int32_t voxscale[MAXVOXELS];
167
167
168
static int32_t ggxinc[MAXXSIZ+1], ggyinc[MAXXSIZ+1];
168
static int32_t ggxinc[MAXXSIZ+1], ggyinc[MAXXSIZ+1];
169
static int32_t lowrecip[1024], nytooclose;
169
static int32_t lowrecip[1024], nytooclose;
170
static const int32_t nytoofar = DISTRECIPSIZ*16384ull - 1048576;
170
static const int32_t nytoofar = DISTRECIPSIZ*16384ull - 1048576;
171
static uint32_t *distrecip;
171
static uint32_t *distrecip;
172
172
173
static int32_t *lookups = NULL;
173
static int32_t *lookups = NULL;
174
static int32_t dommxoverlay = 1, beforedrawrooms = 1;
174
static int32_t dommxoverlay = 1, beforedrawrooms = 1;
175
int32_t indrawroomsandmasks = 0;
175
int32_t indrawroomsandmasks = 0;
176
176
177
static int32_t oxdimen = -1, oviewingrange = -1, oxyaspect = -1;
177
static int32_t oxdimen = -1, oviewingrange = -1, oxyaspect = -1;
178
178
179
// r_usenewaspect is the cvar, newaspect_enable to trigger the new behaviour in the code
179
// r_usenewaspect is the cvar, newaspect_enable to trigger the new behaviour in the code
180
int32_t r_usenewaspect = 1, newaspect_enable=0;
180
int32_t r_usenewaspect = 1, newaspect_enable=0;
181
uint32_t r_screenxy = 0;
181
uint32_t r_screenxy = 0;
182
182
183
int32_t globalflags;
183
int32_t globalflags;
184
184
185
int32_t curbrightness = 0, gammabrightness = 0;
185
int32_t curbrightness = 0, gammabrightness = 0;
186
186
187
float vid_gamma = DEFAULT_GAMMA;
187
float vid_gamma = DEFAULT_GAMMA;
188
float vid_contrast = DEFAULT_CONTRAST;
188
float vid_contrast = DEFAULT_CONTRAST;
189
float vid_brightness = DEFAULT_BRIGHTNESS;
189
float vid_brightness = DEFAULT_BRIGHTNESS;
190
190
191
//Textured Map variables
191
//Textured Map variables
192
static char globalpolytype;
192
static char globalpolytype;
193
static int16_t **dotp1, **dotp2;
193
static int16_t **dotp1, **dotp2;
194
194
195
static int8_t tempbuf[MAXWALLS];
195
static int8_t tempbuf[MAXWALLS];
196
196
197
// referenced from asm
197
// referenced from asm
198
#if !defined(NOASM) && defined __cplusplus
198
#if !defined(NOASM) && defined __cplusplus
199
extern "C" {
199
extern "C" {
200
#endif
200
#endif
201
int32_t ebpbak, espbak;
201
int32_t ebpbak, espbak;
202
int32_t reciptable[2048], fpuasm;
202
int32_t reciptable[2048], fpuasm;
203
intptr_t asm1, asm2, asm3, asm4, palookupoffse[4];
203
intptr_t asm1, asm2, asm3, asm4, palookupoffse[4];
204
uint32_t vplce[4];
204
uint32_t vplce[4];
205
int32_t vince[4];
205
int32_t vince[4];
206
intptr_t bufplce[4];
206
intptr_t bufplce[4];
207
int32_t globaltilesizy;
207
int32_t globaltilesizy;
208
int32_t globalx1, globaly2, globalx3, globaly3;
208
int32_t globalx1, globaly2, globalx3, globaly3;
209
#if !defined(NOASM) && defined __cplusplus
209
#if !defined(NOASM) && defined __cplusplus
210
}
210
}
211
#endif
211
#endif
212
212
213
int32_t sloptable[16384];
213
int32_t sloptable[16384];
214
static intptr_t slopalookup[16384];    // was 2048
214
static intptr_t slopalookup[16384];    // was 2048
215
#if defined(USE_OPENGL)
215
#if defined(USE_OPENGL)
216
palette_t palookupfog[MAXPALOOKUPS];
216
palette_t palookupfog[MAXPALOOKUPS];
217
#endif
217
#endif
218
218
219
// For every pal number, whether tsprite pal should not be taken over from
219
// For every pal number, whether tsprite pal should not be taken over from
220
// floor pal.
220
// floor pal.
221
// NOTE: g_noFloorPal[0] is irrelevant as it's never checked.
221
// NOTE: g_noFloorPal[0] is irrelevant as it's never checked.
222
int8_t g_noFloorPal[MAXPALOOKUPS];
222
int8_t g_noFloorPal[MAXPALOOKUPS];
223
223
224
static void *pic = NULL;
224
static void *pic = NULL;
225
225
226
// The tile file number (tilesXXX <- this) of each tile:
226
// The tile file number (tilesXXX <- this) of each tile:
227
// 0 <= . < MAXARTFILES_BASE: tile is in a "base" ART file
227
// 0 <= . < MAXARTFILES_BASE: tile is in a "base" ART file
228
// MAXARTFILES_BASE <= . < MAXARTFILES_TOTAL: tile is in a map-specific ART file
228
// MAXARTFILES_BASE <= . < MAXARTFILES_TOTAL: tile is in a map-specific ART file
229
static uint8_t tilefilenum[MAXTILES];
229
static uint8_t tilefilenum[MAXTILES];
230
EDUKE32_STATIC_ASSERT(MAXARTFILES_TOTAL <= 256);
230
EDUKE32_STATIC_ASSERT(MAXARTFILES_TOTAL <= 256);
231
231
232
static int32_t tilefileoffs[MAXTILES];
232
static int32_t tilefileoffs[MAXTILES];
233
static int32_t lastageclock;
233
static int32_t lastageclock;
234
234
235
// Backup tilefilenum[] and tilefileoffs[]. These get allocated only when
235
// Backup tilefilenum[] and tilefileoffs[]. These get allocated only when
236
// necessary (have per-map ART files).
236
// necessary (have per-map ART files).
237
static uint8_t *g_bakTileFileNum;
237
static uint8_t *g_bakTileFileNum;
238
static int32_t *g_bakTileFileOffs;
238
static int32_t *g_bakTileFileOffs;
239
static vec2_t *g_bakTileSiz;
239
static vec2_t *g_bakTileSiz;
240
static picanm_t *g_bakPicAnm;
240
static picanm_t *g_bakPicAnm;
241
// NOTE: picsiz[] is not backed up, but recalculated when necessary.
241
// NOTE: picsiz[] is not backed up, but recalculated when necessary.
242
242
243
//static int32_t artsize = 0;
243
//static int32_t artsize = 0;
244
static int32_t cachesize = 0;
244
static int32_t cachesize = 0;
245
245
246
// Whole ART file contents loaded from ZIPs in memory.
246
// Whole ART file contents loaded from ZIPs in memory.
247
static char *artptrs[MAXARTFILES_TOTAL];
247
static char *artptrs[MAXARTFILES_TOTAL];
248
248
249
static int32_t no_radarang2 = 0;
249
static int32_t no_radarang2 = 0;
250
static int16_t radarang[1280], *radarang2;
250
static int16_t radarang[1280], *radarang2;
251
251
252
uint16_t ATTRIBUTE((used)) sqrtable[4096], ATTRIBUTE((used)) shlookup[4096+256];
252
uint16_t ATTRIBUTE((used)) sqrtable[4096], ATTRIBUTE((used)) shlookup[4096+256];
253
const char pow2char[8] = {1,2,4,8,16,32,64,128};
253
const char pow2char[8] = {1,2,4,8,16,32,64,128};
254
const int32_t pow2long[32] =
254
const int32_t pow2long[32] =
255
{
255
{
256
    1, 2, 4, 8,
256
    1, 2, 4, 8,
257
    16, 32, 64, 128,
257
    16, 32, 64, 128,
258
    256, 512, 1024, 2048,
258
    256, 512, 1024, 2048,
259
    4096, 8192, 16384, 32768,
259
    4096, 8192, 16384, 32768,
260
    65536, 131072, 262144, 524288,
260
    65536, 131072, 262144, 524288,
261
    1048576, 2097152, 4194304, 8388608,
261
    1048576, 2097152, 4194304, 8388608,
262
    16777216, 33554432, 67108864, 134217728,
262
    16777216, 33554432, 67108864, 134217728,
263
    268435456, 536870912, 1073741824, 2147483647
263
    268435456, 536870912, 1073741824, 2147483647
264
};
264
};
265
265
266
char britable[16][256]; // JBF 20040207: full 8bit precision
266
char britable[16][256]; // JBF 20040207: full 8bit precision
267
267
268
extern char textfont[2048], smalltextfont[2048];
268
extern char textfont[2048], smalltextfont[2048];
269
269
270
static char kensmessage[128];
270
static char kensmessage[128];
271
const char *engineerrstr = "No error";
271
const char *engineerrstr = "No error";
272
272
273
int32_t showfirstwall=0;
273
int32_t showfirstwall=0;
274
int32_t showheightindicators=1;
274
int32_t showheightindicators=1;
275
int32_t circlewall=-1;
275
int32_t circlewall=-1;
276
276
277
int32_t whitecol;
277
int32_t whitecol;
278
278
279
#ifdef POLYMER
279
#ifdef POLYMER
280
static int16_t maphacklightcnt=0;
280
static int16_t maphacklightcnt=0;
281
static int16_t maphacklight[PR_MAXLIGHTS];
281
static int16_t maphacklight[PR_MAXLIGHTS];
282
#endif
282
#endif
283
283
284
// forward refs
284
// forward refs
285
#ifdef __cplusplus
285
#ifdef __cplusplus
286
extern "C" {
286
extern "C" {
287
#endif
287
#endif
288
void setblendtab(int32_t blend, const char *tab);
288
void setblendtab(int32_t blend, const char *tab);
289
#ifdef LUNATIC
289
#ifdef LUNATIC
290
extern const char *(getblendtab)(int32_t blend);
290
extern const char *(getblendtab)(int32_t blend);
291
int32_t setpalookup(int32_t palnum, const uint8_t *shtab);
291
int32_t setpalookup(int32_t palnum, const uint8_t *shtab);
292
#endif
292
#endif
293
void setup_sideview_sincos(void);
293
void setup_sideview_sincos(void);
294
int32_t getscreenvdisp(int32_t bz, int32_t zoome);
294
int32_t getscreenvdisp(int32_t bz, int32_t zoome);
295
void screencoords(int32_t *xres, int32_t *yres, int32_t x, int32_t y, int32_t zoome);
295
void screencoords(int32_t *xres, int32_t *yres, int32_t x, int32_t y, int32_t zoome);
296
int32_t scalescreeny(int32_t sy);
296
int32_t scalescreeny(int32_t sy);
297
#ifdef YAX_ENABLE
297
#ifdef YAX_ENABLE
298
void yax_tweakpicnums(int32_t bunchnum, int32_t cf, int32_t restore);
298
void yax_tweakpicnums(int32_t bunchnum, int32_t cf, int32_t restore);
299
#endif
299
#endif
300
int32_t getinvdisplacement(int32_t *dx, int32_t *dy, int32_t dz);
300
int32_t getinvdisplacement(int32_t *dx, int32_t *dy, int32_t dz);
301
#ifdef __cplusplus
301
#ifdef __cplusplus
302
}
302
}
303
#endif
303
#endif
304
304
305
static void scansector(int16_t startsectnum);
305
static void scansector(int16_t startsectnum);
306
static void draw_rainbow_background(void);
306
static void draw_rainbow_background(void);
307
307
308
int16_t editstatus = 0;
308
int16_t editstatus = 0;
309
static int32_t global100horiz;  // (-100..300)-scale horiz (the one passed to drawrooms)
309
static int32_t global100horiz;  // (-100..300)-scale horiz (the one passed to drawrooms)
310
310
311
311
312
////////// YAX //////////
312
////////// YAX //////////
313
313
314
int32_t numgraysects = 0;
314
int32_t numgraysects = 0;
315
uint8_t graysectbitmap[MAXSECTORS>>3];
315
uint8_t graysectbitmap[MAXSECTORS>>3];
316
uint8_t graywallbitmap[MAXWALLS>>3];
316
uint8_t graywallbitmap[MAXWALLS>>3];
317
int32_t autogray = 0, showinnergray = 1;
317
int32_t autogray = 0, showinnergray = 1;
318
318
319
//#define YAX_DEBUG_YMOSTS
319
//#define YAX_DEBUG_YMOSTS
320
320
321
#ifdef YAX_DEBUG
321
#ifdef YAX_DEBUG
322
// XXX: This could be replaced with the use of gethiticks().
322
// XXX: This could be replaced with the use of gethiticks().
323
double u64tickspersec;
323
double u64tickspersec;
324
#endif
324
#endif
325
#ifdef ENGINE_SCREENSHOT_DEBUG
325
#ifdef ENGINE_SCREENSHOT_DEBUG
326
int32_t engine_screenshot = 0;
326
int32_t engine_screenshot = 0;
327
#endif
327
#endif
328
328
329
int32_t get_alwaysshowgray(void)
329
int32_t get_alwaysshowgray(void)
330
{
330
{
331
    return showinnergray || !(editorzrange[0]==INT32_MIN && editorzrange[1]==INT32_MAX);
331
    return showinnergray || !(editorzrange[0]==INT32_MIN && editorzrange[1]==INT32_MAX);
332
}
332
}
333
333
334
void yax_updategrays(int32_t posze)
334
void yax_updategrays(int32_t posze)
335
{
335
{
336
    int32_t i, j, k=1;
336
    int32_t i, j, k=1;
337
#ifdef YAX_ENABLE
337
#ifdef YAX_ENABLE
338
    int32_t mingoodz=INT32_MAX, maxgoodz=INT32_MIN;
338
    int32_t mingoodz=INT32_MAX, maxgoodz=INT32_MIN;
339
#else
339
#else
340
    UNREFERENCED_PARAMETER(posze);
340
    UNREFERENCED_PARAMETER(posze);
341
#endif
341
#endif
342
342
343
    Bmemset(graysectbitmap, 0, sizeof(graysectbitmap));
343
    Bmemset(graysectbitmap, 0, sizeof(graysectbitmap));
344
    Bmemset(graywallbitmap, 0, sizeof(graywallbitmap));
344
    Bmemset(graywallbitmap, 0, sizeof(graywallbitmap));
345
345
346
    for (i=0; i<numsectors; i++)
346
    for (i=0; i<numsectors; i++)
347
    {
347
    {
348
#ifdef YAX_ENABLE
348
#ifdef YAX_ENABLE
349
        int16_t cb, fb;
349
        int16_t cb, fb;
350
350
351
        yax_getbunches(i, &cb, &fb);
351
        yax_getbunches(i, &cb, &fb);
352
        // update grayouts due to yax  --v-- has to be half-open  --v--
352
        // update grayouts due to yax  --v-- has to be half-open  --v--
353
        // because only one level should v  be ever active          v
353
        // because only one level should v  be ever active          v
354
        k = ((cb<0 || sector[i].ceilingz < posze) && (fb<0 || posze <= sector[i].floorz));
354
        k = ((cb<0 || sector[i].ceilingz < posze) && (fb<0 || posze <= sector[i].floorz));
355
        if (autogray && (cb>=0 || fb>=0) && (sector[i].ceilingz <= posze && posze <= sector[i].floorz))
355
        if (autogray && (cb>=0 || fb>=0) && (sector[i].ceilingz <= posze && posze <= sector[i].floorz))
356
        {
356
        {
357
            mingoodz = min(mingoodz, sector[i].ceilingz);
357
            mingoodz = min(mingoodz, sector[i].ceilingz);
358
            maxgoodz = max(maxgoodz, sector[i].floorz);
358
            maxgoodz = max(maxgoodz, sector[i].floorz);
359
        }
359
        }
360
#endif
360
#endif
361
        // update grayouts due to editorzrange
361
        // update grayouts due to editorzrange
362
        k &= (sector[i].ceilingz >= editorzrange[0] && sector[i].floorz <= editorzrange[1]);
362
        k &= (sector[i].ceilingz >= editorzrange[0] && sector[i].floorz <= editorzrange[1]);
363
363
364
        if (!k)  // outside bounds, gray out!
364
        if (!k)  // outside bounds, gray out!
365
            graysectbitmap[i>>3] |= (1<<(i&7));
365
            graysectbitmap[i>>3] |= (1<<(i&7));
366
    }
366
    }
367
367
368
#ifdef YAX_ENABLE
368
#ifdef YAX_ENABLE
369
    if (autogray && mingoodz<=maxgoodz)
369
    if (autogray && mingoodz<=maxgoodz)
370
    {
370
    {
371
        for (i=0; i<numsectors; i++)
371
        for (i=0; i<numsectors; i++)
372
            if (!(mingoodz <= sector[i].ceilingz && sector[i].floorz <= maxgoodz))
372
            if (!(mingoodz <= sector[i].ceilingz && sector[i].floorz <= maxgoodz))
373
                graysectbitmap[i>>3] |= (1<<(i&7));
373
                graysectbitmap[i>>3] |= (1<<(i&7));
374
    }
374
    }
375
#endif
375
#endif
376
376
377
    numgraysects = 0;
377
    numgraysects = 0;
378
    for (i=0; i<numsectors; i++)
378
    for (i=0; i<numsectors; i++)
379
    {
379
    {
380
        if (graysectbitmap[i>>3]&(1<<(i&7)))
380
        if (graysectbitmap[i>>3]&(1<<(i&7)))
381
        {
381
        {
382
            numgraysects++;
382
            numgraysects++;
383
            for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
383
            for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
384
                graywallbitmap[j>>3] |= (1<<(j&7));
384
                graywallbitmap[j>>3] |= (1<<(j&7));
385
        }
385
        }
386
    }
386
    }
387
}
387
}
388
388
389
389
390
#if !defined YAX_ENABLE
390
#if !defined YAX_ENABLE
391
# warning Non-TROR builds are supported only for debugging. Expect savegame breakage etc...
391
# warning Non-TROR builds are supported only for debugging. Expect savegame breakage etc...
392
#endif
392
#endif
393
393
394
#ifdef YAX_ENABLE
394
#ifdef YAX_ENABLE
395
// all references to floor/ceiling bunchnums should be through the
395
// all references to floor/ceiling bunchnums should be through the
396
// get/set functions!
396
// get/set functions!
397
397
398
int32_t g_nodraw = 0;
398
int32_t g_nodraw = 0;
399
int32_t scansector_retfast = 0;
399
int32_t scansector_retfast = 0;
400
static int32_t scansector_collectsprites = 1;
400
static int32_t scansector_collectsprites = 1;
401
int32_t yax_globalcf = -1, yax_nomaskpass=0, yax_nomaskdidit;  // engine internal
401
int32_t yax_globalcf = -1, yax_nomaskpass=0, yax_nomaskdidit;  // engine internal
402
int32_t r_tror_nomaskpass = 1;  // cvar
402
int32_t r_tror_nomaskpass = 1;  // cvar
403
int32_t yax_globallev = YAX_MAXDRAWS;
403
int32_t yax_globallev = YAX_MAXDRAWS;
404
int32_t yax_globalbunch = -1;
404
int32_t yax_globalbunch = -1;
405
405
406
// duplicated tsprites
406
// duplicated tsprites
407
//  [i]:
407
//  [i]:
408
//   i==MAXDRAWS: base level
408
//   i==MAXDRAWS: base level
409
//   i<MAXDRAWS: MAXDRAWS-i-1 is level towards ceiling
409
//   i<MAXDRAWS: MAXDRAWS-i-1 is level towards ceiling
410
//   i>MAXDRAWS: i-MAXDRAWS-1 is level towards floor
410
//   i>MAXDRAWS: i-MAXDRAWS-1 is level towards floor
411
static int16_t yax_spritesortcnt[1 + 2*YAX_MAXDRAWS];
411
static int16_t yax_spritesortcnt[1 + 2*YAX_MAXDRAWS];
412
static uint16_t yax_tsprite[1 + 2*YAX_MAXDRAWS][MAXSPRITESONSCREEN];
412
static uint16_t yax_tsprite[1 + 2*YAX_MAXDRAWS][MAXSPRITESONSCREEN];
413
static uint8_t yax_tsprfrombunch[1 + 2*YAX_MAXDRAWS][MAXSPRITESONSCREEN];
413
static uint8_t yax_tsprfrombunch[1 + 2*YAX_MAXDRAWS][MAXSPRITESONSCREEN];
414
414
415
// drawn sectors
415
// drawn sectors
416
uint8_t yax_gotsector[MAXSECTORS>>3];  // engine internal
416
uint8_t yax_gotsector[MAXSECTORS>>3];  // engine internal
417
417
418
# if !defined NEW_MAP_FORMAT
418
# if !defined NEW_MAP_FORMAT
419
// Game-time YAX data structures, V7-V9 map formats.
419
// Game-time YAX data structures, V7-V9 map formats.
420
int16_t yax_bunchnum[MAXSECTORS][2];
420
int16_t yax_bunchnum[MAXSECTORS][2];
421
int16_t yax_nextwall[MAXWALLS][2];
421
int16_t yax_nextwall[MAXWALLS][2];
422
422
423
static inline int32_t yax_islockededge(int32_t line, int32_t cf)
423
static inline int32_t yax_islockededge(int32_t line, int32_t cf)
424
{
424
{
425
    return !!(wall[line].cstat&(YAX_NEXTWALLBIT(cf)));
425
    return !!(wall[line].cstat&(YAX_NEXTWALLBIT(cf)));
426
}
426
}
427
427
428
#define YAX_PTRBUNCHNUM(Ptr, Sect, Cf) (*(&Ptr[Sect].ceilingxpanning + 8*Cf))
428
#define YAX_PTRBUNCHNUM(Ptr, Sect, Cf) (*(&Ptr[Sect].ceilingxpanning + 8*Cf))
429
#define YAX_BUNCHNUM(Sect, Cf) YAX_PTRBUNCHNUM(sector, Sect, Cf)
429
#define YAX_BUNCHNUM(Sect, Cf) YAX_PTRBUNCHNUM(sector, Sect, Cf)
430
430
431
//// bunch getters/setters
431
//// bunch getters/setters
432
int16_t yax_getbunch(int16_t i, int16_t cf)
432
int16_t yax_getbunch(int16_t i, int16_t cf)
433
{
433
{
434
    if (editstatus==0)
434
    if (editstatus==0)
435
        return yax_bunchnum[i][cf];
435
        return yax_bunchnum[i][cf];
436
436
437
    if (((*(&sector[i].ceilingstat + cf))&YAX_BIT)==0)
437
    if (((*(&sector[i].ceilingstat + cf))&YAX_BIT)==0)
438
        return -1;
438
        return -1;
439
439
440
    return YAX_BUNCHNUM(i, cf);
440
    return YAX_BUNCHNUM(i, cf);
441
}
441
}
442
# else
442
# else
443
#  define YAX_PTRBUNCHNUM(Ptr, Sect, Cf) (*((Cf) ? &(Ptr)[Sect].floorbunch : &(Ptr)[Sect].ceilingbunch))
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)
444
#  define YAX_BUNCHNUM(Sect, Cf) YAX_PTRBUNCHNUM(sector, Sect, Cf)
445
445
446
#  if !defined NEW_MAP_FORMAT
446
#  if !defined NEW_MAP_FORMAT
447
static inline int32_t yax_islockededge(int32_t line, int32_t cf)
447
static inline int32_t yax_islockededge(int32_t line, int32_t cf)
448
{
448
{
449
    return (yax_getnextwall(line, cf) >= 0);
449
    return (yax_getnextwall(line, cf) >= 0);
450
}
450
}
451
#  endif
451
#  endif
452
# endif
452
# endif
453
453
454
// bunchnum: -1: also clear yax-nextwalls (forward and reverse)
454
// bunchnum: -1: also clear yax-nextwalls (forward and reverse)
455
//           -2: don't clear reverse yax-nextwalls
455
//           -2: don't clear reverse yax-nextwalls
456
//           -3: don't clear either forward or reverse yax-nextwalls
456
//           -3: don't clear either forward or reverse yax-nextwalls
457
void yax_setbunch(int16_t i, int16_t cf, int16_t bunchnum)
457
void yax_setbunch(int16_t i, int16_t cf, int16_t bunchnum)
458
{
458
{
459
    if (editstatus==0)
459
    if (editstatus==0)
460
    {
460
    {
461
#ifdef NEW_MAP_FORMAT
461
#ifdef NEW_MAP_FORMAT
462
        YAX_BUNCHNUM(i, cf) = bunchnum;
462
        YAX_BUNCHNUM(i, cf) = bunchnum;
463
#else
463
#else
464
        yax_bunchnum[i][cf] = bunchnum;
464
        yax_bunchnum[i][cf] = bunchnum;
465
#endif
465
#endif
466
        return;
466
        return;
467
    }
467
    }
468
468
469
    if (bunchnum < 0)
469
    if (bunchnum < 0)
470
    {
470
    {
471
        int32_t j;
471
        int32_t j;
472
        int16_t ynw;
472
        int16_t ynw;
473
473
474
        if (bunchnum > -3)
474
        if (bunchnum > -3)
475
        {
475
        {
476
            // TODO: for in-game too?
476
            // TODO: for in-game too?
477
            for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
477
            for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
478
            {
478
            {
479
                ynw = yax_getnextwall(j, cf);
479
                ynw = yax_getnextwall(j, cf);
480
                if (ynw >= 0)
480
                if (ynw >= 0)
481
                {
481
                {
482
                    if (bunchnum > -2)
482
                    if (bunchnum > -2)
483
                        yax_setnextwall(ynw, !cf, -1);
483
                        yax_setnextwall(ynw, !cf, -1);
484
                    yax_setnextwall(j, cf, -1);
484
                    yax_setnextwall(j, cf, -1);
485
                }
485
                }
486
            }
486
            }
487
        }
487
        }
488
488
489
#if !defined NEW_MAP_FORMAT
489
#if !defined NEW_MAP_FORMAT
490
        *(&sector[i].ceilingstat + cf) &= ~YAX_BIT;
490
        *(&sector[i].ceilingstat + cf) &= ~YAX_BIT;
491
        // NOTE: Don't reset xpanning-as-index, since we can be called from
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.
492
        // e.g. Mapster32's "Inner loop made into new sector" functionality.
493
//        YAX_BUNCHNUM(i, cf) = 0;
493
//        YAX_BUNCHNUM(i, cf) = 0;
494
#else
494
#else
495
        YAX_BUNCHNUM(i, cf) = -1;
495
        YAX_BUNCHNUM(i, cf) = -1;
496
#endif
496
#endif
497
        return;
497
        return;
498
    }
498
    }
499
499
500
#if !defined NEW_MAP_FORMAT
500
#if !defined NEW_MAP_FORMAT
501
    *(&sector[i].ceilingstat + cf) |= YAX_BIT;
501
    *(&sector[i].ceilingstat + cf) |= YAX_BIT;
502
#endif
502
#endif
503
    YAX_BUNCHNUM(i, cf) = bunchnum;
503
    YAX_BUNCHNUM(i, cf) = bunchnum;
504
}
504
}
505
505
506
void yax_setbunches(int16_t i, int16_t cb, int16_t fb)
506
void yax_setbunches(int16_t i, int16_t cb, int16_t fb)
507
{
507
{
508
    yax_setbunch(i, YAX_CEILING, cb);
508
    yax_setbunch(i, YAX_CEILING, cb);
509
    yax_setbunch(i, YAX_FLOOR, fb);
509
    yax_setbunch(i, YAX_FLOOR, fb);
510
}
510
}
511
511
512
# if !defined NEW_MAP_FORMAT
512
# if !defined NEW_MAP_FORMAT
513
//// nextwall getters/setters
513
//// nextwall getters/setters
514
int16_t yax_getnextwall(int16_t wal, int16_t cf)
514
int16_t yax_getnextwall(int16_t wal, int16_t cf)
515
{
515
{
516
    if (editstatus==0)
516
    if (editstatus==0)
517
        return yax_nextwall[wal][cf];
517
        return yax_nextwall[wal][cf];
518
518
519
    if (!yax_islockededge(wal, cf))
519
    if (!yax_islockededge(wal, cf))
520
        return -1;
520
        return -1;
521
521
522
    return YAX_NEXTWALL(wal, cf);
522
    return YAX_NEXTWALL(wal, cf);
523
}
523
}
524
524
525
// unchecked!
525
// unchecked!
526
void yax_setnextwall(int16_t wal, int16_t cf, int16_t thenextwall)
526
void yax_setnextwall(int16_t wal, int16_t cf, int16_t thenextwall)
527
{
527
{
528
    if (editstatus==0)
528
    if (editstatus==0)
529
    {
529
    {
530
        yax_nextwall[wal][cf] = thenextwall;
530
        yax_nextwall[wal][cf] = thenextwall;
531
        return;
531
        return;
532
    }
532
    }
533
533
534
    if (thenextwall >= 0)
534
    if (thenextwall >= 0)
535
    {
535
    {
536
        wall[wal].cstat |= YAX_NEXTWALLBIT(cf);
536
        wall[wal].cstat |= YAX_NEXTWALLBIT(cf);
537
        YAX_NEXTWALL(wal, cf) = thenextwall;
537
        YAX_NEXTWALL(wal, cf) = thenextwall;
538
    }
538
    }
539
    else
539
    else
540
    {
540
    {
541
        wall[wal].cstat &= ~YAX_NEXTWALLBIT(cf);
541
        wall[wal].cstat &= ~YAX_NEXTWALLBIT(cf);
542
        YAX_NEXTWALL(wal, cf) = YAX_NEXTWALLDEFAULT(cf);
542
        YAX_NEXTWALL(wal, cf) = YAX_NEXTWALLDEFAULT(cf);
543
    }
543
    }
544
}
544
}
545
# endif
545
# endif
546
546
547
// make one step in the vertical direction, and if the wall we arrive at
547
// make one step in the vertical direction, and if the wall we arrive at
548
// is red, return its nextsector.
548
// is red, return its nextsector.
549
int16_t yax_vnextsec(int16_t line, int16_t cf)
549
int16_t yax_vnextsec(int16_t line, int16_t cf)
550
{
550
{
551
    int16_t const ynw = yax_getnextwall(line, cf);
551
    int16_t const ynw = yax_getnextwall(line, cf);
552
    return (ynw < 0) ? -1 : wall[ynw].nextsector;
552
    return (ynw < 0) ? -1 : wall[ynw].nextsector;
553
}
553
}
554
554
555
555
556
//// in-struct --> array transfer (only resetstat==0); list construction
556
//// in-struct --> array transfer (only resetstat==0); list construction
557
// resetstat:  0: reset and read data from structs and construct linked lists etc.
557
// resetstat:  0: reset and read data from structs and construct linked lists etc.
558
//             1: only reset
558
//             1: only reset
559
//             2: read data from game-time arrays and construct linked lists etc.
559
//             2: read data from game-time arrays and construct linked lists etc.
560
void yax_update(int32_t resetstat)
560
void yax_update(int32_t resetstat)
561
{
561
{
562
    int32_t i;
562
    int32_t i;
563
#if !defined NEW_MAP_FORMAT
563
#if !defined NEW_MAP_FORMAT
564
    int32_t j;
564
    int32_t j;
565
    const int32_t oeditstatus=editstatus;
565
    const int32_t oeditstatus=editstatus;
566
#endif
566
#endif
567
    int16_t cb, fb;
567
    int16_t cb, fb;
568
568
569
    if (resetstat != 2)
569
    if (resetstat != 2)
570
        numyaxbunches = 0;
570
        numyaxbunches = 0;
571
571
572
    for (i=0; i<MAXSECTORS; i++)
572
    for (i=0; i<MAXSECTORS; i++)
573
    {
573
    {
574
#if !defined NEW_MAP_FORMAT
574
#if !defined NEW_MAP_FORMAT
575
        if (resetstat != 2 || i>=numsectors)
575
        if (resetstat != 2 || i>=numsectors)
576
            yax_bunchnum[i][0] = yax_bunchnum[i][1] = -1;
576
            yax_bunchnum[i][0] = yax_bunchnum[i][1] = -1;
577
#endif
577
#endif
578
        nextsectbunch[0][i] = nextsectbunch[1][i] = -1;
578
        nextsectbunch[0][i] = nextsectbunch[1][i] = -1;
579
    }
579
    }
580
    for (i=0; i<YAX_MAXBUNCHES; i++)
580
    for (i=0; i<YAX_MAXBUNCHES; i++)
581
        headsectbunch[0][i] = headsectbunch[1][i] = -1;
581
        headsectbunch[0][i] = headsectbunch[1][i] = -1;
582
#if !defined NEW_MAP_FORMAT
582
#if !defined NEW_MAP_FORMAT
583
    for (i=0; i<MAXWALLS; i++)
583
    for (i=0; i<MAXWALLS; i++)
584
        if (resetstat != 2 || i>=numwalls)
584
        if (resetstat != 2 || i>=numwalls)
585
            yax_nextwall[i][0] = yax_nextwall[i][1] = -1;
585
            yax_nextwall[i][0] = yax_nextwall[i][1] = -1;
586
#endif
586
#endif
587
587
588
    if (resetstat==1)
588
    if (resetstat==1)
589
        return;
589
        return;
590
590
591
    // Constuct singly linked list of sectors-of-bunch.
591
    // Constuct singly linked list of sectors-of-bunch.
592
592
593
#if !defined NEW_MAP_FORMAT
593
#if !defined NEW_MAP_FORMAT
594
    // Read bunchnums directly from the sector struct in yax_[gs]etbunch{es}!
594
    // Read bunchnums directly from the sector struct in yax_[gs]etbunch{es}!
595
    editstatus = (resetstat==0);
595
    editstatus = (resetstat==0);
596
    // NOTE: Use oeditstatus to check for in-gamedness from here on!
596
    // NOTE: Use oeditstatus to check for in-gamedness from here on!
597
#endif
597
#endif
598
598
599
    if (resetstat==0)
599
    if (resetstat==0)
600
    {
600
    {
601
        // make bunchnums consecutive
601
        // make bunchnums consecutive
602
        uint8_t *const havebunch = (uint8_t *)tempbuf;
602
        uint8_t *const havebunch = (uint8_t *)tempbuf;
603
        uint8_t *const bunchmap = havebunch + (YAX_MAXBUNCHES>>3);
603
        uint8_t *const bunchmap = havebunch + (YAX_MAXBUNCHES>>3);
604
        int32_t dasub = 0;
604
        int32_t dasub = 0;
605
605
606
        Bmemset(havebunch, 0, YAX_MAXBUNCHES>>3);
606
        Bmemset(havebunch, 0, YAX_MAXBUNCHES>>3);
607
        for (i=0; i<numsectors; i++)
607
        for (i=0; i<numsectors; i++)
608
        {
608
        {
609
            yax_getbunches(i, &cb, &fb);
609
            yax_getbunches(i, &cb, &fb);
610
            if (cb>=0)
610
            if (cb>=0)
611
                havebunch[cb>>3] |= (1<<(cb&7));
611
                havebunch[cb>>3] |= (1<<(cb&7));
612
            if (fb>=0)
612
            if (fb>=0)
613
                havebunch[fb>>3] |= (1<<(fb&7));
613
                havebunch[fb>>3] |= (1<<(fb&7));
614
        }
614
        }
615
615
616
        for (i=0; i<YAX_MAXBUNCHES; i++)
616
        for (i=0; i<YAX_MAXBUNCHES; i++)
617
        {
617
        {
618
            if ((havebunch[i>>3]&(1<<(i&7)))==0)
618
            if ((havebunch[i>>3]&(1<<(i&7)))==0)
619
            {
619
            {
620
                bunchmap[i] = 255;
620
                bunchmap[i] = 255;
621
                dasub++;
621
                dasub++;
622
                continue;
622
                continue;
623
            }
623
            }
624
624
625
            bunchmap[i] = i-dasub;
625
            bunchmap[i] = i-dasub;
626
        }
626
        }
627
627
628
        for (i=0; i<numsectors; i++)
628
        for (i=0; i<numsectors; i++)
629
        {
629
        {
630
            yax_getbunches(i, &cb, &fb);
630
            yax_getbunches(i, &cb, &fb);
631
            if (cb>=0)
631
            if (cb>=0)
632
                yax_setbunch(i, YAX_CEILING, bunchmap[cb]);
632
                yax_setbunch(i, YAX_CEILING, bunchmap[cb]);
633
            if (fb>=0)
633
            if (fb>=0)
634
                yax_setbunch(i, YAX_FLOOR, bunchmap[fb]);
634
                yax_setbunch(i, YAX_FLOOR, bunchmap[fb]);
635
        }
635
        }
636
    }
636
    }
637
637
638
    // In-struct --> array transfer (resetstat==0 and !defined NEW_MAP_FORMAT)
638
    // In-struct --> array transfer (resetstat==0 and !defined NEW_MAP_FORMAT)
639
    // and list construction.
639
    // and list construction.
640
    for (i=numsectors-1; i>=0; i--)
640
    for (i=numsectors-1; i>=0; i--)
641
    {
641
    {
642
        yax_getbunches(i, &cb, &fb);
642
        yax_getbunches(i, &cb, &fb);
643
#if !defined NEW_MAP_FORMAT
643
#if !defined NEW_MAP_FORMAT
644
        if (resetstat==0)
644
        if (resetstat==0)
645
        {
645
        {
646
            yax_bunchnum[i][0] = cb;
646
            yax_bunchnum[i][0] = cb;
647
            yax_bunchnum[i][1] = fb;
647
            yax_bunchnum[i][1] = fb;
648
        }
648
        }
649
#endif
649
#endif
650
650
651
        if (cb >= 0)
651
        if (cb >= 0)
652
        {
652
        {
653
#if !defined NEW_MAP_FORMAT
653
#if !defined NEW_MAP_FORMAT
654
            if (resetstat==0)
654
            if (resetstat==0)
655
                for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
655
                for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
656
                {
656
                {
657
                    if (yax_islockededge(j,YAX_CEILING))
657
                    if (yax_islockededge(j,YAX_CEILING))
658
                    {
658
                    {
659
                        yax_nextwall[j][0] = YAX_NEXTWALL(j,0);
659
                        yax_nextwall[j][0] = YAX_NEXTWALL(j,0);
660
                        if (oeditstatus==0)
660
                        if (oeditstatus==0)
661
                            YAX_NEXTWALL(j,0) = 0;  // reset lotag!
661
                            YAX_NEXTWALL(j,0) = 0;  // reset lotag!
662
                    }
662
                    }
663
                }
663
                }
664
#endif
664
#endif
665
            if (headsectbunch[0][cb] == -1)
665
            if (headsectbunch[0][cb] == -1)
666
            {
666
            {
667
                headsectbunch[0][cb] = i;
667
                headsectbunch[0][cb] = i;
668
                // not duplicated in floors, since every extended ceiling
668
                // not duplicated in floors, since every extended ceiling
669
                // must have a corresponding floor:
669
                // must have a corresponding floor:
670
                if (resetstat==0)
670
                if (resetstat==0)
671
                    numyaxbunches++;
671
                    numyaxbunches++;
672
            }
672
            }
673
            else
673
            else
674
            {
674
            {
675
                int32_t tmpsect = headsectbunch[0][cb];
675
                int32_t tmpsect = headsectbunch[0][cb];
676
                headsectbunch[0][cb] = i;
676
                headsectbunch[0][cb] = i;
677
                nextsectbunch[0][i] = tmpsect;
677
                nextsectbunch[0][i] = tmpsect;
678
            }
678
            }
679
        }
679
        }
680
680
681
        if (fb >= 0)
681
        if (fb >= 0)
682
        {
682
        {
683
#if !defined NEW_MAP_FORMAT
683
#if !defined NEW_MAP_FORMAT
684
            if (resetstat==0)
684
            if (resetstat==0)
685
                for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
685
                for (j=sector[i].wallptr; j<sector[i].wallptr+sector[i].wallnum; j++)
686
                {
686
                {
687
                    if (yax_islockededge(j,YAX_FLOOR))
687
                    if (yax_islockededge(j,YAX_FLOOR))
688
                    {
688
                    {
689
                        yax_nextwall[j][1] = YAX_NEXTWALL(j,1);
689
                        yax_nextwall[j][1] = YAX_NEXTWALL(j,1);
690
                        if (oeditstatus==0)
690
                        if (oeditstatus==0)
691
                            YAX_NEXTWALL(j,1) = -1;  // reset extra!
691
                            YAX_NEXTWALL(j,1) = -1;  // reset extra!
692
                    }
692
                    }
693
                }
693
                }
694
#endif
694
#endif
695
            if (headsectbunch[1][fb] == -1)
695
            if (headsectbunch[1][fb] == -1)
696
                headsectbunch[1][fb] = i;
696
                headsectbunch[1][fb] = i;
697
            else
697
            else
698
            {
698
            {
699
                int32_t tmpsect = headsectbunch[1][fb];
699
                int32_t tmpsect = headsectbunch[1][fb];
700
                headsectbunch[1][fb] = i;
700
                headsectbunch[1][fb] = i;
701
                nextsectbunch[1][i] = tmpsect;
701
                nextsectbunch[1][i] = tmpsect;
702
            }
702
            }
703
        }
703
        }
704
    }
704
    }
705
705
706
#if !defined NEW_MAP_FORMAT
706
#if !defined NEW_MAP_FORMAT
707
    editstatus = oeditstatus;
707
    editstatus = oeditstatus;
708
#else
708
#else
709
    mapversion = get_mapversion();
709
    mapversion = get_mapversion();
710
#endif
710
#endif
711
}
711
}
712
712
713
int32_t yax_getneighborsect(int32_t x, int32_t y, int32_t sectnum, int32_t cf)
713
int32_t yax_getneighborsect(int32_t x, int32_t y, int32_t sectnum, int32_t cf)
714
{
714
{
715
    int16_t bunchnum = yax_getbunch(sectnum, cf);
715
    int16_t bunchnum = yax_getbunch(sectnum, cf);
716
    int32_t i;
716
    int32_t i;
717
717
718
    if (bunchnum < 0)
718
    if (bunchnum < 0)
719
        return -1;
719
        return -1;
720
720
721
    for (SECTORS_OF_BUNCH(bunchnum, !cf, i))
721
    for (SECTORS_OF_BUNCH(bunchnum, !cf, i))
722
        if (inside(x, y, i)==1)
722
        if (inside(x, y, i)==1)
723
            return i;
723
            return i;
724
724
725
    return -1;
725
    return -1;
726
}
726
}
727
727
728
// indexed as a list:
728
// indexed as a list:
729
static int16_t bunches[2][YAX_MAXBUNCHES];
729
static int16_t bunches[2][YAX_MAXBUNCHES];
730
// indexed with bunchnums directly:
730
// indexed with bunchnums directly:
731
static int16_t bunchsec[YAX_MAXBUNCHES], bunchdist[YAX_MAXBUNCHES];
731
static int16_t bunchsec[YAX_MAXBUNCHES], bunchdist[YAX_MAXBUNCHES];
732
732
733
static int32_t ymostallocsize = 0;  // numyaxbunches*xdimen (no sizeof(int16_t) here!)
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]
734
static int16_t *yumost=NULL, *ydmost=NULL;  // used as if [numyaxbunches][xdimen]
735
uint8_t haveymost[YAX_MAXBUNCHES>>3];
735
uint8_t haveymost[YAX_MAXBUNCHES>>3];
736
736
737
// adapted from build.c
737
// adapted from build.c
738
static void yax_getclosestpointonwall(int32_t dawall, int32_t *closestx, int32_t *closesty)
738
static void yax_getclosestpointonwall(int32_t dawall, int32_t *closestx, int32_t *closesty)
739
{
739
{
740
    int64_t i, j, wx,wy, wx2,wy2, dx, dy;
740
    int64_t i, j, wx,wy, wx2,wy2, dx, dy;
741
741
742
    wx = wall[dawall].x;
742
    wx = wall[dawall].x;
743
    wy = wall[dawall].y;
743
    wy = wall[dawall].y;
744
    wx2 = wall[wall[dawall].point2].x;
744
    wx2 = wall[wall[dawall].point2].x;
745
    wy2 = wall[wall[dawall].point2].y;
745
    wy2 = wall[wall[dawall].point2].y;
746
746
747
    dx = wx2 - wx;
747
    dx = wx2 - wx;
748
    dy = wy2 - wy;
748
    dy = wy2 - wy;
749
    i = dx*(globalposx-wx) + dy*(globalposy-wy);
749
    i = dx*(globalposx-wx) + dy*(globalposy-wy);
750
    if (i <= 0) { *closestx = wx; *closesty = wy; return; }
750
    if (i <= 0) { *closestx = wx; *closesty = wy; return; }
751
    j = dx*dx + dy*dy;
751
    j = dx*dx + dy*dy;
752
    if (i >= j) { *closestx = wx2; *closesty = wy2; return; }
752
    if (i >= j) { *closestx = wx2; *closesty = wy2; return; }
753
    i=((i<<15)/j)<<15;
753
    i=((i<<15)/j)<<15;
754
    *closestx = wx + ((dx*i)>>30);
754
    *closestx = wx + ((dx*i)>>30);
755
    *closesty = wy + ((dy*i)>>30);
755
    *closesty = wy + ((dy*i)>>30);
756
}
756
}
757
757
758
static inline int32_t yax_walldist(int32_t w)
758
static inline int32_t yax_walldist(int32_t w)
759
{
759
{
760
    int32_t closestx, closesty;
760
    int32_t closestx, closesty;
761
761
762
    yax_getclosestpointonwall(w, &closestx, &closesty);
762
    yax_getclosestpointonwall(w, &closestx, &closesty);
763
    return klabs(closestx-globalposx) + klabs(closesty-globalposy);
763
    return klabs(closestx-globalposx) + klabs(closesty-globalposy);
764
764
765
//    return klabs(wall[w].x-globalposx) + klabs(wall[w].y-globalposy);
765
//    return klabs(wall[w].x-globalposx) + klabs(wall[w].y-globalposy);
766
}
766
}
767
767
768
// calculate distances to bunches and best start-drawing sectors
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)
769
static void yax_scanbunches(int32_t bbeg, int32_t numhere, const uint8_t *lastgotsector)
770
{
770
{
771
    int32_t bnchcnt, bunchnum, j, k;
771
    int32_t bnchcnt, bunchnum, j, k;
772
    int32_t startwall, endwall;
772
    int32_t startwall, endwall;
773
773
774
    UNREFERENCED_PARAMETER(lastgotsector);
774
    UNREFERENCED_PARAMETER(lastgotsector);
775
775
776
    scansector_retfast = 1;
776
    scansector_retfast = 1;
777
    scansector_collectsprites = 0;
777
    scansector_collectsprites = 0;
778
778
779
    for (bnchcnt=bbeg; bnchcnt<bbeg+numhere; bnchcnt++)
779
    for (bnchcnt=bbeg; bnchcnt<bbeg+numhere; bnchcnt++)
780
    {
780
    {
781
        int32_t walldist, bestsec=-1;
781
        int32_t walldist, bestsec=-1;
782
        int32_t bestwalldist=INT32_MAX, bestbestdist=INT32_MAX;
782
        int32_t bestwalldist=INT32_MAX, bestbestdist=INT32_MAX;
783
783
784
        bunchnum = bunches[yax_globalcf][bnchcnt];
784
        bunchnum = bunches[yax_globalcf][bnchcnt];
785
785
786
        for (SECTORS_OF_BUNCH(bunchnum,!yax_globalcf, k))
786
        for (SECTORS_OF_BUNCH(bunchnum,!yax_globalcf, k))
787
        {
787
        {
788
            int32_t checkthisec = 0;
788
            int32_t checkthisec = 0;
789
789
790
            if (inside(globalposx, globalposy, k)==1)
790
            if (inside(globalposx, globalposy, k)==1)
791
            {
791
            {
792
                bestsec = k;
792
                bestsec = k;
793
                bestbestdist = 0;
793
                bestbestdist = 0;
794
                break;
794
                break;
795
            }
795
            }
796
796
797
            startwall = sector[k].wallptr;
797
            startwall = sector[k].wallptr;
798
            endwall = startwall+sector[k].wallnum;
798
            endwall = startwall+sector[k].wallnum;
799
799
800
            for (j=startwall; j<endwall; j++)
800
            for (j=startwall; j<endwall; j++)
801
            {
801
            {
802
/*
802
/*
803
                if ((w=yax_getnextwall(j,!yax_globalcf))>=0)
803
                if ((w=yax_getnextwall(j,!yax_globalcf))>=0)
804
                    if ((ns=wall[w].nextsector)>=0)
804
                    if ((ns=wall[w].nextsector)>=0)
805
                        if ((lastgotsector[ns>>3]&(1<<(ns&7)))==0)
805
                        if ((lastgotsector[ns>>3]&(1<<(ns&7)))==0)
806
                            continue;
806
                            continue;
807
*/
807
*/
808
                walldist = yax_walldist(j);
808
                walldist = yax_walldist(j);
809
                if (walldist < bestwalldist)
809
                if (walldist < bestwalldist)
810
                {
810
                {
811
                    checkthisec = 1;
811
                    checkthisec = 1;
812
                    bestwalldist = walldist;
812
                    bestwalldist = walldist;
813
                }
813
                }
814
            }
814
            }
815
815
816
            if (checkthisec)
816
            if (checkthisec)
817
            {
817
            {
818
                numscans = numbunches = 0;
818
                numscans = numbunches = 0;
819
                if (getrendermode() == REND_CLASSIC)
819
                if (getrendermode() == REND_CLASSIC)
820
                    scansector(k);
820
                    scansector(k);
821
#ifdef USE_OPENGL
821
#ifdef USE_OPENGL
822
                else
822
                else
823
                    polymost_scansector(k);
823
                    polymost_scansector(k);
824
#endif
824
#endif
825
                if (numbunches > 0)
825
                if (numbunches > 0)
826
                {
826
                {
827
                    bestsec = k;
827
                    bestsec = k;
828
                    bestbestdist = bestwalldist;
828
                    bestbestdist = bestwalldist;
829
                }
829
                }
830
            }
830
            }
831
        }
831
        }
832
832
833
        bunchsec[bunchnum] = bestsec;
833
        bunchsec[bunchnum] = bestsec;
834
        bunchdist[bunchnum] = bestbestdist;
834
        bunchdist[bunchnum] = bestbestdist;
835
    }
835
    }
836
836
837
    scansector_collectsprites = 1;
837
    scansector_collectsprites = 1;
838
    scansector_retfast = 0;
838
    scansector_retfast = 0;
839
}
839
}
840
840
841
static int yax_cmpbunches(const void *b1, const void *b2)
841
static int yax_cmpbunches(const void *b1, const void *b2)
842
{
842
{
843
    return (bunchdist[*(int16_t *)b2] - bunchdist[*(int16_t *)b1]);
843
    return (bunchdist[*(int16_t *)b2] - bunchdist[*(int16_t *)b1]);
844
}
844
}
845
845
846
846
847
void yax_tweakpicnums(int32_t bunchnum, int32_t cf, int32_t restore)
847
void yax_tweakpicnums(int32_t bunchnum, int32_t cf, int32_t restore)
848
{
848
{
849
    // for polymer, this is called before polymer_drawrooms() with restore==0
849
    // for polymer, this is called before polymer_drawrooms() with restore==0
850
    // and after polymer_drawmasks() with restore==1
850
    // and after polymer_drawmasks() with restore==1
851
851
852
    int32_t i, dastat;
852
    int32_t i, dastat;
853
    static int16_t opicnum[2][MAXSECTORS];
853
    static int16_t opicnum[2][MAXSECTORS];
854
#ifdef DEBUGGINGAIDS
854
#ifdef DEBUGGINGAIDS
855
    static uint8_t expect_restore[2][YAX_MAXBUNCHES];
855
    static uint8_t expect_restore[2][YAX_MAXBUNCHES];
856
856
857
    // must call this with restore == 0, 1,  0, 1,  0, 1,  ...
857
    // must call this with restore == 0, 1,  0, 1,  0, 1,  ...
858
    Bassert(expect_restore[cf][bunchnum] == restore);
858
    Bassert(expect_restore[cf][bunchnum] == restore);
859
    expect_restore[cf][bunchnum] = !expect_restore[cf][bunchnum];
859
    expect_restore[cf][bunchnum] = !expect_restore[cf][bunchnum];
860
#endif
860
#endif
861
861
862
    for (SECTORS_OF_BUNCH(bunchnum, cf, i))
862
    for (SECTORS_OF_BUNCH(bunchnum, cf, i))
863
    {
863
    {
864
        dastat = (SECTORFLD(i,stat, cf)&(128+256));
864
        dastat = (SECTORFLD(i,stat, cf)&(128+256));
865
865
866
        // only consider non-masked ceilings/floors
866
        // only consider non-masked ceilings/floors
867
        if (dastat==0 || (restore==1 && opicnum[cf][i]&0x8000))
867
        if (dastat==0 || (restore==1 && opicnum[cf][i]&0x8000))
868
        {
868
        {
869
            if (!restore)
869
            if (!restore)
870
            {
870
            {
871
                opicnum[cf][i] = SECTORFLD(i,picnum, cf);
871
                opicnum[cf][i] = SECTORFLD(i,picnum, cf);
872
                if (editstatus && showinvisibility)
872
                if (editstatus && showinvisibility)
873
                    SECTORFLD(i,picnum, cf) = MAXTILES-1;
873
                    SECTORFLD(i,picnum, cf) = MAXTILES-1;
874
                else //if ((dastat&(128+256))==0)
874
                else //if ((dastat&(128+256))==0)
875
                    SECTORFLD(i,picnum, cf) = 13; //FOF;
875
                    SECTORFLD(i,picnum, cf) = 13; //FOF;
876
            }
876
            }
877
            else
877
            else
878
            {
878
            {
879
                SECTORFLD(i,picnum, cf) = opicnum[cf][i];
879
                SECTORFLD(i,picnum, cf) = opicnum[cf][i];
880
            }
880
            }
881
#ifdef POLYMER
881
#ifdef POLYMER
882
            // will be called only in editor
882
            // will be called only in editor
883
            if (getrendermode() == REND_POLYMER)
883
            if (getrendermode() == REND_POLYMER)
884
            {
884
            {
885
                if (!restore)
885
                if (!restore)
886
                {
886
                {
887
                    SECTORFLD(i,stat, cf) |= 128;
887
                    SECTORFLD(i,stat, cf) |= 128;
888
                    opicnum[cf][i] |= 0x8000;
888
                    opicnum[cf][i] |= 0x8000;
889
                }
889
                }
890
                else
890
                else
891
                {
891
                {
892
                    SECTORFLD(i,stat, cf) &= ~128;
892
                    SECTORFLD(i,stat, cf) &= ~128;
893
                    SECTORFLD(i,picnum, cf) &= 0x7fff;
893
                    SECTORFLD(i,picnum, cf) &= 0x7fff;
894
                    opicnum[cf][i] = 0;
894
                    opicnum[cf][i] = 0;
895
                }
895
                }
896
            }
896
            }
897
#endif
897
#endif
898
        }
898
        }
899
    }
899
    }
900
}
900
}
901
901
902
static void yax_copytsprites()
902
static void yax_copytsprites()
903
{
903
{
904
    int32_t i, spritenum, gotthrough, sectnum;
904
    int32_t i, spritenum, gotthrough, sectnum;
905
    int32_t sortcnt = yax_spritesortcnt[yax_globallev];
905
    int32_t sortcnt = yax_spritesortcnt[yax_globallev];
906
    const spritetype *spr;
906
    const spritetype *spr;
907
907
908
    for (i=0; i<sortcnt; i++)
908
    for (i=0; i<sortcnt; i++)
909
    {
909
    {
910
        spritenum = yax_tsprite[yax_globallev][i];
910
        spritenum = yax_tsprite[yax_globallev][i];
911
911
912
        gotthrough = spritenum&(MAXSPRITES|(MAXSPRITES<<1));
912
        gotthrough = spritenum&(MAXSPRITES|(MAXSPRITES<<1));
913
913
914
        spritenum &= MAXSPRITES-1;
914
        spritenum &= MAXSPRITES-1;
915
        spr = &sprite[spritenum];
915
        spr = &sprite[spritenum];
916
        sectnum = spr->sectnum;
916
        sectnum = spr->sectnum;
917
917
918
        if (gotthrough == (MAXSPRITES|(MAXSPRITES<<1)))
918
        if (gotthrough == (MAXSPRITES|(MAXSPRITES<<1)))
919
        {
919
        {
920
            if (yax_globalbunch != yax_tsprfrombunch[yax_globallev][i])
920
            if (yax_globalbunch != yax_tsprfrombunch[yax_globallev][i])
921
                continue;
921
                continue;
922
        }
922
        }
923
        else
923
        else
924
        {
924
        {
925
            int32_t cf = -1;
925
            int32_t cf = -1;
926
926
927
            if (gotthrough == MAXSPRITES)
927
            if (gotthrough == MAXSPRITES)
928
                cf = YAX_CEILING;  // sprite got here through the ceiling of lower sector
928
                cf = YAX_CEILING;  // sprite got here through the ceiling of lower sector
929
            else if (gotthrough == (MAXSPRITES<<1))
929
            else if (gotthrough == (MAXSPRITES<<1))
930
                cf = YAX_FLOOR;  // sprite got here through the floor of upper sector
930
                cf = YAX_FLOOR;  // sprite got here through the floor of upper sector
931
931
932
            if (cf != -1)
932
            if (cf != -1)
933
            {
933
            {
934
                if ((yax_globallev-YAX_MAXDRAWS)*(-1 + 2*cf) > 0)
934
                if ((yax_globallev-YAX_MAXDRAWS)*(-1 + 2*cf) > 0)
935
                    if (yax_getbunch(sectnum, cf) != yax_globalbunch)
935
                    if (yax_getbunch(sectnum, cf) != yax_globalbunch)
936
                        continue;
936
                        continue;
937
937
938
                sectnum = yax_getneighborsect(spr->x, spr->y, sectnum, cf);
938
                sectnum = yax_getneighborsect(spr->x, spr->y, sectnum, cf);
939
                if (sectnum < 0)
939
                if (sectnum < 0)
940
                    continue;
940
                    continue;
941
            }
941
            }
942
        }
942
        }
943
943
944
        if (spritesortcnt >= MAXSPRITESONSCREEN)
944
        if (spritesortcnt >= MAXSPRITESONSCREEN)
945
            break;
945
            break;
946
946
947
        Bmemcpy(&tsprite[spritesortcnt], spr, sizeof(spritetype));
947
        Bmemcpy(&tsprite[spritesortcnt], spr, sizeof(spritetype));
948
        tsprite[spritesortcnt].owner = spritenum;
948
        tsprite[spritesortcnt].owner = spritenum;
949
949
950
        tsprite[spritesortcnt].sectnum = sectnum;  // potentially tweak sectnum!
950
        tsprite[spritesortcnt].sectnum = sectnum;  // potentially tweak sectnum!
951
        spritesortcnt++;
951
        spritesortcnt++;
952
    }
952
    }
953
}
953
}
954
954
955
955
956
void yax_preparedrawrooms(void)
956
void yax_preparedrawrooms(void)
957
{
957
{
958
    if (getrendermode() == REND_POLYMER || numyaxbunches==0)
958
    if (getrendermode() == REND_POLYMER || numyaxbunches==0)
959
        return;
959
        return;
960
960
961
    g_nodraw = 1;
961
    g_nodraw = 1;
962
    Bmemset(yax_spritesortcnt, 0, sizeof(yax_spritesortcnt));
962
    Bmemset(yax_spritesortcnt, 0, sizeof(yax_spritesortcnt));
963
    Bmemset(haveymost, 0, (numyaxbunches+7)>>3);
963
    Bmemset(haveymost, 0, (numyaxbunches+7)>>3);
964
964
965
    if (getrendermode() == REND_CLASSIC && ymostallocsize < xdimen*numyaxbunches)
965
    if (getrendermode() == REND_CLASSIC && ymostallocsize < xdimen*numyaxbunches)
966
    {
966
    {
967
        ymostallocsize = xdimen*numyaxbunches;
967
        ymostallocsize = xdimen*numyaxbunches;
968
        yumost = (int16_t *)Xrealloc(yumost, ymostallocsize*sizeof(int16_t));
968
        yumost = (int16_t *)Xrealloc(yumost, ymostallocsize*sizeof(int16_t));
969
        ydmost = (int16_t *)Xrealloc(ydmost, ymostallocsize*sizeof(int16_t));
969
        ydmost = (int16_t *)Xrealloc(ydmost, ymostallocsize*sizeof(int16_t));
970
    }
970
    }
971
}
971
}
972
972
973
void yax_drawrooms(void (*SpriteAnimFunc)(int32_t,int32_t,int32_t,int32_t),
973
void yax_drawrooms(void (*SpriteAnimFunc)(int32_t,int32_t,int32_t,int32_t),
974
                   int16_t sectnum, int32_t didmirror, int32_t smoothr)
974
                   int16_t sectnum, int32_t didmirror, int32_t smoothr)
975
{
975
{
976
    static uint8_t havebunch[YAX_MAXBUNCHES>>3];
976
    static uint8_t havebunch[YAX_MAXBUNCHES>>3];
977
977
978
    const int32_t horiz = global100horiz;
978
    const int32_t horiz = global100horiz;
979
979
980
    int32_t i, j, k, lev, cf, nmp;
980
    int32_t i, j, k, lev, cf, nmp;
981
    int32_t bnchcnt, bnchnum[2] = {0,0}, maxlev[2];
981
    int32_t bnchcnt, bnchnum[2] = {0,0}, maxlev[2];
982
    int16_t ourbunch[2] = {-1,-1}, osectnum=sectnum;
982
    int16_t ourbunch[2] = {-1,-1}, osectnum=sectnum;
983
    int32_t bnchbeg[YAX_MAXDRAWS][2], bnchend[YAX_MAXDRAWS][2];
983
    int32_t bnchbeg[YAX_MAXDRAWS][2], bnchend[YAX_MAXDRAWS][2];
984
    int32_t bbeg, numhere;
984
    int32_t bbeg, numhere;
985
985
986
    // original (1st-draw) and accumulated ('per-level') gotsector bitmaps
986
    // original (1st-draw) and accumulated ('per-level') gotsector bitmaps
987
    static uint8_t ogotsector[MAXSECTORS>>3], lgotsector[MAXSECTORS>>3];
987
    static uint8_t ogotsector[MAXSECTORS>>3], lgotsector[MAXSECTORS>>3];
988
#ifdef YAX_DEBUG
988
#ifdef YAX_DEBUG
989
    uint64_t t;
989
    uint64_t t;
990
#endif
990
#endif
991
991
992
    if (getrendermode() == REND_POLYMER || numyaxbunches==0)
992
    if (getrendermode() == REND_POLYMER || numyaxbunches==0)
993
    {
993
    {
994
#ifdef ENGINE_SCREENSHOT_DEBUG
994
#ifdef ENGINE_SCREENSHOT_DEBUG
995
        engine_screenshot = 0;
995
        engine_screenshot = 0;
996
#endif
996
#endif
997
        return;
997
        return;
998
    }
998
    }
999
999
1000
    // if we're here, there was just a drawrooms() call with g_nodraw=1
1000
    // if we're here, there was just a drawrooms() call with g_nodraw=1
1001
1001
1002
    Bmemcpy(ogotsector, gotsector, (numsectors+7)>>3);
1002
    Bmemcpy(ogotsector, gotsector, (numsectors+7)>>3);
1003
1003
1004
    if (sectnum >= 0)
1004
    if (sectnum >= 0)
1005
        yax_getbunches(sectnum, &ourbunch[0], &ourbunch[1]);
1005
        yax_getbunches(sectnum, &ourbunch[0], &ourbunch[1]);
1006
    Bmemset(&havebunch, 0, (numyaxbunches+7)>>3);
1006
    Bmemset(&havebunch, 0, (numyaxbunches+7)>>3);
1007
1007
1008
    // first scan all bunches above, then all below...
1008
    // first scan all bunches above, then all below...
1009
    for (cf=0; cf<2; cf++)
1009
    for (cf=0; cf<2; cf++)
1010
    {
1010
    {
1011
        yax_globalcf = cf;
1011
        yax_globalcf = cf;
1012
1012
1013
        if (cf==1)
1013
        if (cf==1)
1014
        {
1014
        {
1015
            sectnum = osectnum;
1015
            sectnum = osectnum;
1016
            Bmemcpy(gotsector, ogotsector, (numsectors+7)>>3);
1016
            Bmemcpy(gotsector, ogotsector, (numsectors+7)>>3);
1017
        }
1017
        }
1018
1018
1019
        for (lev=0; /*lev<YAX_MAXDRAWS*/; lev++)
1019
        for (lev=0; /*lev<YAX_MAXDRAWS*/; lev++)
1020
        {
1020
        {
1021
            yax_globallev = YAX_MAXDRAWS + (-1 + 2*cf)*(lev+1);
1021
            yax_globallev = YAX_MAXDRAWS + (-1 + 2*cf)*(lev+1);
1022
1022
1023
            bbeg = bnchbeg[lev][cf] = bnchend[lev][cf] = bnchnum[cf];
1023
            bbeg = bnchbeg[lev][cf] = bnchend[lev][cf] = bnchnum[cf];
1024
            numhere = 0;
1024
            numhere = 0;
1025
1025
1026
            for (i=0; i<numsectors; i++)
1026
            for (i=0; i<numsectors; i++)
1027
            {
1027
            {
1028
                if (!(gotsector[i>>3]&(1<<(i&7))))
1028
                if (!(gotsector[i>>3]&(1<<(i&7))))
1029
                    continue;
1029
                    continue;
1030
1030
1031
                j = yax_getbunch(i, cf);
1031
                j = yax_getbunch(i, cf);
1032
                if (j >= 0 && !(havebunch[j>>3]&(1<<(j&7))))
1032
                if (j >= 0 && !(havebunch[j>>3]&(1<<(j&7))))
1033
                {
1033
                {
1034
                    if (getrendermode() == REND_CLASSIC && (haveymost[j>>3]&(1<<(j&7)))==0)
1034
                    if (getrendermode() == REND_CLASSIC && (haveymost[j>>3]&(1<<(j&7)))==0)
1035
                    {
1035
                    {
1036
                        yaxdebug("%s, l %d: skipped bunch %d (no *most)", cf?"v":"^", lev, j);
1036
                        yaxdebug("%s, l %d: skipped bunch %d (no *most)", cf?"v":"^", lev, j);
1037
                        continue;
1037
                        continue;
1038
                    }
1038
                    }
1039
1039
1040
                    if ((SECTORFLD(i,stat, cf)&2) ||
1040
                    if ((SECTORFLD(i,stat, cf)&2) ||
1041
                            (cf==0 && globalposz > sector[i].ceilingz) ||
1041
                            (cf==0 && globalposz > sector[i].ceilingz) ||
1042
                            (cf==1 && globalposz < sector[i].floorz))
1042
                            (cf==1 && globalposz < sector[i].floorz))
1043
                    {
1043
                    {
1044
                        havebunch[j>>3] |= (1<<(j&7));
1044
                        havebunch[j>>3] |= (1<<(j&7));
1045
                        bunches[cf][bnchnum[cf]++] = j;
1045
                        bunches[cf][bnchnum[cf]++] = j;
1046
                        bnchend[lev][cf]++;
1046
                        bnchend[lev][cf]++;
1047
                        numhere++;
1047
                        numhere++;
1048
                    }
1048
                    }
1049
                }
1049
                }
1050
            }
1050
            }
1051
1051
1052
            if (numhere > 0)
1052
            if (numhere > 0)
1053
            {
1053
            {
1054
                // found bunches -- need to fake-draw
1054
                // found bunches -- need to fake-draw
1055
1055
1056
                yax_scanbunches(bbeg, numhere, (uint8_t *)gotsector);
1056
                yax_scanbunches(bbeg, numhere, (uint8_t *)gotsector);
1057
1057
1058
                qsort(&bunches[cf][bbeg], numhere, sizeof(int16_t), &yax_cmpbunches);
1058
                qsort(&bunches[cf][bbeg], numhere, sizeof(int16_t), &yax_cmpbunches);
1059
1059
1060
                if (numhere > 1 && lev != YAX_MAXDRAWS-1)
1060
                if (numhere > 1 && lev != YAX_MAXDRAWS-1)
1061
                    Bmemset(lgotsector, 0, (numsectors+7)>>3);
1061
                    Bmemset(lgotsector, 0, (numsectors+7)>>3);
1062
1062
1063
                for (bnchcnt=bbeg; bnchcnt < bbeg+numhere; bnchcnt++)
1063
                for (bnchcnt=bbeg; bnchcnt < bbeg+numhere; bnchcnt++)
1064
                {
1064
                {
1065
                    j = bunches[cf][bnchcnt];  // the actual bunchnum...
1065
                    j = bunches[cf][bnchcnt];  // the actual bunchnum...
1066
                    yax_globalbunch = j;
1066
                    yax_globalbunch = j;
1067
#ifdef YAX_DEBUG
1067
#ifdef YAX_DEBUG
1068
                    t=getu64ticks();
1068
                    t=getu64ticks();
1069
#endif
1069
#endif
1070
                    k = bunchsec[j];
1070
                    k = bunchsec[j];
1071
1071
1072
                    if (k < 0)
1072
                    if (k < 0)
1073
                    {
1073
                    {
1074
                        yaxprintf("%s, l %d: skipped bunch %d\n", cf?"v":"^", lev, j);
1074
                        yaxprintf("%s, l %d: skipped bunch %d\n", cf?"v":"^", lev, j);
1075
                        continue;
1075
                        continue;
1076
                    }
1076
                    }
1077
1077
1078
                    if (lev != YAX_MAXDRAWS-1)
1078
                    if (lev != YAX_MAXDRAWS-1)
1079
                    {
1079
                    {
1080
#ifdef YAX_DEBUG
1080
#ifdef YAX_DEBUG
1081
                        int32_t odsprcnt = yax_spritesortcnt[yax_globallev];
1081
                        int32_t odsprcnt = yax_spritesortcnt[yax_globallev];
1082
#endif
1082
#endif
1083
                        // +MAXSECTORS: force
1083
                        // +MAXSECTORS: force
1084
                        drawrooms(globalposx,globalposy,globalposz,globalang,horiz,k+MAXSECTORS);
1084
                        drawrooms(globalposx,globalposy,globalposz,globalang,horiz,k+MAXSECTORS);
1085
                        if (numhere > 1)
1085
                        if (numhere > 1)
1086
                            for (i=0; i<(numsectors+7)>>3; i++)
1086
                            for (i=0; i<(numsectors+7)>>3; i++)
1087
                                lgotsector[i] |= gotsector[i];
1087
                                lgotsector[i] |= gotsector[i];
1088
1088
1089
                        yaxdebug("l%d: faked (bn %2d) sec %4d,%3d dspr, ob=[%2d,%2d], sn=%4d, %.3f ms",
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,
1090
                                 yax_globallev-YAX_MAXDRAWS, j, k, yax_spritesortcnt[yax_globallev]-odsprcnt,
1091
                                 ourbunch[0],ourbunch[1],sectnum,
1091
                                 ourbunch[0],ourbunch[1],sectnum,
1092
                                 (double)(1000*(getu64ticks()-t))/u64tickspersec);
1092
                                 (double)(1000*(getu64ticks()-t))/u64tickspersec);
1093
                    }
1093
                    }
1094
1094
1095
                    if (ourbunch[cf]==j)
1095
                    if (ourbunch[cf]==j)
1096
                    {
1096
                    {
1097
                        ourbunch[cf] = yax_getbunch(k, cf);
1097
                        ourbunch[cf] = yax_getbunch(k, cf);
1098
                        sectnum = k;
1098
                        sectnum = k;
1099
                    }
1099
                    }
1100
                }
1100
                }
1101
1101
1102
                if (numhere > 1 && lev != YAX_MAXDRAWS-1)
1102
                if (numhere > 1 && lev != YAX_MAXDRAWS-1)
1103
                    Bmemcpy(gotsector, lgotsector, (numsectors+7)>>3);
1103
                    Bmemcpy(gotsector, lgotsector, (numsectors+7)>>3);
1104
            }
1104
            }
1105
1105
1106
            if (numhere==0 || lev==YAX_MAXDRAWS-1)
1106
            if (numhere==0 || lev==YAX_MAXDRAWS-1)
1107
            {
1107
            {
1108
                // no new bunches or max level reached
1108
                // no new bunches or max level reached
1109
                maxlev[cf] = lev - (numhere==0);
1109
                maxlev[cf] = lev - (numhere==0);
1110
                break;
1110
                break;
1111
            }
1111
            }
1112
        }
1112
        }
1113
    }
1113
    }
1114
1114
1115
//    yax_globalcf = -1;
1115
//    yax_globalcf = -1;
1116
1116
1117
    // now comes the real drawing!
1117
    // now comes the real drawing!
1118
    g_nodraw = 0;
1118
    g_nodraw = 0;
1119
    scansector_collectsprites = 0;
1119
    scansector_collectsprites = 0;
1120
1120
1121
    if (editstatus==1)
1121
    if (editstatus==1)
1122
    {
1122
    {
1123
        if (getrendermode() == REND_CLASSIC)
1123
        if (getrendermode() == REND_CLASSIC)
1124
        {
1124
        {
1125
            begindrawing();
1125
            begindrawing();
1126
            draw_rainbow_background();
1126
            draw_rainbow_background();
1127
            enddrawing();
1127
            enddrawing();
1128
        }
1128
        }
1129
#ifdef USE_OPENGL
1129
#ifdef USE_OPENGL
1130
        else
1130
        else
1131
        {
1131
        {
1132
            bglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
1132
            bglClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
1133
        }
1133
        }
1134
#endif
1134
#endif
1135
    }
1135
    }
1136
1136
1137
    for (cf=0; cf<2; cf++)
1137
    for (cf=0; cf<2; cf++)
1138
    {
1138
    {
1139
        yax_globalcf = cf;
1139
        yax_globalcf = cf;
1140
1140
1141
        for (lev=maxlev[cf]; lev>=0; lev--)
1141
        for (lev=maxlev[cf]; lev>=0; lev--)
1142
        {
1142
        {
1143
            yax_globallev = YAX_MAXDRAWS + (-1 + 2*cf)*(lev+1);
1143
            yax_globallev = YAX_MAXDRAWS + (-1 + 2*cf)*(lev+1);
1144
            scansector_collectsprites = (lev == YAX_MAXDRAWS-1);
1144
            scansector_collectsprites = (lev == YAX_MAXDRAWS-1);
1145
1145
1146
            for (bnchcnt=bnchbeg[lev][cf]; bnchcnt<bnchend[lev][cf]; bnchcnt++)
1146
            for (bnchcnt=bnchbeg[lev][cf]; bnchcnt<bnchend[lev][cf]; bnchcnt++)
1147
            {
1147
            {
1148
                j = bunches[cf][bnchcnt];  // the actual bunchnum...
1148
                j = bunches[cf][bnchcnt];  // the actual bunchnum...
1149
                k = bunchsec[j];  // best start-drawing sector
1149
                k = bunchsec[j];  // best start-drawing sector
1150
                yax_globalbunch = j;
1150
                yax_globalbunch = j;
1151
#ifdef YAX_DEBUG
1151
#ifdef YAX_DEBUG
1152
                t=getu64ticks();
1152
                t=getu64ticks();
1153
#endif
1153
#endif
1154
                yax_tweakpicnums(j, cf, 0);
1154
                yax_tweakpicnums(j, cf, 0);
1155
                if (k < 0)
1155
                if (k < 0)
1156
                    continue;
1156
                    continue;
1157
1157
1158
                yax_nomaskdidit = 0;
1158
                yax_nomaskdidit = 0;
1159
                for (nmp=r_tror_nomaskpass; nmp>=0; nmp--)
1159
                for (nmp=r_tror_nomaskpass; nmp>=0; nmp--)
1160
                {
1160
                {
1161
                    yax_nomaskpass = nmp;
1161
                    yax_nomaskpass = nmp;
1162
                    drawrooms(globalposx,globalposy,globalposz,globalang,horiz,k+MAXSECTORS);  // +MAXSECTORS: force
1162
                    drawrooms(globalposx,globalposy,globalposz,globalang,horiz,k+MAXSECTORS);  // +MAXSECTORS: force
1163
1163
1164
                    if (nmp==1)
1164
                    if (nmp==1)
1165
                    {
1165
                    {
1166
                        yaxdebug("nm1 l%d: DRAWN (bn %2d) sec %4d,          %.3f ms",
1166
                        yaxdebug("nm1 l%d: DRAWN (bn %2d) sec %4d,          %.3f ms",
1167
                                 yax_globallev-YAX_MAXDRAWS, j, k,
1167
                                 yax_globallev-YAX_MAXDRAWS, j, k,
1168
                                 (double)(1000*(getu64ticks()-t))/u64tickspersec);
1168
                                 (double)(1000*(getu64ticks()-t))/u64tickspersec);
1169
1169
1170
                        if (!yax_nomaskdidit)
1170
                        if (!yax_nomaskdidit)
1171
                        {
1171
                        {
1172
                            yax_nomaskpass = 0;
1172
                            yax_nomaskpass = 0;
1173
                            break;  // no need to draw the same stuff twice
1173
                            break;  // no need to draw the same stuff twice
1174
                        }
1174
                        }
1175
                        Bmemcpy(yax_gotsector, gotsector, (numsectors+7)>>3);
1175
                        Bmemcpy(yax_gotsector, gotsector, (numsectors+7)>>3);
1176
                    }
1176
                    }
1177
                }
1177
                }
1178
1178
1179
                if (!scansector_collectsprites)
1179
                if (!scansector_collectsprites)
1180
                    spritesortcnt = 0;
1180
                    spritesortcnt = 0;
1181
                yax_copytsprites();
1181
                yax_copytsprites();
1182
                yaxdebug("nm0 l%d: DRAWN (bn %2d) sec %4d,%3d tspr, %.3f ms",
1182
                yaxdebug("nm0 l%d: DRAWN (bn %2d) sec %4d,%3d tspr, %.3f ms",
1183
                         yax_globallev-YAX_MAXDRAWS, j, k, spritesortcnt,
1183
                         yax_globallev-YAX_MAXDRAWS, j, k, spritesortcnt,
1184
                         (double)(1000*(getu64ticks()-t))/u64tickspersec);
1184
                         (double)(1000*(getu64ticks()-t))/u64tickspersec);
1185
1185
1186
                SpriteAnimFunc(globalposx, globalposy, globalang, smoothr);
1186
                SpriteAnimFunc(globalposx, globalposy, globalang, smoothr);
1187
                drawmasks();
1187
                drawmasks();
1188
            }
1188
            }
1189
1189
1190
            if (lev < maxlev[cf])
1190
            if (lev < maxlev[cf])
1191
                for (bnchcnt=bnchbeg[lev+1][cf]; bnchcnt<bnchend[lev+1][cf]; bnchcnt++)
1191
                for (bnchcnt=bnchbeg[lev+1][cf]; bnchcnt<bnchend[lev+1][cf]; bnchcnt++)
1192
                    yax_tweakpicnums(bunches[cf][bnchcnt], cf, 1);  // restore picnums
1192
                    yax_tweakpicnums(bunches[cf][bnchcnt], cf, 1);  // restore picnums
1193
        }
1193
        }
1194
    }
1194
    }
1195
1195
1196
#ifdef YAX_DEBUG
1196
#ifdef YAX_DEBUG
1197
    t=getu64ticks();
1197
    t=getu64ticks();
1198
#endif
1198
#endif
1199
    yax_globalcf = -1;
1199
    yax_globalcf = -1;
1200
    yax_globalbunch = -1;
1200
    yax_globalbunch = -1;
1201
    yax_globallev = YAX_MAXDRAWS;
1201
    yax_globallev = YAX_MAXDRAWS;
1202
    scansector_collectsprites = 0;
1202
    scansector_collectsprites = 0;
1203
1203
1204
    // draw base level
1204
    // draw base level
1205
    drawrooms(globalposx,globalposy,globalposz,globalang,horiz,
1205
    drawrooms(globalposx,globalposy,globalposz,globalang,horiz,
1206
              osectnum + MAXSECTORS*didmirror);
1206
              osectnum + MAXSECTORS*didmirror);
1207
//    if (scansector_collectsprites)
1207
//    if (scansector_collectsprites)
1208
//        spritesortcnt = 0;
1208
//        spritesortcnt = 0;
1209
    yax_copytsprites();
1209
    yax_copytsprites();
1210
    yaxdebug("DRAWN base level sec %d,%3d tspr, %.3f ms", osectnum,
1210
    yaxdebug("DRAWN base level sec %d,%3d tspr, %.3f ms", osectnum,
1211
             spritesortcnt, (double)(1000*(getu64ticks()-t))/u64tickspersec);
1211
             spritesortcnt, (double)(1000*(getu64ticks()-t))/u64tickspersec);
1212
    scansector_collectsprites = 1;
1212
    scansector_collectsprites = 1;
1213
1213
1214
    for (cf=0; cf<2; cf++)
1214
    for (cf=0; cf<2; cf++)
1215
        if (maxlev[cf] >= 0)
1215
        if (maxlev[cf] >= 0)
1216
            for (bnchcnt=bnchbeg[0][cf]; bnchcnt<bnchend[0][cf]; bnchcnt++)
1216
            for (bnchcnt=bnchbeg[0][cf]; bnchcnt<bnchend[0][cf]; bnchcnt++)
1217
                yax_tweakpicnums(bunches[cf][bnchcnt], cf, 1);  // restore picnums
1217
                yax_tweakpicnums(bunches[cf][bnchcnt], cf, 1);  // restore picnums
1218
1218
1219
#ifdef ENGINE_SCREENSHOT_DEBUG
1219
#ifdef ENGINE_SCREENSHOT_DEBUG
1220
    engine_screenshot = 0;
1220
    engine_screenshot = 0;
1221
#endif
1221
#endif
1222
1222
1223
#ifdef YAX_DEBUG_YMOSTS
1223
#ifdef YAX_DEBUG_YMOSTS
1224
    if (getrendermode() == REND_CLASSIC && numyaxbunches>0)
1224
    if (getrendermode() == REND_CLASSIC && numyaxbunches>0)
1225
    {
1225
    {
1226
        char purple = getclosestcol(63, 0, 63);
1226
        char purple = getclosestcol(63, 0, 63);
1227
        char yellow = getclosestcol(63, 63, 0);
1227
        char yellow = getclosestcol(63, 63, 0);
1228
1228
1229
        begindrawing();
1229
        begindrawing();
1230
        for (i=0; i<numyaxbunches; i++)
1230
        for (i=0; i<numyaxbunches; i++)
1231
        {
1231
        {
1232
            int32_t x, x1;
1232
            int32_t x, x1;
1233
1233
1234
            if ((haveymost[i>>3]&(1<<i&7))==0)
1234
            if ((haveymost[i>>3]&(1<<i&7))==0)
1235
                continue;
1235
                continue;
1236
1236
1237
            x1 = i*xdimen;
1237
            x1 = i*xdimen;
1238
1238
1239
            for (x=x1; x<x1+xdimen; x++)
1239
            for (x=x1; x<x1+xdimen; x++)
1240
            {
1240
            {
1241
                if (yumost[x] >= 0 && yumost[x] < ydim && (x&1))
1241
                if (yumost[x] >= 0 && yumost[x] < ydim && (x&1))
1242
                    *((char *)frameplace + yumost[x]*bytesperline + x-x1) = purple;
1242
                    *((char *)frameplace + yumost[x]*bytesperline + x-x1) = purple;
1243
1243
1244
                if (ydmost[x]-1 >= 0 && ydmost[x]-1 < ydim && !(x&1))
1244
                if (ydmost[x]-1 >= 0 && ydmost[x]-1 < ydim && !(x&1))
1245
                    *((char *)frameplace + (ydmost[x]-1)*bytesperline + x-x1) = yellow;
1245
                    *((char *)frameplace + (ydmost[x]-1)*bytesperline + x-x1) = yellow;
1246
            }
1246
            }
1247
        }
1247
        }
1248
        enddrawing();
1248
        enddrawing();
1249
    }
1249
    }
1250
#endif
1250
#endif
1251
}
1251
}
1252
1252
1253
#endif  // defined YAX_ENABLE
1253
#endif  // defined YAX_ENABLE
1254
1254
1255
// must have writable frame buffer, i.e. done begindrawing()
1255
// must have writable frame buffer, i.e. done begindrawing()
1256
static void draw_rainbow_background(void)
1256
static void draw_rainbow_background(void)
1257
{
1257
{
1258
    int32_t y, i;
1258
    int32_t y, i;
1259
    const int32_t N = 240;  // don't use fullbright colors
1259
    const int32_t N = 240;  // don't use fullbright colors
1260
    const int32_t numfull=bytesperline/N, numrest=bytesperline%N;
1260
    const int32_t numfull=bytesperline/N, numrest=bytesperline%N;
1261
1261
1262
    const char *const src = palookup[0] + 256*18;
1262
    const char *const src = palookup[0] + 256*18;
1263
    char *dst = (char *)frameplace;
1263
    char *dst = (char *)frameplace;
1264
1264
1265
    for (y=0; y<ydim; y++)
1265
    for (y=0; y<ydim; y++)
1266
    {
1266
    {
1267
        for (i=0; i<numfull; i++)
1267
        for (i=0; i<numfull; i++)
1268
            Bmemcpy(&dst[N*i], src, N);
1268
            Bmemcpy(&dst[N*i], src, N);
1269
        if (numrest > 0)
1269
        if (numrest > 0)
1270
            Bmemcpy(&dst[N*i], src, numrest);
1270
            Bmemcpy(&dst[N*i], src, numrest);
1271
1271
1272
        dst += bytesperline;
1272
        dst += bytesperline;
1273
    }
1273
    }
1274
}
1274
}
1275
1275
1276
//
1276
//
1277
// setslope
1277
// setslope
1278
//
1278
//
1279
void setslope(int32_t sectnum, int32_t cf, int16_t slope)
1279
void setslope(int32_t sectnum, int32_t cf, int16_t slope)
1280
{
1280
{
1281
    if (slope==0)
1281
    if (slope==0)
1282
    {
1282
    {
1283
        SECTORFLD(sectnum,stat, cf) &= ~2;
1283
        SECTORFLD(sectnum,stat, cf) &= ~2;
1284
        SECTORFLD(sectnum,heinum, cf) = 0;
1284
        SECTORFLD(sectnum,heinum, cf) = 0;
1285
    }
1285
    }
1286
    else
1286
    else
1287
    {
1287
    {
1288
        SECTORFLD(sectnum,stat, cf) |= 2;
1288
        SECTORFLD(sectnum,stat, cf) |= 2;
1289
        SECTORFLD(sectnum,heinum, cf) = slope;
1289
        SECTORFLD(sectnum,heinum, cf) = slope;
1290
    }
1290
    }
1291
}
1291
}
1292
1292
1293
////////// editor side view //////////
1293
////////// editor side view //////////
1294
int32_t m32_sideview = 0;
1294
int32_t m32_sideview = 0;
1295
int32_t m32_sideelev = 256;  // elevation in BUILD degrees, 0..512
1295
int32_t m32_sideelev = 256;  // elevation in BUILD degrees, 0..512
1296
int16_t m32_sideang = 200;  // azimuth, 0..2047
1296
int16_t m32_sideang = 200;  // azimuth, 0..2047
1297
1297
1298
int32_t m32_sidecos, m32_sidesin;
1298
int32_t m32_sidecos, m32_sidesin;
1299
int32_t m32_swcnt;
1299
int32_t m32_swcnt;
1300
int32_t m32_wallscreenxy[MAXWALLS][2];
1300
int32_t m32_wallscreenxy[MAXWALLS][2];
1301
int16_t m32_wallsprite[MAXWALLS+MAXSPRITES];
1301
int16_t m32_wallsprite[MAXWALLS+MAXSPRITES];
1302
static int32_t m32_sidedist[MAXWALLS+MAXSPRITES];
1302
static int32_t m32_sidedist[MAXWALLS+MAXSPRITES];
1303
static vec3_t m32_viewplane;
1303
static vec3_t m32_viewplane;
1304
1304
1305
1305
1306
////// sector-like clipping for sprites //////
1306
////// sector-like clipping for sprites //////
1307
#ifdef HAVE_CLIPSHAPE_FEATURE
1307
#ifdef HAVE_CLIPSHAPE_FEATURE
1308
typedef struct
1308
typedef struct
1309
{
1309
{
1310
    int16_t numsectors, numwalls;
1310
    int16_t numsectors, numwalls;
1311
    tsectortype *sector;
1311
    tsectortype *sector;
1312
    twalltype *wall;
1312
    twalltype *wall;
1313
} mapinfo_t;
1313
} mapinfo_t;
1314
1314
1315
static void mapinfo_set(mapinfo_t *bak, mapinfo_t *newmap)
1315
static void mapinfo_set(mapinfo_t *bak, mapinfo_t *newmap)
1316
{
1316
{
1317
    if (bak)
1317
    if (bak)
1318
    {
1318
    {
1319
        bak->numsectors = numsectors;
1319
        bak->numsectors = numsectors;
1320
        bak->numwalls = numwalls;
1320
        bak->numwalls = numwalls;
1321
        bak->sector = (tsectortype *)sector;
1321
        bak->sector = (tsectortype *)sector;
1322
        bak->wall = (twalltype *)wall;
1322
        bak->wall = (twalltype *)wall;
1323
    }
1323
    }
1324
1324
1325
    if (newmap)
1325
    if (newmap)
1326
    {
1326
    {
1327
        numsectors = newmap->numsectors;
1327
        numsectors = newmap->numsectors;
1328
        numwalls = newmap->numwalls;
1328
        numwalls = newmap->numwalls;
1329
        sector = (sectortype *)newmap->sector;
1329
        sector = (sectortype *)newmap->sector;
1330
        wall = (walltype *)newmap->wall;
1330
        wall = (walltype *)newmap->wall;
1331
    }
1331
    }
1332
}
1332
}
1333
1333
1334
static mapinfo_t origmapinfo, clipmapinfo;
1334
static mapinfo_t origmapinfo, clipmapinfo;
1335
static int32_t quickloadboard=0;
1335
static int32_t quickloadboard=0;
1336
1336
1337
1337
1338
#define CM_MAX 256  // must be a power of 2
1338
#define CM_MAX 256  // must be a power of 2
1339
1339
1340
typedef struct
1340
typedef struct
1341
{
1341
{
1342
    int16_t qbeg, qend;  // indices into sectq
1342
    int16_t qbeg, qend;  // indices into sectq
1343
    int16_t picnum, next;
1343
    int16_t picnum, next;
1344
    int32_t maxdist;
1344
    int32_t maxdist;
1345
} clipinfo_t;
1345
} clipinfo_t;
1346
1346
1347
static int32_t numclipmaps;
1347
static int32_t numclipmaps;
1348
static clipinfo_t clipinfo[CM_MAX];
1348
static clipinfo_t clipinfo[CM_MAX];
1349
1349
1350
static int32_t numclipsects;  // number in sectq[]
1350
static int32_t numclipsects;  // number in sectq[]
1351
static int16_t *sectoidx, *sectq;  // [numsectors]
1351
static int16_t *sectoidx, *sectq;  // [numsectors]
1352
static int16_t pictoidx[MAXTILES];  // maps tile num to clipinfo[] index
1352
static int16_t pictoidx[MAXTILES];  // maps tile num to clipinfo[] index
1353
static int16_t *tempictoidx;
1353
static int16_t *tempictoidx;
1354
1354
1355
static tsectortype *loadsector;
1355
static tsectortype *loadsector;
1356
static twalltype *loadwall, *loadwallinv;
1356
static twalltype *loadwall, *loadwallinv;
1357
static tspritetype *loadsprite;
1357
static tspritetype *loadsprite;
1358
1358
1359
// sectoidx bits
1359
// sectoidx bits
1360
#undef CM_NONE
1360
#undef CM_NONE
1361
#define CM_NONE (CM_MAX<<1)
1361
#define CM_NONE (CM_MAX<<1)
1362
#define CM_SOME (CM_NONE-1)
1362
#define CM_SOME (CM_NONE-1)
1363
#define CM_OUTER (CM_MAX)   // sector surrounds clipping sector
1363
#define CM_OUTER (CM_MAX)   // sector surrounds clipping sector
1364
1364
1365
// sprite -> sector tag mappings
1365
// sprite -> sector tag mappings
1366
#define CM_XREPEAT floorpal
1366
#define CM_XREPEAT floorpal
1367
#define CM_YREPEAT floorxpanning
1367
#define CM_YREPEAT floorxpanning
1368
#define CM_XOFFSET ceilingshade
1368
#define CM_XOFFSET ceilingshade
1369
#define CM_YOFFSET floorshade
1369
#define CM_YOFFSET floorshade
1370
#define CM_CSTAT hitag
1370
#define CM_CSTAT hitag
1371
#define CM_ANG extra
1371
#define CM_ANG extra
1372
#define CM_FLOORZ(Sec) (*(int32_t *)&sector[Sec].ceilingxpanning)  // ceilingxpanning,ceilingypanning,floorpicnum
1372
#define CM_FLOORZ(Sec) (*(int32_t *)&sector[Sec].ceilingxpanning)  // ceilingxpanning,ceilingypanning,floorpicnum
1373
#define CM_CEILINGZ(Sec) (*(int32_t *)&sector[Sec].visibility)  // visibility,fogpal,lotag
1373
#define CM_CEILINGZ(Sec) (*(int32_t *)&sector[Sec].visibility)  // visibility,fogpal,lotag
1374
1374
1375
// backup of original normalized coordinates
1375
// backup of original normalized coordinates
1376
#define CM_WALL_X(Wal) (*(int32_t *)&wall[Wal].picnum)  // picnum, overpicnum
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
1377
#define CM_WALL_Y(Wal) (*(int32_t *)&wall[Wal].lotag)  // lotag, hitag
1378
1378
1379
// don't rotate when applying clipping, for models with rotational symmetry
1379
// don't rotate when applying clipping, for models with rotational symmetry
1380
#define CM_NOROT(Spri) (sprite[Spri].cstat&2)
1380
#define CM_NOROT(Spri) (sprite[Spri].cstat&2)
1381
#define CM_NOROTS(Sect) (sector[Sect].CM_CSTAT&2)
1381
#define CM_NOROTS(Sect) (sector[Sect].CM_CSTAT&2)
1382
1382
1383
1383
1384
static void clipmapinfo_init()
1384
static void clipmapinfo_init()
1385
{
1385
{
1386
    numclipmaps = 0;
1386
    numclipmaps = 0;
1387
    numclipsects = 0;
1387
    numclipsects = 0;
1388
1388
1389
    DO_FREE_AND_NULL(sectq);
1389
    DO_FREE_AND_NULL(sectq);
1390
    DO_FREE_AND_NULL(sectoidx);
1390
    DO_FREE_AND_NULL(sectoidx);
1391
    DO_FREE_AND_NULL(tempictoidx);
1391
    DO_FREE_AND_NULL(tempictoidx);
1392
    DO_FREE_AND_NULL(loadsector);
1392
    DO_FREE_AND_NULL(loadsector);
1393
    DO_FREE_AND_NULL(loadwall);
1393
    DO_FREE_AND_NULL(loadwall);
1394
    DO_FREE_AND_NULL(loadwallinv);
1394
    DO_FREE_AND_NULL(loadwallinv);
1395
    DO_FREE_AND_NULL(loadsprite);
1395
    DO_FREE_AND_NULL(loadsprite);
1396
1396
1397
    // two's complement trick, -1 = 0xff
1397
    // two's complement trick, -1 = 0xff
1398
    Bmemset(&pictoidx, -1, sizeof(pictoidx));
1398
    Bmemset(&pictoidx, -1, sizeof(pictoidx));
1399
    Bmemset(&clipmapinfo, 0, sizeof(mapinfo_t));
1399
    Bmemset(&clipmapinfo, 0, sizeof(mapinfo_t));
1400
1400
1401
    numsectors = 0;
1401
    numsectors = 0;
1402
    numwalls = 0;
1402
    numwalls = 0;
1403
}
1403
}
1404
1404
1405
// loads the clip maps.
1405
// loads the clip maps.
1406
// this should be called before any real map is loaded.
1406
// this should be called before any real map is loaded.
1407
int32_t clipmapinfo_load(void)
1407
int32_t clipmapinfo_load(void)
1408
{
1408
{
1409
    int32_t i,k,w;
1409
    int32_t i,k,w;
1410
1410
1411
    int32_t lwcp = 0;
1411
    int32_t lwcp = 0;
1412
    int32_t fi;
1412
    int32_t fi;
1413
1413
1414
    int32_t *fisec = NULL;
1414
    int32_t *fisec = NULL;
1415
    int32_t *fispr = NULL;
1415
    int32_t *fispr = NULL;
1416
1416
1417
    int32_t ournumsectors=0, ournumwalls=0, ournumsprites=0;
1417
    int32_t ournumsectors=0, ournumwalls=0, ournumsprites=0;
1418
1418
1419
    clipmapinfo_init();
1419
    clipmapinfo_init();
1420
1420
1421
    loadsector = (tsectortype *)Xmalloc(MAXSECTORS * sizeof(sectortype));
1421
    loadsector = (tsectortype *)Xmalloc(MAXSECTORS * sizeof(sectortype));
1422
    loadwall = (twalltype *)Xmalloc(MAXWALLS * sizeof(walltype));
1422
    loadwall = (twalltype *)Xmalloc(MAXWALLS * sizeof(walltype));
1423
    loadsprite = (tspritetype *)Xmalloc(MAXSPRITES * sizeof(spritetype));
1423
    loadsprite = (tspritetype *)Xmalloc(MAXSPRITES * sizeof(spritetype));
1424
1424
1425
    if (g_clipMapFilesNum)
1425
    if (g_clipMapFilesNum)
1426
        fisec = (int32_t *)Xcalloc(g_clipMapFilesNum, sizeof (int32_t));
1426
        fisec = (int32_t *)Xcalloc(g_clipMapFilesNum, sizeof (int32_t));
1427
    if (g_clipMapFilesNum)
1427
    if (g_clipMapFilesNum)
1428
        fispr = (int32_t *)Xcalloc(g_clipMapFilesNum, sizeof (int32_t));
1428
        fispr = (int32_t *)Xcalloc(g_clipMapFilesNum, sizeof (int32_t));
1429
1429
1430
    quickloadboard = 1;
1430
    quickloadboard = 1;
1431
    for (fi = 0; fi < g_clipMapFilesNum; ++fi)
1431
    for (fi = 0; fi < g_clipMapFilesNum; ++fi)
1432
    {
1432
    {
1433
        int16_t ang,cs;
1433
        int16_t ang,cs;
1434
        vec3_t tmppos;
1434
        vec3_t tmppos;
1435
1435
1436
        fisec[fi] = ournumsectors;
1436
        fisec[fi] = ournumsectors;
1437
        fispr[fi] = ournumsprites;
1437
        fispr[fi] = ournumsprites;
1438
1438
1439
        i = loadboard(g_clipMapFiles[fi], 8, &tmppos, &ang, &cs);
1439
        i = loadboard(g_clipMapFiles[fi], 8, &tmppos, &ang, &cs);
1440
        if (i<0)
1440
        if (i<0)
1441
            continue;
1441
            continue;
1442
        // Numsprites will now be set!
1442
        // Numsprites will now be set!
1443
1443
1444
        initprintf("Loading clip map: %s\n", g_clipMapFiles[fi]);
1444
        initprintf("Loading clip map: %s\n", g_clipMapFiles[fi]);
1445
1445
1446
        if (ournumsectors+numsectors>MAXSECTORS ||
1446
        if (ournumsectors+numsectors>MAXSECTORS ||
1447
                ournumwalls+numwalls>MAXWALLS ||
1447
                ournumwalls+numwalls>MAXWALLS ||
1448
                ournumsprites+Numsprites>MAXSPRITES)
1448
                ournumsprites+Numsprites>MAXSPRITES)
1449
        {
1449
        {
1450
            initprintf("clip map: warning: exceeded limits when loading %s, aborting.\n", g_clipMapFiles[fi]);
1450
            initprintf("clip map: warning: exceeded limits when loading %s, aborting.\n", g_clipMapFiles[fi]);
1451
            break;
1451
            break;
1452
        }
1452
        }
1453
1453
1454
        Bmemcpy(loadsector+ournumsectors, sector, numsectors*sizeof(sectortype));
1454
        Bmemcpy(loadsector+ournumsectors, sector, numsectors*sizeof(sectortype));
1455
        Bmemcpy(loadwall+ournumwalls, wall, numwalls*sizeof(walltype));
1455
        Bmemcpy(loadwall+ournumwalls, wall, numwalls*sizeof(walltype));
1456
        Bmemcpy(loadsprite+ournumsprites, sprite, Numsprites*sizeof(spritetype));
1456
        Bmemcpy(loadsprite+ournumsprites, sprite, Numsprites*sizeof(spritetype));
1457
        for (i=ournumsectors; i<ournumsectors+numsectors; i++)
1457
        for (i=ournumsectors; i<ournumsectors+numsectors; i++)
1458
            loadsector[i].wallptr += ournumwalls;
1458
            loadsector[i].wallptr += ournumwalls;
1459
        for (i=ournumwalls; i<ournumwalls+numwalls; i++)
1459
        for (i=ournumwalls; i<ournumwalls+numwalls; i++)
1460
        {
1460
        {
1461
            if (loadwall[i].point2>=0)
1461
            if (loadwall[i].point2>=0)
1462
                loadwall[i].point2 += ournumwalls;
1462
                loadwall[i].point2 += ournumwalls;
1463
            if (loadwall[i].nextwall>=0)
1463
            if (loadwall[i].nextwall>=0)
1464
            {
1464
            {
1465
                loadwall[i].nextwall += ournumwalls;
1465
                loadwall[i].nextwall += ournumwalls;
1466
                loadwall[i].nextsector += ournumsectors;
1466
                loadwall[i].nextsector += ournumsectors;
1467
            }
1467
            }
1468
        }
1468
        }
1469
        for (i=ournumsprites; i<ournumsprites+Numsprites; i++)
1469
        for (i=ournumsprites; i<ournumsprites+Numsprites; i++)
1470
            if (loadsprite[i].sectnum>=0)
1470
            if (loadsprite[i].sectnum>=0)
1471
                loadsprite[i].sectnum += ournumsectors;
1471
                loadsprite[i].sectnum += ournumsectors;
1472
        ournumsectors += numsectors;
1472
        ournumsectors += numsectors;
1473
        ournumwalls += numwalls;
1473
        ournumwalls += numwalls;
1474
        ournumsprites += Numsprites;
1474
        ournumsprites += Numsprites;
1475
1475
1476
        ++lwcp;
1476
        ++lwcp;
1477
    }
1477
    }
1478
    quickloadboard = 0;
1478
    quickloadboard = 0;
1479
1479
1480
    if (ournumsectors==0 || ournumwalls==0 || ournumsprites==0)  // nothing loaded
1480
    if (ournumsectors==0 || ournumwalls==0 || ournumsprites==0)  // nothing loaded
1481
    {
1481
    {
1482
        clipmapinfo_init();
1482
        clipmapinfo_init();
1483
1483
1484
        Bfree(fisec);
1484
        Bfree(fisec);
1485
        Bfree(fispr);
1485
        Bfree(fispr);
1486
1486
1487
        return -1;
1487
        return -1;
1488
    }
1488
    }
1489
1489
1490
    // shrink
1490
    // shrink
1491
    loadsector = (tsectortype *)Xrealloc(loadsector, ournumsectors*sizeof(sectortype));
1491
    loadsector = (tsectortype *)Xrealloc(loadsector, ournumsectors*sizeof(sectortype));
1492
    loadwall = (twalltype *)Xrealloc(loadwall, ournumwalls*sizeof(walltype));
1492
    loadwall = (twalltype *)Xrealloc(loadwall, ournumwalls*sizeof(walltype));
1493
1493
1494
    Bmemcpy(sector, loadsector, ournumsectors*sizeof(sectortype));
1494
    Bmemcpy(sector, loadsector, ournumsectors*sizeof(sectortype));
1495
    Bmemcpy(wall, loadwall, ournumwalls*sizeof(walltype));
1495
    Bmemcpy(wall, loadwall, ournumwalls*sizeof(walltype));
1496
    Bmemcpy(sprite, loadsprite, ournumsprites*sizeof(spritetype));
1496
    Bmemcpy(sprite, loadsprite, ournumsprites*sizeof(spritetype));
1497
    numsectors = ournumsectors;
1497
    numsectors = ournumsectors;
1498
    numwalls = ournumwalls;
1498
    numwalls = ournumwalls;
1499
1499
1500
    //  vvvv    don't use headsprite[sect,stat]!   vvvv
1500
    //  vvvv    don't use headsprite[sect,stat]!   vvvv
1501
1501
1502
    sectoidx = (int16_t *)Xmalloc(numsectors*sizeof(sectoidx[0]));
1502
    sectoidx = (int16_t *)Xmalloc(numsectors*sizeof(sectoidx[0]));
1503
1503
1504
    for (i=0; i<numsectors; i++)
1504
    for (i=0; i<numsectors; i++)
1505
        sectoidx[i] = CM_NONE;
1505
        sectoidx[i] = CM_NONE;
1506
1506
1507
    // determine outer sectors
1507
    // determine outer sectors
1508
    for (i=0; i<numsectors; i++)
1508
    for (i=0; i<numsectors; i++)
1509
    {
1509
    {
1510
        for (w=sector[i].wallptr; w<sector[i].wallptr+sector[i].wallnum; w++)
1510
        for (w=sector[i].wallptr; w<sector[i].wallptr+sector[i].wallnum; w++)
1511
            if (wall[w].nextsector<0)
1511
            if (wall[w].nextsector<0)
1512
            {
1512
            {
1513
                sectoidx[i] = CM_OUTER;
1513
                sectoidx[i] = CM_OUTER;
1514
                break;
1514
                break;
1515
            }
1515
            }
1516
    }
1516
    }
1517
    // break connections between outer sectors
1517
    // break connections between outer sectors
1518
    for (i=0; i<numsectors; i++)
1518
    for (i=0; i<numsectors; i++)
1519
    {
1519
    {
1520
        if (sectoidx[i] == CM_OUTER)
1520
        if (sectoidx[i] == CM_OUTER)
1521
            for (w=sector[i].wallptr; w<sector[i].wallptr+sector[i].wallnum; w++)
1521
            for (w=sector[i].wallptr; w<sector[i].wallptr+sector[i].wallnum; w++)
1522
            {
1522
            {
1523
                k = wall[w].nextwall;
1523
                k = wall[w].nextwall;
1524
                if (k>=0 && sectoidx[wall[w].nextsector]==CM_OUTER)
1524
                if (k>=0 && sectoidx[wall[w].nextsector]==CM_OUTER)
1525
                {
1525
                {
1526
                    wall[k].nextwall = wall[k].nextsector = -1;
1526
                    wall[k].nextwall = wall[k].nextsector = -1;
1527
                    wall[w].nextwall = wall[w].nextsector = -1;
1527
                    wall[w].nextwall = wall[w].nextsector = -1;
1528
                }
1528
                }
1529
            }
1529
            }
1530
    }
1530
    }
1531
1531
1532
    {
1532
    {
1533
        int16_t ns, outersect;
1533
        int16_t ns, outersect;
1534
        int32_t pn,scnt, x,y,z, maxdist;
1534
        int32_t pn,scnt, x,y,z, maxdist;
1535
1535
1536
        sectq = (int16_t *)Xmalloc(numsectors*sizeof(sectq[0]));
1536
        sectq = (int16_t *)Xmalloc(numsectors*sizeof(sectq[0]));
1537
        tempictoidx = (int16_t *)Xmalloc(MAXTILES*sizeof(tempictoidx[0]));
1537
        tempictoidx = (int16_t *)Xmalloc(MAXTILES*sizeof(tempictoidx[0]));
1538
1538
1539
        for (i=0; i<MAXTILES; i++)
1539
        for (i=0; i<MAXTILES; i++)
1540
            tempictoidx[i]=-1;
1540
            tempictoidx[i]=-1;
1541
1541
1542
        // collect sprite picnums
1542
        // collect sprite picnums
1543
        for (i=0; i<MAXSPRITES && sprite[i].statnum<MAXSTATUS; i++)
1543
        for (i=0; i<MAXSPRITES && sprite[i].statnum<MAXSTATUS; i++)
1544
        {
1544
        {
1545
            pn = sprite[i].picnum;
1545
            pn = sprite[i].picnum;
1546
            k = sprite[i].sectnum;
1546
            k = sprite[i].sectnum;
1547
            //    -v-  note the <=                         ignore sprites in outer sectors
1547
            //    -v-  note the <=                         ignore sprites in outer sectors
1548
            if (pn<=0 || pn>=MAXTILES || k<0 || k>=numsectors || (sectoidx[k]&CM_OUTER))
1548
            if (pn<=0 || pn>=MAXTILES || k<0 || k>=numsectors || (sectoidx[k]&CM_OUTER))
1549
                continue;
1549
                continue;
1550
1550
1551
            if (numclipmaps >= CM_MAX)
1551
            if (numclipmaps >= CM_MAX)
1552
            {
1552
            {
1553
                initprintf("warning: reached max clip map number %d, not processing any more\n", CM_MAX);
1553
                initprintf("warning: reached max clip map number %d, not processing any more\n", CM_MAX);
1554
                break;
1554
                break;
1555
            }
1555
            }
1556
1556
1557
            // chain
1557
            // chain
1558
            if (pictoidx[pn]>=0)
1558
            if (pictoidx[pn]>=0)
1559
            {
1559
            {
1560
                if (sectoidx[k]&CM_SOME)
1560
                if (sectoidx[k]&CM_SOME)
1561
                {
1561
                {
1562
                    for (fi = 0; fi < g_clipMapFilesNum; ++fi)
1562
                    for (fi = 0; fi < g_clipMapFilesNum; ++fi)
1563
                        if (k>=fisec[fi])
1563
                        if (k>=fisec[fi])
1564
                            break;
1564
                            break;
1565
                    initprintf("clip map \"%s\": error: tried to chain picnum %d (sprite %d) in sector %d which"
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],
1566
                               " already belongs to picnum %d.\n", g_clipMapFiles[fi], pn, i-fispr[fi], k-fisec[fi],
1567
                               clipinfo[sectoidx[k]].picnum);
1567
                               clipinfo[sectoidx[k]].picnum);
1568
                    clipmapinfo_init();
1568
                    clipmapinfo_init();
1569
1569
1570
                    Bfree(fisec);
1570
                    Bfree(fisec);
1571
                    Bfree(fispr);
1571
                    Bfree(fispr);
1572
1572
1573
                    return 2;
1573
                    return 2;
1574
                }
1574
                }
1575
1575
1576
                // new one is front
1576
                // new one is front
1577
                clipinfo[numclipmaps].next = pictoidx[pn];
1577
                clipinfo[numclipmaps].next = pictoidx[pn];
1578
                pictoidx[pn] = numclipmaps;
1578
                pictoidx[pn] = numclipmaps;
1579
            }
1579
            }
1580
            else
1580
            else
1581
            {
1581
            {
1582
                clipinfo[numclipmaps].next = -1;
1582
                clipinfo[numclipmaps].next = -1;
1583
                pictoidx[pn] = numclipmaps;
1583
                pictoidx[pn] = numclipmaps;
1584
            }
1584
            }
1585
1585
1586
            if (!CM_NOROT(i))
1586
            if (!CM_NOROT(i))
1587
            {
1587
            {
1588
                if (sprite[i].ang!=1536 && sprite[i].ang!=512)
1588
                if (sprite[i].ang!=1536 && sprite[i].ang!=512)
1589
                {
1589
                {
1590
                    for (fi = 0; fi < g_clipMapFilesNum; ++fi)
1590
                    for (fi = 0; fi < g_clipMapFilesNum; ++fi)
1591
                        if (i>=fispr[fi])
1591
                        if (i>=fispr[fi])
1592
                            break;
1592
                            break;
1593
                    initprintf("clip map \"%s\": warning: sprite %d pointing neither northward nor southward. %s will be wrong.\n",
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");
1594
                               g_clipMapFiles[fi], i-fispr[fi], (sprite[i].cstat&48)==32 ? "Scaling and flipping" : "X-flipping");
1595
                }
1595
                }
1596
            }
1596
            }
1597
1597
1598
            clipinfo[numclipmaps].picnum = pn;
1598
            clipinfo[numclipmaps].picnum = pn;
1599
1599
1600
            // collect sectors
1600
            // collect sectors
1601
            scnt = numclipsects;
1601
            scnt = numclipsects;
1602
            sectq[numclipsects++] = k;
1602
            sectq[numclipsects++] = k;
1603
            sectoidx[k] = numclipmaps;
1603
            sectoidx[k] = numclipmaps;
1604
1604
1605
            clipinfo[numclipmaps].qbeg = scnt;
1605
            clipinfo[numclipmaps].qbeg = scnt;
1606
1606
1607
            outersect = -1;
1607
            outersect = -1;
1608
1608
1609
            do
1609
            do
1610
            {
1610
            {
1611
                k = sectq[scnt];
1611
                k = sectq[scnt];
1612
1612
1613
                for (w=sector[k].wallptr; w<sector[k].wallptr+sector[k].wallnum; w++)
1613
                for (w=sector[k].wallptr; w<sector[k].wallptr+sector[k].wallnum; w++)
1614
                {
1614
                {
1615
                    ns = wall[w].nextsector;
1615
                    ns = wall[w].nextsector;
1616
                    if (ns>=0)
1616
                    if (ns>=0)
1617
                    {
1617
                    {
1618
                        if (sectoidx[ns]==CM_NONE)
1618
                        if (sectoidx[ns]==CM_NONE)
1619
                        {
1619
                        {
1620
                            sectoidx[ns] = numclipmaps;
1620
                            sectoidx[ns] = numclipmaps;
1621
                            sectq[numclipsects++] = ns;
1621
                            sectq[numclipsects++] = ns;
1622
                        }
1622
                        }
1623
                        else if (sectoidx[ns]&CM_OUTER)
1623
                        else if (sectoidx[ns]&CM_OUTER)
1624
                        {
1624
                        {
1625
                            if (outersect>=0 && ns!=outersect)
1625
                            if (outersect>=0 && ns!=outersect)
1626
                            {
1626
                            {
1627
                                for (fi = 0; fi < g_clipMapFilesNum; ++fi)
1627
                                for (fi = 0; fi < g_clipMapFilesNum; ++fi)
1628
                                    if (ns>=fisec[fi])
1628
                                    if (ns>=fisec[fi])
1629
                                        break;
1629
                                        break;
1630
                                initprintf("clip map \"%s\": error: encountered more than one outer sector (%d and %d)"
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]);
1631
                                           " for sprite %d.\n", g_clipMapFiles[fi], outersect-fisec[fi], ns-fisec[fi], i-fispr[fi]);
1632
                                clipmapinfo_init();
1632
                                clipmapinfo_init();
1633
1633
1634
                                Bfree(fisec);
1634
                                Bfree(fisec);
1635
                                Bfree(fispr);
1635
                                Bfree(fispr);
1636
1636
1637
                                return 3;
1637
                                return 3;
1638
                            }
1638
                            }
1639
1639
1640
                            outersect = ns;
1640
                            outersect = ns;
1641
                            sectoidx[outersect] |= numclipmaps;
1641
                            sectoidx[outersect] |= numclipmaps;
1642
                        }
1642
                        }
1643
                        else if (sectoidx[ns]!=numclipmaps)
1643
                        else if (sectoidx[ns]!=numclipmaps)
1644
                        {
1644
                        {
1645
                            for (fi = 0; fi < g_clipMapFilesNum; ++fi)
1645
                            for (fi = 0; fi < g_clipMapFilesNum; ++fi)
1646
                                if (ns>=fisec[fi])
1646
                                if (ns>=fisec[fi])
1647
                                    break;
1647
                                    break;
1648
                            initprintf("clip map \"%s\": error: encountered sector %d belonging to index %d"
1648
                            initprintf("clip map \"%s\": error: encountered sector %d belonging to index %d"
1649
                                       " while collecting sectors for sprite %d (index %d).\n",
1649
                                       " while collecting sectors for sprite %d (index %d).\n",
1650
                                       g_clipMapFiles[fi], ns-fisec[fi], sectoidx[ns], i-fispr[fi], numclipmaps);
1650
                                       g_clipMapFiles[fi], ns-fisec[fi], sectoidx[ns], i-fispr[fi], numclipmaps);
1651
                            clipmapinfo_init();
1651
                            clipmapinfo_init();
1652
1652
1653
                            Bfree(fisec);
1653
                            Bfree(fisec);
1654
                            Bfree(fispr);
1654
                            Bfree(fispr);
1655
1655
1656
                            return 4;
1656
                            return 4;
1657
                        }
1657
                        }
1658
                    }
1658
                    }
1659
                }
1659
                }
1660
            }
1660
            }
1661
            while (++scnt < numclipsects);
1661
            while (++scnt < numclipsects);
1662
1662
1663
            if (outersect==-1)
1663
            if (outersect==-1)
1664
            {
1664
            {
1665
                initprintf("clip map: INTERNAL ERROR: outersect==-1!\n");
1665
                initprintf("clip map: INTERNAL ERROR: outersect==-1!\n");
1666
                clipmapinfo_init();
1666
                clipmapinfo_init();
1667
1667
1668
                Bfree(fisec);
1668
                Bfree(fisec);
1669
                Bfree(fispr);
1669
                Bfree(fispr);
1670
1670
1671
                return 5;
1671
                return 5;
1672
            }
1672
            }
1673
1673
1674
            sectq[numclipsects++] = outersect;  // last is outer
1674
            sectq[numclipsects++] = outersect;  // last is outer
1675
            clipinfo[numclipmaps].qend = numclipsects-1;
1675
            clipinfo[numclipmaps].qend = numclipsects-1;
1676
1676
1677
            // normalize
1677
            // normalize
1678
            maxdist = 0;
1678
            maxdist = 0;
1679
1679
1680
            for (scnt=clipinfo[numclipmaps].qbeg; scnt<=clipinfo[numclipmaps].qend; scnt++)
1680
            for (scnt=clipinfo[numclipmaps].qbeg; scnt<=clipinfo[numclipmaps].qend; scnt++)
1681
            {
1681
            {
1682
                k = sectq[scnt];
1682
                k = sectq[scnt];
1683
1683
1684
                x = sprite[i].x;
1684
                x = sprite[i].x;
1685
                y = sprite[i].y;
1685
                y = sprite[i].y;
1686
                z = sprite[i].z;
1686
                z = sprite[i].z;
1687
1687
1688
                sector[k].floorz -= z;
1688
                sector[k].floorz -= z;
1689
                sector[k].ceilingz -= z;
1689
                sector[k].ceilingz -= z;
1690
1690
1691
                if (scnt==clipinfo[numclipmaps].qbeg)
1691
                if (scnt==clipinfo[numclipmaps].qbeg)
1692
                {
1692
                {
1693
                    // backup sprite tags since we'll discard sprites later
1693
                    // backup sprite tags since we'll discard sprites later
1694
                    sector[k].CM_XREPEAT = sprite[i].xrepeat;
1694
                    sector[k].CM_XREPEAT = sprite[i].xrepeat;
1695
                    sector[k].CM_YREPEAT = sprite[i].yrepeat;
1695
                    sector[k].CM_YREPEAT = sprite[i].yrepeat;
1696
                    sector[k].CM_XOFFSET = sprite[i].xoffset;
1696
                    sector[k].CM_XOFFSET = sprite[i].xoffset;
1697
                    sector[k].CM_YOFFSET = sprite[i].yoffset;
1697
                    sector[k].CM_YOFFSET = sprite[i].yoffset;
1698
                    sector[k].CM_CSTAT = sprite[i].cstat;
1698
                    sector[k].CM_CSTAT = sprite[i].cstat;
1699
                    sector[k].CM_ANG = sprite[i].ang;
1699
                    sector[k].CM_ANG = sprite[i].ang;
1700
                }
1700
                }
1701
1701
1702
                // backup floor and ceiling z
1702
                // backup floor and ceiling z
1703
                CM_FLOORZ(k) = sector[k].floorz;
1703
                CM_FLOORZ(k) = sector[k].floorz;
1704
                CM_CEILINGZ(k) = sector[k].ceilingz;
1704
                CM_CEILINGZ(k) = sector[k].ceilingz;
1705
1705
1706
                for (w=sector[k].wallptr; w<sector[k].wallptr+sector[k].wallnum; w++)
1706
                for (w=sector[k].wallptr; w<sector[k].wallptr+sector[k].wallnum; w++)
1707
                {
1707
                {
1708
                    wall[w].x -= x;
1708
                    wall[w].x -= x;
1709
                    wall[w].y -= y;
1709
                    wall[w].y -= y;
1710
1710
1711
                    if (scnt!=clipinfo[numclipmaps].qend)
1711
                    if (scnt!=clipinfo[numclipmaps].qend)
1712
                    {
1712
                    {
1713
                        if (CM_NOROT(i))
1713
                        if (CM_NOROT(i))
1714
                        {
1714
                        {
1715
                            if (klabs(wall[w].x) > maxdist)
1715
                            if (klabs(wall[w].x) > maxdist)
1716
                                maxdist = klabs(wall[w].x);
1716
                                maxdist = klabs(wall[w].x);
1717
                            if (klabs(wall[w].y) > maxdist)
1717
                            if (klabs(wall[w].y) > maxdist)
1718
                                maxdist = klabs(wall[w].y);
1718
                                maxdist = klabs(wall[w].y);
1719
                        }
1719
                        }
1720
                        else
1720
                        else
1721
                        {
1721
                        {
1722
                            int32_t tmp = ksqrt(uhypsq(wall[w].x, wall[w].y));
1722
                            int32_t tmp = ksqrt(uhypsq(wall[w].x, wall[w].y));
1723
                            if (tmp > maxdist)
1723
                            if (tmp > maxdist)
1724
                                maxdist = tmp;
1724
                                maxdist = tmp;
1725
                        }
1725
                        }
1726
                    }
1726
                    }
1727
1727
1728
                    // aliasing
1728
                    // aliasing
1729
                    if (wall[w].lotag>0 || wall[w].hitag>0)
1729
                    if (wall[w].lotag>0 || wall[w].hitag>0)
1730
                    {
1730
                    {
1731
                        int32_t ii;
1731
                        int32_t ii;
1732
1732
1733
                        if (wall[w].lotag>0 && wall[w].hitag>0)
1733
                        if (wall[w].lotag>0 && wall[w].hitag>0)
1734
                        {
1734
                        {
1735
                            if (wall[w].lotag > wall[w].hitag)
1735
                            if (wall[w].lotag > wall[w].hitag)
1736
                                swapshort(&wall[w].lotag, &wall[w].hitag);
1736
                                swapshort(&wall[w].lotag, &wall[w].hitag);
1737
1737
1738
                            for (ii=wall[w].lotag; ii<wall[w].hitag; ii++)
1738
                            for (ii=wall[w].lotag; ii<wall[w].hitag; ii++)
1739
                                tempictoidx[ii] = numclipmaps;
1739
                                tempictoidx[ii] = numclipmaps;
1740
                        }
1740
                        }
1741
                        else if (wall[w].lotag>0)
1741
                        else if (wall[w].lotag>0)
1742
                        {
1742
                        {
1743
                            if (wall[w].lotag<MAXTILES)
1743
                            if (wall[w].lotag<MAXTILES)
1744
                                tempictoidx[wall[w].lotag] = numclipmaps;
1744
                                tempictoidx[wall[w].lotag] = numclipmaps;
1745
                        }
1745
                        }
1746
                        else
1746
                        else
1747
                        {
1747
                        {
1748
                            if (wall[w].hitag<MAXTILES)
1748
                            if (wall[w].hitag<MAXTILES)
1749
                                tempictoidx[wall[w].hitag] = numclipmaps;
1749
                                tempictoidx[wall[w].hitag] = numclipmaps;
1750
                        }
1750
                        }
1751
                    }
1751
                    }
1752
1752
1753
                    CM_WALL_X(w) = wall[w].x;
1753
                    CM_WALL_X(w) = wall[w].x;
1754
                    CM_WALL_Y(w) = wall[w].y;
1754
                    CM_WALL_Y(w) = wall[w].y;
1755
                }
1755
                }
1756
            }
1756
            }
1757
1757
1758
            clipinfo[numclipmaps].maxdist = maxdist;
1758
            clipinfo[numclipmaps].maxdist = maxdist;
1759
            numclipmaps++;
1759
            numclipmaps++;
1760
        }
1760
        }
1761
    }
1761
    }
1762
1762
1763
    // yes, too much copying, but better than ugly code
1763
    // yes, too much copying, but better than ugly code
1764
    Bmemcpy(loadsector, sector, ournumsectors*sizeof(sectortype));
1764
    Bmemcpy(loadsector, sector, ournumsectors*sizeof(sectortype));
1765
    Bmemcpy(loadwall, wall, ournumwalls*sizeof(walltype));
1765
    Bmemcpy(loadwall, wall, ournumwalls*sizeof(walltype));
1766
1766
1767
    // loadwallinv will contain all walls with inverted orientation for x/y-flip handling
1767
    // loadwallinv will contain all walls with inverted orientation for x/y-flip handling
1768
    loadwallinv = (twalltype *)Xmalloc(ournumwalls*sizeof(walltype));
1768
    loadwallinv = (twalltype *)Xmalloc(ournumwalls*sizeof(walltype));
1769
1769
1770
    {
1770
    {
1771
        int32_t j, loopstart, loopend, numloopwalls;
1771
        int32_t j, loopstart, loopend, numloopwalls;
1772
1772
1773
        // invert walls!
1773
        // invert walls!
1774
        loopstart = 0;
1774
        loopstart = 0;
1775
        for (j=0; j<ournumwalls; j++)
1775
        for (j=0; j<ournumwalls; j++)
1776
        {
1776
        {
1777
            wall[j].nextsector = wall[j].nextwall = -1;
1777
            wall[j].nextsector = wall[j].nextwall = -1;
1778
1778
1779
            if (wall[j].point2 < j)
1779
            if (wall[j].point2 < j)
1780
            {
1780
            {
1781
                loopend = j+1;
1781
                loopend = j+1;
1782
                numloopwalls = loopend-loopstart;
1782
                numloopwalls = loopend-loopstart;
1783