Merge remote-tracking branch 'remotes/origin/master' into Texture_Cleanup

# Conflicts:
#	src/polyrenderer/poly_renderthread.cpp
#	src/swrenderer/r_renderthread.cpp
This commit is contained in:
Christoph Oelckers 2018-12-10 18:47:21 +01:00
commit 91a8f5cd04
17 changed files with 126 additions and 59 deletions

View file

@ -271,6 +271,22 @@ Error X86RAPass::emitSwapGp(VirtReg* dstReg, VirtReg* srcReg, uint32_t dstPhysId
return kErrorOk; return kErrorOk;
} }
Error X86RAPass::emitSwapVec(VirtReg* dstReg, VirtReg* srcReg, uint32_t dstPhysId, uint32_t srcPhysId, const char* reason) noexcept {
ASMJIT_ASSERT(dstPhysId != Globals::kInvalidRegId);
ASMJIT_ASSERT(srcPhysId != Globals::kInvalidRegId);
ASMJIT_ASSERT(dstPhysId != srcPhysId);
X86Reg a = X86Reg::fromSignature(dstReg->getSignature(), dstPhysId);
X86Reg b = X86Reg::fromSignature(srcReg->getSignature(), srcPhysId);
ASMJIT_PROPAGATE(cc()->emit(X86Inst::kIdXorps, a, b));
if (_emitComments)
cc()->getCursor()->setInlineComment(cc()->_cbDataZone.sformat("[%s] %s, %s", reason, dstReg->getName(), srcReg->getName()));
ASMJIT_PROPAGATE(cc()->emit(X86Inst::kIdXorps, b, a));
ASMJIT_PROPAGATE(cc()->emit(X86Inst::kIdXorps, a, b));
return kErrorOk;
}
Error X86RAPass::emitImmToReg(uint32_t dstTypeId, uint32_t dstPhysId, const Imm* src) noexcept { Error X86RAPass::emitImmToReg(uint32_t dstTypeId, uint32_t dstPhysId, const Imm* src) noexcept {
ASMJIT_ASSERT(dstPhysId != Globals::kInvalidRegId); ASMJIT_ASSERT(dstPhysId != Globals::kInvalidRegId);
@ -778,6 +794,9 @@ _MoveOrLoad:
if (C == X86Reg::kKindGp) { if (C == X86Reg::kKindGp) {
self->swapGp(dVReg, sVd); self->swapGp(dVReg, sVd);
} }
else if (C == X86Reg::kKindVec) {
self->swapVec(dVReg, sVd);
}
else { else {
self->spill<C>(dVReg); self->spill<C>(dVReg);
self->move<C>(sVd, physId); self->move<C>(sVd, physId);
@ -932,10 +951,13 @@ static ASMJIT_INLINE void X86RAPass_intersectStateVars(X86RAPass* self, X86RASta
didWork = true; didWork = true;
continue; continue;
} }
else if (C == X86Reg::kKindGp) { else if (C == X86Reg::kKindGp || C == X86Reg::kKindVec) {
if (aCell.getState() == VirtReg::kStateReg) { if (aCell.getState() == VirtReg::kStateReg) {
if (dVReg->getPhysId() != Globals::kInvalidRegId && aVReg->getPhysId() != Globals::kInvalidRegId) { if (dVReg->getPhysId() != Globals::kInvalidRegId && aVReg->getPhysId() != Globals::kInvalidRegId) {
self->swapGp(dVReg, aVReg); if (C == X86Reg::kKindGp)
self->swapGp(dVReg, aVReg);
else
self->swapVec(dVReg, aVReg);
didWork = true; didWork = true;
continue; continue;
@ -2787,9 +2809,13 @@ ASMJIT_INLINE void X86VarAlloc::alloc() {
// allocation tasks by a single 'xchg' instruction, swapping // allocation tasks by a single 'xchg' instruction, swapping
// two registers required by the instruction/node or one register // two registers required by the instruction/node or one register
// required with another non-required. // required with another non-required.
if (C == X86Reg::kKindGp && aPhysId != Globals::kInvalidRegId) { // Uses xor swap for Vec registers.
if ((C == X86Reg::kKindGp || C == X86Reg::kKindVec) && aPhysId != Globals::kInvalidRegId) {
TiedReg* bTied = bVReg->_tied; TiedReg* bTied = bVReg->_tied;
_context->swapGp(aVReg, bVReg); if (C == X86Reg::kKindGp)
_context->swapGp(aVReg, bVReg);
else
_context->swapVec(aVReg, bVReg);
aTied->flags |= TiedReg::kRDone; aTied->flags |= TiedReg::kRDone;
addTiedDone(C); addTiedDone(C);
@ -3341,8 +3367,11 @@ ASMJIT_INLINE void X86CallAlloc::alloc() {
// allocation tasks by a single 'xchg' instruction, swapping // allocation tasks by a single 'xchg' instruction, swapping
// two registers required by the instruction/node or one register // two registers required by the instruction/node or one register
// required with another non-required. // required with another non-required.
if (C == X86Reg::kKindGp && sPhysId != Globals::kInvalidRegId) { if ((C == X86Reg::kKindGp || C == X86Reg::kKindVec) && sPhysId != Globals::kInvalidRegId) {
_context->swapGp(aVReg, bVReg); if (C == X86Reg::kKindGp)
_context->swapGp(aVReg, bVReg);
else
_context->swapVec(aVReg, bVReg);
aTied->flags |= TiedReg::kRDone; aTied->flags |= TiedReg::kRDone;
addTiedDone(C); addTiedDone(C);

View file

@ -327,6 +327,7 @@ public:
Error emitLoad(VirtReg* vreg, uint32_t id, const char* reason); Error emitLoad(VirtReg* vreg, uint32_t id, const char* reason);
Error emitSave(VirtReg* vreg, uint32_t id, const char* reason); Error emitSave(VirtReg* vreg, uint32_t id, const char* reason);
Error emitSwapGp(VirtReg* aVReg, VirtReg* bVReg, uint32_t aId, uint32_t bId, const char* reason) noexcept; Error emitSwapGp(VirtReg* aVReg, VirtReg* bVReg, uint32_t aId, uint32_t bId, const char* reason) noexcept;
Error emitSwapVec(VirtReg* aVReg, VirtReg* bVReg, uint32_t aId, uint32_t bId, const char* reason) noexcept;
Error emitImmToReg(uint32_t dstTypeId, uint32_t dstPhysId, const Imm* src) noexcept; Error emitImmToReg(uint32_t dstTypeId, uint32_t dstPhysId, const Imm* src) noexcept;
Error emitImmToStack(uint32_t dstTypeId, const X86Mem* dst, const Imm* src) noexcept; Error emitImmToStack(uint32_t dstTypeId, const X86Mem* dst, const Imm* src) noexcept;
@ -515,6 +516,37 @@ public:
ASMJIT_X86_CHECK_STATE ASMJIT_X86_CHECK_STATE
} }
//! Swap two registers
//!
//! Xor swap on Vec registers.
ASMJIT_INLINE void swapVec(VirtReg* aVReg, VirtReg* bVReg) {
ASMJIT_ASSERT(aVReg != bVReg);
ASMJIT_ASSERT(aVReg->getKind() == X86Reg::kKindVec);
ASMJIT_ASSERT(aVReg->getState() == VirtReg::kStateReg);
ASMJIT_ASSERT(aVReg->getPhysId() != Globals::kInvalidRegId);
ASMJIT_ASSERT(bVReg->getKind() == X86Reg::kKindVec);
ASMJIT_ASSERT(bVReg->getState() == VirtReg::kStateReg);
ASMJIT_ASSERT(bVReg->getPhysId() != Globals::kInvalidRegId);
uint32_t aIndex = aVReg->getPhysId();
uint32_t bIndex = bVReg->getPhysId();
emitSwapVec(aVReg, bVReg, aIndex, bIndex, "Swap");
aVReg->setPhysId(bIndex);
bVReg->setPhysId(aIndex);
_x86State.getListByKind(X86Reg::kKindVec)[aIndex] = bVReg;
_x86State.getListByKind(X86Reg::kKindVec)[bIndex] = aVReg;
uint32_t m = aVReg->isModified() ^ bVReg->isModified();
_x86State._modified.xor_(X86Reg::kKindVec, (m << aIndex) | (m << bIndex));
ASMJIT_X86_CHECK_STATE
}
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------
// [Alloc / Spill] // [Alloc / Spill]
// -------------------------------------------------------------------------- // --------------------------------------------------------------------------

View file

@ -453,7 +453,7 @@ public:
TObjPtr<AActor*> MUSINFOactor = nullptr; // For MUSINFO purposes TObjPtr<AActor*> MUSINFOactor = nullptr; // For MUSINFO purposes
int8_t MUSINFOtics = 0; int8_t MUSINFOtics = 0;
bool settings_controller = true; // Player can control game settings. bool settings_controller = false; // Player can control game settings.
int8_t crouching = 0; int8_t crouching = 0;
int8_t crouchdir = 0; int8_t crouchdir = 0;

View file

@ -148,7 +148,7 @@ AActor* actorvalue(const svalue_t &svalue)
return NULL; return NULL;
} }
// Inventory items in the player's inventory have to be considered non-present. // Inventory items in the player's inventory have to be considered non-present.
if (svalue.value.mobj == NULL || !svalue.value.mobj->IsMapActor()) if (SpawnedThings[intval] == nullptr || !SpawnedThings[intval]->IsMapActor())
{ {
return NULL; return NULL;
} }

View file

@ -1285,6 +1285,7 @@ void G_PlayerReborn (int player)
log = p->LogText; log = p->LogText;
chasecam = p->cheats & CF_CHASECAM; chasecam = p->cheats & CF_CHASECAM;
Bot = p->Bot; //Added by MC: Bot = p->Bot; //Added by MC:
const bool settings_controller = p->settings_controller;
// Reset player structure to its defaults // Reset player structure to its defaults
p->~player_t(); p->~player_t();
@ -1303,6 +1304,7 @@ void G_PlayerReborn (int player)
p->LogText = log; p->LogText = log;
p->cheats |= chasecam; p->cheats |= chasecam;
p->Bot = Bot; //Added by MC: p->Bot = Bot; //Added by MC:
p->settings_controller = settings_controller;
p->oldbuttons = ~0, p->attackdown = true; p->usedown = true; // don't do anything immediately p->oldbuttons = ~0, p->attackdown = true; p->usedown = true; // don't do anything immediately
p->original_oldbuttons = ~0; p->original_oldbuttons = ~0;

View file

@ -74,6 +74,7 @@ void PolyRenderThread::FlushDrawQueue()
} }
} }
static std::mutex loadmutex;
void PolyRenderThread::PrepareTexture(FSoftwareTexture *texture, FRenderStyle style) void PolyRenderThread::PrepareTexture(FSoftwareTexture *texture, FRenderStyle style)
{ {
if (texture == nullptr) if (texture == nullptr)
@ -87,8 +88,6 @@ void PolyRenderThread::PrepareTexture(FSoftwareTexture *texture, FRenderStyle st
// It is critical that this function is called before any direct // It is critical that this function is called before any direct
// calls to GetPixels for this to work. // calls to GetPixels for this to work.
static std::mutex loadmutex;
std::unique_lock<std::mutex> lock(loadmutex); std::unique_lock<std::mutex> lock(loadmutex);
const FSoftwareTextureSpan *spans; const FSoftwareTextureSpan *spans;
@ -105,10 +104,9 @@ void PolyRenderThread::PrepareTexture(FSoftwareTexture *texture, FRenderStyle st
} }
} }
static std::mutex polyobjmutex;
void PolyRenderThread::PreparePolyObject(subsector_t *sub) void PolyRenderThread::PreparePolyObject(subsector_t *sub)
{ {
static std::mutex polyobjmutex;
std::unique_lock<std::mutex> lock(polyobjmutex); std::unique_lock<std::mutex> lock(polyobjmutex);
if (sub->BSP == nullptr || sub->BSP->bDirty) if (sub->BSP == nullptr || sub->BSP->bDirty)

View file

@ -77,11 +77,14 @@ namespace
} }
} }
void R_ShowCurrentScaling();
CUSTOM_CVAR(Float, vid_scalefactor, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CUSTOM_CVAR(Float, vid_scalefactor, 1.0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
{ {
setsizeneeded = true; setsizeneeded = true;
if (self < 0.05 || self > 2.0) if (self < 0.05 || self > 2.0)
self = 1.0; self = 1.0;
if (self != 1.0)
R_ShowCurrentScaling();
} }
CUSTOM_CVAR(Int, vid_scalemode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) CUSTOM_CVAR(Int, vid_scalemode, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
@ -142,21 +145,6 @@ void R_ShowCurrentScaling()
Printf("Real resolution: %i x %i\nEmulated resolution: %i x %i\n", x1, y1, x2, y2); Printf("Real resolution: %i x %i\nEmulated resolution: %i x %i\n", x1, y1, x2, y2);
} }
bool R_CalcsShouldBeBlocked()
{
if (vid_scalemode < 0 || vid_scalemode > 1)
{
Printf("vid_scalemode should be 0 or 1 before using this command.\n");
return true;
}
if (vid_aspect != 0 && vid_cropaspect == true)
{ // just warn ... I'm not going to fix this, it's a pretty niche condition anyway.
Printf("Warning: Using this command while vid_aspect is not 0 will yield results based on FULL screen geometry, NOT cropped!.\n");
return false;
}
return false;
}
CCMD (vid_showcurrentscaling) CCMD (vid_showcurrentscaling)
{ {
R_ShowCurrentScaling(); R_ShowCurrentScaling();
@ -164,24 +152,21 @@ CCMD (vid_showcurrentscaling)
CCMD (vid_scaletowidth) CCMD (vid_scaletowidth)
{ {
if (R_CalcsShouldBeBlocked())
return;
if (argv.argc() > 1) if (argv.argc() > 1)
vid_scalefactor = (float)((double)atof(argv[1]) / screen->GetClientWidth()); {
// the following enables the use of ViewportScaledWidth to get the proper dimensions in custom scale modes
R_ShowCurrentScaling(); vid_scalefactor = 1;
vid_scalefactor = (float)((double)atof(argv[1]) / ViewportScaledWidth(screen->GetClientWidth(), screen->GetClientHeight()));
}
} }
CCMD (vid_scaletoheight) CCMD (vid_scaletoheight)
{ {
if (R_CalcsShouldBeBlocked())
return;
if (argv.argc() > 1) if (argv.argc() > 1)
vid_scalefactor = (float)((double)atof(argv[1]) / screen->GetClientHeight()); {
vid_scalefactor = 1;
R_ShowCurrentScaling(); vid_scalefactor = (float)((double)atof(argv[1]) / ViewportScaledHeight(screen->GetClientWidth(), screen->GetClientHeight()));
}
} }
inline bool atob(char* I) inline bool atob(char* I)

View file

@ -121,9 +121,9 @@ template<class T, int fill = 1> void ArrayResize(T *self, int amount)
} }
} }
template<class T> void ArrayReserve(T *self, int amount) template<class T> unsigned int ArrayReserve(T *self, int amount)
{ {
self->Reserve(amount); return self->Reserve(amount);
} }
template<class T> int ArrayMax(T *self) template<class T> int ArrayMax(T *self)

View file

@ -543,6 +543,8 @@ void JitCompiler::EmitNativeCall(VMNativeFunction *target)
ParamOpcodes.Clear(); ParamOpcodes.Clear();
} }
static std::map<FString, std::unique_ptr<TArray<uint8_t>>> argsCache;
asmjit::FuncSignature JitCompiler::CreateFuncSignature() asmjit::FuncSignature JitCompiler::CreateFuncSignature()
{ {
using namespace asmjit; using namespace asmjit;
@ -657,7 +659,6 @@ asmjit::FuncSignature JitCompiler::CreateFuncSignature()
} }
// FuncSignature only keeps a pointer to its args array. Store a copy of each args array variant. // FuncSignature only keeps a pointer to its args array. Store a copy of each args array variant.
static std::map<FString, std::unique_ptr<TArray<uint8_t>>> argsCache;
std::unique_ptr<TArray<uint8_t>> &cachedArgs = argsCache[key]; std::unique_ptr<TArray<uint8_t>> &cachedArgs = argsCache[key];
if (!cachedArgs) cachedArgs.reset(new TArray<uint8_t>(args)); if (!cachedArgs) cachedArgs.reset(new TArray<uint8_t>(args));

View file

@ -169,16 +169,28 @@ void JitCompiler::EmitRET()
if (cc.is64Bit()) if (cc.is64Bit())
{ {
if (regtype & REGT_KONST) if (regtype & REGT_KONST)
cc.mov(x86::qword_ptr(location), asmjit::imm_ptr(konsta[regnum].v)); {
auto ptr = newTempIntPtr();
cc.mov(ptr, asmjit::imm_ptr(konsta[regnum].v));
cc.mov(x86::qword_ptr(location), ptr);
}
else else
{
cc.mov(x86::qword_ptr(location), regA[regnum]); cc.mov(x86::qword_ptr(location), regA[regnum]);
}
} }
else else
{ {
if (regtype & REGT_KONST) if (regtype & REGT_KONST)
cc.mov(x86::dword_ptr(location), asmjit::imm_ptr(konsta[regnum].v)); {
auto ptr = newTempIntPtr();
cc.mov(ptr, asmjit::imm_ptr(konsta[regnum].v));
cc.mov(x86::dword_ptr(location), ptr);
}
else else
{
cc.mov(x86::dword_ptr(location), regA[regnum]); cc.mov(x86::dword_ptr(location), regA[regnum]);
}
} }
break; break;
} }

View file

@ -2451,7 +2451,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, GetAutomapPosition, GetAutomapPositi
ACTION_RETURN_VEC2(AM_GetPosition()); ACTION_RETURN_VEC2(AM_GetPosition());
} }
static int ZGetUDMFInt(int type, int index, int key) static int ZGetUDMFInt(FLevelLocals *self, int type, int index, int key)
{ {
return GetUDMFInt(type, index, ENamedName(key)); return GetUDMFInt(type, index, ENamedName(key));
} }
@ -2465,7 +2465,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, GetUDMFInt, ZGetUDMFInt)
ACTION_RETURN_INT(GetUDMFInt(type, index, key)); ACTION_RETURN_INT(GetUDMFInt(type, index, key));
} }
static double ZGetUDMFFloat(int type, int index, int key) static double ZGetUDMFFloat(FLevelLocals *self, int type, int index, int key)
{ {
return GetUDMFFloat(type, index, ENamedName(key)); return GetUDMFFloat(type, index, ENamedName(key));
} }
@ -2479,7 +2479,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(FLevelLocals, GetUDMFFloat, ZGetUDMFFloat)
ACTION_RETURN_FLOAT(GetUDMFFloat(type, index, key)); ACTION_RETURN_FLOAT(GetUDMFFloat(type, index, key));
} }
static void ZGetUDMFString(int type, int index, int key, FString *result) static void ZGetUDMFString(FLevelLocals *self, int type, int index, int key, FString *result)
{ {
*result = GetUDMFString(type, index, ENamedName(key)); *result = GetUDMFString(type, index, ENamedName(key));
} }

View file

@ -128,7 +128,12 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, GetPointer, COPY_AAPTR)
// //
//========================================================================== //==========================================================================
DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_StopSound, S_StopSound) static void NativeStopSound(AActor *actor, int slot)
{
S_StopSound(actor, slot);
}
DEFINE_ACTION_FUNCTION_NATIVE(AActor, A_StopSound, NativeStopSound)
{ {
PARAM_SELF_PROLOGUE(AActor); PARAM_SELF_PROLOGUE(AActor);
PARAM_INT(slot); PARAM_INT(slot);
@ -475,7 +480,7 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, Vec2To, Vec2To)
ACTION_RETURN_VEC2(self->Vec2To(t)); ACTION_RETURN_VEC2(self->Vec2To(t));
} }
static void Vec3Angle(AActor *self, double length, double angle, double z, bool absolute, DVector2 *result) static void Vec3Angle(AActor *self, double length, double angle, double z, bool absolute, DVector3 *result)
{ {
*result = self->Vec3Angle(length, angle, z, absolute); *result = self->Vec3Angle(length, angle, z, absolute);
} }

View file

@ -89,8 +89,8 @@ namespace swrenderer
return pal_drawers.get(); return pal_drawers.get();
} }
void RenderThread::PrepareTexture(FSoftwareTexture *texture, FRenderStyle style) static std::mutex loadmutex;
{ void RenderThread::PrepareTexture(FSoftwareTexture *texture, FRenderStyle style) {
if (texture == nullptr) if (texture == nullptr)
return; return;
@ -102,8 +102,6 @@ namespace swrenderer
// It is critical that this function is called before any direct // It is critical that this function is called before any direct
// calls to GetPixels for this to work. // calls to GetPixels for this to work.
static std::mutex loadmutex;
std::unique_lock<std::mutex> lock(loadmutex); std::unique_lock<std::mutex> lock(loadmutex);
const FSoftwareTextureSpan *spans; const FSoftwareTextureSpan *spans;
@ -117,13 +115,12 @@ namespace swrenderer
bool alpha = !!(style.Flags & STYLEF_RedIsAlpha); bool alpha = !!(style.Flags & STYLEF_RedIsAlpha);
texture->GetPixels(alpha); texture->GetPixels(alpha);
texture->GetColumn(alpha, 0, &spans); texture->GetColumn(alpha, 0, &spans);
} }
} }
static std::mutex polyobjmutex;
void RenderThread::PreparePolyObject(subsector_t *sub) void RenderThread::PreparePolyObject(subsector_t *sub)
{ {
static std::mutex polyobjmutex;
std::unique_lock<std::mutex> lock(polyobjmutex); std::unique_lock<std::mutex> lock(polyobjmutex);
if (sub->BSP == nullptr || sub->BSP->bDirty) if (sub->BSP == nullptr || sub->BSP->bDirty)

View file

@ -70,12 +70,12 @@ TArray<FSWColormap> SpecialSWColormaps;
// Colored Lighting Stuffs // Colored Lighting Stuffs
// //
//========================================================================== //==========================================================================
static std::mutex buildmapmutex;
static FDynamicColormap *CreateSpecialLights (PalEntry color, PalEntry fade, int desaturate) static FDynamicColormap *CreateSpecialLights (PalEntry color, PalEntry fade, int desaturate)
{ {
// GetSpecialLights is called by the scene worker threads. // GetSpecialLights is called by the scene worker threads.
// If we didn't find the colormap, search again, but this time one thread at a time // If we didn't find the colormap, search again, but this time one thread at a time
static std::mutex buildmapmutex;
std::unique_lock<std::mutex> lock(buildmapmutex); std::unique_lock<std::mutex> lock(buildmapmutex);
// If this colormap has already been created, just return it // If this colormap has already been created, just return it

View file

@ -219,8 +219,6 @@ void DFrameBuffer::DrawTextCommon(FFont *font, int normalcolor, double x, double
int kerning; int kerning;
FTexture *pic; FTexture *pic;
assert(string[0] != '$');
if (parms.celly == 0) parms.celly = font->GetHeight() + 1; if (parms.celly == 0) parms.celly = font->GetHeight() + 1;
parms.celly *= parms.scaley; parms.celly *= parms.scaley;

View file

@ -93,6 +93,11 @@ CUSTOM_CVAR(Int, vid_maxfps, 200, CVAR_ARCHIVE | CVAR_GLOBALCONFIG)
CUSTOM_CVAR(Int, vid_rendermode, 4, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) CUSTOM_CVAR(Int, vid_rendermode, 4, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL)
{ {
if (self < 0 || self > 4)
{
self = 4;
}
if (usergame) if (usergame)
{ {
// [SP] Update pitch limits to the netgame/gamesim. // [SP] Update pitch limits to the netgame/gamesim.

View file

@ -172,6 +172,9 @@ AF40D0E49BD1B76D4B1AADD8212ADC46 // MAP01 (the wad that shall not be named =P)
3DEE4EFEFAF3260C800A30734F54CE75 // Hellbound, map14 3DEE4EFEFAF3260C800A30734F54CE75 // Hellbound, map14
5FAA25F5A6AAB3409CAE0AF87F910341 // DOOM.wad e1m6 5FAA25F5A6AAB3409CAE0AF87F910341 // DOOM.wad e1m6
94893A0DC429A22ADC4B3A73DA537E16 // DOOM2.WAD map25 94893A0DC429A22ADC4B3A73DA537E16 // DOOM2.WAD map25
D5F64E02679A81B82006AF34A6A8EAC3 // plutonia.wad map32
BA4860C7A2F5D705DB32A1A38DB77EC4 // pl2.wad map10
EDA5CE7C462BD171BF8110AC56B67857 // pl2.wad map11
{ {
rebuildnodes rebuildnodes
} }