- refined wall sprite check so that orthogonally aligned sprites are only aligned to orthogonal walls.

Here even the slightest deviation can create problems.
This commit is contained in:
Christoph Oelckers 2022-08-03 14:13:42 +02:00
parent cac54d42e9
commit 7debab7ff4
17 changed files with 233 additions and 41 deletions

View file

@ -12,19 +12,19 @@ struct VersionInfo
uint16_t minor;
uint32_t revision;
bool operator <=(const VersionInfo& o) const
constexpr bool operator <=(const VersionInfo& o) const
{
return o.major > this->major || (o.major == this->major && o.minor > this->minor) || (o.major == this->major && o.minor == this->minor && o.revision >= this->revision);
}
bool operator >=(const VersionInfo& o) const
constexpr bool operator >=(const VersionInfo& o) const
{
return o.major < this->major || (o.major == this->major && o.minor < this->minor) || (o.major == this->major && o.minor == this->minor && o.revision <= this->revision);
}
bool operator > (const VersionInfo& o) const
constexpr bool operator > (const VersionInfo& o) const
{
return o.major < this->major || (o.major == this->major && o.minor < this->minor) || (o.major == this->major && o.minor == this->minor && o.revision < this->revision);
}
bool operator < (const VersionInfo& o) const
constexpr bool operator < (const VersionInfo& o) const
{
return o.major > this->major || (o.major == this->major && o.minor > this->minor) || (o.major == this->major && o.minor == this->minor && o.revision > this->revision);
}
@ -32,7 +32,7 @@ struct VersionInfo
};
// Cannot be a constructor because Lemon would puke on it.
inline VersionInfo MakeVersion(unsigned int ma, unsigned int mi, unsigned int re = 0)
constexpr VersionInfo MakeVersion(unsigned int ma, unsigned int mi, unsigned int re = 0)
{
return{ (uint16_t)ma, (uint16_t)mi, (uint32_t)re };
}

View file

@ -484,6 +484,7 @@ void OpenGLFrameBuffer::SetSaveBuffers(bool yes)
void OpenGLFrameBuffer::BeginFrame()
{
SetViewportRects(nullptr);
mViewpoints->Clear();
if (GLRenderer != nullptr)
GLRenderer->BeginFrame();
}

View file

@ -44,7 +44,8 @@
static TArray<FString> m_Extensions;
RenderContext gl;
static double realglversion; // this is public so the statistics code can access it.
static double realglversion;
static bool bindless;
//==========================================================================
//
@ -156,7 +157,7 @@ void gl_LoadExtensions()
#ifdef _WIN32
if (strstr(gl.vendorstring, "ATI Tech"))
{
gl.flags |= RFL_NO_CLIP_PLANES; // gl_ClipDistance is horribly broken on ATI GL3 drivers for Windows. (TBD: Relegate to vintage build? Maybe after the next survey.)
gl.flags |= RFL_NO_CLIP_PLANES; // gl_ClipDistance is horribly broken on ATI GL3 drivers for Windows.
}
#endif
gl.glslversion = 3.31f; // Force GLSL down to 3.3.
@ -201,6 +202,8 @@ void gl_LoadExtensions()
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &gl.max_texturesize);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
bindless = CheckExtension("GL_ARB_bindless_texture");
}
//==========================================================================
@ -247,9 +250,14 @@ void gl_PrintStartupLog()
}
}
void setGlVersion(double glv)
{
realglversion = glv;
}
std::pair<double, bool> gl_getInfo()
{
// gl_ARB_bindless_texture is the closest we can get to determine Vulkan support from OpenGL.
// This isn't foolproof because Intel doesn't support it but for NVidia and AMD support of this extension means Vulkan support.
return std::make_pair(realglversion, CheckExtension("GL_ARB_bindless_texture"));
return std::make_pair(realglversion, bindless);
}

View file

@ -369,6 +369,7 @@ void OpenGLFrameBuffer::WaitForCommands(bool finish)
void OpenGLFrameBuffer::BeginFrame()
{
SetViewportRects(nullptr);
mViewpoints->Clear();
if (GLRenderer != nullptr)
GLRenderer->BeginFrame();
}

View file

@ -22,6 +22,7 @@ public:
explicit OpenGLFrameBuffer() {}
OpenGLFrameBuffer(void *hMonitor, bool fullscreen) ;
~OpenGLFrameBuffer();
int Backend() override { return 0; }
void InitializeState() override;
void Update() override;

View file

@ -9,6 +9,7 @@ CVAR(Bool, gles_use_mapped_buffer, false, 0);
CVAR(Bool, gles_force_glsl_v100, false, 0);
CVAR(Int, gles_max_lights_per_surface, 32, 0);
EXTERN_CVAR(Bool, gl_customshader);
void setGlVersion(double glv);
#if USE_GLES2
@ -191,5 +192,9 @@ namespace OpenGLESRenderer
#endif
gles.numlightvectors = (gles.maxlights * LIGHT_VEC4_NUM);
const char* glversion = (const char*)glGetString(GL_VERSION);
setGlVersion( strtod(glversion, NULL));
}
}

View file

@ -117,11 +117,16 @@ int HWViewpointBuffer::SetViewpoint(FRenderState &di, HWViewpointUniforms *vp)
void HWViewpointBuffer::Clear()
{
bool needNewPipeline = mUploadIndex > 0; // Clear might be called multiple times before any actual rendering
mUploadIndex = 0;
mClipPlaneInfo.Clear();
mPipelinePos++;
mPipelinePos %= mPipelineNbr;
if (needNewPipeline)
{
mPipelinePos++;
mPipelinePos %= mPipelineNbr;
}
mBuffer = mBufferPipeline[mPipelinePos];
}

View file

@ -419,6 +419,7 @@ TArray<uint8_t> VulkanFrameBuffer::GetScreenshotBuffer(int &pitch, ESSType &colo
void VulkanFrameBuffer::BeginFrame()
{
SetViewportRects(nullptr);
mViewpoints->Clear();
mCommands->BeginFrame();
mTextureManager->BeginFrame();
mScreenBuffers->BeginFrame(screen->mScreenViewport.width, screen->mScreenViewport.height, screen->mSceneViewport.width, screen->mSceneViewport.height);

View file

@ -104,8 +104,8 @@ FCompileContext::FCompileContext(PNamespace *cg, PFunction *fnc, PPrototype *ret
if (fnc != nullptr) Class = fnc->OwningClass;
}
FCompileContext::FCompileContext(PNamespace *cg, PContainerType *cls, bool fromdecorate)
: ReturnProto(nullptr), Function(nullptr), Class(cls), FromDecorate(fromdecorate), StateIndex(-1), StateCount(0), Lump(-1), CurGlobals(cg)
FCompileContext::FCompileContext(PNamespace *cg, PContainerType *cls, bool fromdecorate, const VersionInfo& info)
: ReturnProto(nullptr), Function(nullptr), Class(cls), FromDecorate(fromdecorate), StateIndex(-1), StateCount(0), Lump(-1), CurGlobals(cg), Version(info)
{
}
@ -2678,13 +2678,26 @@ FxBinary::~FxBinary()
//
//==========================================================================
bool FxBinary::Promote(FCompileContext &ctx, bool forceint)
bool FxBinary::Promote(FCompileContext &ctx, bool forceint, bool shiftop)
{
// math operations of unsigned ints results in an unsigned int. (16 and 8 bit values never get here, they get promoted to regular ints elsewhere already.)
if (left->ValueType == TypeUInt32 && right->ValueType == TypeUInt32)
{
ValueType = TypeUInt32;
}
// If one side is an unsigned 32-bit int and the other side is a signed 32-bit int, the signed side is implicitly converted to unsigned,
else if (!ctx.FromDecorate && left->ValueType == TypeUInt32 && right->ValueType == TypeSInt32 && !shiftop && ctx.Version >= MakeVersion(4, 9, 0))
{
right = new FxIntCast(right, false, false, true);
right = right->Resolve(ctx);
ValueType = TypeUInt32;
}
else if (!ctx.FromDecorate && left->ValueType == TypeSInt32 && right->ValueType == TypeUInt32 && !shiftop && ctx.Version >= MakeVersion(4, 9, 0))
{
left = new FxIntCast(left, false, false, true);
left = left->Resolve(ctx);
ValueType = TypeUInt32;
}
else if (left->IsInteger() && right->IsInteger())
{
ValueType = TypeSInt32; // Addition and subtraction forces all integer-derived types to signed int.
@ -2728,6 +2741,15 @@ bool FxBinary::Promote(FCompileContext &ctx, bool forceint)
delete this;
return false;
}
// shift operators are different: The left operand defines the type and the right operand must always be made unsigned
if (shiftop)
{
ValueType = left->ValueType == TypeUInt32 ? TypeUInt32 : TypeSInt32;
right = new FxIntCast(right, false, false, true);
right = right->Resolve(ctx);
}
return true;
}
@ -3324,6 +3346,59 @@ FxExpression *FxCompareRel::Resolve(FCompileContext& ctx)
}
else if (left->IsNumeric() && right->IsNumeric())
{
if (left->IsInteger() && right->IsInteger())
{
if (ctx.Version >= MakeVersion(4, 9, 0))
{
// We need to do more checks here to catch problem cases.
if (left->ValueType == TypeUInt32 && right->ValueType == TypeSInt32)
{
if (left->isConstant() && !right->isConstant())
{
auto val = static_cast<FxConstant*>(left)->GetValue().GetUInt();
if (val > INT_MAX)
{
ScriptPosition.Message(MSG_WARNING, "Comparison of signed value with out of range unsigned constant");
}
}
else if (right->isConstant() && !left->isConstant())
{
auto val = static_cast<FxConstant*>(right)->GetValue().GetInt();
if (val < 0)
{
ScriptPosition.Message(MSG_WARNING, "Comparison of unsigned value with negative constant");
}
}
else if (!left->isConstant() && !right->isConstant())
{
ScriptPosition.Message(MSG_WARNING, "Comparison between signed and unsigned value");
}
}
else if (left->ValueType == TypeSInt32 && right->ValueType == TypeUInt32)
{
if (left->isConstant() && !right->isConstant())
{
auto val = static_cast<FxConstant*>(left)->GetValue().GetInt();
if (val < 0)
{
ScriptPosition.Message(MSG_WARNING, "Comparison of unsigned value with negative constant");
}
}
else if (right->isConstant() && !left->isConstant())
{
auto val = static_cast<FxConstant*>(right)->GetValue().GetUInt();
if (val > INT_MAX)
{
ScriptPosition.Message(MSG_WARNING, "Comparison of signed value with out of range unsigned constant");
}
}
else if (!left->isConstant() && !right->isConstant())
{
ScriptPosition.Message(MSG_WARNING, "Comparison between signed and unsigned value");
}
}
}
}
Promote(ctx);
}
else
@ -3929,7 +4004,7 @@ FxExpression *FxShift::Resolve(FCompileContext& ctx)
if (left->IsNumeric() && right->IsNumeric())
{
if (!Promote(ctx, true)) return nullptr;
if (!Promote(ctx, true, true)) return nullptr;
if ((left->ValueType == TypeUInt32 && ctx.Version >= MakeVersion(3, 7)) && Operator == TK_RShift) Operator = TK_URShift;
}
else
@ -8233,7 +8308,7 @@ FxExpression *FxMemberFunctionCall::Resolve(FCompileContext& ctx)
member->membervar = newfield;
Self = nullptr;
delete this;
member->ValueType = TypeUInt32;
member->ValueType = TypeSInt32;
return member;
}
else

View file

@ -93,7 +93,7 @@ struct FCompileContext
FString VersionString;
FCompileContext(PNamespace *spc, PFunction *func, PPrototype *ret, bool fromdecorate, int stateindex, int statecount, int lump, const VersionInfo &ver);
FCompileContext(PNamespace *spc, PContainerType *cls, bool fromdecorate); // only to be used to resolve constants!
FCompileContext(PNamespace *spc, PContainerType *cls, bool fromdecorate, const VersionInfo& ver); // only to be used to resolve constants!
PSymbol *FindInClass(FName identifier, PSymbolTable *&symt);
PSymbol *FindInSelfClass(FName identifier, PSymbolTable *&symt);
@ -910,7 +910,7 @@ public:
FxBinary(int, FxExpression*, FxExpression*);
~FxBinary();
bool Promote(FCompileContext &ctx, bool forceint = false);
bool Promote(FCompileContext &ctx, bool forceint = false, bool shiftop = false);
};
//==========================================================================

View file

@ -334,6 +334,7 @@ void PType::StaticInit()
TypeVector2->moveOp = OP_MOVEV2;
TypeVector2->RegType = REGT_FLOAT;
TypeVector2->RegCount = 2;
TypeVector2->isOrdered = true;
TypeVector3 = new PStruct(NAME_Vector3, nullptr);
TypeVector3->AddField(NAME_X, TypeFloat64);
@ -347,6 +348,7 @@ void PType::StaticInit()
TypeVector3->moveOp = OP_MOVEV3;
TypeVector3->RegType = REGT_FLOAT;
TypeVector3->RegCount = 3;
TypeVector3->isOrdered = true;
TypeFVector2 = new PStruct(NAME_FVector2, nullptr);
@ -358,6 +360,7 @@ void PType::StaticInit()
TypeFVector2->moveOp = OP_MOVEV2;
TypeFVector2->RegType = REGT_FLOAT;
TypeFVector2->RegCount = 2;
TypeFVector2->isOrdered = true;
TypeFVector3 = new PStruct(NAME_FVector3, nullptr);
TypeFVector3->AddField(NAME_X, TypeFloat32);
@ -371,6 +374,7 @@ void PType::StaticInit()
TypeFVector3->moveOp = OP_MOVEV3;
TypeFVector3->RegType = REGT_FLOAT;
TypeFVector3->RegCount = 3;
TypeFVector3->isOrdered = true;
Namespaces.GlobalNamespace->Symbols.AddSymbol(Create<PSymbolType>(NAME_sByte, TypeSInt8));
Namespaces.GlobalNamespace->Symbols.AddSymbol(Create<PSymbolType>(NAME_Byte, TypeUInt8));

View file

@ -537,6 +537,7 @@ public:
PStruct(FName name, PTypeBase *outer, bool isnative = false);
bool isNative;
bool isOrdered = false;
// Some internal structs require explicit construction and destruction of fields the VM cannot handle directly so use these two functions for it.
VMFunction *mConstructor = nullptr;
VMFunction *mDestructor = nullptr;

View file

@ -68,7 +68,7 @@ const char * ZCCCompiler::GetStringConst(FxExpression *ex, FCompileContext &ctx)
int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PContainerType *cls)
{
FCompileContext ctx(OutNamespace, cls, false);
FCompileContext ctx(OutNamespace, cls, false, mVersion);
FxExpression *ex = new FxIntCast(ConvertNode(node), false);
ex = ex->Resolve(ctx);
if (ex == nullptr) return 0;
@ -82,7 +82,7 @@ int ZCCCompiler::IntConstFromNode(ZCC_TreeNode *node, PContainerType *cls)
FString ZCCCompiler::StringConstFromNode(ZCC_TreeNode *node, PContainerType *cls)
{
FCompileContext ctx(OutNamespace, cls, false);
FCompileContext ctx(OutNamespace, cls, false, mVersion);
FxExpression *ex = new FxStringCast(ConvertNode(node));
ex = ex->Resolve(ctx);
if (ex == nullptr) return "";
@ -1144,7 +1144,7 @@ void ZCCCompiler::AddConstant(ZCC_ConstantWork &constant)
bool ZCCCompiler::CompileConstant(ZCC_ConstantWork *work)
{
FCompileContext ctx(OutNamespace, work->cls, false);
FCompileContext ctx(OutNamespace, work->cls, false, mVersion);
FxExpression *exp = ConvertNode(work->node->Value);
try
{
@ -1185,7 +1185,7 @@ void ZCCCompiler::CompileArrays(ZCC_StructWork *work)
ConvertNodeList(values, sas->Values);
bool fail = false;
FCompileContext ctx(OutNamespace, work->Type(), false);
FCompileContext ctx(OutNamespace, work->Type(), false, mVersion);
char *destmem = (char *)ClassDataAllocator.Alloc(values.Size() * ztype->Align);
memset(destmem, 0, values.Size() * ztype->Align);
@ -1325,7 +1325,7 @@ void ZCCCompiler::CompileAllFields()
{
// Create copies of the arrays which can be altered
auto Classes = this->Classes;
auto Structs = this->Structs;
auto Structs = OrderStructs();
TMap<FName, bool> HasNativeChildren;
// first step: Look for native classes with native children.
@ -1612,6 +1612,83 @@ bool ZCCCompiler::CompileFields(PContainerType *type, TArray<ZCC_VarDeclarator *
return Fields.Size() == 0;
}
//==========================================================================
//
// ZCCCompiler :: OrderStructs
//
// Order the Structs array so that the least-dependant structs come first
//
//==========================================================================
TArray<ZCC_StructWork *> ZCCCompiler::OrderStructs()
{
TArray<ZCC_StructWork *> new_order;
for (auto struct_def : Structs)
{
if (std::find(new_order.begin(), new_order.end(), struct_def) != new_order.end())
{
continue;
}
AddStruct(new_order, struct_def);
}
return new_order;
}
//==========================================================================
//
// ZCCCompiler :: AddStruct
//
// Adds a struct to the Structs array, preceded by all its dependant structs
//
//==========================================================================
void ZCCCompiler::AddStruct(TArray<ZCC_StructWork *> &new_order, ZCC_StructWork *my_def)
{
PStruct *my_type = static_cast<PStruct *>(my_def->Type());
if (my_type)
{
if (my_type->isOrdered)
{
return;
}
my_type->isOrdered = true;
}
// Find all struct fields and add them before this one
for (const auto field : my_def->Fields)
{
PType *fieldtype = DetermineType(my_type, field, field->Names->Name, field->Type, true, true);
if (fieldtype->isStruct() && !static_cast<PStruct *>(fieldtype)->isOrdered)
{
AddStruct(new_order, StructTypeToWork(static_cast<PStruct *>(fieldtype)));
}
}
new_order.Push(my_def);
}
//==========================================================================
//
// ZCCCompiler :: StructTypeToWork
//
// Find the ZCC_StructWork that corresponds to a PStruct
//
//==========================================================================
ZCC_StructWork *ZCCCompiler::StructTypeToWork(const PStruct *type) const
{
assert(type->isStruct());
for (auto &def : Structs)
{
if (def->Type() == type)
{
return def;
}
}
assert(false && "Struct not found");
return nullptr;
}
//==========================================================================
//
// ZCCCompiler :: FieldFlagsToString
@ -1937,7 +2014,7 @@ PType *ZCCCompiler::ResolveArraySize(PType *baseType, ZCC_Expression *arraysize,
indices = std::move(fixedIndices);
}
FCompileContext ctx(OutNamespace, cls, false);
FCompileContext ctx(OutNamespace, cls, false, mVersion);
for (auto index : indices)
{
// There is no float->int casting here.
@ -2270,7 +2347,7 @@ void ZCCCompiler::CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool
FxExpression *x = new FxTypeCast(ConvertNode(p->Default), type, false);
FCompileContext ctx(OutNamespace, c->Type(), false);
FCompileContext ctx(OutNamespace, c->Type(), false, mVersion);
x = x->Resolve(ctx);
if (x != nullptr)
@ -2731,7 +2808,14 @@ FxExpression *ZCCCompiler::ConvertNode(ZCC_TreeNode *ast, bool substitute)
}
else if (cnst->Type->isInt())
{
return new FxConstant(cnst->IntVal, *ast);
if (cnst->Type == TypeUInt32)
{
return new FxConstant((unsigned)cnst->IntVal, *ast);
}
else
{
return new FxConstant(cnst->IntVal, *ast);
}
}
else if (cnst->Type == TypeBool)
{

View file

@ -135,6 +135,9 @@ protected:
PType *DetermineType(PType *outertype, ZCC_TreeNode *field, FName name, ZCC_Type *ztype, bool allowarraytypes, bool formember);
PType *ResolveArraySize(PType *baseType, ZCC_Expression *arraysize, PContainerType *cls, bool *nosize);
PType *ResolveUserType(ZCC_BasicType *type, PSymbolTable *sym, bool nativetype);
TArray<ZCC_StructWork *> OrderStructs();
void AddStruct(TArray<ZCC_StructWork *> &new_order, ZCC_StructWork *struct_def);
ZCC_StructWork *StructTypeToWork(const PStruct *type) const;
void CompileFunction(ZCC_StructWork *c, ZCC_FuncDeclarator *f, bool forclass);

View file

@ -998,7 +998,7 @@ DEFINE_ACTION_FUNCTION(DOptionMenuItemCommand, DoCommand)
}
UnsafeExecutionScope scope(unsafe);
C_DoCommand(cmd);
AddCommandString(cmd);
return 0;
}

View file

@ -70,24 +70,27 @@ static walltype* IsOnWall(tspritetype* tspr, int height, DVector2& outpos)
// angle of the sprite must either be the wall's normal or the negative wall's normal to be aligned.
if (deltaang >= 512 - maxangdelta && deltaang <= 512 + maxangdelta)
{
// orthogonal lines do not check the actual position so that certain off-sector sprites get handled properly.
// In Wanton Destruction's airplane level there's such a sprite assigned to the wrong sector.
if (d.X == 0)
if (!((tspr->ang) & 510))
{
double newdist = fabs(tx - wal.pos.X);
if (newdist < maxorthdist)
// orthogonal lines do not check the actual position so that certain off-sector sprites get handled properly.
// In Wanton Destruction's airplane level there's such a sprite assigned to the wrong sector.
if (d.X == 0)
{
maxorthdist = newdist;
best = &wal;
double newdist = fabs(tx - wal.pos.X);
if (newdist < maxorthdist)
{
maxorthdist = newdist;
best = &wal;
}
}
}
else if (d.Y == 0)
{
double newdist = fabs(ty - wal.pos.Y);
if (newdist < maxorthdist)
else if (d.Y == 0)
{
maxorthdist = newdist;
best = &wal;
double newdist = fabs(ty - wal.pos.Y);
if (newdist < maxorthdist)
{
maxorthdist = newdist;
best = &wal;
}
}
}
else

View file

@ -49,7 +49,7 @@ const char *GetVersionString();
#define RC_PRODUCTVERSION2 VERSIONSTR
// These are for content versioning.
#define VER_MAJOR 4
#define VER_MINOR 7
#define VER_MINOR 9
#define VER_REVISION 0
#define ENG_MAJOR 1