From 98e6330eaac751b0cf648f13f18c7ee0383e335c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ricardo=20Lu=C3=ADs=20Vaz=20Silva?= Date: Fri, 5 Jan 2024 09:46:15 -0300 Subject: [PATCH] allow modeldef flags to be overriden --- src/common/models/model.h | 5 ++ src/common/models/modelrenderer.h | 8 +-- src/playsim/actor.h | 5 +- src/playsim/p_actionfunctions.cpp | 70 +++++++++++++++++-- src/r_data/models.cpp | 59 ++++++++++------ src/rendering/hwrenderer/hw_models.cpp | 16 ++--- src/rendering/hwrenderer/hw_models.h | 8 +-- .../hwrenderer/scene/hw_drawstructs.h | 1 + src/rendering/hwrenderer/scene/hw_sprites.cpp | 3 +- wadsrc/static/zscript/actors/actor.zs | 4 ++ wadsrc/static/zscript/constants.zs | 23 ++++++ 11 files changed, 156 insertions(+), 46 deletions(-) diff --git a/src/common/models/model.h b/src/common/models/model.h index 84adab5565..f5bbf43db0 100644 --- a/src/common/models/model.h +++ b/src/common/models/model.h @@ -41,7 +41,9 @@ struct FSpriteModelFrame float xrotate, yrotate, zrotate; float rotationCenterX, rotationCenterY, rotationCenterZ; float rotationSpeed; +private: unsigned int flags; +public: const void* type; // used for hashing, must point to something usable as identifier for the model's owner. short sprite; short frame; @@ -50,6 +52,9 @@ struct FSpriteModelFrame // added pithoffset, rolloffset. float pitchoffset, rolloffset; // I don't want to bother with type transformations, so I made this variables float. bool isVoxel; + unsigned int getFlags(class DActorModelData * defs) const; + friend void InitModels(); + friend void ParseModelDefLump(int Lump); }; diff --git a/src/common/models/modelrenderer.h b/src/common/models/modelrenderer.h index 3a8388e723..d2d774eab9 100644 --- a/src/common/models/modelrenderer.h +++ b/src/common/models/modelrenderer.h @@ -10,15 +10,15 @@ public: virtual ModelRendererType GetType() const = 0; - virtual void BeginDrawModel(FRenderStyle style, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) = 0; - virtual void EndDrawModel(FRenderStyle style, FSpriteModelFrame *smf) = 0; + virtual void BeginDrawModel(FRenderStyle style, int smf_flags, const VSMatrix &objectToWorldMatrix, bool mirrored) = 0; + virtual void EndDrawModel(FRenderStyle style, int smf_flags) = 0; virtual IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) = 0; virtual VSMatrix GetViewToWorldMatrix() = 0; - virtual void BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored, FSpriteModelFrame *smf) = 0; - virtual void EndDrawHUDModel(FRenderStyle style, FSpriteModelFrame *smf) = 0; + virtual void BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored, int smf_flags) = 0; + virtual void EndDrawHUDModel(FRenderStyle style, int smf_flags) = 0; virtual void SetInterpolation(double interpolation) = 0; virtual void SetMaterial(FGameTexture *skin, bool clampNoFilter, FTranslationID translation) = 0; diff --git a/src/playsim/actor.h b/src/playsim/actor.h index 9c8ca78836..43e8b5b2e6 100644 --- a/src/playsim/actor.h +++ b/src/playsim/actor.h @@ -719,18 +719,21 @@ struct ModelOverride enum EModelDataFlags { MODELDATA_HADMODEL = 1 << 0, + MODELDATA_OVERRIDE_FLAGS = 1 << 1, }; class DActorModelData : public DObject { DECLARE_CLASS(DActorModelData, DObject); public: - FName modelDef; + PClass * modelDef; TArray models; TArray skinIDs; TArray animationIDs; TArray modelFrameGenerators; int flags; + int overrideFlagsSet; + int overrideFlagsClear; AnimOverride curAnim; AnimOverride prevAnim; // used for interpolation when switching anims diff --git a/src/playsim/p_actionfunctions.cpp b/src/playsim/p_actionfunctions.cpp index 6875437122..4c842d3bba 100644 --- a/src/playsim/p_actionfunctions.cpp +++ b/src/playsim/p_actionfunctions.cpp @@ -5096,7 +5096,7 @@ static void EnsureModelData(AActor * mobj) auto ptr = Create(); ptr->flags = (mobj->hasmodel ? MODELDATA_HADMODEL : 0); - ptr->modelDef = NAME_None; + ptr->modelDef = nullptr; mobj->modelData = ptr; mobj->hasmodel = true; @@ -5111,7 +5111,8 @@ static void CleanupModelData(AActor * mobj) && mobj->modelData->modelFrameGenerators.Size() == 0 && mobj->modelData->skinIDs.Size() == 0 && mobj->modelData->animationIDs.Size() == 0 - && mobj->modelData->modelDef == NAME_None) + && mobj->modelData->modelDef == nullptr + &&(mobj->modelData->flags & ~MODELDATA_HADMODEL) == 0 ) { mobj->hasmodel = mobj->modelData->flags & MODELDATA_HADMODEL; mobj->modelData->Destroy(); @@ -5123,6 +5124,8 @@ enum ESetAnimationFlags { SAF_INSTANT = 1 << 0, SAF_LOOP = 1 << 1, + SAF_USEACTORROLL = 1 << 2, + SAF_USEACTORPITCH = 1 << 3, }; void SetAnimationInternal(AActor * self, FName animName, double framerate, int startFrame, int loopFrame, int interpolateTics, int flags, double ticFrac) @@ -5265,6 +5268,32 @@ void SetAnimationFrameRateUINative(AActor * self, double framerate) SetAnimationFrameRateInternal(self, framerate, I_GetTimeFrac()); } +void SetModelFlag(AActor * self, int flag) +{ + EnsureModelData(self); + self->modelData->flags |= MODELDATA_OVERRIDE_FLAGS; + self->modelData->overrideFlagsSet |= flag; + self->modelData->overrideFlagsClear &= ~flag; +} + +void ClearModelFlag(AActor * self, int flag) +{ + EnsureModelData(self); + self->modelData->flags |= MODELDATA_OVERRIDE_FLAGS; + self->modelData->overrideFlagsClear |= flag; + self->modelData->overrideFlagsSet &= ~flag; +} + +void ResetModelFlags(AActor * self) +{ + if(self->modelData) + { + self->modelData->overrideFlagsClear = 0; + self->modelData->overrideFlagsSet = 0; + self->modelData->flags &= ~MODELDATA_OVERRIDE_FLAGS; + } +} + enum ChangeModelFlags { CMDL_WEAPONTOPLAYER = 1 << 0, @@ -5291,14 +5320,16 @@ void ChangeModelNative( ) { if(!self) ThrowAbortException(X_READ_NIL, "In function parameter self"); - FName modeldef { ENamedName(i_modeldef) }; + FName n_modeldef { ENamedName(i_modeldef) }; FName model { ENamedName(i_model) }; FName skin { ENamedName(i_skin) }; FName animation { ENamedName(i_animation) }; - if (modeldef != NAME_None && PClass::FindClass(modeldef.GetChars()) == nullptr) + PClass * modeldef = nullptr; + + if (n_modeldef != NAME_None && (modeldef = PClass::FindActor(n_modeldef.GetChars())) == nullptr) { - Printf("Attempt to pass invalid modeldef name %s in %s.", modeldef.GetChars(), self->GetCharacterName()); + Printf("Attempt to pass invalid modeldef name %s in %s.", n_modeldef.GetChars(), self->GetCharacterName()); return; } @@ -5533,6 +5564,35 @@ DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetAnimationFrameRateUI, SetAnimationFrame return 0; } +DEFINE_ACTION_FUNCTION_NATIVE(AActor, SetModelFlag, SetModelFlag) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT(flag); + + SetModelFlag(self, flag); + + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, ClearModelFlag, ClearModelFlag) +{ + PARAM_ACTION_PROLOGUE(AActor); + PARAM_INT(flag); + + ClearModelFlag(self, flag); + + return 0; +} + +DEFINE_ACTION_FUNCTION_NATIVE(AActor, ResetModelFlags, ResetModelFlags) +{ + PARAM_ACTION_PROLOGUE(AActor); + + ResetModelFlags(self); + + return 0; +} + // This needs to account for the fact that internally renderstyles are stored as a series of operations, // but the script side only cares about symbolic constants. DEFINE_ACTION_FUNCTION(AActor, GetRenderStyle) diff --git a/src/r_data/models.cpp b/src/r_data/models.cpp index 0cfb14b0ae..3cca0791ca 100644 --- a/src/r_data/models.cpp +++ b/src/r_data/models.cpp @@ -63,8 +63,10 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod { // Setup transformation. + int smf_flags = smf->getFlags(actor->modelData); + FTranslationID translation = NO_TRANSLATION; - if (!(smf->flags & MDL_IGNORETRANSLATION)) + if (!(smf_flags & MDL_IGNORETRANSLATION)) translation = actor->Translation; // y scale for a sprite means height, i.e. z in the world! @@ -82,7 +84,7 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod float angle = angles.Yaw.Degrees(); // [BB] Workaround for the missing pitch information. - if ((smf->flags & MDL_PITCHFROMMOMENTUM)) + if ((smf_flags & MDL_PITCHFROMMOMENTUM)) { const double x = actor->Vel.X; const double y = actor->Vel.Y; @@ -102,7 +104,7 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod } } - if (smf->flags & MDL_ROTATING) + if (smf_flags & MDL_ROTATING) { if (smf->rotationSpeed > 0.0000000001 || smf->rotationSpeed < -0.0000000001) { @@ -118,13 +120,13 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod // Added MDL_USEACTORPITCH and MDL_USEACTORROLL flags processing. // If both flags MDL_USEACTORPITCH and MDL_PITCHFROMMOMENTUM are set, the pitch sums up the actor pitch and the velocity vector pitch. - if (smf->flags & MDL_USEACTORPITCH) + if (smf_flags & MDL_USEACTORPITCH) { double d = angles.Pitch.Degrees(); - if (smf->flags & MDL_BADROTATION) pitch += d; + if (smf_flags & MDL_BADROTATION) pitch += d; else pitch -= d; } - if (smf->flags & MDL_USEACTORROLL) roll += angles.Roll.Degrees(); + if (smf_flags & MDL_USEACTORROLL) roll += angles.Roll.Degrees(); VSMatrix objectToWorldMatrix; objectToWorldMatrix.loadIdentity(); @@ -140,7 +142,7 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod // [MK] distortions might happen depending on when the pixel stretch is compensated for // so we make the "undistorted" behavior opt-in - if (smf->flags & MDL_CORRECTPIXELSTRETCH) + if (smf_flags & MDL_CORRECTPIXELSTRETCH) { stretch = (smf->modelIDs[0] != -1 ? Models[smf->modelIDs[0]]->getAspectFactor(actor->Level->info->pixelstretch) : 1.f) / actor->Level->info->pixelstretch; objectToWorldMatrix.scale(1, stretch, 1); @@ -148,14 +150,14 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod // Applying model transformations: // 1) Applying actor angle, pitch and roll to the model - if (smf->flags & MDL_USEROTATIONCENTER) + if (smf_flags & MDL_USEROTATIONCENTER) { objectToWorldMatrix.translate(smf->rotationCenterX, smf->rotationCenterZ/stretch, smf->rotationCenterY); } objectToWorldMatrix.rotate(-angle, 0, 1, 0); objectToWorldMatrix.rotate(pitch, 0, 0, 1); objectToWorldMatrix.rotate(-roll, 1, 0, 0); - if (smf->flags & MDL_USEROTATIONCENTER) + if (smf_flags & MDL_USEROTATIONCENTER) { objectToWorldMatrix.translate(-smf->rotationCenterX, -smf->rotationCenterZ/stretch, -smf->rotationCenterY); } @@ -163,7 +165,7 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod // 2) Applying Doomsday like rotation of the weapon pickup models // The rotation angle is based on the elapsed time. - if (smf->flags & MDL_ROTATING) + if (smf_flags & MDL_ROTATING) { objectToWorldMatrix.translate(smf->rotationCenterX, smf->rotationCenterY/stretch, smf->rotationCenterZ); objectToWorldMatrix.rotate(rotateOffset, smf->xrotate, smf->yrotate, smf->zrotate); @@ -181,7 +183,7 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod objectToWorldMatrix.rotate(smf->pitchoffset, 0, 0, 1); objectToWorldMatrix.rotate(-smf->rolloffset, 1, 0, 0); - if (!(smf->flags & MDL_CORRECTPIXELSTRETCH)) + if (!(smf_flags & MDL_CORRECTPIXELSTRETCH)) { stretch = (smf->modelIDs[0] != -1 ? Models[smf->modelIDs[0]]->getAspectFactor(actor->Level->info->pixelstretch) : 1.f) / actor->Level->info->pixelstretch; objectToWorldMatrix.scale(1, stretch, 1); @@ -189,15 +191,17 @@ void RenderModel(FModelRenderer *renderer, float x, float y, float z, FSpriteMod float orientation = scaleFactorX * scaleFactorY * scaleFactorZ; - renderer->BeginDrawModel(actor->RenderStyle, smf, objectToWorldMatrix, orientation < 0); + renderer->BeginDrawModel(actor->RenderStyle, smf_flags, objectToWorldMatrix, orientation < 0); RenderFrameModels(renderer, actor->Level, smf, actor->state, actor->tics, translation, actor); - renderer->EndDrawModel(actor->RenderStyle, smf); + renderer->EndDrawModel(actor->RenderStyle, smf_flags); } void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, FVector3 translation, FVector3 rotation, FVector3 rotation_pivot, FSpriteModelFrame *smf) { AActor * playermo = players[consoleplayer].camera; + int smf_flags = smf->getFlags(psp->Caller->modelData); + // [BB] No model found for this sprite, so we can't render anything. if (smf == nullptr) return; @@ -208,7 +212,7 @@ void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, FVector3 translatio // [Nash] Optional scale weapon FOV float fovscale = 1.0f; - if (smf->flags & MDL_SCALEWEAPONFOV) + if (smf_flags & MDL_SCALEWEAPONFOV) { fovscale = tan(players[consoleplayer].DesiredFOV * (0.5f * M_PI / 180.f)); fovscale = 1.f + (fovscale - 1.f) * cl_scaleweaponfov; @@ -245,12 +249,12 @@ void RenderHUDModel(FModelRenderer *renderer, DPSprite *psp, FVector3 translatio float orientation = smf->xscale * smf->yscale * smf->zscale; - renderer->BeginDrawHUDModel(playermo->RenderStyle, objectToWorldMatrix, orientation < 0, smf); + renderer->BeginDrawHUDModel(playermo->RenderStyle, objectToWorldMatrix, orientation < 0, smf_flags); auto trans = psp->GetTranslation(); if ((psp->Flags & PSPF_PLAYERTRANSLATED)) trans = psp->Owner->mo->Translation; RenderFrameModels(renderer, playermo->Level, smf, psp->GetState(), psp->GetTics(), trans, psp->Caller); - renderer->EndDrawHUDModel(playermo->RenderStyle, smf); + renderer->EndDrawHUDModel(playermo->RenderStyle, smf_flags); } double getCurrentFrame(const AnimOverride &anim, double tic) @@ -295,6 +299,9 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr { // [BB] Frame interpolation: Find the FSpriteModelFrame smfNext which follows after smf in the animation // and the scalar value inter ( element of [0,1) ), both necessary to determine the interpolated frame. + + int smf_flags = smf->getFlags(actor->modelData); + const FSpriteModelFrame * smfNext = nullptr; double inter = 0.; double inter_main = -1.f; @@ -334,7 +341,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr } } } - else if (gl_interpolate_model_frames && !(smf->flags & MDL_NOINTERPOLATION)) + else if (gl_interpolate_model_frames && !(smf_flags & MDL_NOINTERPOLATION)) { FState *nextState = curState->GetNextState(); if (curState != nextState && nextState) @@ -356,7 +363,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr { // [BB] Workaround for actors that use the same frame twice in a row. // Most of the standard Doom monsters do this in their see state. - if ((smf->flags & MDL_INTERPOLATEDOUBLEDFRAMES)) + if ((smf_flags & MDL_INTERPOLATEDOUBLEDFRAMES)) { const FState *prevState = curState - 1; if ((curState->sprite == prevState->sprite) && (curState->Frame == prevState->Frame)) @@ -522,7 +529,7 @@ void RenderFrameModels(FModelRenderer *renderer, FLevelLocals *Level, const FSpr } // [RL0] while per-model animations aren't done, DECOUPLEDANIMATIONS does the same as MODELSAREATTACHMENTS - if ((!(smf->flags & MDL_MODELSAREATTACHMENTS) && !is_decoupled) || !evaluatedSingle) + if ((!(smf_flags & MDL_MODELSAREATTACHMENTS) && !is_decoupled) || !evaluatedSingle) { if (animationid >= 0) { @@ -576,7 +583,7 @@ static TArray SpriteModelHash; // //=========================================================================== -static void ParseModelDefLump(int Lump); +void ParseModelDefLump(int Lump); void InitModels() { @@ -658,7 +665,7 @@ void InitModels() } } -static void ParseModelDefLump(int Lump) +void ParseModelDefLump(int Lump) { FScanner sc(Lump); while (sc.GetString()) @@ -1117,11 +1124,11 @@ FSpriteModelFrame * FindModelFrame(const AActor * thing, int sprite, int frame, if(thing->flags9 & MF9_DECOUPLEDANIMATIONS) { - return &BaseSpriteModelFrames[thing->GetClass()]; + return &BaseSpriteModelFrames[(thing->modelData != nullptr && thing->modelData->modelDef != nullptr) ? thing->modelData->modelDef : thing->GetClass()]; } else { - return FindModelFrameRaw((thing->modelData != nullptr && thing->modelData->modelDef != NAME_None) ? PClass::FindActor(thing->modelData->modelDef) : thing->GetClass(), sprite, frame, dropped); + return FindModelFrameRaw((thing->modelData != nullptr && thing->modelData->modelDef != nullptr) ? thing->modelData->modelDef : thing->GetClass(), sprite, frame, dropped); } } @@ -1143,3 +1150,9 @@ bool IsHUDModelForPlayerAvailable (player_t * player) } return false; } + + +unsigned int FSpriteModelFrame::getFlags(class DActorModelData * defs) const +{ + return (defs && defs->flags & MODELDATA_OVERRIDE_FLAGS)? (flags | defs->overrideFlagsSet) & ~(defs->overrideFlagsClear) : flags; +} \ No newline at end of file diff --git a/src/rendering/hwrenderer/hw_models.cpp b/src/rendering/hwrenderer/hw_models.cpp index d383f07779..06ce5942e9 100644 --- a/src/rendering/hwrenderer/hw_models.cpp +++ b/src/rendering/hwrenderer/hw_models.cpp @@ -53,7 +53,7 @@ VSMatrix FHWModelRenderer::GetViewToWorldMatrix() return objectToWorldMatrix; } -void FHWModelRenderer::BeginDrawModel(FRenderStyle style, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) +void FHWModelRenderer::BeginDrawModel(FRenderStyle style, int smf_flags, const VSMatrix &objectToWorldMatrix, bool mirrored) { state.SetDepthFunc(DF_LEqual); state.EnableTexture(true); @@ -61,7 +61,7 @@ void FHWModelRenderer::BeginDrawModel(FRenderStyle style, FSpriteModelFrame *smf // This solves a few of the problems caused by the lack of depth sorting. // [Nash] Don't do back face culling if explicitly specified in MODELDEF // TO-DO: Implement proper depth sorting. - if ((smf->flags & MDL_FORCECULLBACKFACES) || (!(style == DefaultRenderStyle()) && !(smf->flags & MDL_DONTCULLBACKFACES))) + if ((smf_flags & MDL_FORCECULLBACKFACES) || (!(style == DefaultRenderStyle()) && !(smf_flags & MDL_DONTCULLBACKFACES))) { state.SetCulling((mirrored ^ portalState.isMirrored()) ? Cull_CCW : Cull_CW); } @@ -70,16 +70,16 @@ void FHWModelRenderer::BeginDrawModel(FRenderStyle style, FSpriteModelFrame *smf state.EnableModelMatrix(true); } -void FHWModelRenderer::EndDrawModel(FRenderStyle style, FSpriteModelFrame *smf) +void FHWModelRenderer::EndDrawModel(FRenderStyle style, int smf_flags) { state.SetBoneIndexBase(-1); state.EnableModelMatrix(false); state.SetDepthFunc(DF_Less); - if ((smf->flags & MDL_FORCECULLBACKFACES) || (!(style == DefaultRenderStyle()) && !(smf->flags & MDL_DONTCULLBACKFACES))) + if ((smf_flags & MDL_FORCECULLBACKFACES) || (!(style == DefaultRenderStyle()) && !(smf_flags & MDL_DONTCULLBACKFACES))) state.SetCulling(Cull_None); } -void FHWModelRenderer::BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored, FSpriteModelFrame *smf) +void FHWModelRenderer::BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored, int smf_flags) { state.SetDepthFunc(DF_LEqual); state.SetDepthClamp(true); @@ -87,7 +87,7 @@ void FHWModelRenderer::BeginDrawHUDModel(FRenderStyle style, const VSMatrix &obj // [BB] In case the model should be rendered translucent, do back face culling. // This solves a few of the problems caused by the lack of depth sorting. // TO-DO: Implement proper depth sorting. - if (!(style == DefaultRenderStyle()) || (smf->flags & MDL_FORCECULLBACKFACES)) + if (!(style == DefaultRenderStyle()) || (smf_flags & MDL_FORCECULLBACKFACES)) { state.SetCulling((mirrored ^ portalState.isMirrored()) ? Cull_CW : Cull_CCW); } @@ -96,13 +96,13 @@ void FHWModelRenderer::BeginDrawHUDModel(FRenderStyle style, const VSMatrix &obj state.EnableModelMatrix(true); } -void FHWModelRenderer::EndDrawHUDModel(FRenderStyle style, FSpriteModelFrame *smf) +void FHWModelRenderer::EndDrawHUDModel(FRenderStyle style, int smf_flags) { state.SetBoneIndexBase(-1); state.EnableModelMatrix(false); state.SetDepthFunc(DF_Less); - if (!(style == DefaultRenderStyle()) || (smf->flags & MDL_FORCECULLBACKFACES)) + if (!(style == DefaultRenderStyle()) || (smf_flags & MDL_FORCECULLBACKFACES)) state.SetCulling(Cull_None); } diff --git a/src/rendering/hwrenderer/hw_models.h b/src/rendering/hwrenderer/hw_models.h index c2c80bd752..c3e5125da6 100644 --- a/src/rendering/hwrenderer/hw_models.h +++ b/src/rendering/hwrenderer/hw_models.h @@ -46,12 +46,12 @@ public: FHWModelRenderer(HWDrawInfo *d, FRenderState &st, int mli) : modellightindex(mli), di(d), state(st) {} ModelRendererType GetType() const override { return GLModelRendererType; } - void BeginDrawModel(FRenderStyle style, FSpriteModelFrame *smf, const VSMatrix &objectToWorldMatrix, bool mirrored) override; - void EndDrawModel(FRenderStyle style, FSpriteModelFrame *smf) override; + void BeginDrawModel(FRenderStyle style, int smf_flags, const VSMatrix &objectToWorldMatrix, bool mirrored) override; + void EndDrawModel(FRenderStyle style, int smf_flags) override; IModelVertexBuffer *CreateVertexBuffer(bool needindex, bool singleframe) override; VSMatrix GetViewToWorldMatrix() override; - void BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored, FSpriteModelFrame *smf) override; - void EndDrawHUDModel(FRenderStyle style, FSpriteModelFrame *smf) override; + void BeginDrawHUDModel(FRenderStyle style, const VSMatrix &objectToWorldMatrix, bool mirrored, int smf_flags) override; + void EndDrawHUDModel(FRenderStyle style, int smf_flags) override; void SetInterpolation(double interpolation) override; void SetMaterial(FGameTexture *skin, bool clampNoFilter, FTranslationID translation) override; void DrawArrays(int start, int count) override; diff --git a/src/rendering/hwrenderer/scene/hw_drawstructs.h b/src/rendering/hwrenderer/scene/hw_drawstructs.h index 04179d2505..a025c87c91 100644 --- a/src/rendering/hwrenderer/scene/hw_drawstructs.h +++ b/src/rendering/hwrenderer/scene/hw_drawstructs.h @@ -365,6 +365,7 @@ public: PalEntry ThingColor; // thing's own color FColormap Colormap; FSpriteModelFrame * modelframe; + int modelframeflags; FRenderStyle RenderStyle; int OverrideShader; diff --git a/src/rendering/hwrenderer/scene/hw_sprites.cpp b/src/rendering/hwrenderer/scene/hw_sprites.cpp index 472a4f607c..8735c0f469 100644 --- a/src/rendering/hwrenderer/scene/hw_sprites.cpp +++ b/src/rendering/hwrenderer/scene/hw_sprites.cpp @@ -507,7 +507,7 @@ bool HWSprite::CalculateVertices(HWDrawInfo *di, FVector3 *v, DVector3 *vp) inline void HWSprite::PutSprite(HWDrawInfo *di, bool translucent) { // That's a lot of checks... - if (modelframe && !modelframe->isVoxel && !(modelframe->flags & MDL_NOPERPIXELLIGHTING) && RenderStyle.BlendOp != STYLEOP_Shadow && gl_light_sprites && di->Level->HasDynamicLights && !di->isFullbrightScene() && !fullbright) + if (modelframe && !modelframe->isVoxel && !(modelframeflags & MDL_NOPERPIXELLIGHTING) && RenderStyle.BlendOp != STYLEOP_Shadow && gl_light_sprites && di->Level->HasDynamicLights && !di->isFullbrightScene() && !fullbright) { hw_GetDynModelLight(actor, lightdata); dynlightindex = screen->mLights->UploadLights(lightdata); @@ -797,6 +797,7 @@ void HWSprite::Process(HWDrawInfo *di, AActor* thing, sector_t * sector, area_t } modelframe = isPicnumOverride ? nullptr : FindModelFrame(thing, spritenum, thing->frame, !!(thing->flags & MF_DROPPED)); + modelframeflags = modelframe ? modelframe->getFlags(thing->modelData) : 0; // Too close to the camera. This doesn't look good if it is a sprite. if (fabs(thingpos.X - vp.Pos.X) < 2 && fabs(thingpos.Y - vp.Pos.Y) < 2 diff --git a/wadsrc/static/zscript/actors/actor.zs b/wadsrc/static/zscript/actors/actor.zs index 5855543023..a89072066a 100644 --- a/wadsrc/static/zscript/actors/actor.zs +++ b/wadsrc/static/zscript/actors/actor.zs @@ -1300,6 +1300,10 @@ class Actor : Thinker native native version("4.12") void SetAnimationFrameRate(double framerate); native version("4.12") ui void SetAnimationFrameRateUI(double framerate); + native version("4.12") void SetModelFlag(int flag); + native version("4.12") void ClearModelFlag(int flag); + native version("4.12") void ResetModelFlags(); + int ACS_NamedExecute(name script, int mapnum=0, int arg1=0, int arg2=0, int arg3=0) { return ACS_Execute(-int(script), mapnum, arg1, arg2, arg3); diff --git a/wadsrc/static/zscript/constants.zs b/wadsrc/static/zscript/constants.zs index 85239ef044..71b0fb99df 100644 --- a/wadsrc/static/zscript/constants.zs +++ b/wadsrc/static/zscript/constants.zs @@ -1470,3 +1470,26 @@ const WATER_SINK_FACTOR = 0.125; const WATER_SINK_SMALL_FACTOR = 0.25; const WATER_SINK_SPEED = 0.5; const WATER_JUMP_SPEED = 3.5; + + +// for SetModelFlag/ClearModelFlag +enum EModelFlags +{ + // [BB] Color translations for the model skin are ignored. This is + // useful if the skin texture is not using the game palette. + MDL_IGNORETRANSLATION = 1<<0, + MDL_PITCHFROMMOMENTUM = 1<<1, + MDL_ROTATING = 1<<2, + MDL_INTERPOLATEDOUBLEDFRAMES = 1<<3, + MDL_NOINTERPOLATION = 1<<4, + MDL_USEACTORPITCH = 1<<5, + MDL_USEACTORROLL = 1<<6, + MDL_BADROTATION = 1<<7, + MDL_DONTCULLBACKFACES = 1<<8, + MDL_USEROTATIONCENTER = 1<<9, + MDL_NOPERPIXELLIGHTING = 1<<10, // forces a model to not use per-pixel lighting. useful for voxel-converted-to-model objects. + MDL_SCALEWEAPONFOV = 1<<11, // scale weapon view model with higher user FOVs + MDL_MODELSAREATTACHMENTS = 1<<12, // any model index after 0 is treated as an attachment, and therefore will use the bone results of index 0 + MDL_CORRECTPIXELSTRETCH = 1<<13, // ensure model does not distort with pixel stretch when pitch/roll is applied + MDL_FORCECULLBACKFACES = 1<<14, +}; \ No newline at end of file