Subversion Repositories eduke32

Rev

Rev 5051 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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