From 0c08d9850ed44518fa04bad2f79f111d55ed66b8 Mon Sep 17 00:00:00 2001 From: jeuxjeux20 Y Date: Mon, 1 Aug 2022 17:11:31 +0200 Subject: [PATCH 1/6] Fixed interop StepTimer and added Event/EventWithTimestamp --- include/NovelRT.Interop/Utilities/NrtEvent.h | 46 ++++ src/NovelRT.Interop/CMakeLists.txt | 1 + src/NovelRT.Interop/Timing/NrtStepTimer.cpp | 223 +++++++++---------- src/NovelRT.Interop/Utilities/NrtEvent.cpp | 191 ++++++++++++++++ 4 files changed, 344 insertions(+), 117 deletions(-) create mode 100644 include/NovelRT.Interop/Utilities/NrtEvent.h create mode 100644 src/NovelRT.Interop/Utilities/NrtEvent.cpp diff --git a/include/NovelRT.Interop/Utilities/NrtEvent.h b/include/NovelRT.Interop/Utilities/NrtEvent.h new file mode 100644 index 000000000..6f2367b2c --- /dev/null +++ b/include/NovelRT.Interop/Utilities/NrtEvent.h @@ -0,0 +1,46 @@ +// Copyright © Matt Jones and Contributors. Licensed under the MIT Licence (MIT). See LICENCE.md in the repository root +// for more information. +#ifndef NOVELRT_INTEROP_UTILITIES_NRTEVENT_H +#define NOVELRT_INTEROP_UTILITIES_NRTEVENT_H + +#include "../NrtTypedefs.h" + +#ifdef __cplusplus +extern "C" +{ +#endif + + // Event<> + NrtUtilitiesEventHandle Nrt_Event_Create(); + + NrtResult Nrt_Event_AddEventHandler(NrtUtilitiesEventHandle event, + void (*handler)(void*), + void* context, + NrtAtom* outputEventHandlerId); + + NrtResult Nrt_Event_RemoveEventHandler(NrtUtilitiesEventHandle event, NrtAtom eventHandlerId); + + NrtResult Nrt_Event_Invoke(NrtUtilitiesEventHandle event); + + NrtResult Nrt_Event_Destroy(NrtUtilitiesEventHandle event); + + // Event + NrtUtilitiesEventWithTimestampHandle Nrt_EventWithTimestamp_Create(); + + NrtResult Nrt_EventWithTimestamp_AddEventHandler(NrtUtilitiesEventWithTimestampHandle event, + void (*handler)(NrtTimestamp, void*), + void* context, + NrtAtom* outputEventHandlerId); + + NrtResult Nrt_EventWithTimestamp_RemoveEventHandler(NrtUtilitiesEventWithTimestampHandle event, + NrtAtom eventHandlerId); + + NrtResult Nrt_EventWithTimestamp_Invoke(NrtUtilitiesEventWithTimestampHandle event, NrtTimestamp timestamp); + + NrtResult Nrt_EventWithTimestamp_Destroy(NrtUtilitiesEventWithTimestampHandle event); + +#ifdef __cplusplus +} +#endif + +#endif // NOVELRT_INTEROP_UTILITIES_NRTEVENT_H diff --git a/src/NovelRT.Interop/CMakeLists.txt b/src/NovelRT.Interop/CMakeLists.txt index d7eb83e2f..9af9d86e1 100644 --- a/src/NovelRT.Interop/CMakeLists.txt +++ b/src/NovelRT.Interop/CMakeLists.txt @@ -42,6 +42,7 @@ set(SOURCES Timing/NrtTimestamp.cpp Utilities/NrtMisc.cpp + Utilities/NrtEvent.cpp ) add_library(Interop SHARED ${SOURCES}) diff --git a/src/NovelRT.Interop/Timing/NrtStepTimer.cpp b/src/NovelRT.Interop/Timing/NrtStepTimer.cpp index 404b9022b..9be756f32 100644 --- a/src/NovelRT.Interop/Timing/NrtStepTimer.cpp +++ b/src/NovelRT.Interop/Timing/NrtStepTimer.cpp @@ -3,150 +3,139 @@ #include #include -#include +#include // The order is important for some reason. +#include -#ifdef __cplusplus -extern "C" -{ -#endif - NrtResult Nrt_StepTimer_create(uint32_t targetFrameRate, double maxSecondDelta, NrtStepTimerHandle* output) +NrtResult Nrt_StepTimer_create(uint32_t targetFrameRate, double maxSecondDelta, NrtStepTimerHandle* output) +{ + if (output == nullptr) { - if (output == nullptr) - { - Nrt_setErrIsNullArgProvidedInternal(); - return NRT_FAILURE_NULL_ARGUMENT_PROVIDED; - } - - NovelRT::Timing::StepTimer timer = NovelRT::Timing::StepTimer(targetFrameRate, maxSecondDelta); - *output = reinterpret_cast(&timer); - return NRT_SUCCESS; + Nrt_setErrIsNullArgProvidedInternal(); + return NRT_FAILURE_NULL_ARGUMENT_PROVIDED; } - uint64_t Nrt_StepTimer_getElapsedTicks(NrtStepTimerHandle timer) - { - NovelRT::Timing::StepTimer time = reinterpret_cast(timer); - return time.getElapsedTicks(); - } + auto* timer = new NovelRT::Timing::StepTimer(targetFrameRate, maxSecondDelta); + *output = reinterpret_cast(timer); + return NRT_SUCCESS; +} - uint64_t Nrt_StepTimer_getTotalTicks(NrtStepTimerHandle timer) - { - NovelRT::Timing::StepTimer time = reinterpret_cast(timer); - return time.getTotalTicks(); - } +uint64_t Nrt_StepTimer_getElapsedTicks(NrtStepTimerHandle timer) +{ + auto* time = reinterpret_cast(timer); + return time->getElapsedTicks(); +} - NrtTimestamp Nrt_StepTimer_getElapsedTime(NrtStepTimerHandle timer) - { - NovelRT::Timing::Timestamp* time = new NovelRT::Timing::Timestamp(0); - *time = reinterpret_cast(timer).getElapsedTime(); - return reinterpret_cast(*time); - } +uint64_t Nrt_StepTimer_getTotalTicks(NrtStepTimerHandle timer) +{ + auto* time = reinterpret_cast(timer); + return time->getTotalTicks(); +} - NrtTimestamp Nrt_StepTimer_getTotalTime(NrtStepTimerHandle timer) - { - NovelRT::Timing::Timestamp* time = new NovelRT::Timing::Timestamp(0); - *time = reinterpret_cast(timer).getTotalTime(); - return reinterpret_cast(*time); - } +NrtTimestamp Nrt_StepTimer_getElapsedTime(NrtStepTimerHandle timer) +{ + NovelRT::Timing::Timestamp timestamp = reinterpret_cast(timer).getElapsedTime(); + return reinterpret_cast(timestamp); +} - uint64_t Nrt_StepTimer_getTargetElapsedTicks(NrtStepTimerHandle timer) - { - NovelRT::Timing::StepTimer time = reinterpret_cast(timer); - return time.targetElapsedTicks(); - } +NrtTimestamp Nrt_StepTimer_getTotalTime(NrtStepTimerHandle timer) +{ + NovelRT::Timing::Timestamp timestamp = reinterpret_cast(timer).getTotalTime(); + return reinterpret_cast(timestamp); +} - NrtResult Nrt_StepTimer_setTargetElapsedTicks(NrtStepTimerHandle timer, uint64_t input) - { - if (timer == nullptr) - { - Nrt_setErrIsNullInstanceProvidedInternal(); - return NRT_FAILURE_NULL_INSTANCE_PROVIDED; - } - - NovelRT::Timing::StepTimer time = reinterpret_cast(timer); - time.targetElapsedTicks() = input; - return NRT_SUCCESS; - } +uint64_t Nrt_StepTimer_getTargetElapsedTicks(NrtStepTimerHandle timer) +{ + auto* time = reinterpret_cast(timer); + return time->targetElapsedTicks(); +} - NrtTimestamp Nrt_StepTimer_getTargetElapsedTime(NrtStepTimerHandle timer) +NrtResult Nrt_StepTimer_setTargetElapsedTicks(NrtStepTimerHandle timer, uint64_t input) +{ + if (timer == nullptr) { - NovelRT::Timing::Timestamp* time = new NovelRT::Timing::Timestamp(0); - *time = reinterpret_cast(timer).getTargetElapsedTime(); - return reinterpret_cast(*time); + Nrt_setErrIsNullInstanceProvidedInternal(); + return NRT_FAILURE_NULL_INSTANCE_PROVIDED; } - NrtResult Nrt_StepTimer_setTargetElapsedTime(NrtStepTimerHandle timer, NrtTimestamp target) - { - if (timer == nullptr) - { - Nrt_setErrIsNullInstanceProvidedInternal(); - return NRT_FAILURE_NULL_INSTANCE_PROVIDED; - } - - NovelRT::Timing::StepTimer time = reinterpret_cast(timer); - time.setTargetElapsedTime(NovelRT::Timing::Timestamp(target)); - return NRT_SUCCESS; - } + auto* time = reinterpret_cast(timer); + time->targetElapsedTicks() = input; + return NRT_SUCCESS; +} - uint32_t Nrt_StepTimer_getFrameCount(NrtStepTimerHandle timer) - { - NovelRT::Timing::StepTimer time = reinterpret_cast(timer); - return time.getFrameCount(); - } +NrtTimestamp Nrt_StepTimer_getTargetElapsedTime(NrtStepTimerHandle timer) +{ + NovelRT::Timing::Timestamp timestamp = reinterpret_cast(timer).getTargetElapsedTime(); + return reinterpret_cast(timestamp); +} - uint32_t Nrt_StepTimer_getFramesPerSecond(NrtStepTimerHandle timer) +NrtResult Nrt_StepTimer_setTargetElapsedTime(NrtStepTimerHandle timer, NrtTimestamp target) +{ + if (timer == nullptr) { - NovelRT::Timing::StepTimer time = reinterpret_cast(timer); - return time.getFramesPerSecond(); + Nrt_setErrIsNullInstanceProvidedInternal(); + return NRT_FAILURE_NULL_INSTANCE_PROVIDED; } - NrtBool Nrt_StepTimer_getIsFixedTimeStep(NrtStepTimerHandle timer) - { - NovelRT::Timing::StepTimer time = reinterpret_cast(timer); - return time.isFixedTimeStep() ? NRT_TRUE : NRT_FALSE; - } + auto* time = reinterpret_cast(timer); + time->setTargetElapsedTime(NovelRT::Timing::Timestamp(target)); + return NRT_SUCCESS; +} + +uint32_t Nrt_StepTimer_getFrameCount(NrtStepTimerHandle timer) +{ + auto* time = reinterpret_cast(timer); + return time->getFrameCount(); +} - NrtResult Nrt_StepTimer_setIsFixedTimeStep(NrtStepTimerHandle timer, int32_t input) +uint32_t Nrt_StepTimer_getFramesPerSecond(NrtStepTimerHandle timer) +{ + auto* time = reinterpret_cast(timer); + return time->getFramesPerSecond(); +} + +NrtBool Nrt_StepTimer_getIsFixedTimeStep(NrtStepTimerHandle timer) +{ + auto* time = reinterpret_cast(timer); + return time->isFixedTimeStep() ? NRT_TRUE : NRT_FALSE; +} + +NrtResult Nrt_StepTimer_setIsFixedTimeStep(NrtStepTimerHandle timer, int32_t input) +{ + if (timer == nullptr) { - if (timer == nullptr) - { - Nrt_setErrIsNullInstanceProvidedInternal(); - return NRT_FAILURE_NULL_INSTANCE_PROVIDED; - } - - NovelRT::Timing::StepTimer time = reinterpret_cast(timer); - time.isFixedTimeStep() = input; - return NRT_SUCCESS; + Nrt_setErrIsNullInstanceProvidedInternal(); + return NRT_FAILURE_NULL_INSTANCE_PROVIDED; } - NrtResult Nrt_StepTimer_resetElapsedTime(NrtStepTimerHandle timer) + auto* time = reinterpret_cast(timer); + time->isFixedTimeStep() = input; + return NRT_SUCCESS; +} + +NrtResult Nrt_StepTimer_resetElapsedTime(NrtStepTimerHandle timer) +{ + if (timer == nullptr) { - if (timer == nullptr) - { - Nrt_setErrIsNullInstanceProvidedInternal(); - return NRT_FAILURE_NULL_INSTANCE_PROVIDED; - } - - NovelRT::Timing::StepTimer time = reinterpret_cast(timer); - time.resetElapsedTime(); - return NRT_SUCCESS; + Nrt_setErrIsNullInstanceProvidedInternal(); + return NRT_FAILURE_NULL_INSTANCE_PROVIDED; } - NrtResult Nrt_StepTimer_tick(NrtStepTimerHandle timer, NrtUtilitiesEventWithTimestampHandle event) + auto* time = reinterpret_cast(timer); + time->resetElapsedTime(); + return NRT_SUCCESS; +} + +NrtResult Nrt_StepTimer_tick(NrtStepTimerHandle timer, NrtUtilitiesEventWithTimestampHandle event) +{ + if (event == nullptr) { - if (event == nullptr) - { - Nrt_setErrIsNullInstanceProvidedInternal(); - return NRT_FAILURE_NULL_INSTANCE_PROVIDED; - } - - NovelRT::Timing::StepTimer time = reinterpret_cast(timer); - NovelRT::Utilities::Event eventWithTimestamp = - reinterpret_cast&>(event); - time.tick(eventWithTimestamp); - return NRT_SUCCESS; + Nrt_setErrIsNullInstanceProvidedInternal(); + return NRT_FAILURE_NULL_INSTANCE_PROVIDED; } -#ifdef __cplusplus + auto* time = reinterpret_cast(timer); + auto* eventWithTimestamp = reinterpret_cast*>(event); + time->tick(*eventWithTimestamp); + return NRT_SUCCESS; } -#endif diff --git a/src/NovelRT.Interop/Utilities/NrtEvent.cpp b/src/NovelRT.Interop/Utilities/NrtEvent.cpp new file mode 100644 index 000000000..596d1d8ce --- /dev/null +++ b/src/NovelRT.Interop/Utilities/NrtEvent.cpp @@ -0,0 +1,191 @@ +// Copyright © Matt Jones and Contributors. Licensed under the MIT Licence (MIT). See LICENCE.md in the repository root +// for more information. + +#include +#include +#include +#include + +using namespace NovelRT::Utilities; + +template struct EventImplementationDetails; + +// Example: +// +// template <> +// struct EventImplementationDetails> { +// using Function = void(int, void*); +// using NrtHandle = NrtUtilitiesEventWithIntHandle; +// +// static auto MakeEventHandler(FunctionType func, void* context) { +// return EventHandler([func, context](int val){ func(val, context); }); +// } +// static void Invoke(const Event& event, int value) +// { +// event(value); +// } +// }; + +template> +typename Details::NrtHandle GenericEvent_Create() +{ + return reinterpret_cast(new Event()); +} + +template> +NrtResult GenericEvent_AddEventHandler(typename Details::NrtHandle event, + typename Details::Function handler, + void* context, + NrtAtom* outputEventHandlerId) +{ + if (event == nullptr) + { + Nrt_setErrIsNullInstanceProvidedInternal(); + return NRT_FAILURE_NULL_INSTANCE_PROVIDED; + } + + if (handler == nullptr) + { + Nrt_setErrIsNullArgProvidedInternal(); + return NRT_FAILURE_NULL_ARGUMENT_PROVIDED; + } + + auto* novelEvent = reinterpret_cast(event); + auto&& eventHandler = Details::MakeEventHandler(handler, context); + *novelEvent += eventHandler; + if (outputEventHandlerId != nullptr) + { + *outputEventHandlerId = eventHandler.getId(); + } + + return NRT_SUCCESS; +} + +template> +NrtResult GenericEvent_RemoveEventHandler(typename Details::NrtHandle event, NrtAtom eventHandlerId) +{ + if (event == nullptr) + { + Nrt_setErrIsNullInstanceProvidedInternal(); + return NRT_FAILURE_NULL_INSTANCE_PROVIDED; + } + + auto* novelEvent = reinterpret_cast(event); + novelEvent -= eventHandlerId; + return NRT_SUCCESS; +} + +template> +NrtResult GenericEvent_Invoke(typename Details::NrtHandle event, Args&&... args) +{ + if (event == nullptr) + { + Nrt_setErrIsNullInstanceProvidedInternal(); + return NRT_FAILURE_NULL_INSTANCE_PROVIDED; + } + + auto* novelEvent = reinterpret_cast(event); + Details::Invoke(*novelEvent, std::forward(args)...); + return NRT_SUCCESS; +} + +template> +NrtResult GenericEvent_Destroy(typename Details::NrtHandle event) +{ + if (event == nullptr) + { + Nrt_setErrIsNullInstanceProvidedInternal(); + return NRT_FAILURE_NULL_INSTANCE_PROVIDED; + } + + delete reinterpret_cast(event); + return NRT_SUCCESS; +} + +// Event<> + +template<> struct EventImplementationDetails> +{ + using Function = void(void*); + using NrtHandle = NrtUtilitiesEventHandle; + + static auto MakeEventHandler(Function func, void* context) + { + return EventHandler<>([func, context]() { func(context); }); + } + static void Invoke(const Event<>& event) + { + event(); + } +}; + +NrtUtilitiesEventHandle Nrt_Event_Create() +{ + return GenericEvent_Create>(); +} + +NrtResult Nrt_Event_AddEventHandler(NrtUtilitiesEventHandle event, + void (*handler)(void*), + void* context, + NrtAtom* outputEventHandlerId) +{ + return GenericEvent_AddEventHandler>(event, handler, context, outputEventHandlerId); +} + +NrtResult Nrt_Event_RemoveEventHandler(NrtUtilitiesEventHandle event, NrtAtom eventHandlerId) +{ + return GenericEvent_RemoveEventHandler>(event, eventHandlerId); +} + +NrtResult Nrt_Event_Invoke(NrtUtilitiesEventHandle event) +{ + return GenericEvent_Invoke>(event); +} + +NrtResult Nrt_Event_Destroy(NrtUtilitiesEventHandle event) +{ + return GenericEvent_Destroy>(event); +} + +// Event + +template<> struct EventImplementationDetails> +{ + using Function = void(NrtTimestamp, void*); + using NrtHandle = NrtUtilitiesEventWithTimestampHandle; + + static auto MakeEventHandler(Function func, void* context) + { + return EventHandler([func, context](auto time) + { func(reinterpret_cast(time), context); }); + } + static void Invoke(const Event& event, NrtTimestamp timestamp) + { + event(NovelRT::Timing::Timestamp(timestamp)); + } +}; + +NrtUtilitiesEventWithTimestampHandle Nrt_EventWithTimestamp_Create() +{ + return GenericEvent_Create>(); +} +NrtResult Nrt_EventWithTimestamp_AddEventHandler(NrtUtilitiesEventWithTimestampHandle event, + void (*handler)(NrtTimestamp, void*), + void* context, + NrtAtom* outputEventHandlerId) +{ + return GenericEvent_AddEventHandler>(event, handler, context, + outputEventHandlerId); +} +NrtResult Nrt_EventWithTimestamp_RemoveEventHandler(NrtUtilitiesEventWithTimestampHandle event, NrtAtom eventHandlerId) +{ + return GenericEvent_RemoveEventHandler>(event, eventHandlerId); +} +NrtResult Nrt_EventWithTimestamp_Invoke(NrtUtilitiesEventWithTimestampHandle event, NrtTimestamp timestamp) +{ + return GenericEvent_Invoke>(event, timestamp); +} +NrtResult Nrt_EventWithTimestamp_Destroy(NrtUtilitiesEventWithTimestampHandle event) +{ + return GenericEvent_Destroy>(event); +} From 4c0e00683386753c170b6c0962e1981922fcda20 Mon Sep 17 00:00:00 2001 From: jeuxjeux20 Y Date: Wed, 3 Aug 2022 15:24:31 +0200 Subject: [PATCH 2/6] Apply clang-format patch + Apple fix attempt --- src/NovelRT.Interop/Timing/NrtStepTimer.cpp | 3 +-- src/NovelRT.Interop/Utilities/NrtEvent.cpp | 5 +++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/NovelRT.Interop/Timing/NrtStepTimer.cpp b/src/NovelRT.Interop/Timing/NrtStepTimer.cpp index 9be756f32..34877c147 100644 --- a/src/NovelRT.Interop/Timing/NrtStepTimer.cpp +++ b/src/NovelRT.Interop/Timing/NrtStepTimer.cpp @@ -3,9 +3,8 @@ #include #include -#include // The order is important for some reason. #include - +#include // The order is important for some reason. NrtResult Nrt_StepTimer_create(uint32_t targetFrameRate, double maxSecondDelta, NrtStepTimerHandle* output) { diff --git a/src/NovelRT.Interop/Utilities/NrtEvent.cpp b/src/NovelRT.Interop/Utilities/NrtEvent.cpp index 596d1d8ce..ee781211f 100644 --- a/src/NovelRT.Interop/Utilities/NrtEvent.cpp +++ b/src/NovelRT.Interop/Utilities/NrtEvent.cpp @@ -4,6 +4,7 @@ #include #include #include +#include // Maybe this should fix the Apple issue? #include using namespace NovelRT::Utilities; @@ -156,8 +157,8 @@ template<> struct EventImplementationDetails> static auto MakeEventHandler(Function func, void* context) { - return EventHandler([func, context](auto time) - { func(reinterpret_cast(time), context); }); + return EventHandler( + [func, context](auto time) { func(reinterpret_cast(time), context); }); } static void Invoke(const Event& event, NrtTimestamp timestamp) { From c08e66306667ee6256013a7e2ba0f7ed7d310ba9 Mon Sep 17 00:00:00 2001 From: jeuxjeux20 Y Date: Wed, 3 Aug 2022 15:49:10 +0200 Subject: [PATCH 3/6] clang-format decided that alphabetical order = best order, broke everything; fix attempt --- include/NovelRT/Timing/StepTimer.h | 1 + include/NovelRT/Utilities/Event.h | 1 + src/NovelRT.Interop/Utilities/NrtEvent.cpp | 1 - 3 files changed, 2 insertions(+), 1 deletion(-) diff --git a/include/NovelRT/Timing/StepTimer.h b/include/NovelRT/Timing/StepTimer.h index 6fd08a9b6..0536e3173 100644 --- a/include/NovelRT/Timing/StepTimer.h +++ b/include/NovelRT/Timing/StepTimer.h @@ -5,6 +5,7 @@ // Original code is available under the MIT Licence #include "Timestamp.h" +#include "../Utilities/Event.h" #ifndef NOVELRT_TIMING_STEPTIMER_H #define NOVELRT_TIMING_STEPTIMER_H diff --git a/include/NovelRT/Utilities/Event.h b/include/NovelRT/Utilities/Event.h index 43a554857..045ec5734 100644 --- a/include/NovelRT/Utilities/Event.h +++ b/include/NovelRT/Utilities/Event.h @@ -3,6 +3,7 @@ #include "../Atom.h" #include +#include #ifndef NOVELRT_UTILITIES_EVENT_H #define NOVELRT_UTILITIES_EVENT_H diff --git a/src/NovelRT.Interop/Utilities/NrtEvent.cpp b/src/NovelRT.Interop/Utilities/NrtEvent.cpp index ee781211f..67faa1a5d 100644 --- a/src/NovelRT.Interop/Utilities/NrtEvent.cpp +++ b/src/NovelRT.Interop/Utilities/NrtEvent.cpp @@ -4,7 +4,6 @@ #include #include #include -#include // Maybe this should fix the Apple issue? #include using namespace NovelRT::Utilities; From ecaeebeab13d9fd67cbca9982c7718f82be94fa9 Mon Sep 17 00:00:00 2001 From: jeuxjeux20 Y Date: Wed, 3 Aug 2022 16:01:32 +0200 Subject: [PATCH 4/6] clang-format wants to swap includes, let it be --- include/NovelRT/Timing/StepTimer.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/NovelRT/Timing/StepTimer.h b/include/NovelRT/Timing/StepTimer.h index 0536e3173..798a1bdb6 100644 --- a/include/NovelRT/Timing/StepTimer.h +++ b/include/NovelRT/Timing/StepTimer.h @@ -4,8 +4,8 @@ // This is based on the StepTimer provided in the DirectX ToolKit // Original code is available under the MIT Licence -#include "Timestamp.h" #include "../Utilities/Event.h" +#include "Timestamp.h" #ifndef NOVELRT_TIMING_STEPTIMER_H #define NOVELRT_TIMING_STEPTIMER_H From 1eb72b0d3bd3a3118dcdfdcf9a30e4761ce5af93 Mon Sep 17 00:00:00 2001 From: jeuxjeux20 Y Date: Tue, 9 Aug 2022 12:08:34 +0200 Subject: [PATCH 5/6] Removed misleading comment. --- src/NovelRT.Interop/Timing/NrtStepTimer.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/NovelRT.Interop/Timing/NrtStepTimer.cpp b/src/NovelRT.Interop/Timing/NrtStepTimer.cpp index 34877c147..cd20af57e 100644 --- a/src/NovelRT.Interop/Timing/NrtStepTimer.cpp +++ b/src/NovelRT.Interop/Timing/NrtStepTimer.cpp @@ -4,7 +4,7 @@ #include #include #include -#include // The order is important for some reason. +#include NrtResult Nrt_StepTimer_create(uint32_t targetFrameRate, double maxSecondDelta, NrtStepTimerHandle* output) { From e6671fe759468e493278f3fbbe103b2197e9680d Mon Sep 17 00:00:00 2001 From: jeuxjeux20 Date: Fri, 18 Nov 2022 19:19:57 +0100 Subject: [PATCH 6/6] Updated Timestamp/Event interop, now with documentation! --- src/NovelRT.Interop/Timing/NrtStepTimer.cpp | 12 +- src/NovelRT.Interop/Utilities/NrtEvent.cpp | 142 +++++++++++++++++--- 2 files changed, 127 insertions(+), 27 deletions(-) diff --git a/src/NovelRT.Interop/Timing/NrtStepTimer.cpp b/src/NovelRT.Interop/Timing/NrtStepTimer.cpp index cd20af57e..094ce2cc3 100644 --- a/src/NovelRT.Interop/Timing/NrtStepTimer.cpp +++ b/src/NovelRT.Interop/Timing/NrtStepTimer.cpp @@ -10,7 +10,7 @@ NrtResult Nrt_StepTimer_create(uint32_t targetFrameRate, double maxSecondDelta, { if (output == nullptr) { - Nrt_setErrIsNullArgProvidedInternal(); + Nrt_setErrMsgIsNullArgumentProvidedInternal(); return NRT_FAILURE_NULL_ARGUMENT_PROVIDED; } @@ -53,7 +53,7 @@ NrtResult Nrt_StepTimer_setTargetElapsedTicks(NrtStepTimerHandle timer, uint64_t { if (timer == nullptr) { - Nrt_setErrIsNullInstanceProvidedInternal(); + Nrt_setErrMsgIsNullArgumentProvidedInternal(); return NRT_FAILURE_NULL_INSTANCE_PROVIDED; } @@ -72,7 +72,7 @@ NrtResult Nrt_StepTimer_setTargetElapsedTime(NrtStepTimerHandle timer, NrtTimest { if (timer == nullptr) { - Nrt_setErrIsNullInstanceProvidedInternal(); + Nrt_setErrMsgIsNullArgumentProvidedInternal(); return NRT_FAILURE_NULL_INSTANCE_PROVIDED; } @@ -103,7 +103,7 @@ NrtResult Nrt_StepTimer_setIsFixedTimeStep(NrtStepTimerHandle timer, int32_t inp { if (timer == nullptr) { - Nrt_setErrIsNullInstanceProvidedInternal(); + Nrt_setErrMsgIsNullArgumentProvidedInternal(); return NRT_FAILURE_NULL_INSTANCE_PROVIDED; } @@ -116,7 +116,7 @@ NrtResult Nrt_StepTimer_resetElapsedTime(NrtStepTimerHandle timer) { if (timer == nullptr) { - Nrt_setErrIsNullInstanceProvidedInternal(); + Nrt_setErrMsgIsNullArgumentProvidedInternal(); return NRT_FAILURE_NULL_INSTANCE_PROVIDED; } @@ -129,7 +129,7 @@ NrtResult Nrt_StepTimer_tick(NrtStepTimerHandle timer, NrtUtilitiesEventWithTime { if (event == nullptr) { - Nrt_setErrIsNullInstanceProvidedInternal(); + Nrt_setErrMsgIsNullArgumentProvidedInternal(); return NRT_FAILURE_NULL_INSTANCE_PROVIDED; } diff --git a/src/NovelRT.Interop/Utilities/NrtEvent.cpp b/src/NovelRT.Interop/Utilities/NrtEvent.cpp index 67faa1a5d..90e5d7a74 100644 --- a/src/NovelRT.Interop/Utilities/NrtEvent.cpp +++ b/src/NovelRT.Interop/Utilities/NrtEvent.cpp @@ -8,23 +8,123 @@ using namespace NovelRT::Utilities; -template struct EventImplementationDetails; +/** + * Generic events + * ------ + * + * Events in the C API are implemented in a generic manner to save time, + * to be less redundant, and keep logic consistent. + * + * Due to limitations in the C language, each C++ event type needs a + * distinct representation in the C API. This representation is composed of: + * - An opaque NrtEvent type + * (examples: NrtUtilitiesEventHandle, NrtUtilitiesEventWithTimestampHandle) + * + * - A C function pointer type, returning void, and with a void* parameter at the end. + * This function pointer indicates what parameter types should be used in C. + * (examples: void(void*), void(NrtTimestamp, void*)) + * + * - An EventHandler calling the C function pointer, used to create event handlers + * from C function pointers. + * This EventHandler converts incoming C++ arguments to their C equivalents. + * Example, with func the C function pointer and context the given void* context: + * EventHandler( + * [func, context](auto time) { func(reinterpret_cast(time), context); } + * ) + * + * - An Invoke function, which invokes a C++ event using C parameters. + * This function converts incoming C arguments to their C++ equivalents. + * Example: + * void Invoke(const Event& event, NrtTimestamp timestamp) + * { + * event(NovelRT::Timing::Timestamp(timestamp)); + * } + * + * Those definitions are contained inside specialized instances of the EventImplementationDetails class. + * For example: + * template<> struct EventImplementationDetails> + * { + * using Function = void(NrtTimestamp, void*); + * using NrtHandle = NrtUtilitiesEventWithTimestampHandle; + * + * static auto MakeEventHandler(Function func, void* context) + * { + * return EventHandler( + * [func, context](auto time) { func(reinterpret_cast(time), context); }); + * } + * static void Invoke(const Event& event, NrtTimestamp timestamp) + * { + * event(NovelRT::Timing::Timestamp(timestamp)); + * } + * }; + * + * Once you have created an EventImplementationDetails class and added all of its required + * members (see the documentation for it below), you can use the Event<> type inside the + * generic methods. + * + * Those generic methods correspond one-to-one to the exposed C API: + * - GenericEvent_Create, creates an event + * - GenericEvent_AddEventHandler, adds an event handler using a C function pointer and context + * - GenericEvent_RemoveEventHandler, removes an event handler by id + * - GenericEvent_Invoke, invokes the event with the given parameters, + * - GenericEvent_Destroy, destroys an event + * + * You can then declare all C API methods for the event: replace "GenericEvent" with + * the full event name, such as "Nrt_EventWithTimestamp". + * And then proceed to define them there by simply calling the GenericEvent methods, + * with the C++ event type as the template parameter. That's it, that's lit. + */ -// Example: -// -// template <> -// struct EventImplementationDetails> { -// using Function = void(int, void*); -// using NrtHandle = NrtUtilitiesEventWithIntHandle; -// -// static auto MakeEventHandler(FunctionType func, void* context) { -// return EventHandler([func, context](int val){ func(val, context); }); -// } -// static void Invoke(const Event& event, int value) -// { -// event(value); -// } -// }; +/** + * Defines how a NovelRT::Utilities::Event type should interop with the C API, + * i.e. how C function pointers are called by C++ and vice-versa. + * + * This class must be specialized by the targeted NovelRT::Utilities::Event type. + * + * Specializations of this class must be implemented with the following members + * in order to be make GenericEvent_* methods available: + * + *
    + *
  • A Function type alias, equivalent to the C function pointer used in the C API. + * The function pointer is required to take a void* parameter at the end. + * + *
  • A NrtHandle type alias, equivalent to the opaque type handle used in C for this event. + * + *
  • A MakeEventHandler function, with the following signature: + * EventHandler MakeEventHandler(Function func, void* context) + * This function should return a C++ NovelRT::Utilities::EventHandler (parameterized with + * the right types) calling the C function pointer. + * + *
  • An Invoke function, with the following signature: + * void Invoke(const Event& event, ...) + * Where Event should be parameterized with the C++ event parameters types, and + * the three dots should be filled with the C function pointer parameters types. + * This function should invoke the C++ event using the arguments provided + * by the C caller. + *
+ * + * @example + * Here's an example with a C++ event using taking an int. + * @code + * + * struct EventImplementationDetails> { + * using Function = void(int, void*); + * using NrtHandle = NrtUtilitiesEventWithIntHandle; + * static auto MakeEventHandler(Function func, void* context) + * { + * return EventHandler([func, context](int val){ func(val, context); }); + * } + * static void Invoke(const Event& event, int value) + * { + * event(value); + * } + * }; + * + * @endcode + * + * @tparam T the parameterized type of NovelRT::Utilities::Event + */ +template struct EventImplementationDetails; template> typename Details::NrtHandle GenericEvent_Create() @@ -40,13 +140,13 @@ NrtResult GenericEvent_AddEventHandler(typename Details::NrtHandle event, { if (event == nullptr) { - Nrt_setErrIsNullInstanceProvidedInternal(); + Nrt_setErrMsgIsNullArgumentProvidedInternal(); return NRT_FAILURE_NULL_INSTANCE_PROVIDED; } if (handler == nullptr) { - Nrt_setErrIsNullArgProvidedInternal(); + Nrt_setErrMsgIsNullArgumentProvidedInternal(); return NRT_FAILURE_NULL_ARGUMENT_PROVIDED; } @@ -66,7 +166,7 @@ NrtResult GenericEvent_RemoveEventHandler(typename Details::NrtHandle event, Nrt { if (event == nullptr) { - Nrt_setErrIsNullInstanceProvidedInternal(); + Nrt_setErrMsgIsNullArgumentProvidedInternal(); return NRT_FAILURE_NULL_INSTANCE_PROVIDED; } @@ -80,7 +180,7 @@ NrtResult GenericEvent_Invoke(typename Details::NrtHandle event, Args&&... args) { if (event == nullptr) { - Nrt_setErrIsNullInstanceProvidedInternal(); + Nrt_setErrMsgIsNullArgumentProvidedInternal(); return NRT_FAILURE_NULL_INSTANCE_PROVIDED; } @@ -94,7 +194,7 @@ NrtResult GenericEvent_Destroy(typename Details::NrtHandle event) { if (event == nullptr) { - Nrt_setErrIsNullInstanceProvidedInternal(); + Nrt_setErrMsgIsNullInstanceProvidedInternal(); return NRT_FAILURE_NULL_INSTANCE_PROVIDED; }