diff --git a/specs/usdf.txt b/specs/usdf.txt index 1367ccfbf..093c9e7d7 100644 --- a/specs/usdf.txt +++ b/specs/usdf.txt @@ -87,14 +87,16 @@ conversation // Starts a dialog. page // Starts a new page. Pages are automatically numbered starting at 1. { - name = ; // Name that goes in the upper left hand corner - panel = ; // Name of lump to render as the background. - voice = ; // Narration sound lump. - dialog = ; // Dialog of the page. - drop = ; // mobj for the object to drop if the actor is - // killed. - link = ; // Page to jump to if all ifitem conditions are - // satisified. + name = ; // Name that goes in the upper left hand corner + panel = ; // Name of lump to render as the background. + voice = ; // Narration sound lump. + dialog = ; // Dialog of the page. + goodbye = ; // Custom goodbye message. If omitted then the + // generic goodbyes will be displayed instead. + drop = ; // mobj for the object to drop if the actor is + // killed. + link = ; // Page to jump to if all ifitem conditions are + // satisified. // jumps to the specified page if the player has the specified amount // or more of item in their inventory. This can be repeated as many diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index ff1772ec7..aef7996fe 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1235,6 +1235,7 @@ set (PCH_SOURCES p_3dfloors.cpp p_3dmidtex.cpp p_acs.cpp + p_actionfunctions.cpp p_buildmap.cpp p_ceiling.cpp p_conversation.cpp @@ -1373,7 +1374,6 @@ set (PCH_SOURCES textures/warptexture.cpp thingdef/olddecorations.cpp thingdef/thingdef.cpp - thingdef/thingdef_codeptr.cpp thingdef/thingdef_data.cpp thingdef/thingdef_exp.cpp thingdef/thingdef_expression.cpp diff --git a/src/d_dehacked.cpp b/src/d_dehacked.cpp index 9e068b596..dd71fdf75 100644 --- a/src/d_dehacked.cpp +++ b/src/d_dehacked.cpp @@ -2985,9 +2985,11 @@ static bool LoadDehSupp () void FinishDehPatch () { unsigned int touchedIndex; + unsigned int nameindex = 0; for (touchedIndex = 0; touchedIndex < TouchedActors.Size(); ++touchedIndex) { + PClassActor *subclass; PClassActor *type = TouchedActors[touchedIndex]; AActor *defaults1 = GetDefaultByType (type); if (!(defaults1->flags & MF_SPECIAL)) @@ -2997,9 +2999,16 @@ void FinishDehPatch () // Create a new class that will serve as the actual pickup char typeNameBuilder[32]; - mysnprintf (typeNameBuilder, countof(typeNameBuilder), "DehackedPickup%d", touchedIndex); - PClassActor *subclass = static_cast(RUNTIME_CLASS(ADehackedPickup)-> - CreateDerivedClass(typeNameBuilder, sizeof(ADehackedPickup))); + // + do + { + // Retry until we find a free name. This is unlikely to happen but not impossible. + mysnprintf(typeNameBuilder, countof(typeNameBuilder), "DehackedPickup%d", nameindex++); + subclass = static_cast(RUNTIME_CLASS(ADehackedPickup)-> + CreateDerivedClass(typeNameBuilder, sizeof(ADehackedPickup))); + } + while (subclass == nullptr); + AActor *defaults2 = GetDefaultByType (subclass); memcpy ((void *)defaults2, (void *)defaults1, sizeof(AActor)); diff --git a/src/dobject.h b/src/dobject.h index 51102bc4c..91a80f9d0 100644 --- a/src/dobject.h +++ b/src/dobject.h @@ -201,6 +201,7 @@ enum EObjectFlags OF_EuthanizeMe = 1 << 5, // Object wants to die OF_Cleanup = 1 << 6, // Object is now being deleted by the collector OF_YesReallyDelete = 1 << 7, // Object is being deleted outside the collector, and this is okay, so don't print a warning + OF_Transient = 1 << 11, // Object should not be archived (references to it will be nulled on disk) OF_WhiteBits = OF_White0 | OF_White1, OF_MarkBits = OF_WhiteBits | OF_Black, @@ -573,6 +574,9 @@ protected: } }; +// When you write to a pointer to an Object, you must call this for +// proper bookkeeping in case the Object holding this pointer has +// already been processed by the GC. static inline void GC::WriteBarrier(DObject *pointing, DObject *pointed) { if (pointed != NULL && pointed->IsWhite() && pointing->IsBlack()) diff --git a/src/dobjtype.cpp b/src/dobjtype.cpp index 9693da137..37ff26fe3 100644 --- a/src/dobjtype.cpp +++ b/src/dobjtype.cpp @@ -670,6 +670,20 @@ void PNamedType::GetTypeIDs(intptr_t &id1, intptr_t &id2) const id2 = TypeName; } +//========================================================================== +// +// PNamedType :: QualifiedName +// +//========================================================================== + +FString PNamedType::QualifiedName() const +{ + FString out; + if (Outer != nullptr) out = Outer->QualifiedName(); + out << "::" << TypeName; + return out; +} + /* PInt *******************************************************************/ IMPLEMENT_CLASS(PInt) @@ -1752,7 +1766,7 @@ PEnum::PEnum() // //========================================================================== -PEnum::PEnum(FName name, DObject *outer) +PEnum::PEnum(FName name, PTypeBase *outer) : PNamedType(name, outer), ValueType(NULL) { } @@ -1766,7 +1780,7 @@ PEnum::PEnum(FName name, DObject *outer) // //========================================================================== -PEnum *NewEnum(FName name, DObject *outer) +PEnum *NewEnum(FName name, PTypeBase *outer) { size_t bucket; PType *etype = TypeTable.FindType(RUNTIME_CLASS(PEnum), (intptr_t)outer, (intptr_t)name, &bucket); @@ -2149,7 +2163,7 @@ PStruct::PStruct() // //========================================================================== -PStruct::PStruct(FName name, DObject *outer) +PStruct::PStruct(FName name, PTypeBase *outer) : PNamedType(name, outer) { } @@ -2310,7 +2324,7 @@ size_t PStruct::PropagateMark() // //========================================================================== -PStruct *NewStruct(FName name, DObject *outer) +PStruct *NewStruct(FName name, PTypeBase *outer) { size_t bucket; PType *stype = TypeTable.FindType(RUNTIME_CLASS(PStruct), (intptr_t)outer, (intptr_t)name, &bucket); @@ -2847,10 +2861,7 @@ void PClass::InsertIntoHash () found = TypeTable.FindType(RUNTIME_CLASS(PClass), (intptr_t)Outer, TypeName, &bucket); if (found != NULL) { // This type has already been inserted - // ... but there is no need whatsoever to make it a fatal error! - if (!strictdecorate) Printf (TEXTCOLOR_RED"Tried to register class '%s' more than once.\n", TypeName.GetChars()); - else I_Error("Tried to register class '%s' more than once.\n", TypeName.GetChars()); - TypeTable.ReplaceType(this, found, bucket); + I_Error("Tried to register class '%s' more than once.\n", TypeName.GetChars()); } else { @@ -3015,15 +3026,23 @@ PClass *PClass::CreateDerivedClass(FName name, unsigned int size) PClass *existclass = static_cast(TypeTable.FindType(RUNTIME_CLASS(PClass), /*FIXME:Outer*/0, name, &bucket)); // This is a placeholder so fill it in - if (existclass != NULL && (existclass->Size == TentativeClass)) + if (existclass != nullptr) { - type = const_cast(existclass); - if (!IsDescendantOf(type->ParentClass)) + if (existclass->Size == TentativeClass) { - I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); + type = const_cast(existclass); + if (!IsDescendantOf(type->ParentClass)) + { + I_Error("%s must inherit from %s but doesn't.", name.GetChars(), type->ParentClass->TypeName.GetChars()); + } + DPrintf(DMSG_SPAMMY, "Defining placeholder class %s\n", name.GetChars()); + notnew = true; + } + else + { + // a different class with the same name already exists. Let the calling code deal with this. + return nullptr; } - DPrintf(DMSG_SPAMMY, "Defining placeholder class %s\n", name.GetChars()); - notnew = true; } else { @@ -3360,6 +3379,7 @@ CCMD(typetable) // Symbol tables ------------------------------------------------------------ +IMPLEMENT_ABSTRACT_CLASS(PTypeBase); IMPLEMENT_ABSTRACT_CLASS(PSymbol); IMPLEMENT_CLASS(PSymbolConst); IMPLEMENT_CLASS(PSymbolConstNumeric); diff --git a/src/dobjtype.h b/src/dobjtype.h index 62cfa6753..338c51f98 100644 --- a/src/dobjtype.h +++ b/src/dobjtype.h @@ -22,12 +22,28 @@ typedef std::pair FTypeAndOffset; // Symbol information ------------------------------------------------------- -class PSymbol : public DObject +class PTypeBase : public DObject { - DECLARE_ABSTRACT_CLASS(PSymbol, DObject); + DECLARE_ABSTRACT_CLASS(PTypeBase, DObject) + +public: + virtual FString QualifiedName() const + { + return ""; + } +}; + +class PSymbol : public PTypeBase +{ + DECLARE_ABSTRACT_CLASS(PSymbol, PTypeBase); public: virtual ~PSymbol(); + virtual FString QualifiedName() const + { + return SymbolName.GetChars(); + } + FName SymbolName; protected: @@ -153,13 +169,13 @@ extern PSymbolTable GlobalSymbols; struct ZCC_ExprConstant; class PClassType; -class PType : public DObject +class PType : public PTypeBase { //DECLARE_ABSTRACT_CLASS_WITH_META(PType, DObject, PClassType); // We need to unravel the _WITH_META macro, since PClassType isn't defined yet, // and we can't define it until we've defined PClass. But we can't define that // without defining PType. - DECLARE_ABSTRACT_CLASS(PType, DObject) + DECLARE_ABSTRACT_CLASS(PType, PTypeBase) HAS_OBJECT_POINTERS; protected: enum { MetaClassNum = CLASSREG_PClassType }; @@ -332,14 +348,15 @@ class PNamedType : public PCompoundType DECLARE_ABSTRACT_CLASS(PNamedType, PCompoundType); HAS_OBJECT_POINTERS; public: - DObject *Outer; // object this type is contained within + PTypeBase *Outer; // object this type is contained within FName TypeName; // this type's name PNamedType() : Outer(NULL) {} - PNamedType(FName name, DObject *outer) : Outer(outer), TypeName(name) {} + PNamedType(FName name, PTypeBase *outer) : Outer(outer), TypeName(name) {} virtual bool IsMatch(intptr_t id1, intptr_t id2) const; virtual void GetTypeIDs(intptr_t &id1, intptr_t &id2) const; + virtual FString QualifiedName() const; }; // Basic types -------------------------------------------------------------- @@ -533,7 +550,7 @@ class PEnum : public PNamedType DECLARE_CLASS(PEnum, PNamedType); HAS_OBJECT_POINTERS; public: - PEnum(FName name, DObject *outer); + PEnum(FName name, PTypeBase *outer); PType *ValueType; TMap Values; @@ -610,7 +627,7 @@ class PStruct : public PNamedType { DECLARE_CLASS(PStruct, PNamedType); public: - PStruct(FName name, DObject *outer); + PStruct(FName name, PTypeBase *outer); TArray Fields; @@ -822,8 +839,8 @@ PDynArray *NewDynArray(PType *type); PPointer *NewPointer(PType *type); PClassPointer *NewClassPointer(PClass *restrict); PClassWaitingForParent *NewUnknownClass(FName myname, FName parentname); -PEnum *NewEnum(FName name, DObject *outer); -PStruct *NewStruct(FName name, DObject *outer); +PEnum *NewEnum(FName name, PTypeBase *outer); +PStruct *NewStruct(FName name, PTypeBase *outer); PPrototype *NewPrototype(const TArray &rettypes, const TArray &argtypes); // Built-in types ----------------------------------------------------------- diff --git a/src/fragglescript/t_func.cpp b/src/fragglescript/t_func.cpp index a02ec947f..cc096ed60 100644 --- a/src/fragglescript/t_func.cpp +++ b/src/fragglescript/t_func.cpp @@ -497,7 +497,7 @@ DFsSection *FParser::looping_section() if(!best || (current->start_index > best->start_index)) best = current; // save it } - current = current->next; + current = current->next; } } diff --git a/src/g_game.cpp b/src/g_game.cpp index 629202ea5..48bda24f5 100644 --- a/src/g_game.cpp +++ b/src/g_game.cpp @@ -1999,7 +1999,7 @@ void G_DoLoadGame () { // delete the resource file if anything goes wrong in here. if (resfile != nullptr) delete resfile; - return; + throw; } } diff --git a/src/g_level.cpp b/src/g_level.cpp index 90b31138d..119cde378 100644 --- a/src/g_level.cpp +++ b/src/g_level.cpp @@ -1512,7 +1512,11 @@ void G_UnSnapshotLevel (bool hubLoad) if (level.info->isValid()) { FSerializer arc; - if (!arc.OpenReader(&level.info->Snapshot)) return; + if (!arc.OpenReader(&level.info->Snapshot)) + { + I_Error("Failed to load savegame"); + return; + } G_SerializeLevel (arc, hubLoad); level.FromSnapshot = true; diff --git a/src/gl/dynlights/gl_dynlight.cpp b/src/gl/dynlights/gl_dynlight.cpp index 3fffe3641..ae19ecf60 100644 --- a/src/gl/dynlights/gl_dynlight.cpp +++ b/src/gl/dynlights/gl_dynlight.cpp @@ -1081,6 +1081,7 @@ void gl_AttachLight(AActor *actor, unsigned int count, const FLightDefaults *lig light = Spawn(actor->Pos(), NO_REPLACE); light->target = actor; light->owned = true; + light->ObjectFlags |= OF_Transient; actor->dynamiclights.Push(light); } light->flags2&=~MF2_DORMANT; diff --git a/src/gl/models/gl_voxels.cpp b/src/gl/models/gl_voxels.cpp index 288b1a9db..6e84bd7ab 100644 --- a/src/gl/models/gl_voxels.cpp +++ b/src/gl/models/gl_voxels.cpp @@ -314,12 +314,12 @@ void FVoxelModel::MakeSlabPolys(int x, int y, kvxslab_t *voxptr, FVoxelMap &chec } if (cull & 4) { - AddFace(x, y, z, x+1, y, z, x, y, z+c, x+1, y, z+c, *col, check); + AddFace(x+1, y, z, x, y, z, x+1, y, z+c, x, y, z+c, *col, check); } if (cull & 8) { - AddFace(x+1, y+1, z, x, y+1, z, x+1, y+1, z+c, x, y+1, z+c, *col, check); - } + AddFace(x, y+1, z, x+1, y+1, z, x, y+1, z+c, x+1, y+1, z+c, *col, check); + } z+=c; col+=c; } diff --git a/src/gl/renderer/gl_renderbuffers.h b/src/gl/renderer/gl_renderbuffers.h index efa61f3e2..f2f7b7cb9 100644 --- a/src/gl/renderer/gl_renderbuffers.h +++ b/src/gl/renderer/gl_renderbuffers.h @@ -2,7 +2,6 @@ #define __GL_RENDERBUFFERS_H #include "gl/shaders/gl_shader.h" -#include "gl/renderer/gl_renderer.h" class FGLBloomTextureLevel { diff --git a/src/gl/renderer/gl_renderer.cpp b/src/gl/renderer/gl_renderer.cpp index 2895341cc..90687bcb7 100644 --- a/src/gl/renderer/gl_renderer.cpp +++ b/src/gl/renderer/gl_renderer.cpp @@ -106,6 +106,8 @@ FGLRenderer::FGLRenderer(OpenGLFrameBuffer *fb) mTonemapPalette = nullptr; mBuffers = nullptr; mPresentShader = nullptr; + mPresent3dCheckerShader = nullptr; + mPresent3dColumnShader = nullptr; mPresent3dRowShader = nullptr; mBloomExtractShader = nullptr; mBloomCombineShader = nullptr; @@ -148,6 +150,8 @@ void FGLRenderer::Initialize(int width, int height) mFXAAShader = new FFXAAShader; mFXAALumaShader = new FFXAALumaShader; mPresentShader = new FPresentShader(); + mPresent3dCheckerShader = new FPresent3DCheckerShader(); + mPresent3dColumnShader = new FPresent3DColumnShader(); mPresent3dRowShader = new FPresent3DRowShader(); m2DDrawer = new F2DDrawer; @@ -205,6 +209,8 @@ FGLRenderer::~FGLRenderer() if (mDepthBlurShader) delete mDepthBlurShader; if (mSSAOShader) delete mSSAOShader; if (mSSAOCombineShader) delete mSSAOCombineShader; + if (mPresent3dCheckerShader) delete mPresent3dCheckerShader; + if (mPresent3dColumnShader) delete mPresent3dColumnShader; if (mPresent3dRowShader) delete mPresent3dRowShader; if (mBloomExtractShader) delete mBloomExtractShader; if (mBloomCombineShader) delete mBloomCombineShader; diff --git a/src/gl/renderer/gl_renderer.h b/src/gl/renderer/gl_renderer.h index 264aa1d04..f709cedf4 100644 --- a/src/gl/renderer/gl_renderer.h +++ b/src/gl/renderer/gl_renderer.h @@ -35,6 +35,8 @@ class FLensShader; class FFXAALumaShader; class FFXAAShader; class FPresentShader; +class FPresent3DCheckerShader; +class FPresent3DColumnShader; class FPresent3DRowShader; class F2DDrawer; class FHardwareTexture; @@ -117,6 +119,8 @@ public: FFXAALumaShader *mFXAALumaShader; FFXAAShader *mFXAAShader; FPresentShader *mPresentShader; + FPresent3DCheckerShader *mPresent3dCheckerShader; + FPresent3DColumnShader *mPresent3dColumnShader; FPresent3DRowShader *mPresent3dRowShader; FTexture *gllight; diff --git a/src/gl/scene/gl_flats.cpp b/src/gl/scene/gl_flats.cpp index 394ca1626..c41e7664f 100644 --- a/src/gl/scene/gl_flats.cpp +++ b/src/gl/scene/gl_flats.cpp @@ -187,21 +187,18 @@ void GLFlat::DrawSubsector(subsector_t * sub) unsigned int vi[4]; vi[0] = 0; - for (unsigned int i = 1; i < sub->numlines-1; i += 2) + for (unsigned int i = 0; i < sub->numlines - 2; i += 2) { - if (i < sub->numlines - 3) + for (unsigned int j = 1; j < 4; j++) { - for (unsigned int j = 1; j < 4; j++) - { - vi[j] = MIN(i + j, sub->numlines - 1); - } - for (unsigned int x = 0; x < 4; x++) - { - vertex_t *vt = sub->firstline[vi[x]].v1; - qd.Set(x, vt->fX(), plane.plane.ZatPoint(vt) + dz, vt->fY(), vt->fX() / 64.f, -vt->fY() / 64.f); - } - qd.Render(GL_TRIANGLE_FAN); + vi[j] = MIN(i + j, sub->numlines - 1); } + for (unsigned int x = 0; x < 4; x++) + { + vertex_t *vt = sub->firstline[vi[x]].v1; + qd.Set(x, vt->fX(), plane.plane.ZatPoint(vt) + dz, vt->fY(), vt->fX() / 64.f, -vt->fY() / 64.f); + } + qd.Render(GL_TRIANGLE_FAN); } } diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index 13b210d91..13eb254ce 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -1230,7 +1230,6 @@ void FGLInterface::StateChanged(AActor *actor) void FGLInterface::StartSerialize(FSerializer &arc) { - gl_DeleteAllAttachedLights(); if (arc.BeginObject("glinfo")) { arc("fogdensity", fogdensity) @@ -1242,8 +1241,11 @@ void FGLInterface::StartSerialize(FSerializer &arc) void FGLInterface::EndSerialize(FSerializer &arc) { - gl_RecreateAllAttachedLights(); - if (arc.isReading()) gl_InitPortals(); + if (arc.isReading()) + { + gl_RecreateAllAttachedLights(); + gl_InitPortals(); + } } //=========================================================================== diff --git a/src/gl/scene/gl_sprite.cpp b/src/gl/scene/gl_sprite.cpp index ab88f2f9c..e9748fba6 100644 --- a/src/gl/scene/gl_sprite.cpp +++ b/src/gl/scene/gl_sprite.cpp @@ -138,10 +138,10 @@ void GLSprite::CalculateVertices(FVector3 *v) mat.Rotate(0, 1, 0, - actor->Angles.Roll.Degrees); mat.Translate(-x, -z, -y); } - v[0] = mat * FVector3(x1, z, y2); - v[1] = mat * FVector3(x2, z, y2); - v[2] = mat * FVector3(x1, z, y1); - v[3] = mat * FVector3(x2, z, y1); + v[0] = mat * FVector3(x2, z, y2); + v[1] = mat * FVector3(x1, z, y2); + v[2] = mat * FVector3(x2, z, y1); + v[3] = mat * FVector3(x1, z, y1); return; } diff --git a/src/gl/scene/gl_weapon.cpp b/src/gl/scene/gl_weapon.cpp index cfa5c05d7..a2a12f947 100644 --- a/src/gl/scene/gl_weapon.cpp +++ b/src/gl/scene/gl_weapon.cpp @@ -129,19 +129,20 @@ void FGLRenderer::DrawPSprite (player_t * player,DPSprite *psp, float sx, float y1 = viewwindowy + vh / 2 - (ftexturemid * scale); y2 = y1 + (r.height * scale) + 1; - if (!mirror) + if (!(mirror) != !(psp->Flags & PSPF_FLIP)) { - fU1=tex->GetSpriteUL(); - fV1=tex->GetSpriteVT(); - fU2=tex->GetSpriteUR(); - fV2=tex->GetSpriteVB(); + fU2 = tex->GetSpriteUL(); + fV1 = tex->GetSpriteVT(); + fU1 = tex->GetSpriteUR(); + fV2 = tex->GetSpriteVB(); } else { - fU2=tex->GetSpriteUL(); - fV1=tex->GetSpriteVT(); - fU1=tex->GetSpriteUR(); - fV2=tex->GetSpriteVB(); + fU1 = tex->GetSpriteUL(); + fV1 = tex->GetSpriteVT(); + fU2 = tex->GetSpriteUR(); + fV2 = tex->GetSpriteVB(); + } if (tex->GetTransparent() || OverrideShader != -1) diff --git a/src/gl/shaders/gl_present3dRowshader.cpp b/src/gl/shaders/gl_present3dRowshader.cpp index 607e4ede6..d8369a3b6 100644 --- a/src/gl/shaders/gl_present3dRowshader.cpp +++ b/src/gl/shaders/gl_present3dRowshader.cpp @@ -38,23 +38,37 @@ #include "gl/system/gl_cvars.h" #include "gl/shaders/gl_present3dRowshader.h" +void FPresentStereoShaderBase::Init(const char * vtx_shader_name, const char * program_name) +{ + FPresentShaderBase::Init(vtx_shader_name, program_name); + LeftEyeTexture.Init(mShader, "LeftEyeTexture"); + RightEyeTexture.Init(mShader, "RightEyeTexture"); + WindowPositionParity.Init(mShader, "WindowPositionParity"); +} + +void FPresent3DCheckerShader::Bind() +{ + if (!mShader) + { + Init("shaders/glsl/present_checker3d.fp", "shaders/glsl/presentChecker3d"); + } + mShader.Bind(); +} + +void FPresent3DColumnShader::Bind() +{ + if (!mShader) + { + Init("shaders/glsl/present_column3d.fp", "shaders/glsl/presentColumn3d"); + } + mShader.Bind(); +} + void FPresent3DRowShader::Bind() { if (!mShader) { - mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquadscale.vp", "", 330); - mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/present_row3d.fp", "", 330); - mShader.SetFragDataLocation(0, "FragColor"); - mShader.Link("shaders/glsl/presentRow3d"); - mShader.SetAttribLocation(0, "PositionInProjection"); - mShader.SetAttribLocation(1, "UV"); - LeftEyeTexture.Init(mShader, "LeftEyeTexture"); - RightEyeTexture.Init(mShader, "RightEyeTexture"); - InvGamma.Init(mShader, "InvGamma"); - Contrast.Init(mShader, "Contrast"); - Brightness.Init(mShader, "Brightness"); - Scale.Init(mShader, "UVScale"); - VerticalPixelOffset.Init(mShader, "VerticalPixelOffset"); + Init("shaders/glsl/present_row3d.fp", "shaders/glsl/presentRow3d"); } mShader.Bind(); } diff --git a/src/gl/shaders/gl_present3dRowshader.h b/src/gl/shaders/gl_present3dRowshader.h index 8e3bd772d..10419d7f5 100644 --- a/src/gl/shaders/gl_present3dRowshader.h +++ b/src/gl/shaders/gl_present3dRowshader.h @@ -29,22 +29,35 @@ #define GL_PRESENT3DROWSHADER_H_ #include "gl_shaderprogram.h" +#include "gl_presentshader.h" -class FPresent3DRowShader +class FPresentStereoShaderBase : public FPresentShaderBase { public: - void Bind(); - FBufferedUniformSampler LeftEyeTexture; FBufferedUniformSampler RightEyeTexture; - FBufferedUniform1f InvGamma; - FBufferedUniform1f Contrast; - FBufferedUniform1f Brightness; - FBufferedUniform2f Scale; - FBufferedUniform1i VerticalPixelOffset; + FBufferedUniform1i WindowPositionParity; -private: - FShaderProgram mShader; +protected: + void Init(const char * vtx_shader_name, const char * program_name) override; +}; + +class FPresent3DCheckerShader : public FPresentStereoShaderBase +{ +public: + void Bind() override; +}; + +class FPresent3DColumnShader : public FPresentStereoShaderBase +{ +public: + void Bind() override; +}; + +class FPresent3DRowShader : public FPresentStereoShaderBase +{ +public: + void Bind() override; }; // GL_PRESENT3DROWSHADER_H_ diff --git a/src/gl/shaders/gl_presentshader.cpp b/src/gl/shaders/gl_presentshader.cpp index 39d20d0fc..15acc74fb 100644 --- a/src/gl/shaders/gl_presentshader.cpp +++ b/src/gl/shaders/gl_presentshader.cpp @@ -36,21 +36,26 @@ #include "gl/system/gl_cvars.h" #include "gl/shaders/gl_presentshader.h" +void FPresentShaderBase::Init(const char * vtx_shader_name, const char * program_name) +{ + mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquadscale.vp", "", 330); + mShader.Compile(FShaderProgram::Fragment, vtx_shader_name, "", 330); + mShader.SetFragDataLocation(0, "FragColor"); + mShader.Link(program_name); + mShader.SetAttribLocation(0, "PositionInProjection"); + mShader.SetAttribLocation(1, "UV"); + InvGamma.Init(mShader, "InvGamma"); + Contrast.Init(mShader, "Contrast"); + Brightness.Init(mShader, "Brightness"); + Scale.Init(mShader, "UVScale"); +} + void FPresentShader::Bind() { if (!mShader) { - mShader.Compile(FShaderProgram::Vertex, "shaders/glsl/screenquadscale.vp", "", 330); - mShader.Compile(FShaderProgram::Fragment, "shaders/glsl/present.fp", "", 330); - mShader.SetFragDataLocation(0, "FragColor"); - mShader.Link("shaders/glsl/present"); - mShader.SetAttribLocation(0, "PositionInProjection"); - mShader.SetAttribLocation(1, "UV"); + Init("shaders/glsl/present.fp", "shaders/glsl/present"); InputTexture.Init(mShader, "InputTexture"); - InvGamma.Init(mShader, "InvGamma"); - Contrast.Init(mShader, "Contrast"); - Brightness.Init(mShader, "Brightness"); - Scale.Init(mShader, "UVScale"); } mShader.Bind(); } diff --git a/src/gl/shaders/gl_presentshader.h b/src/gl/shaders/gl_presentshader.h index 6f4e899bb..6f9e1bfd7 100644 --- a/src/gl/shaders/gl_presentshader.h +++ b/src/gl/shaders/gl_presentshader.h @@ -3,19 +3,27 @@ #include "gl_shaderprogram.h" -class FPresentShader +class FPresentShaderBase { public: - void Bind(); + virtual void Bind() = 0; - FBufferedUniformSampler InputTexture; FBufferedUniform1f InvGamma; FBufferedUniform1f Contrast; FBufferedUniform1f Brightness; FBufferedUniform2f Scale; -private: +protected: + virtual void Init(const char * vtx_shader_name, const char * program_name); FShaderProgram mShader; }; +class FPresentShader : public FPresentShaderBase +{ +public: + void Bind() override; + + FBufferedUniformSampler InputTexture; +}; + #endif \ No newline at end of file diff --git a/src/gl/stereo3d/gl_interleaved3d.cpp b/src/gl/stereo3d/gl_interleaved3d.cpp index 036a84b0b..029d233e4 100644 --- a/src/gl/stereo3d/gl_interleaved3d.cpp +++ b/src/gl/stereo3d/gl_interleaved3d.cpp @@ -43,10 +43,25 @@ EXTERN_CVAR(Float, vid_brightness) EXTERN_CVAR(Float, vid_contrast) EXTERN_CVAR(Bool, fullscreen) -EXTERN_CVAR(Int, win_y) // pixel position of top of display window +EXTERN_CVAR(Int, win_x) // screen pixel position of left of display window +EXTERN_CVAR(Int, win_y) // screen pixel position of top of display window namespace s3d { +/* static */ +const CheckerInterleaved3D& CheckerInterleaved3D::getInstance(float ipd) +{ + static CheckerInterleaved3D instance(ipd); + return instance; +} + +/* static */ +const ColumnInterleaved3D& ColumnInterleaved3D::getInstance(float ipd) +{ + static ColumnInterleaved3D instance(ipd); + return instance; +} + /* static */ const RowInterleaved3D& RowInterleaved3D::getInstance(float ipd) { @@ -54,11 +69,7 @@ const RowInterleaved3D& RowInterleaved3D::getInstance(float ipd) return instance; } -RowInterleaved3D::RowInterleaved3D(double ipdMeters) - : TopBottom3D(ipdMeters) -{} - -void RowInterleaved3D::Present() const +static void prepareInterleavedPresent(FPresentStereoShaderBase& shader) { GLRenderer->mBuffers->BindOutputFB(); GLRenderer->ClearBorders(); @@ -79,27 +90,102 @@ void RowInterleaved3D::Present() const const GL_IRECT& box = GLRenderer->mOutputLetterbox; glViewport(box.left, box.top, box.width, box.height); - bool applyGamma = true; + shader.Bind(); + shader.LeftEyeTexture.Set(0); + shader.RightEyeTexture.Set(1); - GLRenderer->mPresent3dRowShader->Bind(); - GLRenderer->mPresent3dRowShader->LeftEyeTexture.Set(0); - GLRenderer->mPresent3dRowShader->RightEyeTexture.Set(1); - - if (!applyGamma || GLRenderer->framebuffer->IsHWGammaActive()) + if ( GLRenderer->framebuffer->IsHWGammaActive() ) { - GLRenderer->mPresent3dRowShader->InvGamma.Set(1.0f); - GLRenderer->mPresent3dRowShader->Contrast.Set(1.0f); - GLRenderer->mPresent3dRowShader->Brightness.Set(0.0f); + shader.InvGamma.Set(1.0f); + shader.Contrast.Set(1.0f); + shader.Brightness.Set(0.0f); } else { - GLRenderer->mPresent3dRowShader->InvGamma.Set(1.0f / clamp(Gamma, 0.1f, 4.f)); - GLRenderer->mPresent3dRowShader->Contrast.Set(clamp(vid_contrast, 0.1f, 3.f)); - GLRenderer->mPresent3dRowShader->Brightness.Set(clamp(vid_brightness, -0.8f, 0.8f)); + shader.InvGamma.Set(1.0f / clamp(Gamma, 0.1f, 4.f)); + shader.Contrast.Set(clamp(vid_contrast, 0.1f, 3.f)); + shader.Brightness.Set(clamp(vid_brightness, -0.8f, 0.8f)); } - GLRenderer->mPresent3dRowShader->Scale.Set( + shader.Scale.Set( GLRenderer->mScreenViewport.width / (float)GLRenderer->mBuffers->GetWidth(), GLRenderer->mScreenViewport.height / (float)GLRenderer->mBuffers->GetHeight()); +} + +// fixme: I don't know how to get absolute window position on Mac and Linux +// fixme: I don't know how to get window border decoration size anywhere +// So for now I'll hard code the border effect on my test machine. +// Workaround for others is to fuss with vr_swap_eyes CVAR until it looks right. +// Presumably the top/left window border on my test machine has an odd number of pixels +// in the horizontal direction, and an even number in the vertical direction. +#define WINDOW_BORDER_HORIZONTAL_PARITY 1 +#define WINDOW_BORDER_VERTICAL_PARITY 0 + +void CheckerInterleaved3D::Present() const +{ + prepareInterleavedPresent(*GLRenderer->mPresent3dCheckerShader); + + // Compute absolute offset from top of screen to top of current display window + // because we need screen-relative, not window-relative, scan line parity + int windowVOffset = 0; + int windowHOffset = 0; + +#ifdef _WIN32 + if (!fullscreen) { + I_SaveWindowedPos(); // update win_y CVAR + windowHOffset = (win_x + WINDOW_BORDER_HORIZONTAL_PARITY) % 2; + windowVOffset = (win_y + WINDOW_BORDER_VERTICAL_PARITY) % 2; + } +#endif // _WIN32 + + GLRenderer->mPresent3dCheckerShader->WindowPositionParity.Set( + (windowVOffset + + windowHOffset + + GLRenderer->mOutputLetterbox.height + 1 // +1 because of origin at bottom + ) % 2 // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset + ); + + GLRenderer->RenderScreenQuad(); +} + +void s3d::CheckerInterleaved3D::AdjustViewports() const +{ + // decrease the total pixel count by 2, but keep the same aspect ratio + const float sqrt2 = 1.41421356237f; + // Change size of renderbuffer, and align to screen + GLRenderer->mSceneViewport.height /= sqrt2; + GLRenderer->mSceneViewport.top /= sqrt2; + GLRenderer->mSceneViewport.width /= sqrt2; + GLRenderer->mSceneViewport.left /= sqrt2; + + GLRenderer->mScreenViewport.height /= sqrt2; + GLRenderer->mScreenViewport.top /= sqrt2; + GLRenderer->mScreenViewport.width /= sqrt2; + GLRenderer->mScreenViewport.left /= sqrt2; +} + +void ColumnInterleaved3D::Present() const +{ + prepareInterleavedPresent(*GLRenderer->mPresent3dColumnShader); + + // Compute absolute offset from top of screen to top of current display window + // because we need screen-relative, not window-relative, scan line parity + int windowHOffset = 0; + +#ifdef _WIN32 + if (!fullscreen) { + I_SaveWindowedPos(); // update win_y CVAR + windowHOffset = (win_x + WINDOW_BORDER_HORIZONTAL_PARITY) % 2; + } +#endif // _WIN32 + + GLRenderer->mPresent3dColumnShader->WindowPositionParity.Set(windowHOffset); + + GLRenderer->RenderScreenQuad(); +} + +void RowInterleaved3D::Present() const +{ + prepareInterleavedPresent(*GLRenderer->mPresent3dRowShader); // Compute absolute offset from top of screen to top of current display window // because we need screen-relative, not window-relative, scan line parity @@ -108,13 +194,14 @@ void RowInterleaved3D::Present() const #ifdef _WIN32 if (! fullscreen) { I_SaveWindowedPos(); // update win_y CVAR - windowVOffset = win_y; + windowVOffset = (win_y + WINDOW_BORDER_VERTICAL_PARITY) % 2; } #endif // _WIN32 - GLRenderer->mPresent3dRowShader->VerticalPixelOffset.Set( - windowVOffset // fixme: vary with window location - + box.height % 2 // because we want the top pixel offset, but gl_FragCoord.y is the bottom pixel offset + GLRenderer->mPresent3dRowShader->WindowPositionParity.Set( + (windowVOffset + + GLRenderer->mOutputLetterbox.height + 1 // +1 because of origin at bottom + ) % 2 ); GLRenderer->RenderScreenQuad(); diff --git a/src/gl/stereo3d/gl_interleaved3d.h b/src/gl/stereo3d/gl_interleaved3d.h index 30aef7d5a..78bd19483 100644 --- a/src/gl/stereo3d/gl_interleaved3d.h +++ b/src/gl/stereo3d/gl_interleaved3d.h @@ -42,15 +42,30 @@ #include "gl/system/gl_system.h" #include "gl/renderer/gl_renderstate.h" -class FPresent3DRowShader; - namespace s3d { +class CheckerInterleaved3D : public SideBySideSquished +{ +public: + static const CheckerInterleaved3D& getInstance(float ipd); + CheckerInterleaved3D(double ipdMeters) : SideBySideSquished(ipdMeters) {} + void Present() const override; + void AdjustViewports() const override; +}; + +class ColumnInterleaved3D : public SideBySideSquished +{ +public: + static const ColumnInterleaved3D& getInstance(float ipd); + ColumnInterleaved3D(double ipdMeters) : SideBySideSquished(ipdMeters) {} + void Present() const override; +}; + class RowInterleaved3D : public TopBottom3D { public: static const RowInterleaved3D& getInstance(float ipd); - RowInterleaved3D(double ipdMeters); + RowInterleaved3D(double ipdMeters) : TopBottom3D(ipdMeters) {} void Present() const override; }; diff --git a/src/gl/stereo3d/gl_stereo_cvars.cpp b/src/gl/stereo3d/gl_stereo_cvars.cpp index 16296393d..fe5ae3261 100644 --- a/src/gl/stereo3d/gl_stereo_cvars.cpp +++ b/src/gl/stereo3d/gl_stereo_cvars.cpp @@ -107,6 +107,12 @@ const Stereo3DMode& Stereo3DMode::getCurrentMode() case 12: setCurrentMode(RowInterleaved3D::getInstance(vr_ipd)); break; + case 13: + setCurrentMode(ColumnInterleaved3D::getInstance(vr_ipd)); + break; + case 14: + setCurrentMode(CheckerInterleaved3D::getInstance(vr_ipd)); + break; case 0: default: setCurrentMode(MonoView::getInstance()); diff --git a/src/gl/textures/gl_hqresize.cpp b/src/gl/textures/gl_hqresize.cpp index fe523c79d..253d91f4b 100644 --- a/src/gl/textures/gl_hqresize.cpp +++ b/src/gl/textures/gl_hqresize.cpp @@ -46,6 +46,17 @@ #include "gl/xbr/xbrz.h" #include "gl/xbr/xbrz_old.h" +#ifdef __APPLE__ +# include +# if MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 +# define GZ_USE_LIBDISPATCH +# endif // MAC_OS_X_VERSION_MAX_ALLOWED >= 1060 +#endif // __APPLE__ + +#ifdef GZ_USE_LIBDISPATCH +# include +#endif // GZ_USE_LIBDISPATCH + CUSTOM_CVAR(Int, gl_texture_hqresize, 0, CVAR_ARCHIVE | CVAR_GLOBALCONFIG | CVAR_NOINITCALL) { if (self < 0 || self > 16) @@ -76,6 +87,22 @@ CVAR (Flag, gl_texture_hqresize_textures, gl_texture_hqresize_targets, 1); CVAR (Flag, gl_texture_hqresize_sprites, gl_texture_hqresize_targets, 2); CVAR (Flag, gl_texture_hqresize_fonts, gl_texture_hqresize_targets, 4); +#ifdef GZ_USE_LIBDISPATCH +CVAR(Bool, gl_texture_hqresize_multithread, true, CVAR_ARCHIVE | CVAR_GLOBALCONFIG); + +CUSTOM_CVAR(Int, gl_texture_hqresize_mt_width, 16, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < 2) self = 2; + if (self > 1024) self = 1024; +} + +CUSTOM_CVAR(Int, gl_texture_hqresize_mt_height, 4, CVAR_ARCHIVE | CVAR_GLOBALCONFIG) +{ + if (self < 2) self = 2; + if (self > 1024) self = 1024; +} +#endif // GZ_USE_LIBDISPATCH + static void scale2x ( uint32* inputBuffer, uint32* outputBuffer, int inWidth, int inHeight ) { @@ -261,26 +288,38 @@ static unsigned char *xbrzHelper( void (*xbrzFunction) ( size_t, const uint32_t* outHeight = N *inHeight; unsigned char * newBuffer = new unsigned char[outWidth*outHeight*4]; - xbrzFunction(N, reinterpret_cast(inputBuffer), reinterpret_cast(newBuffer), inWidth, inHeight, xbrz::ARGB, xbrz::ScalerCfg(), 0, std::numeric_limits::max()); + +#ifdef GZ_USE_LIBDISPATCH + const int thresholdWidth = gl_texture_hqresize_mt_width; + const int thresholdHeight = gl_texture_hqresize_mt_height; + + if (gl_texture_hqresize_multithread + && inWidth > thresholdWidth + && inHeight > thresholdHeight) + { + const dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); + + dispatch_apply(inHeight / thresholdHeight + 1, queue, ^(size_t sliceY) + { + xbrzFunction(N, reinterpret_cast(inputBuffer), reinterpret_cast(newBuffer), + inWidth, inHeight, xbrz::ARGB, xbrz::ScalerCfg(), sliceY * thresholdHeight, (sliceY + 1) * thresholdHeight); + }); + } + else +#endif // GZ_USE_LIBDISPATCH + { + xbrzFunction(N, reinterpret_cast(inputBuffer), reinterpret_cast(newBuffer), + inWidth, inHeight, xbrz::ARGB, xbrz::ScalerCfg(), 0, std::numeric_limits::max()); + } + delete[] inputBuffer; return newBuffer; } -static unsigned char *xbrzoldHelper( void (*xbrzFunction) ( size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, const xbrz_old::ScalerCfg& cfg, int yFirst, int yLast ), - const int N, - unsigned char *inputBuffer, - const int inWidth, - const int inHeight, - int &outWidth, - int &outHeight ) +static void xbrzOldScale(size_t factor, const uint32_t* src, uint32_t* trg, int srcWidth, int srcHeight, xbrz::ColorFormat colFmt, const xbrz::ScalerCfg& cfg, int yFirst, int yLast) { - outWidth = N * inWidth; - outHeight = N *inHeight; - - unsigned char * newBuffer = new unsigned char[outWidth*outHeight*4]; - xbrzFunction(N, reinterpret_cast(inputBuffer), reinterpret_cast(newBuffer), inWidth, inHeight, xbrz_old::ScalerCfg(), 0, std::numeric_limits::max()); - delete[] inputBuffer; - return newBuffer; + static_assert(sizeof(xbrz::ScalerCfg) == sizeof(xbrz_old::ScalerCfg), "ScalerCfg classes have different layout"); + xbrz_old::scale(factor, src, trg, srcWidth, srcHeight, reinterpret_cast(cfg), yFirst, yLast); } @@ -372,7 +411,7 @@ unsigned char *gl_CreateUpsampledTextureBuffer ( const FTexture *inputTexture, u case 13: case 14: case 15: - return xbrzoldHelper(xbrz_old::scale, type - 11, inputBuffer, inWidth, inHeight, outWidth, outHeight ); + return xbrzHelper(xbrzOldScale, type - 11, inputBuffer, inWidth, inHeight, outWidth, outHeight ); } } diff --git a/src/gl/textures/gl_texture.cpp b/src/gl/textures/gl_texture.cpp index ce6ff398c..8aaa98ae6 100644 --- a/src/gl/textures/gl_texture.cpp +++ b/src/gl/textures/gl_texture.cpp @@ -167,7 +167,7 @@ void gl_GenerateGlobalBrightmapFromColormap() // component becomes one. // //=========================================================================== -PalEntry averageColor(const DWORD *data, int size, int maxout) +static PalEntry averageColor(const DWORD *data, int size, int maxout) { int i; unsigned int r, g, b; @@ -216,10 +216,7 @@ FTexture::MiscGLInfo::MiscGLInfo() throw() GlowColor = 0; GlowHeight = 128; bSkybox = false; - FloorSkyColor = 0; - CeilingSkyColor = 0; bFullbright = false; - bSkyColorDone = false; bBrightmapChecked = false; bDisableFullbright = false; bNoFilter = false; @@ -326,38 +323,6 @@ void FTexture::GetGlowColor(float *data) data[2]=gl_info.GlowColor.b/255.0f; } -//=========================================================================== -// -// Gets the average color of a texture for use as a sky cap color -// -//=========================================================================== - -PalEntry FTexture::GetSkyCapColor(bool bottom) -{ - PalEntry col; - int w; - int h; - - if (!gl_info.bSkyColorDone) - { - gl_info.bSkyColorDone = true; - - unsigned char *buffer = GLRenderer->GetTextureBuffer(this, w, h); - - if (buffer) - { - gl_info.CeilingSkyColor = averageColor((DWORD *) buffer, w * MIN(30, h), 0); - if (h>30) - { - gl_info.FloorSkyColor = averageColor(((DWORD *) buffer)+(h-30)*w, w * 30, 0); - } - else gl_info.FloorSkyColor = gl_info.CeilingSkyColor; - delete[] buffer; - } - } - return bottom? gl_info.FloorSkyColor : gl_info.CeilingSkyColor; -} - //=========================================================================== // // Finds gaps in the texture which can be skipped by the renderer diff --git a/src/gl/textures/gl_texture.h b/src/gl/textures/gl_texture.h index 9ee9b27f9..455678f85 100644 --- a/src/gl/textures/gl_texture.h +++ b/src/gl/textures/gl_texture.h @@ -24,7 +24,6 @@ protected: void gl_GenerateGlobalBrightmapFromColormap(); -PalEntry averageColor(const DWORD *data, int size, int maxout); diff --git a/src/m_misc.cpp b/src/m_misc.cpp index 824fe0533..c49b342ce 100644 --- a/src/m_misc.cpp +++ b/src/m_misc.cpp @@ -123,7 +123,8 @@ int M_ReadFile (char const *name, BYTE **buffer) handle = open (name, O_RDONLY | O_BINARY, 0666); if (handle == -1) I_Error ("Couldn't read file %s", name); - if (fstat (handle,&fileinfo) == -1) + // [BL] Use stat instead of fstat for v140_xp hack + if (stat (name,&fileinfo) == -1) I_Error ("Couldn't read file %s", name); length = fileinfo.st_size; buf = new BYTE[length]; @@ -149,7 +150,8 @@ int M_ReadFileMalloc (char const *name, BYTE **buffer) handle = open (name, O_RDONLY | O_BINARY, 0666); if (handle == -1) I_Error ("Couldn't read file %s", name); - if (fstat (handle,&fileinfo) == -1) + // [BL] Use stat instead of fstat for v140_xp hack + if (stat (name,&fileinfo) == -1) I_Error ("Couldn't read file %s", name); length = fileinfo.st_size; buf = (BYTE*)M_Malloc(length); diff --git a/src/m_random.cpp b/src/m_random.cpp index e0a55d095..60ce12fd6 100644 --- a/src/m_random.cpp +++ b/src/m_random.cpp @@ -331,6 +331,10 @@ void FRandom::StaticReadRNGState(FSerializer &arc) FRandom *rng; arc("rngseed", rngseed); + + // Call StaticClearRandom in order to ensure that SFMT is initialized + FRandom::StaticClearRandom (); + if (arc.BeginArray("rngs")) { int count = arc.ArraySize(); diff --git a/src/namedef.h b/src/namedef.h index 36953e385..eab87c503 100644 --- a/src/namedef.h +++ b/src/namedef.h @@ -584,6 +584,7 @@ xx(Dialog) xx(Ifitem) xx(Choice) xx(Link) +xx(Goodbye) // Special menus xx(Mainmenu) diff --git a/src/p_acs.cpp b/src/p_acs.cpp index 0a2ccddac..fcbff904a 100644 --- a/src/p_acs.cpp +++ b/src/p_acs.cpp @@ -1616,7 +1616,7 @@ void FBehavior::StaticSerializeModuleStates (FSerializer &arc) { if (arc.isReading()) { - int modnum = arc.ArraySize(); + auto modnum = arc.ArraySize(); if (modnum != StaticModules.Size()) { I_Error("Level was saved with a different number of ACS modules. (Have %d, save has %d)", StaticModules.Size(), modnum); @@ -2933,7 +2933,7 @@ void DACSThinker::Serialize(FSerializer &arc) if (arc.BeginArray("runningscripts")) { auto cnt = arc.ArraySize(); - for (int i = 0; i < cnt; i++) + for (unsigned i = 0; i < cnt; i++) { SavingRunningscript srs; arc(nullptr, srs); @@ -5821,43 +5821,54 @@ doplaysound: if (funcIndex == ACSF_PlayActorSound) // [ZK] A_Warp in ACS case ACSF_Warp: { - int tid_dest = args[0]; - int xofs = args[1]; - int yofs = args[2]; - int zofs = args[3]; - int angle = args[4]; - int flags = args[5]; - const char *statename = argCount > 6 ? FBehavior::StaticLookupString(args[6]) : ""; - bool exact = argCount > 7 ? !!args[7] : false; - int heightoffset = argCount > 8 ? args[8] : 0; - int radiusoffset = argCount > 9 ? args[9] : 0; - int pitch = argCount > 10 ? args[10] : 0; - - FState *state = argCount > 6 ? activator->GetClass()->FindStateByString(statename, exact) : 0; - - AActor *reference; - if((flags & WARPF_USEPTR) && tid_dest != AAPTR_DEFAULT) + if (nullptr == activator) { - reference = COPY_AAPTR(activator, tid_dest); - } - else - { - reference = SingleActorFromTID(tid_dest, activator); - } - - // If there is no activator or actor to warp to, fail. - if (activator == NULL || !reference) return false; - - if (P_Thing_Warp(activator, reference, ACSToDouble(xofs), ACSToDouble(yofs), ACSToDouble(zofs), ACSToAngle(angle), flags, ACSToDouble(heightoffset), ACSToDouble(radiusoffset), ACSToAngle(pitch))) - { - if (state && argCount > 6) - { - activator->SetState(state); - } - return true; } - return false; + + const int dest = args[0]; + const int flags = args[5]; + + AActor* const reference = ((flags & WARPF_USEPTR) && (AAPTR_DEFAULT != dest)) + ? COPY_AAPTR(activator, dest) + : SingleActorFromTID(dest, activator); + + if (nullptr == reference) + { + // there is no actor to warp to + return false; + } + + const double xofs = ACSToDouble(args[1]); + const double yofs = ACSToDouble(args[2]); + const double zofs = ACSToDouble(args[3]); + const DAngle angle = ACSToAngle(args[4]); + const double heightoffset = argCount > 8 ? ACSToDouble(args[8]) : 0.0; + const double radiusoffset = argCount > 9 ? ACSToDouble(args[9]) : 0.0; + const DAngle pitch = ACSToAngle(argCount > 10 ? args[10] : 0); + + if (!P_Thing_Warp(activator, reference, xofs, yofs, zofs, angle, flags, heightoffset, radiusoffset, pitch)) + { + return false; + } + + if (argCount > 6) + { + const char* const statename = FBehavior::StaticLookupString(args[6]); + + if (nullptr != statename) + { + const bool exact = argCount > 7 && !!args[7]; + FState* const state = activator->GetClass()->FindStateByString(statename, exact); + + if (nullptr != state) + { + activator->SetState(state); + } + } + } + + return true; } case ACSF_GetMaxInventory: actor = SingleActorFromTID(args[0], activator); diff --git a/src/thingdef/thingdef_codeptr.cpp b/src/p_actionfunctions.cpp similarity index 99% rename from src/thingdef/thingdef_codeptr.cpp rename to src/p_actionfunctions.cpp index 3b4e6203e..c6bc8215b 100644 --- a/src/thingdef/thingdef_codeptr.cpp +++ b/src/p_actionfunctions.cpp @@ -2622,6 +2622,92 @@ DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_GiveToSiblings) ACTION_RETURN_INT(count); } +//=========================================================================== +// +// A_SetInventory +// +//=========================================================================== + +DEFINE_ACTION_FUNCTION_PARAMS(AActor, A_SetInventory) +{ + PARAM_ACTION_PROLOGUE; + PARAM_CLASS(itemtype, AInventory); + PARAM_INT(amount); + PARAM_INT_OPT(ptr) { ptr = AAPTR_DEFAULT; } + PARAM_BOOL_OPT(beyondMax) { beyondMax = false; } + + bool res = false; + + if (itemtype == nullptr) + { + ACTION_RETURN_BOOL(false); + } + + AActor *mobj = COPY_AAPTR(self, ptr); + + if (mobj == nullptr) + { + ACTION_RETURN_BOOL(false); + } + + AInventory *item = mobj->FindInventory(itemtype); + + if (item != nullptr) + { + // A_SetInventory sets the absolute amount. + // Subtract or set the appropriate amount as necessary. + + if (amount == item->Amount) + { + // Nothing was changed. + ACTION_RETURN_BOOL(false); + } + else if (amount <= 0) + { + //Remove it all. + res = (mobj->TakeInventory(itemtype, item->Amount, true, false)); + ACTION_RETURN_BOOL(res); + } + else if (amount < item->Amount) + { + int amt = abs(item->Amount - amount); + res = (mobj->TakeInventory(itemtype, amt, true, false)); + ACTION_RETURN_BOOL(res); + } + else + { + item->Amount = (beyondMax ? amount : clamp(amount, 0, item->MaxAmount)); + ACTION_RETURN_BOOL(true); + } + } + else + { + if (amount <= 0) + { + ACTION_RETURN_BOOL(false); + } + item = static_cast(Spawn(itemtype)); + if (item == nullptr) + { + ACTION_RETURN_BOOL(false); + } + else + { + item->Amount = amount; + item->flags |= MF_DROPPED; + item->ItemFlags |= IF_IGNORESKILL; + item->ClearCounters(); + if (!item->CallTryPickup(mobj)) + { + item->Destroy(); + ACTION_RETURN_BOOL(false); + } + ACTION_RETURN_BOOL(true); + } + } + ACTION_RETURN_BOOL(false); +} + //=========================================================================== // // A_TakeInventory diff --git a/src/p_ceiling.cpp b/src/p_ceiling.cpp index 32e5d62be..29b0c5095 100644 --- a/src/p_ceiling.cpp +++ b/src/p_ceiling.cpp @@ -184,7 +184,7 @@ void DCeiling::Tick () case DCeiling::ceilLowerAndCrush: if (m_CrushMode == ECrushMode::crushSlowdown) m_Speed = 1. / 8; - break; + break; default: break; @@ -214,6 +214,12 @@ DCeiling::DCeiling (sector_t *sec, double speed1, double speed2, int silent) m_Speed = m_Speed1 = speed1; m_Speed2 = speed2; m_Silent = silent; + m_BottomHeight = 0; + m_TopHeight = 0; + m_Direction = 0; + m_Texture = FNullTextureID(); + m_Tag = 0; + m_OldDirection = 0; } //============================================================================ diff --git a/src/p_conversation.cpp b/src/p_conversation.cpp index a697223e7..f216d9d78 100644 --- a/src/p_conversation.cpp +++ b/src/p_conversation.cpp @@ -556,6 +556,7 @@ FStrifeDialogueNode::~FStrifeDialogueNode () { if (SpeakerName != NULL) delete[] SpeakerName; if (Dialogue != NULL) delete[] Dialogue; + if (Goodbye != nullptr) delete[] Goodbye; FStrifeDialogueReply *tokill = Children; while (tokill != NULL) { @@ -743,10 +744,25 @@ public: ++i; V_FreeBrokenLines (ReplyLines); } - char goodbye[25]; - mysnprintf(goodbye, countof(goodbye), "TXT_RANDOMGOODBYE_%d", 1+(pr_randomspeech() % NUM_RANDOM_GOODBYES)); - const char *goodbyestr = GStrings[goodbye]; - if (goodbyestr == NULL) goodbyestr = "Bye."; + const char *goodbyestr = CurNode->Goodbye; + if (goodbyestr == nullptr) + { + char goodbye[25]; + mysnprintf(goodbye, countof(goodbye), "TXT_RANDOMGOODBYE_%d", 1 + (pr_randomspeech() % NUM_RANDOM_GOODBYES)); + goodbyestr = GStrings[goodbye]; + } + else if (strncmp(goodbyestr, "RANDOM_", 7) == 0) + { + FString byetext; + + byetext.Format("TXT_%s_%02d", goodbyestr, 1 + (pr_randomspeech() % NUM_RANDOM_LINES)); + goodbyestr = GStrings[byetext]; + } + else if (goodbyestr[0] == '$') + { + goodbyestr = GStrings(goodbyestr + 1); + } + if (goodbyestr == nullptr) goodbyestr = "Bye."; mResponses.Push(mResponseLines.Size()); mResponseLines.Push(FString(goodbyestr)); diff --git a/src/p_conversation.h b/src/p_conversation.h index d6ba65d78..5b068fb04 100644 --- a/src/p_conversation.h +++ b/src/p_conversation.h @@ -30,6 +30,7 @@ struct FStrifeDialogueNode FSoundID SpeakerVoice; FTextureID Backdrop; char *Dialogue; + char *Goodbye = nullptr; // must init to null for binary scripts to work as intended FStrifeDialogueReply *Children; }; diff --git a/src/p_mobj.cpp b/src/p_mobj.cpp index 496f52e86..8f926ea77 100644 --- a/src/p_mobj.cpp +++ b/src/p_mobj.cpp @@ -634,6 +634,7 @@ void AActor::RemoveInventory(AInventory *item) bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate, bool notakeinfinite) { + amount = abs(amount); AInventory *item = FindInventory(itemclass); if (item == NULL) @@ -666,6 +667,7 @@ bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate item->IsKindOf(RUNTIME_CLASS(AAmmo))) { // Nothing to do here, except maybe res = false;? Would it make sense? + result = false; } else if (!amount || amount>=item->Amount) { @@ -685,11 +687,30 @@ bool AActor::TakeInventory(PClassActor *itemclass, int amount, bool fromdecorate void AActor::DestroyAllInventory () { - while (Inventory != NULL) + AInventory *inv = Inventory; + if (inv != nullptr) { - AInventory *item = Inventory; - item->Destroy (); - assert (item != Inventory); + TArray toDelete; + + // Delete the list in a two stage approach. + // This is necessary because an item may destroy another item (e.g. sister weapons) + // which would break the list and leave parts of it undestroyed, maybe doing bad things later. + while (inv != nullptr) + { + toDelete.Push(inv); + AInventory *item = inv->Inventory; + inv->Inventory = nullptr; + inv->Owner = nullptr; + inv = item; + } + for (auto p : toDelete) + { + // the item may already have been deleted by another one, so check this here to avoid problems. + if (!(p->ObjectFlags & OF_EuthanizeMe)) + { + p->Destroy(); + } + } } } @@ -3778,6 +3799,8 @@ void AActor::Tick () else if (Z() <= floorz) { Crash(); + if (ObjectFlags & OF_EuthanizeMe) + return; // actor was destroyed } CheckPortalTransition(true); diff --git a/src/p_pspr.cpp b/src/p_pspr.cpp index fab7e38d8..e5b076acd 100644 --- a/src/p_pspr.cpp +++ b/src/p_pspr.cpp @@ -1006,7 +1006,7 @@ DEFINE_ACTION_FUNCTION(AActor, A_OverlayOffset) PARAM_FLOAT_OPT(wx) { wx = 0.; } PARAM_FLOAT_OPT(wy) { wy = 32.; } PARAM_INT_OPT(flags) { flags = 0; } - A_OverlayOffset(self, layer, wx, wy, flags); + A_OverlayOffset(self, ((layer != 0) ? layer : stateinfo->mPSPIndex), wx, wy, flags); return 0; } @@ -1033,10 +1033,10 @@ DEFINE_ACTION_FUNCTION(AActor, A_OverlayFlags) PARAM_INT(flags); PARAM_BOOL(set); - if (self->player == nullptr) + if (!ACTION_CALL_FROM_PSPRITE()) return 0; - DPSprite *pspr = self->player->FindPSprite(layer); + DPSprite *pspr = self->player->FindPSprite(((layer != 0) ? layer : stateinfo->mPSPIndex)); if (pspr == nullptr) return 0; @@ -1049,6 +1049,52 @@ DEFINE_ACTION_FUNCTION(AActor, A_OverlayFlags) return 0; } +//--------------------------------------------------------------------------- +// +// PROC OverlayX/Y +// Action function to return the X/Y of an overlay. +//--------------------------------------------------------------------------- + +static double GetOverlayPosition(AActor *self, int layer, bool gety) +{ + if (layer) + { + DPSprite *pspr = self->player->FindPSprite(layer); + + if (pspr != nullptr) + { + return gety ? (pspr->y) : (pspr->x); + } + } + return 0.; +} + +DEFINE_ACTION_FUNCTION(AActor, OverlayX) +{ + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(layer) { layer = 0; } + + if (ACTION_CALL_FROM_PSPRITE()) + { + double res = GetOverlayPosition(self, ((layer != 0) ? layer : stateinfo->mPSPIndex), false); + ACTION_RETURN_FLOAT(res); + } + ACTION_RETURN_FLOAT(0.); +} + +DEFINE_ACTION_FUNCTION(AActor, OverlayY) +{ + PARAM_ACTION_PROLOGUE; + PARAM_INT_OPT(layer) { layer = 0; } + + if (ACTION_CALL_FROM_PSPRITE()) + { + double res = GetOverlayPosition(self, ((layer != 0) ? layer : stateinfo->mPSPIndex), true); + ACTION_RETURN_FLOAT(res); + } + ACTION_RETURN_FLOAT(0.); +} + //--------------------------------------------------------------------------- // // PROC OverlayID diff --git a/src/p_pspr.h b/src/p_pspr.h index c0a695e04..084fe8fce 100644 --- a/src/p_pspr.h +++ b/src/p_pspr.h @@ -57,6 +57,7 @@ enum PSPFlags PSPF_ADDBOB = 1 << 1, PSPF_POWDOUBLE = 1 << 2, PSPF_CVARFAST = 1 << 3, + PSPF_FLIP = 1 << 6, }; class DPSprite : public DObject diff --git a/src/p_saveg.cpp b/src/p_saveg.cpp index 24e5ff9ee..ce5b6a74a 100644 --- a/src/p_saveg.cpp +++ b/src/p_saveg.cpp @@ -890,10 +890,10 @@ void G_SerializeLevel(FSerializer &arc, bool hubload) // deep down in the deserializer or just a crash if the few insufficient safeguards were not triggered. BYTE chk[16] = { 0 }; arc.Array("checksum", chk, 16); - if (arc.GetSize("linedefs") != numlines || - arc.GetSize("sidedefs") != numsides || - arc.GetSize("sectors") != numsectors || - arc.GetSize("polyobjs") != po_NumPolyobjs || + if (arc.GetSize("linedefs") != (unsigned)numlines || + arc.GetSize("sidedefs") != (unsigned)numsides || + arc.GetSize("sectors") != (unsigned)numsectors || + arc.GetSize("polyobjs") != (unsigned)po_NumPolyobjs || memcmp(chk, level.md5, 16)) { I_Error("Savegame is from a different level"); diff --git a/src/p_usdf.cpp b/src/p_usdf.cpp index 13a02b964..dccec7c21 100644 --- a/src/p_usdf.cpp +++ b/src/p_usdf.cpp @@ -286,6 +286,7 @@ class USDFParser : public UDMFParserBase FString SpeakerName; FString Dialogue; + FString Goodbye; while (!sc.CheckToken('}')) { @@ -331,7 +332,9 @@ class USDFParser : public UDMFParserBase node->ItemCheckNode = CheckInt(key); break; - + case NAME_Goodbye: + Goodbye = CheckString(key); + break; } } else @@ -354,6 +357,7 @@ class USDFParser : public UDMFParserBase } node->SpeakerName = ncopystring(SpeakerName); node->Dialogue = ncopystring(Dialogue); + node->Goodbye = ncopystring(Goodbye); return true; } diff --git a/src/po_man.cpp b/src/po_man.cpp index 2eed96596..c779a8049 100644 --- a/src/po_man.cpp +++ b/src/po_man.cpp @@ -265,7 +265,6 @@ void DMovePoly::Serialize(FSerializer &arc) { Super::Serialize (arc); arc("angle", m_Angle) - ("speed", m_Speed); ("speedv", m_Speedv); } diff --git a/src/posix/cocoa/i_main.mm b/src/posix/cocoa/i_main.mm index bbe344809..d8f0e74cf 100644 --- a/src/posix/cocoa/i_main.mm +++ b/src/posix/cocoa/i_main.mm @@ -130,6 +130,53 @@ void Mac_I_FatalError(const char* const message) } +static void I_DetectOS() +{ + SInt32 majorVersion = 0; + Gestalt(gestaltSystemVersionMajor, &majorVersion); + + SInt32 minorVersion = 0; + Gestalt(gestaltSystemVersionMinor, &minorVersion); + + SInt32 bugFixVersion = 0; + Gestalt(gestaltSystemVersionBugFix, &bugFixVersion); + + const char* name = "Unknown version"; + + if (10 == majorVersion) switch (minorVersion) + { + case 4: name = "Mac OS X Tiger"; break; + case 5: name = "Mac OS X Leopard"; break; + case 6: name = "Mac OS X Snow Leopard"; break; + case 7: name = "Mac OS X Lion"; break; + case 8: name = "OS X Mountain Lion"; break; + case 9: name = "OS X Mavericks"; break; + case 10: name = "OS X Yosemite"; break; + case 11: name = "OS X El Capitan"; break; + case 12: name = "macOS Sierra"; break; + } + + char release[16] = {}; + size_t size = sizeof release - 1; + sysctlbyname("kern.osversion", release, &size, nullptr, 0); + + const char* const architecture = +#ifdef __i386__ + "32-bit Intel"; +#elif defined __x86_64__ + "64-bit Intel"; +#elif defined __ppc__ + "32-bit PowerPC"; +#elif defined __ppc64__ + "64-bit PowerPC"; +#else + "Unknown"; +#endif + + Printf("OS: %s %d.%d.%d (%s) %s\n", name, majorVersion, minorVersion, bugFixVersion, release, architecture); +} + + DArgs* Args; // command line arguments @@ -165,6 +212,8 @@ void OriginalMainTry(int argc, char** argv) progdir += "/"; C_InitConsole(80 * 8, 25 * 8, false); + + I_DetectOS(); D_DoomMain(); } diff --git a/src/r_data/r_translate.cpp b/src/r_data/r_translate.cpp index 59dc00e32..fe8ff890a 100644 --- a/src/r_data/r_translate.cpp +++ b/src/r_data/r_translate.cpp @@ -1216,6 +1216,10 @@ int R_FindCustomTranslation(const char *name) { return TRANSLATION(TRANSLATION_Standard, 7); } + else if (!stricmp(name, "None")) + { + return 0; + } int *t = customTranslationMap.CheckKey(FName(name, true)); return (t != nullptr)? *t : -1; } diff --git a/src/r_draw.cpp b/src/r_draw.cpp index 80b91ed2d..5f592223b 100644 --- a/src/r_draw.cpp +++ b/src/r_draw.cpp @@ -110,6 +110,8 @@ DWORD vplce[4]; DWORD vince[4]; BYTE* palookupoffse[4]; const BYTE* bufplce[4]; +const BYTE* bufplce2[4]; +uint32_t bufheight[4]; // just for profiling int dccount; @@ -2142,6 +2144,245 @@ void tmvline4_revsubclamp () } while (--count); } +void R_DrawSingleSkyCol1(uint32_t solid_top, uint32_t solid_bottom) +{ + uint8_t *dest = dc_dest; + int count = dc_count; + int pitch = dc_pitch; + const uint8_t *source0 = bufplce[0]; + int textureheight0 = bufheight[0]; + + int32_t frac = vplce[0]; + int32_t fracstep = vince[0]; + + int start_fade = 2; // How fast it should fade out + + int solid_top_r = RPART(solid_top); + int solid_top_g = GPART(solid_top); + int solid_top_b = BPART(solid_top); + int solid_bottom_r = RPART(solid_bottom); + int solid_bottom_g = GPART(solid_bottom); + int solid_bottom_b = BPART(solid_bottom); + + for (int index = 0; index < count; index++) + { + uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; + uint8_t fg = source0[sample_index]; + + int alpha_top = MAX(MIN(frac >> (16 - start_fade), 256), 0); + int alpha_bottom = MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0); + + if (alpha_top == 256 && alpha_bottom == 256) + { + *dest = fg; + } + else + { + int inv_alpha_top = 256 - alpha_top; + int inv_alpha_bottom = 256 - alpha_bottom; + + const auto &c = GPalette.BaseColors[fg]; + int c_red = c.r; + int c_green = c.g; + int c_blue = c.b; + c_red = (c_red * alpha_top + solid_top_r * inv_alpha_top) >> 8; + c_green = (c_green * alpha_top + solid_top_g * inv_alpha_top) >> 8; + c_blue = (c_blue * alpha_top + solid_top_b * inv_alpha_top) >> 8; + c_red = (c_red * alpha_bottom + solid_bottom_r * inv_alpha_bottom) >> 8; + c_green = (c_green * alpha_bottom + solid_bottom_g * inv_alpha_bottom) >> 8; + c_blue = (c_blue * alpha_bottom + solid_bottom_b * inv_alpha_bottom) >> 8; + *dest = RGB32k.RGB[(c_red >> 3)][(c_green >> 3)][(c_blue >> 3)]; + } + + frac += fracstep; + dest += pitch; + } +} + +void R_DrawSingleSkyCol4(uint32_t solid_top, uint32_t solid_bottom) +{ + for (int col = 0; col < 4; col++) + { + uint8_t *dest = dc_dest + col; + int count = dc_count; + int pitch = dc_pitch; + const uint8_t *source0 = bufplce[col]; + int textureheight0 = bufheight[0]; + + int32_t frac = vplce[col]; + int32_t fracstep = vince[col]; + + int start_fade = 2; // How fast it should fade out + + int solid_top_r = RPART(solid_top); + int solid_top_g = GPART(solid_top); + int solid_top_b = BPART(solid_top); + int solid_bottom_r = RPART(solid_bottom); + int solid_bottom_g = GPART(solid_bottom); + int solid_bottom_b = BPART(solid_bottom); + + for (int index = 0; index < count; index++) + { + uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; + uint8_t fg = source0[sample_index]; + + int alpha_top = MAX(MIN(frac >> (16 - start_fade), 256), 0); + int alpha_bottom = MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0); + + if (alpha_top == 256 && alpha_bottom == 256) + { + *dest = fg; + } + else + { + int inv_alpha_top = 256 - alpha_top; + int inv_alpha_bottom = 256 - alpha_bottom; + + const auto &c = GPalette.BaseColors[fg]; + int c_red = c.r; + int c_green = c.g; + int c_blue = c.b; + c_red = (c_red * alpha_top + solid_top_r * inv_alpha_top) >> 8; + c_green = (c_green * alpha_top + solid_top_g * inv_alpha_top) >> 8; + c_blue = (c_blue * alpha_top + solid_top_b * inv_alpha_top) >> 8; + c_red = (c_red * alpha_bottom + solid_bottom_r * inv_alpha_bottom) >> 8; + c_green = (c_green * alpha_bottom + solid_bottom_g * inv_alpha_bottom) >> 8; + c_blue = (c_blue * alpha_bottom + solid_bottom_b * inv_alpha_bottom) >> 8; + *dest = RGB32k.RGB[(c_red >> 3)][(c_green >> 3)][(c_blue >> 3)]; + } + + frac += fracstep; + dest += pitch; + } + } +} + +void R_DrawDoubleSkyCol1(uint32_t solid_top, uint32_t solid_bottom) +{ + uint8_t *dest = dc_dest; + int count = dc_count; + int pitch = dc_pitch; + const uint8_t *source0 = bufplce[0]; + const uint8_t *source1 = bufplce2[0]; + int textureheight0 = bufheight[0]; + uint32_t maxtextureheight1 = bufheight[1] - 1; + + int32_t frac = vplce[0]; + int32_t fracstep = vince[0]; + + int start_fade = 2; // How fast it should fade out + + int solid_top_r = RPART(solid_top); + int solid_top_g = GPART(solid_top); + int solid_top_b = BPART(solid_top); + int solid_bottom_r = RPART(solid_bottom); + int solid_bottom_g = GPART(solid_bottom); + int solid_bottom_b = BPART(solid_bottom); + + for (int index = 0; index < count; index++) + { + uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; + uint8_t fg = source0[sample_index]; + if (fg == 0) + { + uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + fg = source1[sample_index2]; + } + + int alpha_top = MAX(MIN(frac >> (16 - start_fade), 256), 0); + int alpha_bottom = MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0); + + if (alpha_top == 256 && alpha_bottom == 256) + { + *dest = fg; + } + else + { + int inv_alpha_top = 256 - alpha_top; + int inv_alpha_bottom = 256 - alpha_bottom; + + const auto &c = GPalette.BaseColors[fg]; + int c_red = c.r; + int c_green = c.g; + int c_blue = c.b; + c_red = (c_red * alpha_top + solid_top_r * inv_alpha_top) >> 8; + c_green = (c_green * alpha_top + solid_top_g * inv_alpha_top) >> 8; + c_blue = (c_blue * alpha_top + solid_top_b * inv_alpha_top) >> 8; + c_red = (c_red * alpha_bottom + solid_bottom_r * inv_alpha_bottom) >> 8; + c_green = (c_green * alpha_bottom + solid_bottom_g * inv_alpha_bottom) >> 8; + c_blue = (c_blue * alpha_bottom + solid_bottom_b * inv_alpha_bottom) >> 8; + *dest = RGB32k.RGB[(c_red >> 3)][(c_green >> 3)][(c_blue >> 3)]; + } + + frac += fracstep; + dest += pitch; + } +} + +void R_DrawDoubleSkyCol4(uint32_t solid_top, uint32_t solid_bottom) +{ + for (int col = 0; col < 4; col++) + { + uint8_t *dest = dc_dest + col; + int count = dc_count; + int pitch = dc_pitch; + const uint8_t *source0 = bufplce[col]; + const uint8_t *source1 = bufplce2[col]; + int textureheight0 = bufheight[0]; + uint32_t maxtextureheight1 = bufheight[1] - 1; + + int32_t frac = vplce[col]; + int32_t fracstep = vince[col]; + + int start_fade = 2; // How fast it should fade out + + int solid_top_r = RPART(solid_top); + int solid_top_g = GPART(solid_top); + int solid_top_b = BPART(solid_top); + int solid_bottom_r = RPART(solid_bottom); + int solid_bottom_g = GPART(solid_bottom); + int solid_bottom_b = BPART(solid_bottom); + + for (int index = 0; index < count; index++) + { + uint32_t sample_index = (((((uint32_t)frac) << 8) >> FRACBITS) * textureheight0) >> FRACBITS; + uint8_t fg = source0[sample_index]; + if (fg == 0) + { + uint32_t sample_index2 = MIN(sample_index, maxtextureheight1); + fg = source1[sample_index2]; + } + + int alpha_top = MAX(MIN(frac >> (16 - start_fade), 256), 0); + int alpha_bottom = MAX(MIN(((2 << 24) - frac) >> (16 - start_fade), 256), 0); + + if (alpha_top == 256 && alpha_bottom == 256) + { + *dest = fg; + } + else + { + int inv_alpha_top = 256 - alpha_top; + int inv_alpha_bottom = 256 - alpha_bottom; + + const auto &c = GPalette.BaseColors[fg]; + int c_red = c.r; + int c_green = c.g; + int c_blue = c.b; + c_red = (c_red * alpha_top + solid_top_r * inv_alpha_top) >> 8; + c_green = (c_green * alpha_top + solid_top_g * inv_alpha_top) >> 8; + c_blue = (c_blue * alpha_top + solid_top_b * inv_alpha_top) >> 8; + c_red = (c_red * alpha_bottom + solid_bottom_r * inv_alpha_bottom) >> 8; + c_green = (c_green * alpha_bottom + solid_bottom_g * inv_alpha_bottom) >> 8; + c_blue = (c_blue * alpha_bottom + solid_bottom_b * inv_alpha_bottom) >> 8; + *dest = RGB32k.RGB[(c_red >> 3)][(c_green >> 3)][(c_blue >> 3)]; + } + + frac += fracstep; + dest += pitch; + } + } +} //========================================================================== // diff --git a/src/r_draw.h b/src/r_draw.h index cb2f68f33..c45700a21 100644 --- a/src/r_draw.h +++ b/src/r_draw.h @@ -51,6 +51,8 @@ extern "C" DWORD vplce[4]; extern "C" DWORD vince[4]; extern "C" BYTE* palookupoffse[4]; extern "C" const BYTE* bufplce[4]; +extern "C" const BYTE* bufplce2[4]; +extern "C" uint32_t bufheight[4]; // [RH] Temporary buffer for column drawing extern "C" BYTE *dc_temp; @@ -293,4 +295,9 @@ void maskwallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_ // transmaskwallscan is like maskwallscan, but it can also blend to the background void transmaskwallscan (int x1, int x2, short *uwal, short *dwal, float *swal, fixed_t *lwal, double yrepeat, const BYTE *(*getcol)(FTexture *tex, int col)=R_GetColumn); +void R_DrawSingleSkyCol1(uint32_t solid_top, uint32_t solid_bottom); +void R_DrawSingleSkyCol4(uint32_t solid_top, uint32_t solid_bottom); +void R_DrawDoubleSkyCol1(uint32_t solid_top, uint32_t solid_bottom); +void R_DrawDoubleSkyCol4(uint32_t solid_top, uint32_t solid_bottom); + #endif diff --git a/src/r_plane.cpp b/src/r_plane.cpp index ff23492ab..07efb84b4 100644 --- a/src/r_plane.cpp +++ b/src/r_plane.cpp @@ -63,6 +63,8 @@ #pragma warning(disable:4244) #endif +EXTERN_CVAR(Int, r_skymode) + //EXTERN_CVAR (Int, tx) //EXTERN_CVAR (Int, ty) @@ -898,8 +900,171 @@ static const BYTE *R_GetTwoSkyColumns (FTexture *fronttex, int x) return composite; } +static void R_DrawSkyColumnStripe(int start_x, int y1, int y2, int columns, double scale, double texturemid, double yrepeat) +{ + uint32_t height = frontskytex->GetHeight(); + + for (int i = 0; i < columns; i++) + { + double uv_stepd = skyiscale * yrepeat; + double v = (texturemid + uv_stepd * (y1 - CenterY + 0.5)) / height; + double v_step = uv_stepd / height; + + uint32_t uv_pos = (uint32_t)(v * 0x01000000); + uint32_t uv_step = (uint32_t)(v_step * 0x01000000); + + int x = start_x + i; + if (MirrorFlags & RF_XFLIP) + x = (viewwidth - x); + + DWORD ang, angle1, angle2; + + ang = (skyangle + xtoviewangle[x]) ^ skyflip; + angle1 = (DWORD)((UMulScale16(ang, frontcyl) + frontpos) >> FRACBITS); + angle2 = (DWORD)((UMulScale16(ang, backcyl) + backpos) >> FRACBITS); + + bufplce[i] = (const BYTE *)frontskytex->GetColumn(angle1, nullptr); + bufplce2[i] = backskytex ? (const BYTE *)backskytex->GetColumn(angle2, nullptr) : nullptr; + + vince[i] = uv_step; + vplce[i] = uv_pos; + } + + bufheight[0] = height; + bufheight[1] = backskytex ? backskytex->GetHeight() : height; + dc_dest = (ylookup[y1] + start_x) + dc_destorg; + dc_count = y2 - y1; + + uint32_t solid_top = frontskytex->GetSkyCapColor(false); + uint32_t solid_bottom = frontskytex->GetSkyCapColor(true); + + if (columns == 4) + if (!backskytex) + R_DrawSingleSkyCol4(solid_top, solid_bottom); + else + R_DrawDoubleSkyCol4(solid_top, solid_bottom); + else + if (!backskytex) + R_DrawSingleSkyCol1(solid_top, solid_bottom); + else + R_DrawDoubleSkyCol1(solid_top, solid_bottom); +} + +static void R_DrawSkyColumn(int start_x, int y1, int y2, int columns) +{ + if (1 << frontskytex->HeightBits == frontskytex->GetHeight()) + { + double texturemid = skymid * frontskytex->Scale.Y + frontskytex->GetHeight(); + R_DrawSkyColumnStripe(start_x, y1, y2, columns, frontskytex->Scale.Y, texturemid, frontskytex->Scale.Y); + } + else + { + double yrepeat = frontskytex->Scale.Y; + double scale = frontskytex->Scale.Y * skyscale; + double iscale = 1 / scale; + short drawheight = short(frontskytex->GetHeight() * scale); + double topfrac = fmod(skymid + iscale * (1 - CenterY), frontskytex->GetHeight()); + if (topfrac < 0) topfrac += frontskytex->GetHeight(); + double texturemid = topfrac - iscale * (1 - CenterY); + R_DrawSkyColumnStripe(start_x, y1, y2, columns, scale, texturemid, yrepeat); + } +} + +static void R_DrawCapSky(visplane_t *pl) +{ + int x1 = pl->left; + int x2 = pl->right; + short *uwal = (short *)pl->top; + short *dwal = (short *)pl->bottom; + + // Calculate where 4 column alignment begins and ends: + int aligned_x1 = clamp((x1 + 3) / 4 * 4, x1, x2); + int aligned_x2 = clamp(x2 / 4 * 4, x1, x2); + + // First unaligned columns: + for (int x = x1; x < aligned_x1; x++) + { + int y1 = uwal[x]; + int y2 = dwal[x]; + if (y2 <= y1) + continue; + + R_DrawSkyColumn(x, y1, y2, 1); + } + + // The aligned columns + for (int x = aligned_x1; x < aligned_x2; x += 4) + { + // Find y1, y2, light and uv values for four columns: + int y1[4] = { uwal[x], uwal[x + 1], uwal[x + 2], uwal[x + 3] }; + int y2[4] = { dwal[x], dwal[x + 1], dwal[x + 2], dwal[x + 3] }; + + // Figure out where we vertically can start and stop drawing 4 columns in one go + int middle_y1 = y1[0]; + int middle_y2 = y2[0]; + for (int i = 1; i < 4; i++) + { + middle_y1 = MAX(y1[i], middle_y1); + middle_y2 = MIN(y2[i], middle_y2); + } + + // If we got an empty column in our set we cannot draw 4 columns in one go: + bool empty_column_in_set = false; + for (int i = 0; i < 4; i++) + { + if (y2[i] <= y1[i]) + empty_column_in_set = true; + } + if (empty_column_in_set || middle_y2 <= middle_y1) + { + for (int i = 0; i < 4; i++) + { + if (y2[i] <= y1[i]) + continue; + + R_DrawSkyColumn(x + i, y1[i], y2[i], 1); + } + continue; + } + + // Draw the first rows where not all 4 columns are active + for (int i = 0; i < 4; i++) + { + if (y1[i] < middle_y1) + R_DrawSkyColumn(x + i, y1[i], middle_y1, 1); + } + + // Draw the area where all 4 columns are active + R_DrawSkyColumn(x, middle_y1, middle_y2, 4); + + // Draw the last rows where not all 4 columns are active + for (int i = 0; i < 4; i++) + { + if (middle_y2 < y2[i]) + R_DrawSkyColumn(x + i, middle_y2, y2[i], 1); + } + } + + // The last unaligned columns: + for (int x = aligned_x2; x < x2; x++) + { + int y1 = uwal[x]; + int y2 = dwal[x]; + if (y2 <= y1) + continue; + + R_DrawSkyColumn(x, y1, y2, 1); + } +} + static void R_DrawSky (visplane_t *pl) { + if (r_skymode == 2) + { + R_DrawCapSky(pl); + return; + } + int x; float swal; @@ -1314,7 +1479,7 @@ void R_DrawPortals () vissprite_p = firstvissprite; visplaneStack.Pop (pl); - if (pl->Alpha > 0) + if (pl->Alpha > 0 && pl->picnum != skyflatnum) { R_DrawSinglePlane (pl, pl->Alpha, pl->Additive, true); } diff --git a/src/r_sky.cpp b/src/r_sky.cpp index 9ea44db48..37312cbae 100644 --- a/src/r_sky.cpp +++ b/src/r_sky.cpp @@ -48,12 +48,19 @@ bool skystretch; fixed_t sky1cyl, sky2cyl; double sky1pos, sky2pos; +CUSTOM_CVAR(Int, testskyoffset, 0, 0) +{ + R_InitSkyMap(); +} + // [RH] Stretch sky texture if not taller than 128 pixels? -CUSTOM_CVAR (Bool, r_stretchsky, true, CVAR_ARCHIVE) +// Also now controls capped skies. 0 = normal, 1 = stretched, 2 = capped +CUSTOM_CVAR (Int, r_skymode, 2, CVAR_ARCHIVE) { R_InitSkyMap (); } + int freelookviewheight; //========================================================================== @@ -99,7 +106,7 @@ void R_InitSkyMap () skytexturemid = 0; if (skyheight >= 128 && skyheight < 200) { - skystretch = (r_stretchsky + skystretch = (r_skymode == 1 && skyheight >= 128 && level.IsFreelookAllowed() && !(level.flags & LEVEL_FORCENOSKYSTRETCH)) ? 1 : 0; @@ -107,7 +114,7 @@ void R_InitSkyMap () } else if (skyheight > 200) { - skytexturemid = (200 - skyheight) * skytex1->Scale.Y; + skytexturemid = (200 - skyheight) * skytex1->Scale.Y +(r_skymode == 2 ? skytex1->SkyOffset + testskyoffset : 0); } if (viewwidth != 0 && viewheight != 0) diff --git a/src/r_things.cpp b/src/r_things.cpp index a45a6826a..99ca68b60 100644 --- a/src/r_things.cpp +++ b/src/r_things.cpp @@ -408,7 +408,7 @@ void R_DrawVisSprite (vissprite_t *vis) ESPSResult mode; bool ispsprite = (!vis->sector && vis->gpos != FVector3(0, 0, 0)); - if (vis->xscale == 0 || vis->yscale == 0) + if (vis->xscale == 0 || fabs(vis->yscale) < (1.0f / 32000.0f)) { // scaled to 0; can't see return; } @@ -1404,7 +1404,7 @@ void R_DrawPSprite(DPSprite *pspr, AActor *owner, float bobx, float boby, double vis->pic = tex; vis->ColormapNum = 0; - if (flip) + if (!(flip) != !(pspr->Flags & PSPF_FLIP)) { vis->xiscale = -FLOAT2FIXED(pspritexiscale * tex->Scale.X); vis->startfrac = (tex->GetWidth() << FRACBITS) - 1; @@ -2097,7 +2097,7 @@ void R_DrawSprite (vissprite_t *spr) { // seen below floor: clip top if (!spr->bIsVoxel && h > topclip) { - topclip = MIN (h, viewheight); + topclip = short(MIN(h, viewheight)); } hzt = MIN(hzt, hz); } @@ -2127,7 +2127,7 @@ void R_DrawSprite (vissprite_t *spr) { // seen in the middle: clip top if (!spr->bIsVoxel && h > topclip) { - topclip = MIN (h, viewheight); + topclip = MIN(h, viewheight); } hzt = MIN(hzt, hz); } @@ -2181,7 +2181,7 @@ void R_DrawSprite (vissprite_t *spr) int h = xs_RoundToInt(CenterY - (hz - ViewPos.Z) * scale); if (h > topclip) { - topclip = MIN(h, viewheight); + topclip = short(MIN(h, viewheight)); } } hzt = MIN(hzt, sclipTop); @@ -2204,7 +2204,7 @@ void R_DrawSprite (vissprite_t *spr) h = (centeryfrac - FixedMul (h-viewz, scale)) >> FRACBITS; if (h > topclip) { - topclip = MIN (h, viewheight); + topclip = short(MIN(h, viewheight)); } } #endif diff --git a/src/resourcefiles/file_zip.cpp b/src/resourcefiles/file_zip.cpp index 73193062c..8713fe554 100644 --- a/src/resourcefiles/file_zip.cpp +++ b/src/resourcefiles/file_zip.cpp @@ -392,7 +392,8 @@ int FZipLump::FillCache() int FZipLump::GetFileOffset() { if (Method != METHOD_STORED) return -1; - if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); return Position; + if (Flags & LUMPFZIP_NEEDFILESTART) SetLumpAddress(); + return Position; } //========================================================================== diff --git a/src/s_sndseq.cpp b/src/s_sndseq.cpp index 23837c28b..3b39965ff 100644 --- a/src/s_sndseq.cpp +++ b/src/s_sndseq.cpp @@ -442,7 +442,7 @@ IMPLEMENT_CLASS (DSeqPolyNode) void DSeqPolyNode::Serialize(FSerializer &arc) { Super::Serialize (arc); - //arc << m_Poly; + arc("poly", m_Poly); } IMPLEMENT_CLASS (DSeqSectorNode) diff --git a/src/serializer.cpp b/src/serializer.cpp index 7861701c0..49226ce80 100644 --- a/src/serializer.cpp +++ b/src/serializer.cpp @@ -381,7 +381,7 @@ void FSerializer::Close() // //========================================================================== -int FSerializer::ArraySize() +unsigned FSerializer::ArraySize() { if (r != nullptr && r->mObjects.Last().mObject->IsArray()) { @@ -709,7 +709,7 @@ FSerializer &FSerializer::Sprite(const char *key, int32_t &spritenum, int32_t *d { if (val->IsString()) { - int name = *reinterpret_cast(val->GetString()); + uint32_t name = *reinterpret_cast(val->GetString()); for (auto hint = NumStdSprites; hint-- != 0; ) { if (sprites[hint].dwName == name) @@ -1451,7 +1451,7 @@ FSerializer &Serialize(FSerializer &arc, const char *key, DObject *&value, DObje { ndx = -1; } - else if (value->ObjectFlags & OF_EuthanizeMe) + else if (value->ObjectFlags & (OF_EuthanizeMe | OF_Transient)) { return arc; } diff --git a/src/serializer.h b/src/serializer.h index a3e1f531e..4797a4bce 100644 --- a/src/serializer.h +++ b/src/serializer.h @@ -60,7 +60,7 @@ public: FWriter *w = nullptr; FReader *r = nullptr; - int ArraySize(); + unsigned ArraySize(); void WriteKey(const char *key); void WriteObjects(); diff --git a/src/sound/music_hmi_midiout.cpp b/src/sound/music_hmi_midiout.cpp index 21790784c..691970765 100644 --- a/src/sound/music_hmi_midiout.cpp +++ b/src/sound/music_hmi_midiout.cpp @@ -145,8 +145,8 @@ HMISong::HMISong (FileReader &reader, EMidiDevice type, const char *args) MusHeader = new BYTE[len]; SongLen = len; NumTracks = 0; - if (reader.Read(MusHeader, len) != len) - return; + if (reader.Read(MusHeader, len) != len) + return; // Do some validation of the MIDI file if (memcmp(MusHeader, HMI_SONG_MAGIC, sizeof(HMI_SONG_MAGIC)) == 0) @@ -657,7 +657,7 @@ DWORD *HMISong::SendCommand (DWORD *events, TrackInfo *track, DWORD delay, ptrdi if (event == MIDI_SYSEX || event == MIDI_SYSEXEND) { len = ReadVarLen(track); - if (len >= (MAX_EVENTS-1)*3*4) + if (len >= (MAX_EVENTS-1)*3*4 || DeviceType == MDEV_SNDSYS) { // This message will never fit. Throw it away. track->TrackP += len; } diff --git a/src/sound/music_smf_midiout.cpp b/src/sound/music_smf_midiout.cpp index ffcbc9f62..ae0c47e80 100644 --- a/src/sound/music_smf_midiout.cpp +++ b/src/sound/music_smf_midiout.cpp @@ -114,10 +114,10 @@ MIDISong2::MIDISong2 (FileReader &reader, EMidiDevice type, const char *args) return; } #endif - SongLen = reader.GetLength(); + SongLen = reader.GetLength(); MusHeader = new BYTE[SongLen]; - if (reader.Read(MusHeader, SongLen) != SongLen) - return; + if (reader.Read(MusHeader, SongLen) != SongLen) + return; // Do some validation of the MIDI file if (MusHeader[4] != 0 || MusHeader[5] != 0 || MusHeader[6] != 0 || MusHeader[7] != 6) @@ -598,7 +598,7 @@ DWORD *MIDISong2::SendCommand (DWORD *events, TrackInfo *track, DWORD delay, ptr if (event == MIDI_SYSEX || event == MIDI_SYSEXEND) { len = track->ReadVarLen(); - if (len >= (MAX_EVENTS-1)*3*4) + if (len >= (MAX_EVENTS-1)*3*4 || DeviceType == MDEV_SNDSYS) { // This message will never fit. Throw it away. track->TrackP += len; } diff --git a/src/sound/music_xmi_midiout.cpp b/src/sound/music_xmi_midiout.cpp index a9cbcd2c6..c9a2e9c46 100644 --- a/src/sound/music_xmi_midiout.cpp +++ b/src/sound/music_xmi_midiout.cpp @@ -117,10 +117,10 @@ XMISong::XMISong (FileReader &reader, EMidiDevice type, const char *args) return; } #endif - SongLen = reader.GetLength(); + SongLen = reader.GetLength(); MusHeader = new BYTE[SongLen]; - if (reader.Read(MusHeader, SongLen) != SongLen) - return; + if (reader.Read(MusHeader, SongLen) != SongLen) + return; // Find all the songs in this file. NumSongs = FindXMIDforms(MusHeader, SongLen, NULL); @@ -528,7 +528,7 @@ DWORD *XMISong::SendCommand (DWORD *events, EventSource due, DWORD delay, ptrdif if (event == MIDI_SYSEX || event == MIDI_SYSEXEND) { len = track->ReadVarLen(); - if (len >= (MAX_EVENTS-1)*3*4) + if (len >= (MAX_EVENTS-1)*3*4 || DeviceType == MDEV_SNDSYS) { // This message will never fit. Throw it away. track->EventP += len; } diff --git a/src/textures/animations.cpp b/src/textures/animations.cpp index 74f9b1f55..f46289f07 100644 --- a/src/textures/animations.cpp +++ b/src/textures/animations.cpp @@ -161,6 +161,16 @@ FAnimDef *FTextureManager::AddComplexAnim (FTextureID picnum, const TArray entries, terminated by a 0xFF byte. Each entry +// is 23 bytes long and consists of the following fields: +// Byte 0: Bit 1 set for wall texture, clear for flat texture. +// Bytes 1-9: '\0'-terminated name of first texture. +// Bytes 10-18: '\0'-terminated name of last texture. +// Bytes 19-22: Tics per frame (stored in little endian order). +// //========================================================================== CVAR(Bool, debuganimated, false, 0) diff --git a/src/textures/texture.cpp b/src/textures/texture.cpp index 7b90c295f..bc0eaffa3 100644 --- a/src/textures/texture.cpp +++ b/src/textures/texture.cpp @@ -45,6 +45,7 @@ #include "v_video.h" #include "m_fixed.h" #include "textures/textures.h" +#include "v_palette.h" typedef bool (*CheckFunc)(FileReader & file); typedef FTexture * (*CreateFunc)(FileReader & file, int lumpnum); @@ -569,6 +570,78 @@ void FTexture::SetScaledSize(int fitwidth, int fitheight) if (int(Scale.Y * fitheight) != Height) Scale.Y += (1 / 65536.); } +//=========================================================================== +// +// Gets the average color of a texture for use as a sky cap color +// +//=========================================================================== + +namespace +{ + PalEntry averageColor(const DWORD *data, int size, int maxout) + { + int i; + unsigned int r, g, b; + + // First clear them. + r = g = b = 0; + if (size == 0) + { + return PalEntry(255, 255, 255); + } + for (i = 0; i < size; i++) + { + b += BPART(data[i]); + g += GPART(data[i]); + r += RPART(data[i]); + } + + r = r / size; + g = g / size; + b = b / size; + + int maxv = MAX(MAX(r, g), b); + + if (maxv && maxout) + { + r = Scale(r, maxout, maxv); + g = Scale(g, maxout, maxv); + b = Scale(b, maxout, maxv); + } + return PalEntry(255, r, g, b); + } +} + +PalEntry FTexture::GetSkyCapColor(bool bottom) +{ + PalEntry col; + int w; + int h; + + if (!bSWSkyColorDone) + { + bSWSkyColorDone = true; + + FBitmap bitmap; + bitmap.Create(GetWidth(), GetHeight()); + CopyTrueColorPixels(&bitmap, 0, 0); + int w = GetWidth(); + int h = GetHeight(); + + const uint32_t *buffer = (const uint32_t *)bitmap.GetPixels(); + if (buffer) + { + CeilingSkyColor = averageColor((DWORD *)buffer, w * MIN(30, h), 0); + if (h>30) + { + FloorSkyColor = averageColor(((DWORD *)buffer) + (h - 30)*w, w * 30, 0); + } + else FloorSkyColor = CeilingSkyColor; + } + } + return bottom ? FloorSkyColor : CeilingSkyColor; +} + FDummyTexture::FDummyTexture () { diff --git a/src/textures/textures.h b/src/textures/textures.h index 477c39ecc..cc5bba389 100644 --- a/src/textures/textures.h +++ b/src/textures/textures.h @@ -262,6 +262,7 @@ public: } void SetScaledSize(int fitwidth, int fitheight); + PalEntry GetSkyCapColor(bool bottom); virtual void HackHack (int newheight); // called by FMultipatchTexture to discover corrupt patches. @@ -285,6 +286,11 @@ protected: gl_info.areas = NULL; } +private: + bool bSWSkyColorDone = false; + PalEntry FloorSkyColor; + PalEntry CeilingSkyColor; + public: static void FlipSquareBlock (BYTE *block, int x, int y); static void FlipSquareBlockRemap (BYTE *block, int x, int y, const BYTE *remap); @@ -301,8 +307,6 @@ public: FGLTexture *SystemTexture[2]; FTexture *Brightmap; PalEntry GlowColor; - PalEntry FloorSkyColor; - PalEntry CeilingSkyColor; int GlowHeight; FloatRect *areas; int areacount; @@ -312,7 +316,6 @@ public: bool bGlowing:1; // Texture glows bool bFullbright:1; // always draw fullbright bool bSkybox:1; // This is a skybox - bool bSkyColorDone:1; // Fill color for sky char bBrightmapChecked:1; // Set to 1 if brightmap has been checked bool bDisableFullbright:1; // This texture will not be displayed as fullbright sprite bool bNoFilter:1; @@ -325,7 +328,6 @@ public: MiscGLInfo gl_info; void GetGlowColor(float *data); - PalEntry GetSkyCapColor(bool bottom); bool isGlowing() { return gl_info.bGlowing; } bool isFullbright() { return gl_info.bFullbright; } void CreateDefaultBrightmap(); diff --git a/src/thingdef/olddecorations.cpp b/src/thingdef/olddecorations.cpp index 3ea0c4788..9afbfc965 100644 --- a/src/thingdef/olddecorations.cpp +++ b/src/thingdef/olddecorations.cpp @@ -140,6 +140,7 @@ DEFINE_CLASS_PROPERTY(respawns, 0, FakeInventory) // Reads an old style decoration object // //========================================================================== +PClassActor *DecoDerivedClass(const FScriptPosition &sc, PClassActor *parent, FName typeName); void ParseOldDecoration(FScanner &sc, EDefinitionType def) { @@ -154,7 +155,7 @@ void ParseOldDecoration(FScanner &sc, EDefinitionType def) sc.MustGetString(); typeName = FName(sc.String); - type = static_cast(parent->CreateDerivedClass (typeName, parent->Size)); + type = DecoDerivedClass(FScriptPosition(sc), parent, typeName); ResetBaggage(&bag, parent); bag.Info = type; #ifdef _DEBUG diff --git a/src/thingdef/thingdef.cpp b/src/thingdef/thingdef.cpp index 32d4f1ce0..9af031b04 100644 --- a/src/thingdef/thingdef.cpp +++ b/src/thingdef/thingdef.cpp @@ -68,13 +68,44 @@ TDeletingArray ActorDamageFuncs; + // EXTERNAL FUNCTION PROTOTYPES -------------------------------------------- void InitThingdef(); -void ParseDecorate (FScanner &sc); +void ParseDecorate(FScanner &ctx); // STATIC FUNCTION PROTOTYPES -------------------------------------------- PClassActor *QuestItemClasses[31]; +EXTERN_CVAR(Bool, strictdecorate); + +PClassActor *DecoDerivedClass(const FScriptPosition &sc, PClassActor *parent, FName typeName) +{ + PClassActor *type = static_cast(parent->CreateDerivedClass(typeName, parent->Size)); + if (type == nullptr) + { + FString newname = typeName.GetChars(); + FString sourcefile = sc.FileName; + + sourcefile.Substitute(":", "@"); + newname << '@' << sourcefile; + if (strictdecorate) + { + sc.Message(MSG_ERROR, "Tried to define class '%s' more than once.", typeName.GetChars()); + } + else + { + // Due to backwards compatibility issues this cannot be an unconditional error. + sc.Message(MSG_WARNING, "Tried to define class '%s' more than once. Renaming class to '%s'", typeName.GetChars(), newname.GetChars()); + } + type = static_cast(parent->CreateDerivedClass(newname, parent->Size)); + if (type == nullptr) + { + // This we cannot handle cleanly anymore. Let's just abort and forget about the odd mod out that was this careless. + sc.Message(MSG_FATAL, "Tried to define class '%s' more than twice in the same file.", typeName.GetChars()); + } + } + return type; +} //========================================================================== // // Starts a new actor definition @@ -141,7 +172,7 @@ PClassActor *CreateNewActor(const FScriptPosition &sc, FName typeName, FName par else { create: - ti = static_cast(parent->CreateDerivedClass (typeName, parent->Size)); + ti = DecoDerivedClass(sc, parent, typeName); } ti->Replacee = ti->Replacement = NULL; @@ -428,6 +459,16 @@ void LoadActors () while ((lump = Wads.FindLump ("DECORATE", &lastlump)) != -1) { FScanner sc(lump); + + if (Wads.GetLumpFile(lump) == 0) + { + // define namespace 'zdoom' + } + else + { + // use namespace 'zdoom' + } + ParseDecorate (sc); } FinishThingdef(); @@ -439,32 +480,3 @@ void LoadActors () if (!batchrun) Printf("DECORATE parsing took %.2f ms\n", timer.TimeMS()); // Base time: ~52 ms } - - -//========================================================================== -// -// CreateDamageFunction -// -// Creates a damage function suitable for a constant, non-expressioned -// value. -// -//========================================================================== - -VMScriptFunction *CreateDamageFunction(int dmg) -{ - if (dmg == 0) - { - // For zero damage, do not create a function so that the special collision detection case still works as before. - return NULL; - } - else - { - VMFunctionBuilder build; - build.Registers[REGT_POINTER].Get(1); // The self pointer - build.EmitRetInt(0, false, dmg); - build.EmitRetInt(1, true, 0); - VMScriptFunction *sfunc = build.MakeFunction(); - sfunc->NumArgs = 1; - return sfunc; - } -} diff --git a/src/thingdef/thingdef.h b/src/thingdef/thingdef.h index 3a419b112..565da573a 100644 --- a/src/thingdef/thingdef.h +++ b/src/thingdef/thingdef.h @@ -164,14 +164,6 @@ inline void ResetBaggage (Baggage *bag, PClassActor *stateclass) bag->statedef.MakeStateDefines(stateclass); } -//========================================================================== -// -// Damage function creation -// -//========================================================================== - -VMScriptFunction *CreateDamageFunction(int dmg); - //========================================================================== // // Action function lookup diff --git a/src/thingdef/thingdef_expression.cpp b/src/thingdef/thingdef_expression.cpp index 700ac94bb..7c55e5286 100644 --- a/src/thingdef/thingdef_expression.cpp +++ b/src/thingdef/thingdef_expression.cpp @@ -91,7 +91,7 @@ static const FLOP FxFlops[] = // //========================================================================== -FCompileContext::FCompileContext(PClassActor *cls, PPrototype *ret) : Class(cls), ReturnProto(ret) +FCompileContext::FCompileContext(PClassActor *cls, PPrototype *ret) : ReturnProto(ret), Class(cls) { } @@ -959,7 +959,7 @@ ExpEmit FxUnaryNotBoolean::Emit(VMFunctionBuilder *build) //========================================================================== FxPreIncrDecr::FxPreIncrDecr(FxExpression *base, int token) -: FxExpression(base->ScriptPosition), Base(base), Token(token) +: FxExpression(base->ScriptPosition), Token(token), Base(base) { AddressRequested = false; AddressWritable = false; @@ -1045,7 +1045,7 @@ ExpEmit FxPreIncrDecr::Emit(VMFunctionBuilder *build) //========================================================================== FxPostIncrDecr::FxPostIncrDecr(FxExpression *base, int token) -: FxExpression(base->ScriptPosition), Base(base), Token(token) +: FxExpression(base->ScriptPosition), Token(token), Base(base) { } @@ -4956,6 +4956,25 @@ FxExpression *FxRuntimeStateIndex::Resolve(FCompileContext &ctx) return this; } +static bool VerifyJumpTarget(AActor *stateowner, FStateParamInfo *stateinfo, int index) +{ + PClassActor *cls = stateowner->GetClass(); + + while (cls != RUNTIME_CLASS(AActor)) + { + // both calling and target state need to belong to the same class. + if (cls->OwnsState(stateinfo->mCallingState)) + { + return cls->OwnsState(stateinfo->mCallingState + index); + } + + // We can safely assume the ParentClass is of type PClassActor + // since we stop when we see the Actor base class. + cls = static_cast(cls->ParentClass); + } + return false; +} + static int DecoHandleRuntimeState(VMFrameStack *stack, VMValue *param, int numparam, VMReturn *ret, int numret) { PARAM_PROLOGUE; @@ -4963,7 +4982,7 @@ static int DecoHandleRuntimeState(VMFrameStack *stack, VMValue *param, int numpa PARAM_POINTER(stateinfo, FStateParamInfo); PARAM_INT(index); - if (index == 0 || !stateowner->GetClass()->OwnsState(stateinfo->mCallingState + index)) + if (index == 0 || !VerifyJumpTarget(stateowner, stateinfo, index)) { // Null is returned if the location was invalid which means that no jump will be performed // if used as return value diff --git a/src/thingdef/thingdef_properties.cpp b/src/thingdef/thingdef_properties.cpp index d60cda823..80ee6c22f 100644 --- a/src/thingdef/thingdef_properties.cpp +++ b/src/thingdef/thingdef_properties.cpp @@ -1435,7 +1435,7 @@ DEFINE_PROPERTY(spriterotation, F, Actor) //========================================================================== // //========================================================================== -DEFINE_PROPERTY(visibleangles, Ff, Actor) +DEFINE_PROPERTY(visibleangles, FF, Actor) { PROP_DOUBLE_PARM(visstart, 0); PROP_DOUBLE_PARM(visend, 1); @@ -1446,7 +1446,7 @@ DEFINE_PROPERTY(visibleangles, Ff, Actor) //========================================================================== // //========================================================================== -DEFINE_PROPERTY(visiblepitch, Ff, Actor) +DEFINE_PROPERTY(visiblepitch, FF, Actor) { PROP_DOUBLE_PARM(visstart, 0); PROP_DOUBLE_PARM(visend, 1); diff --git a/src/v_blend.cpp b/src/v_blend.cpp index e1552105f..c13ed547c 100644 --- a/src/v_blend.cpp +++ b/src/v_blend.cpp @@ -52,7 +52,8 @@ #include "v_palette.h" #include "d_player.h" - +CVAR( Float, blood_fade_scalar, 1.0f, CVAR_ARCHIVE ) // [SP] Pulled from Skulltag - changed default from 0.5 to 1.0 +CVAR( Float, pickup_fade_scalar, 1.0f, CVAR_ARCHIVE ) // [SP] Uses same logic as blood_fade_scalar except for pickups // [RH] Amount of red flash for up to 114 damage points. Calculated by hand // using a logarithmic scale and my trusty HP48G. @@ -113,6 +114,9 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int if (CPlayer->bonuscount) { cnt = CPlayer->bonuscount << 3; + + // [SP] Allow player to tone down intensity of pickup flash. + cnt = (int)( cnt * pickup_fade_scalar ); V_AddBlend (RPART(gameinfo.pickupcolor)/255.f, GPART(gameinfo.pickupcolor)/255.f, BPART(gameinfo.pickupcolor)/255.f, cnt > 128 ? 0.5f : cnt / 255.f, blend); @@ -124,7 +128,10 @@ void V_AddPlayerBlend (player_t *CPlayer, float blend[4], float maxinvalpha, int if (painFlash.a != 0) { cnt = DamageToAlpha[MIN (113, CPlayer->damagecount * painFlash.a / 255)]; - + + // [BC] Allow users to tone down the intensity of the blood on the screen. + cnt = (int)( cnt * blood_fade_scalar ); + if (cnt) { if (cnt > maxpainblend) diff --git a/src/zscript/zcc-parse.lemon b/src/zscript/zcc-parse.lemon index ee8296ff6..12cbb6625 100644 --- a/src/zscript/zcc-parse.lemon +++ b/src/zscript/zcc-parse.lemon @@ -77,7 +77,7 @@ static void SetNodeLine(ZCC_TreeNode *name, int line) FString unexpected, expecting; int i; - int stateno = yypParser->yystack[yypParser->yyidx].stateno; + int stateno = yypParser->yytos->stateno; unexpected << "Unexpected " << ZCCTokenName(yymajor); diff --git a/src/zscript/zcc_expr.cpp b/src/zscript/zcc_expr.cpp index 0cd399d64..e1a091b18 100644 --- a/src/zscript/zcc_expr.cpp +++ b/src/zscript/zcc_expr.cpp @@ -162,11 +162,11 @@ ZCC_OpProto *ZCC_OpInfoType::FindBestProto( // [[float32 (op) int]] will choose the integer version instead of the floating point // version, which we do not want. int test_dist1 = dist1, test_dist2 = dist2; - if (routes[0][cur_route1][0]->ConvertConstant == FtoD) + if (test_dist1 > 0 && routes[0][cur_route1][0]->ConvertConstant == FtoD) { test_dist1--; } - if (routes[1][cur_route2][0]->ConvertConstant == FtoD) + if (test_dist2 > 0 && routes[1][cur_route2][0]->ConvertConstant == FtoD) { test_dist2--; } diff --git a/tools/lemon/lemon.c b/tools/lemon/lemon.c index 546cf515e..bdc004a17 100644 --- a/tools/lemon/lemon.c +++ b/tools/lemon/lemon.c @@ -167,7 +167,8 @@ struct symbol { int useCnt; /* Number of times used */ char *destructor; /* Code which executes whenever this symbol is ** popped from the stack during error processing */ - int destLineno; /* Line number for start of destructor */ + int destLineno; /* Line number for start of destructor. Set to + ** -1 for duplicate destructors. */ char *datatype; /* The data type of information held by this ** object. Only used if type==NONTERMINAL */ int dtnum; /* The data type number. In the parser, the value @@ -192,10 +193,15 @@ struct rule { const char *code; /* The code executed when this rule is reduced */ const char *codePrefix; /* Setup code before code[] above */ const char *codeSuffix; /* Breakdown code after code[] above */ + int noCode; /* True if this rule has no associated C code */ + int codeEmitted; /* True if the code has been emitted already */ struct symbol *precsym; /* Precedence symbol for this rule */ int index; /* An index number for this rule */ int iRule; /* Rule number as used in the generated tables */ Boolean canReduce; /* True if this rule is ever reduced */ +#if 0 + Boolean doesReduce; /* Reduce actions occur after optimization */ +#endif struct rule *nextlhs; /* Next rule with the same LHS */ struct rule *next; /* Next rule in the global list */ }; @@ -243,6 +249,7 @@ struct action { struct state *stp; /* The new state, if a shift */ struct rule *rp; /* The rule, if a reduce */ } x; + struct symbol *spOpt; /* SHIFTREDUCE optimization to this symbol */ struct action *next; /* Next action for this state */ struct action *collide; /* Next action with the same hash */ }; @@ -253,7 +260,7 @@ struct state { struct config *bp; /* The basis configurations for this state */ struct config *cfp; /* All configurations in this set */ int statenum; /* Sequential number for this state */ - struct action *ap; /* Array of actions for this state */ + struct action *ap; /* List of actions for this state */ int nTknAct, nNtAct; /* Number of actions on terminals and nonterminals */ int iTknOfst, iNtOfst; /* yy_action[] offset for terminals and nonterms */ int iDfltReduce; /* Default action is to REDUCE by this rule */ @@ -433,6 +440,7 @@ void Action_add( *app = newaction; newaction->type = type; newaction->sp = sp; + newaction->spOpt = 0; if( type==SHIFT ){ newaction->x.stp = (struct state *)arg; }else{ @@ -1483,7 +1491,7 @@ static void handle_C_option(char *z){ } } -/* Merge together to lists of rules order by rule.iRule */ +/* Merge together to lists of rules ordered by rule.iRule */ static struct rule *Rule_merge(struct rule *pA, struct rule *pB){ struct rule *pFirst = 0; struct rule **ppPrev = &pFirst; @@ -1627,7 +1635,10 @@ int main(int argc, char **argv) for(i=1; ISUPPER(lem.symbols[i]->name[0]); i++); lem.nterminal = i; - /* Assign sequential rule numbers */ + /* Assign sequential rule numbers. Start with 0. Put rules that have no + ** reduce action C-code associated with them last, so that the switch() + ** statement that selects reduction actions will have a smaller jump table. + */ for(i=0, rp=lem.rule; rp; rp=rp->next){ rp->iRule = rp->code ? i++ : -1; } @@ -2179,7 +2190,7 @@ static void parseonetoken(struct pstate *psp) "There is no prior rule upon which to attach the code \ fragment which begins on this line."); psp->errorcnt++; - }else if( psp->prevrule->code!=0 ){ + }else if( psp->prevrule->code!=0 ){ ErrorMsg(psp->filename,psp->tokenlineno, "Code fragment beginning on this line is not the first \ to follow the previous rule."); @@ -2187,7 +2198,8 @@ to follow the previous rule."); }else{ psp->prevrule->line = psp->tokenlineno; psp->prevrule->code = &x[1]; - } + psp->prevrule->noCode = 0; + } }else if( x[0]=='[' ){ psp->state = PRECEDENCE_MARK_1; }else{ @@ -2293,6 +2305,7 @@ to follow the previous rule."); rp->lhsalias = psp->lhsalias; rp->nrhs = psp->nrhs; rp->code = 0; + rp->noCode = 1; rp->precsym = 0; rp->index = psp->gp->nrule++; rp->nextlhs = rp->lhs->rule; @@ -3153,6 +3166,9 @@ int PrintAction( result = 0; break; } + if( result && ap->spOpt ){ + fprintf(fp," /* because %s==%s */", ap->sp->name, ap->spOpt->name); + } return result; } @@ -3531,9 +3547,8 @@ PRIVATE char *append_str(const char *zText, int n, int p1, int p2, int bNoSubst) } /* -** zCode is a string that is the action associated with a rule. Expand -** the symbols in this string so that the refer to elements of the parser -** stack. +** Write and transform the rp->code string so that symbols are expanded. +** Populate the rp->codePrefix and rp->codeSuffix strings, as appropriate. ** ** Return 1 if the expanded code requires that "yylhsminor" local variable ** to be defined. @@ -3557,12 +3572,12 @@ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){ static char newlinestr[2] = { '\n', '\0' }; rp->code = newlinestr; rp->line = rp->ruleline; + rp->noCode = 1; + }else{ + rp->noCode = 0; } - if( rp->lhsalias==0 ){ - /* There is no LHS value symbol. */ - lhsdirect = 1; - }else if( rp->nrhs==0 ){ + if( rp->nrhs==0 ){ /* If there are no RHS symbols, then writing directly to the LHS is ok */ lhsdirect = 1; }else if( rp->rhsalias[0]==0 ){ @@ -3574,7 +3589,11 @@ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){ append_str(" yy_destructor(yypParser,%d,&yymsp[%d].minor);\n", 0, rp->rhs[0]->index,1-rp->nrhs,0); rp->codePrefix = Strsafe(append_str(0,0,0,0,0)); + rp->noCode = 0; } + }else if( rp->lhsalias==0 ){ + /* There is no LHS value symbol. */ + lhsdirect = 1; }else if( strcmp(rp->lhsalias,rp->rhsalias[0])==0 ){ /* The LHS symbol and the left-most RHS symbol are the same, so ** direct writing is allowed */ @@ -3717,7 +3736,10 @@ PRIVATE int translate_code(struct lemon *lemp, struct rule *rp){ /* Suffix code generation complete */ cp = append_str(0,0,0,0,0); - if( cp ) rp->codeSuffix = Strsafe(cp); + if( cp && cp[0] ){ + rp->codeSuffix = Strsafe(cp); + rp->noCode = 0; + } return rc; } @@ -4136,6 +4158,21 @@ void ReportTable( } free(ax); +#if 0 + /* Mark rules that are actually used for reduce actions after all + ** optimizations have been applied + */ + for(rp=lemp->rule; rp; rp=rp->next) rp->doesReduce = LEMON_FALSE; + for(i=0; inxstate; i++){ + struct action *ap; + for(ap=lemp->sorted[i]->ap; ap; ap=ap->next){ + if( ap->type==REDUCE || ap->type==SHIFTREDUCE ){ + ap->x.rp->doesReduce = i; + } + } + } +#endif + /* Finish rendering the constants now that the action table has ** been computed */ fprintf(out,"#define YYNSTATE %d\n",lemp->nxstate); lineno++; @@ -4201,20 +4238,21 @@ void ReportTable( fprintf(out, "};\n"); lineno++; /* Output the yy_shift_ofst[] table */ - fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", mnTknOfst-1); lineno++; n = lemp->nxstate; while( n>0 && lemp->sorted[n-1]->iTknOfst==NO_OFFSET ) n--; - fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++; - fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++; - fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++; + fprintf(out, "#define YY_SHIFT_USE_DFLT (%d)\n", lemp->nactiontab); lineno++; + fprintf(out, "#define YY_SHIFT_COUNT (%d)\n", n-1); lineno++; + fprintf(out, "#define YY_SHIFT_MIN (%d)\n", mnTknOfst); lineno++; + fprintf(out, "#define YY_SHIFT_MAX (%d)\n", mxTknOfst); lineno++; fprintf(out, "static const %s yy_shift_ofst[] = {\n", - minimum_size_type(mnTknOfst-1, mxTknOfst, &sz)); lineno++; + minimum_size_type(mnTknOfst, lemp->nterminal+lemp->nactiontab, &sz)); + lineno++; lemp->tablesize += n*sz; for(i=j=0; isorted[i]; ofst = stp->iTknOfst; - if( ofst==NO_OFFSET ) ofst = mnTknOfst - 1; + if( ofst==NO_OFFSET ) ofst = lemp->nactiontab; if( j==0 ) fprintf(out," /* %5d */ ", i); fprintf(out, " %4d,", ofst); if( j==9 || i==n-1 ){ @@ -4354,6 +4392,7 @@ void ReportTable( for(i=0; insymbol; i++){ struct symbol *sp = lemp->symbols[i]; if( sp==0 || sp->type==TERMINAL || sp->destructor==0 ) continue; + if( sp->destLineno<0 ) continue; /* Already emitted */ fprintf(out," case %d: /* %s */\n", sp->index, sp->name); lineno++; /* Combine duplicate destructors into a single case */ @@ -4364,7 +4403,7 @@ void ReportTable( && strcmp(sp->destructor,sp2->destructor)==0 ){ fprintf(out," case %d: /* %s */\n", sp2->index, sp2->name); lineno++; - sp2->destructor = 0; + sp2->destLineno = -1; /* Avoid emitting this destructor again */ } } @@ -4398,32 +4437,45 @@ void ReportTable( /* First output rules other than the default: rule */ for(rp=lemp->rule; rp; rp=rp->next){ struct rule *rp2; /* Other rules with the same action */ - if( rp->code==0 ) continue; - if( rp->code[0]=='\n' && rp->code[1]==0 ) continue; /* Will be default: */ + if( rp->codeEmitted ) continue; + if( rp->noCode ){ + /* No C code actions, so this will be part of the "default:" rule */ + continue; + } fprintf(out," case %d: /* ",rp->iRule); writeRuleText(out, rp); fprintf(out," */\n"); lineno++; for(rp2=rp->next; rp2; rp2=rp2->next){ - if( rp2->code==rp->code ){ + if( rp2->code==rp->code && rp2->codePrefix==rp->codePrefix + && rp2->codeSuffix == rp->codeSuffix ){ fprintf(out," case %d: /*",rp2->iRule); writeRuleText(out, rp2); fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp2->iRule); lineno++; - rp2->code = 0; + rp2->codeEmitted = 1; } } emit_code(out,rp,lemp,&lineno); fprintf(out," break;\n"); lineno++; - rp->code = 0; + rp->codeEmitted = 1; } /* Finally, output the default: rule. We choose as the default: all ** empty actions. */ fprintf(out," default:\n"); lineno++; for(rp=lemp->rule; rp; rp=rp->next){ - if( rp->code==0 ) continue; - assert( rp->code[0]=='\n' && rp->code[1]==0 ); + if( rp->codeEmitted ) continue; + assert( rp->noCode ); fprintf(out," /* (%d) ", rp->iRule); writeRuleText(out, rp); - fprintf(out," */ yytestcase(yyruleno==%d);\n", rp->iRule); lineno++; +#if 0 + if( rp->doesReduce ){ +#endif + fprintf(out, " */ yytestcase(yyruleno==%d);\n", rp->iRule); lineno++; +#if 0 + }else{ + fprintf(out, " (OPTIMIZED OUT) */ assert(yyruleno!=%d);\n", + rp->iRule); lineno++; + } +#endif } fprintf(out," break;\n"); lineno++; tplt_xfer(lemp->name,in,out,&lineno); @@ -4496,7 +4548,7 @@ void ReportHeader(struct lemon *lemp) void CompressTables(struct lemon *lemp) { struct state *stp; - struct action *ap, *ap2; + struct action *ap, *ap2, *nextap; struct rule *rp, *rp2, *rbest; int nbest, n; int i; @@ -4573,6 +4625,36 @@ void CompressTables(struct lemon *lemp) } } } + + /* If a SHIFTREDUCE action specifies a rule that has a single RHS term + ** (meaning that the SHIFTREDUCE will land back in the state where it + ** started) and if there is no C-code associated with the reduce action, + ** then we can go ahead and convert the action to be the same as the + ** action for the RHS of the rule. + */ + for(i=0; instate; i++){ + stp = lemp->sorted[i]; + for(ap=stp->ap; ap; ap=nextap){ + nextap = ap->next; + if( ap->type!=SHIFTREDUCE ) continue; + rp = ap->x.rp; + if( rp->noCode==0 ) continue; + if( rp->nrhs!=1 ) continue; +#if 1 + /* Only apply this optimization to non-terminals. It would be OK to + ** apply it to terminal symbols too, but that makes the parser tables + ** larger. */ + if( ap->sp->indexnterminal ) continue; +#endif + /* If we reach this point, it means the optimization can be applied */ + nextap = ap; + for(ap2=stp->ap; ap2 && (ap2==ap || ap2->sp!=rp->lhs); ap2=ap2->next){} + assert( ap2!=0 ); + ap->spOpt = ap2->sp; + ap->type = ap2->type; + ap->x = ap2->x; + } + } } diff --git a/tools/lemon/lempar.c b/tools/lemon/lempar.c index 0549a9dad..93b612017 100644 --- a/tools/lemon/lempar.c +++ b/tools/lemon/lempar.c @@ -41,6 +41,7 @@ ***************** Begin makeheaders token definitions *************************/ %% /**************** End makeheaders token definitions ***************************/ + /* The next section is a series of control #defines. ** various aspects of the generated parser. ** YYCODETYPE is the data type used to store the integer codes @@ -50,8 +51,6 @@ ** YYNOCODE is a number of type YYCODETYPE that is not used for ** any terminal or nonterminal symbol. ** YYFALLBACK If defined, this indicates that one or more tokens -** have fall-back values which should be used if the -** original value of the token will not parse. ** (also known as: "terminal symbols") have fall-back ** values which should be used if the original symbol ** would not parse. This permits keywords to sometimes @@ -126,7 +125,7 @@ ** ** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE ** and YY_MAX_REDUCE - +** ** N == YY_ERROR_ACTION A syntax error has occurred. ** ** N == YY_ACCEPT_ACTION The parser accepts its input. @@ -135,16 +134,20 @@ ** slots in the yy_action[] table. ** ** The action table is constructed as a single large table named yy_action[]. -** Given state S and lookahead X, the action is computed as +** Given state S and lookahead X, the action is computed as either: ** -** yy_action[ yy_shift_ofst[S] + X ] +** (A) N = yy_action[ yy_shift_ofst[S] + X ] +** (B) N = yy_default[S] ** -** If the index value yy_shift_ofst[S]+X is out of range or if the value -** yy_lookahead[yy_shift_ofst[S]+X] is not equal to X or if yy_shift_ofst[S] -** is equal to YY_SHIFT_USE_DFLT, it means that the action is not in the table -** and that yy_default[S] should be used instead. +** The (A) formula is preferred. The B formula is used instead if: +** (1) The yy_shift_ofst[S]+X value is out of range, or +** (2) yy_lookahead[yy_shift_ofst[S]+X] is not equal to X, or +** (3) yy_shift_ofst[S] equal YY_SHIFT_USE_DFLT. +** (Implementation note: YY_SHIFT_USE_DFLT is chosen so that +** YY_SHIFT_USE_DFLT+X will be out of range for all possible lookaheads X. +** Hence only tests (1) and (2) need to be evaluated.) ** -** The formula above is for computing the action when the lookahead is +** The formulas above are for computing the action when the lookahead is ** a terminal symbol. If the lookahead is a non-terminal (as occurs after ** a reduce action) then the yy_reduce_ofst[] array is used in place of ** the yy_shift_ofst[] array and YY_REDUCE_USE_DFLT is used in place of @@ -213,9 +216,9 @@ typedef struct yyStackEntry yyStackEntry; /* The state of the parser is completely contained in an instance of ** the following structure */ struct yyParser { - int yyidx; /* Index of top element in stack */ + yyStackEntry *yytos; /* Pointer to top element of the stack */ #ifdef YYTRACKMAXSTACKDEPTH - int yyidxMax; /* Maximum value of yyidx */ + int yyhwm; /* High-water mark of the stack */ #endif #ifndef YYNOERRORRECOVERY int yyerrcnt; /* Shifts left before out of the error */ @@ -224,6 +227,7 @@ struct yyParser { #if YYSTACKDEPTH<=0 int yystksz; /* Current side of the stack */ yyStackEntry *yystack; /* The parser's stack */ + yyStackEntry yystk0; /* First stack entry */ #else yyStackEntry yystack[YYSTACKDEPTH]; /* The parser's stack */ #endif @@ -278,26 +282,38 @@ static const char *const yyRuleName[] = { }; #endif /* NDEBUG */ + #if YYSTACKDEPTH<=0 /* -** Try to increase the size of the parser stack. +** Try to increase the size of the parser stack. Return the number +** of errors. Return 0 on success. */ -static void yyGrowStack(yyParser *p){ +static int yyGrowStack(yyParser *p){ int newSize; + int idx; yyStackEntry *pNew; newSize = p->yystksz*2 + 100; - pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); + idx = p->yytos ? (int)(p->yytos - p->yystack) : 0; + if( p->yystack==&p->yystk0 ){ + pNew = malloc(newSize*sizeof(pNew[0])); + if( pNew ) pNew[0] = p->yystk0; + }else{ + pNew = realloc(p->yystack, newSize*sizeof(pNew[0])); + } if( pNew ){ p->yystack = pNew; - p->yystksz = newSize; + p->yytos = &p->yystack[idx]; #ifndef NDEBUG if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sStack grows to %d entries!\n", - yyTracePrompt, p->yystksz); + fprintf(yyTraceFILE,"%sStack grows from %d to %d entries.\n", + yyTracePrompt, p->yystksz, newSize); + fflush(yyTraceFILE); } #endif + p->yystksz = newSize; } + return pNew==0; } #endif @@ -326,15 +342,24 @@ void *ParseAlloc(void *(CDECL *mallocProc)(YYMALLOCARGTYPE)){ yyParser *pParser; pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); if( pParser ){ - pParser->yyidx = -1; #ifdef YYTRACKMAXSTACKDEPTH - pParser->yyidxMax = 0; + pParser->yyhwm = 0; #endif #if YYSTACKDEPTH<=0 + pParser->yytos = NULL; pParser->yystack = NULL; pParser->yystksz = 0; - yyGrowStack(pParser); + if( yyGrowStack(pParser) ){ + pParser->yystack = &pParser->yystk0; + pParser->yystksz = 1; + } #endif +#ifndef YYNOERRORRECOVERY + pParser->yyerrcnt = -1; +#endif + pParser->yytos = pParser->yystack; + pParser->yystack[0].stateno = 0; + pParser->yystack[0].major = 0; } return pParser; } @@ -378,22 +403,24 @@ static void yy_destructor( */ static void yy_pop_parser_stack(yyParser *pParser){ yyStackEntry *yytos; - assert( pParser->yyidx>=0 ); - yytos = &pParser->yystack[pParser->yyidx--]; + assert( pParser->yytos!=0 ); + assert( pParser->yytos > pParser->yystack ); + yytos = pParser->yytos--; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sPopping %s\n", yyTracePrompt, yyTokenName[yytos->major]); + fflush(yyTraceFILE); } #endif yy_destructor(pParser, yytos->major, &yytos->minor); } -/* +/* ** Deallocate and destroy a parser. Destructors are called for ** all stack elements before shutting the parser down. -* +** ** If the YYPARSEFREENEVERNULL macro exists (for example because it ** is defined in a %include section of the input grammar) then it is ** assumed that the input pointer is never NULL. @@ -406,9 +433,9 @@ void ParseFree( #ifndef YYPARSEFREENEVERNULL if( pParser==0 ) return; #endif - while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser); + while( pParser->yytos>pParser->yystack ) yy_pop_parser_stack(pParser); #if YYSTACKDEPTH<=0 - free(pParser->yystack); + if( pParser->yystack!=&pParser->yystk0 ) free(pParser->yystack); #endif (*freeProc)((void*)pParser); } @@ -419,7 +446,7 @@ void ParseFree( #ifdef YYTRACKMAXSTACKDEPTH int ParseStackPeak(void *p){ yyParser *pParser = (yyParser*)p; - return pParser->yyidxMax; + return pParser->yyhwm; } #endif @@ -432,56 +459,55 @@ static unsigned int yy_find_shift_action( YYCODETYPE iLookAhead /* The look-ahead token */ ){ int i; - int stateno = pParser->yystack[pParser->yyidx].stateno; + int stateno = pParser->yytos->stateno; if( stateno>=YY_MIN_REDUCE ) return stateno; assert( stateno <= YY_SHIFT_COUNT ); do{ i = yy_shift_ofst[stateno]; - if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno]; assert( iLookAhead!=YYNOCODE ); i += iLookAhead; if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ - if( iLookAhead>0 ){ #ifdef YYFALLBACK - YYCODETYPE iFallback; /* Fallback token */ - if( iLookAhead %s\n", - yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); - } -#endif - assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ - iLookAhead = iFallback; - continue; + if( yyTraceFILE ){ + fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); + fflush(yyTraceFILE); } +#endif + assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ + iLookAhead = iFallback; + continue; + } #endif #ifdef YYWILDCARD - { - int j = i - iLookAhead + YYWILDCARD; - if( + { + int j = i - iLookAhead + YYWILDCARD; + if( #if YY_SHIFT_MIN+YYWILDCARD<0 - j>=0 && + j>=0 && #endif #if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT - j0 + ){ #ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", - yyTracePrompt, yyTokenName[iLookAhead], - yyTokenName[YYWILDCARD]); - } -#endif /* NDEBUG */ - return yy_action[j]; + if( yyTraceFILE ){ + fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", + yyTracePrompt, yyTokenName[iLookAhead], + yyTokenName[YYWILDCARD]); + fflush(yyTraceFILE); } +#endif /* NDEBUG */ + return yy_action[j]; } -#endif /* YYWILDCARD */ } +#endif /* YYWILDCARD */ return yy_default[stateno]; }else{ return yy_action[i]; @@ -500,7 +526,7 @@ static int yy_find_reduce_action( int i; #ifdef YYERRORSYMBOL if( stateno>YY_REDUCE_COUNT ){ - return yy_default[stateno]; + return yy_default[stateno]; } #else assert( stateno<=YY_REDUCE_COUNT ); @@ -525,15 +551,16 @@ static int yy_find_reduce_action( */ static void yyStackOverflow(yyParser *yypParser){ ParseARG_FETCH; - yypParser->yyidx--; + yypParser->yytos--; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sStack Overflow!\n",yyTracePrompt); + fflush(yyTraceFILE); } #endif - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will execute if the parser - ** stack ever overflows */ + ** stack every overflows */ /******** Begin %stack_overflow code ******************************************/ %% /******** End %stack_overflow code ********************************************/ @@ -548,12 +575,13 @@ static void yyTraceShift(yyParser *yypParser, int yyNewState){ if( yyTraceFILE ){ if( yyNewStateyystack[yypParser->yyidx].major], + yyTracePrompt,yyTokenName[yypParser->yytos->major], yyNewState); }else{ fprintf(yyTraceFILE,"%sShift '%s'\n", - yyTracePrompt,yyTokenName[yypParser->yystack[yypParser->yyidx].major]); + yyTracePrompt,yyTokenName[yypParser->yytos->major]); } + fflush(yyTraceFILE); } } #else @@ -570,27 +598,30 @@ static void yy_shift( ParseTOKENTYPE yyMinor /* The minor token to shift in */ ){ yyStackEntry *yytos; - yypParser->yyidx++; + yypParser->yytos++; #ifdef YYTRACKMAXSTACKDEPTH - if( yypParser->yyidx>yypParser->yyidxMax ){ - yypParser->yyidxMax = yypParser->yyidx; + if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ + yypParser->yyhwm++; + assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack) ); } #endif -#if YYSTACKDEPTH>0 - if( yypParser->yyidx>=YYSTACKDEPTH ){ +#if YYSTACKDEPTH>0 + if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH] ){ yyStackOverflow(yypParser); return; } #else - if( yypParser->yyidx>=yypParser->yystksz ){ - yyGrowStack(yypParser); - if( yypParser->yyidx>=yypParser->yystksz ){ + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz] ){ + if( yyGrowStack(yypParser) ){ yyStackOverflow(yypParser); return; } } #endif - yytos = &yypParser->yystack[yypParser->yyidx]; + if( yyNewState > YY_MAX_SHIFT ){ + yyNewState += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; + } + yytos = yypParser->yytos; yytos->stateno = (YYACTIONTYPE)yyNewState; yytos->major = (YYCODETYPE)yyMajor; yytos->minor.yy0 = yyMinor; @@ -622,12 +653,13 @@ static void yy_reduce( yyStackEntry *yymsp; /* The top of the parser's stack */ int yysize; /* Amount to pop the stack */ ParseARG_FETCH; - yymsp = &yypParser->yystack[yypParser->yyidx]; + yymsp = yypParser->yytos; #ifndef NDEBUG if( yyTraceFILE && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ yysize = yyRuleInfo[yyruleno].nrhs; fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt, yyRuleName[yyruleno], yymsp[-yysize].stateno); + fflush(yyTraceFILE); } #endif /* NDEBUG */ @@ -636,22 +668,23 @@ static void yy_reduce( ** enough on the stack to push the LHS value */ if( yyRuleInfo[yyruleno].nrhs==0 ){ #ifdef YYTRACKMAXSTACKDEPTH - if( yypParser->yyidx>yypParser->yyidxMax ){ - yypParser->yyidxMax = yypParser->yyidx; + if( (int)(yypParser->yytos - yypParser->yystack)>yypParser->yyhwm ){ + yypParser->yyhwm++; + assert( yypParser->yyhwm == (int)(yypParser->yytos - yypParser->yystack)); } #endif -#if YYSTACKDEPTH>0 - if( yypParser->yyidx>=YYSTACKDEPTH-1 ){ +#if YYSTACKDEPTH>0 + if( yypParser->yytos>=&yypParser->yystack[YYSTACKDEPTH-1] ){ yyStackOverflow(yypParser); return; } #else - if( yypParser->yyidx>=yypParser->yystksz-1 ){ - yyGrowStack(yypParser); - if( yypParser->yyidx>=yypParser->yystksz-1 ){ + if( yypParser->yytos>=&yypParser->yystack[yypParser->yystksz-1] ){ + if( yyGrowStack(yypParser) ){ yyStackOverflow(yypParser); return; } + yymsp = yypParser->yytos; } #endif } @@ -674,15 +707,17 @@ static void yy_reduce( yysize = yyRuleInfo[yyruleno].nrhs; yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); if( yyact <= YY_MAX_SHIFTREDUCE ){ - if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; - yypParser->yyidx -= yysize - 1; + if( yyact>YY_MAX_SHIFT ){ + yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; + } yymsp -= yysize-1; + yypParser->yytos = yymsp; yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->major = (YYCODETYPE)yygoto; yyTraceShift(yypParser, yyact); }else{ assert( yyact == YY_ACCEPT_ACTION ); - yypParser->yyidx -= yysize; + yypParser->yytos -= yysize; yy_accept(yypParser); } } @@ -698,9 +733,10 @@ static void yy_parse_failed( #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sFail!\n",yyTracePrompt); + fflush(yyTraceFILE); } #endif - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); + while( yypParser->yytos>yypParser->yystack ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will be executed whenever the ** parser fails */ /************ Begin %parse_failure code ***************************************/ @@ -736,9 +772,17 @@ static void yy_accept( #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sAccept!\n",yyTracePrompt); + fflush(yyTraceFILE); } #endif - while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif +#if 0 + assert( yypParser->yytos==yypParser->yystack ); +#else + while (yypParser->yytos>yypParser->yystack) yy_pop_parser_stack(yypParser); +#endif /* Here code is inserted which will be executed whenever the ** parser accepts */ /*********** Begin %parse_accept code *****************************************/ @@ -782,28 +826,8 @@ void Parse( #endif yyParser *yypParser; /* The parser */ - /* (re)initialize the parser, if necessary */ yypParser = (yyParser*)yyp; - if( yypParser->yyidx<0 ){ -#if YYSTACKDEPTH<=0 - if( yypParser->yystksz <=0 ){ - yyStackOverflow(yypParser); - return; - } -#endif - yypParser->yyidx = 0; -#ifndef YYNOERRORRECOVERY - yypParser->yyerrcnt = -1; -#endif - yypParser->yystack[0].stateno = 0; - yypParser->yystack[0].major = 0; -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sInitialize. Empty stack. State 0\n", - yyTracePrompt); - } -#endif - } + assert( yypParser->yytos!=0 ); #if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) yyendofinput = (yymajor==0); #endif @@ -812,13 +836,13 @@ void Parse( #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]); + fflush(yyTraceFILE); } #endif do{ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); if( yyact <= YY_MAX_SHIFTREDUCE ){ - if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; yy_shift(yypParser,yyact,yymajor,yyminor); #ifndef YYNOERRORRECOVERY yypParser->yyerrcnt--; @@ -827,20 +851,21 @@ void Parse( }else if( yyact <= YY_MAX_REDUCE ){ yy_reduce(yypParser,yyact-YY_MIN_REDUCE); }else{ + assert( yyact == YY_ERROR_ACTION ); + yyminorunion.yy0 = yyminor; #ifdef YYERRORSYMBOL int yymx; #endif - assert( yyact == YY_ERROR_ACTION ); - yyminorunion.yy0 = yyminor; #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sSyntax Error!\n",yyTracePrompt); + fflush(yyTraceFILE); } #endif #ifdef YYERRORSYMBOL /* A syntax error has occurred. ** The response to an error depends upon whether or not the - ** grammar defines an error token "ERROR". + ** grammar defines an error token "ERROR". ** ** This is what we do if the grammar does define ERROR: ** @@ -860,29 +885,32 @@ void Parse( if( yypParser->yyerrcnt<0 ){ yy_syntax_error(yypParser,yymajor,yyminor); } - yymx = yypParser->yystack[yypParser->yyidx].major; + yymx = yypParser->yytos->major; if( yymx==YYERRORSYMBOL || yyerrorhit ){ #ifndef NDEBUG if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sDiscard input token %s\n", yyTracePrompt,yyTokenName[yymajor]); + fflush(yyTraceFILE); } #endif yy_destructor(yypParser, (YYCODETYPE)yymajor, &yyminorunion); yymajor = YYNOCODE; }else{ - while( - yypParser->yyidx >= 0 && - yymx != YYERRORSYMBOL && - (yyact = yy_find_reduce_action( - yypParser->yystack[yypParser->yyidx].stateno, + while( yypParser->yytos >= yypParser->yystack + && yymx != YYERRORSYMBOL + && (yyact = yy_find_reduce_action( + yypParser->yytos->stateno, YYERRORSYMBOL)) >= YY_MIN_REDUCE ){ yy_pop_parser_stack(yypParser); } - if( yypParser->yyidx < 0 || yymajor==0 ){ + if( yypParser->yytos < yypParser->yystack || yymajor==0 ){ yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yy_parse_failed(yypParser); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif yymajor = YYNOCODE; }else if( yymx!=YYERRORSYMBOL ){ yy_shift(yypParser,yyact,YYERRORSYMBOL,yyminor); @@ -901,7 +929,7 @@ void Parse( yy_syntax_error(yypParser,yymajor, yyminor); yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); yymajor = YYNOCODE; - + #else /* YYERRORSYMBOL is not defined */ /* This is what we do if the grammar does not define ERROR: ** @@ -919,19 +947,25 @@ void Parse( yy_destructor(yypParser,(YYCODETYPE)yymajor,&yyminorunion); if( yyendofinput ){ yy_parse_failed(yypParser); +#ifndef YYNOERRORRECOVERY + yypParser->yyerrcnt = -1; +#endif } yymajor = YYNOCODE; #endif } - }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); + }while( yymajor!=YYNOCODE && yypParser->yytos>yypParser->yystack ); #ifndef NDEBUG if( yyTraceFILE ){ - int i; + yyStackEntry *i; + char cDiv = '['; fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); - for(i=1; i<=yypParser->yyidx; i++) - fprintf(yyTraceFILE,"%c%s", i==1 ? '[' : ' ', - yyTokenName[yypParser->yystack[i].major]); + for(i=&yypParser->yystack[1]; i<=yypParser->yytos; i++){ + fprintf(yyTraceFILE,"%c%s", cDiv, yyTokenName[i->major]); + cDiv = ' '; + } fprintf(yyTraceFILE,"]\n"); + fflush(yyTraceFILE); } #endif return; diff --git a/wadsrc/static/actors/actor.txt b/wadsrc/static/actors/actor.txt index 44b801f51..eecc843d3 100644 --- a/wadsrc/static/actors/actor.txt +++ b/wadsrc/static/actors/actor.txt @@ -58,6 +58,8 @@ ACTOR Actor native //: Thinker native float GetSpriteRotation(int ptr = AAPTR_DEFAULT); native int GetMissileDamage(int mask, int add, int ptr = AAPTR_DEFAULT); action native int OverlayID(); + action native float OverlayX(int layer = 0); + action native float OverlayY(int layer = 0); // Action functions // Meh, MBF redundant functions. Only for DeHackEd support. @@ -209,6 +211,7 @@ ACTOR Actor native //: Thinker native state A_JumpIfTargetInsideMeleeRange(state label); native state A_JumpIfInventory(class itemtype, int itemamount, state label, int owner = AAPTR_DEFAULT); native state A_JumpIfArmorType(name Type, state label, int amount = 1); + action native bool A_SetInventory(class itemtype, int amount, int ptr = AAPTR_DEFAULT, bool beyondMax = false); native bool A_GiveInventory(class itemtype, int amount = 0, int giveto = AAPTR_DEFAULT); native bool A_TakeInventory(class itemtype, int amount = 0, int flags = 0, int giveto = AAPTR_DEFAULT); action native bool A_SpawnItem(class itemtype = "Unknown", float distance = 0, float zheight = 0, bool useammo = true, bool transfer_translation = false); diff --git a/wadsrc/static/actors/constants.txt b/wadsrc/static/actors/constants.txt index dce2488c2..df3bb860b 100644 --- a/wadsrc/static/actors/constants.txt +++ b/wadsrc/static/actors/constants.txt @@ -598,6 +598,7 @@ enum PSPF_ADDBOB = 1 << 1, PSPF_POWDOUBLE = 1 << 2, PSPF_CVARFAST = 1 << 3, + PSPF_FLIP = 1 << 6, }; // Default psprite layers diff --git a/wadsrc/static/actors/doom/doomimp.txt b/wadsrc/static/actors/doom/doomimp.txt index a5725e724..008cc5229 100644 --- a/wadsrc/static/actors/doom/doomimp.txt +++ b/wadsrc/static/actors/doom/doomimp.txt @@ -52,7 +52,8 @@ ACTOR DoomImp TROO U -1 Stop Raise: - TROO MLKJI 8 + TROO ML 8 + TROO KJI 6 Goto See } } diff --git a/wadsrc/static/actors/shared/sharedmisc.txt b/wadsrc/static/actors/shared/sharedmisc.txt index bfe7d5519..fe5ac72d8 100644 --- a/wadsrc/static/actors/shared/sharedmisc.txt +++ b/wadsrc/static/actors/shared/sharedmisc.txt @@ -75,12 +75,14 @@ ACTOR PointPusher { +NOBLOCKMAP +INVISIBLE + +NOCLIP } ACTOR PointPuller { +NOBLOCKMAP +INVISIBLE + +NOCLIP } // Bloody gibs ------------------------------------------------------------- diff --git a/wadsrc/static/animated.lmp b/wadsrc/static/animated.lmp deleted file mode 100644 index 100c804c8..000000000 Binary files a/wadsrc/static/animated.lmp and /dev/null differ diff --git a/wadsrc/static/filter/game-doomchex/animated.lmp b/wadsrc/static/filter/game-doomchex/animated.lmp new file mode 100644 index 000000000..016ce1fa3 Binary files /dev/null and b/wadsrc/static/filter/game-doomchex/animated.lmp differ diff --git a/wadsrc/static/filter/game-heretic/animated.lmp b/wadsrc/static/filter/game-heretic/animated.lmp new file mode 100644 index 000000000..80102c88e Binary files /dev/null and b/wadsrc/static/filter/game-heretic/animated.lmp differ diff --git a/wadsrc/static/filter/game-strife/animated.lmp b/wadsrc/static/filter/game-strife/animated.lmp new file mode 100644 index 000000000..ca656cfc3 Binary files /dev/null and b/wadsrc/static/filter/game-strife/animated.lmp differ diff --git a/wadsrc/static/language.enu b/wadsrc/static/language.enu index 547b53218..7cf04284f 100644 --- a/wadsrc/static/language.enu +++ b/wadsrc/static/language.enu @@ -1782,9 +1782,11 @@ DSPLYMNU_CAPFPS = "Rendering Interpolation"; DSPLYMNU_COLUMNMETHOD = "Column render mode"; DSPLYMNU_WIPETYPE = "Screen wipe style"; DSPLYMNU_SHOWENDOOM = "Show ENDOOM screen"; +DSPLYMNU_BLOODFADE = "Blood Flash Intensity"; +DSPLYMNU_PICKUPFADE = "Pickup Flash Intensity"; DSPLYMNU_PALLETEHACK = "DirectDraw palette hack"; // Not used DSPLYMNU_ATTACHEDSURFACES = "Use attached surfaces"; // Not used -DSPLYMNU_STRETCHSKY = "Stretch short skies"; +DSPLYMNU_SKYMODE = "Sky render mode"; DSPLYMNU_DRAWFUZZ = "Use fuzz effect"; DSPLYMNU_TRANSSOUL = "Lost Soul translucency"; DSPLYMNU_FAKECONTRAST = "Use fake contrast"; @@ -2188,6 +2190,9 @@ OPTVAL_INVERTED = "Inverted"; OPTVAL_NOTINVERTED = "Not Inverted"; OPTVAL_ORIGINAL = "Original"; OPTVAL_OPTIMIZED = "Optimized"; +OPTVAL_NORMAL = "Normal"; +OPTVAL_STRETCH = "Stretch"; +OPTVAL_CAPPED = "Capped"; OPTVAL_PARTICLES = "Particles"; OPTVAL_SPRITES = "Sprites"; OPTVAL_SPRITESPARTICLES = "Sprites & Particles"; @@ -2711,6 +2716,8 @@ OPTVAL_SBSFULL = "Side-by-side Full"; OPTVAL_SBSNARROW = "Side-by-side Narrow"; OPTVAL_TOPBOTTOM = "Top/Bottom"; OPTVAL_ROWINTERLEAVED = "Row Interleaved"; +OPTVAL_COLUMNINTERLEAVED = "Column Interleaved"; +OPTVAL_CHECKERBOARD = "Checkerboard"; OPTVAL_QUADBUFFERED = "Quad-buffered"; OPTVAL_UNCHARTED2 = "Uncharted 2"; OPTVAL_HEJLDAWSON = "Hejl Dawson"; diff --git a/wadsrc/static/menudef.txt b/wadsrc/static/menudef.txt index adcc2d29c..063225fdd 100644 --- a/wadsrc/static/menudef.txt +++ b/wadsrc/static/menudef.txt @@ -600,6 +600,13 @@ OptionValue ColumnMethods 1.0, "$OPTVAL_OPTIMIZED" } +OptionValue SkyModes +{ + 0.0, "$OPTVAL_NORMAL" + 1.0, "$OPTVAL_STRETCH" + 2.0, "$OPTVAL_CAPPED" +} + OptionValue RocketTrailTypes { 0.0, "$OPTVAL_OFF" @@ -674,6 +681,9 @@ OptionMenu "VideoOptions" Option "$DSPLYMNU_VSYNC", "vid_vsync", "OnOff" Option "$DSPLYMNU_CAPFPS", "cl_capfps", "OffOn" + Slider "$DSPLYMNU_BLOODFADE", "blood_fade_scalar", 0.0, 1.0, 0.05, 1 + Slider "$DSPLYMNU_PICKUPFADE", "pickup_fade_scalar", 0.0, 1.0, 0.05, 1 + Option "$DSPLYMNU_COLUMNMETHOD", "r_columnmethod", "ColumnMethods" StaticText " " Option "$DSPLYMNU_WIPETYPE", "wipetype", "Wipes" @@ -685,7 +695,7 @@ OptionMenu "VideoOptions" //Option "$DSPLYMNU_ATTACHEDSURFACES", "vid_attachedsurfaces", "OnOff" } - Option "$DSPLYMNU_STRETCHSKY", "r_stretchsky", "OnOff" + Option "$DSPLYMNU_SKYMODE", "r_skymode", "SkyModes" Option "$DSPLYMNU_DRAWFUZZ", "r_drawfuzz", "Fuzziness" Slider "$DSPLYMNU_TRANSSOUL", "transsouls", 0.25, 1.0, 0.05, 2 Option "$DSPLYMNU_FAKECONTRAST", "r_fakecontrast", "Contrast" @@ -704,6 +714,7 @@ OptionMenu "VideoOptions" Slider "$DSPLYMNU_MOVEBOB", "movebob", 0, 1.0, 0.05, 2 Slider "$DSPLYMNU_STILLBOB", "stillbob", 0, 1.0, 0.05, 2 Slider "$DSPLYMNU_BOBSPEED", "wbobspeed", 0, 2.0, 0.1, 2 + } //------------------------------------------------------------------------------------------- diff --git a/wadsrc/static/menudef.zz b/wadsrc/static/menudef.zz index d5c2bbc5c..c06862bc8 100644 --- a/wadsrc/static/menudef.zz +++ b/wadsrc/static/menudef.zz @@ -188,6 +188,8 @@ OptionValue VRMode 4, "$OPTVAL_SBSNARROW" 11, "$OPTVAL_TOPBOTTOM" 12, "$OPTVAL_ROWINTERLEAVED" + 13, "$OPTVAL_COLUMNINTERLEAVED" + 14, "$OPTVAL_CHECKERBOARD" 5, "$OPTVAL_LEFTEYE" 6, "$OPTVAL_RIGHTEYE" 7, "$OPTVAL_QUADBUFFERED" diff --git a/wadsrc/static/shaders/glsl/present_checker3d.fp b/wadsrc/static/shaders/glsl/present_checker3d.fp new file mode 100644 index 000000000..5247261e0 --- /dev/null +++ b/wadsrc/static/shaders/glsl/present_checker3d.fp @@ -0,0 +1,37 @@ + +in vec2 TexCoord; +out vec4 FragColor; + +uniform sampler2D LeftEyeTexture; +uniform sampler2D RightEyeTexture; +uniform float InvGamma; +uniform float Contrast; +uniform float Brightness; +uniform int WindowPositionParity; // top-of-window might not be top-of-screen + +vec4 ApplyGamma(vec4 c) +{ + vec3 val = c.rgb * Contrast - (Contrast - 1.0) * 0.5; + val += Brightness * 0.5; + val = pow(max(val, vec3(0.0)), vec3(InvGamma)); + return vec4(val, c.a); +} + +void main() +{ + int thisVerticalPixel = int(gl_FragCoord.y); // Bottom row is typically the right eye, when WindowHeight is even + int thisHorizontalPixel = int(gl_FragCoord.x); // column + bool isLeftEye = (thisVerticalPixel // because we want to alternate eye view on each row + + thisHorizontalPixel // and each column + + WindowPositionParity // because the window might not be aligned to the screen + ) % 2 == 0; + vec4 inputColor; + if (isLeftEye) { + inputColor = texture(LeftEyeTexture, TexCoord); + } + else { + // inputColor = vec4(0, 1, 0, 1); + inputColor = texture(RightEyeTexture, TexCoord); + } + FragColor = ApplyGamma(inputColor); +} diff --git a/wadsrc/static/shaders/glsl/present_column3d.fp b/wadsrc/static/shaders/glsl/present_column3d.fp new file mode 100644 index 000000000..b46246cf0 --- /dev/null +++ b/wadsrc/static/shaders/glsl/present_column3d.fp @@ -0,0 +1,35 @@ + +in vec2 TexCoord; +out vec4 FragColor; + +uniform sampler2D LeftEyeTexture; +uniform sampler2D RightEyeTexture; +uniform float InvGamma; +uniform float Contrast; +uniform float Brightness; +uniform int WindowPositionParity; // top-of-window might not be top-of-screen + +vec4 ApplyGamma(vec4 c) +{ + vec3 val = c.rgb * Contrast - (Contrast - 1.0) * 0.5; + val += Brightness * 0.5; + val = pow(max(val, vec3(0.0)), vec3(InvGamma)); + return vec4(val, c.a); +} + +void main() +{ + int thisHorizontalPixel = int(gl_FragCoord.x); // zero-based column index from left + bool isLeftEye = (thisHorizontalPixel // because we want to alternate eye view on each column + + WindowPositionParity // because the window might not be aligned to the screen + ) % 2 == 0; + vec4 inputColor; + if (isLeftEye) { + inputColor = texture(LeftEyeTexture, TexCoord); + } + else { + // inputColor = vec4(0, 1, 0, 1); + inputColor = texture(RightEyeTexture, TexCoord); + } + FragColor = ApplyGamma(inputColor); +} diff --git a/wadsrc/static/shaders/glsl/present_row3d.fp b/wadsrc/static/shaders/glsl/present_row3d.fp index 8ae72d1e0..50b27ac26 100644 --- a/wadsrc/static/shaders/glsl/present_row3d.fp +++ b/wadsrc/static/shaders/glsl/present_row3d.fp @@ -7,7 +7,7 @@ uniform sampler2D RightEyeTexture; uniform float InvGamma; uniform float Contrast; uniform float Brightness; -uniform int VerticalPixelOffset; // top-of-window might not be top-of-screen +uniform int WindowPositionParity; // top-of-window might not be top-of-screen vec4 ApplyGamma(vec4 c) { @@ -19,9 +19,9 @@ vec4 ApplyGamma(vec4 c) void main() { - int thisVerticalPixel = int(gl_FragCoord.y + 1.0); // Bottom row is typically the right eye, when WindowHeight is even + int thisVerticalPixel = int(gl_FragCoord.y); // Bottom row is typically the right eye, when WindowHeight is even bool isLeftEye = (thisVerticalPixel // because we want to alternate eye view on each row - + VerticalPixelOffset // because the window might not be aligned to the screen + + WindowPositionParity // because the window might not be aligned to the screen ) % 2 == 0; vec4 inputColor; if (isLeftEye) {