diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8702753248..50d873ffd5 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1214,6 +1214,7 @@ set (PCH_SOURCES scripting/zscript/zcc_expr.cpp scripting/zscript/zcc_parser.cpp sfmt/SFMT.cpp + events.cpp ) enable_precompiled_headers( g_pch.h PCH_SOURCES ) diff --git a/src/d_main.cpp b/src/d_main.cpp index 971e0ece0e..6760195db7 100644 --- a/src/d_main.cpp +++ b/src/d_main.cpp @@ -110,6 +110,7 @@ #include "autosegs.h" #include "fragglescript/t_fs.h" #include "g_levellocals.h" +#include "events.h" EXTERN_CVAR(Bool, hud_althud) void DrawHUD(); @@ -775,6 +776,9 @@ void D_Display () screen->SetBlendingRect(viewwindowx, viewwindowy, viewwindowx + viewwidth, viewwindowy + viewheight); + // [ZZ] execute event hook that we just started the frame + E_RenderFrame(); + // Renderer->RenderView(&players[consoleplayer]); if ((hw2d = screen->Begin2D(viewactive))) diff --git a/src/events.cpp b/src/events.cpp new file mode 100755 index 0000000000..9de70eb033 --- /dev/null +++ b/src/events.cpp @@ -0,0 +1,184 @@ +#include "events.h" +#include "virtual.h" +#include "r_utility.h" + +DEventHandler* E_FirstDEventHandler = nullptr; + +void E_RegisterHandler(DEventHandler* handler) +{ + if (handler == nullptr || handler->ObjectFlags & OF_EuthanizeMe) + return; + // link into normal list + handler->prev = nullptr; + handler->next = E_FirstDEventHandler; + if (handler->next) + handler->next->prev = handler; + E_FirstDEventHandler = handler; +} + +void E_UnregisterHandler(DEventHandler* handler) +{ + if (handler == nullptr || handler->ObjectFlags & OF_EuthanizeMe) + return; + // link out of normal list + if (handler->prev) + handler->prev->next = handler->next; + if (handler->next) + handler->next->prev = handler->prev; + if (handler == E_FirstDEventHandler) + E_FirstDEventHandler = handler->next; +} + +void E_MapLoaded() +{ + for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + handler->MapLoaded(); +} + +void E_MapUnloading() +{ + for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + handler->MapUnloading(); +} + +void E_RenderFrame() +{ + for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + handler->RenderFrame(); +} + +void E_RenderCamera() +{ + for (DEventHandler* handler = E_FirstDEventHandler; handler; handler = handler->next) + handler->RenderCamera(); +} + +// declarations +IMPLEMENT_CLASS(DEventHandler, false, false); +IMPLEMENT_CLASS(DRenderEventHandler, false, false); + +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewPos); +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewAngle); +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewPitch); +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, ViewRoll); +DEFINE_FIELD_X(RenderEventHandler, DRenderEventHandler, FracTic); + +DEFINE_ACTION_FUNCTION(DEventHandler, Create) +{ + PARAM_PROLOGUE; + PARAM_CLASS(t, DEventHandler); + // generate a new object of this type. + ACTION_RETURN_OBJECT(t->CreateNew()); +} + +DEFINE_ACTION_FUNCTION(DEventHandler, Register) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(handler, DEventHandler); + E_RegisterHandler(handler); + return 0; +} + +DEFINE_ACTION_FUNCTION(DEventHandler, Unregister) +{ + PARAM_PROLOGUE; + PARAM_OBJECT(handler, DEventHandler); + E_UnregisterHandler(handler); + return 0; +} + +DEFINE_ACTION_FUNCTION(DEventHandler, MapLoaded) +{ + PARAM_SELF_PROLOGUE(DEventHandler); + // do nothing + return 0; +} + +DEFINE_ACTION_FUNCTION(DEventHandler, MapUnloading) +{ + PARAM_SELF_PROLOGUE(DEventHandler); + // do nothing + return 0; +} + +DEFINE_ACTION_FUNCTION(DEventHandler, RenderFrame) +{ + PARAM_SELF_PROLOGUE(DEventHandler); + // do nothing + return 0; +} + +DEFINE_ACTION_FUNCTION(DEventHandler, RenderCamera) +{ + PARAM_SELF_PROLOGUE(DEventHandler); + // do nothing + return 0; +} + +// +void DEventHandler::OnDestroy() +{ + E_UnregisterHandler(this); + DObject::OnDestroy(); +} + +void DEventHandler::MapLoaded() +{ + IFVIRTUAL(DEventHandler, MapLoaded) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DEventHandler*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } +} + +void DEventHandler::MapUnloading() +{ + IFVIRTUAL(DEventHandler, MapUnloading) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DEventHandler*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } +} + +void DEventHandler::RenderFrame() +{ + IFVIRTUAL(DEventHandler, RenderFrame) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DEventHandler*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } +} + +void DEventHandler::RenderCamera() +{ + IFVIRTUAL(DEventHandler, RenderCamera) + { + // Without the type cast this picks the 'void *' assignment... + VMValue params[1] = { (DEventHandler*)this }; + GlobalVMStack.Call(func, params, 1, nullptr, 0, nullptr); + } +} + +void DRenderEventHandler::Setup() +{ + ViewPos = ::ViewPos; + ViewAngle = ::ViewAngle; + ViewPitch = ::ViewPitch; + ViewRoll = ::ViewRoll; + FracTic = ::r_TicFracF; +} + +void DRenderEventHandler::RenderFrame() +{ + Setup(); + DEventHandler::RenderFrame(); +} + +void DRenderEventHandler::RenderCamera() +{ + Setup(); + DEventHandler::RenderCamera(); +} diff --git a/src/events.h b/src/events.h new file mode 100755 index 0000000000..b254ddfaf4 --- /dev/null +++ b/src/events.h @@ -0,0 +1,60 @@ +#ifndef EVENTS_H +#define EVENTS_H + +#include "dobject.h" + +class DEventHandler : public DObject // make it a part of normal GC process +{ + DECLARE_CLASS(DEventHandler, DObject) +public: + DEventHandler* prev; + DEventHandler* next; + DEventHandler* unregPrev; + DEventHandler* unregNext; + + // destroy handler. this unlinks EventHandler from the list automatically. + void OnDestroy() override; + + // called right after the map has loaded (approximately same time as OPEN ACS scripts) + virtual void MapLoaded(); + // called when the map is about to unload (approximately same time as UNLOADING ACS scripts) + virtual void MapUnloading(); + // called on each render frame once. + virtual void RenderFrame(); + // called before entering each actor's view (including RenderFrame) + virtual void RenderCamera(); +}; +extern DEventHandler* E_FirstEventHandler; + +class DRenderEventHandler : public DEventHandler +{ + DECLARE_CLASS(DRenderEventHandler, DEventHandler) +public: + DVector3 ViewPos; + DAngle ViewAngle; + DAngle ViewPitch; + DAngle ViewRoll; + double FracTic; // 0..1 value that describes where we are inside the current gametic, render-wise. + + void RenderFrame() override; + void RenderCamera() override; + +private: + void Setup(); +}; + +// register +void E_RegisterHandler(DEventHandler* handler); +// unregister +void E_UnregisterHandler(DEventHandler* handler); + +// called right after the map has loaded (approximately same time as OPEN ACS scripts) +void E_MapLoaded(); +// called when the map is about to unload (approximately same time as UNLOADING ACS scripts) +void E_MapUnloading(); +// called on each render frame once. +void E_RenderFrame(); +// called before entering each actor's view (including RenderFrame) +void E_RenderCamera(); + +#endif \ No newline at end of file diff --git a/src/gl/scene/gl_scene.cpp b/src/gl/scene/gl_scene.cpp index b67cf810ef..f3b37ffb59 100644 --- a/src/gl/scene/gl_scene.cpp +++ b/src/gl/scene/gl_scene.cpp @@ -44,6 +44,7 @@ #include "gl/gl_functions.h" #include "serializer.h" #include "g_levellocals.h" +#include "events.h" #include "gl/dynlights/gl_lightbuffer.h" #include "gl/system/gl_interface.h" @@ -477,6 +478,9 @@ void FGLRenderer::RenderTranslucent() void FGLRenderer::DrawScene(int drawmode) { + // [ZZ] call event hook + E_RenderCamera(); + static int recursion=0; static int ssao_portals_available = 0; diff --git a/src/r_main.cpp b/src/r_main.cpp index 7030339c7e..11e7cfc094 100644 --- a/src/r_main.cpp +++ b/src/r_main.cpp @@ -59,6 +59,7 @@ #include "r_data/colormaps.h" #include "p_maputl.h" #include "r_thread.h" +#include "events.h" CVAR (String, r_viewsize, "", CVAR_NOSET) CVAR (Bool, r_shadercolormaps, true, CVAR_ARCHIVE) @@ -840,6 +841,9 @@ void R_RenderActorView (AActor *actor, bool dontmaplines) R_SetupBuffer (); R_SetupFrame (actor); + // [ZZ] call event hook + E_RenderCamera(); + // Clear buffers. R_ClearClipSegs (0, viewwidth); R_ClearDrawSegs (); diff --git a/wadsrc/static/zscript.txt b/wadsrc/static/zscript.txt index 7cd9722bc8..9f1033b173 100644 --- a/wadsrc/static/zscript.txt +++ b/wadsrc/static/zscript.txt @@ -5,6 +5,7 @@ #include "zscript/constants.txt" #include "zscript/actor.txt" #include "zscript/actor_checks.txt" +#include "zscript/events.txt" #include "zscript/inventory/inventory.txt" #include "zscript/inventory/inv_misc.txt"