Subversion Repositories eduke32

Rev

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

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