- got rid of the struct trackers.

They were only used for handling an undefined case in the renderer but the overhead and side effects were too severe.
This commit is contained in:
Christoph Oelckers 2020-07-14 13:51:03 +02:00
parent f307b2a954
commit 2e05ff532b
14 changed files with 23 additions and 618 deletions

View file

@ -774,7 +774,6 @@ set (PCH_SOURCES
build/src/common.cpp
build/src/defs.cpp
build/src/engine.cpp
build/src/hash.cpp
build/src/mdsprite.cpp
build/src/mhk.cpp
build/src/polymost.cpp

View file

@ -28,7 +28,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#include "common_game.h"
#include "build.h"
#include "hash.h"
#include "baselayer.h"
#include "gamecontrol.h"
#include "blood.h"

View file

@ -24,7 +24,6 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#ifndef config_public_h_
#define config_public_h_
#include "hash.h"
#include "gamecvars.h"
#include "gamecontrol.h"

View file

@ -566,12 +566,6 @@ bool GameInterface::LoadGame(FSaveGameNode* node)
bVanilla = false;
#ifdef USE_STRUCT_TRACKERS
Bmemset(sectorchanged, 0, sizeof(sectorchanged));
Bmemset(spritechanged, 0, sizeof(spritechanged));
Bmemset(wallchanged, 0, sizeof(wallchanged));
#endif
#ifdef USE_OPENGL
Polymost_prepare_loadboard();
#endif

View file

@ -355,7 +355,7 @@ void nnExtInitModernStuff(bool bSaveLoad) {
}
if (sysStat)
ThrowError("Sprite status list number %d on sprite #%d is in a range of reserved (%d - %d)!", pSprite->index.cast(), pSprite->statnum.cast(), kStatModernBase, kStatModernMax);
ThrowError("Sprite status list number %d on sprite #%d is in a range of reserved (%d - %d)!", pSprite->index, pSprite->statnum, kStatModernBase, kStatModernMax);
}
switch (pSprite->type) {
@ -410,22 +410,22 @@ void nnExtInitModernStuff(bool bSaveLoad) {
switch (pXSprite->command) {
case kCmdLink:
if (pXSprite->data1 < 1 || pXSprite->data1 >= kMaxPlayers)
ThrowError("\nPlayer Control (SPRITE #%d):\nPlayer out of a range (data1 = %d)", pSprite->index.cast(), pXSprite->data1);
ThrowError("\nPlayer Control (SPRITE #%d):\nPlayer out of a range (data1 = %d)", pSprite->index, pXSprite->data1);
//if (numplayers < pXSprite->data1)
//ThrowError("\nPlayer Control (SPRITE #%d):\n There is no player #%d", pSprite->index, pXSprite->data1);
if (pXSprite->rxID && pXSprite->rxID != kChannelLevelStart)
ThrowError("\nPlayer Control (SPRITE #%d) with Link command should have no RX ID!", pSprite->index.cast(), pXSprite->data1);
ThrowError("\nPlayer Control (SPRITE #%d) with Link command should have no RX ID!", pSprite->index, pXSprite->data1);
if (pXSprite->txID && pXSprite->txID < kChannelUser)
ThrowError("\nPlayer Control (SPRITE #%d):\nTX ID should be in range of %d and %d!", pSprite->index.cast(), kChannelUser, kChannelMax);
ThrowError("\nPlayer Control (SPRITE #%d):\nTX ID should be in range of %d and %d!", pSprite->index, kChannelUser, kChannelMax);
// only one linker per player allowed
for (int nSprite = headspritestat[kStatModernPlayerLinker]; nSprite >= 0; nSprite = nextspritestat[nSprite]) {
XSPRITE* pXCtrl = &xsprite[sprite[nSprite].extra];
if (pXSprite->data1 == pXCtrl->data1)
ThrowError("\nPlayer Control (SPRITE #%d):\nPlayer %d already linked with different player control sprite #%d!", pSprite->index.cast(), pXSprite->data1, nSprite);
ThrowError("\nPlayer Control (SPRITE #%d):\nPlayer %d already linked with different player control sprite #%d!", pSprite->index, pXSprite->data1, nSprite);
}
pXSprite->sysData1 = -1;
pSprite->cstat &= ~CSTAT_SPRITE_BLOCK;
@ -443,7 +443,7 @@ void nnExtInitModernStuff(bool bSaveLoad) {
if (pXSprite->waitTime > 0) {
pXSprite->busyTime += ClipHigh(((pXSprite->waitTime * 120) / 10), 4095); pXSprite->waitTime = 0;
consoleSysMsg("Summing busyTime and waitTime for tracking condition #%d, RX ID %d. Result = %d ticks", pSprite->index.cast(), pXSprite->rxID, pXSprite->busyTime);
consoleSysMsg("Summing busyTime and waitTime for tracking condition #%d, RX ID %d. Result = %d ticks", pSprite->index, pXSprite->rxID, pXSprite->busyTime);
}
pXSprite->busy = pXSprite->busyTime;

View file

@ -217,45 +217,8 @@ enum {
# define EXTERN extern
#endif
#if defined __cplusplus && (defined USE_OPENGL || defined POLYMER)
# define USE_STRUCT_TRACKERS
#endif
#ifdef USE_STRUCT_TRACKERS
static FORCE_INLINE void sector_tracker_hook__(intptr_t address);
static FORCE_INLINE void wall_tracker_hook__(intptr_t address);
static FORCE_INLINE void sprite_tracker_hook__(intptr_t address);
#define TRACKER_NAME__ SectorTracker
#define TRACKER_HOOK_ sector_tracker_hook__
#include "tracker.hpp"
#undef TRACKER_NAME__
#undef TRACKER_HOOK_
#define TRACKER_NAME__ WallTracker
#define TRACKER_HOOK_ wall_tracker_hook__
#include "tracker.hpp"
#undef TRACKER_NAME__
#undef TRACKER_HOOK_
#define TRACKER_NAME__ SpriteTracker
#define TRACKER_HOOK_ sprite_tracker_hook__
#include "tracker.hpp"
#undef TRACKER_NAME__
#undef TRACKER_HOOK_
#define Tracker(Container, Type) Container##Tracker<Type>
#define TrackerCast(x) x.cast()
#else
#define Tracker(Container, Type) Type
#define TrackerCast(x) x
#endif // __cplusplus
// Links to various ABIs specifying (or documenting non-normatively) the
// alignment requirements of aggregates:
@ -280,38 +243,22 @@ enum {
SPR_ALIGN_MASK = 32+16,
};
#define UNTRACKED_STRUCTS__
#include "buildtypes.h"
#undef UNTRACKED_STRUCTS__
#undef buildtypes_h__
#include "buildtypes.h"
#if !defined NEW_MAP_FORMAT
using sectortype = sectortypev7;
using usectortype = usectortypev7;
using usectortype = sectortypev7;
using walltype = walltypev7;
using uwalltype = uwalltypev7;
#else
using sectortype = sectortypevx;
using usectortype = usectortypevx;
using walltype = walltypevx;
using uwalltype = uwalltypevx;
#endif
using uwalltype = walltypev7;
using spritetype = spritetypev7;
using uspritetype = uspritetypev7;
using uspritetype = spritetypev7;
using uspriteptr_t = uspritetype const *;
using uwallptr_t = uwalltype const *;
using usectorptr_t = usectortype const *;
using tspriteptr_t = tspritetype *;
// this is probably never going to be necessary
EDUKE32_STATIC_ASSERT(sizeof(sectortype) == sizeof(usectortype));
EDUKE32_STATIC_ASSERT(sizeof(walltype) == sizeof(uwalltype));
EDUKE32_STATIC_ASSERT(sizeof(spritetype) == sizeof(uspritetype));
#include "clip.h"
@ -400,64 +347,12 @@ EXTERN walltype *wall;
EXTERN spritetype *sprite;
EXTERN tspriteptr_t tsprite;
#else
EXTERN spriteext_t spriteext[MAXSPRITES+MAXUNIQHUDID];
EXTERN spritesmooth_t spritesmooth[MAXSPRITES+MAXUNIQHUDID];
# ifndef NEW_MAP_FORMAT
EXTERN wallext_t wallext[MAXWALLS];
# endif
EXTERN sectortype sector[MAXSECTORS + M32_FIXME_SECTORS];
EXTERN walltype wall[MAXWALLS + M32_FIXME_WALLS];
EXTERN spritetype sprite[MAXSPRITES];
EXTERN uspritetype tsprite[MAXSPRITESONSCREEN];
#endif
#ifdef USE_STRUCT_TRACKERS
EXTERN uint32_t sectorchanged[MAXSECTORS + M32_FIXME_SECTORS];
EXTERN uint32_t wallchanged[MAXWALLS + M32_FIXME_WALLS];
EXTERN uint32_t spritechanged[MAXSPRITES];
#endif
#ifdef USE_STRUCT_TRACKERS
static FORCE_INLINE void sector_tracker_hook__(intptr_t const address)
{
intptr_t const sectnum = (address - (intptr_t)sector) / sizeof(sectortype);
#if DEBUGGINGAIDS>=2
Bassert((unsigned)sectnum < ((MAXSECTORS + M32_FIXME_SECTORS)));
#endif
++sectorchanged[sectnum];
}
static FORCE_INLINE void wall_tracker_hook__(intptr_t const address)
{
intptr_t const wallnum = (address - (intptr_t)wall) / sizeof(walltype);
#if DEBUGGINGAIDS>=2
Bassert((unsigned)wallnum < ((MAXWALLS + M32_FIXME_WALLS)));
#endif
++wallchanged[wallnum];
}
static FORCE_INLINE void sprite_tracker_hook__(intptr_t const address)
{
intptr_t const spritenum = (address - (intptr_t)sprite) / sizeof(spritetype);
#if DEBUGGINGAIDS>=2
Bassert((unsigned)spritenum < MAXSPRITES);
#endif
++spritechanged[spritenum];
}
#endif
static inline tspriteptr_t renderMakeTSpriteFromSprite(tspriteptr_t const tspr, uint16_t const spritenum)
{
auto const spr = (uspriteptr_t)&sprite[spritenum];
auto const spr = &sprite[spritenum];
tspr->pos = spr->pos;
tspr->cstat = spr->cstat;
@ -1240,8 +1135,6 @@ int32_t loaddefinitionsfile(const char *fn);
// -2, board is dodgy
int32_t engineLoadBoardV5V6(const char *filename, char fromwhere, vec3_t *dapos, int16_t *daang, int16_t *dacursectnum);
#include "hash.h"
#ifdef USE_OPENGL
# include "polymost.h"
#endif

View file

@ -5,18 +5,9 @@
#undef SECTORTYPE
#undef SPRITETYPE
#ifdef UNTRACKED_STRUCTS__
#define StructTracker(tracker, type) type
#define StructName(name) u ## name
#else
#define StructTracker Tracker
#define StructName(name) name
#endif
//ceilingstat/floorstat:
// bit 0: 1 = parallaxing, 0 = not "P"
// bit 1: 1 = groudraw, 0 = not

View file

@ -1,83 +0,0 @@
#pragma once
#ifndef hash_h_
#define hash_h_
// Hash functions
#define DJB_MAGIC 5381u
typedef struct hashitem // size is 12/24 bytes.
{
char *string;
intptr_t key;
struct hashitem *next;
} hashitem_t;
typedef struct
{
int32_t size;
hashitem_t **items;
} hashtable_t;
// djb3 algorithm
static inline uint32_t hash_getcode(const char *s)
{
uint32_t h = DJB_MAGIC;
char ch;
while ((ch = Btolower(*s++)) != '\0')
h = ((h << 5) + h) ^ ch;
return h;
}
void hash_init(hashtable_t *t);
void hash_loop(hashtable_t *t, void (*func)(const char *, intptr_t));
void hash_free(hashtable_t *t);
void hash_add(hashtable_t *t, const char *s, intptr_t key, int32_t replace);
void hash_delete(hashtable_t *t, const char *s);
intptr_t hash_findcase(hashtable_t const *t, char const *s);
intptr_t hash_find(hashtable_t const *t, char const *s);
// Hash functions
// modified for raw binary keys and one big allocation, and maximum find() performance
typedef struct inthashitem
{
intptr_t key;
intptr_t value;
struct inthashitem *collision; // use NULL to signify empty and pointer identity to signify end of linked list
} inthashitem_t;
typedef struct
{
inthashitem_t *items;
uint32_t count;
} inthashtable_t;
// djb3 algorithm
static inline uint32_t inthash_getcode(intptr_t key)
{
uint32_t h = DJB_MAGIC;
for (auto keybuf = (uint8_t const *) &key, keybuf_end = keybuf + sizeof(key); keybuf < keybuf_end; ++keybuf)
h = ((h << 5) + h) ^ (uint32_t) *keybuf;
return h;
}
void inthash_init(inthashtable_t *t);
void inthash_loop(inthashtable_t const *t, void (*func)(intptr_t, intptr_t));
void inthash_free(inthashtable_t *t);
void inthash_add(inthashtable_t *t, intptr_t key, intptr_t value, int32_t replace);
void inthash_delete(inthashtable_t *t, intptr_t key);
intptr_t inthash_find(inthashtable_t const *t, intptr_t key);
// keep the load factor below 0.75 and make sure the size is odd
// ideally we would find the next largest prime number
#define INTHASH_SIZE(size) ((size * 4u / 3u) | 1u)
#endif // hash_h_

View file

@ -1,109 +0,0 @@
template<typename T>
class TRACKER_NAME__
{
public:
T value;
inline T *operator&()
{
TRACKER_HOOK_((intptr_t) & this->value);
return &this->value;
}
inline T operator++()
{
TRACKER_HOOK_((intptr_t) & this->value);
return ++this->value;
}
inline T operator++(int)
{
TRACKER_HOOK_((intptr_t) & this->value);
return this->value++;
}
inline T operator--()
{
TRACKER_HOOK_((intptr_t) & this->value);
return --this->value;
}
inline T operator--(int)
{
TRACKER_HOOK_((intptr_t) & this->value);
return this->value--;
}
template <typename U> inline T operator=(U operand)
{
TRACKER_HOOK_((intptr_t) & this->value);
return this->value = (T)operand;
}
template <typename U> inline T operator+=(U operand)
{
TRACKER_HOOK_((intptr_t) & this->value);
return this->value += (T)operand;
}
template <typename U> inline T operator-=(U operand)
{
TRACKER_HOOK_((intptr_t) & this->value);
return this->value -= (T)operand;
}
template <typename U> inline T operator*=(U operand)
{
TRACKER_HOOK_((intptr_t) & this->value);
return this->value *= (T)operand;
}
template <typename U> inline T operator/=(U operand)
{
TRACKER_HOOK_((intptr_t) & this->value);
return this->value /= (T)operand;
}
template <typename U> inline T operator|=(U operand)
{
TRACKER_HOOK_((intptr_t) & this->value);
return this->value |= (T)operand;
}
template <typename U> inline T operator&=(U operand)
{
TRACKER_HOOK_((intptr_t) & this->value);
return this->value &= (T)operand;
}
template <typename U> inline T operator^=(U operand)
{
TRACKER_HOOK_((intptr_t) & this->value);
return this->value ^= (T)operand;
}
template <typename U> inline T operator<<=(U operand)
{
TRACKER_HOOK_((intptr_t) & this->value);
return this->value <<= (T)operand;
}
template <typename U> inline T operator>>=(U operand)
{
TRACKER_HOOK_((intptr_t) & this->value);
return this->value >>= (T)operand;
}
inline operator T() const { return this->value; }
inline T cast() const { return this->value; }
};
template <typename T> struct is_signed<TRACKER_NAME__<T>>
{
static constexpr bool value = std::is_signed<T>::value;
};
template <typename T> struct is_unsigned<TRACKER_NAME__<T>>
{
static constexpr bool value = std::is_unsigned<T>::value;
};

View file

@ -1717,8 +1717,10 @@ int32_t insertsprite(int16_t sectnum, int16_t statnum)
// deletesprite
//
int32_t (*deletesprite_replace)(int16_t spritenum) = NULL;
void polymost_deletesprite(int num);
int32_t deletesprite(int16_t spritenum)
{
polymost_deletesprite(spritenum);
if (deletesprite_replace)
return deletesprite_replace(spritenum);
Bassert((sprite[spritenum].statnum == MAXSTATUS)
@ -3460,11 +3462,6 @@ static void enginePrepareLoadBoard(FileReader & fr, vec3_t *dapos, int16_t *daan
show2dsector.Zero();
Bmemset(show2dsprite, 0, sizeof(show2dsprite));
Bmemset(show2dwall, 0, sizeof(show2dwall));
#ifdef USE_STRUCT_TRACKERS
Bmemset(sectorchanged, 0, sizeof(sectorchanged));
Bmemset(spritechanged, 0, sizeof(spritechanged));
Bmemset(wallchanged, 0, sizeof(wallchanged));
#endif
#ifdef USE_OPENGL
Polymost_prepare_loadboard();

View file

@ -1,271 +0,0 @@
#include "compat.h"
#include "hash.h"
#include "baselayer.h"
void hash_init(hashtable_t *t)
{
hash_free(t);
t->items = (hashitem_t **) Xaligned_calloc(16, t->size, sizeof(hashitem_t));
}
void hash_loop(hashtable_t *t, void(*func)(const char *, intptr_t))
{
if (t->items == nullptr)
return;
for (native_t i=0; i < t->size; i++)
for (auto item = t->items[i]; item != nullptr; item = item->next)
func(item->string, item->key);
}
void hash_free(hashtable_t *t)
{
if (t->items == nullptr)
return;
int remaining = t->size - 1;
do
{
auto cur = t->items[remaining];
while (cur)
{
auto tmp = cur;
cur = cur->next;
Xfree(tmp->string);
Xaligned_free(tmp);
}
} while (--remaining >= 0);
ALIGNED_FREE_AND_NULL(t->items);
}
void hash_add(hashtable_t *t, const char *s, intptr_t key, int32_t replace)
{
#ifdef DEBUGGINGAIDS
Bassert(t->items != nullptr);
#endif
uint32_t const code = hash_getcode(s) % t->size;
auto cur = t->items[code];
if (!cur)
{
cur = (hashitem_t *) Xaligned_alloc(16, sizeof(hashitem_t));
cur->string = Xstrdup(s);
cur->key = key;
cur->next = nullptr;
t->items[code] = cur;
return;
}
hashitem_t *prev = nullptr;
do
{
if (Bstrcmp(s, cur->string) == 0)
{
if (replace) cur->key = key;
return;
}
prev = cur;
} while ((cur = cur->next));
cur = (hashitem_t *) Xaligned_alloc(16, sizeof(hashitem_t));
cur->string = Xstrdup(s);
cur->key = key;
cur->next = nullptr;
prev->next = cur;
}
// delete at most once
void hash_delete(hashtable_t *t, const char *s)
{
#ifdef DEBUGGINGAIDS
Bassert(t->items != nullptr);
#endif
uint32_t const code = hash_getcode(s) % t->size;
auto cur = t->items[code];
if (!cur)
return;
hashitem_t *prev = nullptr;
do
{
if (Bstrcmp(s, cur->string) == 0)
{
Xfree(cur->string);
if (!prev)
t->items[code] = cur->next;
else
prev->next = cur->next;
Xaligned_free(cur);
break;
}
prev = cur;
} while ((cur = cur->next));
}
intptr_t hash_find(const hashtable_t * const t, char const * const s)
{
#ifdef DEBUGGINGAIDS
Bassert(t->items != nullptr);
#endif
auto cur = t->items[hash_getcode(s) % t->size];
if (!cur)
return -1;
do
if (Bstrcmp(s, cur->string) == 0)
return cur->key;
while ((cur = cur->next));
return -1;
}
intptr_t hash_findcase(const hashtable_t * const t, char const * const s)
{
#ifdef DEBUGGINGAIDS
Bassert(t->items != nullptr);
#endif
auto cur = t->items[hash_getcode(s) % t->size];
if (!cur)
return -1;
do
if (Bstrcasecmp(s, cur->string) == 0)
return cur->key;
while ((cur = cur->next));
return -1;
}
void inthash_free(inthashtable_t *t) { ALIGNED_FREE_AND_NULL(t->items); }
void inthash_init(inthashtable_t *t)
{
inthash_free(t);
t->items = (inthashitem_t *) Xaligned_calloc(16, t->count, sizeof(inthashitem_t));
}
void inthash_loop(inthashtable_t const *t, void(*func)(intptr_t, intptr_t))
{
if (t->items == nullptr)
return;
for (auto *item = t->items, *const items_end = t->items + t->count; item < items_end; ++item)
func(item->key, item->value);
}
void inthash_add(inthashtable_t *t, intptr_t key, intptr_t value, int32_t replace)
{
#ifdef DEBUGGINGAIDS
Bassert(t->items != nullptr);
#endif
auto seeker = t->items + inthash_getcode(key) % t->count;
if (seeker->collision == nullptr)
{
seeker->key = key;
seeker->value = value;
seeker->collision = seeker;
return;
}
if (seeker->key == key)
{
if (replace)
seeker->value = value;
return;
}
while (seeker != seeker->collision)
{
seeker = seeker->collision;
if (seeker->key == key)
{
if (replace)
seeker->value = value;
return;
}
}
auto tail = seeker;
do
tail = t->items + (tail - t->items + 1) % t->count;
while (tail->collision != nullptr && tail != seeker);
if (EDUKE32_PREDICT_FALSE(tail == seeker))
I_Error("inthash_add(): table full!\n");
tail->key = key;
tail->value = value;
tail->collision = seeker->collision = tail;
}
// delete at most once
void inthash_delete(inthashtable_t *t, intptr_t key)
{
#ifdef DEBUGGINGAIDS
Bassert(t->items != nullptr);
#endif
auto seeker = t->items + inthash_getcode(key) % t->count;
if (seeker->collision == nullptr || seeker->key == key)
{
seeker->collision = nullptr;
return;
}
while (seeker != seeker->collision)
{
auto prev = seeker;
seeker = seeker->collision;
if (seeker->key == key)
{
prev->collision = seeker == seeker->collision ? prev : seeker->collision;
seeker->collision = nullptr;
return;
}
}
}
intptr_t inthash_find(inthashtable_t const *t, intptr_t key)
{
#ifdef DEBUGGINGAIDS
Bassert(t->items != nullptr);
#endif
auto seeker = t->items + inthash_getcode(key) % t->count;
if (seeker->collision == nullptr)
return -1;
if (seeker->key == key)
return seeker->value;
while (seeker != seeker->collision)
{
seeker = seeker->collision;
if (seeker->key == key)
return seeker->value;
}
return -1;
}

View file

@ -3566,8 +3566,6 @@ void polymost_completeMirror()
typedef struct
{
uint32_t wrev;
uint32_t srev;
int16_t wall;
int8_t wdist;
int8_t filler;
@ -3580,6 +3578,13 @@ void Polymost_prepare_loadboard(void)
Bmemset(wsprinfo, 0, sizeof(wsprinfo));
}
void polymost_deletesprite(int num)
{
wsprinfo[num].wall = -1;
}
static inline int32_t polymost_findwall(tspritetype const * const tspr, vec2_t const * const tsiz, int32_t * rd)
{
int32_t dist = 4, closest = -1;
@ -3897,9 +3902,8 @@ void polymost_drawsprite(int32_t snum)
int32_t w = (s == -1) ? -1 : wsprinfo[s].wall;
// find the wall most likely to be what the sprite is supposed to be ornamented against
// this is really slow, so cache the result
if (s == -1 || !wsprinfo[s].wall || (spritechanged[s] != wsprinfo[s].srev) ||
(w != -1 && wallchanged[w] != wsprinfo[s].wrev))
// this is really slow, so cache the result. Also assume that this association never changes once it is set up
if (s == -1 || !wsprinfo[s].wall)
{
w = polymost_findwall(tspr, &tsiz, &walldist);
@ -3911,8 +3915,6 @@ void polymost_drawsprite(int32_t snum)
if (w != -1)
{
ws->wdist = walldist;
ws->wrev = wallchanged[w];
ws->srev = spritechanged[s];
}
}
}

View file

@ -831,10 +831,10 @@ void DrawStatus()
int x = (nViewLeft + nViewRight) / 2;
snprintf(coordBuf, 50, "X %d", (int)sprite[nSprite].x.cast());
snprintf(coordBuf, 50, "X %d", (int)sprite[nSprite].x);
printext(x, nViewTop + 1, coordBuf, kTile159, 255);
snprintf(coordBuf, 50, "Y %d", sprite[nSprite].y.cast());
snprintf(coordBuf, 50, "Y %d", sprite[nSprite].y);
printext(x, nViewTop + 10, coordBuf, kTile159, 255);
}

View file

@ -1197,12 +1197,6 @@ static void postloadplayer(int32_t savegamep)
// if (savegamep) ?
resettimevars();
#ifdef USE_STRUCT_TRACKERS
Bmemset(sectorchanged, 0, sizeof(sectorchanged));
Bmemset(spritechanged, 0, sizeof(spritechanged));
Bmemset(wallchanged, 0, sizeof(wallchanged));
#endif
#ifdef POLYMER
//9
if (videoGetRenderMode() == REND_POLYMER)