From a03a8a09e7a415217a2f188e9c9229ef8d437cce Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 26 Jun 2025 11:03:00 +0200 Subject: [PATCH 001/179] NG: Fix AV in UI for deleted links. --- packages/rendering/source/common/ui/UIVisitors.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/packages/rendering/source/common/ui/UIVisitors.cpp b/packages/rendering/source/common/ui/UIVisitors.cpp index 2470ccce..316cd0b9 100644 --- a/packages/rendering/source/common/ui/UIVisitors.cpp +++ b/packages/rendering/source/common/ui/UIVisitors.cpp @@ -480,6 +480,9 @@ namespace l::ui { if (OverlapCircle(input.mCurPos, pT, 2.0f * size.x * linkContainer.GetCoParent()->GetLayoutArea().mScale)) { mLinkContainer.mContainer = &linkContainer; mLinkHandler(mLinkContainer->GetCoParent()->GetNodeId(), mLinkContainer->GetParent()->GetNodeId(), mLinkContainer->GetCoParent()->GetChannelId(), mLinkContainer->GetParent()->GetChannelId(), false); + if (linkContainer.GetCoParent()) { + linkContainer.GetCoParent()->SetCoParent(nullptr); + } mDragging = true; return true; } @@ -520,8 +523,9 @@ namespace l::ui { // If this link if connected to this input node channel area, we detach it because the overlap failed (we moved it away) else if (mLinkContainer->GetCoParent() == &inputContainer) { mLinkHandler(inputContainer.GetNodeId(), mLinkContainer->GetParent()->GetNodeId(), inputContainer.GetChannelId(), mLinkContainer->GetParent()->GetChannelId(), false); - mLinkContainer->SetCoParent(nullptr); mLinkContainer->ClearNotification(UIContainer_LinkFlag); + mLinkContainer->SetCoParent(nullptr); + inputContainer.SetCoParent(nullptr); } if (input.mStopped) { From 202a2e9cad2e0b30f99da58f527828f4a161f088 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 26 Jun 2025 23:28:30 +0200 Subject: [PATCH 002/179] NG: Simplify ma filter. --- .../common/operations/NodeGraphOpSignalFilter.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpSignalFilter.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpSignalFilter.cpp index a251235a..ad4e3dec 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpSignalFilter.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpSignalFilter.cpp @@ -189,27 +189,21 @@ namespace l::nodegraph { float balanceDivisorSum = 0.0f; { // remove a part of the first sample of the sum as it is not part of the moving average auto fac = mFilterWeight[mFilterStateIndex] * l::math::abs(balanceFactor) * widthFrac; - auto sign = l::math::functions::sign(fac); - fac = l::math::pow(fac * sign, gamma); - fac *= sign; + fac = l::math::pow(fac, gamma); outVal += fac * mFilterState[mFilterStateIndex]; balanceDivisorSum += fac; balanceFactor += balanceDelta * widthFrac; } for (int32_t j = mFilterStateIndex + 1; j < bufferSize; j++) { auto fac = mFilterWeight[j] * l::math::abs(balanceFactor); - auto sign = l::math::functions::sign(fac); - fac = l::math::pow(fac * sign, gamma); - fac *= sign; + fac = l::math::pow(fac, gamma); outVal += fac * mFilterState[j]; balanceDivisorSum += fac; balanceFactor += balanceDelta; } for (int32_t j = 0; j < mFilterStateIndex; j++) { auto fac = mFilterWeight[j] * l::math::abs(balanceFactor); - auto sign = l::math::functions::sign(fac); - fac = l::math::pow(fac * sign, gamma); - fac *= sign; + fac = l::math::pow(fac, gamma); outVal += fac * mFilterState[j]; balanceDivisorSum += fac; balanceFactor += balanceDelta; From 85e68bcf024e2e7793145c41abffb84b79e08d19 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 27 Jun 2025 12:10:45 +0200 Subject: [PATCH 003/179] NG: Add filter test. --- .../tests/common/NodeGraphOpTest.cpp | 77 +++++++++++++++++++ 1 file changed, 77 insertions(+) create mode 100644 packages/nodegraph/tests/common/NodeGraphOpTest.cpp diff --git a/packages/nodegraph/tests/common/NodeGraphOpTest.cpp b/packages/nodegraph/tests/common/NodeGraphOpTest.cpp new file mode 100644 index 00000000..bbd6ce16 --- /dev/null +++ b/packages/nodegraph/tests/common/NodeGraphOpTest.cpp @@ -0,0 +1,77 @@ +#include "testing/Test.h" +#include "logging/Log.h" + +#include "nodegraph/core/NodeGraphData.h" +#include "nodegraph/core/NodeGraphInput.h" +#include "nodegraph/core/NodeGraphOutput.h" +#include "nodegraph/core/NodeGraphBase.h" +#include +#include + +using namespace l; +using namespace l::nodegraph; + + +float MAFilter(float width, float weightAccent, float balance, float gamma) { + int32_t widthInt = 1 + static_cast(width); + int32_t bufferSize = widthInt; + float widthFrac = width - l::math::floor(width); + + float state = 100.0f; + float inputWeight = 1.0f; + + float outVal = 0.0; + float balanceFactor = 1.0f - balance; + float balanceDelta = balance / static_cast(widthInt - 1); + float balanceDivisorSum = 0.0f; + float weight = l::math::pow(inputWeight, weightAccent); + + { // remove a part of the first sample of the sum as it is not part of the moving average + balanceFactor -= balanceDelta * widthFrac; + + auto fac = weight * balanceFactor; + auto sign = l::math::functions::sign(fac); + fac = l::math::pow(fac * sign, gamma); + fac *= sign; + outVal = fac * state * widthFrac; + balanceDivisorSum = fac * widthFrac; + + balanceFactor += balanceDelta * widthFrac; + } + for (int32_t j = 0; j < bufferSize; j++) { + float weight = l::math::pow(inputWeight, weightAccent); + auto fac = weight * balanceFactor; + auto sign = l::math::functions::sign(fac); + fac = l::math::pow(fac * sign, gamma); + fac *= sign; + outVal += fac * state; + balanceDivisorSum += fac; + balanceFactor += balanceDelta; + } + + {// Check that balanceFactor summed to 1 (but first subtract the last unused addition) + balanceFactor -= balanceDelta; + TEST_FUZZY(balanceFactor, 1.0f, 0.001f, ""); + } + + auto signal = outVal / balanceDivisorSum; + + return signal; +} + +TEST(NodeGraphOp, MAFilterSumming) { + + for (int32_t i = 0; i < 3; i++) { + MAFilter(4.3f + i * 1.3f, 1.0f, 1.5f, 1.0f); + } + for (int32_t i = 0; i < 3; i++) { + auto v0 = MAFilter(4.3f + i * 1.3f, 1.0f, 1.5f, 1.0f); + auto v1 = MAFilter(4.3f + i * 1.3f, 1.0f, 1.5f, 1.000001f); + TEST_FUZZY(v0, v1, 0.0001f, ""); + } + for (int32_t i = 0; i < 3; i++) { + MAFilter(4.3f + i * 1.3f, 1.4f, 1.5f, 3.0f); + } + + return 0; +} From 41bca468762d98181e518b131369ad4764941442 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 29 Jun 2025 10:26:11 +0200 Subject: [PATCH 004/179] NG: Fix potential recursion overflow. --- packages/nodegraph/include/nodegraph/core/NodeGraphBase.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h index 90528ae7..b41e8270 100644 --- a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h @@ -360,9 +360,9 @@ namespace l::nodegraph { if (tickCount <= mLastTickCount) { return; } + mLastTickCount = tickCount; NodeGraphBase::Tick(tickCount, delta); mOperation.Tick(tickCount, delta); - mLastTickCount = tickCount; } virtual std::string_view GetInputName(int8_t inputChannel) override { From dd1d801fc0d8af1c8288965ee6a14ae8d7eb841b Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 1 Jul 2025 00:38:53 +0200 Subject: [PATCH 005/179] NG: Fix error. --- .../source/common/operations/NodeGraphOpTradingFilter.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingFilter.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingFilter.cpp index 59ce8262..2c547fd0 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingFilter.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingFilter.cpp @@ -135,7 +135,7 @@ namespace l::nodegraph { float width = l::math::max2(inputs.at(2).Get(), 1.0f); float weightAccent = l::math::clamp(inputs.at(3).Get(), 0.0f, 100.0f); - auto output = outputs.at(0).GetIterator(numSamples); + auto output = &outputs.at(0).Get(numSamples); int32_t widthInt = 1 + static_cast(width); int32_t bufferSize = widthInt; From 498c5b413021b090c8eaf17f12a33950d19b8e12 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 8 Jul 2025 15:37:05 +0200 Subject: [PATCH 006/179] NG: Add text editing to text . --- packages/hid/include/hid/KeyState.h | 4 ++ packages/hid/source/common/KeyState.cpp | 15 +++++ .../include/nodegraph/core/NodeGraphBase.h | 2 +- .../include/rendering/ui/UIContainer.h | 3 +- .../include/rendering/ui/UINodeEditor.h | 6 +- .../include/rendering/ui/UIVisitors.h | 18 +++++- .../rendering/source/common/ui/UICreator.cpp | 4 +- .../source/common/ui/UINodeEditor.cpp | 57 +++++++++++++++++-- .../rendering/source/common/ui/UIVisitors.cpp | 51 ++++++++++++++++- 9 files changed, 148 insertions(+), 12 deletions(-) diff --git a/packages/hid/include/hid/KeyState.h b/packages/hid/include/hid/KeyState.h index 4addfb88..945b7695 100644 --- a/packages/hid/include/hid/KeyState.h +++ b/packages/hid/include/hid/KeyState.h @@ -37,6 +37,8 @@ namespace l::hid { } ~KeyState() = default; + char LastKeyPressed(); + int32_t LastKeyDetections(); void UpdateKeyDown(int32_t keyCode); void UpdateKeyUp(int32_t keyCode); bool IsReleased(int32_t keyCode); @@ -47,6 +49,8 @@ namespace l::hid { void ForEachKeyChange(std::function keyHandler); void ForEachKey(std::function keyHandler); protected: + int32_t mLastKeyPressed = 0; + int32_t mLastKeyDetections = 0; std::unordered_map mActiveKeys; }; } diff --git a/packages/hid/source/common/KeyState.cpp b/packages/hid/source/common/KeyState.cpp index d6f7d1bf..fb22c6a2 100644 --- a/packages/hid/source/common/KeyState.cpp +++ b/packages/hid/source/common/KeyState.cpp @@ -50,8 +50,23 @@ namespace l::hid { return pressedNow; } + char KeyState::LastKeyPressed() { + return static_cast(mLastKeyPressed); + } + + int32_t KeyState::LastKeyDetections() { + return mLastKeyDetections; + } + void KeyState::UpdateKeyDown(int32_t keyCode) { mActiveKeys[keyCode].UpdateKeyDown(); + if (mLastKeyPressed != keyCode) { + mLastKeyPressed = keyCode; + mLastKeyDetections = 1; + } + else { + mLastKeyDetections++; + } } void KeyState::UpdateKeyUp(int32_t keyCode) { diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h index b41e8270..06ca9f95 100644 --- a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h @@ -90,7 +90,7 @@ namespace l::nodegraph { virtual std::string_view GetInputText(int8_t inputChannel, int32_t minSize = 16); virtual float& GetOutput(int8_t outputChannel, int32_t minSize = 1, int32_t offset = 0); - virtual std::string_view GetOutputText(int8_t outputChannel, int32_t minSize); + virtual std::string_view GetOutputText(int8_t outputChannel, int32_t minSize = 16); virtual NodeGraphInput& GetInputOf(int8_t inputChannel); virtual NodeGraphOutput& GetOutputOf(int8_t outputChannel); diff --git a/packages/rendering/include/rendering/ui/UIContainer.h b/packages/rendering/include/rendering/ui/UIContainer.h index d817cc59..81887e23 100644 --- a/packages/rendering/include/rendering/ui/UIContainer.h +++ b/packages/rendering/include/rendering/ui/UIContainer.h @@ -247,8 +247,9 @@ namespace l::ui { const uint32_t UIContainer_OutputFlag = 0x00000400; const uint32_t UIContainer_LinkFlag = 0x00000800; const uint32_t UIContainer_SelectFlag = 0x00001000; - const uint32_t UIContainer_EditFlag = 0x00002000; + const uint32_t UIContainer_TouchEditFlag = 0x00002000; const uint32_t UIContainer_ConstantsKeyboardFlag = 0x00004000; + const uint32_t UIContainer_TextEditFlag = 0x00008000; class UIDraw; diff --git a/packages/rendering/include/rendering/ui/UINodeEditor.h b/packages/rendering/include/rendering/ui/UINodeEditor.h index 209977ba..431aa211 100644 --- a/packages/rendering/include/rendering/ui/UINodeEditor.h +++ b/packages/rendering/include/rendering/ui/UINodeEditor.h @@ -39,6 +39,7 @@ namespace l::ui { void SetOverlayContentWindow(std::function action); void SetNGSchema(l::nodegraph::NodeGraphSchema* ngSchema); + void SetKeyState(l::hid::KeyState* keyState); void SetEventListener(std::function cb); l::nodegraph::NodeGraphSchema* GetNGSchema(); @@ -54,9 +55,12 @@ namespace l::ui { UIDrag mDragVisitor; UIMove mMoveVisitor; UIResize mResizeVisitor; - UIEdit mEditVisitor; + UITouchEdit mTouchEditVisitor; + UITextEdit mTextEditVisitor; l::nodegraph::NodeGraphSchema* mNGSchema = nullptr; + l::hid::KeyState* mKeyState = nullptr; + char mLastKeyPressed = 0; std::vector> mEventListeners; std::function mOverlayContentWindow = nullptr; diff --git a/packages/rendering/include/rendering/ui/UIVisitors.h b/packages/rendering/include/rendering/ui/UIVisitors.h index 29028b29..04966d5c 100644 --- a/packages/rendering/include/rendering/ui/UIVisitors.h +++ b/packages/rendering/include/rendering/ui/UIVisitors.h @@ -86,7 +86,7 @@ namespace l::ui { std::function mRemoveHandler = nullptr; }; - class UIEdit : public UIVisitor { + class UITouchEdit : public UIVisitor { public: virtual bool Visit(UIContainer& container, const InputState& input); virtual void Reset(); @@ -101,6 +101,22 @@ namespace l::ui { std::function mEditHandler = nullptr; }; + class UITextEdit : public UIVisitor { + public: + virtual bool Visit(UIContainer& container, const InputState& input); + virtual void Reset(); + + void SetEditHandler(std::function handler) { + mEditHandler = handler; + } + + protected: + std::string mEditedText; + bool mEditing = false; + UIContainer* mSourceContainer = nullptr; + std::function mEditHandler = nullptr; + }; + class UIDraw : public UIVisitor { public: UIDraw(ImDrawList* drawList = nullptr) : mDrawList(drawList) {} diff --git a/packages/rendering/source/common/ui/UICreator.cpp b/packages/rendering/source/common/ui/UICreator.cpp index c522b236..f8c7a9e1 100644 --- a/packages/rendering/source/common/ui/UICreator.cpp +++ b/packages/rendering/source/common/ui/UICreator.cpp @@ -65,7 +65,9 @@ namespace l::ui { } if (node.IsInputDataVisible(i)) { - auto inputDataText = CreateContainer(uiManager, (node.IsInputDataEditable(i) ? l::ui::UIContainer_EditFlag : 0) | l::ui::UIContainer_DrawFlag, l::ui::UIRenderType::NodeOutputValue, l::ui::UIAlignH::Left); + bool isText = node.IsInputDataText(i); + bool isEditable = node.IsInputDataEditable(i); + auto inputDataText = CreateContainer(uiManager, (isEditable ? (isText ? l::ui::UIContainer_TextEditFlag : l::ui::UIContainer_TouchEditFlag) : 0) | l::ui::UIContainer_DrawFlag, l::ui::UIRenderType::NodeOutputValue, l::ui::UIAlignH::Left); inputDataText->SetColor(mediumWhite); inputDataText->SetPosition(ImVec2(estimatedWidth, 0.0f)); inputDataText->SetSize(ImVec2(10 * 7, 14.0f)); diff --git a/packages/rendering/source/common/ui/UINodeEditor.cpp b/packages/rendering/source/common/ui/UINodeEditor.cpp index afa08295..b93377a0 100644 --- a/packages/rendering/source/common/ui/UINodeEditor.cpp +++ b/packages/rendering/source/common/ui/UINodeEditor.cpp @@ -182,13 +182,13 @@ namespace l::ui { return inputNode->ClearInput(static_cast(inputChannel)); }); - mEditVisitor.SetEditHandler([&](int32_t nodeId, int8_t channelId, float, float dy) { + mTouchEditVisitor.SetEditHandler([&](int32_t nodeId, int8_t channelId, float, float dy) { if (mNGSchema == nullptr) { return; } auto node = mNGSchema->GetNode(nodeId); - if (node->IsInputDataEditable(channelId)) { + if (node->IsInputDataEditable(channelId) && !node->IsInputDataText(channelId)) { float* nodeValue = nullptr; if (channelId < node->GetNumInputs()) { nodeValue = &node->GetInput(channelId, 1); @@ -223,6 +223,48 @@ namespace l::ui { } }); + mTextEditVisitor.SetEditHandler([&](int32_t nodeId, int8_t channelId, std::string& text) { + if (mNGSchema == nullptr) { + return; + } + + auto node = mNGSchema->GetNode(nodeId); + if (text.empty() && node->IsInputDataEditable(channelId) && node->IsInputDataText(channelId)) { + if (channelId < node->GetNumInputs()) { + text = node->GetInputText(channelId); + } + else if (channelId < node->GetNumOutputs()) { + text = node->GetOutputText(channelId); + } + if (ImGui::IsKeyDown(ImGuiKey::ImGuiKey_Enter)) { + } + } + + if (mLastKeyPressed != mKeyState->LastKeyPressed() || mKeyState->LastKeyDetections() % 10 == 0) { + mLastKeyPressed = mKeyState->LastKeyPressed(); + if( + mLastKeyPressed >= 'a' && mLastKeyPressed <= 'z' || + mLastKeyPressed >= 'A' && mLastKeyPressed <= 'Z' || + mLastKeyPressed >= '0' && mLastKeyPressed <= '9' || + mLastKeyPressed == ' ' || + mLastKeyPressed == '-' || + mLastKeyPressed == '_' || + mLastKeyPressed == '.' || + mLastKeyPressed == ':' || + mLastKeyPressed == '(' || + mLastKeyPressed == ')' || + mLastKeyPressed == '[' || + mLastKeyPressed == ']' + ) + text += mLastKeyPressed; + + if (channelId < node->GetNumInputs()) { + node->SetInput(channelId, text); + } + } + + }); + mSelectVisitor.SetDeleteHandler([&](int32_t containerId, int32_t nodeId) { if (mNGSchema == nullptr) { return; @@ -293,7 +335,8 @@ namespace l::ui { mDragVisitor.Reset(); mMoveVisitor.Reset(); mResizeVisitor.Reset(); - mEditVisitor.Reset(); + mTouchEditVisitor.Reset(); + mTextEditVisitor.Reset(); if (mUIRoot.IsValid()) { mUIRoot->RemoveAll(); @@ -367,6 +410,10 @@ namespace l::ui { }); } + void UINodeEditor::SetKeyState(l::hid::KeyState* keyState) { + mKeyState = keyState; + } + l::nodegraph::NodeGraphSchema* UINodeEditor::GetNGSchema() { return mNGSchema; } @@ -391,7 +438,9 @@ namespace l::ui { if (IsHovered()) { if (mUIRoot->Accept(mLinkIOVisitor, mUIInput, l::ui::UITraversalMode::DFS)) { } - else if (mUIRoot->Accept(mEditVisitor, mUIInput, l::ui::UITraversalMode::DFS)) { + else if (mUIRoot->Accept(mTouchEditVisitor, mUIInput, l::ui::UITraversalMode::DFS)) { + } + else if (mUIRoot->Accept(mTextEditVisitor, mUIInput, l::ui::UITraversalMode::DFS)) { } else if (mUIRoot->Accept(mSelectVisitor, mUIInput, l::ui::UITraversalMode::BFS)) { } diff --git a/packages/rendering/source/common/ui/UIVisitors.cpp b/packages/rendering/source/common/ui/UIVisitors.cpp index 316cd0b9..cba64ad0 100644 --- a/packages/rendering/source/common/ui/UIVisitors.cpp +++ b/packages/rendering/source/common/ui/UIVisitors.cpp @@ -245,8 +245,8 @@ namespace l::ui { } /***********************************************************************************/ - bool UIEdit::Visit(UIContainer& container, const InputState& input) { - if (!container.HasConfigFlag(UIContainer_EditFlag)) { + bool UITouchEdit::Visit(UIContainer& container, const InputState& input) { + if (!container.HasConfigFlag(UIContainer_TouchEditFlag)) { return false; } if (input.mStarted && !mEditing) { @@ -254,6 +254,7 @@ namespace l::ui { if (Overlap(input.GetLocalPos(), container.GetPosition(), container.GetPositionAtSize(), layoutArea)) { mEditing = true; mSourceContainer = &container; + mSourceContainer->SetNotification(UIContainer_TouchEditFlag); } } if (mEditing && mSourceContainer == &container) { @@ -265,6 +266,7 @@ namespace l::ui { } if (input.mStopped) { + mSourceContainer->ClearNotification(UIContainer_TouchEditFlag); mEditing = false; mSourceContainer = nullptr; } @@ -273,7 +275,50 @@ namespace l::ui { return false; } - void UIEdit::Reset() { + void UITouchEdit::Reset() { + if (mSourceContainer) { + mSourceContainer->ClearNotification(UIContainer_TouchEditFlag); + } + mEditing = false; + mSourceContainer = nullptr; + } + + /***********************************************************************************/ + bool UITextEdit::Visit(UIContainer& container, const InputState& input) { + if (!container.HasConfigFlag(UIContainer_TextEditFlag)) { + return false; + } + if (input.mStarted && !mEditing) { + auto& layoutArea = container.GetLayoutArea(); + if (Overlap(input.GetLocalPos(), container.GetPosition(), container.GetPositionAtSize(), layoutArea)) { + mEditing = true; + mSourceContainer = &container; + mSourceContainer->SetNotification(UIContainer_TextEditFlag); + } + } + if (mEditing && mSourceContainer == &container) { + if (mEditHandler) { + mEditHandler(container.GetNodeId(), static_cast(container.GetChannelId()), mEditedText); + } + + if (ImGui::IsKeyPressed(ImGuiKey::ImGuiKey_Enter, false)) { + mSourceContainer->ClearNotification(UIContainer_TextEditFlag); + mEditing = false; + mSourceContainer = nullptr; + mEditedText.clear(); + } + if (ImGui::IsKeyPressed(ImGuiKey::ImGuiKey_Backspace, false)) { + mEditedText.pop_back(); + } + return mEditing; + } + return false; + } + + void UITextEdit::Reset() { + if (mSourceContainer) { + mSourceContainer->ClearNotification(UIContainer_TextEditFlag); + } mEditing = false; mSourceContainer = nullptr; } From 219ce43f2779aa3d4a53ba96cbe57f769d0535c2 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 8 Jul 2025 17:05:36 +0200 Subject: [PATCH 007/179] Add glfw char input for text editing. --- packages/hid/include/hid/KeyState.h | 5 ++- packages/hid/source/common/KeyState.cpp | 21 +++++----- .../rendering/include/rendering/GLFWWindow.h | 8 +++- .../include/rendering/ui/UINodeEditor.h | 3 +- .../include/rendering/ui/UIVisitors.h | 4 +- .../rendering/source/common/GLFWWindow.cpp | 28 ++++++++++--- .../source/common/ui/UINodeEditor.cpp | 39 +++++++------------ .../rendering/source/common/ui/UIVisitors.cpp | 14 ++++--- 8 files changed, 68 insertions(+), 54 deletions(-) diff --git a/packages/hid/include/hid/KeyState.h b/packages/hid/include/hid/KeyState.h index 945b7695..4fdd967d 100644 --- a/packages/hid/include/hid/KeyState.h +++ b/packages/hid/include/hid/KeyState.h @@ -37,8 +37,9 @@ namespace l::hid { } ~KeyState() = default; - char LastKeyPressed(); - int32_t LastKeyDetections(); + std::tuple LastKeyPressed(); + void UpdateKeyPress(int32_t scanCode); + void UpdateKeyDown(int32_t keyCode); void UpdateKeyUp(int32_t keyCode); bool IsReleased(int32_t keyCode); diff --git a/packages/hid/source/common/KeyState.cpp b/packages/hid/source/common/KeyState.cpp index fb22c6a2..225821bf 100644 --- a/packages/hid/source/common/KeyState.cpp +++ b/packages/hid/source/common/KeyState.cpp @@ -50,23 +50,22 @@ namespace l::hid { return pressedNow; } - char KeyState::LastKeyPressed() { - return static_cast(mLastKeyPressed); + std::tuple KeyState::LastKeyPressed() { + return { static_cast(mLastKeyPressed), mLastKeyDetections }; } - int32_t KeyState::LastKeyDetections() { - return mLastKeyDetections; + void KeyState::UpdateKeyPress(int32_t scanCode) { + if (scanCode >= 32 && scanCode <= 126) { + if (mLastKeyPressed != scanCode) { + mLastKeyDetections = 0; + } + mLastKeyPressed = scanCode; + mLastKeyDetections++; + } } void KeyState::UpdateKeyDown(int32_t keyCode) { mActiveKeys[keyCode].UpdateKeyDown(); - if (mLastKeyPressed != keyCode) { - mLastKeyPressed = keyCode; - mLastKeyDetections = 1; - } - else { - mLastKeyDetections++; - } } void KeyState::UpdateKeyUp(int32_t keyCode) { diff --git a/packages/rendering/include/rendering/GLFWWindow.h b/packages/rendering/include/rendering/GLFWWindow.h index cb055264..f73b036d 100644 --- a/packages/rendering/include/rendering/GLFWWindow.h +++ b/packages/rendering/include/rendering/GLFWWindow.h @@ -19,6 +19,7 @@ namespace rendering { using KeyCB = void(GLFWwindow* window, int key, int scancode, int action, int mods); using MouseCB = void(GLFWwindow* window, int button, int action, int mods); using ScrollCB = void(GLFWwindow* window, float xoffset, float yoffset); + using CharsCB = void(GLFWwindow* window, unsigned int codepoint); class GLFWWindowHandle { public: @@ -36,9 +37,12 @@ namespace rendering { GLFWwindow* get(); // setup - void SetInput(std::function keyCallback = nullptr, + void SetInput( + std::function keyCallback = nullptr, std::function mouseCallback = nullptr, - std::function scrollCallback = nullptr); + std::function scrollCallback = nullptr, + std::function charsCallback = nullptr + ); void SetOpacity(float opacity); // control diff --git a/packages/rendering/include/rendering/ui/UINodeEditor.h b/packages/rendering/include/rendering/ui/UINodeEditor.h index 431aa211..0d08cdab 100644 --- a/packages/rendering/include/rendering/ui/UINodeEditor.h +++ b/packages/rendering/include/rendering/ui/UINodeEditor.h @@ -60,7 +60,8 @@ namespace l::ui { l::nodegraph::NodeGraphSchema* mNGSchema = nullptr; l::hid::KeyState* mKeyState = nullptr; - char mLastKeyPressed = 0; + int32_t mLastKeyPressed = 0; + int32_t mLastKeyDetections = 0; std::vector> mEventListeners; std::function mOverlayContentWindow = nullptr; diff --git a/packages/rendering/include/rendering/ui/UIVisitors.h b/packages/rendering/include/rendering/ui/UIVisitors.h index 04966d5c..756b60db 100644 --- a/packages/rendering/include/rendering/ui/UIVisitors.h +++ b/packages/rendering/include/rendering/ui/UIVisitors.h @@ -106,7 +106,7 @@ namespace l::ui { virtual bool Visit(UIContainer& container, const InputState& input); virtual void Reset(); - void SetEditHandler(std::function handler) { + void SetEditHandler(std::function handler) { mEditHandler = handler; } @@ -114,7 +114,7 @@ namespace l::ui { std::string mEditedText; bool mEditing = false; UIContainer* mSourceContainer = nullptr; - std::function mEditHandler = nullptr; + std::function mEditHandler = nullptr; }; class UIDraw : public UIVisitor { diff --git a/packages/rendering/source/common/GLFWWindow.cpp b/packages/rendering/source/common/GLFWWindow.cpp index 35f1961b..8b0b0ef6 100644 --- a/packages/rendering/source/common/GLFWWindow.cpp +++ b/packages/rendering/source/common/GLFWWindow.cpp @@ -29,19 +29,24 @@ namespace { std::function key; std::function mouse; std::function scroll; + std::function chars; }; std::unordered_map sCallbacks; std::atomic_int sGLFWWindowCount = 0; - void set_callbacks(GLFWwindow* window, std::function key = nullptr, - std::function mouse = nullptr, - std::function scroll = nullptr) { - if (key || mouse || scroll) { + void set_callbacks(GLFWwindow* window, + std::function key = nullptr, + std::function mouse = nullptr, + std::function scroll = nullptr, + std::function chars = nullptr + ) { + if (chars || key || mouse || scroll) { Callbacks cb; cb.key = std::move(key); cb.mouse = std::move(mouse); cb.scroll = std::move(scroll); + cb.chars = std::move(chars); sCallbacks.emplace(window, std::move(cb)); } else { @@ -74,6 +79,14 @@ namespace { it->second.scroll(window, static_cast(xoffset), static_cast(yoffset)); } } + + static void invoke_chars(GLFWwindow* window, unsigned int codepoint) { + auto it = sCallbacks.find(window); + if (it != sCallbacks.end() && it->second.key) { + it->second.chars(window, codepoint); + } + } + } namespace l { @@ -165,6 +178,7 @@ namespace l { glfwSetKeyCallback(window, invoke_key); glfwSetMouseButtonCallback(window, invoke_mouse); glfwSetScrollCallback(window, invoke_scroll); + glfwSetCharCallback(window, invoke_chars); //l::rendering::read("images/favicon.ico") //GLFWimage icon; @@ -202,11 +216,13 @@ namespace l { void GLFWWindowHandle::SetInput( std::function keyCallback, std::function mouseCallback, - std::function scrollCallback) { + std::function scrollCallback, + std::function charsCallback + ) { if (!IsValid()) { return; } - set_callbacks(mHandle.get(), std::move(keyCallback), std::move(mouseCallback), std::move(scrollCallback)); + set_callbacks(mHandle.get(), std::move(keyCallback), std::move(mouseCallback), std::move(scrollCallback), std::move(charsCallback)); SetMouseMode(); diff --git a/packages/rendering/source/common/ui/UINodeEditor.cpp b/packages/rendering/source/common/ui/UINodeEditor.cpp index b93377a0..194f42b2 100644 --- a/packages/rendering/source/common/ui/UINodeEditor.cpp +++ b/packages/rendering/source/common/ui/UINodeEditor.cpp @@ -223,44 +223,33 @@ namespace l::ui { } }); - mTextEditVisitor.SetEditHandler([&](int32_t nodeId, int8_t channelId, std::string& text) { - if (mNGSchema == nullptr) { + mTextEditVisitor.SetEditHandler([&](int32_t nodeId, int8_t channelId, std::string& text, bool noedit) { + if (mNGSchema == nullptr || mKeyState == nullptr) { return; } + auto [keyPressed, keyDetections] = mKeyState->LastKeyPressed(); auto node = mNGSchema->GetNode(nodeId); - if (text.empty() && node->IsInputDataEditable(channelId) && node->IsInputDataText(channelId)) { + if (noedit && node->IsInputDataEditable(channelId) && node->IsInputDataText(channelId)) { if (channelId < node->GetNumInputs()) { text = node->GetInputText(channelId); } else if (channelId < node->GetNumOutputs()) { text = node->GetOutputText(channelId); } - if (ImGui::IsKeyDown(ImGuiKey::ImGuiKey_Enter)) { - } + mLastKeyPressed = keyPressed; + mLastKeyDetections = keyDetections; } - if (mLastKeyPressed != mKeyState->LastKeyPressed() || mKeyState->LastKeyDetections() % 10 == 0) { - mLastKeyPressed = mKeyState->LastKeyPressed(); - if( - mLastKeyPressed >= 'a' && mLastKeyPressed <= 'z' || - mLastKeyPressed >= 'A' && mLastKeyPressed <= 'Z' || - mLastKeyPressed >= '0' && mLastKeyPressed <= '9' || - mLastKeyPressed == ' ' || - mLastKeyPressed == '-' || - mLastKeyPressed == '_' || - mLastKeyPressed == '.' || - mLastKeyPressed == ':' || - mLastKeyPressed == '(' || - mLastKeyPressed == ')' || - mLastKeyPressed == '[' || - mLastKeyPressed == ']' - ) - text += mLastKeyPressed; - - if (channelId < node->GetNumInputs()) { - node->SetInput(channelId, text); + if (mLastKeyPressed != keyPressed || keyDetections != mLastKeyDetections) { + if (text.size() <= 16) { + text += keyPressed; } + mLastKeyPressed = keyPressed; + mLastKeyDetections = keyDetections; + } + if (!noedit && channelId < node->GetNumInputs()) { + node->SetInput(channelId, text); } }); diff --git a/packages/rendering/source/common/ui/UIVisitors.cpp b/packages/rendering/source/common/ui/UIVisitors.cpp index cba64ad0..b9c42fe8 100644 --- a/packages/rendering/source/common/ui/UIVisitors.cpp +++ b/packages/rendering/source/common/ui/UIVisitors.cpp @@ -294,22 +294,26 @@ namespace l::ui { mEditing = true; mSourceContainer = &container; mSourceContainer->SetNotification(UIContainer_TextEditFlag); + if (mEditHandler) { + mEditHandler(container.GetNodeId(), static_cast(container.GetChannelId()), mEditedText, true); + } } } if (mEditing && mSourceContainer == &container) { + if (ImGui::IsKeyPressed(ImGuiKey::ImGuiKey_Backspace, true)) { + if (!mEditedText.empty()) { + mEditedText.pop_back(); + } + } if (mEditHandler) { - mEditHandler(container.GetNodeId(), static_cast(container.GetChannelId()), mEditedText); + mEditHandler(container.GetNodeId(), static_cast(container.GetChannelId()), mEditedText, false); } - if (ImGui::IsKeyPressed(ImGuiKey::ImGuiKey_Enter, false)) { mSourceContainer->ClearNotification(UIContainer_TextEditFlag); mEditing = false; mSourceContainer = nullptr; mEditedText.clear(); } - if (ImGui::IsKeyPressed(ImGuiKey::ImGuiKey_Backspace, false)) { - mEditedText.pop_back(); - } return mEditing; } return false; From 3f4e31dd57fd91b7b8293c00de7b149641e62722 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 8 Jul 2025 17:50:41 +0200 Subject: [PATCH 008/179] NG: Use imgui character input io since dockable windows wont work with central char input dispatching with uiwindow. --- .../include/rendering/ui/UINodeEditor.h | 4 ---- packages/rendering/source/common/GLFWWindow.cpp | 2 +- .../rendering/source/common/ui/UINodeEditor.cpp | 17 +++++------------ 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/packages/rendering/include/rendering/ui/UINodeEditor.h b/packages/rendering/include/rendering/ui/UINodeEditor.h index 0d08cdab..be0fd99b 100644 --- a/packages/rendering/include/rendering/ui/UINodeEditor.h +++ b/packages/rendering/include/rendering/ui/UINodeEditor.h @@ -39,7 +39,6 @@ namespace l::ui { void SetOverlayContentWindow(std::function action); void SetNGSchema(l::nodegraph::NodeGraphSchema* ngSchema); - void SetKeyState(l::hid::KeyState* keyState); void SetEventListener(std::function cb); l::nodegraph::NodeGraphSchema* GetNGSchema(); @@ -59,9 +58,6 @@ namespace l::ui { UITextEdit mTextEditVisitor; l::nodegraph::NodeGraphSchema* mNGSchema = nullptr; - l::hid::KeyState* mKeyState = nullptr; - int32_t mLastKeyPressed = 0; - int32_t mLastKeyDetections = 0; std::vector> mEventListeners; std::function mOverlayContentWindow = nullptr; diff --git a/packages/rendering/source/common/GLFWWindow.cpp b/packages/rendering/source/common/GLFWWindow.cpp index 8b0b0ef6..2feb7939 100644 --- a/packages/rendering/source/common/GLFWWindow.cpp +++ b/packages/rendering/source/common/GLFWWindow.cpp @@ -82,7 +82,7 @@ namespace { static void invoke_chars(GLFWwindow* window, unsigned int codepoint) { auto it = sCallbacks.find(window); - if (it != sCallbacks.end() && it->second.key) { + if (it != sCallbacks.end() && it->second.chars) { it->second.chars(window, codepoint); } } diff --git a/packages/rendering/source/common/ui/UINodeEditor.cpp b/packages/rendering/source/common/ui/UINodeEditor.cpp index 194f42b2..68165c10 100644 --- a/packages/rendering/source/common/ui/UINodeEditor.cpp +++ b/packages/rendering/source/common/ui/UINodeEditor.cpp @@ -224,11 +224,10 @@ namespace l::ui { }); mTextEditVisitor.SetEditHandler([&](int32_t nodeId, int8_t channelId, std::string& text, bool noedit) { - if (mNGSchema == nullptr || mKeyState == nullptr) { + if (mNGSchema == nullptr) { return; } - auto [keyPressed, keyDetections] = mKeyState->LastKeyPressed(); auto node = mNGSchema->GetNode(nodeId); if (noedit && node->IsInputDataEditable(channelId) && node->IsInputDataText(channelId)) { if (channelId < node->GetNumInputs()) { @@ -237,16 +236,14 @@ namespace l::ui { else if (channelId < node->GetNumOutputs()) { text = node->GetOutputText(channelId); } - mLastKeyPressed = keyPressed; - mLastKeyDetections = keyDetections; } - if (mLastKeyPressed != keyPressed || keyDetections != mLastKeyDetections) { + ImGuiIO& io = ImGui::GetIO(); + for (int i = 0; i < io.InputQueueCharacters.Size; i++) { + ImWchar c = io.InputQueueCharacters[i]; if (text.size() <= 16) { - text += keyPressed; + text += static_cast(c); } - mLastKeyPressed = keyPressed; - mLastKeyDetections = keyDetections; } if (!noedit && channelId < node->GetNumInputs()) { node->SetInput(channelId, text); @@ -399,10 +396,6 @@ namespace l::ui { }); } - void UINodeEditor::SetKeyState(l::hid::KeyState* keyState) { - mKeyState = keyState; - } - l::nodegraph::NodeGraphSchema* UINodeEditor::GetNGSchema() { return mNGSchema; } From ec1702c3b7f6fa2329f645ebc4d3386adba73b0a Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 8 Jul 2025 18:07:58 +0200 Subject: [PATCH 009/179] NG: Make some text input fields editable. --- .../include/nodegraph/operations/NodeGraphOpTradingDataIO.h | 4 ++-- .../nodegraph/include/nodegraph/operations/NodeGraphOpUI.h | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h index 3c77afa6..b28ae6b7 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h @@ -31,8 +31,8 @@ namespace l::nodegraph { } AddInput("In", 0.0f, 2, -l::math::constants::FLTMAX, l::math::constants::FLTMAX, false, false); - AddInput2("Symbol", 16, InputFlags(false, true, false, true)); - AddInput2("Base", 16, InputFlags(false, true, false, true)); + AddInput2("Symbol", 16, InputFlags(false, true, true, true)); + AddInput2("Base", 16, InputFlags(false, true, true, true)); AddInput("Index", 2.0f, 1, 0.0f, 10.0f); diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index 2f740bfb..e9ffb35c 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -93,7 +93,7 @@ namespace l::nodegraph { { AddInput2("x", 1, InputFlags(false, false, false, false)); AddInput2("y", 1, InputFlags(false, false, false, false)); - AddInput2("name", 1, InputFlags(false, false, false, true)); + AddInput2("name", 1, InputFlags(false, true, true, true)); AddOutput("Interleaved Data"); } virtual ~GraphUIChartLine() { @@ -119,7 +119,7 @@ namespace l::nodegraph { AddInput2("high", 1, InputFlags(false, false, false, false)); AddInput2("low", 1, InputFlags(false, false, false, false)); AddInput2("volume", 1, InputFlags(false, false, false, false)); - AddInput2("name", 1, InputFlags(false, false, false, true)); + AddInput2("name", 1, InputFlags(false, true, true, true)); AddOutput("Interleaved Data"); } virtual ~GraphUICandleSticks() = default; From bae735f804129038a72cca04ea6dca36e7b1fc87 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 8 Jul 2025 18:20:18 +0200 Subject: [PATCH 010/179] NG: Fix name. --- .../nodegraph/include/nodegraph/operations/NodeGraphOpUI.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index e9ffb35c..01044ff9 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -89,7 +89,7 @@ namespace l::nodegraph { class GraphUIChartLine : public NodeGraphOpCached { public: GraphUIChartLine(NodeGraphBase* node) : - NodeGraphOpCached(node, "Chart Lines") + NodeGraphOpCached(node, "Chart Line") { AddInput2("x", 1, InputFlags(false, false, false, false)); AddInput2("y", 1, InputFlags(false, false, false, false)); @@ -100,7 +100,7 @@ namespace l::nodegraph { } virtual void DefaultDataInit() override { - mNode->SetInput(2, "Chart Lines"); + mNode->SetInput(2, "Chart Line"); } virtual void ProcessWriteCached(int32_t writtenSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; protected: From 589346a76b49fa35b7b1b7495c71b79008028f6b Mon Sep 17 00:00:00 2001 From: lnd3 Date: Wed, 9 Jul 2025 18:32:31 +0200 Subject: [PATCH 011/179] Minor fixes. --- .../operations/NodeGraphOpMathAritmethic.h | 32 +++++++-------- .../operations/NodeGraphOpTradingDataIO.h | 12 +++--- .../nodegraph/operations/NodeGraphOpUI.h | 27 ++++++------- .../rendering/include/rendering/ui/UIBase.h | 1 + .../include/rendering/ui/UIVisitors.h | 2 +- .../rendering/source/common/ui/UIBase.cpp | 5 +++ .../rendering/source/common/ui/UICreator.cpp | 12 +++++- .../rendering/source/common/ui/UIVisitors.cpp | 39 ++++++++++++++++--- 8 files changed, 86 insertions(+), 44 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h index 165b46e0..d5fc1c59 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h @@ -29,8 +29,8 @@ namespace l::nodegraph { MathAritmethicAdd(NodeGraphBase* node) : NodeGraphOp(node, "Add") { - AddInput("In1"); - AddInput("In2"); + AddInput2("In1", 1, InputFlags(false, false, false, false)); + AddInput2("In2", 1, InputFlags(false, false, false, false)); AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); AddOutput("In1+In2"); } @@ -54,8 +54,8 @@ namespace l::nodegraph { MathAritmethicMultiply(NodeGraphBase* node) : NodeGraphOp(node, "Multiply") { - AddInput("In1"); - AddInput("In2"); + AddInput2("In1", 1, InputFlags(false, false, false, false)); + AddInput2("In2", 1, InputFlags(false, false, false, false)); AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); AddOutput("In1*In2"); } @@ -80,8 +80,8 @@ namespace l::nodegraph { MathAritmethicSubtract(NodeGraphBase* node) : NodeGraphOp(node, "Subtract") { - AddInput("In1"); - AddInput("In2"); + AddInput2("In1", 1, InputFlags(false, false, false, false)); + AddInput2("In2", 1, InputFlags(false, false, false, false)); AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); AddOutput("In1-In2"); AddOutput("In2-In1"); @@ -109,7 +109,7 @@ namespace l::nodegraph { MathAritmethicNegate(NodeGraphBase* node) : NodeGraphOp(node, "Negate") { - AddInput("In"); + AddInput2("In", 1, InputFlags(false, false, false, false)); AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); AddOutput("-In"); } @@ -134,7 +134,7 @@ namespace l::nodegraph { MathAritmethicAbs(NodeGraphBase* node) : NodeGraphOp(node, "Abs") { - AddInput("In"); + AddInput2("In", 1, InputFlags(false, false, false, false)); AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); AddOutput("abs(In)"); AddOutput("max(In,0)"); @@ -165,7 +165,7 @@ namespace l::nodegraph { MathAritmethicLog(NodeGraphBase* node) : NodeGraphOp(node, "Log") { - AddInput("In"); + AddInput2("In", 1, InputFlags(false, false, false, false)); AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); AddInput("Base", 2.72f, 1, 1.0f, 10.0f); AddOutput("ln(In)"); @@ -200,9 +200,9 @@ namespace l::nodegraph { MathAritmethicMultiply3(NodeGraphBase* node) : NodeGraphOp(node, "Multiply3") { - AddInput("In1"); - AddInput("In2"); - AddInput("In3"); + AddInput2("In1", 1, InputFlags(false, false, false, false)); + AddInput2("In2", 1, InputFlags(false, false, false, false)); + AddInput2("In3", 1, InputFlags(false, false, false, false)); AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); AddOutput("In1*In2*In3"); } @@ -228,9 +228,9 @@ namespace l::nodegraph { MathAritmethicMultiplyAndAdd(NodeGraphBase* node) : NodeGraphOp(node, "Multiply & Add") { - AddInput("In1"); - AddInput("In2"); - AddInput("In3"); + AddInput2("In1", 1, InputFlags(false, false, false, false)); + AddInput2("In2", 1, InputFlags(false, false, false, false)); + AddInput2("In3", 1, InputFlags(false, false, false, false)); AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); AddOutput("In1*In2+In3"); } @@ -256,7 +256,7 @@ namespace l::nodegraph { MathAritmethicRound(NodeGraphBase* node) : NodeGraphOp(node, "Round") { - AddInput("In"); + AddInput2("In", 1, InputFlags(false, false, false, false)); AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); AddOutput("int(In+0.5)"); } diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h index b28ae6b7..40a557b5 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h @@ -30,15 +30,15 @@ namespace l::nodegraph { mName = "OCHLV Heikin-Ashi In"; } - AddInput("In", 0.0f, 2, -l::math::constants::FLTMAX, l::math::constants::FLTMAX, false, false); - AddInput2("Symbol", 16, InputFlags(false, true, true, true)); - AddInput2("Base", 16, InputFlags(false, true, true, true)); + AddInput2("In", 16, InputFlags(false, false, false, false)); + AddInput2("Symbol", 16, InputFlags(false, true, false, true)); + AddInput2("Base", 16, InputFlags(false, true, false, true)); AddInput("Index", 2.0f, 1, 0.0f, 10.0f); - AddOutput2("Symbol", 16, OutputFlags(true, true)); - AddOutput2("Base", 16, OutputFlags(true, true)); - AddOutput("Interval Min", 1.0f); + AddOutput2("Symbol", 16, OutputFlags(false, true)); + AddOutput2("Base", 16, OutputFlags(false, true)); + AddOutput("Min", 1.0f); AddOutput("Unixtime", 0.0f, 2); AddOutput("Open", 0.0f, 2); diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index 01044ff9..5666f762 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -47,7 +47,7 @@ namespace l::nodegraph { GraphUISlider(NodeGraphBase* node) : NodeGraphOp(node, "UI Slider") { - AddInput("In", 0.0f); + AddInput2("In", 1, InputFlags(false, false, false, false)); AddInput("Min", 0.0f); AddInput("Max", 1.0f); AddInput("Power", 1.0f); @@ -91,10 +91,11 @@ namespace l::nodegraph { GraphUIChartLine(NodeGraphBase* node) : NodeGraphOpCached(node, "Chart Line") { - AddInput2("x", 1, InputFlags(false, false, false, false)); - AddInput2("y", 1, InputFlags(false, false, false, false)); - AddInput2("name", 1, InputFlags(false, true, true, true)); - AddOutput("Interleaved Data"); + + AddInput2("X", 1, InputFlags(false, false, false, false)); + AddInput2("Y", 1, InputFlags(false, false, false, false)); + AddInput2("Name", 1, InputFlags(false, true, true, true)); + AddOutput("Data"); } virtual ~GraphUIChartLine() { @@ -113,14 +114,14 @@ namespace l::nodegraph { GraphUICandleSticks(NodeGraphBase* node) : NodeGraphOpCached(node, "Candle Sticks") { - AddInput2("unixtime", 1, InputFlags(false, false, false, false)); - AddInput2("open", 1, InputFlags(false, false, false, false)); - AddInput2("close", 1, InputFlags(false, false, false, false)); - AddInput2("high", 1, InputFlags(false, false, false, false)); - AddInput2("low", 1, InputFlags(false, false, false, false)); - AddInput2("volume", 1, InputFlags(false, false, false, false)); - AddInput2("name", 1, InputFlags(false, true, true, true)); - AddOutput("Interleaved Data"); + AddInput2("Unixtime", 1, InputFlags(false, false, false, false)); + AddInput2("Open", 1, InputFlags(false, false, false, false)); + AddInput2("Close", 1, InputFlags(false, false, false, false)); + AddInput2("High", 1, InputFlags(false, false, false, false)); + AddInput2("Low", 1, InputFlags(false, false, false, false)); + AddInput2("Volume", 1, InputFlags(false, false, false, false)); + AddInput2("Name", 1, InputFlags(false, true, true, true)); + AddOutput("Data"); } virtual ~GraphUICandleSticks() = default; virtual void DefaultDataInit() override { diff --git a/packages/rendering/include/rendering/ui/UIBase.h b/packages/rendering/include/rendering/ui/UIBase.h index 0940d285..bf44821f 100644 --- a/packages/rendering/include/rendering/ui/UIBase.h +++ b/packages/rendering/include/rendering/ui/UIBase.h @@ -22,6 +22,7 @@ namespace l::ui { void UIAdopt(std::unique_ptr&& ui); void UIErase(l::ui::UIBase* ui); void UIErase(std::string_view name); + void UIDestroy(); void UIHouseKeeping(); UIBase* UIGet(std::string_view name); bool UIHas(std::string_view name); diff --git a/packages/rendering/include/rendering/ui/UIVisitors.h b/packages/rendering/include/rendering/ui/UIVisitors.h index 756b60db..efe26edd 100644 --- a/packages/rendering/include/rendering/ui/UIVisitors.h +++ b/packages/rendering/include/rendering/ui/UIVisitors.h @@ -142,7 +142,7 @@ namespace l::ui { ImDrawList* mDrawList; std::function mDrawChannelTextHandler = nullptr; std::function mDrawLineHandler = nullptr; - ImColor mSelectColor = ImColor(darkGrey); + ImColor mSelectColor = ImColor(pastellYellow); }; class UILinkIO : public UIVisitor { diff --git a/packages/rendering/source/common/ui/UIBase.cpp b/packages/rendering/source/common/ui/UIBase.cpp index f51680b7..855ba99b 100644 --- a/packages/rendering/source/common/ui/UIBase.cpp +++ b/packages/rendering/source/common/ui/UIBase.cpp @@ -39,6 +39,11 @@ namespace l::ui { mUIDeleted.clear(); } + void UIDestroy() { + std::lock_guard lock(mUIsMutex); + mUIs.clear(); + } + UIBase* UIGet(std::string_view name) { std::lock_guard lock(mUIsMutex); for (auto& ui : mUIs) { diff --git a/packages/rendering/source/common/ui/UICreator.cpp b/packages/rendering/source/common/ui/UICreator.cpp index f8c7a9e1..67685b31 100644 --- a/packages/rendering/source/common/ui/UICreator.cpp +++ b/packages/rendering/source/common/ui/UICreator.cpp @@ -67,13 +67,21 @@ namespace l::ui { if (node.IsInputDataVisible(i)) { bool isText = node.IsInputDataText(i); bool isEditable = node.IsInputDataEditable(i); + auto inputDataText = CreateContainer(uiManager, (isEditable ? (isText ? l::ui::UIContainer_TextEditFlag : l::ui::UIContainer_TouchEditFlag) : 0) | l::ui::UIContainer_DrawFlag, l::ui::UIRenderType::NodeOutputValue, l::ui::UIAlignH::Left); inputDataText->SetColor(mediumWhite); inputDataText->SetPosition(ImVec2(estimatedWidth, 0.0f)); - inputDataText->SetSize(ImVec2(10 * 7, 14.0f)); + if (isText) { + auto textSize = ImGui::CalcTextSize(node.GetInputText(i).data()); + inputDataText->SetSize(ImVec2(textSize.x < 100.0f ? 100.0f : textSize.x, 14.0f)); + estimatedWidth += textSize.x; + } + else { + inputDataText->SetSize(ImVec2(10.0f * 4 + 10.0f, 14.0f)); + estimatedWidth += 10.0f * 4 + 10.0f; + } inputDataText->SetNodeId(node.GetId()); inputDataText->SetChannelId(i); - estimatedWidth += 10 * 7 + 10; row->Add(inputDataText); } diff --git a/packages/rendering/source/common/ui/UIVisitors.cpp b/packages/rendering/source/common/ui/UIVisitors.cpp index b9c42fe8..711deba9 100644 --- a/packages/rendering/source/common/ui/UIVisitors.cpp +++ b/packages/rendering/source/common/ui/UIVisitors.cpp @@ -308,7 +308,7 @@ namespace l::ui { if (mEditHandler) { mEditHandler(container.GetNodeId(), static_cast(container.GetChannelId()), mEditedText, false); } - if (ImGui::IsKeyPressed(ImGuiKey::ImGuiKey_Enter, false)) { + if (ImGui::IsKeyPressed(ImGuiKey::ImGuiKey_Enter, false) || ImGui::IsKeyPressed(ImGuiKey::ImGuiKey_Escape, false)) { mSourceContainer->ClearNotification(UIContainer_TextEditFlag); mEditing = false; mSourceContainer = nullptr; @@ -352,6 +352,24 @@ namespace l::ui { const char* nameEnd; auto renderType = container.GetRenderData().mType; + + + switch (container.GetRenderData().mType) { + case l::ui::UIRenderType::Rect: + case l::ui::UIRenderType::RectFilled: + case l::ui::UIRenderType::Texture: + case l::ui::UIRenderType::LinkH: + case l::ui::UIRenderType::NodeOutputValue: + if (container.HasConfigFlag(UIContainer_SelectFlag) && container.HasNotification(UIContainer_SelectFlag)) { + auto p1cpy = ImVec2(p1.x - 1.0f, p1.y - 1.0f); + auto p2cpy = ImVec2(p2.x + 1.0f, p2.y + 1.0f); + mDrawList->AddRect(p1cpy, p2cpy, mSelectColor, 0.0f, 0, 3.0f * container.GetScale() * layoutArea.mScale); + } + break; + default: + break; + } + switch (renderType) { case l::ui::UIRenderType::Rect: mDrawList->AddRect(p1, p2, color, 5.0f, ImDrawFlags_RoundCornersAll, 1.0f * container.GetScale() * layoutArea.mScale); @@ -454,21 +472,30 @@ namespace l::ui { case l::ui::UIRenderType::RectFilled: case l::ui::UIRenderType::Texture: case l::ui::UIRenderType::LinkH: - if (container.HasConfigFlag(UIContainer_SelectFlag) && container.HasNotification(UIContainer_SelectFlag)) { + case l::ui::UIRenderType::NodeOutputValue: + if (container.HasConfigFlag(UIContainer_TouchEditFlag) && container.HasNotification(UIContainer_TouchEditFlag)) { + auto p1cpy = ImVec2(p1.x - 1.0f, p1.y - 1.0f); + auto p2cpy = ImVec2(p2.x + 1.0f, p2.y + 1.0f); + mDrawList->AddRect(p1cpy, p2cpy, mSelectColor, 0.0f, 0, 1.0f * container.GetScale() * layoutArea.mScale); + } + if (container.HasConfigFlag(UIContainer_TextEditFlag) && container.HasNotification(UIContainer_TextEditFlag)) { auto p1cpy = ImVec2(p1.x - 1.0f, p1.y - 1.0f); auto p2cpy = ImVec2(p2.x + 1.0f, p2.y + 1.0f); - mDrawList->AddRect(p1cpy, p2cpy, mSelectColor, 0.0f, 0, 1.0f); + mDrawList->AddRect(p1cpy, p2cpy, mSelectColor, 0.0f, 0, 1.0f * container.GetScale() * layoutArea.mScale); } if (container.HasConfigFlag(ui::UIContainer_ResizeFlag)) { float size = 3.0f * layoutArea.mScale; ImVec2 p3 = layoutArea.Transform(pLowRight, ImVec2(-size, -size)); - ImVec2 p4 = layoutArea.Transform(pLowRight, ImVec2(size, size)); + ImVec2 p4 = layoutArea.Transform(pLowRight, ImVec2(size - 2, size - 2)); if (container.HasNotification(ui::UIContainer_ResizeFlag)) { float size2 = 5.0f * layoutArea.mScale; p3 = layoutArea.Transform(pLowRight, ImVec2(-size2, -size2)); - p4 = layoutArea.Transform(pLowRight, ImVec2(size2, size2)); + p4 = layoutArea.Transform(pLowRight, ImVec2(size2 - 1, size2 - 1)); + mDrawList->AddRectFilled(p3, p4, mSelectColor); + } + else { + mDrawList->AddRectFilled(p3, p4, color); } - mDrawList->AddRectFilled(p3, p4, color); } break; default: From 5c69598fdcb2c9bddb35cf6a700bd0dab4f95b03 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Wed, 9 Jul 2025 18:45:35 +0200 Subject: [PATCH 012/179] Add size param to node creator so we save that to json as well. --- .../nodegraph/operations/NodeGraphOpTradingDataIO.h | 2 +- .../nodegraph/include/nodegraph/operations/NodeGraphOpUI.h | 2 +- packages/rendering/include/rendering/ui/UICreator.h | 2 +- packages/rendering/source/common/ui/UICreator.cpp | 5 ++++- packages/rendering/source/common/ui/UINodeEditor.cpp | 7 ++----- 5 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h index 40a557b5..3832294b 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h @@ -40,7 +40,7 @@ namespace l::nodegraph { AddOutput2("Base", 16, OutputFlags(false, true)); AddOutput("Min", 1.0f); - AddOutput("Unixtime", 0.0f, 2); + AddOutput("Time", 0.0f, 2); AddOutput("Open", 0.0f, 2); AddOutput("Close", 0.0f, 2); AddOutput("High", 0.0f, 2); diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index 5666f762..79bb112f 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -114,7 +114,7 @@ namespace l::nodegraph { GraphUICandleSticks(NodeGraphBase* node) : NodeGraphOpCached(node, "Candle Sticks") { - AddInput2("Unixtime", 1, InputFlags(false, false, false, false)); + AddInput2("Time", 1, InputFlags(false, false, false, false)); AddInput2("Open", 1, InputFlags(false, false, false, false)); AddInput2("Close", 1, InputFlags(false, false, false, false)); AddInput2("High", 1, InputFlags(false, false, false, false)); diff --git a/packages/rendering/include/rendering/ui/UICreator.h b/packages/rendering/include/rendering/ui/UICreator.h index fa92f611..c5a83bcd 100644 --- a/packages/rendering/include/rendering/ui/UICreator.h +++ b/packages/rendering/include/rendering/ui/UICreator.h @@ -9,5 +9,5 @@ namespace l::ui { - UIHandle CreateUINode(UIManager& uiManager, l::nodegraph::NodeGraphBase& node, ImVec2 p); + UIHandle CreateUINode(UIManager& uiManager, l::nodegraph::NodeGraphBase& node, ImVec2 p, ImVec2 s = ImVec2(0.0f, 0.0f)); } diff --git a/packages/rendering/source/common/ui/UICreator.cpp b/packages/rendering/source/common/ui/UICreator.cpp index 67685b31..926740ac 100644 --- a/packages/rendering/source/common/ui/UICreator.cpp +++ b/packages/rendering/source/common/ui/UICreator.cpp @@ -8,7 +8,7 @@ namespace l::ui { - UIHandle CreateUINode(UIManager& uiManager, l::nodegraph::NodeGraphBase& node, ImVec2 p) { + UIHandle CreateUINode(UIManager& uiManager, l::nodegraph::NodeGraphBase& node, ImVec2 p, ImVec2 s) { auto numInputChannels = node.GetNumInputs(); auto numOutputChannels = node.GetNumOutputs(); @@ -128,6 +128,9 @@ namespace l::ui { } sizeEstimate.x += node4->GetContainerArea().mMargin * 2 + 2.0f; + if (sizeEstimate.x < s.x) { + sizeEstimate.x = s.x; + } node4->SetSize(sizeEstimate); return node4; diff --git a/packages/rendering/source/common/ui/UINodeEditor.cpp b/packages/rendering/source/common/ui/UINodeEditor.cpp index 68165c10..207035e1 100644 --- a/packages/rendering/source/common/ui/UINodeEditor.cpp +++ b/packages/rendering/source/common/ui/UINodeEditor.cpp @@ -350,11 +350,8 @@ namespace l::ui { if (node != nullptr) { auto& uiData = node->GetUIData(); auto p = ImVec2(uiData.x, uiData.y); - //auto s = ImVec2(uiData.w, uiData.h); - auto uiNode = l::ui::CreateUINode(mUIManager, *node, p); - //if (s.x > 10.0f && s.y > 10.0f) { - // uiNode->SetSize(s); - //} + auto s = ImVec2(uiData.w, uiData.h); + auto uiNode = l::ui::CreateUINode(mUIManager, *node, p, s); //LOG(LogInfo) << "Replicated node type " << node->GetTypeId() << " as a ui node"; mUIRoot->Add(uiNode); From 3daea10a64846bcb6d89dfee72fba7071092ddb6 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 10 Jul 2025 02:28:28 +0200 Subject: [PATCH 013/179] NG: Add node pow and level trigger. Fix node size on loading from json. Fix some node channel names. --- .../operations/NodeGraphOpMathAritmethic.h | 24 +++++++++ .../operations/NodeGraphOpMathNumerical.h | 51 +++++++++++++++++++ .../operations/NodeGraphOpSignalFilter.h | 4 +- .../operations/NodeGraphOpTradingFilter.h | 4 +- .../source/common/NodeGraphSchema.cpp | 8 +++ .../rendering/source/common/ui/UICreator.cpp | 5 +- 6 files changed, 91 insertions(+), 5 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h index d5fc1c59..4f9c7601 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h @@ -276,4 +276,28 @@ namespace l::nodegraph { } }; + /*********************************************************************/ + class MathAritmethicPow : public NodeGraphOp { + public: + MathAritmethicPow(NodeGraphBase* node) : + NodeGraphOp(node, "Pow") + { + AddInput2("In", 1, InputFlags(false, false, false, false)); + AddInput("Exponent", 2.72f, 1, 1.0f, 10.0f); + AddOutput("exp(In)"); + } + + virtual ~MathAritmethicPow() = default; + virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { + auto input0 = &inputs.at(0).Get(numSamples); + auto exponent = inputs.at(2).Get(); + auto output1 = &outputs.at(0).Get(numSamples); + + for (int32_t i = 0; i < numSamples; i++) { + auto in = *input0++; + auto pow = l::math::pow(in, exponent); + *output1++ = pow; + } + } + }; } \ No newline at end of file diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index ab0a314d..6019141b 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -206,4 +206,55 @@ namespace l::nodegraph { float mInputPrev = 0.0f; }; + /*********************************************************************/ + class MathNumericalLevelTrigger : public NodeGraphOp { + public: + MathNumericalLevelTrigger(NodeGraphBase* node) : + NodeGraphOp(node, "Level Trigger") + { + AddInput2("In", 1, InputFlags(false, false, false, false)); + AddInput2("In limits", 1, InputFlags(false, false, false, false)); + AddInput("Num levels", 1.0f, 1, 1.0f, 10.0f, true, true); + AddInput("Min%", 1.0f, 1, 0.0f, 1.0f, true, true); + AddInput("Max%", 1.0f, 1, 0.0f, 1.0f, true, true); + AddOutput("Level", 0.0f, 1); + AddOutput("Pulse", 0.0f, 1); + } + + virtual ~MathNumericalLevelTrigger() = default; + virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { + auto input = &inputs.at(0).Get(numSamples); + auto inlimit = l::math::abs(inputs.at(1).Get()); + auto numLevels = l::math::clamp(inputs.at(2).Get(), 1.0f, 10.0f); + auto min = l::math::clamp(inputs.at(3).Get(), 0.0f, 1.0f); + auto max = l::math::clamp(inputs.at(4).Get(), min, 1.0f); + auto levelOutput = &outputs.at(0).Get(numSamples); + auto pulseOutput = &outputs.at(1).Get(numSamples); + + for (int32_t i = 0; i < numSamples; i++) { + float in = *input++; + float inLimited = l::math::clamp(in, -inlimit, inlimit); + float inNorm = 0.0f; + if (inlimit > 0.0f) { + inNorm = (inLimited + inlimit) / (2.0f * inlimit); + } + float inClamped = l::math::clamp(inNorm, min, max); + float minmax = max - min; + float level = 0.0f; + if (minmax > 0.0f) { + level = numLevels * inClamped / minmax; + } + float pulse = 0.0f; + if (static_cast(mLevelPrev) != static_cast(level)) { + pulse = level > mLevelPrev ? 1.0f : -1.0f; + } + + mLevelPrev = level; + *levelOutput++ = level; + *pulseOutput++ = pulse; + } + } + protected: + float mLevelPrev = 0.0f; + }; } \ No newline at end of file diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalFilter.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalFilter.h index 58b4a951..f314445d 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalFilter.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalFilter.h @@ -135,8 +135,8 @@ namespace l::nodegraph { mInputManager.AddInput(InputIterationType::SAMPLED_ARRAY, AddInput("In")); mInputManager.AddInput(InputIterationType::SAMPLED_ARRAY, AddInput("Weight")); - AddInput("Kernel Size", 1.0f, 1, 1.0f, 5000.0f); - AddInput("Kernel Balance", 0.0f, 1, 0.0f, 10.0f); + AddInput("Kernel", 1.0f, 1, 1.0f, 5000.0f); + AddInput("Balance", 0.0f, 1, 0.0f, 10.0f); AddInput("Weight Accent", 1.0f, 1, 0.0f, 10.0f); AddInput("Gamma", 1.0f, 1, 0.0f, 10.0f); diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingFilter.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingFilter.h index 8b9db4ba..6ddfa922 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingFilter.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingFilter.h @@ -77,8 +77,8 @@ namespace l::nodegraph { { AddInput("In"); AddInput("Weight", 1.0f); - AddInput("Kernel Size", 1.0f, 1, 1.0f, 5000.0f); - AddInput("Weight Accent", 1.0f, 1, 0.0f, 100.0f); + AddInput("Kernel", 1.0f, 1, 1.0f, 5000.0f); + AddInput("Accent", 1.0f, 1, 0.0f, 100.0f); AddOutput("Out", 0.0f); } diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 0fae8a85..7116ae9b 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -275,6 +275,9 @@ namespace l::nodegraph { case 108: node = mMainNodeGraph.NewNode(id, NodeType::Default); break; + case 109: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; // Math logical operators case 120: @@ -300,6 +303,9 @@ namespace l::nodegraph { case 143: node = mMainNodeGraph.NewNode(id, NodeType::Default); break; + case 144: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; // Trading data io case 200: @@ -588,6 +594,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Aritmethic", 106, "Mul3"); RegisterNodeType("Math.Aritmethic", 107, "Madd"); RegisterNodeType("Math.Aritmethic", 108, "Round"); + RegisterNodeType("Math.Aritmethic", 109, "Pow"); } else if (typeGroup == "Math.Logic") { RegisterNodeType("Math.Logic", 120, "And"); @@ -599,6 +606,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Numerical", 141, "Derivate"); RegisterNodeType("Math.Numerical", 142, "Difference Normalized"); RegisterNodeType("Math.Numerical", 143, "Difference"); + RegisterNodeType("Math.Numerical", 144, "Level Trigger"); } else if (typeGroup == "Trading.Data IO") { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); diff --git a/packages/rendering/source/common/ui/UICreator.cpp b/packages/rendering/source/common/ui/UICreator.cpp index 926740ac..b8eb8e45 100644 --- a/packages/rendering/source/common/ui/UICreator.cpp +++ b/packages/rendering/source/common/ui/UICreator.cpp @@ -128,9 +128,12 @@ namespace l::ui { } sizeEstimate.x += node4->GetContainerArea().mMargin * 2 + 2.0f; - if (sizeEstimate.x < s.x) { + if (s.x > 0.0f) { sizeEstimate.x = s.x; } + if (s.y > sizeEstimate.y) { + sizeEstimate.y = s.y; + } node4->SetSize(sizeEstimate); return node4; From 7426b06ad131e239c6b6d29b27cbd8bfe5f11c82 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 10 Jul 2025 13:49:18 +0200 Subject: [PATCH 014/179] NG: Take input range in level trigger node. --- .../operations/NodeGraphOpMathNumerical.h | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 6019141b..8d96bff1 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -213,36 +213,41 @@ namespace l::nodegraph { NodeGraphOp(node, "Level Trigger") { AddInput2("In", 1, InputFlags(false, false, false, false)); - AddInput2("In limits", 1, InputFlags(false, false, false, false)); + AddInput2("Max", 1, InputFlags(false, false, false, false)); + AddInput2("Min", 1, InputFlags(false, false, false, false)); AddInput("Num levels", 1.0f, 1, 1.0f, 10.0f, true, true); - AddInput("Min%", 1.0f, 1, 0.0f, 1.0f, true, true); AddInput("Max%", 1.0f, 1, 0.0f, 1.0f, true, true); + AddInput("Min%", 1.0f, 1, 0.0f, 1.0f, true, true); AddOutput("Level", 0.0f, 1); AddOutput("Pulse", 0.0f, 1); } virtual ~MathNumericalLevelTrigger() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input = &inputs.at(0).Get(numSamples); - auto inlimit = l::math::abs(inputs.at(1).Get()); - auto numLevels = l::math::clamp(inputs.at(2).Get(), 1.0f, 10.0f); - auto min = l::math::clamp(inputs.at(3).Get(), 0.0f, 1.0f); - auto max = l::math::clamp(inputs.at(4).Get(), min, 1.0f); + auto inInput = &inputs.at(0).Get(numSamples); + auto maxInput = &inputs.at(1).Get(); + auto minInput = &inputs.at(2).Get(); + auto numLevels = l::math::clamp(inputs.at(3).Get(), 1.0f, 10.0f); + auto max = l::math::clamp(inputs.at(4).Get(), 0.0f, 1.0f); + auto min = l::math::clamp(inputs.at(5).Get(), 0.0f, max); auto levelOutput = &outputs.at(0).Get(numSamples); auto pulseOutput = &outputs.at(1).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { - float in = *input++; - float inLimited = l::math::clamp(in, -inlimit, inlimit); - float inNorm = 0.0f; - if (inlimit > 0.0f) { - inNorm = (inLimited + inlimit) / (2.0f * inlimit); + float in = *inInput++; + float inMax = *maxInput++; + float inMin = *minInput++; + float inLimited = l::math::clamp(in, inMin, inMax); + float inRange = inMax - inMin; + float inRangeFactor = 0.0f; + if (inRange > 0.0f) { + inRangeFactor = (inLimited - inMin) / inRange; } - float inClamped = l::math::clamp(inNorm, min, max); - float minmax = max - min; + float inRangeFactorClamped = l::math::clamp(inRangeFactor, min, max); + float minmaxRange = max - min; float level = 0.0f; - if (minmax > 0.0f) { - level = numLevels * inClamped / minmax; + if (minmaxRange > 0.0f) { + level = numLevels * inRangeFactorClamped / minmaxRange; } float pulse = 0.0f; if (static_cast(mLevelPrev) != static_cast(level)) { From 6c0eb3b100c83fea962b7b9436cc7a781f5c70a7 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 10 Jul 2025 18:54:42 +0200 Subject: [PATCH 015/179] NG: Split up aritmetic nodes. --- .../operations/NodeGraphOpMathNumerical.h | 152 +----------------- .../operations/NodeGraphOpMathNumerical.cpp | 145 +++++++++++++++++ 2 files changed, 152 insertions(+), 145 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 8d96bff1..711c2ddf 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -36,33 +36,7 @@ namespace l::nodegraph { } virtual ~MathNumericalIntegral() = default; - virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override { - auto input0 = inputs.at(0).GetIterator(numSamples); - auto friction = inputs.at(1).Get(); - auto frictionFactor = l::math::clamp(l::math::pow(friction, 0.25f), 0.0f, 1.0f); - auto lodExp = inputs.at(2).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto output = outputs.at(0).GetIterator(numSamples, lodFactor); - - for (int32_t i = 0; i < numSamples; i++) { - mOutput += *input0++; - mOutput *= frictionFactor; - *output++ = mOutput; - } - - mReadSamples += numSamples; - - if (mReadSamples >= numCacheSamples) { - mReadSamples = 0; - mOutput = 0.0f; - } - - if (isnan(mOutput)) { - mOutput = 0.0f; - } - - - } + virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; virtual void Reset() override { mOutput = 0.0f; } @@ -84,31 +58,7 @@ namespace l::nodegraph { } virtual ~MathNumericalDerivate() = default; - virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override { - auto input0 = inputs.at(0).GetIterator(numSamples); - auto lodExp = inputs.at(1).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto output = outputs.at(0).GetIterator(numSamples, lodFactor); - - for (int32_t i = 0; i < numSamples; i++) { - float input = *input0++; - float value = input - mInputPrev; - float divisor = l::math::abs(input) + l::math::abs(mInputPrev); - if (divisor > 0.0f) { - value = 2.0f * value / divisor; - } - mInputPrev = input; - *output++ = value; - } - - mReadSamples += numSamples; - - if (mReadSamples >= numCacheSamples) { - mReadSamples = 0; - mInputPrev = 0.0f; - } - - } + virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; protected: int32_t mReadSamples = 0; @@ -127,40 +77,7 @@ namespace l::nodegraph { } virtual ~MathNumericalDiffNorm() = default; - virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override { - auto input0 = inputs.at(0).GetIterator(numSamples); - auto lodExp = inputs.at(1).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto output = outputs.at(0).GetIterator(numSamples, lodFactor); - - for (int32_t i = 0; i < numSamples; i++) { - float input = *input0++; - float value = mInputPrev; - if (mInputPrev != 0.0f) { - if (input > 0.0f && mInputPrev > 0.0f) { - value = input / mInputPrev; - value = value - 1.0f; - } - else if (input < 0.0f && mInputPrev < 0.0f) { - value = input / mInputPrev; - value = (value - 1.0f); - } - else { - value = 0.0f; - } - } - mInputPrev = input; - *output++ = value; - } - - mReadSamples += numSamples; - - if (mReadSamples >= numCacheSamples) { - mReadSamples = 0; - mInputPrev = 0.0f; - } - - } + virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; protected: int32_t mReadSamples = 0; @@ -179,27 +96,7 @@ namespace l::nodegraph { } virtual ~MathNumericalDiff() = default; - virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override { - auto input0 = inputs.at(0).GetIterator(numSamples); - auto lodExp = inputs.at(1).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto output = outputs.at(0).GetIterator(numSamples, lodFactor); - - for (int32_t i = 0; i < numSamples; i++) { - float input = *input0++; - float value = input - mInputPrev; - mInputPrev = input; - *output++ = value; - } - - mReadSamples += numSamples; - - if (mReadSamples >= numCacheSamples) { - mReadSamples = 0; - mInputPrev = 0.0f; - } - - } + virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; protected: int32_t mReadSamples = 0; @@ -215,50 +112,15 @@ namespace l::nodegraph { AddInput2("In", 1, InputFlags(false, false, false, false)); AddInput2("Max", 1, InputFlags(false, false, false, false)); AddInput2("Min", 1, InputFlags(false, false, false, false)); - AddInput("Num levels", 1.0f, 1, 1.0f, 10.0f, true, true); + AddInput("Num levels", 1.0f, 1, 1.0f, 100.0f, true, true); AddInput("Max%", 1.0f, 1, 0.0f, 1.0f, true, true); - AddInput("Min%", 1.0f, 1, 0.0f, 1.0f, true, true); + AddInput("Min%", 0.0f, 1, 0.0f, 1.0f, true, true); AddOutput("Level", 0.0f, 1); AddOutput("Pulse", 0.0f, 1); } virtual ~MathNumericalLevelTrigger() = default; - virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto inInput = &inputs.at(0).Get(numSamples); - auto maxInput = &inputs.at(1).Get(); - auto minInput = &inputs.at(2).Get(); - auto numLevels = l::math::clamp(inputs.at(3).Get(), 1.0f, 10.0f); - auto max = l::math::clamp(inputs.at(4).Get(), 0.0f, 1.0f); - auto min = l::math::clamp(inputs.at(5).Get(), 0.0f, max); - auto levelOutput = &outputs.at(0).Get(numSamples); - auto pulseOutput = &outputs.at(1).Get(numSamples); - - for (int32_t i = 0; i < numSamples; i++) { - float in = *inInput++; - float inMax = *maxInput++; - float inMin = *minInput++; - float inLimited = l::math::clamp(in, inMin, inMax); - float inRange = inMax - inMin; - float inRangeFactor = 0.0f; - if (inRange > 0.0f) { - inRangeFactor = (inLimited - inMin) / inRange; - } - float inRangeFactorClamped = l::math::clamp(inRangeFactor, min, max); - float minmaxRange = max - min; - float level = 0.0f; - if (minmaxRange > 0.0f) { - level = numLevels * inRangeFactorClamped / minmaxRange; - } - float pulse = 0.0f; - if (static_cast(mLevelPrev) != static_cast(level)) { - pulse = level > mLevelPrev ? 1.0f : -1.0f; - } - - mLevelPrev = level; - *levelOutput++ = level; - *pulseOutput++ = pulse; - } - } + virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override; protected: float mLevelPrev = 0.0f; }; diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 4e22ec34..4c845722 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -9,4 +9,149 @@ namespace l::nodegraph { + void MathNumericalIntegral::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + auto input0 = inputs.at(0).GetIterator(numSamples); + auto friction = inputs.at(1).Get(); + auto frictionFactor = l::math::clamp(l::math::pow(friction, 0.25f), 0.0f, 1.0f); + auto lodExp = inputs.at(2).Get(); + auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); + auto output = outputs.at(0).GetIterator(numSamples, lodFactor); + + for (int32_t i = 0; i < numSamples; i++) { + mOutput += *input0++; + mOutput *= frictionFactor; + *output++ = mOutput; + } + + mReadSamples += numSamples; + + if (mReadSamples >= numCacheSamples) { + mReadSamples = 0; + mOutput = 0.0f; + } + + if (isnan(mOutput)) { + mOutput = 0.0f; + } + } + + void MathNumericalDerivate::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + auto input0 = inputs.at(0).GetIterator(numSamples); + auto lodExp = inputs.at(1).Get(); + auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); + auto output = outputs.at(0).GetIterator(numSamples, lodFactor); + + for (int32_t i = 0; i < numSamples; i++) { + float input = *input0++; + float value = input - mInputPrev; + float divisor = l::math::abs(input) + l::math::abs(mInputPrev); + if (divisor > 0.0f) { + value = 2.0f * value / divisor; + } + mInputPrev = input; + *output++ = value; + } + + mReadSamples += numSamples; + + if (mReadSamples >= numCacheSamples) { + mReadSamples = 0; + mInputPrev = 0.0f; + } + } + + void MathNumericalDiffNorm::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + auto input0 = inputs.at(0).GetIterator(numSamples); + auto lodExp = inputs.at(1).Get(); + auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); + auto output = outputs.at(0).GetIterator(numSamples, lodFactor); + + for (int32_t i = 0; i < numSamples; i++) { + float input = *input0++; + float value = mInputPrev; + if (mInputPrev != 0.0f) { + if (input > 0.0f && mInputPrev > 0.0f) { + value = input / mInputPrev; + value = value - 1.0f; + } + else if (input < 0.0f && mInputPrev < 0.0f) { + value = input / mInputPrev; + value = (value - 1.0f); + } + else { + value = 0.0f; + } + } + mInputPrev = input; + *output++ = value; + } + + mReadSamples += numSamples; + + if (mReadSamples >= numCacheSamples) { + mReadSamples = 0; + mInputPrev = 0.0f; + } + } + + void MathNumericalDiff::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + auto input0 = inputs.at(0).GetIterator(numSamples); + auto lodExp = inputs.at(1).Get(); + auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); + auto output = outputs.at(0).GetIterator(numSamples, lodFactor); + + for (int32_t i = 0; i < numSamples; i++) { + float input = *input0++; + float value = input - mInputPrev; + mInputPrev = input; + *output++ = value; + } + + mReadSamples += numSamples; + + if (mReadSamples >= numCacheSamples) { + mReadSamples = 0; + mInputPrev = 0.0f; + } + + } + + void MathNumericalLevelTrigger::Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) { + auto inInput = &inputs.at(0).Get(numSamples); + auto maxInput = &inputs.at(1).Get(); + auto minInput = &inputs.at(2).Get(); + auto numLevels = l::math::clamp(inputs.at(3).Get(), 1.0f, 10.0f); + auto max = l::math::clamp(inputs.at(4).Get(), 0.0f, 1.0f); + auto min = l::math::clamp(inputs.at(5).Get(), 0.0f, max); + auto levelOutput = &outputs.at(0).Get(numSamples); + auto pulseOutput = &outputs.at(1).Get(numSamples); + + for (int32_t i = 0; i < numSamples; i++) { + float in = *inInput++; + float inMax = *maxInput++; + float inMin = *minInput++; + float inLimited = l::math::clamp(in, inMin, inMax); + float inRange = inMax - inMin; + float inRangeFactor = 0.0f; + if (inRange > 0.0f) { + inRangeFactor = (inLimited - inMin) / inRange; + } + float inRangeFactorClamped = l::math::clamp(inRangeFactor, min, max); + float minmaxRange = max - min; + float level = 0.0f; + if (minmaxRange > 0.0f) { + float levelMinMax = (inRangeFactorClamped - min) / minmaxRange; + level = numLevels * levelMinMax; + } + float pulse = 0.0f; + if (static_cast(mLevelPrev) != static_cast(level)) { + pulse = level > mLevelPrev ? 1.0f : -1.0f; + } + + mLevelPrev = level; + *levelOutput++ = level; + *pulseOutput++ = pulse; + } + } + } From faabeffbfe4198608951962f2a5b771a02dacf84 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 13 Jul 2025 15:32:01 +0200 Subject: [PATCH 016/179] Test no web socket auto ping and raw mode more easily with documentation. --- packages/network/source/common/NetworkConnection.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/network/source/common/NetworkConnection.cpp b/packages/network/source/common/NetworkConnection.cpp index 99f02be0..3c13943c 100644 --- a/packages/network/source/common/NetworkConnection.cpp +++ b/packages/network/source/common/NetworkConnection.cpp @@ -100,7 +100,15 @@ namespace l::network { SetResponseSize(expectedResponseSize); - curl_easy_setopt(mCurl, CURLOPT_CONNECT_ONLY, mIsWebSocket ? 2L : 0L); + if (mIsWebSocket) { + curl_easy_setopt(mCurl, CURLOPT_CONNECT_ONLY, 2L); + auto res = curl_easy_setopt(mCurl, CURLOPT_WS_OPTIONS, 0L); // CURLWS_RAW_MODE, CURLWS_NOAUTOPONG + ASSERT(res == CURLE_OK); + } + else { + curl_easy_setopt(mCurl, CURLOPT_CONNECT_ONLY, 0L); + } + curl_easy_setopt(mCurl, CURLOPT_URL, mRequestQuery.c_str()); LOG(LogDebug) << mRequestQuery; //curl_easy_setopt(mCurl, CURLOPT_FRESH_CONNECT, 0L); // only use if necessary to create a new connection From e073dab50f33bbf1ec193f8ac1ae72a28da1aa89 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Wed, 16 Jul 2025 18:32:27 +0200 Subject: [PATCH 017/179] Remove some error checking that caused missing data. --- .../source/common/operations/NodeGraphOpTradingDataIO.cpp | 2 +- .../nodegraph/source/common/operations/NodeGraphOpUI.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp index 290962ab..dbbe69ac 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp @@ -57,7 +57,7 @@ namespace l::nodegraph { if (mUnixtimePrev == 0) { mUnixtimePrev = unixtime; } - else if (unixtime != mUnixtimePrev + intervalMinutes * 60) { + else if (unixtime == mUnixtimePrev) { unixtime = 0; unixtimef = l::math::algorithm::convert(unixtime); } diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index a54d2495..735b2c52 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -114,10 +114,12 @@ namespace l::nodegraph { auto unixtimef = *input[0]; auto unixtime = l::math::algorithm::convert(unixtimef); if (unixtimef == 0.0f || mLatestUnixtime >= unixtime) { + //mLatestUnixtime = unixtime; + //break; + } + else { mLatestUnixtime = unixtime; - break; } - mLatestUnixtime = unixtime; for (int32_t i = 0; i < mChannels; i++) { *buf++ = *input[i]++; } From ccc091d302979eddca137736ef73f9895245fa10 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 17 Jul 2025 01:51:18 +0200 Subject: [PATCH 018/179] Zero memory properly so string_buffer also work with cstrings. --- packages/logging/include/logging/String.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/logging/include/logging/String.h b/packages/logging/include/logging/String.h index aeafea11..29c4223f 100644 --- a/packages/logging/include/logging/String.h +++ b/packages/logging/include/logging/String.h @@ -34,7 +34,9 @@ namespace l::string { template class string_buffer { public: - string_buffer() = default; + string_buffer() { + memset(mBuf, 0, BUFSIZE); + } ~string_buffer() = default; void pos(int32_t p) { @@ -42,6 +44,7 @@ namespace l::string { } void clear() { + mBuf[0] = 0; mPos = 0; cur() = 0; } From 86e4b5a7b29ef69af165cb9456c4719a951f52eb Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 19 Jul 2025 04:35:18 +0200 Subject: [PATCH 019/179] Network: Check curl handle in all exposed api functions. --- .../source/common/NetworkConnection.cpp | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/network/source/common/NetworkConnection.cpp b/packages/network/source/common/NetworkConnection.cpp index 3c13943c..e6403a8e 100644 --- a/packages/network/source/common/NetworkConnection.cpp +++ b/packages/network/source/common/NetworkConnection.cpp @@ -383,6 +383,22 @@ namespace l::network { } void ConnectionBase::WSClose() { + if (HasExpired()) { + mWebSocketCanSendData = false; + LOG(LogError) << "Failed wss close, connection expired"; + } + if (mCurl == nullptr) { + mWebSocketCanSendData = false; + LOG(LogError) << "Failed wss close, no curl instance"; + } + + ASSERT(mOngoingRequest); + + if (mCompletedRequest) { + // request probably timed out so discard data + return; + } + size_t sentBytes = 0; auto res = curl_ws_send(mCurl, nullptr, 0, &sentBytes, 0, CURLWS_CLOSE); if (res == CURLE_OK) { @@ -393,6 +409,15 @@ namespace l::network { } void ConnectionBase::NotifyAppendHeader(const char* contents, size_t size) { + if (HasExpired()) { + mWebSocketCanSendData = false; + LOG(LogError) << "Failed notify append header, connection expired"; + } + if (mCurl == nullptr) { + mWebSocketCanSendData = false; + LOG(LogError) << "Failed notify append header, no curl instance"; + } + ASSERT(mOngoingRequest); if (mCompletedRequest) { @@ -422,6 +447,15 @@ namespace l::network { } void ConnectionBase::NotifyAppendResponse(const char* contents, size_t size) { + if (HasExpired()) { + mWebSocketCanSendData = false; + LOG(LogError) << "Failed notify append response, connection expired"; + } + if (mCurl == nullptr) { + mWebSocketCanSendData = false; + LOG(LogError) << "Failed notify append response, no curl instance"; + } + ASSERT(mOngoingRequest); if (mCompletedRequest) { From 591a321def292d15b22bd76daad99cceeeecc45b Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 19 Jul 2025 07:57:27 +0200 Subject: [PATCH 020/179] Math: Add logx conversion function. --- packages/math/include/math/MathFunc.h | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/packages/math/include/math/MathFunc.h b/packages/math/include/math/MathFunc.h index a4bb6fb2..99745b66 100644 --- a/packages/math/include/math/MathFunc.h +++ b/packages/math/include/math/MathFunc.h @@ -242,6 +242,11 @@ namespace l::math { } } + template + auto logx(T base, T val) { + return log(val) / log(base); + } + // Sinc curve // A phase shifted sinc curve can be useful if it starts at zeroand ends at zero, for some bouncing behaviors(suggested by Hubert - Jan).Give k different integer values to tweak the amount of bounces.It peaks at 1.0, but that take negative values, which can make it unusable in some applications. template From e1806ce3ae478b5f2b1c700f3e99aa2b0a37c16a Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 19 Jul 2025 22:17:38 +0200 Subject: [PATCH 021/179] Network: Add auto reconnect state to websockets. --- .../include/network/NetworkConnection.h | 3 ++ .../include/network/NetworkInterfaceWS.h | 2 + .../network/include/network/NetworkManager.h | 2 + .../source/common/NetworkConnection.cpp | 8 ++++ .../source/common/NetworkInterfaceWS.cpp | 41 ++++++++++++++++--- .../network/source/common/NetworkManager.cpp | 37 +++++++++++++++++ 6 files changed, 87 insertions(+), 6 deletions(-) diff --git a/packages/network/include/network/NetworkConnection.h b/packages/network/include/network/NetworkConnection.h index edfd936b..0ac631ca 100644 --- a/packages/network/include/network/NetworkConnection.h +++ b/packages/network/include/network/NetworkConnection.h @@ -84,6 +84,8 @@ namespace l::network { int32_t WSWrite(const char* buffer, size_t size); int32_t WSRead(char* buffer, size_t size); void WSClose(); + bool WSAutoConnectEnabled(); + void WSSetAutoConnect(bool autoReconnect); const curl_ws_frame* GetWebSocketMeta(); @@ -120,6 +122,7 @@ namespace l::network { bool mIsWebSocket = false; bool mWebSocketCanReceiveData = false; bool mWebSocketCanSendData = false; + bool mWebSocketAutoConnect = false; }; template diff --git a/packages/network/include/network/NetworkInterfaceWS.h b/packages/network/include/network/NetworkInterfaceWS.h index 39d40f87..196ba1f5 100644 --- a/packages/network/include/network/NetworkInterfaceWS.h +++ b/packages/network/include/network/NetworkInterfaceWS.h @@ -39,6 +39,8 @@ namespace l::network { void ClearQueued(std::string_view interfaceName); bool IsConnected(std::string_view interfaceName); + bool IsAutoConnecting(std::string_view queryName); + void SetAutoConnect(std::string_view queryName, bool autoConnect); bool NetworkStatus(std::string_view interfaceName); diff --git a/packages/network/include/network/NetworkManager.h b/packages/network/include/network/NetworkManager.h index 2bc19ab7..3030cf46 100644 --- a/packages/network/include/network/NetworkManager.h +++ b/packages/network/include/network/NetworkManager.h @@ -51,6 +51,8 @@ namespace l::network { int32_t WSWrite(std::string_view queryName, const char* buffer, size_t size); int32_t WSRead(std::string_view queryName, char* buffer, size_t size); bool WSConnected(std::string_view queryName); + bool WSAutoConnectEnabled(std::string_view queryName); + void WSSetAutoConnect(std::string_view queryName, bool autoConnect); protected: std::thread mCurlPerformer; diff --git a/packages/network/source/common/NetworkConnection.cpp b/packages/network/source/common/NetworkConnection.cpp index e6403a8e..449371bd 100644 --- a/packages/network/source/common/NetworkConnection.cpp +++ b/packages/network/source/common/NetworkConnection.cpp @@ -408,6 +408,14 @@ namespace l::network { NotifyCompleteRequest(true); } + bool ConnectionBase::WSAutoConnectEnabled() { + return mWebSocketAutoConnect; + } + + void ConnectionBase::WSSetAutoConnect(bool autoReconnect) { + mWebSocketAutoConnect = autoReconnect; + } + void ConnectionBase::NotifyAppendHeader(const char* contents, size_t size) { if (HasExpired()) { mWebSocketCanSendData = false; diff --git a/packages/network/source/common/NetworkInterfaceWS.cpp b/packages/network/source/common/NetworkInterfaceWS.cpp index 791e5528..080a5409 100644 --- a/packages/network/source/common/NetworkInterfaceWS.cpp +++ b/packages/network/source/common/NetworkInterfaceWS.cpp @@ -30,7 +30,8 @@ namespace l::network { void NetworkInterfaceWS::Disconnect(std::string_view interfaceName) { auto networkManager = mNetworkManager.lock(); if (networkManager) { - networkManager->WSClose(interfaceName); + auto queryName = interfaceName; // With websocket, we have one query only per interface and it has the same name + networkManager->WSClose(queryName); } } @@ -48,7 +49,8 @@ namespace l::network { if (!query.empty()) { auto networkManager = mNetworkManager.lock(); if (networkManager) { - result = networkManager->PostQuery(interfaceName, "", retries, query, expectedResponseSize, timeOut, cb); + auto queryName = interfaceName; // With websocket, we have one query only per interface and it has the same name + result = networkManager->PostQuery(queryName, "", retries, query, expectedResponseSize, timeOut, cb); } } } @@ -63,7 +65,8 @@ namespace l::network { if (NetworkStatus(interfaceName)) { auto networkManager = mNetworkManager.lock(); if (networkManager) { - read = networkManager->WSRead(interfaceName, buffer, size); + auto queryName = interfaceName; // With websocket, we have one query only per interface and it has the same name + read = networkManager->WSRead(queryName, buffer, size); } } } @@ -93,7 +96,8 @@ namespace l::network { auto& queue = it->second.GetQueue(); while (!queue.empty() && maxQueued > 0) { auto& command = queue.front(); - auto written = networkManager->WSWrite(interfaceName, command.c_str(), command.size()); + auto queryName = interfaceName; // With websocket, we have one query only per interface and it has the same name + auto written = networkManager->WSWrite(queryName, command.c_str(), command.size()); if (written > 0) { queue.pop_front(); } @@ -134,7 +138,8 @@ namespace l::network { if (NetworkStatus(interfaceName)) { auto networkManager = mNetworkManager.lock(); if (networkManager) { - written = networkManager->WSWrite(interfaceName, buffer, size) >= 0; + auto queryName = interfaceName; // With websocket, we have one query only per interface and it has the same name + written = networkManager->WSWrite(queryName, buffer, size) >= 0; if (written < 0) { LOG(LogWarning) << "Failed to write to: " << interfaceName << " : error: " << written; } @@ -149,12 +154,36 @@ namespace l::network { if (it != mInterfaces.end()) { auto networkManager = mNetworkManager.lock(); if (networkManager) { - return networkManager->WSConnected(interfaceName); + auto queryName = interfaceName; // With websocket, we have one query only per interface and it has the same name + return networkManager->WSConnected(queryName); } } return false; } + bool NetworkInterfaceWS::IsAutoConnecting(std::string_view interfaceName) { + auto it = mInterfaces.find(interfaceName.data()); + if (it != mInterfaces.end()) { + auto networkManager = mNetworkManager.lock(); + if (networkManager) { + auto queryName = interfaceName; // With websocket, we have one query only per interface and it has the same name + return networkManager->WSAutoConnectEnabled(queryName); + } + } + return false; + } + + void NetworkInterfaceWS::SetAutoConnect(std::string_view interfaceName, bool autoConnect) { + auto it = mInterfaces.find(interfaceName.data()); + if (it != mInterfaces.end()) { + auto networkManager = mNetworkManager.lock(); + if (networkManager) { + auto queryName = interfaceName; // With websocket, we have one query only per interface and it has the same name + networkManager->WSSetAutoConnect(queryName, autoConnect); + } + } + } + bool NetworkInterfaceWS::NetworkStatus(std::string_view interfaceName) { auto it = mInterfaces.find(interfaceName.data()); if (it != mInterfaces.end()) { diff --git a/packages/network/source/common/NetworkManager.cpp b/packages/network/source/common/NetworkManager.cpp index 5542aa97..723c2d08 100644 --- a/packages/network/source/common/NetworkManager.cpp +++ b/packages/network/source/common/NetworkManager.cpp @@ -257,4 +257,41 @@ namespace l::network { return request->IsAlive(); } + + bool NetworkManager::WSAutoConnectEnabled(std::string_view queryName) { + std::unique_lock lock(mConnectionsMutex); + auto it = std::find_if(mConnections.begin(), mConnections.end(), [&](std::unique_ptr& request) { + if (queryName == request->GetRequestName()) { + return true; + } + return false; + }); + + if (it == mConnections.end()) { + return false; + } + auto request = it->get(); + lock.unlock(); + + return request->WSAutoConnectEnabled(); + } + + void NetworkManager::WSSetAutoConnect(std::string_view queryName, bool autoConnect) { + std::unique_lock lock(mConnectionsMutex); + auto it = std::find_if(mConnections.begin(), mConnections.end(), [&](std::unique_ptr& request) { + if (queryName == request->GetRequestName()) { + return true; + } + return false; + }); + + if (it == mConnections.end()) { + return ; + } + auto request = it->get(); + lock.unlock(); + + request->WSSetAutoConnect(autoConnect); + } + } From c4324000d3d8af294cf6dd2f1d22b3e3b9bed07d Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 19 Jul 2025 23:35:05 +0200 Subject: [PATCH 022/179] Storage: Fix some issues with sequential cache. --- .../storage/include/storage/SequentialCache.h | 46 +++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/packages/storage/include/storage/SequentialCache.h b/packages/storage/include/storage/SequentialCache.h index df609596..d85ef81f 100644 --- a/packages/storage/include/storage/SequentialCache.h +++ b/packages/storage/include/storage/SequentialCache.h @@ -176,6 +176,40 @@ namespace l::filecache { } ~SequentialCache() = default; + bool HasAny(int32_t startposition, int32_t endposition) { + auto clampedStartPos = GetClampedPosition(startposition, mCacheBlockWidth); + auto clampedEndPos = GetClampedPosition(endposition, mCacheBlockWidth); + + std::lock_guard lock(mMutexCacheBlockMap); + + if (clampedStartPos < clampedEndPos) { + do { + auto it = mCacheBlockMap.find(clampedStartPos); + if (it != mCacheBlockMap.end()) { + return true; + } + if (static_cast(clampedStartPos) + mCacheBlockWidth >= l::math::constants::INTMAX) { + break; + } + clampedStartPos += mCacheBlockWidth; + } while (clampedStartPos <= clampedEndPos); + } + else { + do { + auto it = mCacheBlockMap.find(clampedStartPos); + if (it != mCacheBlockMap.end()) { + return true; + } + if (static_cast(clampedStartPos) - mCacheBlockWidth <= l::math::constants::INTMIN) { + break; + } + clampedStartPos -= mCacheBlockWidth; + } while (clampedStartPos >= clampedEndPos); + } + + return false; + } + bool Has(int32_t position) { auto clampedPos = GetClampedPosition(position, mCacheBlockWidth); @@ -222,6 +256,18 @@ namespace l::filecache { {} ~SequentialCacheStore() = default; + bool HasAny(std::string_view cacheKey, int32_t startposition, int32_t endposition) { + std::unique_lock lock(mMutexSequentialCacheMap); + auto it = mSequentialCacheMap.find(cacheKey.data()); + if (it == mSequentialCacheMap.end()) { + return false; + } + SequentialCache* sequentialCacheMap = it->second.get(); + lock.unlock(); + + return sequentialCacheMap->HasAny(startposition, endposition); + } + bool Has(std::string_view cacheKey, int32_t position) { std::unique_lock lock(mMutexSequentialCacheMap); auto it = mSequentialCacheMap.find(cacheKey.data()); From 52c0bafa406bb33d9d1debb5af22bf2449e1f5ee Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 20 Jul 2025 08:28:04 +0200 Subject: [PATCH 023/179] NG: Remove destructor logging. --- packages/nodegraph/include/nodegraph/core/NodeGraphBase.h | 8 ++++---- .../nodegraph/include/nodegraph/core/NodeGraphGroup.h | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h index 06ca9f95..a1342f79 100644 --- a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h @@ -46,7 +46,7 @@ namespace l::nodegraph { mInputs.clear(); mOutputs.clear(); - LOG(LogInfo) << "Node graph base destroyed"; + //LOG(LogInfo) << "Node graph base destroyed"; } NodeGraphBase& operator=(NodeGraphBase&& other) noexcept { @@ -186,7 +186,7 @@ namespace l::nodegraph { mName(name) {} virtual ~NodeGraphOp() { - LOG(LogInfo) << "Node operation destroyed"; + //LOG(LogInfo) << "Node operation destroyed"; } NodeGraphOp& operator=(NodeGraphOp&& other) noexcept { @@ -265,7 +265,7 @@ namespace l::nodegraph { { } virtual ~NodeGraphOpCached() { - LOG(LogInfo) << "Buffered operation destroyed"; + //LOG(LogInfo) << "Buffered operation destroyed"; } NodeGraphOpCached& operator=(NodeGraphOpCached&& other) noexcept { @@ -308,7 +308,7 @@ namespace l::nodegraph { DefaultDataInit(); } virtual ~NodeGraph() { - LOG(LogInfo) << "Node destroyed"; + //LOG(LogInfo) << "Node destroyed"; } NodeGraph& operator=(NodeGraph&& other) noexcept { diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h b/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h index 22b3a1c2..4a6048b0 100644 --- a/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h @@ -48,7 +48,7 @@ namespace l::nodegraph { } ~NodeGraphGroup() { Reset(); - LOG(LogInfo) << "Node group destroyed"; + //LOG(LogInfo) << "Node group destroyed"; } NodeGraphGroup& operator=(NodeGraphGroup&& other) noexcept { From 1f9fd120ec1256b8104a02ae877496d3dd411674 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 21 Jul 2025 15:04:33 +0200 Subject: [PATCH 024/179] Add delete functions for persistent cache. --- packages/storage/include/storage/SequentialCache.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/storage/include/storage/SequentialCache.h b/packages/storage/include/storage/SequentialCache.h index d85ef81f..a479ebb0 100644 --- a/packages/storage/include/storage/SequentialCache.h +++ b/packages/storage/include/storage/SequentialCache.h @@ -62,6 +62,11 @@ namespace l::filecache { archive(*self.mData.get()); } + bool UnpersistData() { + std::lock_guard lock(mPathMutex); + std::filesystem::remove(mPath); + } + bool PersistData() { if (!mCacheProvider) { return false; @@ -143,6 +148,13 @@ namespace l::filecache { } } + void Deallocate() { + std::lock_guard lock(mDataMutex); + if (!mData) { + mData = nullptr; + } + } + l::concurrency::ObjectLock Get() { mDataMutex.lock(); return l::concurrency::ObjectLock(mDataMutex, mData.get()); From a1060d3da2a41aa3cf7526a4619ffa8b58cf6886 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 21 Jul 2025 19:50:25 +0200 Subject: [PATCH 025/179] Storage+Network: Fix unpersist in sequencial cache. Also added a protocol level keepalive for websockets. --- .../include/network/NetworkConnection.h | 1 + .../include/network/NetworkInterfaceWS.h | 1 + .../network/include/network/NetworkManager.h | 1 + .../source/common/NetworkConnection.cpp | 33 +++++++++++++++++++ .../source/common/NetworkInterfaceWS.cpp | 18 ++++++++++ .../network/source/common/NetworkManager.cpp | 19 +++++++++++ .../storage/include/storage/CacheProvider.h | 2 ++ .../include/storage/FileCacheProvider.h | 1 + .../storage/include/storage/SequentialCache.h | 4 +-- .../source/common/FileCacheProvider.cpp | 5 +++ 10 files changed, 83 insertions(+), 2 deletions(-) diff --git a/packages/network/include/network/NetworkConnection.h b/packages/network/include/network/NetworkConnection.h index 0ac631ca..9ea7bbe4 100644 --- a/packages/network/include/network/NetworkConnection.h +++ b/packages/network/include/network/NetworkConnection.h @@ -81,6 +81,7 @@ namespace l::network { void SetRunningTimeout(int32_t secondsFromNow); void ClearRunningTimeout(); + int32_t WSKeepalive(); int32_t WSWrite(const char* buffer, size_t size); int32_t WSRead(char* buffer, size_t size); void WSClose(); diff --git a/packages/network/include/network/NetworkInterfaceWS.h b/packages/network/include/network/NetworkInterfaceWS.h index 196ba1f5..414ad92d 100644 --- a/packages/network/include/network/NetworkInterfaceWS.h +++ b/packages/network/include/network/NetworkInterfaceWS.h @@ -33,6 +33,7 @@ namespace l::network { void Disconnect(std::string_view queryName); int32_t Read(std::string_view interfaceName, char* buffer, size_t size); void QueueWrite(std::string_view interfaceName, const char* buffer, size_t size); + int32_t Keepalive(std::string_view interfaceName); int32_t Write(std::string_view interfaceName, const char* buffer, size_t size); void SendQueued(std::string_view interfaceName, int32_t maxQueued); int32_t NumQueued(std::string_view interfaceName); diff --git a/packages/network/include/network/NetworkManager.h b/packages/network/include/network/NetworkManager.h index 3030cf46..e5828e74 100644 --- a/packages/network/include/network/NetworkManager.h +++ b/packages/network/include/network/NetworkManager.h @@ -48,6 +48,7 @@ namespace l::network { std::function cb = nullptr); void WSClose(std::string_view queryName = ""); + int32_t WSKeepalive(std::string_view queryName); int32_t WSWrite(std::string_view queryName, const char* buffer, size_t size); int32_t WSRead(std::string_view queryName, char* buffer, size_t size); bool WSConnected(std::string_view queryName); diff --git a/packages/network/source/common/NetworkConnection.cpp b/packages/network/source/common/NetworkConnection.cpp index 449371bd..8f0c2dd7 100644 --- a/packages/network/source/common/NetworkConnection.cpp +++ b/packages/network/source/common/NetworkConnection.cpp @@ -258,6 +258,30 @@ namespace l::network { return m; } + int32_t ConnectionBase::WSKeepalive() { + if (HasExpired()) { + mWebSocketCanSendData = false; + LOG(LogError) << "Failed wss write, connection expired"; + return -101; + } + if (mCurl == nullptr) { + mWebSocketCanSendData = false; + LOG(LogError) << "Failed wss write, no curl instance"; + return -102; + } + + const char* payload = "keepalive"; + size_t sentBytes = 0; + auto rc = curl_ws_send(mCurl, payload, strlen(payload), &sentBytes, 0, CURLWS_PONG); + if (rc == CURLE_OK) { + LOG(LogError) << "[Keepalive] Sent PONG"; + } + else { + LOG(LogError) << "[Keepalive] Failed to send PONG: " << curl_easy_strerror(rc); + } + return rc; + } + int32_t ConnectionBase::WSWrite(const char* buffer, size_t size) { if (HasExpired()) { mWebSocketCanSendData = false; @@ -322,6 +346,15 @@ namespace l::network { if (meta) { multiFragmentBit = (meta->flags & CURLWS_CONT) == CURLWS_CONT; recvLeft = static_cast(meta->bytesleft); + + if (meta->flags & CURLWS_PONG) { + LOG(LogInfo) << "[WebSocket] Received PONG: "; + } + else if (meta->flags & CURLWS_PING) { + LOG(LogInfo) << "[WebSocket] Received PING: "; + } + //else if (meta->flags & CURLWS_TEXT) { + //} } if (res == CURLE_OK) { diff --git a/packages/network/source/common/NetworkInterfaceWS.cpp b/packages/network/source/common/NetworkInterfaceWS.cpp index 080a5409..20c78071 100644 --- a/packages/network/source/common/NetworkInterfaceWS.cpp +++ b/packages/network/source/common/NetworkInterfaceWS.cpp @@ -131,6 +131,24 @@ namespace l::network { } } + int32_t NetworkInterfaceWS::Keepalive(std::string_view interfaceName) { + int32_t written = 0; + auto it = mInterfaces.find(interfaceName.data()); + if (it != mInterfaces.end()) { + if (NetworkStatus(interfaceName)) { + auto networkManager = mNetworkManager.lock(); + if (networkManager) { + auto queryName = interfaceName; // With websocket, we have one query only per interface and it has the same name + written = networkManager->WSKeepalive(queryName) >= 0; + if (written < 0) { + LOG(LogWarning) << "Failed to send keepalive: " << interfaceName << " : error: " << written; + } + } + } + } + return written; + } + int32_t NetworkInterfaceWS::Write(std::string_view interfaceName, const char* buffer, size_t size) { int32_t written = 0; auto it = mInterfaces.find(interfaceName.data()); diff --git a/packages/network/source/common/NetworkManager.cpp b/packages/network/source/common/NetworkManager.cpp index 723c2d08..df2fe49b 100644 --- a/packages/network/source/common/NetworkManager.cpp +++ b/packages/network/source/common/NetworkManager.cpp @@ -202,6 +202,25 @@ namespace l::network { } } + int32_t NetworkManager::WSKeepalive(std::string_view queryName) { + std::unique_lock lock(mConnectionsMutex); + auto it = std::find_if(mConnections.begin(), mConnections.end(), [&](std::unique_ptr& request) { + if (queryName == request->GetRequestName()) { + return true; + } + return false; + }); + + if (it == mConnections.end()) { + LOG(LogError) << "Failed to find connection: " << queryName; + return -201; + } + auto request = it->get(); + lock.unlock(); + + return request->WSKeepalive(); + } + int32_t NetworkManager::WSWrite(std::string_view queryName, const char* buffer, size_t size) { std::unique_lock lock(mConnectionsMutex); auto it = std::find_if(mConnections.begin(), mConnections.end(), [&](std::unique_ptr& request) { diff --git a/packages/storage/include/storage/CacheProvider.h b/packages/storage/include/storage/CacheProvider.h index 92aa8a38..1211958b 100644 --- a/packages/storage/include/storage/CacheProvider.h +++ b/packages/storage/include/storage/CacheProvider.h @@ -9,6 +9,8 @@ namespace l::filecache { public: ICacheProvider() = default; virtual ~ICacheProvider() = default; + virtual void UnPersistData(std::string_view) { + }; virtual bool PersistData(std::string_view, const std::vector&) { return false; }; diff --git a/packages/storage/include/storage/FileCacheProvider.h b/packages/storage/include/storage/FileCacheProvider.h index cea7908f..f56c0113 100644 --- a/packages/storage/include/storage/FileCacheProvider.h +++ b/packages/storage/include/storage/FileCacheProvider.h @@ -22,6 +22,7 @@ namespace l::filecache { mExtension(extension) {} ~FileCacheProvider() = default; + virtual void UnPersistData(std::string_view path) override; virtual bool PersistData(std::string_view path, const std::vector& data) override; virtual bool ProvideData(std::string_view path, std::vector& data) override; diff --git a/packages/storage/include/storage/SequentialCache.h b/packages/storage/include/storage/SequentialCache.h index a479ebb0..1af437f2 100644 --- a/packages/storage/include/storage/SequentialCache.h +++ b/packages/storage/include/storage/SequentialCache.h @@ -62,9 +62,9 @@ namespace l::filecache { archive(*self.mData.get()); } - bool UnpersistData() { + void UnpersistData() { std::lock_guard lock(mPathMutex); - std::filesystem::remove(mPath); + mCacheProvider->UnPersistData(mPath); } bool PersistData() { diff --git a/packages/storage/source/common/FileCacheProvider.cpp b/packages/storage/source/common/FileCacheProvider.cpp index 572b67ff..9b86ce8e 100644 --- a/packages/storage/source/common/FileCacheProvider.cpp +++ b/packages/storage/source/common/FileCacheProvider.cpp @@ -5,6 +5,11 @@ namespace l::filecache { + void FileCacheProvider::UnPersistData(std::string_view path) { + auto file = mLocation / (std::string(path) + mExtension); + std::filesystem::remove(file); + } + bool FileCacheProvider::PersistData(std::string_view path, const std::vector& data) { if (data.empty()) { return false; From bc442db25b90efc1dc76829efc5e442b96591b46 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 21 Jul 2025 20:28:44 +0200 Subject: [PATCH 026/179] Network: Add logging prefix. --- .../source/common/NetworkConnection.cpp | 50 +++++++++---------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/packages/network/source/common/NetworkConnection.cpp b/packages/network/source/common/NetworkConnection.cpp index 8f0c2dd7..12c9aa2f 100644 --- a/packages/network/source/common/NetworkConnection.cpp +++ b/packages/network/source/common/NetworkConnection.cpp @@ -69,7 +69,7 @@ namespace l::network { int32_t timeOut, std::function cb ) { - ASSERT(mOngoingRequest) << "Request has not been reserved for usage"; + ASSERT(mOngoingRequest) << "[Request] Request has not been reserved for usage"; ASSERT(!mCompletedRequest); if (mRequestQuery.empty() && query.empty()) { @@ -113,11 +113,11 @@ namespace l::network { LOG(LogDebug) << mRequestQuery; //curl_easy_setopt(mCurl, CURLOPT_FRESH_CONNECT, 0L); // only use if necessary to create a new connection auto res_verify_peer = curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYPEER, 0L); - ASSERT(res_verify_peer == CURLE_OK) << "Failed to verify peer: " << std::to_string(res_verify_peer); + ASSERT(res_verify_peer == CURLE_OK) << "[Request] Failed to verify peer: " << std::to_string(res_verify_peer); auto res_verify_host = curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYHOST, 0L); - ASSERT(res_verify_host == CURLE_OK) << "Failed to verify host: " << std::to_string(res_verify_host); + ASSERT(res_verify_host == CURLE_OK) << "[Request] Failed to verify host: " << std::to_string(res_verify_host); auto res_ssl = curl_easy_setopt(mCurl, CURLOPT_SSL_OPTIONS, (long)CURLSSLOPT_ALLOW_BEAST | CURLSSLOPT_NO_REVOKE); - ASSERT(res_ssl == CURLE_OK) << "Failed to set ssl options: " << std::to_string(res_ssl); + ASSERT(res_ssl == CURLE_OK) << "[Request] Failed to set ssl options: " << std::to_string(res_ssl); //curl_easy_setopt(mCurl, CURLOPT_NOSIGNAL, 1); curl_easy_setopt(mCurl, CURLOPT_CLOSESOCKETFUNCTION, CurlClientCloseSocket); @@ -143,7 +143,7 @@ namespace l::network { #endif auto curlMCode = curl_multi_add_handle(multiHandle, mCurl); if (curlMCode != CURLMcode::CURLM_OK) { - LOG(LogError) << "Curl failure " << std::to_string(curlMCode) << ": " << mRequestQueryArgs; + LOG(LogError) << "[Request] Curl failure " << std::to_string(curlMCode) << ": " << mRequestQueryArgs; mSuccess = false; } } @@ -151,7 +151,7 @@ namespace l::network { auto curlCode = curl_easy_perform(mCurl); //curl_easy_header() if (curlCode != CURLE_OK) { - LOG(LogError) << "Curl failure " << std::to_string(curlCode) << ": " << mRequestQueryArgs; + LOG(LogError) << "[Request] Curl failure " << std::to_string(curlCode) << ": " << mRequestQueryArgs; mSuccess = false; } } @@ -261,12 +261,12 @@ namespace l::network { int32_t ConnectionBase::WSKeepalive() { if (HasExpired()) { mWebSocketCanSendData = false; - LOG(LogError) << "Failed wss write, connection expired"; + LOG(LogError) << "[Keepalive] connection expired"; return -101; } if (mCurl == nullptr) { mWebSocketCanSendData = false; - LOG(LogError) << "Failed wss write, no curl instance"; + LOG(LogError) << "[Keepalive] no curl instance"; return -102; } @@ -285,12 +285,12 @@ namespace l::network { int32_t ConnectionBase::WSWrite(const char* buffer, size_t size) { if (HasExpired()) { mWebSocketCanSendData = false; - LOG(LogError) << "Failed wss write, connection expired"; + LOG(LogError) << "[Websocket] Failed write, connection expired"; return -101; } if (mCurl == nullptr) { mWebSocketCanSendData = false; - LOG(LogError) << "Failed wss write, no curl instance"; + LOG(LogError) << "[Websocket] Failed write, no curl instance"; return -102; } size_t sentBytes = 0; @@ -305,13 +305,13 @@ namespace l::network { } else if (res == CURLE_GOT_NOTHING) { if (mWebSocketCanSendData) { - LOG(LogError) << "Failed wss write got nothing, error: " << res; + LOG(LogError) << "[Websocket] Failed write: got nothing, error: " << res; } mWebSocketCanSendData = false; } else { if (mWebSocketCanSendData) { - LOG(LogError) << "Failed wss write, error: " << res; + LOG(LogError) << "[Websocket] Failed write, error: " << res; } mWebSocketCanSendData = false; } @@ -322,12 +322,12 @@ namespace l::network { int32_t ConnectionBase::WSRead(char* buffer, size_t size) { if (HasExpired()) { mWebSocketCanReceiveData = false; - LOG(LogError) << "Failed wss read, connection expired"; + LOG(LogError) << "[Websocket] Failed read, connection expired"; return -101; } if (mCurl == nullptr) { mWebSocketCanReceiveData = false; - LOG(LogError) << "Failed wss read, no curl instance"; + LOG(LogError) << "[Websocket] Failed read, no curl instance"; return -102; } int32_t maxTries = 3; @@ -390,25 +390,25 @@ namespace l::network { // In this path only if there's an error if (res == CURLE_GOT_NOTHING) { if (mWebSocketCanReceiveData) { - LOG(LogError) << "Failed wss read - 'curl got nothing' - connection closed, error: " << res; + LOG(LogError) << "[Websocket] Failed read - 'curl got nothing' - connection closed, error: " << res; } mWebSocketCanReceiveData = false; } if (res == CURLE_RECV_ERROR) { if (mWebSocketCanReceiveData) { - LOG(LogError) << "Failed wss read - 'curl recieve error' - connection closed, error: " << res; + LOG(LogError) << "[Websocket] Failed read - 'curl recieve error' - connection closed, error: " << res; } mWebSocketCanReceiveData = false; } if (res == CURLE_BAD_FUNCTION_ARGUMENT) { if (mWebSocketCanReceiveData) { - LOG(LogError) << "Failed wss read - 'curl bad function arg', error: " << res; + LOG(LogError) << "[Websocket] Failed read - 'curl bad function arg', error: " << res; } mWebSocketCanReceiveData = false; } if (mWebSocketCanReceiveData) { - LOG(LogError) << "Failed wss read, connection closed, error: " << res; + LOG(LogError) << "[Websocket] Failed read, connection closed, error: " << res; } mWebSocketCanReceiveData = false; SetRunningTimeout(20); @@ -418,11 +418,11 @@ namespace l::network { void ConnectionBase::WSClose() { if (HasExpired()) { mWebSocketCanSendData = false; - LOG(LogError) << "Failed wss close, connection expired"; + LOG(LogError) << "[Websocket] Failed close, connection expired"; } if (mCurl == nullptr) { mWebSocketCanSendData = false; - LOG(LogError) << "Failed wss close, no curl instance"; + LOG(LogError) << "[Websocket] Failed close, no curl instance"; } ASSERT(mOngoingRequest); @@ -435,7 +435,7 @@ namespace l::network { size_t sentBytes = 0; auto res = curl_ws_send(mCurl, nullptr, 0, &sentBytes, 0, CURLWS_CLOSE); if (res == CURLE_OK) { - LOG(LogInfo) << "Closed connection"; + LOG(LogInfo) << "[Websocket] Closed connection"; } NotifyCompleteRequest(true); @@ -452,11 +452,11 @@ namespace l::network { void ConnectionBase::NotifyAppendHeader(const char* contents, size_t size) { if (HasExpired()) { mWebSocketCanSendData = false; - LOG(LogError) << "Failed notify append header, connection expired"; + LOG(LogError) << "[Request] Failed notify append header, connection expired"; } if (mCurl == nullptr) { mWebSocketCanSendData = false; - LOG(LogError) << "Failed notify append header, no curl instance"; + LOG(LogError) << "[Request] Failed notify append header, no curl instance"; } ASSERT(mOngoingRequest); @@ -490,11 +490,11 @@ namespace l::network { void ConnectionBase::NotifyAppendResponse(const char* contents, size_t size) { if (HasExpired()) { mWebSocketCanSendData = false; - LOG(LogError) << "Failed notify append response, connection expired"; + LOG(LogError) << "[Request] Failed notify append response, connection expired"; } if (mCurl == nullptr) { mWebSocketCanSendData = false; - LOG(LogError) << "Failed notify append response, no curl instance"; + LOG(LogError) << "[Request] Failed notify append response, no curl instance"; } ASSERT(mOngoingRequest); From 6c348cb7728458849aca1aa587da05450e2fe4cc Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 22 Jul 2025 08:38:45 +0200 Subject: [PATCH 027/179] Network: Do not log errors liberally. No keepalive logging. --- .../source/common/NetworkConnection.cpp | 40 +++++++++---------- .../storage/include/storage/CacheProvider.h | 3 +- .../include/storage/FileCacheProvider.h | 2 +- .../storage/include/storage/SequentialCache.h | 7 +++- .../source/common/FileCacheProvider.cpp | 3 +- .../tests/common/SequentialCacheTest.cpp | 4 ++ 6 files changed, 35 insertions(+), 24 deletions(-) diff --git a/packages/network/source/common/NetworkConnection.cpp b/packages/network/source/common/NetworkConnection.cpp index 12c9aa2f..e4c30cfd 100644 --- a/packages/network/source/common/NetworkConnection.cpp +++ b/packages/network/source/common/NetworkConnection.cpp @@ -261,12 +261,12 @@ namespace l::network { int32_t ConnectionBase::WSKeepalive() { if (HasExpired()) { mWebSocketCanSendData = false; - LOG(LogError) << "[Keepalive] connection expired"; + LOG(LogWarning) << "[Keepalive] connection expired"; return -101; } if (mCurl == nullptr) { mWebSocketCanSendData = false; - LOG(LogError) << "[Keepalive] no curl instance"; + LOG(LogWarning) << "[Keepalive] no curl instance"; return -102; } @@ -274,10 +274,10 @@ namespace l::network { size_t sentBytes = 0; auto rc = curl_ws_send(mCurl, payload, strlen(payload), &sentBytes, 0, CURLWS_PONG); if (rc == CURLE_OK) { - LOG(LogError) << "[Keepalive] Sent PONG"; + //LOG(LogInfo) << "[Keepalive] Sent PONG"; } else { - LOG(LogError) << "[Keepalive] Failed to send PONG: " << curl_easy_strerror(rc); + LOG(LogWarning) << "[Keepalive] Failed to send PONG: " << curl_easy_strerror(rc); } return rc; } @@ -285,12 +285,12 @@ namespace l::network { int32_t ConnectionBase::WSWrite(const char* buffer, size_t size) { if (HasExpired()) { mWebSocketCanSendData = false; - LOG(LogError) << "[Websocket] Failed write, connection expired"; + LOG(LogWarning) << "[Websocket] Failed write, connection expired"; return -101; } if (mCurl == nullptr) { mWebSocketCanSendData = false; - LOG(LogError) << "[Websocket] Failed write, no curl instance"; + LOG(LogWarning) << "[Websocket] Failed write, no curl instance"; return -102; } size_t sentBytes = 0; @@ -305,13 +305,13 @@ namespace l::network { } else if (res == CURLE_GOT_NOTHING) { if (mWebSocketCanSendData) { - LOG(LogError) << "[Websocket] Failed write: got nothing, error: " << res; + LOG(LogWarning) << "[Websocket] Failed write: got nothing, error: " << res; } mWebSocketCanSendData = false; } else { if (mWebSocketCanSendData) { - LOG(LogError) << "[Websocket] Failed write, error: " << res; + LOG(LogWarning) << "[Websocket] Failed write, error: " << res; } mWebSocketCanSendData = false; } @@ -322,12 +322,12 @@ namespace l::network { int32_t ConnectionBase::WSRead(char* buffer, size_t size) { if (HasExpired()) { mWebSocketCanReceiveData = false; - LOG(LogError) << "[Websocket] Failed read, connection expired"; + LOG(LogWarning) << "[Websocket] Failed read, connection expired"; return -101; } if (mCurl == nullptr) { mWebSocketCanReceiveData = false; - LOG(LogError) << "[Websocket] Failed read, no curl instance"; + LOG(LogWarning) << "[Websocket] Failed read, no curl instance"; return -102; } int32_t maxTries = 3; @@ -390,25 +390,25 @@ namespace l::network { // In this path only if there's an error if (res == CURLE_GOT_NOTHING) { if (mWebSocketCanReceiveData) { - LOG(LogError) << "[Websocket] Failed read - 'curl got nothing' - connection closed, error: " << res; + LOG(LogWarning) << "[Websocket] Failed read - 'curl got nothing' - connection closed, error: " << res; } mWebSocketCanReceiveData = false; } if (res == CURLE_RECV_ERROR) { if (mWebSocketCanReceiveData) { - LOG(LogError) << "[Websocket] Failed read - 'curl recieve error' - connection closed, error: " << res; + LOG(LogWarning) << "[Websocket] Failed read - 'curl recieve error' - connection closed, error: " << res; } mWebSocketCanReceiveData = false; } if (res == CURLE_BAD_FUNCTION_ARGUMENT) { if (mWebSocketCanReceiveData) { - LOG(LogError) << "[Websocket] Failed read - 'curl bad function arg', error: " << res; + LOG(LogWarning) << "[Websocket] Failed read - 'curl bad function arg', error: " << res; } mWebSocketCanReceiveData = false; } if (mWebSocketCanReceiveData) { - LOG(LogError) << "[Websocket] Failed read, connection closed, error: " << res; + LOG(LogWarning) << "[Websocket] Failed read, connection closed, error: " << res; } mWebSocketCanReceiveData = false; SetRunningTimeout(20); @@ -418,11 +418,11 @@ namespace l::network { void ConnectionBase::WSClose() { if (HasExpired()) { mWebSocketCanSendData = false; - LOG(LogError) << "[Websocket] Failed close, connection expired"; + LOG(LogWarning) << "[Websocket] Failed close, connection expired"; } if (mCurl == nullptr) { mWebSocketCanSendData = false; - LOG(LogError) << "[Websocket] Failed close, no curl instance"; + LOG(LogWarning) << "[Websocket] Failed close, no curl instance"; } ASSERT(mOngoingRequest); @@ -452,11 +452,11 @@ namespace l::network { void ConnectionBase::NotifyAppendHeader(const char* contents, size_t size) { if (HasExpired()) { mWebSocketCanSendData = false; - LOG(LogError) << "[Request] Failed notify append header, connection expired"; + LOG(LogWarning) << "[Request] Failed notify append header, connection expired"; } if (mCurl == nullptr) { mWebSocketCanSendData = false; - LOG(LogError) << "[Request] Failed notify append header, no curl instance"; + LOG(LogWarning) << "[Request] Failed notify append header, no curl instance"; } ASSERT(mOngoingRequest); @@ -490,11 +490,11 @@ namespace l::network { void ConnectionBase::NotifyAppendResponse(const char* contents, size_t size) { if (HasExpired()) { mWebSocketCanSendData = false; - LOG(LogError) << "[Request] Failed notify append response, connection expired"; + LOG(LogWarning) << "[Request] Failed notify append response, connection expired"; } if (mCurl == nullptr) { mWebSocketCanSendData = false; - LOG(LogError) << "[Request] Failed notify append response, no curl instance"; + LOG(LogWarning) << "[Request] Failed notify append response, no curl instance"; } ASSERT(mOngoingRequest); diff --git a/packages/storage/include/storage/CacheProvider.h b/packages/storage/include/storage/CacheProvider.h index 1211958b..1f024ee2 100644 --- a/packages/storage/include/storage/CacheProvider.h +++ b/packages/storage/include/storage/CacheProvider.h @@ -9,7 +9,8 @@ namespace l::filecache { public: ICacheProvider() = default; virtual ~ICacheProvider() = default; - virtual void UnPersistData(std::string_view) { + virtual bool UnPersistData(std::string_view) { + return false; }; virtual bool PersistData(std::string_view, const std::vector&) { return false; diff --git a/packages/storage/include/storage/FileCacheProvider.h b/packages/storage/include/storage/FileCacheProvider.h index f56c0113..8fb4e941 100644 --- a/packages/storage/include/storage/FileCacheProvider.h +++ b/packages/storage/include/storage/FileCacheProvider.h @@ -22,7 +22,7 @@ namespace l::filecache { mExtension(extension) {} ~FileCacheProvider() = default; - virtual void UnPersistData(std::string_view path) override; + virtual bool UnPersistData(std::string_view path) override; virtual bool PersistData(std::string_view path, const std::vector& data) override; virtual bool ProvideData(std::string_view path, std::vector& data) override; diff --git a/packages/storage/include/storage/SequentialCache.h b/packages/storage/include/storage/SequentialCache.h index 1af437f2..8ae966d2 100644 --- a/packages/storage/include/storage/SequentialCache.h +++ b/packages/storage/include/storage/SequentialCache.h @@ -62,9 +62,14 @@ namespace l::filecache { archive(*self.mData.get()); } - void UnpersistData() { + bool UnpersistData() { + if (!mCacheProvider) { + return false; + } + std::lock_guard lock(mPathMutex); mCacheProvider->UnPersistData(mPath); + return true; } bool PersistData() { diff --git a/packages/storage/source/common/FileCacheProvider.cpp b/packages/storage/source/common/FileCacheProvider.cpp index 9b86ce8e..b77587a7 100644 --- a/packages/storage/source/common/FileCacheProvider.cpp +++ b/packages/storage/source/common/FileCacheProvider.cpp @@ -5,9 +5,10 @@ namespace l::filecache { - void FileCacheProvider::UnPersistData(std::string_view path) { + bool FileCacheProvider::UnPersistData(std::string_view path) { auto file = mLocation / (std::string(path) + mExtension); std::filesystem::remove(file); + return true; } bool FileCacheProvider::PersistData(std::string_view path, const std::vector& data) { diff --git a/packages/storage/tests/common/SequentialCacheTest.cpp b/packages/storage/tests/common/SequentialCacheTest.cpp index eb857e21..0e2d9428 100644 --- a/packages/storage/tests/common/SequentialCacheTest.cpp +++ b/packages/storage/tests/common/SequentialCacheTest.cpp @@ -46,6 +46,10 @@ TEST(SequentialCacheStore, Setup) { TEST_TRUE(block->HasData(), ""); TEST_TRUE(block->Get()->mValue == 1, ""); + + block->UnpersistData(); + + TEST_FALSE(std::filesystem::exists("tests/store/Key_10_20.test"), ""); } return 0; } From beb59ce27f65224b5e50fc804d8ef95d9088a53c Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 24 Jul 2025 10:20:39 +0200 Subject: [PATCH 028/179] NG: Add output float/test setters. --- .../include/nodegraph/core/NodeGraphBase.h | 3 +++ .../include/nodegraph/operations/NodeGraphOpUI.h | 16 ++++++++++++++++ .../source/common/core/NodeGraphBase.cpp | 8 ++++++++ 3 files changed, 27 insertions(+) diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h index a1342f79..7b36b896 100644 --- a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h @@ -86,6 +86,9 @@ namespace l::nodegraph { virtual int8_t GetNumInputs(); virtual int8_t GetNumOutputs(); + void SetOutputText(int8_t inputChannel, std::string_view text); + void SetOutput(int8_t inputChannel, float value); + virtual float& GetInput(int8_t inputChannel, int32_t minSize = 1, int32_t offset = 0); virtual std::string_view GetInputText(int8_t inputChannel, int32_t minSize = 16); diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index 79bb112f..59a6c3a5 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -68,6 +68,22 @@ namespace l::nodegraph { float mMax = 1.0f; }; + /*********************************************************************/ + class GraphUIChart : public NodeGraphOp { + public: + GraphUIChart(NodeGraphBase* node) : + NodeGraphOp(node, "UI Chart") + { + AddOutput2("Symbol", 16, OutputFlags(false, true)); + AddOutput2("Base", 16, OutputFlags(false, true)); + AddOutput("Min#0", 1.0f); + AddOutput("Min#1", 2.0f); + AddOutput("Min#2", 3.0f); + } + + virtual ~GraphUIChart() = default; + }; + /*********************************************************************/ class GraphUIText : public NodeGraphOp { public: diff --git a/packages/nodegraph/source/common/core/NodeGraphBase.cpp b/packages/nodegraph/source/common/core/NodeGraphBase.cpp index e33707a5..94c8173b 100644 --- a/packages/nodegraph/source/common/core/NodeGraphBase.cpp +++ b/packages/nodegraph/source/common/core/NodeGraphBase.cpp @@ -79,6 +79,14 @@ namespace l::nodegraph { mLastTickCount = tickCount; } + void NodeGraphBase::SetOutputText(int8_t outputChannel, std::string_view text) { + mOutputs.at(outputChannel).SetText(text); + } + + void NodeGraphBase::SetOutput(int8_t outputChannel, float value) { + mOutputs.at(outputChannel).Get() = value; + } + float& NodeGraphBase::GetInput(int8_t inputChannel, int32_t minSize, int32_t offset) { return mInputs.at(inputChannel).Get(minSize, offset); } From 6c478c81427982d799da3724a338a10b0b5f2fdc Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 24 Jul 2025 10:39:30 +0200 Subject: [PATCH 029/179] NG: Add chart info node. --- .../operations/NodeGraphOpTradingDataIO.h | 15 +++++++++++++++ .../include/nodegraph/operations/NodeGraphOpUI.h | 16 ---------------- .../nodegraph/source/common/NodeGraphSchema.cpp | 4 ++++ 3 files changed, 19 insertions(+), 16 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h index 3832294b..cbf5392b 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h @@ -67,6 +67,21 @@ namespace l::nodegraph { /*********************************************************************/ + class TradingDataIOChartInfo : public NodeGraphOp { + public: + TradingDataIOChartInfo(NodeGraphBase* node) : + NodeGraphOp(node, "Chart Info") + { + AddOutput2("Symbol", 16, OutputFlags(false, true)); + AddOutput2("Base", 16, OutputFlags(false, true)); + AddOutput("Min#0", 1.0f); + AddOutput("Min#1", 2.0f); + AddOutput("Min#2", 3.0f); + } + + virtual ~TradingDataIOChartInfo() = default; + }; + } \ No newline at end of file diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index 59a6c3a5..79bb112f 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -68,22 +68,6 @@ namespace l::nodegraph { float mMax = 1.0f; }; - /*********************************************************************/ - class GraphUIChart : public NodeGraphOp { - public: - GraphUIChart(NodeGraphBase* node) : - NodeGraphOp(node, "UI Chart") - { - AddOutput2("Symbol", 16, OutputFlags(false, true)); - AddOutput2("Base", 16, OutputFlags(false, true)); - AddOutput("Min#0", 1.0f); - AddOutput("Min#1", 2.0f); - AddOutput("Min#2", 3.0f); - } - - virtual ~GraphUIChart() = default; - }; - /*********************************************************************/ class GraphUIText : public NodeGraphOp { public: diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 7116ae9b..cc5bd42d 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -314,6 +314,9 @@ namespace l::nodegraph { case 201: node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 1); break; + case 202: + node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput); + break; // Trading detectors case 220: @@ -611,6 +614,7 @@ namespace l::nodegraph { else if (typeGroup == "Trading.Data IO") { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); RegisterNodeType("Trading.Data IO", 201, "Heikin-Ashi Data In"); + RegisterNodeType("Trading.Data IO", 202, "Chart Info"); } else if (typeGroup == "Trading.Detector") { RegisterNodeType("Trading.Detector", 220, "Trend"); From e3787236c83639f10d986dc32390613a91b87cbb Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 24 Jul 2025 13:12:36 +0200 Subject: [PATCH 030/179] NG: Fix chart info node. --- .../operations/NodeGraphOpTradingDataIO.h | 15 ++++++++---- .../operations/NodeGraphOpTradingDataIO.cpp | 23 ++++++++++++++++--- 2 files changed, 30 insertions(+), 8 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h index cbf5392b..0f7e38d8 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h @@ -72,16 +72,21 @@ namespace l::nodegraph { TradingDataIOChartInfo(NodeGraphBase* node) : NodeGraphOp(node, "Chart Info") { + AddInput2("Symbol", 16, InputFlags(false, true, false, true)); + AddInput2("Base", 16, InputFlags(false, true, false, true)); + AddInput("Index", 2.0f, 1, 0.0f, 10.0f); + AddOutput2("Symbol", 16, OutputFlags(false, true)); AddOutput2("Base", 16, OutputFlags(false, true)); - AddOutput("Min#0", 1.0f); - AddOutput("Min#1", 2.0f); - AddOutput("Min#2", 3.0f); + AddOutput("Index#0", 0.0f); + AddOutput("Index#1", 1.0f); + AddOutput("Index#2", 2.0f); + AddOutput("Index#3", 3.0f); } virtual ~TradingDataIOChartInfo() = default; - }; - + virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + }; } \ No newline at end of file diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp index dbbe69ac..94d98766 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp @@ -3,7 +3,7 @@ #include "logging/Log.h" #include "audio/AudioUtils.h" -#include "math/MathFunc.h" +#include #include @@ -14,12 +14,12 @@ namespace l::nodegraph { if (mInputHasChanged) { auto symbolInput = inputs.at(1).GetText(16); auto baseInput = inputs.at(2).GetText(16); - auto intervalInput = static_cast(l::math::clamp(inputs.at(3).Get(1), 0.0f, 9.0f)); + auto intervalInput = static_cast(l::math::clamp(inputs.at(3).Get(1), 0.0f, 9.9999f)); outputs.at(0).SetText(symbolInput); outputs.at(1).SetText(baseInput); float* intervalOut = &outputs.at(2).Get(1); - *intervalOut = math::max2(1.0f, static_cast(kIntervals[intervalInput])); + *intervalOut = l::math::max2(1.0f, static_cast(kIntervals[intervalInput])); } } @@ -129,4 +129,21 @@ namespace l::nodegraph { } } + void TradingDataIOChartInfo::Process(int32_t, int32_t, std::vector& inputs, std::vector& outputs) { + auto symbolInput = inputs.at(0).GetText(16); + auto baseInput = inputs.at(1).GetText(16); + auto indexInput = l::math::clamp(inputs.at(3).Get(1), 0.0f, 9.9999f); + + outputs.at(0).SetText(symbolInput); + outputs.at(1).SetText(baseInput); + float* indexOut0 = &outputs.at(2).Get(); + float* indexOut1 = &outputs.at(3).Get(); + float* indexOut2 = &outputs.at(4).Get(); + float* indexOut3 = &outputs.at(5).Get(); + *indexOut0 = l::math::clamp(indexInput, 0.0f, 9.9999f); + *indexOut1 = l::math::clamp(indexInput, 0.0f, 9.9999f); + *indexOut2 = l::math::clamp(indexInput, 0.0f, 9.9999f); + *indexOut3 = l::math::clamp(indexInput, 0.0f, 9.9999f); + } + } From 79208071b615dd968985e825830626da3fe61d48 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 25 Jul 2025 13:31:14 +0200 Subject: [PATCH 031/179] Websocket: default to autoping. --- packages/network/source/common/NetworkConnection.cpp | 2 +- .../source/common/operations/NodeGraphOpTradingDataIO.cpp | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/network/source/common/NetworkConnection.cpp b/packages/network/source/common/NetworkConnection.cpp index e4c30cfd..7106d12f 100644 --- a/packages/network/source/common/NetworkConnection.cpp +++ b/packages/network/source/common/NetworkConnection.cpp @@ -102,7 +102,7 @@ namespace l::network { if (mIsWebSocket) { curl_easy_setopt(mCurl, CURLOPT_CONNECT_ONLY, 2L); - auto res = curl_easy_setopt(mCurl, CURLOPT_WS_OPTIONS, 0L); // CURLWS_RAW_MODE, CURLWS_NOAUTOPONG + auto res = curl_easy_setopt(mCurl, CURLOPT_WS_OPTIONS, 0L); // 1L - CURLWS_RAW_MODE, 2L - CURLWS_NOAUTOPONG ASSERT(res == CURLE_OK); } else { diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp index 94d98766..e458e8ba 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp @@ -132,7 +132,7 @@ namespace l::nodegraph { void TradingDataIOChartInfo::Process(int32_t, int32_t, std::vector& inputs, std::vector& outputs) { auto symbolInput = inputs.at(0).GetText(16); auto baseInput = inputs.at(1).GetText(16); - auto indexInput = l::math::clamp(inputs.at(3).Get(1), 0.0f, 9.9999f); + auto indexInput = l::math::clamp(inputs.at(2).Get(), 0.0f, 9.9999f); outputs.at(0).SetText(symbolInput); outputs.at(1).SetText(baseInput); @@ -141,9 +141,9 @@ namespace l::nodegraph { float* indexOut2 = &outputs.at(4).Get(); float* indexOut3 = &outputs.at(5).Get(); *indexOut0 = l::math::clamp(indexInput, 0.0f, 9.9999f); - *indexOut1 = l::math::clamp(indexInput, 0.0f, 9.9999f); - *indexOut2 = l::math::clamp(indexInput, 0.0f, 9.9999f); - *indexOut3 = l::math::clamp(indexInput, 0.0f, 9.9999f); + *indexOut1 = l::math::clamp(indexInput + 1.0f, 0.0f, 9.9999f); + *indexOut2 = l::math::clamp(indexInput + 2.0f, 0.0f, 9.9999f); + *indexOut3 = l::math::clamp(indexInput + 3.0f, 0.0f, 9.9999f); } } From 6eca0bdc30a0a9786bca56b8b7c45479ded47cdc Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 25 Jul 2025 21:14:10 +0200 Subject: [PATCH 032/179] NG: Add numerical minmax channel. --- .../operations/NodeGraphOpMathNumerical.h | 25 ++++++++++++ .../source/common/NodeGraphSchema.cpp | 4 ++ .../operations/NodeGraphOpMathNumerical.cpp | 40 ++++++++++++++++++- 3 files changed, 68 insertions(+), 1 deletion(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 711c2ddf..f841fadb 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -124,4 +124,29 @@ namespace l::nodegraph { protected: float mLevelPrev = 0.0f; }; + + /*********************************************************************/ + class MathNumericalMinMaxChannel : public NodeGraphOp { + public: + MathNumericalMinMaxChannel(NodeGraphBase* node) : + NodeGraphOp(node, "Minmax Channel") + { + AddInput("Upper Bound", 0.0f, 1); + AddInput("Lower Bound", 0.0f, 1); + AddInput("Bounded Value", 0.0f, 1); + + AddOutput("Range", 0.0f, 1); + AddOutput("Range Max", 0.0f, 1); + AddOutput("Range Min", 0.0f, 1); + AddOutput("Value Norm", 0.0f, 1); + } + + virtual ~MathNumericalMinMaxChannel() = default; + virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + protected: + int32_t mReadSamples = 0; + + float mCurRangeMax = 0.0f; + float mCurRangeMin = 0.0f; + }; } \ No newline at end of file diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index cc5bd42d..6f3281b3 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -306,6 +306,9 @@ namespace l::nodegraph { case 144: node = mMainNodeGraph.NewNode(id, NodeType::Default); break; + case 145: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; // Trading data io case 200: @@ -610,6 +613,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Numerical", 142, "Difference Normalized"); RegisterNodeType("Math.Numerical", 143, "Difference"); RegisterNodeType("Math.Numerical", 144, "Level Trigger"); + RegisterNodeType("Math.Numerical", 145, "Minmax Channel"); } else if (typeGroup == "Trading.Data IO") { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 4c845722..cda231ed 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -113,7 +113,6 @@ namespace l::nodegraph { mReadSamples = 0; mInputPrev = 0.0f; } - } void MathNumericalLevelTrigger::Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) { @@ -154,4 +153,43 @@ namespace l::nodegraph { } } + void MathNumericalMinMaxChannel::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + auto inInput = &inputs.at(0).Get(numSamples); + auto upperInput = &inputs.at(1).Get(); + auto lowerInput = &inputs.at(2).Get(); + + auto rangeOutput = &outputs.at(0).Get(numSamples); + auto rangeMaxOutput = &outputs.at(1).Get(numSamples); + auto rangeMinOutput = &outputs.at(2).Get(numSamples); + auto valueNormOutput = &outputs.at(3).Get(numSamples); + + if (mReadSamples >= numCacheSamples) { + mReadSamples = 0; + mCurRangeMax = -100000000000000.0f; + mCurRangeMin = 100000000000000.0f; + } + + for (int32_t i = 0; i < numSamples; i++) { + float in = *inInput++; + float upper = *upperInput++; + float lower = *lowerInput++; + + lower = lower > in ? in - 0.0000001f : lower; + upper = upper < in ? in + 0.0000001f : lower; + + auto range = upper - lower; + if (mCurRangeMax < range) { + mCurRangeMax = range; + } + if (mCurRangeMin > range) { + mCurRangeMin = range; + } + + *rangeOutput++ = range; + *rangeMaxOutput++ = mCurRangeMax; + *rangeMinOutput++ = mCurRangeMin; + *valueNormOutput++ = (in - lower) / range; + } + } + } From a434418871dd6fcc099f8215f779ebd5616ae89c Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 26 Jul 2025 06:23:20 +0200 Subject: [PATCH 033/179] Add another binary searcher for less or equal values. --- packages/math/include/math/MathAlgorithm.h | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/packages/math/include/math/MathAlgorithm.h b/packages/math/include/math/MathAlgorithm.h index 5e37be63..f42def76 100644 --- a/packages/math/include/math/MathAlgorithm.h +++ b/packages/math/include/math/MathAlgorithm.h @@ -57,6 +57,26 @@ namespace l::math::algorithm { return 0; } + template + int32_t binary_search_leq(const std::vector& elements, const T& data) { + int32_t left = 0; + int32_t right = static_cast(elements.size()) - 1; + int32_t result = -1; // Default if no element is <= value + + while (left <= right) { + int32_t mid = left + (right - left) / 2; + + if (elements.at(mid) <= data) { + result = mid; // Valid candidate found + left = mid + 1; // Look for a better candidate to the right + } + else { + right = mid - 1; // Look to the left + } + } + return result; + } + template T bisect(T a, T b, T tolerance, int iterations, std::function eval) { int n = 0; From 5c66c09a4b0e21e9f70b7d31561505454f23d888 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 26 Jul 2025 08:49:42 +0200 Subject: [PATCH 034/179] Math: Accept bounds in search. --- packages/math/include/math/MathAlgorithm.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/math/include/math/MathAlgorithm.h b/packages/math/include/math/MathAlgorithm.h index f42def76..bb4ccc61 100644 --- a/packages/math/include/math/MathAlgorithm.h +++ b/packages/math/include/math/MathAlgorithm.h @@ -58,9 +58,9 @@ namespace l::math::algorithm { } template - int32_t binary_search_leq(const std::vector& elements, const T& data) { - int32_t left = 0; - int32_t right = static_cast(elements.size()) - 1; + int32_t binary_search_leq(const std::vector& elements, const T& data, int32_t minIndex = 0, int32_t maxIndex = INT32_MAX) { + int32_t left = static_cast(minIndex < 0 ? 0 : minIndex); + int32_t right = static_cast((maxIndex < elements.size() ? maxIndex : elements.size()) - 1); int32_t result = -1; // Default if no element is <= value while (left <= right) { From 255626042c6f0da9789a8d697243859821cc6b31 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 26 Jul 2025 17:40:43 +0200 Subject: [PATCH 035/179] Fix minmax channel writing. --- .../common/operations/NodeGraphOpMathNumerical.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index cda231ed..73bd5f9f 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -163,8 +163,7 @@ namespace l::nodegraph { auto rangeMinOutput = &outputs.at(2).Get(numSamples); auto valueNormOutput = &outputs.at(3).Get(numSamples); - if (mReadSamples >= numCacheSamples) { - mReadSamples = 0; + if (mReadSamples == 0) { mCurRangeMax = -100000000000000.0f; mCurRangeMin = 100000000000000.0f; } @@ -190,6 +189,12 @@ namespace l::nodegraph { *rangeMinOutput++ = mCurRangeMin; *valueNormOutput++ = (in - lower) / range; } + + mReadSamples += numSamples; + + if (mReadSamples >= numCacheSamples) { + mReadSamples = 0; + } } } From 7d8cb04a10da489e951e6c75c63e3ee7a97012d3 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Wed, 30 Jul 2025 12:27:54 +0200 Subject: [PATCH 036/179] Add fixed point math and test. --- CMakeLists.txt | 2 +- packages/math/CMakeLists.txt | 1 - packages/math/include/math/MathAll.h | 1 + packages/math/include/math/MathFixedPoint.h | 109 ++++++++++++++++++ .../math/source/common/MathFixedPoint.cpp | 107 +++++++++++++++++ .../math/tests/common/MathFixedPointTest.cpp | 43 +++++++ packages/serialization/CMakeLists.txt | 2 + .../include/serialization/JsonParser.h | 2 + .../source/common/JsonParser.cpp | 11 +- 9 files changed, 273 insertions(+), 5 deletions(-) create mode 100644 packages/math/include/math/MathFixedPoint.h create mode 100644 packages/math/source/common/MathFixedPoint.cpp create mode 100644 packages/math/tests/common/MathFixedPointTest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e0e72e52..53776efa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,10 +24,10 @@ else() filesystem meta memory + math concurrency serialization crypto - math audio hid nodegraph diff --git a/packages/math/CMakeLists.txt b/packages/math/CMakeLists.txt index dcd2c725..3d657915 100644 --- a/packages/math/CMakeLists.txt +++ b/packages/math/CMakeLists.txt @@ -3,7 +3,6 @@ project (math) set(deps logging testing - memory ) bs_generate_package(math "tier1" "${deps}" "") diff --git a/packages/math/include/math/MathAll.h b/packages/math/include/math/MathAll.h index abbee162..f2683de0 100644 --- a/packages/math/include/math/MathAll.h +++ b/packages/math/include/math/MathAll.h @@ -5,3 +5,4 @@ #include "math/MathConstants.h" #include "math/MathAlgorithm.h" #include "math/MathTween.h" +#include "math/MathFixedPoint.h" diff --git a/packages/math/include/math/MathFixedPoint.h b/packages/math/include/math/MathFixedPoint.h new file mode 100644 index 00000000..f3bb656e --- /dev/null +++ b/packages/math/include/math/MathFixedPoint.h @@ -0,0 +1,109 @@ +#pragma once + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +namespace l::math::fp { + + class FixedPoint { + public: + static FixedPoint FromDouble(double d, int64_t scale = 100000000); + static FixedPoint FromFloat(float f, int64_t scale = 100000000); + static FixedPoint FromString(std::string_view number, int64_t scale = 100000000); + static int64_t GetScaleFromString(std::string_view number, int32_t precision_digits = 1); + static int64_t GetScale(int32_t precision_digits = 1); + static int64_t GetScaleFromFloat(float scaleFloat, int32_t precision_digits = 1); + static int64_t GetScaleFromDouble(double scaleDouble, int32_t precision_digits = 1); + + // Constructors + FixedPoint() : value_(0), scale_(100000000) {} + FixedPoint(int64_t scaledValue, int64_t scale = 100000000) + : value_(scaledValue), scale_(scale) { + } + FixedPoint(float value, int32_t precision_digits = 1) { + scale_ = GetScaleFromFloat(value, precision_digits); + value_ = static_cast(l::math::round(value * scale_)); + normalise(precision_digits); + } + FixedPoint(double value, int32_t precision_digits = 1) { + scale_ = GetScaleFromDouble(value, precision_digits); + value_ = static_cast(l::math::round(value * scale_)); + normalise(precision_digits); + } + FixedPoint(std::string_view number, int32_t precision_digits = 1) { + scale_ = GetScaleFromString(number, precision_digits); + auto f = std::atof(number.data()); + value_ = static_cast(l::math::round(f * scale_)); + } + + int32_t numDigits() const; + double toDouble() const; + float toFloat() const; + std::string toString() const; + void normalise(int32_t precision_digits = 1); + + // Arithmetic + FixedPoint operator+(const FixedPoint& other) const { + ASSERT(scale_ == other.scale_); // Ensure matching scales + return FixedPoint(value_ + other.value_, scale_); + } + + FixedPoint operator-(const FixedPoint& other) const { + ASSERT(scale_ == other.scale_); + return FixedPoint(value_ - other.value_, scale_); + } + + FixedPoint operator*(int64_t multiplier) const { + return FixedPoint(value_ * multiplier, scale_); + } + + bool operator==(const FixedPoint& other) const { + return value_ == other.value_ && scale_ == other.scale_; + } + + bool operator!=(const FixedPoint& other) const { + return !(*this == other); + } + + bool operator<(const FixedPoint& other) const { + ASSERT(scale_ == other.scale_); + return value_ < other.value_; + } + + bool operator>(const FixedPoint& other) const { + return other < *this; + } + + bool operator<=(const FixedPoint& other) const { + return !(*this > other); + } + + bool operator>=(const FixedPoint& other) const { + return !(*this < other); + } + + FixedPoint operator%(const FixedPoint& other) const { + ASSERT(scale_ == other.scale_); + return FixedPoint(value_ % other.value_, scale_); + } + + // Getters + int64_t rawValue() const { return value_; } + int64_t scale() const { return scale_; } + + private: + int64_t value_ = 0; + int64_t scale_ = 1; // per-instance scale (e.g., 1e8) + + }; + + +} diff --git a/packages/math/source/common/MathFixedPoint.cpp b/packages/math/source/common/MathFixedPoint.cpp new file mode 100644 index 00000000..95e5b2ae --- /dev/null +++ b/packages/math/source/common/MathFixedPoint.cpp @@ -0,0 +1,107 @@ + +#include "math/MathFixedPoint.h" + +namespace l::math::fp { + FixedPoint FixedPoint::FromDouble(double d, int64_t scale) { + return FixedPoint(static_cast(l::math::round(d * scale)), scale); + } + + FixedPoint FixedPoint::FromFloat(float f, int64_t scale) { + return FixedPoint(static_cast(l::math::round(f * scale)), scale); + } + + FixedPoint FixedPoint::FromString(std::string_view number, int64_t scale) { + return FromDouble(std::atof(number.data()), scale); + } + + int64_t FixedPoint::GetScaleFromString(std::string_view number, int32_t precision_digits) { + if (number.empty() || precision_digits == 0) { + return 0; + } + + auto it = std::find(number.begin(), number.end(), '.'); + if (it == number.end()) { + return 0; // str contains an integer and doesnt need fixed point + } + + + // Find index of most significant digit + size_t decimal_start = 1 + it - number.begin(); + size_t first_nonzero = decimal_start; + while (first_nonzero < number.size() && number[first_nonzero] == '0') { + ++first_nonzero; + } + + if (first_nonzero == number.size()) return false; // no non-zero digit found + auto decimalZeroes = static_cast(first_nonzero - decimal_start); + + int32_t total_digits = decimalZeroes + precision_digits; + if (total_digits > 18) return false; // avoid int64_t overflow + + auto scale = static_cast(0.5f + l::math::pow(10.0f, static_cast(total_digits))); + return scale; + } + + int64_t FixedPoint::GetScaleFromFloat(float scaleFloat, int32_t precision_digits) { + return GetScaleFromDouble(static_cast(scaleFloat), precision_digits); + } + + int64_t FixedPoint::GetScaleFromDouble(double scaleDouble, int32_t precision_digits) { + if (scaleDouble == 0.0 || precision_digits == 0) { + return 0; + } + + int32_t decimalZeroes = 0; + scaleDouble *= 10.0; + while (scaleDouble < 1.0 && decimalZeroes < 18) { + scaleDouble *= 10.0; + ++decimalZeroes; + } + int32_t total_digits = decimalZeroes + precision_digits; + if (total_digits > 18) return false; // avoid int64_t overflow + + auto scale = static_cast(0.5f + l::math::pow(10.0f, static_cast(total_digits))); + return scale; + } + + void FixedPoint::normalise(int32_t precision_digits) { + auto precisionScale = static_cast(0.5 + l::math::pow(10.0, static_cast(precision_digits))); + while (value_ >= precisionScale) { + value_ = value_ / precisionScale; + scale_ = scale_ / 10; + } + } + + int32_t FixedPoint::numDigits() const { + return static_cast(l::math::logx(10.0f, static_cast(scale_))); + } + + double FixedPoint::toDouble() const { + return static_cast(value_) / static_cast(scale_); + } + + float FixedPoint::toFloat() const { + return static_cast(value_) / static_cast(scale_); + } + + std::string FixedPoint::toString() const { + std::ostringstream oss; + + int64_t int_part = value_ / scale_; + int64_t frac_part = l::math::abs(value_ % scale_); + + oss << int_part; + + if (scale_ > 1) { + // Determine number of digits in the scale (e.g., 100000000 -> 8) + int decimal_digits = static_cast(l::math::logx(10.0f, static_cast(scale_))); + + // Pad with leading zeros if necessary + oss << "." << std::setw(decimal_digits) << std::setfill('0') << frac_part; + } + + return oss.str(); + } + + +} diff --git a/packages/math/tests/common/MathFixedPointTest.cpp b/packages/math/tests/common/MathFixedPointTest.cpp new file mode 100644 index 00000000..516c75f4 --- /dev/null +++ b/packages/math/tests/common/MathFixedPointTest.cpp @@ -0,0 +1,43 @@ +#include "testing/Test.h" +#include "logging/Log.h" + +#include "math/MathAll.h" + +using namespace l; +using namespace l::math::fp; + +TEST(MathFixedPoint, Basic) { + { + FixedPoint fp(0.0001f, 1); + TEST_TRUE(fp.scale() == 10000, ""); + TEST_FUZZY(fp.toFloat(), 0.0001f, 0.0000001f, ""); + TEST_TRUE(fp.rawValue() == 1, ""); + } + { + FixedPoint fp("0.002", 1); + TEST_TRUE(fp.scale() == 1000, ""); + TEST_FUZZY(fp.toFloat(), 0.002f, 0.0000001f, ""); + TEST_TRUE(fp.rawValue() == 2, ""); + } + { + FixedPoint fp("0.00213", 3); + TEST_TRUE(fp.scale() == 100000, ""); + TEST_FUZZY(fp.toFloat(), 0.00213f, 0.0000001f, ""); + TEST_TRUE(fp.rawValue() == 213, ""); + } + { + FixedPoint fp(0.002f, 1); + TEST_TRUE(fp.scale() == 1000, ""); + TEST_FUZZY(fp.toFloat(), 0.002f, 0.0000001f, ""); + TEST_TRUE(fp.rawValue() == 2, ""); + } + { + FixedPoint fp(0.00213f, 3); + TEST_TRUE(fp.scale() == 100000, ""); + TEST_FUZZY(fp.toFloat(), 0.00213f, 0.0000001f, ""); + TEST_TRUE(fp.rawValue() == 213, ""); + } + + return 0; +} + diff --git a/packages/serialization/CMakeLists.txt b/packages/serialization/CMakeLists.txt index 1ed2f61a..5a26a78a 100644 --- a/packages/serialization/CMakeLists.txt +++ b/packages/serialization/CMakeLists.txt @@ -3,6 +3,8 @@ project (serialization) set(deps logging testing + + math ) bs_generate_package(serialization "tier1" "${deps}" "various;jsonxx") diff --git a/packages/serialization/include/serialization/JsonParser.h b/packages/serialization/include/serialization/JsonParser.h index 2150f47b..298cb5c2 100644 --- a/packages/serialization/include/serialization/JsonParser.h +++ b/packages/serialization/include/serialization/JsonParser.h @@ -1,6 +1,7 @@ #pragma once #include +#include #define JSMN_HEADER #include @@ -52,6 +53,7 @@ namespace l::serialization { bool as_bool() const; double as_double() const; float as_float() const; + l::math::fp::FixedPoint as_fixed_point() const; int8_t as_int8() const; int16_t as_int16() const; int32_t as_int32() const; diff --git a/packages/serialization/source/common/JsonParser.cpp b/packages/serialization/source/common/JsonParser.cpp index c4bec9a0..8392a71c 100644 --- a/packages/serialization/source/common/JsonParser.cpp +++ b/packages/serialization/source/common/JsonParser.cpp @@ -2,9 +2,10 @@ #include #include - #include +#include + namespace l::serialization { bool JsonValue::valid() const { return mTokens && mCount > 0; } @@ -28,11 +29,15 @@ namespace l::serialization { } double JsonValue::as_double() const { - return std::atof(as_string().data()); + return std::stod(as_string().data()); } float JsonValue::as_float() const { - return static_cast(std::atof(as_string().data())); + return static_cast(std::stod(as_string().data())); + } + + l::math::fp::FixedPoint JsonValue::as_fixed_point() const { + return l::math::fp::FixedPoint(as_string()); } int8_t JsonValue::as_int8() const { From 0953f7eb78da4dbba3fe3637a6cb21213a1decfe Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 1 Aug 2025 23:10:43 +0200 Subject: [PATCH 037/179] Fix a few more fixed point edge cases. --- packages/math/include/math/MathFixedPoint.h | 12 +++++++++++- .../serialization/include/serialization/JsonParser.h | 2 +- packages/serialization/source/common/JsonParser.cpp | 4 ++-- 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/packages/math/include/math/MathFixedPoint.h b/packages/math/include/math/MathFixedPoint.h index f3bb656e..ad8bf321 100644 --- a/packages/math/include/math/MathFixedPoint.h +++ b/packages/math/include/math/MathFixedPoint.h @@ -19,7 +19,6 @@ namespace l::math::fp { static FixedPoint FromFloat(float f, int64_t scale = 100000000); static FixedPoint FromString(std::string_view number, int64_t scale = 100000000); static int64_t GetScaleFromString(std::string_view number, int32_t precision_digits = 1); - static int64_t GetScale(int32_t precision_digits = 1); static int64_t GetScaleFromFloat(float scaleFloat, int32_t precision_digits = 1); static int64_t GetScaleFromDouble(double scaleDouble, int32_t precision_digits = 1); @@ -28,6 +27,17 @@ namespace l::math::fp { FixedPoint(int64_t scaledValue, int64_t scale = 100000000) : value_(scaledValue), scale_(scale) { } + FixedPoint(int32_t scaledValue, int64_t scale = 100000000) + : value_(static_cast(scaledValue)), scale_(scale) { + } + FixedPoint(float value, int64_t scale) { + scale_ = scale; + value_ = static_cast(l::math::round(value * scale_)); + } + FixedPoint(double value, int64_t scale) { + scale_ = scale; + value_ = static_cast(l::math::round(value * scale_)); + } FixedPoint(float value, int32_t precision_digits = 1) { scale_ = GetScaleFromFloat(value, precision_digits); value_ = static_cast(l::math::round(value * scale_)); diff --git a/packages/serialization/include/serialization/JsonParser.h b/packages/serialization/include/serialization/JsonParser.h index 298cb5c2..024b3b40 100644 --- a/packages/serialization/include/serialization/JsonParser.h +++ b/packages/serialization/include/serialization/JsonParser.h @@ -53,7 +53,7 @@ namespace l::serialization { bool as_bool() const; double as_double() const; float as_float() const; - l::math::fp::FixedPoint as_fixed_point() const; + l::math::fp::FixedPoint as_fixed_point(int32_t precision_digits = 8) const; int8_t as_int8() const; int16_t as_int16() const; int32_t as_int32() const; diff --git a/packages/serialization/source/common/JsonParser.cpp b/packages/serialization/source/common/JsonParser.cpp index 8392a71c..4d0e10b4 100644 --- a/packages/serialization/source/common/JsonParser.cpp +++ b/packages/serialization/source/common/JsonParser.cpp @@ -36,8 +36,8 @@ namespace l::serialization { return static_cast(std::stod(as_string().data())); } - l::math::fp::FixedPoint JsonValue::as_fixed_point() const { - return l::math::fp::FixedPoint(as_string()); + l::math::fp::FixedPoint JsonValue::as_fixed_point(int32_t precision_digits) const { + return l::math::fp::FixedPoint(as_string(), precision_digits); } int8_t JsonValue::as_int8() const { From e6f68d55fc56837214211f5f30b5625a5c6fbac1 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 2 Aug 2025 21:30:11 +0200 Subject: [PATCH 038/179] Math: Fix fixed point implementation. --- packages/logging/include/logging/String.h | 1 + packages/logging/source/common/String.cpp | 23 +++ packages/math/include/math/MathFixedPoint.h | 131 ++++++++++++------ .../math/source/common/MathFixedPoint.cpp | 85 ++++-------- .../math/tests/common/MathFixedPointTest.cpp | 60 +++++++- .../include/serialization/JsonParser.h | 2 +- .../source/common/JsonParser.cpp | 4 +- 7 files changed, 194 insertions(+), 112 deletions(-) diff --git a/packages/logging/include/logging/String.h b/packages/logging/include/logging/String.h index 29c4223f..d2a52f51 100644 --- a/packages/logging/include/logging/String.h +++ b/packages/logging/include/logging/String.h @@ -225,6 +225,7 @@ namespace l::string { std::wstring widen(const std::string& str); int count_digits(int number); + std::tuple to_fixed_int(std::string_view s); template concept Number = requires(T a) { requires std::convertible_to || std::convertible_to; }; diff --git a/packages/logging/source/common/String.cpp b/packages/logging/source/common/String.cpp index 8a17dd72..d7a2229e 100644 --- a/packages/logging/source/common/String.cpp +++ b/packages/logging/source/common/String.cpp @@ -547,6 +547,29 @@ namespace l::string { return i; } + std::tuple to_fixed_int(std::string_view s) { + int64_t n = 0; + int32_t numDecimals = -1; + int32_t numDigits = -1; + for (char c : s) { + int64_t digit = static_cast(c - '0'); + if (digit < 0 || digit > 9) { + if (c == '.') { + numDecimals = 0; + } + continue; + } + if (digit > 0) { + numDigits = 0; + } + numDecimals = numDecimals < 0 ? numDecimals : numDecimals + 1; + numDigits = numDigits < 0 ? numDigits : numDigits + 1; + n *= 10; + n += digit; + } + return std::tuple(n, numDecimals, numDigits); + } + std::string_view cut(std::string_view s, const char ch) { auto i = s.find(ch); if (i != std::string::npos) { diff --git a/packages/math/include/math/MathFixedPoint.h b/packages/math/include/math/MathFixedPoint.h index ad8bf321..e1c100c5 100644 --- a/packages/math/include/math/MathFixedPoint.h +++ b/packages/math/include/math/MathFixedPoint.h @@ -15,60 +15,101 @@ namespace l::math::fp { class FixedPoint { public: - static FixedPoint FromDouble(double d, int64_t scale = 100000000); - static FixedPoint FromFloat(float f, int64_t scale = 100000000); - static FixedPoint FromString(std::string_view number, int64_t scale = 100000000); - static int64_t GetScaleFromString(std::string_view number, int32_t precision_digits = 1); - static int64_t GetScaleFromFloat(float scaleFloat, int32_t precision_digits = 1); - static int64_t GetScaleFromDouble(double scaleDouble, int32_t precision_digits = 1); - - // Constructors - FixedPoint() : value_(0), scale_(100000000) {} - FixedPoint(int64_t scaledValue, int64_t scale = 100000000) - : value_(scaledValue), scale_(scale) { + static FixedPoint FromDouble(double d, int64_t scale) { + return FixedPoint(static_cast(l::math::round(d * scale)), scale); } - FixedPoint(int32_t scaledValue, int64_t scale = 100000000) - : value_(static_cast(scaledValue)), scale_(scale) { - } - FixedPoint(float value, int64_t scale) { - scale_ = scale; - value_ = static_cast(l::math::round(value * scale_)); - } - FixedPoint(double value, int64_t scale) { - scale_ = scale; - value_ = static_cast(l::math::round(value * scale_)); + + static FixedPoint FromFloat(float f, int64_t scale) { + return FixedPoint(static_cast(l::math::round(f * scale)), scale); } - FixedPoint(float value, int32_t precision_digits = 1) { - scale_ = GetScaleFromFloat(value, precision_digits); - value_ = static_cast(l::math::round(value * scale_)); - normalise(precision_digits); + + static FixedPoint FromString(std::string_view number, int64_t scale) { + return FromDouble(std::atof(number.data()), scale); } - FixedPoint(double value, int32_t precision_digits = 1) { - scale_ = GetScaleFromDouble(value, precision_digits); - value_ = static_cast(l::math::round(value * scale_)); - normalise(precision_digits); + + static int64_t GetMinScaleFromDouble(double scaleDouble) { + if (scaleDouble == 0.0) { + return 0; + } + int32_t numDecimals = 0; + while (scaleDouble < 1.0 && numDecimals < 18) { + scaleDouble *= 10.0; + ++numDecimals; + } + if (numDecimals > 18) return false; // avoid int64_t overflow + auto scale = static_cast(0.5f + l::math::pow(10.0f, static_cast(numDecimals))); + return scale; } - FixedPoint(std::string_view number, int32_t precision_digits = 1) { - scale_ = GetScaleFromString(number, precision_digits); - auto f = std::atof(number.data()); - value_ = static_cast(l::math::round(f * scale_)); + + FixedPoint() : value_(0), scale_(1) {} + FixedPoint(int64_t scaledValue, int64_t scale = 100000000) + : value_(scaledValue), scale_(scale) { + normalise(); + } + FixedPoint(double value, int8_t numdecimals) { + auto v = l::math::abs(value); + if (v < 1.0) { + scale_ = 1000000000000000000; + value_ = static_cast(l::math::round(value * scale_)); + } + else if (v < 1000000000.0) { + scale_ = 1000000000; + value_ = static_cast(l::math::round(value * scale_)); + } + else { + scale_ = 1; + value_ = static_cast(l::math::round(value * scale_)); + } + round(numdecimals); + } + FixedPoint(double value) { + auto v = l::math::abs(value); + if (v < 1.0) { + scale_ = 1000000000000000000; + value_ = static_cast(l::math::round(value * scale_)); + round(9); + } + else if (v < 1000000000.0) { + scale_ = 1000000000; + value_ = static_cast(l::math::round(value * scale_)); + round(9); + } + else { + scale_ = 1; + value_ = static_cast(l::math::round(value * scale_)); + round(0); + } + } + FixedPoint(float value, int8_t numdecimals) : FixedPoint(static_cast(value), numdecimals) {} + FixedPoint(float value) : FixedPoint(static_cast(value)) {} + + FixedPoint(std::string_view number) { + auto [n, d, s] = l::string::to_fixed_int(number); + value_ = n; + auto scale = static_cast(0.5f + l::math::pow(10.0f, static_cast(d))); + scale_ = scale; + normalise(); } int32_t numDigits() const; double toDouble() const; float toFloat() const; std::string toString() const; - void normalise(int32_t precision_digits = 1); + void normalise(); + void rescale(int64_t scale); + void round(int32_t numDecimals); // Arithmetic FixedPoint operator+(const FixedPoint& other) const { - ASSERT(scale_ == other.scale_); // Ensure matching scales - return FixedPoint(value_ + other.value_, scale_); + FixedPoint tmp(other); + tmp.rescale(scale_); + return FixedPoint(value_ + tmp.value_, scale_); } FixedPoint operator-(const FixedPoint& other) const { - ASSERT(scale_ == other.scale_); - return FixedPoint(value_ - other.value_, scale_); + FixedPoint tmp(other); + tmp.rescale(scale_); + return FixedPoint(value_ - tmp.value_, scale_); } FixedPoint operator*(int64_t multiplier) const { @@ -76,7 +117,9 @@ namespace l::math::fp { } bool operator==(const FixedPoint& other) const { - return value_ == other.value_ && scale_ == other.scale_; + FixedPoint tmp(other); + tmp.rescale(scale_); + return value_ == tmp.value_ && scale_ == tmp.scale_; } bool operator!=(const FixedPoint& other) const { @@ -84,8 +127,9 @@ namespace l::math::fp { } bool operator<(const FixedPoint& other) const { - ASSERT(scale_ == other.scale_); - return value_ < other.value_; + FixedPoint tmp(other); + tmp.rescale(scale_); + return value_ < tmp.value_; } bool operator>(const FixedPoint& other) const { @@ -101,8 +145,9 @@ namespace l::math::fp { } FixedPoint operator%(const FixedPoint& other) const { - ASSERT(scale_ == other.scale_); - return FixedPoint(value_ % other.value_, scale_); + FixedPoint tmp(other); + tmp.rescale(scale_); + return FixedPoint(value_ % tmp.value_, scale_); } // Getters diff --git a/packages/math/source/common/MathFixedPoint.cpp b/packages/math/source/common/MathFixedPoint.cpp index 95e5b2ae..873e9d3e 100644 --- a/packages/math/source/common/MathFixedPoint.cpp +++ b/packages/math/source/common/MathFixedPoint.cpp @@ -2,74 +2,39 @@ #include "math/MathFixedPoint.h" namespace l::math::fp { - FixedPoint FixedPoint::FromDouble(double d, int64_t scale) { - return FixedPoint(static_cast(l::math::round(d * scale)), scale); - } - - FixedPoint FixedPoint::FromFloat(float f, int64_t scale) { - return FixedPoint(static_cast(l::math::round(f * scale)), scale); - } - - FixedPoint FixedPoint::FromString(std::string_view number, int64_t scale) { - return FromDouble(std::atof(number.data()), scale); - } - - int64_t FixedPoint::GetScaleFromString(std::string_view number, int32_t precision_digits) { - if (number.empty() || precision_digits == 0) { - return 0; - } - - auto it = std::find(number.begin(), number.end(), '.'); - if (it == number.end()) { - return 0; // str contains an integer and doesnt need fixed point - } - - // Find index of most significant digit - size_t decimal_start = 1 + it - number.begin(); - size_t first_nonzero = decimal_start; - while (first_nonzero < number.size() && number[first_nonzero] == '0') { - ++first_nonzero; + void FixedPoint::normalise() { + while (scale_ >= 10 && value_ >= 10 && (value_ % 10) == 0) { + value_ = value_ / 10; + scale_ = scale_ / 10; } - - if (first_nonzero == number.size()) return false; // no non-zero digit found - auto decimalZeroes = static_cast(first_nonzero - decimal_start); - - int32_t total_digits = decimalZeroes + precision_digits; - if (total_digits > 18) return false; // avoid int64_t overflow - - auto scale = static_cast(0.5f + l::math::pow(10.0f, static_cast(total_digits))); - return scale; - } - - int64_t FixedPoint::GetScaleFromFloat(float scaleFloat, int32_t precision_digits) { - return GetScaleFromDouble(static_cast(scaleFloat), precision_digits); } - int64_t FixedPoint::GetScaleFromDouble(double scaleDouble, int32_t precision_digits) { - if (scaleDouble == 0.0 || precision_digits == 0) { - return 0; + void FixedPoint::rescale(int64_t newScale) { + if (newScale > scale_) { // scale up, no loss in precision + int64_t diff = newScale / scale_; + ASSERT(l::math::abs(value_ * diff) < 100000000000000000); + value_ *= diff; + scale_ *= diff; } - - int32_t decimalZeroes = 0; - scaleDouble *= 10.0; - while (scaleDouble < 1.0 && decimalZeroes < 18) { - scaleDouble *= 10.0; - ++decimalZeroes; + else if (newScale < scale_) { + int64_t diff = scale_ / newScale; + ASSERT(diff >= 10); + scale_ /= diff; + diff /= 10; + value_ /= diff; + value_ += 5; // add 0.5 before floor + value_ /= 10; // round (floor(0.5 + x)) } - int32_t total_digits = decimalZeroes + precision_digits; - if (total_digits > 18) return false; // avoid int64_t overflow - - auto scale = static_cast(0.5f + l::math::pow(10.0f, static_cast(total_digits))); - return scale; } - void FixedPoint::normalise(int32_t precision_digits) { - auto precisionScale = static_cast(0.5 + l::math::pow(10.0, static_cast(precision_digits))); - while (value_ >= precisionScale) { - value_ = value_ / precisionScale; - scale_ = scale_ / 10; - } + void FixedPoint::round(int32_t numDecimals) { + int64_t scale = 1; + while (numDecimals-- > 0) { + scale *= 10; + }; + rescale(scale); + normalise(); } int32_t FixedPoint::numDigits() const { diff --git a/packages/math/tests/common/MathFixedPointTest.cpp b/packages/math/tests/common/MathFixedPointTest.cpp index 516c75f4..0312504e 100644 --- a/packages/math/tests/common/MathFixedPointTest.cpp +++ b/packages/math/tests/common/MathFixedPointTest.cpp @@ -8,36 +8,84 @@ using namespace l::math::fp; TEST(MathFixedPoint, Basic) { { - FixedPoint fp(0.0001f, 1); + FixedPoint fp(100300001.12); + TEST_TRUE(fp.scale() == 100, ""); + TEST_FUZZY(fp.toDouble(), 100300001.12, 0.001, ""); + TEST_TRUE(fp.rawValue() == 10030000112, ""); + } + { + FixedPoint fp(100300001000016.0); + TEST_TRUE(fp.scale() == 1, ""); + TEST_FUZZY(fp.toDouble(), 100300001000016.0, 0.01, ""); + TEST_TRUE(fp.rawValue() == 100300001000016, ""); + } + { + FixedPoint fp(1000.1f, 0); + TEST_TRUE(fp.scale() == 1, ""); + TEST_FUZZY(fp.toFloat(), 1000.0f, 0.0000001f, ""); + TEST_TRUE(fp.rawValue() == 1000, ""); + } + { + FixedPoint fp(1000.1f, 1); + TEST_TRUE(fp.scale() == 10, ""); + TEST_FUZZY(fp.toFloat(), 1000.1f, 0.0000001f, ""); + TEST_TRUE(fp.rawValue() == 10001, ""); + } + { + FixedPoint fp(1001.1f, 1); + TEST_TRUE(fp.scale() == 10, ""); + TEST_FUZZY(fp.toFloat(), 1001.1f, 0.0000001f, ""); + TEST_TRUE(fp.rawValue() == 10011, ""); + } + { + FixedPoint fp(0.0001f); TEST_TRUE(fp.scale() == 10000, ""); TEST_FUZZY(fp.toFloat(), 0.0001f, 0.0000001f, ""); TEST_TRUE(fp.rawValue() == 1, ""); } { - FixedPoint fp("0.002", 1); + FixedPoint fp(0.00000004f); + TEST_TRUE(fp.scale() == 100000000, ""); + TEST_FUZZY(fp.toFloat(), 0.00000004f, 0.00000001f, ""); + TEST_TRUE(fp.rawValue() == 4, ""); + } + { + FixedPoint fp(0.002f); TEST_TRUE(fp.scale() == 1000, ""); TEST_FUZZY(fp.toFloat(), 0.002f, 0.0000001f, ""); TEST_TRUE(fp.rawValue() == 2, ""); } { - FixedPoint fp("0.00213", 3); + FixedPoint fp(0.00213f); TEST_TRUE(fp.scale() == 100000, ""); TEST_FUZZY(fp.toFloat(), 0.00213f, 0.0000001f, ""); TEST_TRUE(fp.rawValue() == 213, ""); } + { - FixedPoint fp(0.002f, 1); + FixedPoint fp("0.002"); TEST_TRUE(fp.scale() == 1000, ""); TEST_FUZZY(fp.toFloat(), 0.002f, 0.0000001f, ""); TEST_TRUE(fp.rawValue() == 2, ""); } { - FixedPoint fp(0.00213f, 3); + FixedPoint fp("0.00213"); TEST_TRUE(fp.scale() == 100000, ""); TEST_FUZZY(fp.toFloat(), 0.00213f, 0.0000001f, ""); TEST_TRUE(fp.rawValue() == 213, ""); } - + { + FixedPoint fp("0.001f"); + TEST_TRUE(fp.scale() == 1000, ""); + TEST_FUZZY(fp.toFloat(), 0.001f, 0.0000001f, ""); + TEST_TRUE(fp.rawValue() == 1, ""); + } + { + FixedPoint fp("10000.0f"); + TEST_TRUE(fp.scale() == 1, ""); + TEST_FUZZY(fp.toFloat(), 10000.0f, 0.0000001f, ""); + TEST_TRUE(fp.rawValue() == 10000, ""); + } return 0; } diff --git a/packages/serialization/include/serialization/JsonParser.h b/packages/serialization/include/serialization/JsonParser.h index 024b3b40..298cb5c2 100644 --- a/packages/serialization/include/serialization/JsonParser.h +++ b/packages/serialization/include/serialization/JsonParser.h @@ -53,7 +53,7 @@ namespace l::serialization { bool as_bool() const; double as_double() const; float as_float() const; - l::math::fp::FixedPoint as_fixed_point(int32_t precision_digits = 8) const; + l::math::fp::FixedPoint as_fixed_point() const; int8_t as_int8() const; int16_t as_int16() const; int32_t as_int32() const; diff --git a/packages/serialization/source/common/JsonParser.cpp b/packages/serialization/source/common/JsonParser.cpp index 4d0e10b4..8392a71c 100644 --- a/packages/serialization/source/common/JsonParser.cpp +++ b/packages/serialization/source/common/JsonParser.cpp @@ -36,8 +36,8 @@ namespace l::serialization { return static_cast(std::stod(as_string().data())); } - l::math::fp::FixedPoint JsonValue::as_fixed_point(int32_t precision_digits) const { - return l::math::fp::FixedPoint(as_string(), precision_digits); + l::math::fp::FixedPoint JsonValue::as_fixed_point() const { + return l::math::fp::FixedPoint(as_string()); } int8_t JsonValue::as_int8() const { From 4f35ebf751100b5ecb8354a41c28b3242a501802 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 3 Aug 2025 00:11:55 +0200 Subject: [PATCH 039/179] Math: add fp multiplication. --- packages/math/include/math/MathFixedPoint.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/math/include/math/MathFixedPoint.h b/packages/math/include/math/MathFixedPoint.h index e1c100c5..c989be22 100644 --- a/packages/math/include/math/MathFixedPoint.h +++ b/packages/math/include/math/MathFixedPoint.h @@ -112,6 +112,15 @@ namespace l::math::fp { return FixedPoint(value_ - tmp.value_, scale_); } + FixedPoint operator*(const FixedPoint& other) const { + if (other.scale() != scale()) { + FixedPoint tmp(other); + tmp.rescale(scale_); + return FixedPoint(value_ * tmp.value_, scale_ * scale_); + } + return FixedPoint(value_ * other.value_, scale_ * scale_); + } + FixedPoint operator*(int64_t multiplier) const { return FixedPoint(value_ * multiplier, scale_); } From 07baac3f5f9a0fa7e64859337c485055689ae30b Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 3 Aug 2025 13:46:39 +0200 Subject: [PATCH 040/179] logging: add empty string buffer check. --- packages/logging/include/logging/String.h | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/logging/include/logging/String.h b/packages/logging/include/logging/String.h index d2a52f51..d2724a3d 100644 --- a/packages/logging/include/logging/String.h +++ b/packages/logging/include/logging/String.h @@ -49,6 +49,10 @@ namespace l::string { cur() = 0; } + bool empty() { + return size() == 0; + } + size_t left() { return static_cast(BUFSIZE - mPos); } From 280a2f0ac473b5af010ec8c4947b173db44b86f8 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 3 Aug 2025 23:05:04 +0200 Subject: [PATCH 041/179] NG: Add combined diff+int+add+scale node. --- deps/ldeps | 1 - .../operations/NodeGraphOpMathNumerical.h | 29 +++++++ .../source/common/NodeGraphSchema.cpp | 4 + .../operations/NodeGraphOpMathNumerical.cpp | 75 ++++++++++++++++++- 4 files changed, 106 insertions(+), 3 deletions(-) delete mode 160000 deps/ldeps diff --git a/deps/ldeps b/deps/ldeps deleted file mode 160000 index 92d1d022..00000000 --- a/deps/ldeps +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 92d1d02274008c44e6367e665747258e9d977b75 diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index f841fadb..5dcdeac4 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -149,4 +149,33 @@ namespace l::nodegraph { float mCurRangeMax = 0.0f; float mCurRangeMin = 0.0f; }; + + /*********************************************************************/ + class MathNumericalDerivate2 : public NodeGraphOp { + public: + MathNumericalDerivate2(NodeGraphBase* node) : + NodeGraphOp(node, "Derivate2") + { + AddInput("In", 0.0f, 1); + AddInput("Base", 0.0f, 1); + AddInput("Friction1", 1.0f, 1, 0.0f, 1.0f); + AddInput("Friction2", 1.0f, 1, 0.0f, 1.0f); + AddInput("Scale1", 1.0f, 1, 0.0f, 100.0f); + AddInput("Scale2", 1.0f, 1, 0.0f, 100.0f); + + AddOutput("d1dt", 0.0f, 1); + AddOutput("d2dt", 0.0f, 1); + AddOutput("d1+base", 0.0f, 1); + AddOutput("d2+base", 0.0f, 1); + } + + virtual ~MathNumericalDerivate2() = default; + virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + protected: + int32_t mReadSamples = 0; + float mInputPrev1 = 0.0f; + float mOutput1 = 0.0f; + float mInputPrev2 = 0.0f; + float mOutput2 = 0.0f; + }; } \ No newline at end of file diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 6f3281b3..bcfaeabb 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -309,6 +309,9 @@ namespace l::nodegraph { case 145: node = mMainNodeGraph.NewNode(id, NodeType::Default); break; + case 146: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; // Trading data io case 200: @@ -614,6 +617,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Numerical", 143, "Difference"); RegisterNodeType("Math.Numerical", 144, "Level Trigger"); RegisterNodeType("Math.Numerical", 145, "Minmax Channel"); + RegisterNodeType("Math.Numerical", 146, "Derivate2"); } else if (typeGroup == "Trading.Data IO") { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 73bd5f9f..afadaef9 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -143,8 +143,11 @@ namespace l::nodegraph { level = numLevels * levelMinMax; } float pulse = 0.0f; - if (static_cast(mLevelPrev) != static_cast(level)) { - pulse = level > mLevelPrev ? 1.0f : -1.0f; + if (static_cast(level) > static_cast(mLevelPrev + level)) { + pulse = 1.0f; + } + else if (static_cast(level) < static_cast(mLevelPrev)) { + pulse = -1.0f; } mLevelPrev = level; @@ -197,4 +200,72 @@ namespace l::nodegraph { } } + void MathNumericalDerivate2::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + + auto inInput = &inputs.at(0).Get(numSamples); + auto baseInput = &inputs.at(1).Get(numSamples); + + auto friction1 = inputs.at(2).Get(); + auto friction2 = inputs.at(3).Get(); + auto scale1 = inputs.at(4).Get(); + auto scale2 = inputs.at(5).Get(); + + auto frictionFactor1 = l::math::clamp(l::math::pow(friction1, 0.25f), 0.0f, 1.0f); + auto frictionFactor2 = l::math::clamp(l::math::pow(friction2, 0.25f), 0.0f, 1.0f); + + auto output1 = &outputs.at(0).Get(numSamples); + auto output2 = &outputs.at(1).Get(numSamples); + auto outputBase1 = &outputs.at(2).Get(numSamples); + auto outputBase2 = &outputs.at(3).Get(numSamples); + + for (int32_t i = 0; i < numSamples; i++) { + float in = *inInput++; + auto base = *baseInput++; + + // derivate 1 + float diff1 = in - mInputPrev1; + mInputPrev1 = in; + + // integral 1 + mOutput1 += diff1; + mOutput1 *= frictionFactor1; + + auto output1Scaled = mOutput1 * scale1; + + // derivate 2 + float diff2 = output1Scaled - mInputPrev2; + mInputPrev2 = output1Scaled; + + // integral 2 + mOutput2 += diff2; + mOutput2 *= frictionFactor2; + + auto output2Scaled = mOutput2 * scale2; + + *output1++ = output1Scaled; + *output2++ = output2Scaled; + *outputBase1++ = output1Scaled + base; + *outputBase2++ = output2Scaled + base; + } + + mReadSamples += numSamples; + + if (mReadSamples >= numCacheSamples) { + mReadSamples = 0; + mOutput1 = 0.0f; + mOutput2 = 0.0f; + mInputPrev1 = 0.0f; + mInputPrev2 = 0.0f; + } + + if (isnan(mOutput1)) { + mOutput1 = 0.0f; + mInputPrev1 = 0.0f; + } + if (isnan(mOutput2)) { + mOutput2 = 0.0f; + mInputPrev2 = 0.0f; + } + } + } From 3115a48d5f9609cab50dbbd5fab51227eeabb5ea Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 4 Aug 2025 13:46:19 +0200 Subject: [PATCH 042/179] Fix some node names and value edit. Add ui markers and a reconstruct node to simplify common usecase. --- .../include/nodegraph/core/NodeGraphBase.h | 4 +- .../operations/NodeGraphOpMathAritmethic.h | 167 +++++++++--------- .../operations/NodeGraphOpMathNumerical.h | 76 ++++---- .../nodegraph/operations/NodeGraphOpUI.h | 31 +++- .../source/common/NodeGraphSchema.cpp | 12 +- .../source/common/core/NodeGraphBase.cpp | 10 +- .../operations/NodeGraphOpMathNumerical.cpp | 79 ++++----- .../common/operations/NodeGraphOpUI.cpp | 30 ++++ 8 files changed, 228 insertions(+), 181 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h index 7b36b896..1409a84d 100644 --- a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h @@ -244,8 +244,8 @@ namespace l::nodegraph { virtual int32_t AddInput(std::string_view name, float defaultValue = 0.0f, int32_t minSize = 1, float boundMin = -l::math::constants::FLTMAX, float boundMax = l::math::constants::FLTMAX, bool visible = true, bool editable = true); virtual int32_t AddOutput(std::string_view name, float defaultValue = 0.0f, int32_t minSize = 1, bool visible = true); virtual int32_t AddConstant(std::string_view name, float defaultValue = 0.0f, int32_t minSize = 1, float boundMin = -l::math::constants::FLTMAX, float boundMax = l::math::constants::FLTMAX, bool visible = true, bool editable = true); - virtual int32_t AddInput2(std::string_view name, int32_t minSize, InputFlags flags); - virtual int32_t AddOutput2(std::string_view name, int32_t minSize, OutputFlags flags); + virtual int32_t AddInput2(std::string_view name, int32_t minSize = 2, InputFlags flags = InputFlags(false, false, false, false)); + virtual int32_t AddOutput2(std::string_view name, int32_t minSize = 2, OutputFlags flags = OutputFlags(false, false)); NodeGraphBase* mNode = nullptr; std::string mName; diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h index 4f9c7601..c34e1072 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h @@ -29,18 +29,15 @@ namespace l::nodegraph { MathAritmethicAdd(NodeGraphBase* node) : NodeGraphOp(node, "Add") { - AddInput2("In1", 1, InputFlags(false, false, false, false)); - AddInput2("In2", 1, InputFlags(false, false, false, false)); - AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); - AddOutput("In1+In2"); + AddInput("a"); + AddInput("b"); + AddOutput("a+b"); } virtual ~MathAritmethicAdd() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = inputs.at(0).GetIterator(numSamples); - auto input1 = inputs.at(1).GetIterator(numSamples); - auto lodExp = inputs.at(2).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto output = outputs.at(0).GetIterator(numSamples, lodFactor); + auto input0 = &inputs.at(0).Get(numSamples); + auto input1 = &inputs.at(1).Get(numSamples); + auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { *output++ = *input0++ + *input1++; @@ -54,19 +51,16 @@ namespace l::nodegraph { MathAritmethicMultiply(NodeGraphBase* node) : NodeGraphOp(node, "Multiply") { - AddInput2("In1", 1, InputFlags(false, false, false, false)); - AddInput2("In2", 1, InputFlags(false, false, false, false)); - AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); - AddOutput("In1*In2"); + AddInput("a"); + AddInput("b"); + AddOutput("a*b"); } virtual ~MathAritmethicMultiply() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = inputs.at(0).GetIterator(numSamples); - auto input1 = inputs.at(1).GetIterator(numSamples); - auto lodExp = inputs.at(2).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto output = outputs.at(0).GetIterator(numSamples, lodFactor); + auto input0 = &inputs.at(0).Get(numSamples); + auto input1 = &inputs.at(1).Get(numSamples); + auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { *output++ = *input0++ * *input1++; @@ -80,20 +74,17 @@ namespace l::nodegraph { MathAritmethicSubtract(NodeGraphBase* node) : NodeGraphOp(node, "Subtract") { - AddInput2("In1", 1, InputFlags(false, false, false, false)); - AddInput2("In2", 1, InputFlags(false, false, false, false)); - AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); - AddOutput("In1-In2"); - AddOutput("In2-In1"); + AddInput("a"); + AddInput("b"); + AddOutput("a-b"); + AddOutput("b-a"); } virtual ~MathAritmethicSubtract() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = inputs.at(0).GetIterator(numSamples); - auto input1 = inputs.at(1).GetIterator(numSamples); - auto lodExp = inputs.at(2).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto output1 = outputs.at(0).GetIterator(numSamples, lodFactor); - auto output2 = outputs.at(1).GetIterator(numSamples, lodFactor); + auto input0 = &inputs.at(0).Get(numSamples); + auto input1 = &inputs.at(1).Get(numSamples); + auto output1 = &outputs.at(0).Get(numSamples); + auto output2 = &outputs.at(1).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { auto diff = *input0++ - *input1++; @@ -109,17 +100,14 @@ namespace l::nodegraph { MathAritmethicNegate(NodeGraphBase* node) : NodeGraphOp(node, "Negate") { - AddInput2("In", 1, InputFlags(false, false, false, false)); - AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); - AddOutput("-In"); + AddInput("x"); + AddOutput("-x"); } virtual ~MathAritmethicNegate() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = inputs.at(0).GetIterator(numSamples); - auto lodExp = inputs.at(1).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto output = outputs.at(0).GetIterator(numSamples, lodFactor); + auto input0 = &inputs.at(0).Get(numSamples); + auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { *output++ = -*input0++; @@ -134,21 +122,18 @@ namespace l::nodegraph { MathAritmethicAbs(NodeGraphBase* node) : NodeGraphOp(node, "Abs") { - AddInput2("In", 1, InputFlags(false, false, false, false)); - AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); - AddOutput("abs(In)"); - AddOutput("max(In,0)"); - AddOutput("min(In,0)"); + AddInput("x"); + AddOutput("abs(x)"); + AddOutput("max(x,0)"); + AddOutput("min(x,0)"); } virtual ~MathAritmethicAbs() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = inputs.at(0).GetIterator(numSamples); - auto lodExp = inputs.at(1).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto output1 = outputs.at(0).GetIterator(numSamples, lodFactor); - auto output2 = outputs.at(1).GetIterator(numSamples, lodFactor); - auto output3 = outputs.at(2).GetIterator(numSamples, lodFactor); + auto input0 = &inputs.at(0).Get(numSamples); + auto output1 = &outputs.at(0).Get(numSamples); + auto output2 = &outputs.at(1).Get(numSamples); + auto output3 = &outputs.at(2).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { auto in = *input0++; @@ -165,21 +150,18 @@ namespace l::nodegraph { MathAritmethicLog(NodeGraphBase* node) : NodeGraphOp(node, "Log") { - AddInput2("In", 1, InputFlags(false, false, false, false)); - AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); - AddInput("Base", 2.72f, 1, 1.0f, 10.0f); - AddOutput("ln(In)"); - AddOutput("ln(In)/ln(Base)"); + AddInput("x"); + AddInput("b", 2.72f, 1, 1.0f, 10.0f); + AddOutput("Log"); + AddOutput("Logb"); } virtual ~MathAritmethicLog() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = inputs.at(0).GetIterator(numSamples); - auto lodExp = inputs.at(1).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto base = inputs.at(2).Get(); - auto output1 = outputs.at(0).GetIterator(numSamples, lodFactor); - auto output2 = outputs.at(1).GetIterator(numSamples, lodFactor); + auto input0 = &inputs.at(0).Get(numSamples); + auto base = inputs.at(1).Get(); + auto output1 = &outputs.at(0).Get(numSamples); + auto output2 = &outputs.at(1).Get(numSamples); // we want logb(in) = ln(in)/ln(b) // so precalc base factor 1/ln(b) @@ -200,21 +182,18 @@ namespace l::nodegraph { MathAritmethicMultiply3(NodeGraphBase* node) : NodeGraphOp(node, "Multiply3") { - AddInput2("In1", 1, InputFlags(false, false, false, false)); - AddInput2("In2", 1, InputFlags(false, false, false, false)); - AddInput2("In3", 1, InputFlags(false, false, false, false)); - AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); - AddOutput("In1*In2*In3"); + AddInput("a"); + AddInput("b"); + AddInput("c"); + AddOutput("abc"); } virtual ~MathAritmethicMultiply3() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = inputs.at(0).GetIterator(numSamples); - auto input1 = inputs.at(1).GetIterator(numSamples); - auto input2 = inputs.at(2).GetIterator(numSamples); - auto lodExp = inputs.at(3).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto output = outputs.at(0).GetIterator(numSamples, lodFactor); + auto input0 = &inputs.at(0).Get(numSamples); + auto input1 = &inputs.at(1).Get(numSamples); + auto input2 = &inputs.at(2).Get(numSamples); + auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { *output++ = *input0++ * *input1++ * *input2++; @@ -228,11 +207,10 @@ namespace l::nodegraph { MathAritmethicMultiplyAndAdd(NodeGraphBase* node) : NodeGraphOp(node, "Multiply & Add") { - AddInput2("In1", 1, InputFlags(false, false, false, false)); - AddInput2("In2", 1, InputFlags(false, false, false, false)); - AddInput2("In3", 1, InputFlags(false, false, false, false)); - AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); - AddOutput("In1*In2+In3"); + AddInput("a"); + AddInput("b"); + AddInput("c"); + AddOutput("ab+c"); } virtual ~MathAritmethicMultiplyAndAdd() = default; @@ -256,19 +234,16 @@ namespace l::nodegraph { MathAritmethicRound(NodeGraphBase* node) : NodeGraphOp(node, "Round") { - AddInput2("In", 1, InputFlags(false, false, false, false)); - AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); - AddOutput("int(In+0.5)"); + AddInput("x"); + AddOutput("Out"); } virtual ~MathAritmethicRound() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { outputs.at(0).mOutput = l::math::round(inputs.at(0).Get()); - auto input0 = inputs.at(0).GetIterator(numSamples); - auto lodExp = inputs.at(1).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto output = outputs.at(0).GetIterator(numSamples, lodFactor); + auto input0 = &inputs.at(0).Get(numSamples); + auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { *output++ = l::math::round(*input0++); @@ -282,9 +257,9 @@ namespace l::nodegraph { MathAritmethicPow(NodeGraphBase* node) : NodeGraphOp(node, "Pow") { - AddInput2("In", 1, InputFlags(false, false, false, false)); - AddInput("Exponent", 2.72f, 1, 1.0f, 10.0f); - AddOutput("exp(In)"); + AddInput("x"); + AddInput("y", 2.72f, 1, 1.0f, 10.0f); + AddOutput("x^y"); } virtual ~MathAritmethicPow() = default; @@ -300,4 +275,28 @@ namespace l::nodegraph { } } }; + + /*********************************************************************/ + class MathAritmethicSum3 : public NodeGraphOp { + public: + MathAritmethicSum3(NodeGraphBase* node) : + NodeGraphOp(node, "Sum3") + { + AddInput("a"); + AddInput("b"); + AddInput("c"); + AddOutput("a+b+c"); + } + virtual ~MathAritmethicSum3() = default; + virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { + auto input0 = &inputs.at(0).Get(numSamples); + auto input1 = &inputs.at(1).Get(numSamples); + auto input2 = &inputs.at(2).Get(numSamples); + auto output = &outputs.at(0).Get(numSamples); + + for (int32_t i = 0; i < numSamples; i++) { + *output++ = *input0++ + *input1++ + *input2++; + } + } + }; } \ No newline at end of file diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 5dcdeac4..0a358c31 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -29,10 +29,9 @@ namespace l::nodegraph { MathNumericalIntegral(NodeGraphBase* node) : NodeGraphOp(node, "Integral") { - AddInput("In", 0.0f, 1); + AddInput2("x"); AddInput("Friction", 1.0f, 1, 0.0f, 1.0f); - AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); - AddOutput("Out", 0.0f, 1); + AddOutput2("Intgr(x)"); } virtual ~MathNumericalIntegral() = default; @@ -47,17 +46,16 @@ namespace l::nodegraph { }; /*********************************************************************/ - class MathNumericalDerivate : public NodeGraphOp { + class MathNumericalTemporalChange : public NodeGraphOp { public: - MathNumericalDerivate(NodeGraphBase* node) : - NodeGraphOp(node, "Derivate") + MathNumericalTemporalChange(NodeGraphBase* node) : + NodeGraphOp(node, "Temporal Change") { - AddInput("In", 0.0f, 1); - AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); - AddOutput("Out", 0.0f, 1); + AddInput2("in"); + AddOutput2("out"); } - virtual ~MathNumericalDerivate() = default; + virtual ~MathNumericalTemporalChange() = default; virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; protected: int32_t mReadSamples = 0; @@ -69,11 +67,10 @@ namespace l::nodegraph { class MathNumericalDiffNorm : public NodeGraphOp { public: MathNumericalDiffNorm(NodeGraphBase* node) : - NodeGraphOp(node, "Difference Normalized") + NodeGraphOp(node, "Temporal diff norm") { - AddInput("In", 0.0f, 1); - AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); - AddOutput("Out", 0.0f, 1); + AddInput2("x"); + AddOutput2("Diff norm"); } virtual ~MathNumericalDiffNorm() = default; @@ -88,11 +85,10 @@ namespace l::nodegraph { class MathNumericalDiff : public NodeGraphOp { public: MathNumericalDiff(NodeGraphBase* node) : - NodeGraphOp(node, "Difference") + NodeGraphOp(node, "Temporal Difference") { - AddInput("In", 0.0f, 1); - AddInput("Lod", 0.0f, 1, 0.0f, 1.0f); - AddOutput("Out", 0.0f, 1); + AddInput2("In"); + AddOutput2("Diff"); } virtual ~MathNumericalDiff() = default; @@ -109,14 +105,14 @@ namespace l::nodegraph { MathNumericalLevelTrigger(NodeGraphBase* node) : NodeGraphOp(node, "Level Trigger") { - AddInput2("In", 1, InputFlags(false, false, false, false)); - AddInput2("Max", 1, InputFlags(false, false, false, false)); - AddInput2("Min", 1, InputFlags(false, false, false, false)); + AddInput2("In"); + AddInput2("Max"); + AddInput2("Min"); AddInput("Num levels", 1.0f, 1, 1.0f, 100.0f, true, true); AddInput("Max%", 1.0f, 1, 0.0f, 1.0f, true, true); AddInput("Min%", 0.0f, 1, 0.0f, 1.0f, true, true); - AddOutput("Level", 0.0f, 1); - AddOutput("Pulse", 0.0f, 1); + AddOutput2("Level"); + AddOutput2("Pulse"); } virtual ~MathNumericalLevelTrigger() = default; @@ -131,14 +127,14 @@ namespace l::nodegraph { MathNumericalMinMaxChannel(NodeGraphBase* node) : NodeGraphOp(node, "Minmax Channel") { - AddInput("Upper Bound", 0.0f, 1); - AddInput("Lower Bound", 0.0f, 1); - AddInput("Bounded Value", 0.0f, 1); - - AddOutput("Range", 0.0f, 1); - AddOutput("Range Max", 0.0f, 1); - AddOutput("Range Min", 0.0f, 1); - AddOutput("Value Norm", 0.0f, 1); + AddInput2("Upper Bound"); + AddInput2("Lower Bound"); + AddInput2("Bounded Value"); + + AddOutput2("Range"); + AddOutput2("Range Max"); + AddOutput2("Range Min"); + AddOutput2("Value Norm"); } virtual ~MathNumericalMinMaxChannel() = default; @@ -154,28 +150,30 @@ namespace l::nodegraph { class MathNumericalDerivate2 : public NodeGraphOp { public: MathNumericalDerivate2(NodeGraphBase* node) : - NodeGraphOp(node, "Derivate2") + NodeGraphOp(node, "Reconstructor") { - AddInput("In", 0.0f, 1); + AddInput2("In"); AddInput("Base", 0.0f, 1); AddInput("Friction1", 1.0f, 1, 0.0f, 1.0f); AddInput("Friction2", 1.0f, 1, 0.0f, 1.0f); AddInput("Scale1", 1.0f, 1, 0.0f, 100.0f); AddInput("Scale2", 1.0f, 1, 0.0f, 100.0f); - AddOutput("d1dt", 0.0f, 1); - AddOutput("d2dt", 0.0f, 1); - AddOutput("d1+base", 0.0f, 1); - AddOutput("d2+base", 0.0f, 1); + AddOutput2("Diff"); + AddOutput2("Diff+base"); + AddOutput2("Intgr1"); + AddOutput2("Intgr+base"); + AddOutput2("Intgr2"); + AddOutput2("Intgr2+base"); } virtual ~MathNumericalDerivate2() = default; virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; protected: int32_t mReadSamples = 0; - float mInputPrev1 = 0.0f; + float mInputPrev = 0.0f; + float mDiffPrev = 0.0f; float mOutput1 = 0.0f; - float mInputPrev2 = 0.0f; float mOutput2 = 0.0f; }; } \ No newline at end of file diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index 79bb112f..b105a56e 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -74,7 +74,7 @@ namespace l::nodegraph { GraphUIText(NodeGraphBase* node) : NodeGraphOp(node, "UI Text") { - AddInput2("In", 1, InputFlags(false, false, false, true)); + AddInput2("In", 1, InputFlags(false, true, true, true)); } virtual ~GraphUIText() = default; @@ -97,9 +97,7 @@ namespace l::nodegraph { AddInput2("Name", 1, InputFlags(false, true, true, true)); AddOutput("Data"); } - virtual ~GraphUIChartLine() { - - } + virtual ~GraphUIChartLine() = default; virtual void DefaultDataInit() override { mNode->SetInput(2, "Chart Line"); } @@ -131,5 +129,30 @@ namespace l::nodegraph { protected: int32_t mLatestUnixtime = 0; }; + + /*********************************************************************/ + class GraphUIChartMarkers : public NodeGraphOp { + public: + GraphUIChartMarkers(NodeGraphBase* node) : + NodeGraphOp(node, "Chart Markers") + { + AddInput2("Time"); + AddInput2("y"); + AddInput2("Marker"); + AddInput2("Name", 1, InputFlags(false, true, true, true)); + } + virtual ~GraphUIChartMarkers() = default; + virtual void DefaultDataInit() override { + mNode->SetInput(2, "Chart Markers"); + } + virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + std::vector>& GetMarkers() { + return mMarkers; + } + protected: + int32_t mReadSamples = 0; + float mPrevValue = 0.0f; + std::vector> mMarkers; + }; } diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index bcfaeabb..abdc6b50 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -278,6 +278,9 @@ namespace l::nodegraph { case 109: node = mMainNodeGraph.NewNode(id, NodeType::Default); break; + case 110: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; // Math logical operators case 120: @@ -295,7 +298,7 @@ namespace l::nodegraph { node = mMainNodeGraph.NewNode(id, NodeType::Default); break; case 141: - node = mMainNodeGraph.NewNode(id, NodeType::Default); + node = mMainNodeGraph.NewNode(id, NodeType::Default); break; case 142: node = mMainNodeGraph.NewNode(id, NodeType::Default); @@ -495,6 +498,9 @@ namespace l::nodegraph { case 604: node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput); break; + case 605: + node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput); + break; @@ -604,6 +610,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Aritmethic", 107, "Madd"); RegisterNodeType("Math.Aritmethic", 108, "Round"); RegisterNodeType("Math.Aritmethic", 109, "Pow"); + RegisterNodeType("Math.Aritmethic", 110, "Sum3"); } else if (typeGroup == "Math.Logic") { RegisterNodeType("Math.Logic", 120, "And"); @@ -617,7 +624,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Numerical", 143, "Difference"); RegisterNodeType("Math.Numerical", 144, "Level Trigger"); RegisterNodeType("Math.Numerical", 145, "Minmax Channel"); - RegisterNodeType("Math.Numerical", 146, "Derivate2"); + RegisterNodeType("Math.Numerical", 146, "Reconstructor"); } else if (typeGroup == "Trading.Data IO") { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); @@ -693,6 +700,7 @@ namespace l::nodegraph { RegisterNodeType("UI", 602, "UI Chart Lines"); RegisterNodeType("UI", 603, "UI Candle Sticks"); RegisterNodeType("UI", 604, "UI Text"); + RegisterNodeType("UI", 605, "UI Chart Markers"); } else { LOG(LogWarning) << "Type group does not exist: " << typeGroup; diff --git a/packages/nodegraph/source/common/core/NodeGraphBase.cpp b/packages/nodegraph/source/common/core/NodeGraphBase.cpp index 94c8173b..a3ae9dea 100644 --- a/packages/nodegraph/source/common/core/NodeGraphBase.cpp +++ b/packages/nodegraph/source/common/core/NodeGraphBase.cpp @@ -120,7 +120,7 @@ namespace l::nodegraph { } bool NodeGraphBase::ClearInput(int8_t inputChannel) { - ASSERT(inputChannel >= 0 && static_cast(inputChannel) < mInputs.size()); + //ASSERT(inputChannel >= 0 && static_cast(inputChannel) < mInputs.size()); if (!IsValidInOutNum(inputChannel, mInputs.size())) { return false; } @@ -136,7 +136,7 @@ namespace l::nodegraph { } bool NodeGraphBase::SetInput(int8_t inputChannel, NodeGraphBase& source, int8_t sourceOutputChannel) { - ASSERT(inputChannel >= 0 && static_cast(inputChannel) < mInputs.size()); + //ASSERT(inputChannel >= 0 && static_cast(inputChannel) < mInputs.size()); if (!IsValidInOutNum(inputChannel, mInputs.size())) { return false; } @@ -148,7 +148,7 @@ namespace l::nodegraph { } bool NodeGraphBase::SetInput(int8_t inputChannel, NodeGraphGroup& source, int8_t sourceChannel) { - ASSERT(inputChannel >= 0 && static_cast(inputChannel) < mInputs.size()); + //ASSERT(inputChannel >= 0 && static_cast(inputChannel) < mInputs.size()); if (!IsValidInOutNum(inputChannel, mInputs.size())) { return false; } @@ -167,7 +167,7 @@ namespace l::nodegraph { } bool NodeGraphBase::SetInput(int8_t inputChannel, float initialValue, int32_t minSize) { - ASSERT(inputChannel >= 0 && static_cast(inputChannel) < mInputs.size()); + //ASSERT(inputChannel >= 0 && static_cast(inputChannel) < mInputs.size()); if (!IsValidInOutNum(inputChannel, mInputs.size())) { return false; } @@ -194,7 +194,7 @@ namespace l::nodegraph { } bool NodeGraphBase::SetInput(int8_t inputChannel, std::string_view text) { - ASSERT(inputChannel >= 0 && static_cast(inputChannel) < mInputs.size()); + //ASSERT(inputChannel >= 0 && static_cast(inputChannel) < mInputs.size()); if (!IsValidInOutNum(inputChannel, mInputs.size())) { return false; } diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index afadaef9..608107c6 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -10,12 +10,10 @@ namespace l::nodegraph { void MathNumericalIntegral::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { - auto input0 = inputs.at(0).GetIterator(numSamples); + auto input0 = &inputs.at(0).Get(numSamples); auto friction = inputs.at(1).Get(); auto frictionFactor = l::math::clamp(l::math::pow(friction, 0.25f), 0.0f, 1.0f); - auto lodExp = inputs.at(2).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto output = outputs.at(0).GetIterator(numSamples, lodFactor); + auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { mOutput += *input0++; @@ -35,11 +33,9 @@ namespace l::nodegraph { } } - void MathNumericalDerivate::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { - auto input0 = inputs.at(0).GetIterator(numSamples); - auto lodExp = inputs.at(1).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto output = outputs.at(0).GetIterator(numSamples, lodFactor); + void MathNumericalTemporalChange::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + auto input0 = &inputs.at(0).Get(numSamples); + auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { float input = *input0++; @@ -61,10 +57,8 @@ namespace l::nodegraph { } void MathNumericalDiffNorm::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { - auto input0 = inputs.at(0).GetIterator(numSamples); - auto lodExp = inputs.at(1).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto output = outputs.at(0).GetIterator(numSamples, lodFactor); + auto input0 = &inputs.at(0).Get(numSamples); + auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { float input = *input0++; @@ -95,10 +89,8 @@ namespace l::nodegraph { } void MathNumericalDiff::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { - auto input0 = inputs.at(0).GetIterator(numSamples); - auto lodExp = inputs.at(1).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto output = outputs.at(0).GetIterator(numSamples, lodFactor); + auto input0 = &inputs.at(0).Get(numSamples); + auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { float input = *input0++; @@ -213,39 +205,40 @@ namespace l::nodegraph { auto frictionFactor1 = l::math::clamp(l::math::pow(friction1, 0.25f), 0.0f, 1.0f); auto frictionFactor2 = l::math::clamp(l::math::pow(friction2, 0.25f), 0.0f, 1.0f); - auto output1 = &outputs.at(0).Get(numSamples); - auto output2 = &outputs.at(1).Get(numSamples); - auto outputBase1 = &outputs.at(2).Get(numSamples); - auto outputBase2 = &outputs.at(3).Get(numSamples); + auto outputDiff = &outputs.at(0).Get(numSamples); + auto outputDiffBase = &outputs.at(1).Get(numSamples); + auto outputIntegral1 = &outputs.at(2).Get(numSamples); + auto outputBase1 = &outputs.at(3).Get(numSamples); + auto outputIntegral2 = &outputs.at(4).Get(numSamples); + auto outputBase2 = &outputs.at(5).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { float in = *inInput++; auto base = *baseInput++; - // derivate 1 - float diff1 = in - mInputPrev1; - mInputPrev1 = in; + // derivate + float diff = in - mInputPrev; + mInputPrev = in; // integral 1 - mOutput1 += diff1; + mOutput1 += diff; mOutput1 *= frictionFactor1; - auto output1Scaled = mOutput1 * scale1; - - // derivate 2 - float diff2 = output1Scaled - mInputPrev2; - mInputPrev2 = output1Scaled; - // integral 2 - mOutput2 += diff2; + mOutput2 += (diff + mDiffPrev) * 0.5f; mOutput2 *= frictionFactor2; - auto output2Scaled = mOutput2 * scale2; + mDiffPrev = diff; + + auto outputScaled1 = mOutput1 * scale1; + auto outputScaled2 = mOutput2 * scale2; - *output1++ = output1Scaled; - *output2++ = output2Scaled; - *outputBase1++ = output1Scaled + base; - *outputBase2++ = output2Scaled + base; + *outputDiff++ = diff; + *outputDiffBase++ = diff + base; + *outputIntegral1++ = mOutput1; + *outputBase1++ = outputScaled1 + base; + *outputIntegral2++ = mOutput2; + *outputBase2++ = outputScaled2 + base; } mReadSamples += numSamples; @@ -253,18 +246,14 @@ namespace l::nodegraph { if (mReadSamples >= numCacheSamples) { mReadSamples = 0; mOutput1 = 0.0f; - mOutput2 = 0.0f; - mInputPrev1 = 0.0f; - mInputPrev2 = 0.0f; + mInputPrev = 0.0f; + mDiffPrev = 0.0f; } if (isnan(mOutput1)) { mOutput1 = 0.0f; - mInputPrev1 = 0.0f; - } - if (isnan(mOutput2)) { - mOutput2 = 0.0f; - mInputPrev2 = 0.0f; + mInputPrev = 0.0f; + mDiffPrev = 0.0f; } } diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index 735b2c52..449a7615 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -167,4 +167,34 @@ namespace l::nodegraph { } } + /*********************************************************************/ + void GraphUIChartMarkers::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector&) { + auto timeInput = &inputs.at(0).Get(numSamples); + auto yInput = &inputs.at(1).Get(numSamples); + auto inInput = &inputs.at(3).Get(numSamples); + + if (mReadSamples == 0) { + mMarkers.clear(); + } + + for (int32_t i = 0; i < numSamples; i++) { + auto time = *timeInput++; + auto unixtime = l::math::algorithm::convert(time); + auto y = *yInput++; + auto in = *inInput++; + if (in != mPrevValue && in > 0.0f) { + mMarkers.push_back({ unixtime, y, in }); + } + else if (in != mPrevValue && in < 0.0f) { + mMarkers.push_back({ unixtime, y, in }); + } + mPrevValue = in; + } + + mReadSamples += numSamples; + if (mReadSamples >= numCacheSamples) { + mReadSamples = 0; + mPrevValue = 0.0f; + } + } } From f0818a141291ac3e070fca8119402471fca3396b Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 4 Aug 2025 14:18:55 +0200 Subject: [PATCH 043/179] Fix some bugs. --- .../include/nodegraph/operations/NodeGraphOpUI.h | 2 +- .../nodegraph/source/common/NodeGraphSchema.cpp | 2 +- .../source/common/operations/NodeGraphOpUI.cpp | 14 +++++++------- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index b105a56e..3c0e4167 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -143,7 +143,7 @@ namespace l::nodegraph { } virtual ~GraphUIChartMarkers() = default; virtual void DefaultDataInit() override { - mNode->SetInput(2, "Chart Markers"); + mNode->SetInput(3, "Chart Markers"); } virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; std::vector>& GetMarkers() { diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index abdc6b50..43155f88 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -499,7 +499,7 @@ namespace l::nodegraph { node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput); break; case 605: - node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput); + node = mMainNodeGraph.NewNode(id, NodeType::ExternalOutput); break; diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index 449a7615..18198440 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -171,7 +171,7 @@ namespace l::nodegraph { void GraphUIChartMarkers::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector&) { auto timeInput = &inputs.at(0).Get(numSamples); auto yInput = &inputs.at(1).Get(numSamples); - auto inInput = &inputs.at(3).Get(numSamples); + auto markerInput = &inputs.at(2).Get(numSamples); if (mReadSamples == 0) { mMarkers.clear(); @@ -181,14 +181,14 @@ namespace l::nodegraph { auto time = *timeInput++; auto unixtime = l::math::algorithm::convert(time); auto y = *yInput++; - auto in = *inInput++; - if (in != mPrevValue && in > 0.0f) { - mMarkers.push_back({ unixtime, y, in }); + auto marker = *markerInput++; + if (marker != mPrevValue && marker > 0.0f) { + mMarkers.push_back({ unixtime, y, marker }); } - else if (in != mPrevValue && in < 0.0f) { - mMarkers.push_back({ unixtime, y, in }); + else if (marker != mPrevValue && marker < 0.0f) { + mMarkers.push_back({ unixtime, y, marker }); } - mPrevValue = in; + mPrevValue = marker; } mReadSamples += numSamples; From 46551176d6d473b0f0518b41be0a9c4a9df7ff6a Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 4 Aug 2025 14:37:12 +0200 Subject: [PATCH 044/179] Fix error. --- .../nodegraph/source/common/operations/NodeGraphOpUI.cpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index 18198440..f2974a90 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -182,10 +182,14 @@ namespace l::nodegraph { auto unixtime = l::math::algorithm::convert(time); auto y = *yInput++; auto marker = *markerInput++; - if (marker != mPrevValue && marker > 0.0f) { + if (unixtime == 0) { + mPrevValue = marker; + continue; + } + if (marker > 0.0f && mPrevValue < 0.0f) { mMarkers.push_back({ unixtime, y, marker }); } - else if (marker != mPrevValue && marker < 0.0f) { + else if (marker < 0.0f && mPrevValue > 0.0f) { mMarkers.push_back({ unixtime, y, marker }); } mPrevValue = marker; From 0824e24eececa2490fac277bf6b4361d9f3a57c5 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 5 Aug 2025 01:00:28 +0200 Subject: [PATCH 045/179] Update cmake-multi-platform.yml --- .github/workflows/cmake-multi-platform.yml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index a3b32549..6227a281 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -28,6 +28,11 @@ jobs: working-directory: ${{github.workspace}}/build shell: bash run: ctest --rerun-failed --output-on-failure -C $BUILD_TYPE + - name: Checkout deps/ldeps + uses: actions/checkout@v4 + with: + repository: git@github.com:lnd3/ldeps.git + path: deps/ldeps linux: runs-on: ubuntu-latest steps: From 75f22e41441b3a77fbd4ea45d68f21fbcab7a6c0 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 5 Aug 2025 01:03:37 +0200 Subject: [PATCH 046/179] Change default build path for ldeps when building standalone. --- CMakeLists.txt | 2 +- packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 53776efa..218f1104 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ else() enable_testing() message("'ltools' expect 'ldeps' be present in 'deps/ldeps'") - add_subdirectory(deps/ldeps) + add_subdirectory(../deps/ldeps) include(bs) bs_init() diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index f2974a90..592faafb 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -186,10 +186,10 @@ namespace l::nodegraph { mPrevValue = marker; continue; } - if (marker > 0.0f && mPrevValue < 0.0f) { + if (marker > 0.0f && mPrevValue <= 0.0f) { mMarkers.push_back({ unixtime, y, marker }); } - else if (marker < 0.0f && mPrevValue > 0.0f) { + else if (marker < 0.0f && mPrevValue >= 0.0f) { mMarkers.push_back({ unixtime, y, marker }); } mPrevValue = marker; From 2f0382b0adff22194244c37d4795530242bcecd5 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 5 Aug 2025 01:08:26 +0200 Subject: [PATCH 047/179] Update cmake-multi-platform.yml --- .github/workflows/cmake-multi-platform.yml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index 6227a281..d2abefbb 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -14,6 +14,11 @@ jobs: uses: actions/checkout@v4 with: submodules: recursive + - name: Checkout deps/ldeps + uses: actions/checkout@v4 + with: + repository: git@github.com:lnd3/ldeps.git + path: deps/ldeps - name: Create Build Environment run: cmake -E make_directory ${{github.workspace}}/build - name: Configure CMake @@ -28,11 +33,6 @@ jobs: working-directory: ${{github.workspace}}/build shell: bash run: ctest --rerun-failed --output-on-failure -C $BUILD_TYPE - - name: Checkout deps/ldeps - uses: actions/checkout@v4 - with: - repository: git@github.com:lnd3/ldeps.git - path: deps/ldeps linux: runs-on: ubuntu-latest steps: From 809a2af4d405559f5459a307dec1cfc23bc04dfb Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 5 Aug 2025 01:10:18 +0200 Subject: [PATCH 048/179] Update cmake-multi-platform.yml --- .github/workflows/cmake-multi-platform.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index d2abefbb..10549bb9 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -17,7 +17,7 @@ jobs: - name: Checkout deps/ldeps uses: actions/checkout@v4 with: - repository: git@github.com:lnd3/ldeps.git + repository: lnd3/ldeps path: deps/ldeps - name: Create Build Environment run: cmake -E make_directory ${{github.workspace}}/build From 3edf2289db6c7c13ddb5f883fd647fd921d858b2 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 5 Aug 2025 01:10:46 +0200 Subject: [PATCH 049/179] Revert ldeps path. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 218f1104..53776efa 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -11,7 +11,7 @@ else() enable_testing() message("'ltools' expect 'ldeps' be present in 'deps/ldeps'") - add_subdirectory(../deps/ldeps) + add_subdirectory(deps/ldeps) include(bs) bs_init() From 4e54c4b3565b69f92f29452a423a428320692083 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 5 Aug 2025 01:12:51 +0200 Subject: [PATCH 050/179] Update cmake-multi-platform.yml --- .github/workflows/cmake-multi-platform.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index 10549bb9..a061a76f 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -19,6 +19,7 @@ jobs: with: repository: lnd3/ldeps path: deps/ldeps + submodules: recursive - name: Create Build Environment run: cmake -E make_directory ${{github.workspace}}/build - name: Configure CMake From 266d624d435013d56601eb084e2930da869851c0 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 5 Aug 2025 01:14:42 +0200 Subject: [PATCH 051/179] Update cmake-multi-platform.yml --- .github/workflows/cmake-multi-platform.yml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/.github/workflows/cmake-multi-platform.yml b/.github/workflows/cmake-multi-platform.yml index a061a76f..2421d184 100644 --- a/.github/workflows/cmake-multi-platform.yml +++ b/.github/workflows/cmake-multi-platform.yml @@ -41,6 +41,12 @@ jobs: uses: actions/checkout@v4 with: submodules: recursive + - name: Checkout deps/ldeps + uses: actions/checkout@v4 + with: + repository: lnd3/ldeps + path: deps/ldeps + submodules: recursive - name: Install Dependencies run: | sudo apt-get update From 02a61c7da52fc60ba592099667a139c614d88b2f Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 5 Aug 2025 02:47:31 +0200 Subject: [PATCH 052/179] Fix error. --- .../nodegraph/operations/NodeGraphOpMathAritmethic.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h index c34e1072..21156b0b 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h @@ -215,12 +215,10 @@ namespace l::nodegraph { virtual ~MathAritmethicMultiplyAndAdd() = default; void virtual Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = inputs.at(0).GetIterator(numSamples); - auto input1 = inputs.at(1).GetIterator(numSamples); - auto input2 = inputs.at(2).GetIterator(numSamples); - auto lodExp = inputs.at(3).Get(); - auto lodFactor = l::math::pow(2.0f, l::math::round(lodExp)); - auto output = outputs.at(0).GetIterator(numSamples, lodFactor); + auto input0 = &inputs.at(0).Get(numSamples); + auto input1 = &inputs.at(1).Get(numSamples); + auto input2 = &inputs.at(2).Get(numSamples); + auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { *output++ = *input0++ * *input1++ + *input2++; From 6390c5bff59040dfc5471b13ed126a9334c0dddf Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 5 Aug 2025 03:20:22 +0200 Subject: [PATCH 053/179] Add rolling sum for ui chart marker node. --- .../include/nodegraph/operations/NodeGraphOpUI.h | 6 ++++-- .../nodegraph/source/common/operations/NodeGraphOpUI.cpp | 8 ++++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index 3c0e4167..1c4a1ea6 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -146,13 +146,15 @@ namespace l::nodegraph { mNode->SetInput(3, "Chart Markers"); } virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; - std::vector>& GetMarkers() { + std::vector>& GetMarkers() { return mMarkers; } protected: int32_t mReadSamples = 0; float mPrevValue = 0.0f; - std::vector> mMarkers; + float mPrevY = 0.0f; + float mYSum = 0.0f; + std::vector> mMarkers; }; } diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index 592faafb..a9730ee6 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -187,10 +187,13 @@ namespace l::nodegraph { continue; } if (marker > 0.0f && mPrevValue <= 0.0f) { - mMarkers.push_back({ unixtime, y, marker }); + mMarkers.push_back({ unixtime, y, marker, mYSum }); + mPrevY = y; } else if (marker < 0.0f && mPrevValue >= 0.0f) { - mMarkers.push_back({ unixtime, y, marker }); + auto diff = y - mPrevY; + mYSum += diff; + mMarkers.push_back({ unixtime, y, marker, mYSum }); } mPrevValue = marker; } @@ -199,6 +202,7 @@ namespace l::nodegraph { if (mReadSamples >= numCacheSamples) { mReadSamples = 0; mPrevValue = 0.0f; + mYSum = 0.0f; } } } From 672142e50fea2ec9d2a93e8dfd4d75b750432a7f Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 5 Aug 2025 13:01:10 +0200 Subject: [PATCH 054/179] NG: Use to change factor in chart marker. --- .../include/nodegraph/operations/NodeGraphOpUI.h | 4 ++-- .../source/common/operations/NodeGraphOpUI.cpp | 11 ++++++----- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index 1c4a1ea6..af8d76a5 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -146,14 +146,14 @@ namespace l::nodegraph { mNode->SetInput(3, "Chart Markers"); } virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; - std::vector>& GetMarkers() { + const std::vector>& GetMarkers() { return mMarkers; } protected: int32_t mReadSamples = 0; float mPrevValue = 0.0f; float mPrevY = 0.0f; - float mYSum = 0.0f; + float mYTotalChange = 1.0f; std::vector> mMarkers; }; } diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index a9730ee6..d6b2c72c 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -187,13 +187,14 @@ namespace l::nodegraph { continue; } if (marker > 0.0f && mPrevValue <= 0.0f) { - mMarkers.push_back({ unixtime, y, marker, mYSum }); + mMarkers.push_back({ unixtime, y, marker, mYTotalChange }); mPrevY = y; } else if (marker < 0.0f && mPrevValue >= 0.0f) { - auto diff = y - mPrevY; - mYSum += diff; - mMarkers.push_back({ unixtime, y, marker, mYSum }); + if (mPrevY > 0.0f && y > 0.0f) { + mYTotalChange *= y / mPrevY; + } + mMarkers.push_back({ unixtime, y, marker, mYTotalChange }); } mPrevValue = marker; } @@ -202,7 +203,7 @@ namespace l::nodegraph { if (mReadSamples >= numCacheSamples) { mReadSamples = 0; mPrevValue = 0.0f; - mYSum = 0.0f; + mYTotalChange = 1.0f; } } } From 0fab51fd05bd26903516e02eb069f2ce59ca815b Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 5 Aug 2025 13:28:24 +0200 Subject: [PATCH 055/179] NG:Add beep for chart markers. --- .../include/nodegraph/operations/NodeGraphOpUI.h | 1 + .../nodegraph/source/common/operations/NodeGraphOpUI.cpp | 9 +++++++++ 2 files changed, 10 insertions(+) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index af8d76a5..ef08aff7 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -154,6 +154,7 @@ namespace l::nodegraph { float mPrevValue = 0.0f; float mPrevY = 0.0f; float mYTotalChange = 1.0f; + int32_t mLastBeep = l::string::get_unix_epoch(); std::vector> mMarkers; }; } diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index d6b2c72c..16ae380c 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -177,6 +177,13 @@ namespace l::nodegraph { mMarkers.clear(); } + auto beep = [&](int32_t unixtime, int32_t freq, int32_t duration) { + if (mLastBeep + 30 < unixtime) { + l::audio::PCBeep(freq, duration); + mLastBeep = unixtime; + } + }; + for (int32_t i = 0; i < numSamples; i++) { auto time = *timeInput++; auto unixtime = l::math::algorithm::convert(time); @@ -189,12 +196,14 @@ namespace l::nodegraph { if (marker > 0.0f && mPrevValue <= 0.0f) { mMarkers.push_back({ unixtime, y, marker, mYTotalChange }); mPrevY = y; + beep(unixtime, 1000, 50); } else if (marker < 0.0f && mPrevValue >= 0.0f) { if (mPrevY > 0.0f && y > 0.0f) { mYTotalChange *= y / mPrevY; } mMarkers.push_back({ unixtime, y, marker, mYTotalChange }); + beep(unixtime, 1000, 50); } mPrevValue = marker; } From 3e67adfdfb73094d8fab45f98bdcdfad5476ba0d Mon Sep 17 00:00:00 2001 From: lnd3 Date: Wed, 6 Aug 2025 10:07:46 +0200 Subject: [PATCH 056/179] NG: marker chart changes. --- .../nodegraph/operations/NodeGraphOpUI.h | 12 +++- .../common/operations/NodeGraphOpUI.cpp | 70 +++++++++++++++---- 2 files changed, 68 insertions(+), 14 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index ef08aff7..fb3f04f0 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -137,13 +137,14 @@ namespace l::nodegraph { NodeGraphOp(node, "Chart Markers") { AddInput2("Time"); - AddInput2("y"); + AddInput2("Open"); + AddInput2("Close"); AddInput2("Marker"); AddInput2("Name", 1, InputFlags(false, true, true, true)); } virtual ~GraphUIChartMarkers() = default; virtual void DefaultDataInit() override { - mNode->SetInput(3, "Chart Markers"); + mNode->SetInput(4, "Chart Markers"); } virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; const std::vector>& GetMarkers() { @@ -155,6 +156,13 @@ namespace l::nodegraph { float mPrevY = 0.0f; float mYTotalChange = 1.0f; int32_t mLastBeep = l::string::get_unix_epoch(); + float mProfitEma = 1.0f; + float mProfitMean = 1.0f; + float mStopEma = 1.0f; + float mStopMean = 1.0f; + bool mStopLossActive = false; + bool mOrderPlaced = false; + int32_t buySellCounter = 0; std::vector> mMarkers; }; } diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index 16ae380c..af31cf5b 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -170,8 +170,9 @@ namespace l::nodegraph { /*********************************************************************/ void GraphUIChartMarkers::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector&) { auto timeInput = &inputs.at(0).Get(numSamples); - auto yInput = &inputs.at(1).Get(numSamples); - auto markerInput = &inputs.at(2).Get(numSamples); + auto openInput = &inputs.at(1).Get(numSamples); + auto closeInput = &inputs.at(2).Get(numSamples); + auto eventInput = &inputs.at(3).Get(numSamples); if (mReadSamples == 0) { mMarkers.clear(); @@ -187,24 +188,69 @@ namespace l::nodegraph { for (int32_t i = 0; i < numSamples; i++) { auto time = *timeInput++; auto unixtime = l::math::algorithm::convert(time); - auto y = *yInput++; - auto marker = *markerInput++; + auto open = *openInput++; + auto close = *closeInput++; + auto marker = *eventInput++; if (unixtime == 0) { mPrevValue = marker; continue; } - if (marker > 0.0f && mPrevValue <= 0.0f) { - mMarkers.push_back({ unixtime, y, marker, mYTotalChange }); - mPrevY = y; - beep(unixtime, 1000, 50); + auto price = (open + close) * 0.5f; + auto currentMarkerChange = 1.0f; + if (mPrevY > 0.0f) { + currentMarkerChange = price / mPrevY; } - else if (marker < 0.0f && mPrevValue >= 0.0f) { - if (mPrevY > 0.0f && y > 0.0f) { - mYTotalChange *= y / mPrevY; + bool hitStopLoss = false; + if (mOrderPlaced) { + auto meanStop = 0.0f; + if (mProfitMean > 1.0f) { + auto meanStopFactor = 1.0f; + meanStop = 1.0f - meanStopFactor * (mProfitMean - 1.0f); + } + if (currentMarkerChange < meanStop) { + //hitStopLoss = true; + } + auto emaStop = 0.0f; + if (mProfitEma > 1.0f) { + auto emaStopFactor = 1.0f; + emaStop = 1.0f - emaStopFactor * (mProfitEma - 1.0f); + } + if (currentMarkerChange < emaStop) { + //hitStopLoss = true; + } + } + + auto buy = !mOrderPlaced && !mStopLossActive && (marker > 0.0f && mPrevValue <= 0.0f); + auto sell = mOrderPlaced && !mStopLossActive && (hitStopLoss || marker < 0.0f && mPrevValue >= 0.0f); + + if (buy) { + buySellCounter++; + mMarkers.push_back({ unixtime, price, marker, mYTotalChange }); + mOrderPlaced = true; + mPrevY = price; + beep(unixtime, 4000, 50); + } + else if (sell) { + buySellCounter--; + if (mPrevY > 0.0f && price > 0.0f) { + mYTotalChange *= currentMarkerChange; + mProfitEma = mProfitEma + 0.5f * (currentMarkerChange - mProfitEma); + if (mMarkers.size() > 1) { + mProfitMean = 1.0f + (mYTotalChange - 1.0f) / static_cast(mMarkers.size()); + } + } + mMarkers.push_back({ unixtime, price, marker, mYTotalChange }); + mOrderPlaced = false; + if (!mStopLossActive && hitStopLoss) { + // stop loss must not be active until this round and sell must not be + mStopLossActive = true; } - mMarkers.push_back({ unixtime, y, marker, mYTotalChange }); beep(unixtime, 1000, 50); } + else if (mStopLossActive && marker < 0.0f && mPrevValue >= 0.0f) { + // wait for actual sell signal so we can begin anew + mStopLossActive = false; + } mPrevValue = marker; } From ee8adc5930757a46101b51122ec8c4177416039e Mon Sep 17 00:00:00 2001 From: lnd3 Date: Wed, 6 Aug 2025 11:51:25 +0200 Subject: [PATCH 057/179] NG: Fix start condition. --- packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index af31cf5b..46ed5c79 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -259,6 +259,7 @@ namespace l::nodegraph { mReadSamples = 0; mPrevValue = 0.0f; mYTotalChange = 1.0f; + mOrderPlaced = false; } } } From 79906d92c8c59e9b184a9d8bd0984ffd0a8846c0 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 7 Aug 2025 19:32:38 +0200 Subject: [PATCH 058/179] Split up conditions and also fix unix build error. --- .../nodegraph/source/common/operations/NodeGraphOpUI.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index 46ed5c79..7c6a94d8 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -220,8 +220,10 @@ namespace l::nodegraph { } } - auto buy = !mOrderPlaced && !mStopLossActive && (marker > 0.0f && mPrevValue <= 0.0f); - auto sell = mOrderPlaced && !mStopLossActive && (hitStopLoss || marker < 0.0f && mPrevValue >= 0.0f); + auto buyCond = marker > 0.0f && mPrevValue <= 0.0f; + auto sellCond = marker < 0.0f && mPrevValue >= 0.0f; + auto buy = !mOrderPlaced && !mStopLossActive && buyCond; + auto sell = mOrderPlaced && !mStopLossActive && (hitStopLoss || sellCond); if (buy) { buySellCounter++; @@ -247,7 +249,7 @@ namespace l::nodegraph { } beep(unixtime, 1000, 50); } - else if (mStopLossActive && marker < 0.0f && mPrevValue >= 0.0f) { + else if (mStopLossActive && sellCond) { // wait for actual sell signal so we can begin anew mStopLossActive = false; } From db80e1aed838f790a77f9fb7a5cb42eb9c435e1d Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 7 Aug 2025 19:33:38 +0200 Subject: [PATCH 059/179] No need to check for nan if we reset every new round. --- .../source/common/operations/NodeGraphOpMathNumerical.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 608107c6..a1ed48ec 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -246,12 +246,7 @@ namespace l::nodegraph { if (mReadSamples >= numCacheSamples) { mReadSamples = 0; mOutput1 = 0.0f; - mInputPrev = 0.0f; - mDiffPrev = 0.0f; - } - - if (isnan(mOutput1)) { - mOutput1 = 0.0f; + mOutput2 = 0.0f; mInputPrev = 0.0f; mDiffPrev = 0.0f; } From 2df96ce7f2a0351c08846f5a13021cc8a305c127 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 10 Aug 2025 03:21:29 +0200 Subject: [PATCH 060/179] NG: Fix custom input to math nodes. Remove asserts on some string op. --- packages/logging/include/logging/String.h | 2 +- packages/logging/source/common/String.cpp | 15 ++++--- .../operations/NodeGraphOpMathAritmethic.h | 40 +++++++++---------- .../operations/NodeGraphOpMathNumerical.h | 9 +++-- .../nodegraph/operations/NodeGraphOpUI.h | 12 +++++- .../source/common/NodeGraphSchema.cpp | 2 +- .../operations/NodeGraphOpMathNumerical.cpp | 30 +++++++++----- .../common/operations/NodeGraphOpUI.cpp | 34 +++++++++------- 8 files changed, 86 insertions(+), 58 deletions(-) diff --git a/packages/logging/include/logging/String.h b/packages/logging/include/logging/String.h index d2724a3d..0d0e742a 100644 --- a/packages/logging/include/logging/String.h +++ b/packages/logging/include/logging/String.h @@ -177,7 +177,7 @@ namespace l::string { template void get_local_date_and_time(string_buffer& buf, const int32_t unixtime, bool fullYear = false) { struct std::tm tminfo = {}; - convert_to_local_tm_from_utc_time(unixtime, &tminfo, false); + convert_to_local_tm_from_utc_time(unixtime, &tminfo, true); if (fullYear) { buf.printf("%4d-%2d-%2d %2d:%2d:%2d", tminfo.tm_year, tminfo.tm_mon + 1, tminfo.tm_mday, tminfo.tm_hour, tminfo.tm_min, tminfo.tm_sec); } diff --git a/packages/logging/source/common/String.cpp b/packages/logging/source/common/String.cpp index d7a2229e..7cd414a7 100644 --- a/packages/logging/source/common/String.cpp +++ b/packages/logging/source/common/String.cpp @@ -49,8 +49,9 @@ namespace l::string { init_timezone(); #ifdef WIN32 long time; - auto res = _get_timezone(&time); - ASSERT(res == 0); + //auto res = + _get_timezone(&time); + //ASSERT(res == 0); #else auto time = timezone; #endif @@ -61,8 +62,9 @@ namespace l::string { init_timezone(); #ifdef WIN32 int time; - auto res = _get_daylight(&time); - ASSERT(res == 0); + //auto res = + _get_daylight(&time); + //ASSERT(res == 0); #else auto time = daylight; #endif @@ -99,8 +101,9 @@ namespace l::string { void convert_to_tm(const time_t time, tm* timeinfo, bool adjustYearAndMonth) { #ifdef WIN32 - auto res = _gmtime64_s(timeinfo, &time); - ASSERT(res == 0); + //auto res = + _gmtime64_s(timeinfo, &time); + //ASSERT(res == 0); #else tm* ti = gmtime(&time); *timeinfo = *ti; diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h index 21156b0b..fca23f03 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h @@ -35,8 +35,8 @@ namespace l::nodegraph { } virtual ~MathAritmethicAdd() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = &inputs.at(0).Get(numSamples); - auto input1 = &inputs.at(1).Get(numSamples); + auto input0 = inputs.at(0).GetIterator(numSamples); + auto input1 = inputs.at(1).GetIterator(numSamples); auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { @@ -58,8 +58,8 @@ namespace l::nodegraph { virtual ~MathAritmethicMultiply() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = &inputs.at(0).Get(numSamples); - auto input1 = &inputs.at(1).Get(numSamples); + auto input0 = inputs.at(0).GetIterator(numSamples); + auto input1 = inputs.at(1).GetIterator(numSamples); auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { @@ -81,8 +81,8 @@ namespace l::nodegraph { } virtual ~MathAritmethicSubtract() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = &inputs.at(0).Get(numSamples); - auto input1 = &inputs.at(1).Get(numSamples); + auto input0 = inputs.at(0).GetIterator(numSamples); + auto input1 = inputs.at(1).GetIterator(numSamples); auto output1 = &outputs.at(0).Get(numSamples); auto output2 = &outputs.at(1).Get(numSamples); @@ -106,7 +106,7 @@ namespace l::nodegraph { virtual ~MathAritmethicNegate() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = &inputs.at(0).Get(numSamples); + auto input0 = inputs.at(0).GetIterator(numSamples); auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { @@ -130,7 +130,7 @@ namespace l::nodegraph { virtual ~MathAritmethicAbs() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = &inputs.at(0).Get(numSamples); + auto input0 = inputs.at(0).GetIterator(numSamples); auto output1 = &outputs.at(0).Get(numSamples); auto output2 = &outputs.at(1).Get(numSamples); auto output3 = &outputs.at(2).Get(numSamples); @@ -158,7 +158,7 @@ namespace l::nodegraph { virtual ~MathAritmethicLog() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = &inputs.at(0).Get(numSamples); + auto input0 = inputs.at(0).GetIterator(numSamples); auto base = inputs.at(1).Get(); auto output1 = &outputs.at(0).Get(numSamples); auto output2 = &outputs.at(1).Get(numSamples); @@ -190,9 +190,9 @@ namespace l::nodegraph { virtual ~MathAritmethicMultiply3() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = &inputs.at(0).Get(numSamples); - auto input1 = &inputs.at(1).Get(numSamples); - auto input2 = &inputs.at(2).Get(numSamples); + auto input0 = inputs.at(0).GetIterator(numSamples); + auto input1 = inputs.at(1).GetIterator(numSamples); + auto input2 = inputs.at(2).GetIterator(numSamples); auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { @@ -215,9 +215,9 @@ namespace l::nodegraph { virtual ~MathAritmethicMultiplyAndAdd() = default; void virtual Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = &inputs.at(0).Get(numSamples); - auto input1 = &inputs.at(1).Get(numSamples); - auto input2 = &inputs.at(2).Get(numSamples); + auto input0 = inputs.at(0).GetIterator(numSamples); + auto input1 = inputs.at(1).GetIterator(numSamples); + auto input2 = inputs.at(2).GetIterator(numSamples); auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { @@ -240,7 +240,7 @@ namespace l::nodegraph { virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { outputs.at(0).mOutput = l::math::round(inputs.at(0).Get()); - auto input0 = &inputs.at(0).Get(numSamples); + auto input0 = inputs.at(0).GetIterator(numSamples); auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { @@ -262,7 +262,7 @@ namespace l::nodegraph { virtual ~MathAritmethicPow() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = &inputs.at(0).Get(numSamples); + auto input0 = inputs.at(0).GetIterator(numSamples); auto exponent = inputs.at(2).Get(); auto output1 = &outputs.at(0).Get(numSamples); @@ -287,9 +287,9 @@ namespace l::nodegraph { } virtual ~MathAritmethicSum3() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input0 = &inputs.at(0).Get(numSamples); - auto input1 = &inputs.at(1).Get(numSamples); - auto input2 = &inputs.at(2).Get(numSamples); + auto input0 = inputs.at(0).GetIterator(numSamples); + auto input1 = inputs.at(1).GetIterator(numSamples); + auto input2 = inputs.at(2).GetIterator(numSamples); auto output = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 0a358c31..c82ef7b1 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -130,11 +130,12 @@ namespace l::nodegraph { AddInput2("Upper Bound"); AddInput2("Lower Bound"); AddInput2("Bounded Value"); + AddInput("Friction", 1.0f, 1, 0.0f, 1.0f); AddOutput2("Range"); AddOutput2("Range Max"); AddOutput2("Range Min"); - AddOutput2("Value Norm"); + AddOutput2("Range Norm"); } virtual ~MathNumericalMinMaxChannel() = default; @@ -147,9 +148,9 @@ namespace l::nodegraph { }; /*********************************************************************/ - class MathNumericalDerivate2 : public NodeGraphOp { + class MathNumericalReconstructor : public NodeGraphOp { public: - MathNumericalDerivate2(NodeGraphBase* node) : + MathNumericalReconstructor(NodeGraphBase* node) : NodeGraphOp(node, "Reconstructor") { AddInput2("In"); @@ -167,7 +168,7 @@ namespace l::nodegraph { AddOutput2("Intgr2+base"); } - virtual ~MathNumericalDerivate2() = default; + virtual ~MathNumericalReconstructor() = default; virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; protected: int32_t mReadSamples = 0; diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index fb3f04f0..2fe8e4ee 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -99,6 +99,7 @@ namespace l::nodegraph { } virtual ~GraphUIChartLine() = default; virtual void DefaultDataInit() override { + NodeGraphOp::DefaultDataInit(); mNode->SetInput(2, "Chart Line"); } virtual void ProcessWriteCached(int32_t writtenSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; @@ -123,6 +124,7 @@ namespace l::nodegraph { } virtual ~GraphUICandleSticks() = default; virtual void DefaultDataInit() override { + NodeGraphOp::DefaultDataInit(); mNode->SetInput(6, "Candle Sticks"); } void ProcessWriteCached(int32_t writtenSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; @@ -139,12 +141,18 @@ namespace l::nodegraph { AddInput2("Time"); AddInput2("Open"); AddInput2("Close"); - AddInput2("Marker"); + AddInput2("Mark"); // positive or negative + AddInput("Risk", 0.5f, 1, 0.0f, 1.0f); + AddInput("Slip", 0.0002f, 1, 0.0f, 1.0f); AddInput2("Name", 1, InputFlags(false, true, true, true)); + AddInput("Pin Length", 30.0f, 1, 1.0f, 200.0f); + AddInput("Pin Size", 5.0f, 1, 1.0f, 40.0f); + AddInput("Font Size", 10.8f, 1, 3.0f, 20.0f); } virtual ~GraphUIChartMarkers() = default; virtual void DefaultDataInit() override { - mNode->SetInput(4, "Chart Markers"); + NodeGraphOp::DefaultDataInit(); + mNode->SetInput(6, "Chart Markers"); } virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; const std::vector>& GetMarkers() { diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 43155f88..da2823e8 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -313,7 +313,7 @@ namespace l::nodegraph { node = mMainNodeGraph.NewNode(id, NodeType::Default); break; case 146: - node = mMainNodeGraph.NewNode(id, NodeType::Default); + node = mMainNodeGraph.NewNode(id, NodeType::Default); break; // Trading data io diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index a1ed48ec..bfb312cd 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -109,8 +109,8 @@ namespace l::nodegraph { void MathNumericalLevelTrigger::Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) { auto inInput = &inputs.at(0).Get(numSamples); - auto maxInput = &inputs.at(1).Get(); - auto minInput = &inputs.at(2).Get(); + auto maxInput = inputs.at(1).GetIterator(numSamples); + auto minInput = inputs.at(2).GetIterator(numSamples); auto numLevels = l::math::clamp(inputs.at(3).Get(), 1.0f, 10.0f); auto max = l::math::clamp(inputs.at(4).Get(), 0.0f, 1.0f); auto min = l::math::clamp(inputs.at(5).Get(), 0.0f, max); @@ -150,13 +150,14 @@ namespace l::nodegraph { void MathNumericalMinMaxChannel::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto inInput = &inputs.at(0).Get(numSamples); - auto upperInput = &inputs.at(1).Get(); - auto lowerInput = &inputs.at(2).Get(); + auto upperInput = inputs.at(1).GetIterator(numSamples); + auto lowerInput = inputs.at(2).GetIterator(numSamples); + auto friction = inputs.at(3).Get(); auto rangeOutput = &outputs.at(0).Get(numSamples); auto rangeMaxOutput = &outputs.at(1).Get(numSamples); auto rangeMinOutput = &outputs.at(2).Get(numSamples); - auto valueNormOutput = &outputs.at(3).Get(numSamples); + auto rangeNormOutput = &outputs.at(3).Get(numSamples); if (mReadSamples == 0) { mCurRangeMax = -100000000000000.0f; @@ -169,7 +170,7 @@ namespace l::nodegraph { float lower = *lowerInput++; lower = lower > in ? in - 0.0000001f : lower; - upper = upper < in ? in + 0.0000001f : lower; + upper = upper < in ? in + 0.0000001f : upper; auto range = upper - lower; if (mCurRangeMax < range) { @@ -179,10 +180,21 @@ namespace l::nodegraph { mCurRangeMin = range; } + mCurRangeMax += friction * (range - mCurRangeMax); + mCurRangeMin += friction * (range - mCurRangeMin); + + *rangeOutput++ = range; *rangeMaxOutput++ = mCurRangeMax; *rangeMinOutput++ = mCurRangeMin; - *valueNormOutput++ = (in - lower) / range; + + auto rangeDiff = mCurRangeMax - mCurRangeMin; + auto rangeNorm = 0.5f; + if (rangeDiff > 0.0f) { + rangeNorm = (range - mCurRangeMin) / rangeDiff; + } + + *rangeNormOutput++ = rangeNorm; } mReadSamples += numSamples; @@ -192,10 +204,10 @@ namespace l::nodegraph { } } - void MathNumericalDerivate2::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + void MathNumericalReconstructor::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto inInput = &inputs.at(0).Get(numSamples); - auto baseInput = &inputs.at(1).Get(numSamples); + auto baseInput = inputs.at(1).GetIterator(); auto friction1 = inputs.at(2).Get(); auto friction2 = inputs.at(3).Get(); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index 7c6a94d8..2171cc74 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -172,14 +172,16 @@ namespace l::nodegraph { auto timeInput = &inputs.at(0).Get(numSamples); auto openInput = &inputs.at(1).Get(numSamples); auto closeInput = &inputs.at(2).Get(numSamples); - auto eventInput = &inputs.at(3).Get(numSamples); + auto markInput = &inputs.at(3).Get(numSamples); + auto meanRisk = inputs.at(4).Get(); + auto slip = inputs.at(5).Get(); if (mReadSamples == 0) { mMarkers.clear(); } auto beep = [&](int32_t unixtime, int32_t freq, int32_t duration) { - if (mLastBeep + 30 < unixtime) { + if (mLastBeep + 5 < unixtime) { l::audio::PCBeep(freq, duration); mLastBeep = unixtime; } @@ -190,9 +192,10 @@ namespace l::nodegraph { auto unixtime = l::math::algorithm::convert(time); auto open = *openInput++; auto close = *closeInput++; - auto marker = *eventInput++; + auto mark = *markInput++; + if (unixtime == 0) { - mPrevValue = marker; + mPrevValue = mark; continue; } auto price = (open + close) * 0.5f; @@ -204,15 +207,15 @@ namespace l::nodegraph { if (mOrderPlaced) { auto meanStop = 0.0f; if (mProfitMean > 1.0f) { - auto meanStopFactor = 1.0f; + auto meanStopFactor = meanRisk; meanStop = 1.0f - meanStopFactor * (mProfitMean - 1.0f); } if (currentMarkerChange < meanStop) { - //hitStopLoss = true; + hitStopLoss = true; } auto emaStop = 0.0f; if (mProfitEma > 1.0f) { - auto emaStopFactor = 1.0f; + auto emaStopFactor = meanRisk; emaStop = 1.0f - emaStopFactor * (mProfitEma - 1.0f); } if (currentMarkerChange < emaStop) { @@ -220,14 +223,14 @@ namespace l::nodegraph { } } - auto buyCond = marker > 0.0f && mPrevValue <= 0.0f; - auto sellCond = marker < 0.0f && mPrevValue >= 0.0f; + auto buyCond = mark > 0.0f && mPrevValue <= 0.0f; + auto sellCond = mark < 0.0f && mPrevValue >= 0.0f; auto buy = !mOrderPlaced && !mStopLossActive && buyCond; auto sell = mOrderPlaced && !mStopLossActive && (hitStopLoss || sellCond); if (buy) { buySellCounter++; - mMarkers.push_back({ unixtime, price, marker, mYTotalChange }); + mMarkers.push_back({ unixtime, price, mark, mYTotalChange }); mOrderPlaced = true; mPrevY = price; beep(unixtime, 4000, 50); @@ -235,25 +238,26 @@ namespace l::nodegraph { else if (sell) { buySellCounter--; if (mPrevY > 0.0f && price > 0.0f) { - mYTotalChange *= currentMarkerChange; - mProfitEma = mProfitEma + 0.5f * (currentMarkerChange - mProfitEma); + auto profit = currentMarkerChange * (1.0f - slip); + mYTotalChange *= profit; + mProfitEma = mProfitEma + 0.5f * (profit - mProfitEma); if (mMarkers.size() > 1) { mProfitMean = 1.0f + (mYTotalChange - 1.0f) / static_cast(mMarkers.size()); } } - mMarkers.push_back({ unixtime, price, marker, mYTotalChange }); + mMarkers.push_back({ unixtime, price, mark, mYTotalChange }); mOrderPlaced = false; if (!mStopLossActive && hitStopLoss) { // stop loss must not be active until this round and sell must not be mStopLossActive = true; } - beep(unixtime, 1000, 50); + beep(unixtime, 500, 50); } else if (mStopLossActive && sellCond) { // wait for actual sell signal so we can begin anew mStopLossActive = false; } - mPrevValue = marker; + mPrevValue = mark; } mReadSamples += numSamples; From 17bbe7618e2bd3529a025a55e819321a2a21fbba Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 12 Aug 2025 12:30:53 +0200 Subject: [PATCH 061/179] Simplify order node. --- .../include/nodegraph/core/NodeGraphBase.h | 2 +- .../nodegraph/operations/NodeGraphOpUI.h | 5 ++ .../common/operations/NodeGraphOpUI.cpp | 79 +++++++------------ 3 files changed, 35 insertions(+), 51 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h index 1409a84d..6e48f21b 100644 --- a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h @@ -287,7 +287,7 @@ namespace l::nodegraph { void InputHasChanged() override { mInputHasChanged = true; - mWrittenSamples = 0; + //mWrittenSamples = 0; } protected: diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index 2fe8e4ee..b0950dda 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -19,6 +19,7 @@ #include #include #include +#include namespace l::nodegraph { @@ -148,6 +149,8 @@ namespace l::nodegraph { AddInput("Pin Length", 30.0f, 1, 1.0f, 200.0f); AddInput("Pin Size", 5.0f, 1, 1.0f, 40.0f); AddInput("Font Size", 10.8f, 1, 3.0f, 20.0f); + AddInput("Buy confirm", 0.1f, 1, 0.0f, 1.0f); + AddInput("Sell confirm", 0.1f, 1, 0.0f, 1.0f); } virtual ~GraphUIChartMarkers() = default; virtual void DefaultDataInit() override { @@ -171,6 +174,8 @@ namespace l::nodegraph { bool mStopLossActive = false; bool mOrderPlaced = false; int32_t buySellCounter = 0; + int32_t mBuyConfirmTime = 0; + int32_t mSellConfirmTime = 0; std::vector> mMarkers; }; } diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index 2171cc74..3a15efd1 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -173,11 +173,15 @@ namespace l::nodegraph { auto openInput = &inputs.at(1).Get(numSamples); auto closeInput = &inputs.at(2).Get(numSamples); auto markInput = &inputs.at(3).Get(numSamples); - auto meanRisk = inputs.at(4).Get(); + //auto meanRisk = inputs.at(4).Get(); auto slip = inputs.at(5).Get(); + //auto buyConfirm = inputs.at(10).Get(); + //auto sellConfirm = inputs.at(11).Get(); if (mReadSamples == 0) { + buySellCounter = 0; mMarkers.clear(); + //mMarkers.reserve(100); } auto beep = [&](int32_t unixtime, int32_t freq, int32_t duration) { @@ -198,64 +202,39 @@ namespace l::nodegraph { mPrevValue = mark; continue; } - auto price = (open + close) * 0.5f; - auto currentMarkerChange = 1.0f; - if (mPrevY > 0.0f) { - currentMarkerChange = price / mPrevY; - } - bool hitStopLoss = false; - if (mOrderPlaced) { - auto meanStop = 0.0f; - if (mProfitMean > 1.0f) { - auto meanStopFactor = meanRisk; - meanStop = 1.0f - meanStopFactor * (mProfitMean - 1.0f); - } - if (currentMarkerChange < meanStop) { - hitStopLoss = true; - } - auto emaStop = 0.0f; - if (mProfitEma > 1.0f) { - auto emaStopFactor = meanRisk; - emaStop = 1.0f - emaStopFactor * (mProfitEma - 1.0f); - } - if (currentMarkerChange < emaStop) { - //hitStopLoss = true; - } - } - auto buyCond = mark > 0.0f && mPrevValue <= 0.0f; - auto sellCond = mark < 0.0f && mPrevValue >= 0.0f; - auto buy = !mOrderPlaced && !mStopLossActive && buyCond; - auto sell = mOrderPlaced && !mStopLossActive && (hitStopLoss || sellCond); + auto buyCond = mark > 0.0f && mPrevValue < 0.0f; + auto sellCond = mark < 0.0f && mPrevValue > 0.0f; + auto buy = !mOrderPlaced && buyCond; + auto sell = mOrderPlaced && sellCond; + + // recalculate price based on progress at crossing zero + auto progress = 0.0f; + if (buy || sell) { + progress = -mPrevValue / (mark - mPrevValue); + ASSERT(progress >= 0.0f && progress <= 1.0f); + } + auto price2 = open + progress * (close - open); if (buy) { buySellCounter++; - mMarkers.push_back({ unixtime, price, mark, mYTotalChange }); + ASSERT(buySellCounter <= 1); + auto s = std::make_tuple(unixtime, price2, mark, mYTotalChange); + mMarkers.push_back(std::move(s)); mOrderPlaced = true; - mPrevY = price; - beep(unixtime, 4000, 50); + mPrevY = price2; + //beep(unixtime, 4000, 50); } else if (sell) { buySellCounter--; - if (mPrevY > 0.0f && price > 0.0f) { - auto profit = currentMarkerChange * (1.0f - slip); - mYTotalChange *= profit; - mProfitEma = mProfitEma + 0.5f * (profit - mProfitEma); - if (mMarkers.size() > 1) { - mProfitMean = 1.0f + (mYTotalChange - 1.0f) / static_cast(mMarkers.size()); - } - } - mMarkers.push_back({ unixtime, price, mark, mYTotalChange }); + ASSERT(buySellCounter >= 0); + auto change = price2 / mPrevY; + auto profit = change * (1.0f - slip); + mYTotalChange *= profit; + auto s = std::make_tuple(unixtime, price2, mark, mYTotalChange); + mMarkers.push_back(std::move(s)); mOrderPlaced = false; - if (!mStopLossActive && hitStopLoss) { - // stop loss must not be active until this round and sell must not be - mStopLossActive = true; - } - beep(unixtime, 500, 50); - } - else if (mStopLossActive && sellCond) { - // wait for actual sell signal so we can begin anew - mStopLossActive = false; + //beep(unixtime, 500, 50); } mPrevValue = mark; } From f4b620cb19f282c52e4966635eafba89ba5882b0 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Wed, 13 Aug 2025 13:47:00 +0200 Subject: [PATCH 062/179] Fix bad default values. --- packages/nodegraph/include/nodegraph/core/NodeGraphBase.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h index 6e48f21b..ad22eba2 100644 --- a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h @@ -244,8 +244,8 @@ namespace l::nodegraph { virtual int32_t AddInput(std::string_view name, float defaultValue = 0.0f, int32_t minSize = 1, float boundMin = -l::math::constants::FLTMAX, float boundMax = l::math::constants::FLTMAX, bool visible = true, bool editable = true); virtual int32_t AddOutput(std::string_view name, float defaultValue = 0.0f, int32_t minSize = 1, bool visible = true); virtual int32_t AddConstant(std::string_view name, float defaultValue = 0.0f, int32_t minSize = 1, float boundMin = -l::math::constants::FLTMAX, float boundMax = l::math::constants::FLTMAX, bool visible = true, bool editable = true); - virtual int32_t AddInput2(std::string_view name, int32_t minSize = 2, InputFlags flags = InputFlags(false, false, false, false)); - virtual int32_t AddOutput2(std::string_view name, int32_t minSize = 2, OutputFlags flags = OutputFlags(false, false)); + virtual int32_t AddInput2(std::string_view name, int32_t minSize = 1, InputFlags flags = InputFlags(false, false, false, false)); + virtual int32_t AddOutput2(std::string_view name, int32_t minSize = 1, OutputFlags flags = OutputFlags(false, false)); NodeGraphBase* mNode = nullptr; std::string mName; From da693dd86854f77c061e94656b58b2383c64f049 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 14 Aug 2025 11:50:58 +0200 Subject: [PATCH 063/179] Remove unused code. --- packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index 3a15efd1..3948827c 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -184,6 +184,7 @@ namespace l::nodegraph { //mMarkers.reserve(100); } + /* auto beep = [&](int32_t unixtime, int32_t freq, int32_t duration) { if (mLastBeep + 5 < unixtime) { l::audio::PCBeep(freq, duration); @@ -191,6 +192,8 @@ namespace l::nodegraph { } }; + */ + for (int32_t i = 0; i < numSamples; i++) { auto time = *timeInput++; auto unixtime = l::math::algorithm::convert(time); From 67f295d35007b24af5a9fe059a2d600a0e6c0ccc Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 16 Aug 2025 17:57:24 +0200 Subject: [PATCH 064/179] NG: marker ui node and simple trade tracking. --- .../nodegraph/operations/NodeGraphOpUI.h | 92 ++++++++++++++---- .../common/operations/NodeGraphOpUI.cpp | 95 +++++++++---------- 2 files changed, 121 insertions(+), 66 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index b0950dda..03007806 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -134,6 +134,71 @@ namespace l::nodegraph { }; /*********************************************************************/ + struct TradePosition { + float mEntry = 0.0f; + float mExit = 0.0f; + float mLotShare = 1.0f; + int32_t mEntryTime = 0; + int32_t mExitTime = 0; + + void Reset(float lotShare = 1.0f) { + mLotShare = lotShare; + mEntry = 0.0f; + mExit = 0.0f; + mEntryTime = 0; + mExitTime = 0; + } + + bool IsReady() { + return mEntryTime == 0 && mExitTime == 0 && mEntry == 0.0f && mExit == 0.0f; + } + + bool HasPosition() { + return mEntryTime > 0 && mExitTime == 0 && mEntry > 0.0f && mExit == 0.0f; + } + + bool HasEntry() { + return mEntryTime > 0 && mEntry > 0.0f; + } + + bool HasExit() { + return mExitTime > 0 && mExit > 0.0f; + } + + bool HasCompleted() { + return mEntryTime > 0 && mExitTime > 0 && mEntry > 0.0f && mExit > 0.0f; + } + + bool TradeEntered(int32_t time) { + return time > 0 && time == mEntryTime && mEntry > 0.0f; + } + + bool TradeExited(int32_t time) { + return time > 0 && time == mExitTime && mExit > 0.0f; + } + + float GetProfit(float slip) { + if (mEntry > 0.0f && mExit > 0.0f) { + auto change = mExit / mEntry; + change = change * (1.0f - slip); + change = 1.0f + (change - 1.0f) * mLotShare; + return change; + } + return 1.0f; + } + + void Update(float state, float price, int32_t time) { + if (time > 0 && mEntryTime == 0 && state > 0.0f) { + mEntry = price; + mEntryTime = time; + } + if (time > 0 && mEntryTime > 0 && mEntryTime < time && mExitTime == 0 && state < 0.0f) { + mExit = price; + mExitTime = time; + } + } + }; + class GraphUIChartMarkers : public NodeGraphOp { public: GraphUIChartMarkers(NodeGraphBase* node) : @@ -142,15 +207,15 @@ namespace l::nodegraph { AddInput2("Time"); AddInput2("Open"); AddInput2("Close"); - AddInput2("Mark"); // positive or negative - AddInput("Risk", 0.5f, 1, 0.0f, 1.0f); + AddInput2("Entry 1"); + AddInput2("Entry 2"); AddInput("Slip", 0.0002f, 1, 0.0f, 1.0f); AddInput2("Name", 1, InputFlags(false, true, true, true)); AddInput("Pin Length", 30.0f, 1, 1.0f, 200.0f); AddInput("Pin Size", 5.0f, 1, 1.0f, 40.0f); AddInput("Font Size", 10.8f, 1, 3.0f, 20.0f); - AddInput("Buy confirm", 0.1f, 1, 0.0f, 1.0f); - AddInput("Sell confirm", 0.1f, 1, 0.0f, 1.0f); + AddInput("Main Size", 0.5f, 1, 0.0f, 1.0f); + AddInput2("Entry 3"); } virtual ~GraphUIChartMarkers() = default; virtual void DefaultDataInit() override { @@ -163,19 +228,12 @@ namespace l::nodegraph { } protected: int32_t mReadSamples = 0; - float mPrevValue = 0.0f; - float mPrevY = 0.0f; - float mYTotalChange = 1.0f; - int32_t mLastBeep = l::string::get_unix_epoch(); - float mProfitEma = 1.0f; - float mProfitMean = 1.0f; - float mStopEma = 1.0f; - float mStopMean = 1.0f; - bool mStopLossActive = false; - bool mOrderPlaced = false; - int32_t buySellCounter = 0; - int32_t mBuyConfirmTime = 0; - int32_t mSellConfirmTime = 0; + float mTotalProfit = 1.0f; + + TradePosition mEntry1; + TradePosition mEntry2; + TradePosition mEntry3; + std::vector> mMarkers; }; } diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index 3948827c..4aef2749 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -172,82 +172,79 @@ namespace l::nodegraph { auto timeInput = &inputs.at(0).Get(numSamples); auto openInput = &inputs.at(1).Get(numSamples); auto closeInput = &inputs.at(2).Get(numSamples); - auto markInput = &inputs.at(3).Get(numSamples); - //auto meanRisk = inputs.at(4).Get(); + auto entry1Input = &inputs.at(3).Get(numSamples); + auto entry2Input = &inputs.at(4).Get(numSamples); auto slip = inputs.at(5).Get(); - //auto buyConfirm = inputs.at(10).Get(); - //auto sellConfirm = inputs.at(11).Get(); + //auto mainSize = inputs.at(10).Get(); + auto entry3Input = &inputs.at(11).Get(numSamples); + + auto entry1Active = inputs.at(3).HasInputNode(); + auto entry2Active = inputs.at(4).HasInputNode(); + auto entry3Active = inputs.at(11).HasInputNode(); + auto entryShare = (entry1Active && entry2Active && entry3Active) ? 0.3333f : (entry1Active && entry2Active || entry1Active && entry3Active || entry2Active || entry3Active) ? 0.5f : 1.0f; if (mReadSamples == 0) { - buySellCounter = 0; mMarkers.clear(); - //mMarkers.reserve(100); + mEntry1.Reset(entry1Active ? entryShare : 0.0f); + mEntry2.Reset(entry2Active ? entryShare : 0.0f); + mEntry3.Reset(entry3Active ? entryShare : 0.0f); } - /* - auto beep = [&](int32_t unixtime, int32_t freq, int32_t duration) { - if (mLastBeep + 5 < unixtime) { - l::audio::PCBeep(freq, duration); - mLastBeep = unixtime; - } - }; - - */ - for (int32_t i = 0; i < numSamples; i++) { auto time = *timeInput++; auto unixtime = l::math::algorithm::convert(time); auto open = *openInput++; auto close = *closeInput++; - auto mark = *markInput++; + auto entry1 = *entry1Input++; + auto entry2 = *entry2Input++; + auto entry3 = *entry3Input++; if (unixtime == 0) { - mPrevValue = mark; continue; } - auto buyCond = mark > 0.0f && mPrevValue < 0.0f; - auto sellCond = mark < 0.0f && mPrevValue > 0.0f; - auto buy = !mOrderPlaced && buyCond; - auto sell = mOrderPlaced && sellCond; + auto estimatedPrice = (open + close) * 0.5f; - // recalculate price based on progress at crossing zero - auto progress = 0.0f; - if (buy || sell) { - progress = -mPrevValue / (mark - mPrevValue); - ASSERT(progress >= 0.0f && progress <= 1.0f); - } - auto price2 = open + progress * (close - open); + mEntry1.Update(entry1, estimatedPrice, unixtime); + mEntry2.Update(entry2, estimatedPrice, unixtime); + mEntry3.Update(entry3, estimatedPrice, unixtime); - if (buy) { - buySellCounter++; - ASSERT(buySellCounter <= 1); - auto s = std::make_tuple(unixtime, price2, mark, mYTotalChange); + if (mEntry1.TradeEntered(unixtime)) { + auto s = std::make_tuple(unixtime, estimatedPrice, 1.0f, mTotalProfit); + mMarkers.push_back(std::move(s)); + } + if (mEntry2.TradeEntered(unixtime)) { + auto s = std::make_tuple(unixtime, estimatedPrice, 1.0f, mTotalProfit); + mMarkers.push_back(std::move(s)); + } + if (mEntry3.TradeEntered(unixtime)) { + auto s = std::make_tuple(unixtime, estimatedPrice, 1.0f, mTotalProfit); + mMarkers.push_back(std::move(s)); + } + if (mEntry1.TradeExited(unixtime)) { + mTotalProfit *= mEntry1.GetProfit(slip); + auto s = std::make_tuple(unixtime, estimatedPrice, -1.0f, mTotalProfit); + mMarkers.push_back(std::move(s)); + mEntry1.Reset(entry1Active ? entryShare : 0.0f); + } + if (mEntry2.TradeExited(unixtime)) { + mTotalProfit *= mEntry2.GetProfit(slip); + auto s = std::make_tuple(unixtime, estimatedPrice, -1.0f, mTotalProfit); mMarkers.push_back(std::move(s)); - mOrderPlaced = true; - mPrevY = price2; - //beep(unixtime, 4000, 50); + mEntry2.Reset(entry2Active ? entryShare : 0.0f); } - else if (sell) { - buySellCounter--; - ASSERT(buySellCounter >= 0); - auto change = price2 / mPrevY; - auto profit = change * (1.0f - slip); - mYTotalChange *= profit; - auto s = std::make_tuple(unixtime, price2, mark, mYTotalChange); + if (mEntry3.TradeExited(unixtime)) { + mTotalProfit *= mEntry3.GetProfit(slip); + auto s = std::make_tuple(unixtime, estimatedPrice, -1.0f, mTotalProfit); mMarkers.push_back(std::move(s)); - mOrderPlaced = false; - //beep(unixtime, 500, 50); + mEntry3.Reset(entry3Active ? entryShare : 0.0f); } - mPrevValue = mark; } mReadSamples += numSamples; if (mReadSamples >= numCacheSamples) { mReadSamples = 0; - mPrevValue = 0.0f; - mYTotalChange = 1.0f; - mOrderPlaced = false; + mTotalProfit = 1.0f; } } } From 461a01680845ffc99a67901fca579a5d892f5f32 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 16 Aug 2025 23:12:54 +0200 Subject: [PATCH 065/179] NG: Fix warning. --- packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index 4aef2749..72b7f55f 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -181,7 +181,8 @@ namespace l::nodegraph { auto entry1Active = inputs.at(3).HasInputNode(); auto entry2Active = inputs.at(4).HasInputNode(); auto entry3Active = inputs.at(11).HasInputNode(); - auto entryShare = (entry1Active && entry2Active && entry3Active) ? 0.3333f : (entry1Active && entry2Active || entry1Active && entry3Active || entry2Active || entry3Active) ? 0.5f : 1.0f; + auto entryShared3 = ((entry1Active && entry2Active) || (entry1Active && entry3Active) || (entry2Active && entry3Active)) ? 0.5f : 1.0f; + auto entryShare = (entry1Active && entry2Active && entry3Active) ? 0.3333f : entryShared3; if (mReadSamples == 0) { mMarkers.clear(); From 6967540863acca053bda3407377585ac15ed4436 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 17 Aug 2025 20:13:06 +0200 Subject: [PATCH 066/179] Add current time to chart info. --- .../include/nodegraph/operations/NodeGraphOpTradingDataIO.h | 2 ++ .../source/common/operations/NodeGraphOpTradingDataIO.cpp | 3 +++ 2 files changed, 5 insertions(+) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h index 0f7e38d8..152c8e9b 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h @@ -75,6 +75,7 @@ namespace l::nodegraph { AddInput2("Symbol", 16, InputFlags(false, true, false, true)); AddInput2("Base", 16, InputFlags(false, true, false, true)); AddInput("Index", 2.0f, 1, 0.0f, 10.0f); + AddInput2("Now", 1, InputFlags(false, true, false, false)); AddOutput2("Symbol", 16, OutputFlags(false, true)); AddOutput2("Base", 16, OutputFlags(false, true)); @@ -82,6 +83,7 @@ namespace l::nodegraph { AddOutput("Index#1", 1.0f); AddOutput("Index#2", 2.0f); AddOutput("Index#3", 3.0f); + AddOutput("Now", 0.0f); } virtual ~TradingDataIOChartInfo() = default; diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp index e458e8ba..27ad4c75 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp @@ -133,6 +133,7 @@ namespace l::nodegraph { auto symbolInput = inputs.at(0).GetText(16); auto baseInput = inputs.at(1).GetText(16); auto indexInput = l::math::clamp(inputs.at(2).Get(), 0.0f, 9.9999f); + auto now = inputs.at(3).Get(); outputs.at(0).SetText(symbolInput); outputs.at(1).SetText(baseInput); @@ -140,10 +141,12 @@ namespace l::nodegraph { float* indexOut1 = &outputs.at(3).Get(); float* indexOut2 = &outputs.at(4).Get(); float* indexOut3 = &outputs.at(5).Get(); + float* nowOutput = &outputs.at(6).Get(); *indexOut0 = l::math::clamp(indexInput, 0.0f, 9.9999f); *indexOut1 = l::math::clamp(indexInput + 1.0f, 0.0f, 9.9999f); *indexOut2 = l::math::clamp(indexInput + 2.0f, 0.0f, 9.9999f); *indexOut3 = l::math::clamp(indexInput + 3.0f, 0.0f, 9.9999f); + *nowOutput = now; } } From eedf3d8962cf44fc07c9f236ba2347284656e69b Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 18 Aug 2025 11:40:59 +0200 Subject: [PATCH 067/179] Fix sorted vector. --- packages/memory/include/memory/VectorSorted.h | 28 +++++++++++++++++++ .../operations/NodeGraphOpTradingDataIO.h | 4 +-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/packages/memory/include/memory/VectorSorted.h b/packages/memory/include/memory/VectorSorted.h index a8e71bdb..95ca59e7 100644 --- a/packages/memory/include/memory/VectorSorted.h +++ b/packages/memory/include/memory/VectorSorted.h @@ -54,6 +54,14 @@ namespace l::container { return it; } + typename std::vector::iterator upper_bound_it(const T& key) { + if (!m_bSorted) + sort(); + + typename std::vector::iterator it = std::upper_bound(vec.begin(), vec.end(), key); + return it; + } + /*const*/ T* lower_bound_ptr(const T& key) { typename std::vector::iterator it = lower_bound_it(key); @@ -101,6 +109,23 @@ namespace l::container { return vec.end(); } + typename std::vector::iterator find_upper_bound(const T& key) { + typename std::vector::iterator it = upper_bound_it(key); + + if (it == vec.begin()) // first element is greater than key + return vec.end(); + if (!vec.empty()) // key is greater than all elements so get the last one + return it - 1; + return vec.end(); + } + typename std::vector::iterator find_lower_bound(const T& key) { + typename std::vector::iterator it = lower_bound_it(key); + + if (it != vec.end()) + return it; + + return vec.end(); + } //-------------------------------------------------------------------// // find_ptr_or_fail() // //-------------------------------------------------------------------// @@ -242,6 +267,9 @@ namespace l::container { return vec.empty(); } + inline void clear() noexcept { + return vec.clear(); + } protected: std::vector vec; bool m_bSorted; diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h index 152c8e9b..587f3d31 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h @@ -75,7 +75,7 @@ namespace l::nodegraph { AddInput2("Symbol", 16, InputFlags(false, true, false, true)); AddInput2("Base", 16, InputFlags(false, true, false, true)); AddInput("Index", 2.0f, 1, 0.0f, 10.0f); - AddInput2("Now", 1, InputFlags(false, true, false, false)); + AddInput2("Now"); AddOutput2("Symbol", 16, OutputFlags(false, true)); AddOutput2("Base", 16, OutputFlags(false, true)); @@ -83,7 +83,7 @@ namespace l::nodegraph { AddOutput("Index#1", 1.0f); AddOutput("Index#2", 2.0f); AddOutput("Index#3", 3.0f); - AddOutput("Now", 0.0f); + AddOutput("Now"); } virtual ~TradingDataIOChartInfo() = default; From f8cfacdd213da429ae3e47080cbf83892702c525 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 18 Aug 2025 15:29:45 +0200 Subject: [PATCH 068/179] Fix padding in to time string buffer. --- packages/logging/include/logging/String.h | 10 +++++----- packages/memory/include/memory/VectorSorted.h | 9 +++++++++ 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/packages/logging/include/logging/String.h b/packages/logging/include/logging/String.h index 0d0e742a..9c1a3be6 100644 --- a/packages/logging/include/logging/String.h +++ b/packages/logging/include/logging/String.h @@ -160,10 +160,10 @@ namespace l::string { struct std::tm tminfo = {}; convert_to_local_tm_from_utc_time(unixtime, &tminfo, false); if (fullYear) { - buf.printf("%4d-%2d-%2d", tminfo.tm_year, tminfo.tm_mon + 1, tminfo.tm_mday); + buf.printf("%04d-%02d-%02d", tminfo.tm_year, tminfo.tm_mon + 1, tminfo.tm_mday); } else { - buf.printf("%4d-%2d-%2d", tminfo.tm_year, tminfo.tm_mon + 1, tminfo.tm_mday); + buf.printf("%04d-%02d-%02d", tminfo.tm_year, tminfo.tm_mon + 1, tminfo.tm_mday); } } @@ -171,7 +171,7 @@ namespace l::string { void get_local_time(string_buffer& buf, const int32_t unixtime) { struct std::tm tminfo = {}; convert_to_local_tm_from_utc_time(unixtime, &tminfo, false); - buf.printf("%2d:%2d:%2d", tminfo.tm_hour, tminfo.tm_min, tminfo.tm_sec); + buf.printf("%02d:%02d:%02d", tminfo.tm_hour, tminfo.tm_min, tminfo.tm_sec); } template @@ -179,10 +179,10 @@ namespace l::string { struct std::tm tminfo = {}; convert_to_local_tm_from_utc_time(unixtime, &tminfo, true); if (fullYear) { - buf.printf("%4d-%2d-%2d %2d:%2d:%2d", tminfo.tm_year, tminfo.tm_mon + 1, tminfo.tm_mday, tminfo.tm_hour, tminfo.tm_min, tminfo.tm_sec); + buf.printf("%04d-%02d-%02d %02d:%02d:%02d", tminfo.tm_year, tminfo.tm_mon + 1, tminfo.tm_mday, tminfo.tm_hour, tminfo.tm_min, tminfo.tm_sec); } else { - buf.printf("%2d-%2d-%2d %2d:%2d:%2d", tminfo.tm_year, tminfo.tm_mon + 1, tminfo.tm_mday, tminfo.tm_hour, tminfo.tm_min, tminfo.tm_sec); + buf.printf("%02d-%02d-%02d %02d:%02d:%02d", tminfo.tm_year, tminfo.tm_mon + 1, tminfo.tm_mday, tminfo.tm_hour, tminfo.tm_min, tminfo.tm_sec); } } diff --git a/packages/memory/include/memory/VectorSorted.h b/packages/memory/include/memory/VectorSorted.h index 95ca59e7..084f1a5d 100644 --- a/packages/memory/include/memory/VectorSorted.h +++ b/packages/memory/include/memory/VectorSorted.h @@ -270,6 +270,15 @@ namespace l::container { inline void clear() noexcept { return vec.clear(); } + + const T& back() noexcept { + if (!m_bSorted) + { + sort(); + } + return vec.back(); + } + protected: std::vector vec; bool m_bSorted; From 0512fe682d94dbb717247d8b6cf41df8bc51135b Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 19 Aug 2025 17:04:57 +0200 Subject: [PATCH 069/179] Add some more functions to sorted vector. --- packages/memory/include/memory/VectorSorted.h | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/packages/memory/include/memory/VectorSorted.h b/packages/memory/include/memory/VectorSorted.h index 084f1a5d..f1e069ef 100644 --- a/packages/memory/include/memory/VectorSorted.h +++ b/packages/memory/include/memory/VectorSorted.h @@ -109,7 +109,7 @@ namespace l::container { return vec.end(); } - typename std::vector::iterator find_upper_bound(const T& key) { + typename std::vector::iterator find_at_or_below(const T& key) { typename std::vector::iterator it = upper_bound_it(key); if (it == vec.begin()) // first element is greater than key @@ -118,7 +118,7 @@ namespace l::container { return it - 1; return vec.end(); } - typename std::vector::iterator find_lower_bound(const T& key) { + typename std::vector::iterator find_at_or_above(const T& key) { typename std::vector::iterator it = lower_bound_it(key); if (it != vec.end()) @@ -271,7 +271,7 @@ namespace l::container { return vec.clear(); } - const T& back() noexcept { + T& back() noexcept { if (!m_bSorted) { sort(); @@ -279,9 +279,18 @@ namespace l::container { return vec.back(); } + void pop_front(size_t count) { + if (count < vec.size()) { + vec.erase(vec.begin(), vec.begin() + count); + } + else { + clear(); + } + } + protected: std::vector vec; - bool m_bSorted; + bool m_bSorted = true; }; } From 95cebd8eb2b8dea986f57a0bebf4ea92227be6e2 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 19 Aug 2025 23:56:32 +0200 Subject: [PATCH 070/179] Add ochlv ma source. --- .../operations/NodeGraphOpTradingDataIO.h | 39 ++++++++- .../source/common/NodeGraphSchema.cpp | 24 ++++++ .../operations/NodeGraphOpTradingDataIO.cpp | 80 +++++++++++++++++++ 3 files changed, 139 insertions(+), 4 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h index 587f3d31..5402700c 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h @@ -26,9 +26,27 @@ namespace l::nodegraph { NodeGraphOpCached(node, "OCHLV Data In"), mMode(mode) { - if (mMode == 1) { - mName = "OCHLV Heikin-Ashi In"; - } + if (mMode == 1) { + mName = "OCHLV Heikin-Ashi In"; + } + else if (mMode == 2) { + mName = "OCHLV Data In 2xMA"; + } + else if (mMode == 2) { + mName = "OCHLV Data In 3xMA"; + } + else if (mMode == 3) { + mName = "OCHLV Data In 5xMA"; + } + else if (mMode == 3) { + mName = "OCHLV Data In 15xMA"; + } + else if (mMode == 3) { + mName = "OCHLV Data In 30xMA"; + } + else if (mMode == 3) { + mName = "OCHLV Data In 60xMA"; + } AddInput2("In", 16, InputFlags(false, false, false, false)); AddInput2("Symbol", 16, InputFlags(false, true, false, true)); @@ -61,9 +79,22 @@ namespace l::nodegraph { int32_t mUnixtimePrev = 0; + // Heikin ashi vars float mOpenPrev = 0.0f; float mClosePrev = 0.0f; - }; + + // Time frame vars + float mOpenMa = 0.0f; + float mCloseMa = 0.0f; + float mHighMa = 0.0f; + float mLowMa = 0.0f; + float mVolMa = 0.0f; + float mQuantMa = 0.0f; + float mBuyVolMa = 0.0f; + float mSellVolMa = 0.0f; + float mBuyQuantMa = 0.0f; + float mSellQuantMa = 0.0f; + }; /*********************************************************************/ diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index da2823e8..89d4f47d 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -326,6 +326,24 @@ namespace l::nodegraph { case 202: node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput); break; + case 203: + node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 2); + break; + case 204: + node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 3); + break; + case 205: + node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 4); + break; + case 206: + node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 5); + break; + case 207: + node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 6); + break; + case 208: + node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 7); + break; // Trading detectors case 220: @@ -630,6 +648,12 @@ namespace l::nodegraph { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); RegisterNodeType("Trading.Data IO", 201, "Heikin-Ashi Data In"); RegisterNodeType("Trading.Data IO", 202, "Chart Info"); + RegisterNodeType("Trading.Data IO", 203, "OCHLV Data In 2xMA"); + RegisterNodeType("Trading.Data IO", 204, "OCHLV Data In 3xMA"); + RegisterNodeType("Trading.Data IO", 205, "OCHLV Data In 5xMA"); + RegisterNodeType("Trading.Data IO", 206, "OCHLV Data In 15xMA"); + RegisterNodeType("Trading.Data IO", 207, "OCHLV Data In 30xMA"); + RegisterNodeType("Trading.Data IO", 208, "OCHLV Data In 60xMA"); } else if (typeGroup == "Trading.Detector") { RegisterNodeType("Trading.Detector", 220, "Trend"); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp index 27ad4c75..ace80f84 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp @@ -127,6 +127,86 @@ namespace l::nodegraph { *out11++ = in[offset + 6] - in[offset + 8]; // sell quantity } } + auto multiplier = 2; + if (mMode == 2) { + multiplier = 2; + } + else if (mMode == 3) { + multiplier = 3; + } + else if (mMode == 4) { + multiplier = 5; + } + else if (mMode == 5) { + multiplier = 15; + } + else if (mMode == 6) { + multiplier = 30; + } + else if (mMode == 7) { + multiplier = 60; + } + + + if (mMode >= 2 && mMode <= 7) { + for (int32_t j = 0; j < numSamples; j++) { + auto offset = j * stride; + + auto unixtimef = in[offset + 0]; + auto unixtime = l::math::algorithm::convert(unixtimef); + if (mUnixtimePrev == 0) { + mUnixtimePrev = unixtime; + } + else if (unixtime == mUnixtimePrev) { + unixtime = 0; + unixtimef = l::math::algorithm::convert(unixtime); + } + else { + mUnixtimePrev = unixtime; + } + + *out1++ = unixtimef; // unixtime + auto o = in[offset + 1]; + auto c = in[offset + 2]; + auto h = in[offset + 3]; + auto l = in[offset + 4]; + auto v = in[offset + 5]; + auto q = in[offset + 6]; // quantity + + auto timemin = unixtime / 60; + if (timemin % multiplier == 0) { + // time interval looping so reset moving averages + mOpenMa = o; // simply first value + mVolMa = v; + mHighMa = h; + mLowMa = l; + mCloseMa = c; + mQuantMa = q; + mBuyVolMa = 0.0f; + mSellVolMa = 0.0f; + mBuyQuantMa = 0.0f; + mSellQuantMa = 0.0f; + } + else { + mCloseMa = c; // simply last value + mHighMa = l::math::max2(mHighMa, h); + mLowMa = l::math::min2(mLowMa, l); + mVolMa += v; // just the sum + mQuantMa += q; + } + + *out2++ = mOpenMa; + *out3++ = mCloseMa; + *out4++ = mHighMa; + *out5++ = mLowMa; + *out6++ = mVolMa; + *out7++ = mQuantMa; // quantity + *out8++ = 0.0f; // buy volume + *out9++ = 0.0f; // sell volume + *out10++ = 0.0f; // buy quantity + *out11++ = 0.0f; // sell quantity + } + } } void TradingDataIOChartInfo::Process(int32_t, int32_t, std::vector& inputs, std::vector& outputs) { From fd8ef52d42508fe7fb1cfdffa17905a1673fb4d5 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Wed, 20 Aug 2025 01:01:23 +0200 Subject: [PATCH 071/179] NG: Fix up ochlv ma. --- .../nodegraph/operations/NodeGraphOpTradingDataIO.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h index 5402700c..a223ed75 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h @@ -32,19 +32,19 @@ namespace l::nodegraph { else if (mMode == 2) { mName = "OCHLV Data In 2xMA"; } - else if (mMode == 2) { + else if (mMode == 3) { mName = "OCHLV Data In 3xMA"; } - else if (mMode == 3) { + else if (mMode == 4) { mName = "OCHLV Data In 5xMA"; } - else if (mMode == 3) { + else if (mMode == 5) { mName = "OCHLV Data In 15xMA"; } - else if (mMode == 3) { + else if (mMode == 6) { mName = "OCHLV Data In 30xMA"; } - else if (mMode == 3) { + else if (mMode == 7) { mName = "OCHLV Data In 60xMA"; } From 082c0a617ff6437c69b1d07f6c96a34af472f6d8 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Wed, 20 Aug 2025 05:50:39 +0200 Subject: [PATCH 072/179] NG: Integrate timeframe option in standard ochlv in data node. --- .../operations/NodeGraphOpTradingDataIO.h | 21 +-- .../source/common/NodeGraphSchema.cpp | 24 ---- .../operations/NodeGraphOpTradingDataIO.cpp | 134 ++++++------------ 3 files changed, 44 insertions(+), 135 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h index a223ed75..679d716e 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h @@ -29,29 +29,12 @@ namespace l::nodegraph { if (mMode == 1) { mName = "OCHLV Heikin-Ashi In"; } - else if (mMode == 2) { - mName = "OCHLV Data In 2xMA"; - } - else if (mMode == 3) { - mName = "OCHLV Data In 3xMA"; - } - else if (mMode == 4) { - mName = "OCHLV Data In 5xMA"; - } - else if (mMode == 5) { - mName = "OCHLV Data In 15xMA"; - } - else if (mMode == 6) { - mName = "OCHLV Data In 30xMA"; - } - else if (mMode == 7) { - mName = "OCHLV Data In 60xMA"; - } AddInput2("In", 16, InputFlags(false, false, false, false)); AddInput2("Symbol", 16, InputFlags(false, true, false, true)); AddInput2("Base", 16, InputFlags(false, true, false, true)); AddInput("Index", 2.0f, 1, 0.0f, 10.0f); + AddInput("Timeframe", 1.0f, 1, 1.0f, 1440.0f); AddOutput2("Symbol", 16, OutputFlags(false, true)); @@ -91,9 +74,7 @@ namespace l::nodegraph { float mVolMa = 0.0f; float mQuantMa = 0.0f; float mBuyVolMa = 0.0f; - float mSellVolMa = 0.0f; float mBuyQuantMa = 0.0f; - float mSellQuantMa = 0.0f; }; /*********************************************************************/ diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 89d4f47d..da2823e8 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -326,24 +326,6 @@ namespace l::nodegraph { case 202: node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput); break; - case 203: - node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 2); - break; - case 204: - node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 3); - break; - case 205: - node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 4); - break; - case 206: - node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 5); - break; - case 207: - node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 6); - break; - case 208: - node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 7); - break; // Trading detectors case 220: @@ -648,12 +630,6 @@ namespace l::nodegraph { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); RegisterNodeType("Trading.Data IO", 201, "Heikin-Ashi Data In"); RegisterNodeType("Trading.Data IO", 202, "Chart Info"); - RegisterNodeType("Trading.Data IO", 203, "OCHLV Data In 2xMA"); - RegisterNodeType("Trading.Data IO", 204, "OCHLV Data In 3xMA"); - RegisterNodeType("Trading.Data IO", 205, "OCHLV Data In 5xMA"); - RegisterNodeType("Trading.Data IO", 206, "OCHLV Data In 15xMA"); - RegisterNodeType("Trading.Data IO", 207, "OCHLV Data In 30xMA"); - RegisterNodeType("Trading.Data IO", 208, "OCHLV Data In 60xMA"); } else if (typeGroup == "Trading.Detector") { RegisterNodeType("Trading.Detector", 220, "Trend"); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp index ace80f84..cbc651f5 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp @@ -33,6 +33,7 @@ namespace l::nodegraph { inputs.at(0).MinimizeBuffer(numCacheSamples * stride); auto in = &inputs.at(0).Get(numCacheSamples * stride, readSamples * stride); + auto timeframeMultiplier = static_cast(inputs.at(4).Get()); float* out1 = &outputs.at(3).Get(numSamples); // unixtime float* out2 = &outputs.at(4).Get(numSamples); // open @@ -70,18 +71,49 @@ namespace l::nodegraph { auto c = in[offset + 2]; auto h = in[offset + 3]; auto l = in[offset + 4]; - auto v = in[offset + 5]; + auto v = in[offset + 5]; // total volume + auto q = in[offset + 6]; // total quantity + auto bv = in[offset + 7]; // buy volume + auto bq = in[offset + 8]; // buy quantity - *out2++ = o; - *out3++ = c; - *out4++ = h; - *out5++ = l; - *out6++ = v; - *out7++ = in[offset + 6]; // quantity - *out8++ = in[offset + 7]; // buy volume - *out9++ = in[offset + 5] - in[offset + 7]; // sell volume - *out10++ = in[offset + 8]; // buy quantity - *out11++ = in[offset + 6] - in[offset + 8]; // sell quantity + auto timemin = unixtime / 60; + if (timemin % timeframeMultiplier == 0) { + // time interval looping so reset moving averages + mOpenMa = o; // simply first value + mCloseMa = c; + mHighMa = h; + mLowMa = l; + mVolMa = v; + mQuantMa = q; + mBuyVolMa = bv; + mBuyQuantMa = bq; + } + else { + // last value + mCloseMa = c; + + // extremes + mHighMa = l::math::max2(mHighMa, h); + mLowMa = l::math::min2(mLowMa, l); + + // just the sums + mVolMa += v; + mQuantMa += q; + mBuyVolMa += bv; + mBuyQuantMa += bq; + } + + *out2++ = mOpenMa; + *out3++ = mCloseMa; + *out4++ = mHighMa; + *out5++ = mLowMa; + *out6++ = mVolMa; + *out7++ = mQuantMa; // quantity + + *out8++ = mBuyVolMa; // buy volume + *out9++ = mVolMa - mBuyVolMa; // sell volume + *out10++ = mBuyQuantMa; // buy quantity + *out11++ = mQuantMa - mBuyQuantMa; // sell quantity } } else if (mMode == 1) { @@ -127,86 +159,6 @@ namespace l::nodegraph { *out11++ = in[offset + 6] - in[offset + 8]; // sell quantity } } - auto multiplier = 2; - if (mMode == 2) { - multiplier = 2; - } - else if (mMode == 3) { - multiplier = 3; - } - else if (mMode == 4) { - multiplier = 5; - } - else if (mMode == 5) { - multiplier = 15; - } - else if (mMode == 6) { - multiplier = 30; - } - else if (mMode == 7) { - multiplier = 60; - } - - - if (mMode >= 2 && mMode <= 7) { - for (int32_t j = 0; j < numSamples; j++) { - auto offset = j * stride; - - auto unixtimef = in[offset + 0]; - auto unixtime = l::math::algorithm::convert(unixtimef); - if (mUnixtimePrev == 0) { - mUnixtimePrev = unixtime; - } - else if (unixtime == mUnixtimePrev) { - unixtime = 0; - unixtimef = l::math::algorithm::convert(unixtime); - } - else { - mUnixtimePrev = unixtime; - } - - *out1++ = unixtimef; // unixtime - auto o = in[offset + 1]; - auto c = in[offset + 2]; - auto h = in[offset + 3]; - auto l = in[offset + 4]; - auto v = in[offset + 5]; - auto q = in[offset + 6]; // quantity - - auto timemin = unixtime / 60; - if (timemin % multiplier == 0) { - // time interval looping so reset moving averages - mOpenMa = o; // simply first value - mVolMa = v; - mHighMa = h; - mLowMa = l; - mCloseMa = c; - mQuantMa = q; - mBuyVolMa = 0.0f; - mSellVolMa = 0.0f; - mBuyQuantMa = 0.0f; - mSellQuantMa = 0.0f; - } - else { - mCloseMa = c; // simply last value - mHighMa = l::math::max2(mHighMa, h); - mLowMa = l::math::min2(mLowMa, l); - mVolMa += v; // just the sum - mQuantMa += q; - } - - *out2++ = mOpenMa; - *out3++ = mCloseMa; - *out4++ = mHighMa; - *out5++ = mLowMa; - *out6++ = mVolMa; - *out7++ = mQuantMa; // quantity - *out8++ = 0.0f; // buy volume - *out9++ = 0.0f; // sell volume - *out10++ = 0.0f; // buy quantity - *out11++ = 0.0f; // sell quantity - } - } } void TradingDataIOChartInfo::Process(int32_t, int32_t, std::vector& inputs, std::vector& outputs) { From 423cdf1ce4ad3288b130cea3519c85583b108d4e Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 21 Aug 2025 20:43:25 +0200 Subject: [PATCH 073/179] NG: Fix some issue with trade nodes. --- .../operations/NodeGraphOpMathNumerical.h | 4 ++-- .../operations/NodeGraphOpTradingDataIO.h | 1 + .../operations/NodeGraphOpMathNumerical.cpp | 21 ++++++++++--------- .../common/operations/NodeGraphOpSource.cpp | 9 ++++++++ .../operations/NodeGraphOpTradingDataIO.cpp | 6 ++++++ 5 files changed, 29 insertions(+), 12 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index c82ef7b1..d0f2df87 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -109,8 +109,8 @@ namespace l::nodegraph { AddInput2("Max"); AddInput2("Min"); AddInput("Num levels", 1.0f, 1, 1.0f, 100.0f, true, true); - AddInput("Max%", 1.0f, 1, 0.0f, 1.0f, true, true); - AddInput("Min%", 0.0f, 1, 0.0f, 1.0f, true, true); + AddInput("Max", 1.0f, 1, 0.0f, 3.0f, true, true); + AddInput("Min", 0.0f, 1, -3.0f, 1.0f, true, true); AddOutput2("Level"); AddOutput2("Pulse"); } diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h index 679d716e..794c75cd 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h @@ -35,6 +35,7 @@ namespace l::nodegraph { AddInput2("Base", 16, InputFlags(false, true, false, true)); AddInput("Index", 2.0f, 1, 0.0f, 10.0f); AddInput("Timeframe", 1.0f, 1, 1.0f, 1440.0f); + AddInput("Friction", 0.0f, 1, 0.0f, 1.0f); AddOutput2("Symbol", 16, OutputFlags(false, true)); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index bfb312cd..140638b6 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -112,8 +112,8 @@ namespace l::nodegraph { auto maxInput = inputs.at(1).GetIterator(numSamples); auto minInput = inputs.at(2).GetIterator(numSamples); auto numLevels = l::math::clamp(inputs.at(3).Get(), 1.0f, 10.0f); - auto max = l::math::clamp(inputs.at(4).Get(), 0.0f, 1.0f); - auto min = l::math::clamp(inputs.at(5).Get(), 0.0f, max); + auto max = l::math::clamp(inputs.at(4).Get(), 0.0f, 3.0f); + auto min = l::math::clamp(inputs.at(5).Get(), -3.0f, max); auto levelOutput = &outputs.at(0).Get(numSamples); auto pulseOutput = &outputs.at(1).Get(numSamples); @@ -121,28 +121,29 @@ namespace l::nodegraph { float in = *inInput++; float inMax = *maxInput++; float inMin = *minInput++; - float inLimited = l::math::clamp(in, inMin, inMax); float inRange = inMax - inMin; float inRangeFactor = 0.0f; if (inRange > 0.0f) { - inRangeFactor = (inLimited - inMin) / inRange; + inRangeFactor = (in - inMin) / inRange; } - float inRangeFactorClamped = l::math::clamp(inRangeFactor, min, max); float minmaxRange = max - min; float level = 0.0f; if (minmaxRange > 0.0f) { - float levelMinMax = (inRangeFactorClamped - min) / minmaxRange; - level = numLevels * levelMinMax; + float levelMinMax = (inRangeFactor - min) / minmaxRange; + level = levelMinMax; } + auto levelExpanded = numLevels * level; + float pulse = 0.0f; - if (static_cast(level) > static_cast(mLevelPrev + level)) { + if (level >= 0.0f && level <= 1.0f && static_cast(levelExpanded) > static_cast(mLevelPrev)) { pulse = 1.0f; + mLevelPrev = levelExpanded; } - else if (static_cast(level) < static_cast(mLevelPrev)) { + else if (level >= 0.0f && level <= 1.0f && static_cast(levelExpanded) < static_cast(mLevelPrev)) { pulse = -1.0f; + mLevelPrev = levelExpanded; } - mLevelPrev = level; *levelOutput++ = level; *pulseOutput++ = pulse; } diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpSource.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpSource.cpp index 9dcb7fad..a49ee57a 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpSource.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpSource.cpp @@ -14,10 +14,19 @@ namespace l::nodegraph { /*********************************************************************/ void GraphSourceConstants::Process(int32_t, int32_t, std::vector& inputs, std::vector& outputs) { auto input0 = inputs.at(0).GetIterator(1); + auto input1 = inputs.at(1).GetIterator(1); + auto input2 = inputs.at(2).GetIterator(1); + auto input3 = inputs.at(3).GetIterator(1); auto output0 = outputs.at(0).GetIterator(1); + auto output1 = outputs.at(1).GetIterator(1); + auto output2 = outputs.at(2).GetIterator(1); + auto output3 = outputs.at(3).GetIterator(1); for (int8_t i = 0; i < mNumOutputs; i++) { *output0 = *input0; + *output1 = *input1; + *output2 = *input2; + *output3 = *input3; } } diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp index cbc651f5..2aeeb5c7 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp @@ -34,6 +34,7 @@ namespace l::nodegraph { inputs.at(0).MinimizeBuffer(numCacheSamples * stride); auto in = &inputs.at(0).Get(numCacheSamples * stride, readSamples * stride); auto timeframeMultiplier = static_cast(inputs.at(4).Get()); + auto friction = inputs.at(5).Get(); float* out1 = &outputs.at(3).Get(numSamples); // unixtime float* out2 = &outputs.at(4).Get(numSamples); // open @@ -92,6 +93,11 @@ namespace l::nodegraph { // last value mCloseMa = c; + // smooth + mOpenMa += friction * (mCloseMa - mOpenMa); + mHighMa += friction * (mCloseMa - mHighMa); + mLowMa += friction * (mCloseMa - mLowMa); + // extremes mHighMa = l::math::max2(mHighMa, h); mLowMa = l::math::min2(mLowMa, l); From 98047ddf39e0ececf02c628092e22b17ce9cffd3 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 22 Aug 2025 10:18:41 +0200 Subject: [PATCH 074/179] NG: Add tooltip in node picker for node descriptions. --- packages/logging/include/logging/String.h | 7 ++ .../include/nodegraph/NodeGraphSchema.h | 16 +++-- .../source/common/NodeGraphSchema.cpp | 24 ++++--- .../include/rendering/ui/UINodeEditor.h | 4 +- .../source/common/ui/UINodeEditor.cpp | 65 ++++++++++++------- 5 files changed, 78 insertions(+), 38 deletions(-) diff --git a/packages/logging/include/logging/String.h b/packages/logging/include/logging/String.h index 9c1a3be6..f18ad1fd 100644 --- a/packages/logging/include/logging/String.h +++ b/packages/logging/include/logging/String.h @@ -83,6 +83,13 @@ namespace l::string { return std::string_view( &mBuf[0], size()); } + char* data() { + return &mBuf[0]; + } + + size_t capacity() { + return BUFSIZE - 1; + } protected: int32_t mPos = 0; char mBuf[BUFSIZE]; diff --git a/packages/nodegraph/include/nodegraph/NodeGraphSchema.h b/packages/nodegraph/include/nodegraph/NodeGraphSchema.h index 9e5c6543..22d9b714 100644 --- a/packages/nodegraph/include/nodegraph/NodeGraphSchema.h +++ b/packages/nodegraph/include/nodegraph/NodeGraphSchema.h @@ -35,7 +35,7 @@ namespace l::nodegraph { class TreeMenuNode { public: TreeMenuNode() = default; - TreeMenuNode(std::string_view pathPart, std::string_view name, int32_t id) : mPathPart(pathPart), mName(name), mId(id) {} + TreeMenuNode(std::string_view pathPart, std::string_view name, int32_t id, std::string_view description = "") : mPathPart(pathPart), mName(name), mId(id), mDescription(description) {} ~TreeMenuNode() = default; std::string_view GetPathPart() const { @@ -47,27 +47,35 @@ namespace l::nodegraph { int32_t GetId() const { return mId; } + std::string_view GetDescription() const { + return mDescription; + } std::vector mChildren; std::string mPathPart; protected: std::string mName; int32_t mId = 0; + std::string mDescription; }; TreeMenuNode* findOrCreateChild(TreeMenuNode& node, std::string_view pathPart); - void insertPath(TreeMenuNode& root, std::string_view path, std::string_view name, int32_t nodeId); + void insertPath(TreeMenuNode& root, std::string_view path, std::string_view name, int32_t nodeId, std::string_view description); struct UINodeDesc { std::string_view GetName() const { return mName; } + std::string_view GetDescription() const { + return mDescription; + } int32_t GetId() const { return mId; } int32_t mId; std::string mName; + std::string mDescription; }; class NodeGraphSchema : public l::serialization::JsonSerializationBase, public NodeFactoryBase { @@ -173,8 +181,8 @@ namespace l::nodegraph { void ForEachOutputNode(std::function cb); bool HasNodeType(const std::string& typeGroup, int32_t typeId); - void ForEachNodeType(std::function&)> cb) const; - void RegisterNodeType(const std::string& typeGroup, int32_t uniqueTypeId, std::string_view typeName); + void ForEachNodeType(std::string_view search, std::function&)> cb) const; + void RegisterNodeType(const std::string& typeGroup, int32_t uniqueTypeId, std::string_view typeName, std::string_view description = ""); void RegisterAllOf(const std::string& typeGroup); void ProcessSubGraph(int32_t numSamples, int32_t numCacheSamples = -1); void Tick(int32_t tickCount, float delta); diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index da2823e8..32a98163 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -17,12 +17,12 @@ namespace l::nodegraph { } // Insert a path like "a.b.c" - void insertPath(TreeMenuNode& root, std::string_view path, std::string_view name, int32_t nodeId) { + void insertPath(TreeMenuNode& root, std::string_view path, std::string_view name, int32_t nodeId, std::string_view description) { TreeMenuNode* current = &root; for (auto part : l::string::split(path, ".")) { current = findOrCreateChild(*current, part); } - current->mChildren.emplace_back("", name, nodeId); + current->mChildren.emplace_back("", name, nodeId, description); } bool NodeGraphSchema::NodeGraphNewNode(int32_t typeId, int32_t nodeId) { @@ -563,9 +563,11 @@ namespace l::nodegraph { mMainNodeGraph.ForEachOutputNode(std::move(cb)); } - void NodeGraphSchema::ForEachNodeType(std::function&)> cb) const { + void NodeGraphSchema::ForEachNodeType(std::string_view search, std::function&)> cb) const { for (auto& it : mRegisteredNodeTypes) { - cb(it.first, it.second); + if (search.empty() || l::string::equal_anywhere(it.first, search)) { + cb(it.first, it.second); + } } } @@ -573,11 +575,15 @@ namespace l::nodegraph { return mPickerRootMenu; } - void NodeGraphSchema::RegisterNodeType(const std::string& typeGroup, int32_t uniqueTypeId, std::string_view typeName) { + void NodeGraphSchema::RegisterNodeType(const std::string& typeGroup, int32_t uniqueTypeId, std::string_view typeName, std::string_view description) { if (!HasNodeType(typeGroup, uniqueTypeId)) { - mRegisteredNodeTypes[typeGroup].push_back(UINodeDesc{ uniqueTypeId, std::string(typeName) }); + UINodeDesc nodeInfo; + nodeInfo.mId = uniqueTypeId; + nodeInfo.mName = typeName; + nodeInfo.mDescription = description; + mRegisteredNodeTypes[typeGroup].push_back(nodeInfo); } - insertPath(mPickerRootMenu, typeGroup, typeName, uniqueTypeId); + insertPath(mPickerRootMenu, typeGroup, typeName, uniqueTypeId, description); } void NodeGraphSchema::RegisterAllOf(const std::string& typeGroup) { @@ -622,9 +628,9 @@ namespace l::nodegraph { RegisterNodeType("Math.Numerical", 141, "Derivate"); RegisterNodeType("Math.Numerical", 142, "Difference Normalized"); RegisterNodeType("Math.Numerical", 143, "Difference"); - RegisterNodeType("Math.Numerical", 144, "Level Trigger"); + RegisterNodeType("Math.Numerical", 144, "Level Trigger", "Determines where some input is located between two extremes (min/max) in the format [0,1] "); RegisterNodeType("Math.Numerical", 145, "Minmax Channel"); - RegisterNodeType("Math.Numerical", 146, "Reconstructor"); + RegisterNodeType("Math.Numerical", 146, "Reconstructor", "Deconstructs the input into derivatives (change per index) and outputs the sum of through a ewa with a cooefficient of 'friction' {x1 = x0 + friction * (target - x0)}. An second output is provided which is the average of the last two outputs of that function."); } else if (typeGroup == "Trading.Data IO") { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); diff --git a/packages/rendering/include/rendering/ui/UINodeEditor.h b/packages/rendering/include/rendering/ui/UINodeEditor.h index be0fd99b..f9e30ea4 100644 --- a/packages/rendering/include/rendering/ui/UINodeEditor.h +++ b/packages/rendering/include/rendering/ui/UINodeEditor.h @@ -17,7 +17,7 @@ namespace l::ui { - void depthFirstTraversal(const nodegraph::TreeMenuNode& node, std::vector& path, std::function cbMenuItem); + void depthFirstTraversal(const nodegraph::TreeMenuNode& node, std::vector& path, std::function cbMenuItem); struct NodeEvent { l::nodegraph::NodeGraphSchema* mNodeSchema = nullptr; @@ -61,5 +61,7 @@ namespace l::ui { std::vector> mEventListeners; std::function mOverlayContentWindow = nullptr; + + l::string::string_buffer<20> mPickerSearch; }; } diff --git a/packages/rendering/source/common/ui/UINodeEditor.cpp b/packages/rendering/source/common/ui/UINodeEditor.cpp index 207035e1..bd77bea6 100644 --- a/packages/rendering/source/common/ui/UINodeEditor.cpp +++ b/packages/rendering/source/common/ui/UINodeEditor.cpp @@ -1,15 +1,17 @@ #include "rendering/ui/UINodeEditor.h" +#include "rendering/ImguiSpectrum.h" + #include namespace l::ui { - void depthFirstTraversal(const nodegraph::TreeMenuNode& node, std::vector& path, std::function cbMenuItem) { + void depthFirstTraversal(const nodegraph::TreeMenuNode& node, std::vector& path, std::function cbMenuItem) { if (node.GetPathPart().empty()) { for (const auto& child : node.mChildren) { depthFirstTraversal(child, path, cbMenuItem); } - cbMenuItem(node.GetName(), node.GetId()); + cbMenuItem(node.GetName(), node.GetId(), node.GetDescription()); } else { path.emplace_back(node.GetPathPart()); @@ -48,6 +50,7 @@ namespace l::ui { SetPointerPopup([&]() { ImGui::Text("Node picker"); + ImGui::InputText("find", mPickerSearch.data(), mPickerSearch.capacity(), ImGuiInputTextFlags_EnterReturnsTrue); ImGui::Separator(); if (mNGSchema == nullptr) { @@ -55,28 +58,42 @@ namespace l::ui { } std::vector path; - depthFirstTraversal(mNGSchema->GetPickerRoot(), path, [&](std::string_view menuName, int32_t menuId) { - if (!menuName.empty() && ImGui::MenuItem(menuName.data())) { - ImVec2 p = ImVec2(mUIInput.mCurPos.x - GetPosition().x, mUIInput.mCurPos.y - GetPosition().y); - p.x -= mUIRoot->GetPosition().x; - p.y -= mUIRoot->GetPosition().y; - p.x /= mUIRoot->GetScale(); - p.y /= mUIRoot->GetScale(); - p.x -= 3.0f; - p.y -= 3.0f; - auto nodeId = mNGSchema->NewNode(menuId); - auto node = mNGSchema->GetNode(nodeId); - if (node != nullptr) { - auto uiNode = l::ui::CreateUINode(mUIManager, *node, p); - mUIRoot->Add(uiNode); - - auto& uiData = node->GetUIData(); - auto position = uiNode->GetPosition(); - auto size = uiNode->GetSize(); - uiData.x = position.x; - uiData.y = position.y; - uiData.w = size.x; - uiData.h = size.y; + depthFirstTraversal(mNGSchema->GetPickerRoot(), path, [&](std::string_view menuName, int32_t menuId, std::string_view description) { + if (!menuName.empty()) { + if (ImGui::MenuItem(menuName.data())) { + ImVec2 p = ImVec2(mUIInput.mCurPos.x - GetPosition().x, mUIInput.mCurPos.y - GetPosition().y); + p.x -= mUIRoot->GetPosition().x; + p.y -= mUIRoot->GetPosition().y; + p.x /= mUIRoot->GetScale(); + p.y /= mUIRoot->GetScale(); + p.x -= 3.0f; + p.y -= 3.0f; + auto nodeId = mNGSchema->NewNode(menuId); + auto node = mNGSchema->GetNode(nodeId); + if (node != nullptr) { + auto uiNode = l::ui::CreateUINode(mUIManager, *node, p); + mUIRoot->Add(uiNode); + + auto& uiData = node->GetUIData(); + auto position = uiNode->GetPosition(); + auto size = uiNode->GetSize(); + uiData.x = position.x; + uiData.y = position.y; + uiData.w = size.x; + uiData.h = size.y; + } + } + if (!description.empty() && ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip)) { + ImGui::BeginTooltip(); + ImGui::PushTextWrapPos(350); + ImGui::PushStyleColor(0, ImGui::ColorConvertU32ToFloat4(ImGui::Spectrum::GRAY900)); + ImGui::TextWrapped(menuName.data()); + ImGui::PopStyleColor(); + ImGui::Separator(); + ImGui::PushStyleColor(0, ImGui::ColorConvertU32ToFloat4(ImGui::Spectrum::GRAY700)); + ImGui::TextWrapped(description.data()); + ImGui::PopStyleColor(); + ImGui::EndTooltip(); } } From 2e913c9aa0bbf22d7ce30fddc4eb53896b96bdf8 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 22 Aug 2025 11:07:24 +0200 Subject: [PATCH 075/179] Enable unity builds for most projects. Update ldeps unity builds. --- CMakeLists.txt | 47 +++++++++++++++++++++++++++++++++++++++++++++++ deps/ldeps | 2 +- 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index e0e72e52..2e84bd71 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -43,4 +43,51 @@ else() bs_configure_packages("packages" "${PACKAGE_NAMES}") + + option(LTOOLS_ENABLE_UNITY_BUILD "Enable unity builds for faster compilation" OFF) + if(LTOOLS_ENABLE_UNITY_BUILD) + set_target_properties(logging PROPERTIES UNITY_BUILD ON) + + set_target_properties(testing PROPERTIES UNITY_BUILD ON) + set_target_properties(filesystem PROPERTIES UNITY_BUILD ON) + set_target_properties(meta PROPERTIES UNITY_BUILD ON) + set_target_properties(memory PROPERTIES UNITY_BUILD ON) + set_target_properties(concurrency PROPERTIES UNITY_BUILD ON) + set_target_properties(serialization PROPERTIES UNITY_BUILD ON) + set_target_properties(crypto PROPERTIES UNITY_BUILD ON) + set_target_properties(math PROPERTIES UNITY_BUILD ON) + set_target_properties(audio PROPERTIES UNITY_BUILD ON) + set_target_properties(hid PROPERTIES UNITY_BUILD ON) + set_target_properties(nodegraph PROPERTIES UNITY_BUILD ON) + + set_target_properties(network PROPERTIES UNITY_BUILD ON) + set_target_properties(storage PROPERTIES UNITY_BUILD ON) + set_target_properties(tools PROPERTIES UNITY_BUILD ON) + + set_target_properties(physics PROPERTIES UNITY_BUILD ON) + set_target_properties(ecs PROPERTIES UNITY_BUILD ON) + #set_target_properties(rendering PROPERTIES UNITY_BUILD ON) + + set_target_properties(testing_test PROPERTIES UNITY_BUILD ON) + set_target_properties(filesystem_test PROPERTIES UNITY_BUILD ON) + set_target_properties(meta_test PROPERTIES UNITY_BUILD ON) + #set_target_properties(memory_test PROPERTIES UNITY_BUILD ON) + #set_target_properties(concurrency_test PROPERTIES UNITY_BUILD ON) + #set_target_properties(serialization_test PROPERTIES UNITY_BUILD ON) + set_target_properties(crypto_test PROPERTIES UNITY_BUILD ON) + set_target_properties(math_test PROPERTIES UNITY_BUILD ON) + set_target_properties(audio_test PROPERTIES UNITY_BUILD ON) + set_target_properties(hid_test PROPERTIES UNITY_BUILD ON) + #set_target_properties(nodegraph_test PROPERTIES UNITY_BUILD ON) + + #set_target_properties(network_test PROPERTIES UNITY_BUILD ON) + set_target_properties(storage_test PROPERTIES UNITY_BUILD ON) + set_target_properties(tools_test PROPERTIES UNITY_BUILD ON) + + #set_target_properties(physics_test PROPERTIES UNITY_BUILD ON) + #set_target_properties(ecs_test PROPERTIES UNITY_BUILD ON) + #set_target_properties(rendering_test PROPERTIES UNITY_BUILD ON) + + endif() + endif() diff --git a/deps/ldeps b/deps/ldeps index 92d1d022..d8737f06 160000 --- a/deps/ldeps +++ b/deps/ldeps @@ -1 +1 @@ -Subproject commit 92d1d02274008c44e6367e665747258e9d977b75 +Subproject commit d8737f06d951387d98928c0f70d6f34c1b935f7d From 1a1b397fcfa49dca58677cb0f7189c124c195ec1 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 22 Aug 2025 11:21:12 +0200 Subject: [PATCH 076/179] Also exclude math_test from unity build. --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index fa3f430c..acf3aa5c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -75,7 +75,7 @@ else() #set_target_properties(concurrency_test PROPERTIES UNITY_BUILD ON) #set_target_properties(serialization_test PROPERTIES UNITY_BUILD ON) set_target_properties(crypto_test PROPERTIES UNITY_BUILD ON) - set_target_properties(math_test PROPERTIES UNITY_BUILD ON) + #set_target_properties(math_test PROPERTIES UNITY_BUILD ON) set_target_properties(audio_test PROPERTIES UNITY_BUILD ON) set_target_properties(hid_test PROPERTIES UNITY_BUILD ON) #set_target_properties(nodegraph_test PROPERTIES UNITY_BUILD ON) From 0ebad25512ab5a1a5c8c09d2b3451adfe01d3834 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 22 Aug 2025 11:22:17 +0200 Subject: [PATCH 077/179] Fix linux warning. --- packages/rendering/source/common/ui/UINodeEditor.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/rendering/source/common/ui/UINodeEditor.cpp b/packages/rendering/source/common/ui/UINodeEditor.cpp index bd77bea6..891cef55 100644 --- a/packages/rendering/source/common/ui/UINodeEditor.cpp +++ b/packages/rendering/source/common/ui/UINodeEditor.cpp @@ -87,11 +87,11 @@ namespace l::ui { ImGui::BeginTooltip(); ImGui::PushTextWrapPos(350); ImGui::PushStyleColor(0, ImGui::ColorConvertU32ToFloat4(ImGui::Spectrum::GRAY900)); - ImGui::TextWrapped(menuName.data()); + ImGui::TextWrapped("%s", menuName.data()); ImGui::PopStyleColor(); ImGui::Separator(); ImGui::PushStyleColor(0, ImGui::ColorConvertU32ToFloat4(ImGui::Spectrum::GRAY700)); - ImGui::TextWrapped(description.data()); + ImGui::TextWrapped("%s", description.data()); ImGui::PopStyleColor(); ImGui::EndTooltip(); } From 523014e9ade4c7c22ae5d49a29fc2c3b6b99d74b Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 22 Aug 2025 11:52:01 +0200 Subject: [PATCH 078/179] Make tests more unique (with __counter__) and also make them static to get them to work with unity builds. --- packages/logging/include/logging/Macro.h | 8 +++++--- packages/testing/include/testing/Test.h | 10 +++++----- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/logging/include/logging/Macro.h b/packages/logging/include/logging/Macro.h index f989e1fe..7a1ebd4b 100644 --- a/packages/logging/include/logging/Macro.h +++ b/packages/logging/include/logging/Macro.h @@ -2,12 +2,14 @@ #define CONCATE_(X,Y) X##Y +#define CONCATE_3(X,Y,Z) X##Y##Z +#define CONCATE_4(X,Y,Z,W) X##Y##Z##W #define CONCATE(X,Y) CONCATE_(X,Y) -#define CONCATE3(X,Y,Z) CONCATE_(X,CONCATE(Y, Z)) -#define CONCATE4(X,Y,Z,W) CONCATE_(X,CONCATE3(Y, Z, W)) +#define CONCATE3(X,Y,Z) CONCATE_3(X,Y,Z) +#define CONCATE4(X,Y,Z,W) CONCATE_4(X,Y,Z,W) #define STRINGIFY(X) #X -#define UNIQUE(NAME) CONCATE(NAME, __LINE__) +#define UNIQUE(NAME) CONCATE3(NAME, __LINE__, __COUNTER__) #define UNUSED(symbol) (void)(symbol) diff --git a/packages/testing/include/testing/Test.h b/packages/testing/include/testing/Test.h index 1cb0c8d1..27b3bec3 100644 --- a/packages/testing/include/testing/Test.h +++ b/packages/testing/include/testing/Test.h @@ -26,9 +26,9 @@ namespace testing { #define TESTNAME(group, name) CONCATE(Test, CONCATE(group, name)) \ #define TEST(testgroup, testname) \ - int TESTNAME(testgroup, testname)(); \ + static int TESTNAME(testgroup, testname)(); \ ADDTEST(STRINGIFY(testgroup), STRINGIFY(testname), TESTNAME(testgroup, testname)) \ - int TESTNAME(testgroup, testname)() \ + static int TESTNAME(testgroup, testname)() \ @@ -39,10 +39,10 @@ namespace testing { #define PERFNAMEWRAPPER(group, name) CONCATE(Perf, CONCATE(group, CONCATE(name, Wrapper))) \ #define PERF_TEST(perfgroup, perfname) \ - int PERFNAME(perfgroup, perfname)(); \ - int PERFNAMEWRAPPER(perfgroup, perfname)() {l::testing::get_current_test_group()=#perfgroup;return PERFNAME(perfgroup, perfname)();} \ + static int PERFNAME(perfgroup, perfname)(); \ + static int PERFNAMEWRAPPER(perfgroup, perfname)() {l::testing::get_current_test_group()=#perfgroup;return PERFNAME(perfgroup, perfname)();} \ ADDPERF(STRINGIFY(perfgroup), STRINGIFY(perfname), PERFNAMEWRAPPER(perfgroup, perfname)) \ - int PERFNAME(perfgroup, perfname)() \ + static int PERFNAME(perfgroup, perfname)() \ #ifndef _DEBUG #define TEST_TRUE(expr, msg) \ From 60d439ca375bb57292dcda5bcced44c0a6d43049 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 22 Aug 2025 12:03:18 +0200 Subject: [PATCH 079/179] Reenable some projects that work with the new changes in test suite. --- CMakeLists.txt | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index acf3aa5c..e20020a6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -71,22 +71,22 @@ else() set_target_properties(testing_test PROPERTIES UNITY_BUILD ON) set_target_properties(filesystem_test PROPERTIES UNITY_BUILD ON) set_target_properties(meta_test PROPERTIES UNITY_BUILD ON) - #set_target_properties(memory_test PROPERTIES UNITY_BUILD ON) - #set_target_properties(concurrency_test PROPERTIES UNITY_BUILD ON) - #set_target_properties(serialization_test PROPERTIES UNITY_BUILD ON) + set_target_properties(memory_test PROPERTIES UNITY_BUILD ON) + set_target_properties(concurrency_test PROPERTIES UNITY_BUILD ON) + set_target_properties(serialization_test PROPERTIES UNITY_BUILD ON) set_target_properties(crypto_test PROPERTIES UNITY_BUILD ON) - #set_target_properties(math_test PROPERTIES UNITY_BUILD ON) + set_target_properties(math_test PROPERTIES UNITY_BUILD ON) set_target_properties(audio_test PROPERTIES UNITY_BUILD ON) set_target_properties(hid_test PROPERTIES UNITY_BUILD ON) - #set_target_properties(nodegraph_test PROPERTIES UNITY_BUILD ON) + set_target_properties(nodegraph_test PROPERTIES UNITY_BUILD ON) - #set_target_properties(network_test PROPERTIES UNITY_BUILD ON) + set_target_properties(network_test PROPERTIES UNITY_BUILD ON) set_target_properties(storage_test PROPERTIES UNITY_BUILD ON) set_target_properties(tools_test PROPERTIES UNITY_BUILD ON) - #set_target_properties(physics_test PROPERTIES UNITY_BUILD ON) + set_target_properties(physics_test PROPERTIES UNITY_BUILD ON) #set_target_properties(ecs_test PROPERTIES UNITY_BUILD ON) - #set_target_properties(rendering_test PROPERTIES UNITY_BUILD ON) + set_target_properties(rendering_test PROPERTIES UNITY_BUILD ON) endif() From e1d9a4b7732cf8b3d74561a17899b19c19262bfe Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 23 Aug 2025 02:03:50 +0200 Subject: [PATCH 080/179] Clean up picker tooltip. Add a few node descriptions. --- packages/logging/include/logging/String.h | 9 +++++++++ packages/nodegraph/source/common/NodeGraphSchema.cpp | 6 +++--- packages/rendering/include/rendering/ui/UINodeEditor.h | 2 +- packages/rendering/source/common/ui/UINodeEditor.cpp | 6 +++++- 4 files changed, 18 insertions(+), 5 deletions(-) diff --git a/packages/logging/include/logging/String.h b/packages/logging/include/logging/String.h index f18ad1fd..e12842a6 100644 --- a/packages/logging/include/logging/String.h +++ b/packages/logging/include/logging/String.h @@ -53,6 +53,15 @@ namespace l::string { return size() == 0; } + void flush() { + for (size_t i = 0; i < BUFSIZE; i++) { + if (mBuf[i] == 0) { + return; + } + mPos++; + } + } + size_t left() { return static_cast(BUFSIZE - mPos); } diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 32a98163..8ed5fe25 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -624,12 +624,12 @@ namespace l::nodegraph { RegisterNodeType("Math.Logic", 122, "Xor"); } else if (typeGroup == "Math.Numerical") { - RegisterNodeType("Math.Numerical", 140, "Integral"); - RegisterNodeType("Math.Numerical", 141, "Derivate"); + RegisterNodeType("Math.Numerical", 140, "Integral", "Basically a temporal summation node with a EWA on the output with a cooefficient 'friction'"); + RegisterNodeType("Math.Numerical", 141, "Derivate", ""); RegisterNodeType("Math.Numerical", 142, "Difference Normalized"); RegisterNodeType("Math.Numerical", 143, "Difference"); RegisterNodeType("Math.Numerical", 144, "Level Trigger", "Determines where some input is located between two extremes (min/max) in the format [0,1] "); - RegisterNodeType("Math.Numerical", 145, "Minmax Channel"); + RegisterNodeType("Math.Numerical", 145, "Minmax Channel", "Computes the range between the EWA smootherd min/max inputs"); RegisterNodeType("Math.Numerical", 146, "Reconstructor", "Deconstructs the input into derivatives (change per index) and outputs the sum of through a ewa with a cooefficient of 'friction' {x1 = x0 + friction * (target - x0)}. An second output is provided which is the average of the last two outputs of that function."); } else if (typeGroup == "Trading.Data IO") { diff --git a/packages/rendering/include/rendering/ui/UINodeEditor.h b/packages/rendering/include/rendering/ui/UINodeEditor.h index f9e30ea4..031163e4 100644 --- a/packages/rendering/include/rendering/ui/UINodeEditor.h +++ b/packages/rendering/include/rendering/ui/UINodeEditor.h @@ -62,6 +62,6 @@ namespace l::ui { std::vector> mEventListeners; std::function mOverlayContentWindow = nullptr; - l::string::string_buffer<20> mPickerSearch; + //l::string::string_buffer<20> mPickerSearch; }; } diff --git a/packages/rendering/source/common/ui/UINodeEditor.cpp b/packages/rendering/source/common/ui/UINodeEditor.cpp index 891cef55..f848f7ff 100644 --- a/packages/rendering/source/common/ui/UINodeEditor.cpp +++ b/packages/rendering/source/common/ui/UINodeEditor.cpp @@ -50,7 +50,8 @@ namespace l::ui { SetPointerPopup([&]() { ImGui::Text("Node picker"); - ImGui::InputText("find", mPickerSearch.data(), mPickerSearch.capacity(), ImGuiInputTextFlags_EnterReturnsTrue); +// ImGui::SameLine(); +// ImGui::InputText("##pickersearchbar", mPickerSearch.data(), 20); ImGui::Separator(); if (mNGSchema == nullptr) { @@ -59,6 +60,9 @@ namespace l::ui { std::vector path; depthFirstTraversal(mNGSchema->GetPickerRoot(), path, [&](std::string_view menuName, int32_t menuId, std::string_view description) { + //if (mPickerSearch.data() != 0 && !l::string::equal_partial(mPickerSearch.data(), menuName.data(), 0, 0, 20)) { + // return; + //} if (!menuName.empty()) { if (ImGui::MenuItem(menuName.data())) { ImVec2 p = ImVec2(mUIInput.mCurPos.x - GetPosition().x, mUIInput.mCurPos.y - GetPosition().y); From 6d92cffcc49d467c60b66516a350f46fccbce069 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 24 Aug 2025 14:47:35 +0200 Subject: [PATCH 081/179] NG: Add two more util node ops. --- .../operations/NodeGraphOpMathAritmethic.h | 29 +++++++++++++++++++ .../operations/NodeGraphOpMathNumerical.h | 6 ++-- .../nodegraph/operations/NodeGraphOpSource.h | 26 +++++++++++++++++ .../operations/NodeGraphOpTradingFilter.h | 4 +-- .../source/common/NodeGraphSchema.cpp | 8 +++++ .../common/operations/NodeGraphOpSource.cpp | 25 ++++++++++++++++ 6 files changed, 93 insertions(+), 5 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h index fca23f03..00968f51 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h @@ -297,4 +297,33 @@ namespace l::nodegraph { } } }; + + /*********************************************************************/ + class MathAritmethicSum5 : public NodeGraphOp { + public: + MathAritmethicSum5(NodeGraphBase* node) : + NodeGraphOp(node, "Sum5") + { + AddInput("a"); + AddInput("b"); + AddInput("c"); + AddInput("d"); + AddInput("e"); + AddOutput("sum"); + } + virtual ~MathAritmethicSum5() = default; + virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { + auto input0 = inputs.at(0).GetIterator(numSamples); + auto input1 = inputs.at(1).GetIterator(numSamples); + auto input2 = inputs.at(2).GetIterator(numSamples); + auto input3 = inputs.at(3).GetIterator(numSamples); + auto input4 = inputs.at(4).GetIterator(numSamples); + auto output = &outputs.at(0).Get(numSamples); + + for (int32_t i = 0; i < numSamples; i++) { + *output++ = *input0++ + *input1++ + *input2++ + *input3++ + *input4++; + } + } + }; + } \ No newline at end of file diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index d0f2df87..17b1896d 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -127,9 +127,9 @@ namespace l::nodegraph { MathNumericalMinMaxChannel(NodeGraphBase* node) : NodeGraphOp(node, "Minmax Channel") { - AddInput2("Upper Bound"); - AddInput2("Lower Bound"); - AddInput2("Bounded Value"); + AddInput("Max", 1.0f, 1); + AddInput("Min", 0.0f, 1); + AddInput2("In"); AddInput("Friction", 1.0f, 1, 0.0f, 1.0f); AddOutput2("Range"); diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSource.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSource.h index 9c717fa5..626bc3e7 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSource.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSource.h @@ -112,5 +112,31 @@ namespace l::nodegraph { } virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; }; + + /*********************************************************************/ + class GraphSourceConstants2 : public NodeGraphOp { + public: + GraphSourceConstants2(NodeGraphBase* node) : + NodeGraphOp(node, "Constants2") + { + AddConstant("1"); + AddConstant("2"); + AddConstant("3"); + AddConstant("4"); + AddConstant("Min"); + AddConstant("Max"); + + AddOutput("Out 1"); + AddOutput("Out 2"); + AddOutput("Out 3"); + AddOutput("Out 3"); + } + + virtual ~GraphSourceConstants2() { + } + virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + protected: + }; + } diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingFilter.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingFilter.h index 6ddfa922..b51f3c66 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingFilter.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingFilter.h @@ -29,8 +29,8 @@ namespace l::nodegraph { NodeGraphOp(node, "Flip Gate") { AddInput("In", 0.0f); - AddInput("Pos Max Hold", 0.0f, 1, 0.0f, l::math::constants::FLTMAX); - AddInput("Neg Max Hold", 0.0f, 1, 0.0f, l::math::constants::FLTMAX); + AddInput("Sustain Pos", 0.0f, 1, 0.0f, l::math::constants::FLTMAX); + AddInput("Sustain Neg", 0.0f, 1, 0.0f, l::math::constants::FLTMAX); AddOutput("Gate Hold", 0.0f); AddOutput("Gate", 0.0f); } diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 8ed5fe25..50b971ef 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -222,6 +222,9 @@ namespace l::nodegraph { case 5: node = mMainNodeGraph.NewNode(id, NodeType::Default); break; + case 6: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; // Internal output like NG chart or debug view case 20: @@ -281,6 +284,9 @@ namespace l::nodegraph { case 110: node = mMainNodeGraph.NewNode(id, NodeType::Default); break; + case 111: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; // Math logical operators case 120: @@ -594,6 +600,7 @@ namespace l::nodegraph { RegisterNodeType("Node Graph.Source", 3, "Value [-inf,inf]"); RegisterNodeType("Node Graph.Source", 4, "Time"); RegisterNodeType("Node Graph.Source", 5, "Text"); + RegisterNodeType("Node Graph.Source", 6, "Constants"); } else if (typeGroup == "Node Graph.Output") { RegisterNodeType("Node Graph.Output", 20, "Debug"); @@ -617,6 +624,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Aritmethic", 108, "Round"); RegisterNodeType("Math.Aritmethic", 109, "Pow"); RegisterNodeType("Math.Aritmethic", 110, "Sum3"); + RegisterNodeType("Math.Aritmethic", 111, "Sum5"); } else if (typeGroup == "Math.Logic") { RegisterNodeType("Math.Logic", 120, "And"); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpSource.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpSource.cpp index a49ee57a..6cb8d874 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpSource.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpSource.cpp @@ -91,4 +91,29 @@ namespace l::nodegraph { auto textIn = inputs.at(0).GetText(16); outputs.at(0).SetText(textIn); } + + /*********************************************************************/ + void GraphSourceConstants2::Process(int32_t, int32_t, std::vector& inputs, std::vector& outputs) { + auto input0 = &inputs.at(0).Get(); + auto input1 = &inputs.at(1).Get(); + auto input2 = &inputs.at(2).Get(); + auto input3 = &inputs.at(3).Get(); + auto min = inputs.at(4).Get(); + auto max = inputs.at(5).Get(); + auto output0 = outputs.at(0).GetIterator(1); + auto output1 = outputs.at(1).GetIterator(1); + auto output2 = outputs.at(2).GetIterator(1); + auto output3 = outputs.at(3).GetIterator(1); + + for (int8_t i = 0; i < mNumOutputs; i++) { + *input0 = l::math::clamp(*input0, min, max); + *input1 = l::math::clamp(*input1, min, max); + *input2 = l::math::clamp(*input2, min, max); + *input3 = l::math::clamp(*input3, min, max); + *output0 = *input0; + *output1 = *input1; + *output2 = *input2; + *output3 = *input3; + } + } } From addedf2f3b9e701bbe3b90c35b3bbe2df3a3a77d Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 25 Aug 2025 11:51:13 +0200 Subject: [PATCH 082/179] Some fixes. --- .../operations/NodeGraphOpSignalGenerator.h | 2 +- .../operations/NodeGraphOpTradingDataIO.h | 4 ++++ .../operations/NodeGraphOpSignalGenerator.cpp | 24 +++++++++++++++---- .../operations/NodeGraphOpTradingDataIO.cpp | 10 +++++++- 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalGenerator.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalGenerator.h index 002b81a8..22525d59 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalGenerator.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalGenerator.h @@ -253,7 +253,6 @@ namespace l::nodegraph { float mVolume = 0.0f; double mFmod = 0.0; double mPmod = 0.0; - float mReset = 0.0f; double mWave = 0.0; double mDeltaTime = 0.0; @@ -263,6 +262,7 @@ namespace l::nodegraph { double mPhaseFmod = 0.0; float mSamplesUntilUpdate = 0.0f; + int32_t mReadSamples = 0; }; /*********************************************************************/ diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h index 794c75cd..16cb68e4 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h @@ -97,11 +97,15 @@ namespace l::nodegraph { AddOutput("Index#2", 2.0f); AddOutput("Index#3", 3.0f); AddOutput("Now"); + AddOutput("Reset"); } virtual ~TradingDataIOChartInfo() = default; virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + + protected: + int32_t mReadSamples = 0; }; } \ No newline at end of file diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpSignalGenerator.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpSignalGenerator.cpp index b6090f72..4f4ce4df 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpSignalGenerator.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpSignalGenerator.cpp @@ -120,25 +120,34 @@ namespace l::nodegraph { } /*********************************************************************/ - void SignalGeneratorSine::Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) { + void SignalGeneratorSine::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { float* output0 = &outputs.at(0).Get(numSamples); float updateRate = 256.0f; + if (mReadSamples == 0) { + auto reset = inputs.at(5).Get(); + if (reset > 0.0f) { + mVolume = 0.0f; + mVol = 0.0f; + + mPhase = 0.0f; + mPhaseFmod = 0.0f; + mWave = 0.0f; + mSamplesUntilUpdate = 0.0f; + } + } + mSamplesUntilUpdate = l::audio::BatchUpdate(updateRate, mSamplesUntilUpdate, 0, numSamples, [&]() { mFreq = l::math::max2(static_cast(inputs.at(0).Get()), 0.0); mVolume = inputs.at(1).Get(); - mReset = inputs.at(5).Get(); if (mFreq == 0.0f) { mVolume = 0.0f; outputs.at(0).mOutput = 0.0f; return updateRate; } - if (mReset > 0.5f) { - mVolume = 0.0f; - } mDeltaTime = 1.0 / 44100.0; return updateRate; @@ -191,6 +200,11 @@ namespace l::nodegraph { } } ); + + mReadSamples += numSamples; + if (mReadSamples >= numCacheSamples) { + mReadSamples = 0; + } } /*********************************************************************/ diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp index 2aeeb5c7..115c1889 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp @@ -167,7 +167,7 @@ namespace l::nodegraph { } } - void TradingDataIOChartInfo::Process(int32_t, int32_t, std::vector& inputs, std::vector& outputs) { + void TradingDataIOChartInfo::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto symbolInput = inputs.at(0).GetText(16); auto baseInput = inputs.at(1).GetText(16); auto indexInput = l::math::clamp(inputs.at(2).Get(), 0.0f, 9.9999f); @@ -180,11 +180,19 @@ namespace l::nodegraph { float* indexOut2 = &outputs.at(4).Get(); float* indexOut3 = &outputs.at(5).Get(); float* nowOutput = &outputs.at(6).Get(); + float* resetOutput = &outputs.at(7).Get(); + *indexOut0 = l::math::clamp(indexInput, 0.0f, 9.9999f); *indexOut1 = l::math::clamp(indexInput + 1.0f, 0.0f, 9.9999f); *indexOut2 = l::math::clamp(indexInput + 2.0f, 0.0f, 9.9999f); *indexOut3 = l::math::clamp(indexInput + 3.0f, 0.0f, 9.9999f); *nowOutput = now; + *resetOutput = mReadSamples == 0; + + mReadSamples += numSamples; + if (mReadSamples >= numCacheSamples) { + mReadSamples = 0; + } } } From 20aa863859575d2f07ce893198320eb2b565e458 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 25 Aug 2025 22:32:50 +0200 Subject: [PATCH 083/179] NG: Fix error in ochlv reset state. --- .../operations/NodeGraphOpTradingDataIO.cpp | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp index 115c1889..5bded53b 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp @@ -25,10 +25,6 @@ namespace l::nodegraph { void TradingDataIOOCHLVDataIn::ProcessReadCached(int32_t readSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { - if (readSamples == 0) { - mUnixtimePrev = 0; - } - int32_t stride = 9; inputs.at(0).MinimizeBuffer(numCacheSamples * stride); @@ -50,6 +46,12 @@ namespace l::nodegraph { auto intervalMinutes = static_cast(outputs.at(2).Get(1) + 0.5f); + bool reset = false; + if (mReadSamples == 0) { + reset = true; + mUnixtimePrev = 0; + } + if (mMode == 0) { for (int32_t j = 0; j < numSamples; j++) { auto offset = j * stride; @@ -67,7 +69,6 @@ namespace l::nodegraph { mUnixtimePrev = unixtime; } - *out1++ = unixtimef; // unixtime auto o = in[offset + 1]; auto c = in[offset + 2]; auto h = in[offset + 3]; @@ -78,7 +79,8 @@ namespace l::nodegraph { auto bq = in[offset + 8]; // buy quantity auto timemin = unixtime / 60; - if (timemin % timeframeMultiplier == 0) { + if (reset || timemin % timeframeMultiplier == 0) { + reset = false; // time interval looping so reset moving averages mOpenMa = o; // simply first value mCloseMa = c; @@ -109,6 +111,7 @@ namespace l::nodegraph { mBuyQuantMa += bq; } + *out1++ = unixtimef; // unixtime *out2++ = mOpenMa; *out3++ = mCloseMa; *out4++ = mHighMa; @@ -139,7 +142,6 @@ namespace l::nodegraph { mUnixtimePrev = unixtime; } - *out1++ = unixtimef; // unixtime auto o = in[offset + 1]; auto c = in[offset + 2]; auto h = in[offset + 3]; @@ -153,6 +155,7 @@ namespace l::nodegraph { mOpenPrev = open; mClosePrev = close; + *out1++ = unixtimef; // unixtime *out2++ = open; *out3++ = close; *out4++ = high; From cf69a1fba1f789de861d63a18080577ed809ec37 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 26 Aug 2025 19:54:39 +0200 Subject: [PATCH 084/179] NG: Add a numerical trend node. --- deps/ldeps | 1 - .../operations/NodeGraphOpMathNumerical.h | 33 +++++++++ .../source/common/NodeGraphSchema.cpp | 6 +- .../operations/NodeGraphOpMathNumerical.cpp | 74 ++++++++++++++++++- 4 files changed, 111 insertions(+), 3 deletions(-) delete mode 160000 deps/ldeps diff --git a/deps/ldeps b/deps/ldeps deleted file mode 160000 index d8737f06..00000000 --- a/deps/ldeps +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d8737f06d951387d98928c0f70d6f34c1b935f7d diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 17b1896d..8e3e3c48 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -177,4 +177,37 @@ namespace l::nodegraph { float mOutput1 = 0.0f; float mOutput2 = 0.0f; }; + + /*********************************************************************/ + class MathNumericalTrends : public NodeGraphOp { + public: + MathNumericalTrends(NodeGraphBase* node) : + NodeGraphOp(node, "Trends") + { + AddInput2("In1"); + AddInput2("In2"); + AddInput("Friction1", 1.0f, 1, 0.0f, 1.0f); + AddInput("Friction2", 1.0f, 1, 0.0f, 1.0f); + + AddOutput2("Trend1"); + AddOutput2("Trend2"); + AddOutput2("Trend Both"); + } + + virtual ~MathNumericalTrends() = default; + virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + protected: + int32_t mReadSamples = 0; + + float mInPrev1 = 0.0f; + float mIn1Prev1 = 0.0f; + float mIn2Prev1 = 0.0f; + + float mInAccum = 0.0f; + float mIn1Accum = 0.0f; + float mIn2Accum = 0.0f; + float mInAccumPrev1 = 0.0f; + float mIn1AccumPrev1 = 0.0f; + float mIn2AccumPrev1 = 0.0f; + }; } \ No newline at end of file diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 50b971ef..2f4b9011 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -321,7 +321,10 @@ namespace l::nodegraph { case 146: node = mMainNodeGraph.NewNode(id, NodeType::Default); break; - + case 147: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; + // Trading data io case 200: node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 0); @@ -639,6 +642,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Numerical", 144, "Level Trigger", "Determines where some input is located between two extremes (min/max) in the format [0,1] "); RegisterNodeType("Math.Numerical", 145, "Minmax Channel", "Computes the range between the EWA smootherd min/max inputs"); RegisterNodeType("Math.Numerical", 146, "Reconstructor", "Deconstructs the input into derivatives (change per index) and outputs the sum of through a ewa with a cooefficient of 'friction' {x1 = x0 + friction * (target - x0)}. An second output is provided which is the average of the last two outputs of that function."); + RegisterNodeType("Math.Numerical", 147, ""); } else if (typeGroup == "Trading.Data IO") { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 140638b6..34ba478c 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -9,6 +9,7 @@ namespace l::nodegraph { + /*********************************************************************/ void MathNumericalIntegral::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto input0 = &inputs.at(0).Get(numSamples); auto friction = inputs.at(1).Get(); @@ -33,6 +34,7 @@ namespace l::nodegraph { } } + /*********************************************************************/ void MathNumericalTemporalChange::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto input0 = &inputs.at(0).Get(numSamples); auto output = &outputs.at(0).Get(numSamples); @@ -56,6 +58,7 @@ namespace l::nodegraph { } } + /*********************************************************************/ void MathNumericalDiffNorm::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto input0 = &inputs.at(0).Get(numSamples); auto output = &outputs.at(0).Get(numSamples); @@ -88,6 +91,7 @@ namespace l::nodegraph { } } + /*********************************************************************/ void MathNumericalDiff::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto input0 = &inputs.at(0).Get(numSamples); auto output = &outputs.at(0).Get(numSamples); @@ -107,6 +111,7 @@ namespace l::nodegraph { } } + /*********************************************************************/ void MathNumericalLevelTrigger::Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) { auto inInput = &inputs.at(0).Get(numSamples); auto maxInput = inputs.at(1).GetIterator(numSamples); @@ -149,6 +154,7 @@ namespace l::nodegraph { } } + /*********************************************************************/ void MathNumericalMinMaxChannel::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto inInput = &inputs.at(0).Get(numSamples); auto upperInput = inputs.at(1).GetIterator(numSamples); @@ -205,8 +211,9 @@ namespace l::nodegraph { } } + /*********************************************************************/ void MathNumericalReconstructor::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { - + auto inInput = &inputs.at(0).Get(numSamples); auto baseInput = inputs.at(1).GetIterator(); @@ -265,4 +272,69 @@ namespace l::nodegraph { } } + /*********************************************************************/ + void MathNumericalTrends::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + + auto in1Input = &inputs.at(0).Get(numSamples); + auto in2Input = &inputs.at(1).Get(numSamples); + auto friction1 = inputs.at(2).Get(); + auto friction2 = inputs.at(3).Get(); + auto frictionFactor1 = l::math::clamp(l::math::pow(friction1, 0.25f), 0.0f, 1.0f); + auto frictionFactor2 = l::math::clamp(l::math::pow(friction2, 0.25f), 0.0f, 1.0f); + + auto trend1Output = &outputs.at(0).Get(numSamples); + auto trend2Output = &outputs.at(1).Get(numSamples); + auto trendOutput = &outputs.at(2).Get(numSamples); + + auto in1Enabled = inputs.at(0).HasInputNode(); + auto in2Enabled = inputs.at(1).HasInputNode(); + + for (int32_t i = 0; i < numSamples; i++) { + float in1 = 0.0f; + float in2 = 0.0f; + + if (in1Enabled) { + in1 = *in1Input++; + } + if (in2Enabled) { + in2 = *in2Input++; + } + + auto in = (in1 + in2) * 0.5f; + + auto in1Diff = in1 - mIn1Prev1; + auto in2Diff = in2 - mIn2Prev1; + auto inDiff = in - mInPrev1; + + mIn1Accum += in1Diff; + mIn1Accum *= frictionFactor2; + mIn2Accum += in2Diff; + mIn2Accum *= frictionFactor2; + mInAccum += inDiff; + mInAccum *= frictionFactor1; + + auto in1Accum = mIn1Accum - mIn1AccumPrev1; + auto in2Accum = mIn2Accum - mIn2AccumPrev1; + auto inAccum = mInAccum - mInAccumPrev1; + + *trend1Output++ = in1Accum; + *trend2Output++ = in2Accum; + *trendOutput++ = inAccum; + + mIn1Prev1 = in1; + mIn2Prev1 = in2; + mInPrev1 = in; + + mIn1AccumPrev1 = mIn1Accum; + mIn2AccumPrev1 = mIn2Accum; + mInAccumPrev1 = mInAccum; + } + + mReadSamples += numSamples; + + if (mReadSamples >= numCacheSamples) { + mReadSamples = 0; + } + } + } From da02412f6dcc1d416dd3c6c4f1716c0fa4635897 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 26 Aug 2025 21:04:38 +0200 Subject: [PATCH 085/179] NG: Add trends node. --- packages/nodegraph/source/common/NodeGraphSchema.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 2f4b9011..2f892d00 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -642,7 +642,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Numerical", 144, "Level Trigger", "Determines where some input is located between two extremes (min/max) in the format [0,1] "); RegisterNodeType("Math.Numerical", 145, "Minmax Channel", "Computes the range between the EWA smootherd min/max inputs"); RegisterNodeType("Math.Numerical", 146, "Reconstructor", "Deconstructs the input into derivatives (change per index) and outputs the sum of through a ewa with a cooefficient of 'friction' {x1 = x0 + friction * (target - x0)}. An second output is provided which is the average of the last two outputs of that function."); - RegisterNodeType("Math.Numerical", 147, ""); + RegisterNodeType("Math.Numerical", 147, "Trends", ""); } else if (typeGroup == "Trading.Data IO") { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); From 04c78af40211527b5536142606d3051eb0f2f27d Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 28 Aug 2025 15:07:37 +0200 Subject: [PATCH 086/179] NG: Change name of filter trends to reconstructor2. Add ATR node. Add amplitude tracking normalizer node. --- .../operations/NodeGraphOpMathNumerical.h | 34 ++++++++++++---- .../operations/NodeGraphOpTradingIndicator.h | 33 +++++++++++++--- .../nodegraph/operations/NodeGraphOpUI.h | 3 +- .../source/common/NodeGraphSchema.cpp | 12 ++++-- .../operations/NodeGraphOpMathNumerical.cpp | 39 +++++++++++++++---- 5 files changed, 96 insertions(+), 25 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 8e3e3c48..fe87e3a4 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -179,22 +179,22 @@ namespace l::nodegraph { }; /*********************************************************************/ - class MathNumericalTrends : public NodeGraphOp { + class MathNumericalReconstructor2 : public NodeGraphOp { public: - MathNumericalTrends(NodeGraphBase* node) : - NodeGraphOp(node, "Trends") + MathNumericalReconstructor2(NodeGraphBase* node) : + NodeGraphOp(node, "Reconstructor 2") { AddInput2("In1"); AddInput2("In2"); AddInput("Friction1", 1.0f, 1, 0.0f, 1.0f); AddInput("Friction2", 1.0f, 1, 0.0f, 1.0f); - AddOutput2("Trend1"); - AddOutput2("Trend2"); - AddOutput2("Trend Both"); + AddOutput2("Intgr1"); + AddOutput2("Intgr1"); + AddOutput2("Intgr Both"); } - virtual ~MathNumericalTrends() = default; + virtual ~MathNumericalReconstructor2() = default; virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; protected: int32_t mReadSamples = 0; @@ -210,4 +210,24 @@ namespace l::nodegraph { float mIn1AccumPrev1 = 0.0f; float mIn2AccumPrev1 = 0.0f; }; + + /*********************************************************************/ + class MathNumericalNormalizer : public nodegraph::NodeGraphOp { + public: + MathNumericalNormalizer(nodegraph::NodeGraphBase* node) : + NodeGraphOp(node, "Normalizer") + { + AddInput2("In"); + AddInput("Friction", 0.5f, 1, 0.0f, 1.0f); + + AddOutput2("Out"); + } + + virtual ~MathNumericalNormalizer() = default; + virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + protected: + float mInAbsPrev = 0.0f; + float mTargetMagnitude = 1.0f; + }; + } \ No newline at end of file diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingIndicator.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingIndicator.h index 6368c640..b7b67ccb 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingIndicator.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingIndicator.h @@ -268,24 +268,45 @@ namespace l::nodegraph { class TradingIndicatorATR : public NodeGraphOp { public: TradingIndicatorATR(NodeGraphBase* node) : - NodeGraphOp(node, "ATR (average true range)") + NodeGraphOp(node, "Average True Range") { - AddInput("In", 0.0f, 1, -l::math::constants::FLTMAX, l::math::constants::FLTMAX, false, false); + AddInput2("Close"); + AddInput2("High"); + AddInput2("Low"); + AddInput("N", 14.0f, 1, 1.0f, 200.0f); + + AddOutput("TR", 0.0f); AddOutput("ATR", 0.0f); } virtual ~TradingIndicatorATR() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { - auto input = inputs.at(0).GetIterator(numSamples); - auto output = outputs.at(0).GetIterator(numSamples); + auto closeInput = &inputs.at(0).Get(numSamples); + auto highInput = &inputs.at(1).Get(numSamples); + auto lowInput = &inputs.at(2).Get(numSamples); + auto periodN = static_cast(l::math::max2(1.0f, inputs.at(3).Get())); + + auto trOutput = &outputs.at(0).Get(numSamples); + auto atrOutput = &outputs.at(1).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { - float in = *input++; - *output++ = in; + float close = *closeInput++; + float high = *highInput++; + float low = *lowInput++; + + auto trueRange = l::math::max3(high - low, l::math::abs(high) - mClosePrev, l::math::abs(low) - mClosePrev); + auto atr = (mATRPrev * static_cast(periodN - 1) + trueRange) / static_cast(periodN); + *trOutput++ = trueRange; + *atrOutput++ = atr; + + mClosePrev = close; + mATRPrev = atr; } } protected: + float mClosePrev = 0.0f; + float mATRPrev = 0.0f; }; /*********************************************************************/ diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index 03007806..b1963381 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -179,8 +179,9 @@ namespace l::nodegraph { float GetProfit(float slip) { if (mEntry > 0.0f && mExit > 0.0f) { + auto entry = mEntry * (1.0f + slip); // entry commission auto change = mExit / mEntry; - change = change * (1.0f - slip); + change = change * (1.0f - slip); // exit commission change = 1.0f + (change - 1.0f) * mLotShare; return change; } diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 2f892d00..1d0316ed 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -322,9 +322,12 @@ namespace l::nodegraph { node = mMainNodeGraph.NewNode(id, NodeType::Default); break; case 147: - node = mMainNodeGraph.NewNode(id, NodeType::Default); + node = mMainNodeGraph.NewNode(id, NodeType::Default); break; - + case 148: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; + // Trading data io case 200: node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 0); @@ -642,7 +645,8 @@ namespace l::nodegraph { RegisterNodeType("Math.Numerical", 144, "Level Trigger", "Determines where some input is located between two extremes (min/max) in the format [0,1] "); RegisterNodeType("Math.Numerical", 145, "Minmax Channel", "Computes the range between the EWA smootherd min/max inputs"); RegisterNodeType("Math.Numerical", 146, "Reconstructor", "Deconstructs the input into derivatives (change per index) and outputs the sum of through a ewa with a cooefficient of 'friction' {x1 = x0 + friction * (target - x0)}. An second output is provided which is the average of the last two outputs of that function."); - RegisterNodeType("Math.Numerical", 147, "Trends", ""); + RegisterNodeType("Math.Numerical", 147, "Reconstructor 2", ""); + RegisterNodeType("Math.Numerical", 148, "Normalizer", "Tracks the magnitude with an internal EMA and divides the input by its length"); } else if (typeGroup == "Trading.Data IO") { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); @@ -664,7 +668,7 @@ namespace l::nodegraph { RegisterNodeType("Trading.Indicator", 262, "On-Balance Volume 2 (OBV2)"); RegisterNodeType("Trading.Indicator", 263, "Gated Accumulation (GA)"); //RegisterNodeType("Trading.Indicator", 264, "Volume Relative Strength Index (VRSI)"); - //RegisterNodeType("Trading.Indicator", 265, "Average True Range (ATR)"); + RegisterNodeType("Trading.Indicator", 265, "Average True Range (ATR)"); } else if (typeGroup == "Signal.Generator") { RegisterNodeType("Signal.Generator", 300, "Sine"); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 34ba478c..e2dc85aa 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -273,7 +273,7 @@ namespace l::nodegraph { } /*********************************************************************/ - void MathNumericalTrends::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + void MathNumericalReconstructor2::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto in1Input = &inputs.at(0).Get(numSamples); auto in2Input = &inputs.at(1).Get(numSamples); @@ -282,9 +282,9 @@ namespace l::nodegraph { auto frictionFactor1 = l::math::clamp(l::math::pow(friction1, 0.25f), 0.0f, 1.0f); auto frictionFactor2 = l::math::clamp(l::math::pow(friction2, 0.25f), 0.0f, 1.0f); - auto trend1Output = &outputs.at(0).Get(numSamples); - auto trend2Output = &outputs.at(1).Get(numSamples); - auto trendOutput = &outputs.at(2).Get(numSamples); + auto intgr1Output = &outputs.at(0).Get(numSamples); + auto intgr2Output = &outputs.at(1).Get(numSamples); + auto intgrBothOutput = &outputs.at(2).Get(numSamples); auto in1Enabled = inputs.at(0).HasInputNode(); auto in2Enabled = inputs.at(1).HasInputNode(); @@ -317,9 +317,9 @@ namespace l::nodegraph { auto in2Accum = mIn2Accum - mIn2AccumPrev1; auto inAccum = mInAccum - mInAccumPrev1; - *trend1Output++ = in1Accum; - *trend2Output++ = in2Accum; - *trendOutput++ = inAccum; + *intgr1Output++ = in1Accum; + *intgr2Output++ = in2Accum; + *intgrBothOutput++ = inAccum; mIn1Prev1 = in1; mIn2Prev1 = in2; @@ -337,4 +337,29 @@ namespace l::nodegraph { } } + /*********************************************************************/ + void MathNumericalNormalizer::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + auto inInput = &inputs.at(0).Get(numSamples); + auto friction = inputs.at(1).Get(); + + auto outOutput = &outputs.at(0).Get(numSamples); + + for (int32_t i = 0; i < numSamples; i++) { + float in = *inInput++; + + auto inAbs = l::math::abs(in); + if (inAbs < mInAbsPrev) { + mTargetMagnitude += 0.5f * friction * (-mTargetMagnitude); // decreasing magnitude is half as strong + } + else { + mTargetMagnitude += friction * (-mTargetMagnitude); + } + + auto out = in / mTargetMagnitude; + + *outOutput++ = out; + + mInAbsPrev = inAbs; + } + } } From 657468eec646846174523eac56374bccc1085b54 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 28 Aug 2025 16:44:52 +0200 Subject: [PATCH 087/179] NG: Fix some errors. --- .../operations/NodeGraphOpMathNumerical.h | 3 ++- .../include/nodegraph/operations/NodeGraphOpUI.h | 2 +- .../operations/NodeGraphOpMathNumerical.cpp | 16 +++++++++++++--- 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index fe87e3a4..6981a12d 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -226,8 +226,9 @@ namespace l::nodegraph { virtual ~MathNumericalNormalizer() = default; virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; protected: + int32_t mReadSamples = 0; float mInAbsPrev = 0.0f; - float mTargetMagnitude = 1.0f; + float mEmaMagnitude = 1.0f; }; } \ No newline at end of file diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index b1963381..a59f0d3f 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -180,7 +180,7 @@ namespace l::nodegraph { float GetProfit(float slip) { if (mEntry > 0.0f && mExit > 0.0f) { auto entry = mEntry * (1.0f + slip); // entry commission - auto change = mExit / mEntry; + auto change = mExit / entry; change = change * (1.0f - slip); // exit commission change = 1.0f + (change - 1.0f) * mLotShare; return change; diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index e2dc85aa..ec2b3d1d 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -344,22 +344,32 @@ namespace l::nodegraph { auto outOutput = &outputs.at(0).Get(numSamples); + if (mReadSamples == 0) { + mEmaMagnitude = 0.0f; + mInAbsPrev = l::math::abs(*inInput); + } + for (int32_t i = 0; i < numSamples; i++) { float in = *inInput++; auto inAbs = l::math::abs(in); if (inAbs < mInAbsPrev) { - mTargetMagnitude += 0.5f * friction * (-mTargetMagnitude); // decreasing magnitude is half as strong + mEmaMagnitude += 0.5f * friction * (inAbs - mEmaMagnitude); // decreasing magnitude is half as strong } else { - mTargetMagnitude += friction * (-mTargetMagnitude); + mEmaMagnitude += friction * (inAbs - mEmaMagnitude); } - auto out = in / mTargetMagnitude; + auto out = in / mEmaMagnitude; *outOutput++ = out; mInAbsPrev = inAbs; } + + mReadSamples += numSamples; + if (mReadSamples == numCacheSamples) { + mReadSamples = 0; + } } } From f2ffa4a0ea15896cd34e2232ecdd1e440e1ca868 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 28 Aug 2025 17:03:29 +0200 Subject: [PATCH 088/179] NG: Change normalizer to sigmoid to map input to unit area. --- .../operations/NodeGraphOpMathNumerical.h | 13 ++++----- .../source/common/NodeGraphSchema.cpp | 4 +-- .../operations/NodeGraphOpMathNumerical.cpp | 28 ++----------------- 3 files changed, 10 insertions(+), 35 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 6981a12d..1c26a494 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -212,23 +212,20 @@ namespace l::nodegraph { }; /*********************************************************************/ - class MathNumericalNormalizer : public nodegraph::NodeGraphOp { + class MathNumericalSigmoid : public nodegraph::NodeGraphOp { public: - MathNumericalNormalizer(nodegraph::NodeGraphBase* node) : - NodeGraphOp(node, "Normalizer") + MathNumericalSigmoid(nodegraph::NodeGraphBase* node) : + NodeGraphOp(node, "Sigmoid") { AddInput2("In"); - AddInput("Friction", 0.5f, 1, 0.0f, 1.0f); + AddInput("Scale", 0.5f, 1, 0.0f, 100.0f); AddOutput2("Out"); } - virtual ~MathNumericalNormalizer() = default; + virtual ~MathNumericalSigmoid() = default; virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; protected: - int32_t mReadSamples = 0; - float mInAbsPrev = 0.0f; - float mEmaMagnitude = 1.0f; }; } \ No newline at end of file diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 1d0316ed..d3120754 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -325,7 +325,7 @@ namespace l::nodegraph { node = mMainNodeGraph.NewNode(id, NodeType::Default); break; case 148: - node = mMainNodeGraph.NewNode(id, NodeType::Default); + node = mMainNodeGraph.NewNode(id, NodeType::Default); break; // Trading data io @@ -646,7 +646,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Numerical", 145, "Minmax Channel", "Computes the range between the EWA smootherd min/max inputs"); RegisterNodeType("Math.Numerical", 146, "Reconstructor", "Deconstructs the input into derivatives (change per index) and outputs the sum of through a ewa with a cooefficient of 'friction' {x1 = x0 + friction * (target - x0)}. An second output is provided which is the average of the last two outputs of that function."); RegisterNodeType("Math.Numerical", 147, "Reconstructor 2", ""); - RegisterNodeType("Math.Numerical", 148, "Normalizer", "Tracks the magnitude with an internal EMA and divides the input by its length"); + RegisterNodeType("Math.Numerical", 148, "Sigmoid", "Maps the input to [-1,1] via a sigmoid function. A scale factor can be provided that changes the mapping"); } else if (typeGroup == "Trading.Data IO") { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index ec2b3d1d..86aff23d 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -338,38 +338,16 @@ namespace l::nodegraph { } /*********************************************************************/ - void MathNumericalNormalizer::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + void MathNumericalSigmoid::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto inInput = &inputs.at(0).Get(numSamples); - auto friction = inputs.at(1).Get(); + auto k = inputs.at(1).Get(); auto outOutput = &outputs.at(0).Get(numSamples); - if (mReadSamples == 0) { - mEmaMagnitude = 0.0f; - mInAbsPrev = l::math::abs(*inInput); - } - for (int32_t i = 0; i < numSamples; i++) { float in = *inInput++; - - auto inAbs = l::math::abs(in); - if (inAbs < mInAbsPrev) { - mEmaMagnitude += 0.5f * friction * (inAbs - mEmaMagnitude); // decreasing magnitude is half as strong - } - else { - mEmaMagnitude += friction * (inAbs - mEmaMagnitude); - } - - auto out = in / mEmaMagnitude; - + auto out = l::math::functions::sigmoid(in, k); *outOutput++ = out; - - mInAbsPrev = inAbs; - } - - mReadSamples += numSamples; - if (mReadSamples == numCacheSamples) { - mReadSamples = 0; } } } From 1452d59d8d8206208cbb40b3971216f0c1a25493 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 28 Aug 2025 17:23:13 +0200 Subject: [PATCH 089/179] NG: Change sigmoid to unitmap and remap to -1,1 interval. --- packages/math/include/math/MathFunc.h | 1 + .../nodegraph/operations/NodeGraphOpMathNumerical.h | 8 ++++---- packages/nodegraph/source/common/NodeGraphSchema.cpp | 4 ++-- .../source/common/operations/NodeGraphOpMathNumerical.cpp | 4 ++-- 4 files changed, 9 insertions(+), 8 deletions(-) diff --git a/packages/math/include/math/MathFunc.h b/packages/math/include/math/MathFunc.h index 99745b66..efe46bc0 100644 --- a/packages/math/include/math/MathFunc.h +++ b/packages/math/include/math/MathFunc.h @@ -403,6 +403,7 @@ namespace l::math::functions { return k * math::pow(x, a) * math::pow(1.0 - x, b); } + // Sigmoid function maps the input to the interval [0,1] for [0,inf] input ([1] maps to [0.5]). template auto sigmoid(T x, T k) { return static_cast(static_cast(1.0) / (static_cast(1.0) + math::exp(-x * k))); diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 1c26a494..bbcee0f3 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -212,10 +212,10 @@ namespace l::nodegraph { }; /*********************************************************************/ - class MathNumericalSigmoid : public nodegraph::NodeGraphOp { + class MathNumericalUnitmap : public nodegraph::NodeGraphOp { public: - MathNumericalSigmoid(nodegraph::NodeGraphBase* node) : - NodeGraphOp(node, "Sigmoid") + MathNumericalUnitmap(nodegraph::NodeGraphBase* node) : + NodeGraphOp(node, "Unitmap") { AddInput2("In"); AddInput("Scale", 0.5f, 1, 0.0f, 100.0f); @@ -223,7 +223,7 @@ namespace l::nodegraph { AddOutput2("Out"); } - virtual ~MathNumericalSigmoid() = default; + virtual ~MathNumericalUnitmap() = default; virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; protected: }; diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index d3120754..717754cb 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -325,7 +325,7 @@ namespace l::nodegraph { node = mMainNodeGraph.NewNode(id, NodeType::Default); break; case 148: - node = mMainNodeGraph.NewNode(id, NodeType::Default); + node = mMainNodeGraph.NewNode(id, NodeType::Default); break; // Trading data io @@ -646,7 +646,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Numerical", 145, "Minmax Channel", "Computes the range between the EWA smootherd min/max inputs"); RegisterNodeType("Math.Numerical", 146, "Reconstructor", "Deconstructs the input into derivatives (change per index) and outputs the sum of through a ewa with a cooefficient of 'friction' {x1 = x0 + friction * (target - x0)}. An second output is provided which is the average of the last two outputs of that function."); RegisterNodeType("Math.Numerical", 147, "Reconstructor 2", ""); - RegisterNodeType("Math.Numerical", 148, "Sigmoid", "Maps the input to [-1,1] via a sigmoid function. A scale factor can be provided that changes the mapping"); + RegisterNodeType("Math.Numerical", 148, "Unitmap", "Maps the input to [-1,1] via a sigmoid function. A scale factor can be provided that changes the shape of the mapping"); } else if (typeGroup == "Trading.Data IO") { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 86aff23d..403eb817 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -338,7 +338,7 @@ namespace l::nodegraph { } /*********************************************************************/ - void MathNumericalSigmoid::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + void MathNumericalUnitmap::Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) { auto inInput = &inputs.at(0).Get(numSamples); auto k = inputs.at(1).Get(); @@ -346,7 +346,7 @@ namespace l::nodegraph { for (int32_t i = 0; i < numSamples; i++) { float in = *inInput++; - auto out = l::math::functions::sigmoid(in, k); + auto out = l::math::functions::sigmoid(in, k) * 2.0f - 1.0f; *outOutput++ = out; } } From 717b7121b2cf9a17f6920a0d23868fcd1178563c Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 2 Sep 2025 01:03:21 +0200 Subject: [PATCH 090/179] NG: Add ema node. Fix some reset errors. --- .../operations/NodeGraphOpMathNumerical.h | 24 ++++++++- .../operations/NodeGraphOpTradingIndicator.h | 4 +- .../source/common/NodeGraphSchema.cpp | 4 ++ .../operations/NodeGraphOpMathNumerical.cpp | 52 ++++++++++++++++++- 4 files changed, 79 insertions(+), 5 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index bbcee0f3..336c560c 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -218,7 +218,8 @@ namespace l::nodegraph { NodeGraphOp(node, "Unitmap") { AddInput2("In"); - AddInput("Scale", 0.5f, 1, 0.0f, 100.0f); + AddInput("Scale", 0.5f, 1, 0.0f, 100000.0f); + AddInput("Offset", 0.0f, 1, -1.0f, 1.0f); AddOutput2("Out"); } @@ -228,4 +229,25 @@ namespace l::nodegraph { protected: }; + /*********************************************************************/ + class MathNumericalEMA : public nodegraph::NodeGraphOp { + public: + MathNumericalEMA(nodegraph::NodeGraphBase* node) : + NodeGraphOp(node, "EMA") + { + AddInput2("In"); + AddInput("N", 14.0f, 1, 1.0f, 1000.0f); + AddInput("Zero", 0.0f, 1, 0.0f, 1.0f); + + AddOutput2("Out"); + } + + virtual ~MathNumericalEMA() = default; + virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + protected: + int32_t mReadSamples = 0; + + float mEmaAccum = 0.0f; + }; + } \ No newline at end of file diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingIndicator.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingIndicator.h index b7b67ccb..671b497e 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingIndicator.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingIndicator.h @@ -284,7 +284,7 @@ namespace l::nodegraph { auto closeInput = &inputs.at(0).Get(numSamples); auto highInput = &inputs.at(1).Get(numSamples); auto lowInput = &inputs.at(2).Get(numSamples); - auto periodN = static_cast(l::math::max2(1.0f, inputs.at(3).Get())); + auto periodN = l::math::max2(1.0f, inputs.at(3).Get()); auto trOutput = &outputs.at(0).Get(numSamples); auto atrOutput = &outputs.at(1).Get(numSamples); @@ -295,7 +295,7 @@ namespace l::nodegraph { float low = *lowInput++; auto trueRange = l::math::max3(high - low, l::math::abs(high) - mClosePrev, l::math::abs(low) - mClosePrev); - auto atr = (mATRPrev * static_cast(periodN - 1) + trueRange) / static_cast(periodN); + auto atr = (mATRPrev * (periodN - 1.0f) + trueRange) / periodN; *trOutput++ = trueRange; *atrOutput++ = atr; diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 717754cb..33442176 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -327,6 +327,9 @@ namespace l::nodegraph { case 148: node = mMainNodeGraph.NewNode(id, NodeType::Default); break; + case 149: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; // Trading data io case 200: @@ -647,6 +650,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Numerical", 146, "Reconstructor", "Deconstructs the input into derivatives (change per index) and outputs the sum of through a ewa with a cooefficient of 'friction' {x1 = x0 + friction * (target - x0)}. An second output is provided which is the average of the last two outputs of that function."); RegisterNodeType("Math.Numerical", 147, "Reconstructor 2", ""); RegisterNodeType("Math.Numerical", 148, "Unitmap", "Maps the input to [-1,1] via a sigmoid function. A scale factor can be provided that changes the shape of the mapping"); + RegisterNodeType("Math.Numerical", 149, "EMA", "Exponential moving average [ema1=(ema0*(n-1)+input)/n]"); } else if (typeGroup == "Trading.Data IO") { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 403eb817..e2778765 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -232,6 +232,10 @@ namespace l::nodegraph { auto outputIntegral2 = &outputs.at(4).Get(numSamples); auto outputBase2 = &outputs.at(5).Get(numSamples); + if (mReadSamples == 0) { + mInputPrev = *inInput; + + } for (int32_t i = 0; i < numSamples; i++) { float in = *inInput++; auto base = *baseInput++; @@ -289,6 +293,18 @@ namespace l::nodegraph { auto in1Enabled = inputs.at(0).HasInputNode(); auto in2Enabled = inputs.at(1).HasInputNode(); + if (mReadSamples == 0) { + mIn1Prev1 = 0.0f; + mIn2Prev1 = 0.0f; + + if (in1Enabled) { + mIn1Prev1 = *in1Input; + } + if (in2Enabled) { + mIn2Prev1 = *in2Input; + } + mInPrev1 = (mIn1Prev1 + mIn2Prev1) * 0.5f; + } for (int32_t i = 0; i < numSamples; i++) { float in1 = 0.0f; float in2 = 0.0f; @@ -340,14 +356,46 @@ namespace l::nodegraph { /*********************************************************************/ void MathNumericalUnitmap::Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) { auto inInput = &inputs.at(0).Get(numSamples); - auto k = inputs.at(1).Get(); + auto k = l::math::pow(inputs.at(1).Get(), 2.0f); + auto offs = inputs.at(2).Get(); + offs = offs * offs * offs; auto outOutput = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { float in = *inInput++; auto out = l::math::functions::sigmoid(in, k) * 2.0f - 1.0f; - *outOutput++ = out; + *outOutput++ = offs + out; + } + } + + /*********************************************************************/ + void MathNumericalEMA::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + auto inInput = &inputs.at(0).Get(numSamples); + auto n = l::math::max2(inputs.at(1).Get(), 1.0f); + auto zero = inputs.at(2).Get(); + zero *= zero * zero; + + auto outOutput = &outputs.at(0).Get(numSamples); + + if (mReadSamples == 0) { + mEmaAccum = *inInput; + } + + for (int32_t i = 0; i < numSamples; i++) { + float in = *inInput++; + mEmaAccum = (mEmaAccum * (n - 1.0f) + in) / n; + if (l::math::abs(mEmaAccum) < zero) { + *outOutput++ = 0.0f; + } + else { + *outOutput++ = mEmaAccum; + } + } + + mReadSamples += numSamples; + if (mReadSamples == numCacheSamples) { + mReadSamples = 0; } } } From 8195d9f3adbd5b1552a7587eb13436776dbc4ba0 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 4 Sep 2025 03:30:16 +0200 Subject: [PATCH 091/179] Add nn.lib with a fann test project. --- CMakeLists.txt | 2 + packages/nn/CMakeLists.txt | 19 ++++++ packages/nn/include/nn/FannNNBase.h | 45 +++++++++++++ packages/nn/include/nn/NNBase.h | 53 +++++++++++++++ packages/nn/include/nn/NNUtils.h | 35 ++++++++++ packages/nn/include/nn/SlidingWindowBuffer.h | 70 ++++++++++++++++++++ packages/nn/source/common/FannNNBase.cpp | 36 ++++++++++ packages/nn/tests/common/FannTest.cpp | 57 ++++++++++++++++ packages/nn/tests/common/NNTest.cpp | 7 ++ 9 files changed, 324 insertions(+) create mode 100644 packages/nn/CMakeLists.txt create mode 100644 packages/nn/include/nn/FannNNBase.h create mode 100644 packages/nn/include/nn/NNBase.h create mode 100644 packages/nn/include/nn/NNUtils.h create mode 100644 packages/nn/include/nn/SlidingWindowBuffer.h create mode 100644 packages/nn/source/common/FannNNBase.cpp create mode 100644 packages/nn/tests/common/FannTest.cpp create mode 100644 packages/nn/tests/common/NNTest.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index e20020a6..25dfdd69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -31,6 +31,7 @@ else() audio hid nodegraph + nn network storage @@ -59,6 +60,7 @@ else() set_target_properties(audio PROPERTIES UNITY_BUILD ON) set_target_properties(hid PROPERTIES UNITY_BUILD ON) set_target_properties(nodegraph PROPERTIES UNITY_BUILD ON) + set_target_properties(nn PROPERTIES UNITY_BUILD ON) set_target_properties(network PROPERTIES UNITY_BUILD ON) set_target_properties(storage PROPERTIES UNITY_BUILD ON) diff --git a/packages/nn/CMakeLists.txt b/packages/nn/CMakeLists.txt new file mode 100644 index 00000000..111561ac --- /dev/null +++ b/packages/nn/CMakeLists.txt @@ -0,0 +1,19 @@ +project (nn) + +set(deps + logging + testing + memory + serialization + + filesystem + storage +) + +set(deps_external + floatfann_static + ncnn + tiny_dnn_static +) + +bs_generate_package(nn "tier1" "${deps}" "${deps_external}") diff --git a/packages/nn/include/nn/FannNNBase.h b/packages/nn/include/nn/FannNNBase.h new file mode 100644 index 00000000..ea6a2ee2 --- /dev/null +++ b/packages/nn/include/nn/FannNNBase.h @@ -0,0 +1,45 @@ +#pragma once + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define FANN_NO_DLL +#include + +namespace l::nn::fann { + + class FannNNBase : public NNBase { + public: + FannNNBase() = default; + FannNNBase(std::string name, unsigned inputSize, unsigned outputSize) + : NNBase(std::move(name)), input_size_(inputSize), output_size_(outputSize) + { + + net_ = fann_create_standard(3, inputSize, 16, outputSize); + fann_set_training_algorithm(net_, FANN_TRAIN_RPROP); + fann_set_learning_rate(net_, 0.01f); + } + + ~FannNNBase() override = default; + + std::optional infer(const InputVec& input) override; + void forceTrain(const TrainingExample& ex) override; + void loadModel(const std::string& path) override; + void saveModel(const std::string& path) const override; + + private: + struct fann* net_ = nullptr; + unsigned input_size_; + unsigned output_size_; + }; + + +} \ No newline at end of file diff --git a/packages/nn/include/nn/NNBase.h b/packages/nn/include/nn/NNBase.h new file mode 100644 index 00000000..6befbc27 --- /dev/null +++ b/packages/nn/include/nn/NNBase.h @@ -0,0 +1,53 @@ +#pragma once + +#include + +#include + +namespace l::nn::fann { + + class NNBase { + public: + NNBase() = default; + NNBase(std::string name) : name_(std::move(name)) {} + virtual ~NNBase() = default; + + // Perform inference given input vector; returns optional output + virtual std::optional infer(const InputVec& input) = 0; + + // Train if this time range has not been trained yet + bool trainIfNeeded(const TrainingExample& example) { + if (!hasTrainedOn(example.time)) { + forceTrain(example); + markTrained(example.time); + return true; + } + return false; + } + + // Force training, regardless of training history + virtual void forceTrain(const TrainingExample& example) = 0; + + virtual void loadModel(const std::string& path) = 0; + virtual void saveModel(const std::string& path) const = 0; + + bool hasTrainedOn(const TimeRange& range) const { + for (const auto& trained : trained_ranges_) { + if (trained.overlaps(range)) return true; + } + return false; + } + + void markTrained(const TimeRange& range) { + trained_ranges_.push_back(range); + // Optional: merge overlapping ranges to keep list small (not implemented here) + } + + const std::string& name() const { return name_; } + + protected: + std::string name_; + std::vector trained_ranges_; + }; + +} \ No newline at end of file diff --git a/packages/nn/include/nn/NNUtils.h b/packages/nn/include/nn/NNUtils.h new file mode 100644 index 00000000..c4192d47 --- /dev/null +++ b/packages/nn/include/nn/NNUtils.h @@ -0,0 +1,35 @@ +#pragma once + +#include + +namespace l::nn::fann { + + using UnixTime = int32_t; // Unix timestamp in seconds + + struct TimeRange { + UnixTime start; // inclusive + UnixTime end; // exclusive + + bool overlaps(const TimeRange& other) const { + return start < other.end && end > other.start; + } + + bool contains(UnixTime t) const { + return t >= start && t < end; + } + + int32_t duration() const { return end - start; } + }; + + // ---------- Data Types ---------- + + using InputVec = std::vector; + using TargetVec = std::vector; + + struct TrainingExample { + TimeRange time; + InputVec input; + TargetVec target; + }; + +} \ No newline at end of file diff --git a/packages/nn/include/nn/SlidingWindowBuffer.h b/packages/nn/include/nn/SlidingWindowBuffer.h new file mode 100644 index 00000000..6bdf9dcd --- /dev/null +++ b/packages/nn/include/nn/SlidingWindowBuffer.h @@ -0,0 +1,70 @@ +#pragma once + +#include + +#include +#include +#include + +namespace l::nn::fann { + + /** + * Collects timestamped inputs and allows querying a fixed-size window + */ + class SlidingWindowBuffer { + public: + SlidingWindowBuffer(size_t window_size_seconds, size_t sample_rate_hz) + : window_size_(window_size_seconds), sample_rate_(sample_rate_hz) + { + max_samples_ = window_size_ * sample_rate_; + } + + // Add a new timestamped sample (assumes monotonically increasing time) + void push(UnixTime timestamp, const InputVec& input) { + assert(!input.empty()); + timestamps_.push_back(timestamp); + inputs_.push_back(input); + + // Maintain max size + while (!timestamps_.empty() && timestamps_.front() < timestamp - window_size_) { + timestamps_.erase(timestamps_.begin()); + inputs_.erase(inputs_.begin()); + } + } + + // Return concatenated input vector for current window if complete + std::optional getWindow() const { + if (timestamps_.empty()) return std::nullopt; + + UnixTime window_start = timestamps_.front(); + UnixTime window_end = timestamps_.back(); + + // Ensure window covers the full requested duration + if (window_end - window_start + 1 < static_cast(window_size_)) { + return std::nullopt; // Not enough data yet + } + + // Concatenate all input vectors into one big vector + InputVec concatenated; + for (const auto& sample : inputs_) { + concatenated.insert(concatenated.end(), sample.begin(), sample.end()); + } + return concatenated; + } + + TimeRange currentTimeRange() const { + if (timestamps_.empty()) return { 0,0 }; + return { timestamps_.front(), timestamps_.back() + 1 }; // +1 exclusive + } + + private: + size_t window_size_; // seconds + size_t sample_rate_; // samples per second + size_t max_samples_; + + std::vector timestamps_; + std::vector inputs_; + }; + +} + diff --git a/packages/nn/source/common/FannNNBase.cpp b/packages/nn/source/common/FannNNBase.cpp new file mode 100644 index 00000000..6135185a --- /dev/null +++ b/packages/nn/source/common/FannNNBase.cpp @@ -0,0 +1,36 @@ +#include + +namespace l::nn::fann { + + std::optional FannNNBase::infer(const InputVec& input) { + if (input.size() != input_size_) return std::nullopt; + + float* output = fann_run(net_, const_cast(input.data())); + return TargetVec(output, output + output_size_); + } + + void FannNNBase::forceTrain(const TrainingExample& ex) { + if (ex.input.size() != input_size_ || ex.target.size() != output_size_) { + std::cerr << "Input/target size mismatch in forceTrain\n"; + return; + } + fann_train(net_, const_cast(ex.input.data()), const_cast(ex.target.data())); + // markTrained called by trainIfNeeded + } + + void FannNNBase::loadModel(const std::string& path) { + struct fann* loaded = fann_create_from_file(path.c_str()); + if (loaded) { + fann_destroy(net_); + net_ = nullptr; + } + else { + std::cerr << "Failed to load FANN model from " << path << "\n"; + } + } + + void FannNNBase::saveModel(const std::string& path) const { + fann_save(net_, path.c_str()); + } + +} diff --git a/packages/nn/tests/common/FannTest.cpp b/packages/nn/tests/common/FannTest.cpp new file mode 100644 index 00000000..93bc0f11 --- /dev/null +++ b/packages/nn/tests/common/FannTest.cpp @@ -0,0 +1,57 @@ +#include "testing/Test.h" +#include "logging/Log.h" + +#include +#include + +using namespace l::nn::fann; + + +TEST(Fann, SlidingWindow) { + + // Setup sliding window for 10 seconds at 1 sample per second + SlidingWindowBuffer sliding_window(10, 1); + + // Create a node that expects input size = 4 (10 seconds * 1 sample/sec * 4 features) + // Actually, since sliding_window concatenates all inputs in window, if each input is 1 feature: + // input_size = window_size * sample_rate * features_per_sample + const unsigned features_per_sample = 1; + const unsigned input_size = 10 * 1 * features_per_sample; + const unsigned output_size = 1; + + FannNNBase node("example_node", input_size, output_size); + + // Feed data into the sliding window over time + for (UnixTime t = 1000; t < 1020; ++t) { + InputVec sample = { static_cast(t % 10) }; // dummy input feature + sliding_window.push(t, sample); + + // Once we have a full window, prepare training example + auto window_input = sliding_window.getWindow(); + if (window_input) { + TrainingExample ex{ + .time = sliding_window.currentTimeRange(), + .input = *window_input, + // Dummy target for demo + .target = {0.5f} + }; + + if (node.trainIfNeeded(ex)) { + std::cout << "Trained on time range [" << ex.time.start << ", " << ex.time.end << ")\n"; + } + else { + std::cout << "Already trained on this time range\n"; + } + + // Try inference + auto pred = node.infer(ex.input); + if (pred) { + std::cout << "Inference output: " << (*pred)[0] << "\n"; + } + } + } + + return 0; +} + + diff --git a/packages/nn/tests/common/NNTest.cpp b/packages/nn/tests/common/NNTest.cpp new file mode 100644 index 00000000..6d728e9e --- /dev/null +++ b/packages/nn/tests/common/NNTest.cpp @@ -0,0 +1,7 @@ +#include "testing/Test.h" + +int main(int, char* argw[]) { + TEST_RUN(argw[0]); + + return 0; +} From 294496d4a97e4f8c32d2346d63099731100355f6 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 5 Sep 2025 05:34:17 +0200 Subject: [PATCH 092/179] Add tiny-dnn test. Fix issues with tinydnn. --- packages/nn/CMakeLists.txt | 7 +- packages/nn/include/nn/NNBase.h | 4 +- packages/nn/include/nn/NNUtils.h | 2 +- packages/nn/include/nn/SlidingWindowBuffer.h | 2 +- .../nn/{FannNNBase.h => fann/NNFannBase.h} | 8 +- .../nn/tinydnn/TrendReversalPredictor.h | 29 +++ .../nn/include/nn/tinydnn/flatten_layer.h | 61 +++++++ .../{FannNNBase.cpp => fann/NNFannBase.cpp} | 10 +- .../common/tinydnn/TrendReversalPredictor.cpp | 167 ++++++++++++++++++ .../source/common/tinydnn/flatten_layer.cpp | 1 + packages/nn/tests/common/FannTest.cpp | 14 +- packages/nn/tests/common/TinyDnnTest.cpp | 36 ++++ 12 files changed, 321 insertions(+), 20 deletions(-) rename packages/nn/include/nn/{FannNNBase.h => fann/NNFannBase.h} (84%) create mode 100644 packages/nn/include/nn/tinydnn/TrendReversalPredictor.h create mode 100644 packages/nn/include/nn/tinydnn/flatten_layer.h rename packages/nn/source/common/{FannNNBase.cpp => fann/NNFannBase.cpp} (76%) create mode 100644 packages/nn/source/common/tinydnn/TrendReversalPredictor.cpp create mode 100644 packages/nn/source/common/tinydnn/flatten_layer.cpp create mode 100644 packages/nn/tests/common/TinyDnnTest.cpp diff --git a/packages/nn/CMakeLists.txt b/packages/nn/CMakeLists.txt index 111561ac..c587c886 100644 --- a/packages/nn/CMakeLists.txt +++ b/packages/nn/CMakeLists.txt @@ -7,7 +7,6 @@ set(deps serialization filesystem - storage ) set(deps_external @@ -17,3 +16,9 @@ set(deps_external ) bs_generate_package(nn "tier1" "${deps}" "${deps_external}") +target_compile_definitions(nn PUBLIC cxx_std_17) +if(MSVC) + target_compile_options(nn PRIVATE /W2 /bigobj) +else() + target_compile_options(nn PRIVATE -Werror -Wno-unused-result) +endif() diff --git a/packages/nn/include/nn/NNBase.h b/packages/nn/include/nn/NNBase.h index 6befbc27..eeb34543 100644 --- a/packages/nn/include/nn/NNBase.h +++ b/packages/nn/include/nn/NNBase.h @@ -3,8 +3,10 @@ #include #include +#include +#include -namespace l::nn::fann { +namespace l::nn { class NNBase { public: diff --git a/packages/nn/include/nn/NNUtils.h b/packages/nn/include/nn/NNUtils.h index c4192d47..f9ec3957 100644 --- a/packages/nn/include/nn/NNUtils.h +++ b/packages/nn/include/nn/NNUtils.h @@ -2,7 +2,7 @@ #include -namespace l::nn::fann { +namespace l::nn { using UnixTime = int32_t; // Unix timestamp in seconds diff --git a/packages/nn/include/nn/SlidingWindowBuffer.h b/packages/nn/include/nn/SlidingWindowBuffer.h index 6bdf9dcd..0f8d1393 100644 --- a/packages/nn/include/nn/SlidingWindowBuffer.h +++ b/packages/nn/include/nn/SlidingWindowBuffer.h @@ -6,7 +6,7 @@ #include #include -namespace l::nn::fann { +namespace l::nn { /** * Collects timestamped inputs and allows querying a fixed-size window diff --git a/packages/nn/include/nn/FannNNBase.h b/packages/nn/include/nn/fann/NNFannBase.h similarity index 84% rename from packages/nn/include/nn/FannNNBase.h rename to packages/nn/include/nn/fann/NNFannBase.h index ea6a2ee2..80a76706 100644 --- a/packages/nn/include/nn/FannNNBase.h +++ b/packages/nn/include/nn/fann/NNFannBase.h @@ -16,10 +16,10 @@ namespace l::nn::fann { - class FannNNBase : public NNBase { + class NNFannBase : public NNBase { public: - FannNNBase() = default; - FannNNBase(std::string name, unsigned inputSize, unsigned outputSize) + NNFannBase() = default; + NNFannBase(std::string name, unsigned inputSize, unsigned outputSize) : NNBase(std::move(name)), input_size_(inputSize), output_size_(outputSize) { @@ -28,7 +28,7 @@ namespace l::nn::fann { fann_set_learning_rate(net_, 0.01f); } - ~FannNNBase() override = default; + ~NNFannBase() override = default; std::optional infer(const InputVec& input) override; void forceTrain(const TrainingExample& ex) override; diff --git a/packages/nn/include/nn/tinydnn/TrendReversalPredictor.h b/packages/nn/include/nn/tinydnn/TrendReversalPredictor.h new file mode 100644 index 00000000..95c61b7b --- /dev/null +++ b/packages/nn/include/nn/tinydnn/TrendReversalPredictor.h @@ -0,0 +1,29 @@ +#pragma once +#include +#include +#include + +namespace l::nn::tinydnn { + + struct Sample { + tiny_dnn::vec_t ts_data; // OHLC: seq_len * 4 + tiny_dnn::vec_t ext_data; // Support/resistance: 4 + tiny_dnn::label_t label; // 0 or 1 + }; + + class TrendReversalPredictor { + private: + tiny_dnn::network net; + tiny_dnn::vec_t ts_buffer; // OHLC sliding window + tiny_dnn::vec_t ext_buffer; // Support/resistance + size_t seq_len, ts_features, ext_features, conv_out_height, conv_out_width, fc_in_size; + + public: + TrendReversalPredictor(size_t seq_len, size_t ts_features, size_t ext_features); + void train(const std::vector& dataset, int epochs = 50, float lr = 0.001); + void update_context(const tiny_dnn::vec_t& new_ts_data, const tiny_dnn::vec_t& new_ext_data, float price_min, float price_max); + float predict(); + void normalize(tiny_dnn::vec_t& data, float min, float max); + static std::vector load_dataset(const std::string& file_path, size_t seq_len, size_t ts_features); + }; +} diff --git a/packages/nn/include/nn/tinydnn/flatten_layer.h b/packages/nn/include/nn/tinydnn/flatten_layer.h new file mode 100644 index 00000000..360f03ec --- /dev/null +++ b/packages/nn/include/nn/tinydnn/flatten_layer.h @@ -0,0 +1,61 @@ +#pragma once + +#include + +#include + +namespace l::nn::tinydnn { + + using namespace tiny_dnn; + + class flatten_layer : public layer { + public: + flatten_layer(size_t in_height, size_t in_width) + : layer({ vector_type::data }, { vector_type::data }), + in_height_(in_height), in_width_(in_width), out_size_(in_height* in_width) {} + + std::string layer_type() const override { return "flatten"; } + + virtual void forward_propagation(const std::vector& in_data, + std::vector& out_data) override { + const tensor_t& input = *(in_data[0]); + tensor_t& output = *(out_data[0]); + for (size_t i = 0; i < input.size(); ++i) { + output[i].resize(out_size_); + for (size_t h = 0; h < in_height_; ++h) { + for (size_t w = 0; w < in_width_; ++w) { + output[i][h * in_width_ + w] = input[i][h * in_width_ + w]; + } + } + } + } + + virtual void back_propagation(const std::vector& in_data, + const std::vector& out_data, + std::vector& out_grad, + std::vector& in_grad) override { + const tensor_t& out_gradient = *(out_grad[0]); + tensor_t& in_gradient = *(in_grad[0]); + for (size_t i = 0; i < out_gradient.size(); ++i) { + in_gradient[i].resize(in_height_ * in_width_); + for (size_t h = 0; h < in_height_; ++h) { + for (size_t w = 0; w < in_width_; ++w) { + in_gradient[i][h * in_width_ + w] = out_gradient[i][h * in_width_ + w]; + } + } + } + } + + std::vector> in_shape() const override { + return { {in_height_, in_width_, 1} }; + } + + std::vector> out_shape() const override { + return { {out_size_, 1, 1} }; + } + + private: + size_t in_height_, in_width_, out_size_; + }; + +} // \ No newline at end of file diff --git a/packages/nn/source/common/FannNNBase.cpp b/packages/nn/source/common/fann/NNFannBase.cpp similarity index 76% rename from packages/nn/source/common/FannNNBase.cpp rename to packages/nn/source/common/fann/NNFannBase.cpp index 6135185a..fd21ed53 100644 --- a/packages/nn/source/common/FannNNBase.cpp +++ b/packages/nn/source/common/fann/NNFannBase.cpp @@ -1,15 +1,15 @@ -#include +#include namespace l::nn::fann { - std::optional FannNNBase::infer(const InputVec& input) { + std::optional NNFannBase::infer(const InputVec& input) { if (input.size() != input_size_) return std::nullopt; float* output = fann_run(net_, const_cast(input.data())); return TargetVec(output, output + output_size_); } - void FannNNBase::forceTrain(const TrainingExample& ex) { + void NNFannBase::forceTrain(const TrainingExample& ex) { if (ex.input.size() != input_size_ || ex.target.size() != output_size_) { std::cerr << "Input/target size mismatch in forceTrain\n"; return; @@ -18,7 +18,7 @@ namespace l::nn::fann { // markTrained called by trainIfNeeded } - void FannNNBase::loadModel(const std::string& path) { + void NNFannBase::loadModel(const std::string& path) { struct fann* loaded = fann_create_from_file(path.c_str()); if (loaded) { fann_destroy(net_); @@ -29,7 +29,7 @@ namespace l::nn::fann { } } - void FannNNBase::saveModel(const std::string& path) const { + void NNFannBase::saveModel(const std::string& path) const { fann_save(net_, path.c_str()); } diff --git a/packages/nn/source/common/tinydnn/TrendReversalPredictor.cpp b/packages/nn/source/common/tinydnn/TrendReversalPredictor.cpp new file mode 100644 index 00000000..56dd21a2 --- /dev/null +++ b/packages/nn/source/common/tinydnn/TrendReversalPredictor.cpp @@ -0,0 +1,167 @@ +#include + +#include + +#include +#include +#include + +namespace l::nn::tinydnn { + + + + + + + + + void TrendReversalPredictor::normalize(tiny_dnn::vec_t& data, float min, float max) { + if (max == min) return; + for (auto& val : data) val = (val - min) / (max - min); + } + + class bce_loss { + public: + static tiny_dnn::float_t f(const tiny_dnn::vec_t& y, const tiny_dnn::vec_t& t) { + if (y.size() != 1 || t.size() != 1) { + throw std::runtime_error("bce_loss::f expects single output and target, got y.size: " + + std::to_string(y.size()) + ", t.size: " + std::to_string(t.size())); + } + tiny_dnn::float_t y_val = y[0]; + tiny_dnn::float_t t_val = t[0]; + if (t_val != 0.0f && t_val != 1.0f) { + throw std::runtime_error("bce_loss::f expects binary target (0 or 1), got: " + std::to_string(t_val)); + } + if (y_val < 0.0f || y_val > 1.0f) { + throw std::runtime_error("bce_loss::f expects y in [0,1], got: " + std::to_string(y_val)); + } + return -t_val * log(y_val + 1e-10) - (1 - t_val) * log(1 - y_val + 1e-10); + } + static tiny_dnn::vec_t df(const tiny_dnn::vec_t& y, const tiny_dnn::vec_t& t) { + if (y.size() != 1 || t.size() != 1) { + throw std::runtime_error("bce_loss::df expects single output and target, got y.size: " + + std::to_string(y.size()) + ", t.size: " + std::to_string(t.size())); + } + tiny_dnn::float_t y_val = y[0]; + tiny_dnn::float_t t_val = t[0]; + if (t_val != 0.0f && t_val != 1.0f) { + throw std::runtime_error("bce_loss::df expects binary target (0 or 1), got: " + std::to_string(t_val)); + } + if (y_val < 0.0f || y_val > 1.0f) { + throw std::runtime_error("bce_loss::df expects y in [0,1], got: " + std::to_string(y_val)); + } + tiny_dnn::float_t grad = (y_val - t_val) / ((y_val + 1e-10) * (1 - y_val + 1e-10)); + return { grad }; + } + }; + + TrendReversalPredictor::TrendReversalPredictor(size_t seq_len_, size_t ts_features_, size_t ext_features_) + : seq_len(seq_len_), ts_features(ts_features_), ext_features(ext_features_), + ts_buffer(seq_len* ts_features, 0.0f), ext_buffer(ext_features, 0.0f) { + using namespace tiny_dnn; + // Compute convolutional output size + size_t kernel_size = 3, stride = 1, filters = 8; + conv_out_height = (seq_len - kernel_size + 1) / stride; // 28 + conv_out_width = filters; // 8 + fc_in_size = conv_out_height * conv_out_width + ext_features; // 224 + 4 = 228 + + net << convolutional_layer(seq_len, ts_features, kernel_size, 1, filters, padding::valid) // [30, 4] -> [28, 8] + << relu_layer() + << flatten_layer(conv_out_height, conv_out_width) // [28, 8] -> [224] + << fully_connected_layer(fc_in_size, 1) // [224 + 4] -> [1] + << sigmoid_layer(); + } + + void TrendReversalPredictor::train(const std::vector& dataset, int epochs, float lr) { + using namespace tiny_dnn; + adam optimizer; + optimizer.alpha = lr; + const int batch_size = 8; + + std::random_device rd; + std::mt19937 g(rd()); + + for (int epoch = 0; epoch < epochs; ++epoch) { + std::shuffle(dataset.begin(), dataset.end(), g); + float total_loss = 0.0f; + size_t batch_count = 0; + for (size_t i = 0; i < dataset.size(); i += batch_size) { + auto batch_end = std::min(i + batch_size, dataset.size()); + std::vector batch_data; + std::vector batch_labels; // Changed to vec_t + for (size_t j = i; j < batch_end; ++j) { + vec_t input = dataset[j].ts_data; + input.insert(input.end(), dataset[j].ext_data.begin(), dataset[j].ext_data.end()); + batch_data.push_back(input); + batch_labels.push_back({ static_cast(dataset[j].label) }); // Convert label_t to vec_t + } + bool success = net.train(optimizer, batch_data, batch_labels, batch_size, 1); + if (!success) { + std::cerr << "Training failed for batch " << batch_count + 1 << "\n"; + continue; + } + float batch_loss = 0.0f; + for (size_t j = 0; j < batch_data.size(); ++j) { + vec_t output = net.predict(batch_data[j]); + batch_loss += bce_loss::f(output, batch_labels[j]); // Use vec_t for target + } + batch_loss /= batch_data.size(); + total_loss += batch_loss; + batch_count++; + } + std::cout << "Epoch " << epoch + 1 << ", Loss: " << total_loss / batch_count << "\n"; + } + net.save("trend_model.bin"); + } + + void TrendReversalPredictor::update_context(const tiny_dnn::vec_t& new_ts_data, const tiny_dnn::vec_t& new_ext_data, float price_min, float max) { + if (new_ts_data.size() == ts_features) { + std::copy(ts_buffer.begin() + ts_features, ts_buffer.end(), ts_buffer.begin()); + vec_t normalized_ts = new_ts_data; + normalize(normalized_ts, price_min, max); + std::copy(normalized_ts.begin(), normalized_ts.end(), ts_buffer.end() - ts_features); + } + if (new_ext_data.size() == ext_features) { + ext_buffer = new_ext_data; + } + } + + float TrendReversalPredictor::predict() { + using namespace tiny_dnn; + vec_t input = ts_buffer; + input.insert(input.end(), ext_buffer.begin(), ext_buffer.end()); + + auto start = std::chrono::high_resolution_clock::now(); + auto output = net.predict(input); + auto end = std::chrono::high_resolution_clock::now(); + auto duration = std::chrono::duration_cast(end - start).count(); + std::cout << "Inference time: " << duration << " ms\n"; + + return output[0]; + } + + std::vector TrendReversalPredictor::load_dataset(const std::string& file_path, size_t seq_len, size_t ts_features) { + std::vector dataset; + std::ifstream file(file_path); + std::string line; + while (std::getline(file, line)) { + std::stringstream ss(line); + vec_t ts_data(seq_len * ts_features); + vec_t ext_data(4); + label_t label; + for (size_t i = 0; i < seq_len * ts_features; ++i) { + ss >> ts_data[i]; + if (ss.peek() == ',') ss.ignore(); + } + for (size_t i = 0; i < 4; ++i) { + ss >> ext_data[i]; + if (ss.peek() == ',') ss.ignore(); + } + ss >> label; + dataset.push_back({ ts_data, ext_data, label }); + } + return dataset; + } + + +} diff --git a/packages/nn/source/common/tinydnn/flatten_layer.cpp b/packages/nn/source/common/tinydnn/flatten_layer.cpp new file mode 100644 index 00000000..7247ccf1 --- /dev/null +++ b/packages/nn/source/common/tinydnn/flatten_layer.cpp @@ -0,0 +1 @@ +#include diff --git a/packages/nn/tests/common/FannTest.cpp b/packages/nn/tests/common/FannTest.cpp index 93bc0f11..359066a3 100644 --- a/packages/nn/tests/common/FannTest.cpp +++ b/packages/nn/tests/common/FannTest.cpp @@ -1,9 +1,10 @@ #include "testing/Test.h" #include "logging/Log.h" -#include +#include #include +using namespace l::nn; using namespace l::nn::fann; @@ -19,7 +20,7 @@ TEST(Fann, SlidingWindow) { const unsigned input_size = 10 * 1 * features_per_sample; const unsigned output_size = 1; - FannNNBase node("example_node", input_size, output_size); + NNFannBase node("example_node", input_size, output_size); // Feed data into the sliding window over time for (UnixTime t = 1000; t < 1020; ++t) { @@ -29,12 +30,11 @@ TEST(Fann, SlidingWindow) { // Once we have a full window, prepare training example auto window_input = sliding_window.getWindow(); if (window_input) { - TrainingExample ex{ - .time = sliding_window.currentTimeRange(), - .input = *window_input, + TrainingExample ex; + ex.time = sliding_window.currentTimeRange(); + ex.input = *window_input; // Dummy target for demo - .target = {0.5f} - }; + ex.target = {0.5f}; if (node.trainIfNeeded(ex)) { std::cout << "Trained on time range [" << ex.time.start << ", " << ex.time.end << ")\n"; diff --git a/packages/nn/tests/common/TinyDnnTest.cpp b/packages/nn/tests/common/TinyDnnTest.cpp new file mode 100644 index 00000000..e1aa447a --- /dev/null +++ b/packages/nn/tests/common/TinyDnnTest.cpp @@ -0,0 +1,36 @@ +#include "testing/Test.h" +#include "logging/Log.h" + +#include + +#include + +using namespace l::nn::tinydnn; + +TEST(TinyDnn, Basic) { + + size_t seq_len = 30; + size_t ts_features = 4; + size_t ext_features = 4; + + TrendReversalPredictor predictor(seq_len, ts_features, ext_features); + auto dataset = TrendReversalPredictor::load_dataset("dataset/data.csv", seq_len, ts_features); + + float price_min = 90.0f, price_max = 110.0f; + for (auto& sample : dataset) { + predictor.normalize(sample.ts_data, price_min, price_max); + } + + predictor.train(dataset, 50, 0.001); + + tiny_dnn::vec_t new_ts_data = { 100.5f, 101.0f, 100.0f, 100.8f }; + tiny_dnn::vec_t new_ext_data = { 95.0f, 105.0f, 5.8f, 4.2f }; + predictor.update_context(new_ts_data, new_ext_data, price_min, price_max); + float prob = predictor.predict(); + std::cout << "Trend reversal probability: " << prob * 100 << "%\n"; + + return 0; + +} + + From 8581a0a982fc4436c24864ec59d1c3dd53c70931 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 6 Sep 2025 13:43:23 +0200 Subject: [PATCH 093/179] NN: Fix tinydnn integration. --- packages/nn/CMakeLists.txt | 4 +- .../nn/tinydnn/TrendReversalPredictor.h | 19 ++- .../nn/include/nn/tinydnn/flatten_layer.h | 35 +++-- .../common/tinydnn/TrendReversalPredictor.cpp | 120 +++++++----------- packages/nn/tests/common/TinyDnnTest.cpp | 8 +- 5 files changed, 88 insertions(+), 98 deletions(-) diff --git a/packages/nn/CMakeLists.txt b/packages/nn/CMakeLists.txt index c587c886..f368a9a7 100644 --- a/packages/nn/CMakeLists.txt +++ b/packages/nn/CMakeLists.txt @@ -16,7 +16,9 @@ set(deps_external ) bs_generate_package(nn "tier1" "${deps}" "${deps_external}") -target_compile_definitions(nn PUBLIC cxx_std_17) +set_target_properties(nn PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED YES) +set_target_properties(nn_test PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED YES) + if(MSVC) target_compile_options(nn PRIVATE /W2 /bigobj) else() diff --git a/packages/nn/include/nn/tinydnn/TrendReversalPredictor.h b/packages/nn/include/nn/tinydnn/TrendReversalPredictor.h index 95c61b7b..fbe8b321 100644 --- a/packages/nn/include/nn/tinydnn/TrendReversalPredictor.h +++ b/packages/nn/include/nn/tinydnn/TrendReversalPredictor.h @@ -1,7 +1,9 @@ #pragma once + +#include + #include #include -#include namespace l::nn::tinydnn { @@ -13,15 +15,18 @@ namespace l::nn::tinydnn { class TrendReversalPredictor { private: + size_t seq_len; + size_t ts_features; + size_t kernel_size, stride, conv_filters; + size_t conv_out_height, conv_out_width; + size_t fc_in_size; + tiny_dnn::vec_t ts_buffer; tiny_dnn::network net; - tiny_dnn::vec_t ts_buffer; // OHLC sliding window - tiny_dnn::vec_t ext_buffer; // Support/resistance - size_t seq_len, ts_features, ext_features, conv_out_height, conv_out_width, fc_in_size; public: - TrendReversalPredictor(size_t seq_len, size_t ts_features, size_t ext_features); - void train(const std::vector& dataset, int epochs = 50, float lr = 0.001); - void update_context(const tiny_dnn::vec_t& new_ts_data, const tiny_dnn::vec_t& new_ext_data, float price_min, float price_max); + TrendReversalPredictor(size_t seq_len_, size_t ts_features_); + void train(std::vector& dataset, int epochs = 50, float lr = 0.001); + void update_context(const tiny_dnn::vec_t& new_ts_data, float price_min, float price_max); float predict(); void normalize(tiny_dnn::vec_t& data, float min, float max); static std::vector load_dataset(const std::string& file_path, size_t seq_len, size_t ts_features); diff --git a/packages/nn/include/nn/tinydnn/flatten_layer.h b/packages/nn/include/nn/tinydnn/flatten_layer.h index 360f03ec..6d5cc197 100644 --- a/packages/nn/include/nn/tinydnn/flatten_layer.h +++ b/packages/nn/include/nn/tinydnn/flatten_layer.h @@ -10,44 +10,53 @@ namespace l::nn::tinydnn { class flatten_layer : public layer { public: - flatten_layer(size_t in_height, size_t in_width) + flatten_layer(size_t in_height, size_t in_width, size_t in_channels = 1) : layer({ vector_type::data }, { vector_type::data }), - in_height_(in_height), in_width_(in_width), out_size_(in_height* in_width) {} + in_height_(in_height), in_width_(in_width), in_channels_(in_channels), + out_size_(in_height* in_width* in_channels) { + } std::string layer_type() const override { return "flatten"; } - virtual void forward_propagation(const std::vector& in_data, + void forward_propagation(const std::vector& in_data, std::vector& out_data) override { const tensor_t& input = *(in_data[0]); tensor_t& output = *(out_data[0]); for (size_t i = 0; i < input.size(); ++i) { output[i].resize(out_size_); - for (size_t h = 0; h < in_height_; ++h) { - for (size_t w = 0; w < in_width_; ++w) { - output[i][h * in_width_ + w] = input[i][h * in_width_ + w]; + size_t idx = 0; + for (size_t c = 0; c < in_channels_; ++c) { + for (size_t h = 0; h < in_height_; ++h) { + for (size_t w = 0; w < in_width_; ++w) { + output[i][idx++] = input[i][c * in_height_ * in_width_ + h * in_width_ + w]; + } } } } } - virtual void back_propagation(const std::vector& in_data, + void back_propagation(const std::vector& in_data, const std::vector& out_data, std::vector& out_grad, std::vector& in_grad) override { const tensor_t& out_gradient = *(out_grad[0]); tensor_t& in_gradient = *(in_grad[0]); for (size_t i = 0; i < out_gradient.size(); ++i) { - in_gradient[i].resize(in_height_ * in_width_); - for (size_t h = 0; h < in_height_; ++h) { - for (size_t w = 0; w < in_width_; ++w) { - in_gradient[i][h * in_width_ + w] = out_gradient[i][h * in_width_ + w]; + in_gradient[i].resize(out_size_); + size_t idx = 0; + for (size_t c = 0; c < in_channels_; ++c) { + for (size_t h = 0; h < in_height_; ++h) { + for (size_t w = 0; w < in_width_; ++w) { + in_gradient[i][c * in_height_ * in_width_ + h * in_width_ + w] = + out_gradient[i][idx++]; + } } } } } std::vector> in_shape() const override { - return { {in_height_, in_width_, 1} }; + return { {in_height_, in_width_, in_channels_} }; } std::vector> out_shape() const override { @@ -55,7 +64,7 @@ namespace l::nn::tinydnn { } private: - size_t in_height_, in_width_, out_size_; + size_t in_height_, in_width_, in_channels_, out_size_; }; } // \ No newline at end of file diff --git a/packages/nn/source/common/tinydnn/TrendReversalPredictor.cpp b/packages/nn/source/common/tinydnn/TrendReversalPredictor.cpp index 56dd21a2..9ae225b5 100644 --- a/packages/nn/source/common/tinydnn/TrendReversalPredictor.cpp +++ b/packages/nn/source/common/tinydnn/TrendReversalPredictor.cpp @@ -5,75 +5,55 @@ #include #include #include +#include namespace l::nn::tinydnn { - - - - - - - void TrendReversalPredictor::normalize(tiny_dnn::vec_t& data, float min, float max) { - if (max == min) return; - for (auto& val : data) val = (val - min) / (max - min); - } - + // Binary Cross Entropy Loss class bce_loss { public: - static tiny_dnn::float_t f(const tiny_dnn::vec_t& y, const tiny_dnn::vec_t& t) { - if (y.size() != 1 || t.size() != 1) { - throw std::runtime_error("bce_loss::f expects single output and target, got y.size: " + - std::to_string(y.size()) + ", t.size: " + std::to_string(t.size())); - } - tiny_dnn::float_t y_val = y[0]; - tiny_dnn::float_t t_val = t[0]; - if (t_val != 0.0f && t_val != 1.0f) { - throw std::runtime_error("bce_loss::f expects binary target (0 or 1), got: " + std::to_string(t_val)); - } - if (y_val < 0.0f || y_val > 1.0f) { - throw std::runtime_error("bce_loss::f expects y in [0,1], got: " + std::to_string(y_val)); - } - return -t_val * log(y_val + 1e-10) - (1 - t_val) * log(1 - y_val + 1e-10); + static float_t f(const vec_t& y, const vec_t& t) { + if (y.size() != 1 || t.size() != 1) throw std::runtime_error("BCE requires scalar output."); + float_t y_val = y[0], t_val = t[0]; + return -t_val * log(y_val + 1e-10f) - (1.0f - t_val) * log(1.0f - y_val + 1e-10f); } - static tiny_dnn::vec_t df(const tiny_dnn::vec_t& y, const tiny_dnn::vec_t& t) { - if (y.size() != 1 || t.size() != 1) { - throw std::runtime_error("bce_loss::df expects single output and target, got y.size: " + - std::to_string(y.size()) + ", t.size: " + std::to_string(t.size())); - } - tiny_dnn::float_t y_val = y[0]; - tiny_dnn::float_t t_val = t[0]; - if (t_val != 0.0f && t_val != 1.0f) { - throw std::runtime_error("bce_loss::df expects binary target (0 or 1), got: " + std::to_string(t_val)); - } - if (y_val < 0.0f || y_val > 1.0f) { - throw std::runtime_error("bce_loss::df expects y in [0,1], got: " + std::to_string(y_val)); - } - tiny_dnn::float_t grad = (y_val - t_val) / ((y_val + 1e-10) * (1 - y_val + 1e-10)); + + static vec_t df(const vec_t& y, const vec_t& t) { + if (y.size() != 1 || t.size() != 1) throw std::runtime_error("BCE requires scalar output."); + float_t y_val = y[0], t_val = t[0]; + float_t grad = (y_val - t_val) / ((y_val + 1e-10f) * (1.0f - y_val + 1e-10f)); return { grad }; } }; - TrendReversalPredictor::TrendReversalPredictor(size_t seq_len_, size_t ts_features_, size_t ext_features_) - : seq_len(seq_len_), ts_features(ts_features_), ext_features(ext_features_), - ts_buffer(seq_len* ts_features, 0.0f), ext_buffer(ext_features, 0.0f) { + TrendReversalPredictor::TrendReversalPredictor(size_t seq_len_, size_t ts_features_) + : seq_len(seq_len_), ts_features(ts_features_), + ts_buffer(seq_len* ts_features, 0.0f) { using namespace tiny_dnn; - // Compute convolutional output size - size_t kernel_size = 3, stride = 1, filters = 8; - conv_out_height = (seq_len - kernel_size + 1) / stride; // 28 - conv_out_width = filters; // 8 - fc_in_size = conv_out_height * conv_out_width + ext_features; // 224 + 4 = 228 + // Layer config parameters + kernel_size = 3; + stride = 1; + conv_filters = 8; - net << convolutional_layer(seq_len, ts_features, kernel_size, 1, filters, padding::valid) // [30, 4] -> [28, 8] + conv_out_height = (seq_len - kernel_size) / stride + 1; // e.g. 28 + conv_out_width = conv_filters; // e.g. 8 + + fc_in_size = conv_out_height * conv_out_width * 2; // flatten output size, no ext_features + + net << convolutional_layer(seq_len, ts_features, kernel_size, 1, conv_filters, padding::valid) << relu_layer() - << flatten_layer(conv_out_height, conv_out_width) // [28, 8] -> [224] - << fully_connected_layer(fc_in_size, 1) // [224 + 4] -> [1] + << flatten_layer(conv_out_height, 2, conv_out_width) + << fully_connected_layer(fc_in_size, 1) << sigmoid_layer(); } - void TrendReversalPredictor::train(const std::vector& dataset, int epochs, float lr) { - using namespace tiny_dnn; + void TrendReversalPredictor::normalize(vec_t& data, float min, float max) { + if (max == min) return; + for (auto& val : data) val = (val - min) / (max - min); + } + + void TrendReversalPredictor::train(std::vector& dataset, int epochs, float lr) { adam optimizer; optimizer.alpha = lr; const int batch_size = 8; @@ -85,59 +65,53 @@ namespace l::nn::tinydnn { std::shuffle(dataset.begin(), dataset.end(), g); float total_loss = 0.0f; size_t batch_count = 0; + for (size_t i = 0; i < dataset.size(); i += batch_size) { - auto batch_end = std::min(i + batch_size, dataset.size()); + size_t batch_end = std::min(i + batch_size, dataset.size()); std::vector batch_data; - std::vector batch_labels; // Changed to vec_t + std::vector batch_labels; + for (size_t j = i; j < batch_end; ++j) { vec_t input = dataset[j].ts_data; input.insert(input.end(), dataset[j].ext_data.begin(), dataset[j].ext_data.end()); batch_data.push_back(input); - batch_labels.push_back({ static_cast(dataset[j].label) }); // Convert label_t to vec_t + batch_labels.push_back({ static_cast(dataset[j].label) }); } + bool success = net.train(optimizer, batch_data, batch_labels, batch_size, 1); if (!success) { std::cerr << "Training failed for batch " << batch_count + 1 << "\n"; continue; } + float batch_loss = 0.0f; for (size_t j = 0; j < batch_data.size(); ++j) { vec_t output = net.predict(batch_data[j]); - batch_loss += bce_loss::f(output, batch_labels[j]); // Use vec_t for target + batch_loss += bce_loss::f(output, batch_labels[j]); } batch_loss /= batch_data.size(); total_loss += batch_loss; - batch_count++; + ++batch_count; } + std::cout << "Epoch " << epoch + 1 << ", Loss: " << total_loss / batch_count << "\n"; } + net.save("trend_model.bin"); } - void TrendReversalPredictor::update_context(const tiny_dnn::vec_t& new_ts_data, const tiny_dnn::vec_t& new_ext_data, float price_min, float max) { + void TrendReversalPredictor::update_context(const vec_t& new_ts_data, float price_min, float price_max) { if (new_ts_data.size() == ts_features) { std::copy(ts_buffer.begin() + ts_features, ts_buffer.end(), ts_buffer.begin()); - vec_t normalized_ts = new_ts_data; - normalize(normalized_ts, price_min, max); + auto normalized_ts = new_ts_data; + normalize(normalized_ts, price_min, price_max); std::copy(normalized_ts.begin(), normalized_ts.end(), ts_buffer.end() - ts_features); } - if (new_ext_data.size() == ext_features) { - ext_buffer = new_ext_data; - } } float TrendReversalPredictor::predict() { using namespace tiny_dnn; - vec_t input = ts_buffer; - input.insert(input.end(), ext_buffer.begin(), ext_buffer.end()); - - auto start = std::chrono::high_resolution_clock::now(); - auto output = net.predict(input); - auto end = std::chrono::high_resolution_clock::now(); - auto duration = std::chrono::duration_cast(end - start).count(); - std::cout << "Inference time: " << duration << " ms\n"; - - return output[0]; + return net.predict(ts_buffer)[0]; } std::vector TrendReversalPredictor::load_dataset(const std::string& file_path, size_t seq_len, size_t ts_features) { diff --git a/packages/nn/tests/common/TinyDnnTest.cpp b/packages/nn/tests/common/TinyDnnTest.cpp index e1aa447a..2f16f457 100644 --- a/packages/nn/tests/common/TinyDnnTest.cpp +++ b/packages/nn/tests/common/TinyDnnTest.cpp @@ -9,11 +9,12 @@ using namespace l::nn::tinydnn; TEST(TinyDnn, Basic) { + return; + size_t seq_len = 30; size_t ts_features = 4; - size_t ext_features = 4; - TrendReversalPredictor predictor(seq_len, ts_features, ext_features); + TrendReversalPredictor predictor(seq_len, ts_features); auto dataset = TrendReversalPredictor::load_dataset("dataset/data.csv", seq_len, ts_features); float price_min = 90.0f, price_max = 110.0f; @@ -24,8 +25,7 @@ TEST(TinyDnn, Basic) { predictor.train(dataset, 50, 0.001); tiny_dnn::vec_t new_ts_data = { 100.5f, 101.0f, 100.0f, 100.8f }; - tiny_dnn::vec_t new_ext_data = { 95.0f, 105.0f, 5.8f, 4.2f }; - predictor.update_context(new_ts_data, new_ext_data, price_min, price_max); + predictor.update_context(new_ts_data, price_min, price_max); float prob = predictor.predict(); std::cout << "Trend reversal probability: " << prob * 100 << "%\n"; From 714722ca20b473e7e904f3e878fc3fe24126946b Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 6 Sep 2025 13:54:30 +0200 Subject: [PATCH 094/179] Fix error. --- packages/nn/tests/common/TinyDnnTest.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nn/tests/common/TinyDnnTest.cpp b/packages/nn/tests/common/TinyDnnTest.cpp index 2f16f457..743bb4ae 100644 --- a/packages/nn/tests/common/TinyDnnTest.cpp +++ b/packages/nn/tests/common/TinyDnnTest.cpp @@ -9,7 +9,7 @@ using namespace l::nn::tinydnn; TEST(TinyDnn, Basic) { - return; + return 0 ; size_t seq_len = 30; size_t ts_features = 4; From 7dbcf7d3c4e27fa976deb95573634a816952a74f Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 7 Sep 2025 02:13:18 +0200 Subject: [PATCH 095/179] NN: Fix some build warnings. Clarify node description. --- packages/nn/CMakeLists.txt | 3 ++- .../include/nodegraph/operations/NodeGraphOpMathNumerical.h | 6 +++--- packages/nodegraph/source/common/NodeGraphSchema.cpp | 4 ++-- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/packages/nn/CMakeLists.txt b/packages/nn/CMakeLists.txt index f368a9a7..507a71bd 100644 --- a/packages/nn/CMakeLists.txt +++ b/packages/nn/CMakeLists.txt @@ -22,5 +22,6 @@ set_target_properties(nn_test PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED Y if(MSVC) target_compile_options(nn PRIVATE /W2 /bigobj) else() - target_compile_options(nn PRIVATE -Werror -Wno-unused-result) +-Werror=ignored-qualifiers + target_compile_options(nn PRIVATE -Werror -Wno-unused-result -Wno-ignored-qualifiers -Wno-unused-parameter) endif() diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 336c560c..3e50aa5b 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -49,7 +49,7 @@ namespace l::nodegraph { class MathNumericalTemporalChange : public NodeGraphOp { public: MathNumericalTemporalChange(NodeGraphBase* node) : - NodeGraphOp(node, "Temporal Change") + NodeGraphOp(node, "Change %") { AddInput2("in"); AddOutput2("out"); @@ -85,7 +85,7 @@ namespace l::nodegraph { class MathNumericalDiff : public NodeGraphOp { public: MathNumericalDiff(NodeGraphBase* node) : - NodeGraphOp(node, "Temporal Difference") + NodeGraphOp(node, "Difference") { AddInput2("In"); AddOutput2("Diff"); @@ -190,7 +190,7 @@ namespace l::nodegraph { AddInput("Friction2", 1.0f, 1, 0.0f, 1.0f); AddOutput2("Intgr1"); - AddOutput2("Intgr1"); + AddOutput2("Intgr2"); AddOutput2("Intgr Both"); } diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 33442176..61901300 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -642,9 +642,9 @@ namespace l::nodegraph { } else if (typeGroup == "Math.Numerical") { RegisterNodeType("Math.Numerical", 140, "Integral", "Basically a temporal summation node with a EWA on the output with a cooefficient 'friction'"); - RegisterNodeType("Math.Numerical", 141, "Derivate", ""); + RegisterNodeType("Math.Numerical", 141, "Change", "Temporal change. Computes the value of (v_now - v_prev / (abs(v_now) + abs(v_prev))."); RegisterNodeType("Math.Numerical", 142, "Difference Normalized"); - RegisterNodeType("Math.Numerical", 143, "Difference"); + RegisterNodeType("Math.Numerical", 143, "Difference", ""); RegisterNodeType("Math.Numerical", 144, "Level Trigger", "Determines where some input is located between two extremes (min/max) in the format [0,1] "); RegisterNodeType("Math.Numerical", 145, "Minmax Channel", "Computes the range between the EWA smootherd min/max inputs"); RegisterNodeType("Math.Numerical", 146, "Reconstructor", "Deconstructs the input into derivatives (change per index) and outputs the sum of through a ewa with a cooefficient of 'friction' {x1 = x0 + friction * (target - x0)}. An second output is provided which is the average of the last two outputs of that function."); From 86b86fb6351afa6d3e9f784df99d1657222623b7 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 7 Sep 2025 02:20:47 +0200 Subject: [PATCH 096/179] NG: Better description. --- .../include/nodegraph/operations/NodeGraphOpMathNumerical.h | 6 +++--- packages/nodegraph/source/common/NodeGraphSchema.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 3e50aa5b..ff219146 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -67,10 +67,10 @@ namespace l::nodegraph { class MathNumericalDiffNorm : public NodeGraphOp { public: MathNumericalDiffNorm(NodeGraphBase* node) : - NodeGraphOp(node, "Temporal diff norm") + NodeGraphOp(node, "Difference 2") { - AddInput2("x"); - AddOutput2("Diff norm"); + AddInput2("In"); + AddOutput2("Diff 2"); } virtual ~MathNumericalDiffNorm() = default; diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 61901300..4ea8f1e5 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -643,8 +643,8 @@ namespace l::nodegraph { else if (typeGroup == "Math.Numerical") { RegisterNodeType("Math.Numerical", 140, "Integral", "Basically a temporal summation node with a EWA on the output with a cooefficient 'friction'"); RegisterNodeType("Math.Numerical", 141, "Change", "Temporal change. Computes the value of (v_now - v_prev / (abs(v_now) + abs(v_prev))."); - RegisterNodeType("Math.Numerical", 142, "Difference Normalized"); - RegisterNodeType("Math.Numerical", 143, "Difference", ""); + RegisterNodeType("Math.Numerical", 142, "Difference2", "Temporal difference 2. Computes the value of (v_now / v_prev - 1)"); + RegisterNodeType("Math.Numerical", 143, "Difference", "Temporal difference. Computes the value of (v_now - v_prev)."); RegisterNodeType("Math.Numerical", 144, "Level Trigger", "Determines where some input is located between two extremes (min/max) in the format [0,1] "); RegisterNodeType("Math.Numerical", 145, "Minmax Channel", "Computes the range between the EWA smootherd min/max inputs"); RegisterNodeType("Math.Numerical", 146, "Reconstructor", "Deconstructs the input into derivatives (change per index) and outputs the sum of through a ewa with a cooefficient of 'friction' {x1 = x0 + friction * (target - x0)}. An second output is provided which is the average of the last two outputs of that function."); From f75e9628f57740562809901768171c2bf900e252 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 7 Sep 2025 02:24:59 +0200 Subject: [PATCH 097/179] Fix error. --- packages/nn/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/nn/CMakeLists.txt b/packages/nn/CMakeLists.txt index 507a71bd..cfe7cb5b 100644 --- a/packages/nn/CMakeLists.txt +++ b/packages/nn/CMakeLists.txt @@ -22,6 +22,5 @@ set_target_properties(nn_test PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED Y if(MSVC) target_compile_options(nn PRIVATE /W2 /bigobj) else() --Werror=ignored-qualifiers target_compile_options(nn PRIVATE -Werror -Wno-unused-result -Wno-ignored-qualifiers -Wno-unused-parameter) endif() From 42035374a835c479b5fff8d2395b781f7760e2ec Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 7 Sep 2025 17:56:53 +0200 Subject: [PATCH 098/179] NG: Add minmax nodes. Add a simple temporal change node. --- .../operations/NodeGraphOpMathAritmethic.h | 39 ++++++++++++++++ .../operations/NodeGraphOpMathNumerical.h | 46 +++++++++++++------ .../source/common/NodeGraphSchema.cpp | 22 ++++++--- .../operations/NodeGraphOpMathNumerical.cpp | 38 +++++++++++++-- 4 files changed, 120 insertions(+), 25 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h index 00968f51..bc8bf0ca 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h @@ -326,4 +326,43 @@ namespace l::nodegraph { } }; + /*********************************************************************/ + class MathAritmethicMinMax : public NodeGraphOp { + public: + MathAritmethicMinMax(NodeGraphBase* node) : + NodeGraphOp(node, "Minmax") + { + AddInput("In"); + AddInput("Min"); + AddInput("Max"); + + AddOutput(">=<"); + AddOutput(">="); + AddOutput("<="); + } + virtual ~MathAritmethicMinMax() = default; + virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { + auto inInput = inputs.at(0).GetIterator(numSamples); + auto min = inputs.at(1).Get(); + auto max = inputs.at(2).Get(); + auto minmaxOutput = &outputs.at(0).Get(numSamples); + auto minOutput = &outputs.at(1).Get(numSamples); + auto maxOutput = &outputs.at(2).Get(numSamples); + + for (int32_t i = 0; i < numSamples; i++) { + auto in = *inInput++; + if (min < max) { + // min max contains legal values + *minmaxOutput++ = in < min ? min : (in > max ? max : in); + } + else { + // min max excludes legal values + *minmaxOutput++ = in >= min ? in : (in >= max ? min : in); + } + *minOutput++ = in >= min ? in : min; + *maxOutput++ = in <= max ? in : max; + } + } + }; + } \ No newline at end of file diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index ff219146..5cb3de11 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -46,16 +46,16 @@ namespace l::nodegraph { }; /*********************************************************************/ - class MathNumericalTemporalChange : public NodeGraphOp { + class MathNumericalTemporalChange1 : public NodeGraphOp { public: - MathNumericalTemporalChange(NodeGraphBase* node) : - NodeGraphOp(node, "Change %") + MathNumericalTemporalChange1(NodeGraphBase* node) : + NodeGraphOp(node, "Change 1") { AddInput2("in"); AddOutput2("out"); } - virtual ~MathNumericalTemporalChange() = default; + virtual ~MathNumericalTemporalChange1() = default; virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; protected: int32_t mReadSamples = 0; @@ -64,16 +64,34 @@ namespace l::nodegraph { }; /*********************************************************************/ - class MathNumericalDiffNorm : public NodeGraphOp { + class MathNumericalTemporalChange2 : public NodeGraphOp { public: - MathNumericalDiffNorm(NodeGraphBase* node) : + MathNumericalTemporalChange2(NodeGraphBase* node) : + NodeGraphOp(node, "Change 2") + { + AddInput2("in"); + AddOutput2("out"); + } + + virtual ~MathNumericalTemporalChange2() = default; + virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + protected: + int32_t mReadSamples = 0; + + float mInputPrev = 0.0f; + }; + + /*********************************************************************/ + class MathNumericalDiff2 : public NodeGraphOp { + public: + MathNumericalDiff2(NodeGraphBase* node) : NodeGraphOp(node, "Difference 2") { AddInput2("In"); AddOutput2("Diff 2"); } - virtual ~MathNumericalDiffNorm() = default; + virtual ~MathNumericalDiff2() = default; virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; protected: int32_t mReadSamples = 0; @@ -82,16 +100,16 @@ namespace l::nodegraph { }; /*********************************************************************/ - class MathNumericalDiff : public NodeGraphOp { + class MathNumericalDiff1 : public NodeGraphOp { public: - MathNumericalDiff(NodeGraphBase* node) : - NodeGraphOp(node, "Difference") + MathNumericalDiff1(NodeGraphBase* node) : + NodeGraphOp(node, "Difference 1") { AddInput2("In"); AddOutput2("Diff"); } - virtual ~MathNumericalDiff() = default; + virtual ~MathNumericalDiff1() = default; virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; protected: int32_t mReadSamples = 0; @@ -148,9 +166,9 @@ namespace l::nodegraph { }; /*********************************************************************/ - class MathNumericalReconstructor : public NodeGraphOp { + class MathNumericalReconstructor1 : public NodeGraphOp { public: - MathNumericalReconstructor(NodeGraphBase* node) : + MathNumericalReconstructor1(NodeGraphBase* node) : NodeGraphOp(node, "Reconstructor") { AddInput2("In"); @@ -168,7 +186,7 @@ namespace l::nodegraph { AddOutput2("Intgr2+base"); } - virtual ~MathNumericalReconstructor() = default; + virtual ~MathNumericalReconstructor1() = default; virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; protected: int32_t mReadSamples = 0; diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 4ea8f1e5..1a0c52e3 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -287,6 +287,9 @@ namespace l::nodegraph { case 111: node = mMainNodeGraph.NewNode(id, NodeType::Default); break; + case 112: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; // Math logical operators case 120: @@ -304,13 +307,13 @@ namespace l::nodegraph { node = mMainNodeGraph.NewNode(id, NodeType::Default); break; case 141: - node = mMainNodeGraph.NewNode(id, NodeType::Default); + node = mMainNodeGraph.NewNode(id, NodeType::Default); break; case 142: - node = mMainNodeGraph.NewNode(id, NodeType::Default); + node = mMainNodeGraph.NewNode(id, NodeType::Default); break; case 143: - node = mMainNodeGraph.NewNode(id, NodeType::Default); + node = mMainNodeGraph.NewNode(id, NodeType::Default); break; case 144: node = mMainNodeGraph.NewNode(id, NodeType::Default); @@ -319,7 +322,7 @@ namespace l::nodegraph { node = mMainNodeGraph.NewNode(id, NodeType::Default); break; case 146: - node = mMainNodeGraph.NewNode(id, NodeType::Default); + node = mMainNodeGraph.NewNode(id, NodeType::Default); break; case 147: node = mMainNodeGraph.NewNode(id, NodeType::Default); @@ -330,6 +333,9 @@ namespace l::nodegraph { case 149: node = mMainNodeGraph.NewNode(id, NodeType::Default); break; + case 150: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; // Trading data io case 200: @@ -634,6 +640,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Aritmethic", 109, "Pow"); RegisterNodeType("Math.Aritmethic", 110, "Sum3"); RegisterNodeType("Math.Aritmethic", 111, "Sum5"); + RegisterNodeType("Math.Aritmethic", 112, "Minmax"); } else if (typeGroup == "Math.Logic") { RegisterNodeType("Math.Logic", 120, "And"); @@ -642,15 +649,16 @@ namespace l::nodegraph { } else if (typeGroup == "Math.Numerical") { RegisterNodeType("Math.Numerical", 140, "Integral", "Basically a temporal summation node with a EWA on the output with a cooefficient 'friction'"); - RegisterNodeType("Math.Numerical", 141, "Change", "Temporal change. Computes the value of (v_now - v_prev / (abs(v_now) + abs(v_prev))."); - RegisterNodeType("Math.Numerical", 142, "Difference2", "Temporal difference 2. Computes the value of (v_now / v_prev - 1)"); - RegisterNodeType("Math.Numerical", 143, "Difference", "Temporal difference. Computes the value of (v_now - v_prev)."); + RegisterNodeType("Math.Numerical", 141, "Change 1", "Temporal change 1. Computes the value: (v_now - v_prev) / (abs(v_now) + abs(v_prev))."); + RegisterNodeType("Math.Numerical", 142, "Difference 2", "Temporal difference 2. Computes the value: (v_now / v_prev - 1)"); + RegisterNodeType("Math.Numerical", 143, "Difference 1", "Temporal difference 1. Computes the value: (v_now - v_prev)."); RegisterNodeType("Math.Numerical", 144, "Level Trigger", "Determines where some input is located between two extremes (min/max) in the format [0,1] "); RegisterNodeType("Math.Numerical", 145, "Minmax Channel", "Computes the range between the EWA smootherd min/max inputs"); RegisterNodeType("Math.Numerical", 146, "Reconstructor", "Deconstructs the input into derivatives (change per index) and outputs the sum of through a ewa with a cooefficient of 'friction' {x1 = x0 + friction * (target - x0)}. An second output is provided which is the average of the last two outputs of that function."); RegisterNodeType("Math.Numerical", 147, "Reconstructor 2", ""); RegisterNodeType("Math.Numerical", 148, "Unitmap", "Maps the input to [-1,1] via a sigmoid function. A scale factor can be provided that changes the shape of the mapping"); RegisterNodeType("Math.Numerical", 149, "EMA", "Exponential moving average [ema1=(ema0*(n-1)+input)/n]"); + RegisterNodeType("Math.Numerical", 150, "Change 2", "Temporal change 2. Computes the value: (v_now - v_prev) / abs(v_now)."); } else if (typeGroup == "Trading.Data IO") { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index e2778765..f34197e7 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -35,7 +35,7 @@ namespace l::nodegraph { } /*********************************************************************/ - void MathNumericalTemporalChange::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + void MathNumericalTemporalChange1::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto input0 = &inputs.at(0).Get(numSamples); auto output = &outputs.at(0).Get(numSamples); @@ -46,6 +46,36 @@ namespace l::nodegraph { if (divisor > 0.0f) { value = 2.0f * value / divisor; } + else { + value = 0.0f; + } + mInputPrev = input; + *output++ = value; + } + + mReadSamples += numSamples; + + if (mReadSamples >= numCacheSamples) { + mReadSamples = 0; + mInputPrev = 0.0f; + } + } + + /*********************************************************************/ + void MathNumericalTemporalChange2::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + auto input0 = &inputs.at(0).Get(numSamples); + auto output = &outputs.at(0).Get(numSamples); + + for (int32_t i = 0; i < numSamples; i++) { + float input = *input0++; + float value = input - mInputPrev; + float divisor = l::math::abs(input); + if (divisor > 0.0f) { + value = value / divisor; + } + else { + value = 0.0f; + } mInputPrev = input; *output++ = value; } @@ -59,7 +89,7 @@ namespace l::nodegraph { } /*********************************************************************/ - void MathNumericalDiffNorm::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + void MathNumericalDiff2::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto input0 = &inputs.at(0).Get(numSamples); auto output = &outputs.at(0).Get(numSamples); @@ -92,7 +122,7 @@ namespace l::nodegraph { } /*********************************************************************/ - void MathNumericalDiff::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + void MathNumericalDiff1::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto input0 = &inputs.at(0).Get(numSamples); auto output = &outputs.at(0).Get(numSamples); @@ -212,7 +242,7 @@ namespace l::nodegraph { } /*********************************************************************/ - void MathNumericalReconstructor::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + void MathNumericalReconstructor1::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto inInput = &inputs.at(0).Get(numSamples); auto baseInput = inputs.at(1).GetIterator(); From a8023e6290e385aa3a9ac5d6964fe72e68c6081b Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 8 Sep 2025 13:15:37 +0200 Subject: [PATCH 099/179] NG: Add chart line node for 2 and 3 interleaved lines. --- .../nodegraph/operations/NodeGraphOpUI.h | 47 ++++++++++++++- .../source/common/NodeGraphSchema.cpp | 10 +++- .../common/operations/NodeGraphOpUI.cpp | 57 ++++++++++++++++--- 3 files changed, 105 insertions(+), 9 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index a59f0d3f..2aebd678 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -90,7 +90,7 @@ namespace l::nodegraph { class GraphUIChartLine : public NodeGraphOpCached { public: GraphUIChartLine(NodeGraphBase* node) : - NodeGraphOpCached(node, "Chart Line") + NodeGraphOpCached(node, "Chart Line 1") { AddInput2("X", 1, InputFlags(false, false, false, false)); @@ -108,6 +108,51 @@ namespace l::nodegraph { int32_t mLatestUnixtime = 0; }; + /*********************************************************************/ + class GraphUIChartLine2 : public NodeGraphOpCached { + public: + GraphUIChartLine2(NodeGraphBase* node) : + NodeGraphOpCached(node, "Chart Line 2") + { + AddInput2("X", 1, InputFlags(false, false, false, false)); + AddInput2("Y1", 1, InputFlags(false, false, false, false)); + AddInput2("Y2", 1, InputFlags(false, false, false, false)); + AddInput2("Name", 1, InputFlags(false, true, true, true)); + AddOutput("Data"); + } + virtual ~GraphUIChartLine2() = default; + virtual void DefaultDataInit() override { + NodeGraphOp::DefaultDataInit(); + mNode->SetInput(3, "Chart Line"); + } + virtual void ProcessWriteCached(int32_t writtenSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + protected: + int32_t mLatestUnixtime = 0; + }; + + /*********************************************************************/ + class GraphUIChartLine3 : public NodeGraphOpCached { + public: + GraphUIChartLine3(NodeGraphBase* node) : + NodeGraphOpCached(node, "Chart Line 3") + { + AddInput2("X", 1, InputFlags(false, false, false, false)); + AddInput2("Y1", 1, InputFlags(false, false, false, false)); + AddInput2("Y2", 1, InputFlags(false, false, false, false)); + AddInput2("Y3", 1, InputFlags(false, false, false, false)); + AddInput2("Name", 1, InputFlags(false, true, true, true)); + AddOutput("Data"); + } + virtual ~GraphUIChartLine3() = default; + virtual void DefaultDataInit() override { + NodeGraphOp::DefaultDataInit(); + mNode->SetInput(4, "Chart Line"); + } + virtual void ProcessWriteCached(int32_t writtenSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + protected: + int32_t mLatestUnixtime = 0; + }; + /*********************************************************************/ class GraphUICandleSticks : public NodeGraphOpCached { public: diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 1a0c52e3..b89d7640 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -522,6 +522,12 @@ namespace l::nodegraph { case 605: node = mMainNodeGraph.NewNode(id, NodeType::ExternalOutput); break; + case 606: + node = mMainNodeGraph.NewNode(id, NodeType::ExternalOutput); + break; + case 607: + node = mMainNodeGraph.NewNode(id, NodeType::ExternalOutput); + break; @@ -731,10 +737,12 @@ namespace l::nodegraph { else if (typeGroup == "UI") { RegisterNodeType("UI", 600, "UI Checkbox"); RegisterNodeType("UI", 601, "UI Slider"); - RegisterNodeType("UI", 602, "UI Chart Lines"); + RegisterNodeType("UI", 602, "UI Chart Lines 1"); RegisterNodeType("UI", 603, "UI Candle Sticks"); RegisterNodeType("UI", 604, "UI Text"); RegisterNodeType("UI", 605, "UI Chart Markers"); + RegisterNodeType("UI", 606, "UI Chart Lines 2"); + RegisterNodeType("UI", 607, "UI Chart Lines 3"); } else { LOG(LogWarning) << "Type group does not exist: " << typeGroup; diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index 72b7f55f..48212890 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -97,6 +97,7 @@ namespace l::nodegraph { std::string_view GraphUIText::GetOutputText() { return mOutputText.str(); } + /*********************************************************************/ void GraphUIChartLine::ProcessWriteCached(int32_t writtenSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { int32_t mChannels = 2; @@ -111,15 +112,57 @@ namespace l::nodegraph { auto buf = out + writtenSamples * mChannels; int32_t j = 0; for (j = 0; j < numSamples; j++) { - auto unixtimef = *input[0]; - auto unixtime = l::math::algorithm::convert(unixtimef); - if (unixtimef == 0.0f || mLatestUnixtime >= unixtime) { - //mLatestUnixtime = unixtime; - //break; + for (int32_t i = 0; i < mChannels; i++) { + *buf++ = *input[i]++; } - else { - mLatestUnixtime = unixtime; + } + for (; j < numSamples; j++) { + for (int32_t i = 0; i < mChannels; i++) { + *buf++ = 0.0f; + } + } + } + + /*********************************************************************/ + void GraphUIChartLine2::ProcessWriteCached(int32_t writtenSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + int32_t mChannels = 3; + + outputs.at(0).MinimizeBuffer(numCacheSamples * mChannels); + float* out = &outputs.at(0).Get(numCacheSamples * mChannels); + + float* input[3]; + for (int32_t j = 0; j < mChannels; j++) { + input[j] = &inputs.at(j).Get(numSamples); + } + auto buf = out + writtenSamples * mChannels; + int32_t j = 0; + for (j = 0; j < numSamples; j++) { + for (int32_t i = 0; i < mChannels; i++) { + *buf++ = *input[i]++; + } + } + for (; j < numSamples; j++) { + for (int32_t i = 0; i < mChannels; i++) { + *buf++ = 0.0f; } + } + } + + + /*********************************************************************/ + void GraphUIChartLine3::ProcessWriteCached(int32_t writtenSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + int32_t mChannels = 4; + + outputs.at(0).MinimizeBuffer(numCacheSamples * mChannels); + float* out = &outputs.at(0).Get(numCacheSamples * mChannels); + + float* input[4]; + for (int32_t j = 0; j < mChannels; j++) { + input[j] = &inputs.at(j).Get(numSamples); + } + auto buf = out + writtenSamples * mChannels; + int32_t j = 0; + for (j = 0; j < numSamples; j++) { for (int32_t i = 0; i < mChannels; i++) { *buf++ = *input[i]++; } From 83c21927b59f62059ae3f15d161bcc3f485d37d0 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 14 Sep 2025 17:50:05 +0200 Subject: [PATCH 100/179] NG: Add div and minmax node. Fix descriptions. --- .../operations/NodeGraphOpMathAritmethic.h | 68 +++++++++++++++++-- .../operations/NodeGraphOpMathNumerical.h | 2 +- .../source/common/NodeGraphSchema.cpp | 18 +++-- 3 files changed, 78 insertions(+), 10 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h index bc8bf0ca..6577911a 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h @@ -180,7 +180,7 @@ namespace l::nodegraph { class MathAritmethicMultiply3 : public NodeGraphOp { public: MathAritmethicMultiply3(NodeGraphBase* node) : - NodeGraphOp(node, "Multiply3") + NodeGraphOp(node, "Multiply 3") { AddInput("a"); AddInput("b"); @@ -278,7 +278,7 @@ namespace l::nodegraph { class MathAritmethicSum3 : public NodeGraphOp { public: MathAritmethicSum3(NodeGraphBase* node) : - NodeGraphOp(node, "Sum3") + NodeGraphOp(node, "Sum 3") { AddInput("a"); AddInput("b"); @@ -302,7 +302,7 @@ namespace l::nodegraph { class MathAritmethicSum5 : public NodeGraphOp { public: MathAritmethicSum5(NodeGraphBase* node) : - NodeGraphOp(node, "Sum5") + NodeGraphOp(node, "Sum 5") { AddInput("a"); AddInput("b"); @@ -330,7 +330,7 @@ namespace l::nodegraph { class MathAritmethicMinMax : public NodeGraphOp { public: MathAritmethicMinMax(NodeGraphBase* node) : - NodeGraphOp(node, "Minmax") + NodeGraphOp(node, "Minmax 1") { AddInput("In"); AddInput("Min"); @@ -365,4 +365,64 @@ namespace l::nodegraph { } }; + /*********************************************************************/ + class MathAritmethicMinMax2 : public NodeGraphOp { + public: + MathAritmethicMinMax2(NodeGraphBase* node) : + NodeGraphOp(node, "Minmax 2") + { + AddInput("In1"); + AddInput("In2"); + + AddOutput("Min"); + AddOutput("Max"); + } + virtual ~MathAritmethicMinMax2() = default; + virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { + auto in1Input = inputs.at(0).GetIterator(numSamples); + auto in2Input = inputs.at(1).GetIterator(numSamples); + auto minOutput = &outputs.at(0).Get(numSamples); + auto maxOutput = &outputs.at(1).Get(numSamples); + + for (int32_t i = 0; i < numSamples; i++) { + auto in1 = *in1Input++; + auto in2 = *in2Input++; + + *minOutput++ = in1 < in2 ? in1 : in2; + *maxOutput++ = in2 < in1 ? in2 : in1; + } + } + }; + + /*********************************************************************/ + class MathAritmethicDiv : public NodeGraphOp { + public: + MathAritmethicDiv(NodeGraphBase* node) : + NodeGraphOp(node, "Div") + { + AddInput("In1"); + AddInput("In2"); + + AddOutput("Out"); + } + virtual ~MathAritmethicDiv() = default; + virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { + auto in1Input = inputs.at(0).GetIterator(numSamples); + auto in2Input = inputs.at(1).GetIterator(numSamples); + auto outOutput = &outputs.at(0).Get(numSamples); + + for (int32_t i = 0; i < numSamples; i++) { + auto in1 = *in1Input++; + auto in2 = *in2Input++; + + auto out = 0.0f; + if (in2 != 0.0f) { + out = in1 / in2; + } + + *outOutput++ = out; + } + } + }; + } \ No newline at end of file diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 5cb3de11..e6f95216 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -169,7 +169,7 @@ namespace l::nodegraph { class MathNumericalReconstructor1 : public NodeGraphOp { public: MathNumericalReconstructor1(NodeGraphBase* node) : - NodeGraphOp(node, "Reconstructor") + NodeGraphOp(node, "Reconstructor 1") { AddInput2("In"); AddInput("Base", 0.0f, 1); diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index b89d7640..32406d20 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -290,6 +290,12 @@ namespace l::nodegraph { case 112: node = mMainNodeGraph.NewNode(id, NodeType::Default); break; + case 113: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; + case 114: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; // Math logical operators case 120: @@ -640,13 +646,15 @@ namespace l::nodegraph { RegisterNodeType("Math.Aritmethic", 103, "Neg"); RegisterNodeType("Math.Aritmethic", 104, "Abs"); RegisterNodeType("Math.Aritmethic", 105, "Log"); - RegisterNodeType("Math.Aritmethic", 106, "Mul3"); + RegisterNodeType("Math.Aritmethic", 106, "Mul 3"); RegisterNodeType("Math.Aritmethic", 107, "Madd"); RegisterNodeType("Math.Aritmethic", 108, "Round"); RegisterNodeType("Math.Aritmethic", 109, "Pow"); - RegisterNodeType("Math.Aritmethic", 110, "Sum3"); - RegisterNodeType("Math.Aritmethic", 111, "Sum5"); - RegisterNodeType("Math.Aritmethic", 112, "Minmax"); + RegisterNodeType("Math.Aritmethic", 110, "Sum 3"); + RegisterNodeType("Math.Aritmethic", 111, "Sum 5"); + RegisterNodeType("Math.Aritmethic", 112, "Minmax 1", "Compares input with a min and a max value. Outputs values in the 1) min/max range, 2) larger or equal to min and 3) less or equal to max, respectively."); + RegisterNodeType("Math.Aritmethic", 113, "Minmax 2", "Compares the inputs. Outputs the 1) smaller and the 2) larger values respectively."); + RegisterNodeType("Math.Aritmethic", 114, "Div", "Divides input 1 with input 2"); } else if (typeGroup == "Math.Logic") { RegisterNodeType("Math.Logic", 120, "And"); @@ -660,7 +668,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Numerical", 143, "Difference 1", "Temporal difference 1. Computes the value: (v_now - v_prev)."); RegisterNodeType("Math.Numerical", 144, "Level Trigger", "Determines where some input is located between two extremes (min/max) in the format [0,1] "); RegisterNodeType("Math.Numerical", 145, "Minmax Channel", "Computes the range between the EWA smootherd min/max inputs"); - RegisterNodeType("Math.Numerical", 146, "Reconstructor", "Deconstructs the input into derivatives (change per index) and outputs the sum of through a ewa with a cooefficient of 'friction' {x1 = x0 + friction * (target - x0)}. An second output is provided which is the average of the last two outputs of that function."); + RegisterNodeType("Math.Numerical", 146, "Reconstructor 1", "Deconstructs the input into derivatives (change per index) and outputs the sum of through a ewa with a cooefficient of 'friction' {x1 = x0 + friction * (target - x0)}. An second output is provided which is the average of the last two outputs of that function."); RegisterNodeType("Math.Numerical", 147, "Reconstructor 2", ""); RegisterNodeType("Math.Numerical", 148, "Unitmap", "Maps the input to [-1,1] via a sigmoid function. A scale factor can be provided that changes the shape of the mapping"); RegisterNodeType("Math.Numerical", 149, "EMA", "Exponential moving average [ema1=(ema0*(n-1)+input)/n]"); From 81279a91c59e6fa93c09173663c5339db88aaa38 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Wed, 17 Sep 2025 01:38:15 +0200 Subject: [PATCH 101/179] NG: Add an event handler for common node state changes. --- .../nodegraph/include/nodegraph/core/NodeGraphBase.h | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h index ad22eba2..270873ce 100644 --- a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h @@ -132,6 +132,7 @@ namespace l::nodegraph { virtual void NodeHasChanged(); bool IsOutOfDate2(); virtual NodeType GetOutputType(); + virtual void RecieveEvent(int32_t id, int32_t cmd, void* userdata) = 0; template bool IsOfOperation() { @@ -221,6 +222,7 @@ namespace l::nodegraph { virtual void Process(int32_t, int32_t, std::vector&, std::vector&) {}; virtual void Tick(int32_t /*tickCount*/, float /*delta*/) {} virtual void InputHasChanged(); + virtual void RecieveEvent(int32_t, int32_t, void*) {} int8_t GetNumInputs(); int8_t GetNumOutputs(); @@ -388,6 +390,13 @@ namespace l::nodegraph { return &mOperation; } + virtual void RecieveEvent(int32_t id, int32_t cmd, void* userdata) override { + auto op = GetOperation(); + if (op) { + op->RecieveEvent(id, cmd, userdata); + } + } + protected: T mOperation; }; From 3a82c94894f609db655d2ef42147f41f79861b42 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Wed, 17 Sep 2025 19:11:57 +0200 Subject: [PATCH 102/179] Rename LOG -> LLOG because it has global name conflicts with some deps. --- packages/audio/source/common/PortAudio.cpp | 16 ++--- packages/audio/tests/common/PortAudioTest.cpp | 2 +- .../include/concurrency/ExecutorService.h | 2 +- .../source/common/ExecutorService.cpp | 48 +++++++-------- .../tests/common/ContainersTest.cpp | 6 +- .../tests/common/ThreadingTest.cpp | 22 +++---- packages/crypto/source/common/Crypto.cpp | 4 +- packages/crypto/tests/common/CryptoppTest.cpp | 58 +++++++++--------- packages/crypto/tests/common/ed25519Test.cpp | 56 ++++++++--------- .../ecs/include/ecs/entityecs/BaseSystem.h | 4 +- packages/ecs/include/ecs/entityecs/ECSExt.h | 2 +- packages/ecs/tests/common/EntityECS2Test.cpp | 22 +++---- packages/ecs/tests/common/EntityECSTest.cpp | 40 ++++++------- .../source/common/filesystem/File.cpp | 20 +++---- packages/hid/source/common/KeyState.cpp | 2 +- packages/hid/source/common/Midi.cpp | 16 ++--- packages/hid/source/windows/MidiWindows.cpp | 40 ++++++------- packages/logging/include/logging/Log.h | 11 +++- packages/logging/include/logging/Static.h | 2 +- packages/math/include/math/MathAlgorithm.h | 2 +- packages/math/tests/common/MathTweenTest.cpp | 10 ++-- packages/memory/source/common/Arena.cpp | 8 +-- .../memory/tests/common/ContainersTest.cpp | 2 +- packages/meta/tests/common/ReflectionTest.cpp | 18 +++--- .../source/common/NetworkConnection.cpp | 60 +++++++++---------- .../source/common/NetworkInterfaceWS.cpp | 6 +- .../network/source/common/NetworkManager.cpp | 12 ++-- .../tests/common/NetworkInterfaceTest.cpp | 4 +- .../tests/common/NetworkManagerTest.cpp | 10 ++-- .../tests/common/NetworkWebSocketTest.cpp | 12 ++-- .../include/nodegraph/core/NodeGraphBase.h | 8 +-- .../include/nodegraph/core/NodeGraphGroup.h | 2 +- .../source/common/NodeGraphSchema.cpp | 18 +++--- .../source/common/core/NodeGraphGroup.cpp | 10 ++-- .../operations/NodeGraphOpDeviceIOInput.cpp | 2 +- .../tests/common/NodeGraphBatchingTest.cpp | 4 +- .../tests/common/NodeGraphDataTest.cpp | 8 +-- .../tests/common/NodeGraphSchemaTest.cpp | 4 +- .../common/NodeGraphSerializationTest.cpp | 4 +- .../physics/include/physics/Integration.h | 8 +-- .../physics/tests/common/BoxSweepTest.cpp | 2 +- packages/physics/tests/common/GridMapTest.cpp | 2 +- packages/physics/tests/common/VectorTest.cpp | 8 +-- .../include/rendering/DataConversion.h | 2 +- .../rendering/include/rendering/GLFWShaders.h | 6 +- .../include/rendering/GeometryManip.h | 2 +- .../include/rendering/ui/UIContainer.h | 2 +- .../rendering/source/common/FPSInterface.cpp | 8 +-- .../rendering/source/common/GLFWRenderVAO.cpp | 4 +- .../rendering/source/common/GLFWWindow.cpp | 12 ++-- packages/rendering/source/common/Geometry.cpp | 12 ++-- .../rendering/source/common/ImageSupport.cpp | 4 +- .../source/common/ui/UINodeEditor.cpp | 6 +- .../include/serialization/JsonParser.h | 8 +-- .../source/common/SerializationBase.cpp | 6 +- .../serialization/tests/common/Base16Test.cpp | 6 +- .../serialization/tests/common/Base64Test.cpp | 6 +- .../serialization/tests/common/JsonxxTest.cpp | 2 +- .../source/common/FileCacheProvider.cpp | 2 +- packages/testing/include/testing/Test.h | 44 +++++++------- packages/testing/source/common/Test.cpp | 30 +++++----- packages/testing/tests/common/LoggingTest.cpp | 12 ++-- .../windows/platform/PlatformWindows.cpp | 14 ++--- .../tools/source/windows/utils/Opengl.cpp | 14 ++--- .../tools/source/windows/utils/Process.cpp | 10 ++-- .../tools/source/windows/utils/Socket.cpp | 30 +++++----- packages/tools/source/windows/utils/Win32.cpp | 24 ++++---- 67 files changed, 436 insertions(+), 427 deletions(-) diff --git a/packages/audio/source/common/PortAudio.cpp b/packages/audio/source/common/PortAudio.cpp index 6c8e4b3f..5f374832 100644 --- a/packages/audio/source/common/PortAudio.cpp +++ b/packages/audio/source/common/PortAudio.cpp @@ -73,13 +73,13 @@ namespace l::audio { auto maxDevices = Pa_GetDeviceCount(); for (int32_t index = 0; index < maxDevices; index++) { auto deviceInfo = Pa_GetDeviceInfo(index); - LOG(LogInfo) << "Audio device " << index << ": " << deviceInfo->name; + LLOG(LogInfo) << "Audio device " << index << ": " << deviceInfo->name; } mInputParameters.device = Pa_GetDefaultInputDevice(); /* default input device */ mOutputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */ if (mOutputParameters.device == paNoDevice) { - LOG(LogError) << "Error: No default output device."; + LLOG(LogError) << "Error: No default output device."; return false; } @@ -104,10 +104,10 @@ namespace l::audio { //auto inputInfo = Pa_GetDeviceInfo(mInputParameters.device); mInputParameters.suggestedLatency = latencyMs / 1000.0f; // inputInfo->defaultHighInputLatency; - LOG(LogInfo) << "Port Audio set latency ms: " << static_cast(latencyMs); + LLOG(LogInfo) << "Port Audio set latency ms: " << static_cast(latencyMs); } else { - LOG(LogInfo) << "Port Audio recommended latency ms: " << static_cast(defaultLatency * 1000.0f); + LLOG(LogInfo) << "Port Audio recommended latency ms: " << static_cast(defaultLatency * 1000.0f); mOutputParameters.suggestedLatency = defaultLatency; } mOutputParameters.hostApiSpecificStreamInfo = NULL; @@ -149,7 +149,7 @@ namespace l::audio { &mAudioStreamData); if (err != paNoError) { - LOG(LogError) << "Failed to open stream: " << err; + LLOG(LogError) << "Failed to open stream: " << err; return false; } return true; @@ -159,7 +159,7 @@ namespace l::audio { bool AudioStream::StartStream() { auto err = Pa_StartStream(mPaStream); if (err != paNoError) { - LOG(LogError) << "Failed to start stream: " << err; + LLOG(LogError) << "Failed to start stream: " << err; return false; } @@ -212,7 +212,7 @@ namespace l::audio { } auto err = Pa_CloseStream(mPaStream); if (err != paNoError) { - LOG(LogError) << "Failed to close stream: " << err; + LLOG(LogError) << "Failed to close stream: " << err; return false; } return true; @@ -237,7 +237,7 @@ namespace l::audio { bool AudioManager::Init() { auto err = Pa_Initialize(); if (err != paNoError) { - LOG(LogError) << "Failed to initialize port audio."; + LLOG(LogError) << "Failed to initialize port audio."; return false; } return true; diff --git a/packages/audio/tests/common/PortAudioTest.cpp b/packages/audio/tests/common/PortAudioTest.cpp index 426030b0..35bb0f7c 100644 --- a/packages/audio/tests/common/PortAudioTest.cpp +++ b/packages/audio/tests/common/PortAudioTest.cpp @@ -58,7 +58,7 @@ TEST(PortAudio, Setup) { if (!stream->StopStream()) { - LOG(LogError) << "Failed to stop stream"; + LLOG(LogError) << "Failed to stop stream"; } manager.CloseOutStream("speaker"); diff --git a/packages/concurrency/include/concurrency/ExecutorService.h b/packages/concurrency/include/concurrency/ExecutorService.h index 8d330929..a9e1c111 100644 --- a/packages/concurrency/include/concurrency/ExecutorService.h +++ b/packages/concurrency/include/concurrency/ExecutorService.h @@ -95,7 +95,7 @@ namespace l::concurrency { Worker(Worker&&) = default; Worker(const Worker&) = default; virtual ~Worker() override { - //LOG(LogDebug) << "Destroying " << mName; + //LLOG(LogDebug) << "Destroying " << mName; } RunnableResult run(const RunState& state) override; diff --git a/packages/concurrency/source/common/ExecutorService.cpp b/packages/concurrency/source/common/ExecutorService.cpp index 34dd8cbd..03a92216 100644 --- a/packages/concurrency/source/common/ExecutorService.cpp +++ b/packages/concurrency/source/common/ExecutorService.cpp @@ -56,7 +56,7 @@ namespace l::concurrency { } RunnableResult Runnable::run(const RunState&) { - LOG(LogInfo) << "Default run implementation"; + LLOG(LogInfo) << "Default run implementation"; return RunnableResult::SUCCESS; } @@ -85,7 +85,7 @@ namespace l::concurrency { if (mRunState.mDestructing) { return; } - if (gDebugLogging) LOG(LogDebug) << "Executor service shutdown is imminent"; + if (gDebugLogging) LLOG(LogDebug) << "Executor service shutdown is imminent"; { std::lock_guard lock(mRunnablesMutex); mRunState.mDestructing = true; @@ -96,12 +96,12 @@ namespace l::concurrency { } do { - if (gDebugLogging) LOG(LogDebug) << "Executor service notifying threads of imminent shutdown"; + if (gDebugLogging) LLOG(LogDebug) << "Executor service notifying threads of imminent shutdown"; std::this_thread::sleep_for(std::chrono::milliseconds(50)); mCondition.notify_all(); } while (!mRunState.IsShutdown()); - if (gDebugLogging) LOG(LogDebug) << "Executor service notified all waiting schedulers to exit immediately"; + if (gDebugLogging) LLOG(LogDebug) << "Executor service notified all waiting schedulers to exit immediately"; for (auto& t : mPoolThreads) { if (t.joinable()) { @@ -117,18 +117,18 @@ namespace l::concurrency { } void ExecutorService::startJobs() { - LOG(LogDebug) << "Start jobs " << mName; + LLOG(LogDebug) << "Start jobs " << mName; mRunState.mRunning = true; mCondition.notify_all(); } void ExecutorService::pauseJobs() { - LOG(LogDebug) << "Pause jobs " << mName; + LLOG(LogDebug) << "Pause jobs " << mName; mRunState.mRunning = false; } void ExecutorService::clearJobs() { - LOG(LogDebug) << "Clear jobs " << mName; + LLOG(LogDebug) << "Clear jobs " << mName; std::lock_guard lock(mRunnablesMutex); mRunState.mRunning = false; @@ -138,13 +138,13 @@ namespace l::concurrency { bool ExecutorService::queueJob(std::unique_ptr runnable) { { if (mRunState.mDestructing) { - LOG(LogWarning) << "Service is shutdown and waiting for destruction"; + LLOG(LogWarning) << "Service is shutdown and waiting for destruction"; return false; } std::lock_guard lock(mRunnablesMutex); if (mMaxQueuedJobs > 0 && mRunnables.size() > mMaxQueuedJobs) { - LOG(LogWarning) << "Too many jobs!"; + LLOG(LogWarning) << "Too many jobs!"; return false; } mRunnables.push_back(std::move(runnable)); @@ -173,16 +173,16 @@ namespace l::concurrency { } std::unique_ptr runnable = nullptr; - if (gDebugLogging) LOG(LogDebug) << "Scheduler " << id << " started"; + if (gDebugLogging) LLOG(LogDebug) << "Scheduler " << id << " started"; if (!mRunState.mRunning) { std::unique_lock lock(mRunnablesMutex); - if (gDebugLogging) LOG(LogDebug) << "Scheduler " << id << " is paused"; + if (gDebugLogging) LLOG(LogDebug) << "Scheduler " << id << " is paused"; mCondition.wait(lock); } else { std::unique_lock lock(mRunnablesMutex); if (mRunnables.empty()) { - if (gDebugLogging) LOG(LogDebug) << "Scheduler " << id << " is waiting for work"; + if (gDebugLogging) LLOG(LogDebug) << "Scheduler " << id << " is waiting for work"; mCondition.wait(lock); } else { @@ -194,10 +194,10 @@ namespace l::concurrency { if (gDebugLogging) { if (runnable->NumTries() > 0) { - LOG(LogDebug) << "Scheduler " << id << " picked up requeued(" << runnable->NumTries() << ") job"; + LLOG(LogDebug) << "Scheduler " << id << " picked up requeued(" << runnable->NumTries() << ") job"; } else { - LOG(LogDebug) << "Scheduler " << id << " picked up new job"; + LLOG(LogDebug) << "Scheduler " << id << " picked up new job"; } } break; @@ -206,50 +206,50 @@ namespace l::concurrency { lock.unlock(); if (!runnable) { - if (gDebugLogging) LOG(LogDebug) << "Scheduler " << id << " sleeping"; + if (gDebugLogging) LLOG(LogDebug) << "Scheduler " << id << " sleeping"; std::this_thread::sleep_for(std::chrono::milliseconds(50)); } } } if (runnable) { - if (gDebugLogging) LOG(LogDebug) << "Scheduler " << id << " executes task"; + if (gDebugLogging) LLOG(LogDebug) << "Scheduler " << id << " executes task"; mRunState.mNumRunningJobs++; RunnableResult result = runnable->run(mRunState); mRunState.mNumRunningJobs--; switch (result) { case l::concurrency::RunnableResult::FAILURE: - if (gDebugLogging) LOG(LogDebug) << "Scheduler " << id << " task failed"; + if (gDebugLogging) LLOG(LogDebug) << "Scheduler " << id << " task failed"; runnable.reset(); break; case l::concurrency::RunnableResult::CANCELLED: - if (gDebugLogging) LOG(LogDebug) << "Scheduler " << id << " task was cancelled"; + if (gDebugLogging) LLOG(LogDebug) << "Scheduler " << id << " task was cancelled"; runnable.reset(); break; case l::concurrency::RunnableResult::SUCCESS: - if (gDebugLogging) LOG(LogDebug) << "Scheduler " << id << " task succeeded"; + if (gDebugLogging) LLOG(LogDebug) << "Scheduler " << id << " task succeeded"; mNumCompletedJobs++; runnable.reset(); break; case l::concurrency::RunnableResult::REQUEUE_DELAYED: runnable->Reschedule(); - if (gDebugLogging) LOG(LogDebug) << "Job '" + runnable->Name() + "' could not run yet and was requeued "; + if (gDebugLogging) LLOG(LogDebug) << "Job '" + runnable->Name() + "' could not run yet and was requeued "; queueJob(std::move(runnable)); break; case l::concurrency::RunnableResult::REQUEUE_BACKOFF: runnable->Backoff(); if (!runnable->Failed()) { - if (gDebugLogging) LOG(LogDebug) << "Job '" + runnable->Name() + "' was delayed and then requeued with backoff"; + if (gDebugLogging) LLOG(LogDebug) << "Job '" + runnable->Name() + "' was delayed and then requeued with backoff"; queueJob(std::move(runnable)); } else { - if (gDebugLogging) LOG(LogDebug) << "Job '" + runnable->Name() + "' failed and was cancelled"; + if (gDebugLogging) LLOG(LogDebug) << "Job '" + runnable->Name() + "' failed and was cancelled"; runnable.reset(); } break; case l::concurrency::RunnableResult::REQUEUE_IMMEDIATE: - if (gDebugLogging) LOG(LogInfo) << "Scheduler " << mName << " task was requeued"; + if (gDebugLogging) LLOG(LogInfo) << "Scheduler " << mName << " task was requeued"; queueJob(std::move(runnable)); break; } @@ -257,7 +257,7 @@ namespace l::concurrency { } mRunState.mNumRunningJobThreads--; - if (gDebugLogging) LOG(LogInfo) << "Scheduler " << mName << " exited"; + if (gDebugLogging) LLOG(LogInfo) << "Scheduler " << mName << " exited"; } } diff --git a/packages/concurrency/tests/common/ContainersTest.cpp b/packages/concurrency/tests/common/ContainersTest.cpp index 36bce7ce..ffd3aa87 100644 --- a/packages/concurrency/tests/common/ContainersTest.cpp +++ b/packages/concurrency/tests/common/ContainersTest.cpp @@ -100,9 +100,9 @@ TEST(Containers, Polymorphic) { TEST_TRUE(meta::Type::hash_code() != meta::Type::hash_code(), ""); TEST_TRUE(meta::Type::hash_code() != meta::Type::hash_code(), ""); - LOG(LogInfo) << meta::Type::hash_code(); - LOG(LogInfo) << meta::Type::hash_code(); - LOG(LogInfo) << meta::Type::hash_code(); + LLOG(LogInfo) << meta::Type::hash_code(); + LLOG(LogInfo) << meta::Type::hash_code(); + LLOG(LogInfo) << meta::Type::hash_code(); } { diff --git a/packages/concurrency/tests/common/ThreadingTest.cpp b/packages/concurrency/tests/common/ThreadingTest.cpp index a02ca30f..f2aea34c 100644 --- a/packages/concurrency/tests/common/ThreadingTest.cpp +++ b/packages/concurrency/tests/common/ThreadingTest.cpp @@ -27,20 +27,20 @@ TEST(Threading, ExecutorServiceStressTest) { int innerLoops = 100000; - LOG(LogInfo) << "Running " << numJobs << " jobs each doing " << innerLoops << "x some simple work."; + LLOG(LogInfo) << "Running " << numJobs << " jobs each doing " << innerLoops << "x some simple work."; for (int i = 0; i < numJobs; i++) { bool result = executor.queueJob(std::make_unique( "Worker " + std::to_string(i), [index = i, loops = innerLoops, &completedCount, &abortedCount](const l::concurrency::RunState& state) { - //LOG(LogDebug) << "Updating thread " << index; + //LLOG(LogDebug) << "Updating thread " << index; for (int j = 0; j < loops; j++) { j--; j++; j++; if (state.IsShuttingDown()) { abortedCount++; - //LOG(LogDebug) << "Breaking thread looping for shutdown on thread " << index; + //LLOG(LogDebug) << "Breaking thread looping for shutdown on thread " << index; return l::concurrency::RunnableResult::FAILURE; } } @@ -53,7 +53,7 @@ TEST(Threading, ExecutorServiceStressTest) { executor.startJobs(); - LOG(LogInfo) << "Ran " << completedCount << " jobs"; + LLOG(LogInfo) << "Ran " << completedCount << " jobs"; executor.pauseJobs(); @@ -64,13 +64,13 @@ TEST(Threading, ExecutorServiceStressTest) { std::this_thread::sleep_for(std::chrono::milliseconds(5)); } - LOG(LogInfo) << "Ran " << completedCount << " and aborted " << abortedCount << " jobs"; + LLOG(LogInfo) << "Ran " << completedCount << " and aborted " << abortedCount << " jobs"; auto totalCount = completedCount + abortedCount; TEST_EQ(totalCount, 1000, "Count was wrong"); - LOG(LogInfo) << "Ran a total of " << totalCount << " jobs"; + LLOG(LogInfo) << "Ran a total of " << totalCount << " jobs"; return 0; } @@ -86,20 +86,20 @@ TEST(Threading, ExecutorServiceShutdown) { int innerLoops = 10000; - LOG(LogInfo) << "Running " << numJobs << " jobs each doing " << innerLoops << "x some simple work."; + LLOG(LogInfo) << "Running " << numJobs << " jobs each doing " << innerLoops << "x some simple work."; for (int i = 0; i < numJobs; i++) { bool result = executor.queueJob(std::make_unique( "Worker " + std::to_string(i), [index = i, loops = innerLoops, &completedCount, &abortedCount](const l::concurrency::RunState& state) { - //LOG(LogDebug) << "Updating thread " << index; + //LLOG(LogDebug) << "Updating thread " << index; for (int j = 0; j < loops; j++) { j--; j++; j++; if (state.IsShuttingDown()) { abortedCount++; - //LOG(LogDebug) << "Breaking thread looping for shutdown on thread " << index; + //LLOG(LogDebug) << "Breaking thread looping for shutdown on thread " << index; return l::concurrency::RunnableResult::FAILURE; } } @@ -114,14 +114,14 @@ TEST(Threading, ExecutorServiceShutdown) { std::this_thread::sleep_for(std::chrono::milliseconds(150)); } - LOG(LogInfo) << "Ran " << completedCount << " and aborted " << abortedCount << " jobs"; + LLOG(LogInfo) << "Ran " << completedCount << " and aborted " << abortedCount << " jobs"; auto totalCount = completedCount + abortedCount; TEST_EQ(totalCount, 5000, "Count was wrong"); - LOG(LogInfo) << "Ran a total of " << totalCount << " jobs"; + LLOG(LogInfo) << "Ran a total of " << totalCount << " jobs"; return 0; } diff --git a/packages/crypto/source/common/Crypto.cpp b/packages/crypto/source/common/Crypto.cpp index b26b453b..ac676b2b 100644 --- a/packages/crypto/source/common/Crypto.cpp +++ b/packages/crypto/source/common/Crypto.cpp @@ -316,7 +316,7 @@ namespace l::crypto { } else if (pubKey.size() == 44) { // rsa/pem encoded, first 12 bytes are id bytes - LOG(LogInfo) << "Loaded public key of type '" << std::string_view(pubKey.c_str(), 12) << "'"; + LLOG(LogInfo) << "Loaded public key of type '" << std::string_view(pubKey.c_str(), 12) << "'"; memcpy(mPubKey, pubKey.c_str() + 12, pubKey.size() - 12); } } @@ -341,7 +341,7 @@ namespace l::crypto { } else if (pubKey.size() == 44) { // rsa/pem encoded, first 12 bytes are id bytes - LOG(LogInfo) << "Loaded public key of type '" << std::string_view(pubKey.c_str(), 12) << "'"; + LLOG(LogInfo) << "Loaded public key of type '" << std::string_view(pubKey.c_str(), 12) << "'"; memcpy(mPubKey, pubKey.c_str() + 12, pubKey.size() - 12); } } diff --git a/packages/crypto/tests/common/CryptoppTest.cpp b/packages/crypto/tests/common/CryptoppTest.cpp index e2c393bb..f31fe423 100644 --- a/packages/crypto/tests/common/CryptoppTest.cpp +++ b/packages/crypto/tests/common/CryptoppTest.cpp @@ -53,7 +53,7 @@ TEST(CryptoPP, verifydigest) { mHmac.Update(p, message.size()); mHmac.Final(mSignature); auto sign = l::serialization::base16_encode(mSignature, 32); - LOG(LogTest) << sign; + LLOG(LogTest) << sign; /* echo -n 'apiKey=test' | openssl dgst -hex -sha256 -hmac 'NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j' @@ -81,8 +81,8 @@ TEST(Cryptopp, x25519test) { auto skxpemCorrectHex = l::serialization::base16_encode(l::serialization::base64_decode(skxpemCorrect)); auto pkxpemCorrectHex = l::serialization::base16_encode(l::serialization::base64_decode(pkxpemCorrect)); - LOG(LogInfo) << "Secret pem key in hex: " << skxpemCorrectHex; - LOG(LogInfo) << "Public pem key in hex: " << pkxpemCorrectHex; + LLOG(LogInfo) << "Secret pem key in hex: " << skxpemCorrectHex; + LLOG(LogInfo) << "Public pem key in hex: " << pkxpemCorrectHex; CryptoPP::byte privateKeyCorrect[32]; CryptoPP::byte publicKeyCorrect[32]; @@ -101,13 +101,13 @@ TEST(Cryptopp, x25519test) { auto pkxString = std::string_view(reinterpret_cast(publicKeyGen), 32); auto pkxPem = crypto::To25519PemKey(pkxString, true, true); - LOG(LogInfo) << "Public key pem format:\n" << pkxPem; + LLOG(LogInfo) << "Public key pem format:\n" << pkxPem; TEST_TRUE(pkxPem == pkxpemCorrect, ""); auto skxHex = l::serialization::base16_encode(privateKeyCorrect, 32); auto pkxHex = l::serialization::base16_encode(publicKeyGen, 32); - LOG(LogInfo) << "Public correct key hex format:\n" << pkxHex; + LLOG(LogInfo) << "Public correct key hex format:\n" << pkxHex; return 0; } @@ -145,8 +145,8 @@ bool TestGeneratedKey() { auto pkStr = std::string_view(reinterpret_cast(computedPublicKeyData), 32); auto skB16 = l::serialization::base16_encode(skStr); auto pkB16 = l::serialization::base16_encode(pkStr); - LOG(LogInfo) << "generated private:" << skB16; - LOG(LogInfo) << "generated public:" << pkB16; + LLOG(LogInfo) << "generated private:" << skB16; + LLOG(LogInfo) << "generated public:" << pkB16; TEST_FALSE(TestPublicKey(skB16, pkB16), ""); return 0; @@ -198,7 +198,7 @@ bool TestVerifier(std::string_view publicKeyB16, std::string_view message, std:: TEST(Cryptopp, printPemKeys) { auto messageHex = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; auto signatureHex = "dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b58909351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704"; - LOG(LogInfo) << "private key pem: " << crypto::ToPemKey("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"); + LLOG(LogInfo) << "private key pem: " << crypto::ToPemKey("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42"); return 0; } @@ -211,8 +211,8 @@ TEST(Cryptopp, xed) { CryptoPP::byte privateKey[32]; CryptoPP::byte publicKey[32]; xed.GenerateKeyPair(rand, privateKey, publicKey); - LOG(LogTest) << "private key: " << l::string::to_hex2(privateKey, 32); - LOG(LogTest) << "public key: " << l::string::to_hex2(publicKey, 32); + LLOG(LogTest) << "private key: " << l::string::to_hex2(privateKey, 32); + LLOG(LogTest) << "public key: " << l::string::to_hex2(publicKey, 32); } return 0; @@ -234,10 +234,10 @@ TEST(Cryptopp, printgenerated) { auto message = std::string_view("TestMessage"); auto len = signer.SignMessage(CryptoPP::NullRNG(), reinterpret_cast(message.data()), message.size(), sign); - LOG(LogTest) << "private key: " << l::serialization::base16_encode(sk, 32); - LOG(LogTest) << "public key: " << l::serialization::base16_encode(pk, 32); - LOG(LogTest) << "message: " << message; - LOG(LogTest) << "signature: " << l::serialization::base16_encode(sign, 64); + LLOG(LogTest) << "private key: " << l::serialization::base16_encode(sk, 32); + LLOG(LogTest) << "public key: " << l::serialization::base16_encode(pk, 32); + LLOG(LogTest) << "message: " << message; + LLOG(LogTest) << "signature: " << l::serialization::base16_encode(sign, 64); return 0; } @@ -251,8 +251,8 @@ TEST(Cryptopp, test2) { auto publicKeyB16 = "C5F9F54D52D5A2FB6AE692B1CCE695017C2EAD755B213D46AC6912F7B979C6CD"; auto messageB16 = "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"; auto signatureB16 = "e30fc92c7548d99838f520eda491e5311ed9ce9fa868e5743191abe8d7f1a45e470f10cc9d23ddc3f5c906851c8b3d974c03006b9afc5bd6263d0fd72dcf5b09"; - LOG(LogInfo) << "private:" << privateKeyB16; - LOG(LogInfo) << "public:" << publicKeyB16; + LLOG(LogInfo) << "private:" << privateKeyB16; + LLOG(LogInfo) << "public:" << publicKeyB16; TEST_TRUE(!TestPublicKey(privateKeyB16, publicKeyB16), ""); TEST_TRUE(!TestSignature(privateKeyB16, messageB16, signatureB16), ""); TEST_TRUE(!TestVerifier(publicKeyB16, messageB16, signatureB16), ""); @@ -265,8 +265,8 @@ TEST(Cryptopp, test3) { auto publicKeyB16 = "EE8D0405408B1036B046F63923421C87AD9046CFB7FB23ED66A7DB0F6F7EDE90"; auto message = "TestMessage"; auto signatureB16 = "743D4194555C5F578F20D859A98DB1F93EB10297609EF3E2A459EE05513CA0D3DBEA5BFDECF17A3A3C9272C24A543882FBF6B717A4E35920CF71C64908C44D0F"; - LOG(LogInfo) << "private:" << privateKeyB16; - LOG(LogInfo) << "public:" << publicKeyB16; + LLOG(LogInfo) << "private:" << privateKeyB16; + LLOG(LogInfo) << "public:" << publicKeyB16; TEST_TRUE(!TestPublicKey(privateKeyB16, publicKeyB16), ""); TEST_TRUE(!TestSignature(privateKeyB16, message, signatureB16), ""); TEST_TRUE(!TestVerifier(publicKeyB16, message, signatureB16), ""); @@ -280,9 +280,9 @@ TEST(Cryptopp, PrintPKCS8) { crypto::CryptoXED25519 crypto; crypto.LoadPublicKeyHex(pk); - LOG(LogTest) << "pk: \n" << pk; - LOG(LogTest) << "Pem public key: \n" << crypto.GetPublicKeyPem(true); - LOG(LogTest) << "PKCS8 public key: \n" << crypto.GetPublicKeyPKCS8(); + LLOG(LogTest) << "pk: \n" << pk; + LLOG(LogTest) << "Pem public key: \n" << crypto.GetPublicKeyPem(true); + LLOG(LogTest) << "PKCS8 public key: \n" << crypto.GetPublicKeyPKCS8(); return 0; } @@ -313,16 +313,16 @@ TEST(Cryptopp, CryptoXED25519) { crypto.LoadPrivateKeyHex(privateKeyHex); TEST_TRUE(crypto.GetPrivateKeyHex() == privateKeyHex, ""); TEST_TRUE(crypto.GetPublicKeyHex() == publicKeyHex, ""); - LOG(LogInfo) << "Private key : " << crypto.GetPrivateKeyHex(); - LOG(LogTest) << "DER0 public key hex: " << crypto.SaveDERPublicKeyHex(false); - LOG(LogTest) << "DER1 public key hex: " << crypto.SaveDERPublicKeyHex(); - LOG(LogTest) << "DER0 public key b64: " << crypto.SaveDERPublicKeyB64(false); - LOG(LogTest) << "DER1 public key b64: \n" << crypto::ToPublicKeyFormat(crypto.SaveDERPublicKeyB64(1)); - LOG(LogTest) << "PEM public key: \n" << crypto.GetPublicKeyPem(true); - LOG(LogTest) << "PKCS8 public key: \n" << crypto.GetPublicKeyPKCS8(); + LLOG(LogInfo) << "Private key : " << crypto.GetPrivateKeyHex(); + LLOG(LogTest) << "DER0 public key hex: " << crypto.SaveDERPublicKeyHex(false); + LLOG(LogTest) << "DER1 public key hex: " << crypto.SaveDERPublicKeyHex(); + LLOG(LogTest) << "DER0 public key b64: " << crypto.SaveDERPublicKeyB64(false); + LLOG(LogTest) << "DER1 public key b64: \n" << crypto::ToPublicKeyFormat(crypto.SaveDERPublicKeyB64(1)); + LLOG(LogTest) << "PEM public key: \n" << crypto.GetPublicKeyPem(true); + LLOG(LogTest) << "PKCS8 public key: \n" << crypto.GetPublicKeyPKCS8(); crypto.AccumulateMessage(message); auto signature = crypto.SignMessageB64(); - LOG(LogTest) << "Sign: \n" << signature; + LLOG(LogTest) << "Sign: \n" << signature; { crypto::CryptoXED25519 cryptoV; diff --git a/packages/crypto/tests/common/ed25519Test.cpp b/packages/crypto/tests/common/ed25519Test.cpp index 869ff326..bb5fce10 100644 --- a/packages/crypto/tests/common/ed25519Test.cpp +++ b/packages/crypto/tests/common/ed25519Test.cpp @@ -21,8 +21,8 @@ TEST(Cryptopp, ed25519test) { auto skpemCorrectHex = l::serialization::base16_encode(l::serialization::base64_decode(skpemCorrect)); auto pkpemCorrectHex = l::serialization::base16_encode(l::serialization::base64_decode(pkpemCorrect)); - LOG(LogInfo) << "Secret pem key in hex: " << skpemCorrectHex; - LOG(LogInfo) << "Public pem key in hex: " << pkpemCorrectHex; + LLOG(LogInfo) << "Secret pem key in hex: " << skpemCorrectHex; + LLOG(LogInfo) << "Public pem key in hex: " << pkpemCorrectHex; unsigned char seed[32]; unsigned char sk[64]; @@ -39,9 +39,9 @@ TEST(Cryptopp, ed25519test) { auto skHex = l::serialization::base16_encode(skStr); auto pkHex = l::serialization::base16_encode(pkStr); - LOG(LogInfo) << "seed hex: " << seedHex; - LOG(LogInfo) << "secret key hex: " << skHex; - LOG(LogInfo) << "public key hex: " << pkHex; + LLOG(LogInfo) << "seed hex: " << seedHex; + LLOG(LogInfo) << "secret key hex: " << skHex; + LLOG(LogInfo) << "public key hex: " << pkHex; auto message = std::string_view("testmessage"); @@ -49,7 +49,7 @@ TEST(Cryptopp, ed25519test) { auto sgStr = std::string_view(reinterpret_cast(sg), 64); auto sgHex = l::serialization::base16_encode(sgStr); - LOG(LogInfo) << "signature of 'testmessage': " << sgHex; + LLOG(LogInfo) << "signature of 'testmessage': " << sgHex; return 0; } @@ -65,36 +65,36 @@ TEST(Crypto, ed2519) { crypto::CryptoED25519 ed25519; ed25519.CreateKeys(pubKey, priKey); - LOG(LogTest) << "public key base64: " << ed25519.GetPubKeyBase64(); - LOG(LogTest) << "private key base64: " << ed25519.GetPriKeyBase64(); - LOG(LogTest) << "public key hex: " << ed25519.GetPubKeyHex(); - LOG(LogTest) << "private key hex: " << ed25519.GetPriKeyHex(); - LOG(LogTest) << "public key pem2: " << ed25519.GetPubKeyPem(); + LLOG(LogTest) << "public key base64: " << ed25519.GetPubKeyBase64(); + LLOG(LogTest) << "private key base64: " << ed25519.GetPriKeyBase64(); + LLOG(LogTest) << "public key hex: " << ed25519.GetPubKeyHex(); + LLOG(LogTest) << "private key hex: " << ed25519.GetPriKeyHex(); + LLOG(LogTest) << "public key pem2: " << ed25519.GetPubKeyPem(); auto signature = ed25519.GetSign(message); - LOG(LogTest) << "signature:" << signature; + LLOG(LogTest) << "signature:" << signature; TEST_FALSE(ed25519.Verify(signature, message + "s", pubKey), ""); TEST_TRUE(ed25519.Verify(signature, message), pubKey); // Signature // r5YGa0VjkFxOgoY1dMyfH6Jf3j0fIzx5oY/V10Xc4b4Mu6tXrF7RZgQXWLCAfonrJdtDKL99wNuB0RGaJSVyAw== - LOG(LogTest) << "signature key hex: " << l::string::to_hex2(l::serialization::base64_decode(signature)); + LLOG(LogTest) << "signature key hex: " << l::string::to_hex2(l::serialization::base64_decode(signature)); // Examples private keys // MC4CAQAwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC - LOG(LogTest) << "private key hex: " << l::string::to_hex2(l::serialization::base64_decode(ed25519.GetPriKeyBase64())); - LOG(LogTest) << l::string::to_hex2(l::serialization::base64_decode("MC4CAQAwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC")); + LLOG(LogTest) << "private key hex: " << l::string::to_hex2(l::serialization::base64_decode(ed25519.GetPriKeyBase64())); + LLOG(LogTest) << l::string::to_hex2(l::serialization::base64_decode("MC4CAQAwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC")); // Examples public key with prefix separately printed - LOG(LogTest) << l::string::to_hex2(l::serialization::base64_decode("MCowBQYDK2VwAyEA")); + LLOG(LogTest) << l::string::to_hex2(l::serialization::base64_decode("MCowBQYDK2VwAyEA")); - LOG(LogTest) << l::string::to_hex2(l::serialization::base64_decode("MCowBQYDK2VwAyEAVBGfgCzo9ILV1gGq0UuqIRwcbL1RMCSxYPGpdjHxaOk=")); + LLOG(LogTest) << l::string::to_hex2(l::serialization::base64_decode("MCowBQYDK2VwAyEAVBGfgCzo9ILV1gGq0UuqIRwcbL1RMCSxYPGpdjHxaOk=")); - //LOG(LogTest) << l::string::to_hex2(l::serialization::base64_decode("MCowBQYDK2VwAyEAhh0h5M77+TuNChqNfxFiOqAT5fy6UbHsO6M4pDGmEuE=")); - //LOG(LogTest) << l::string::to_hex2(l::serialization::base64_decode("MCowBQYDK2VwAyEAgmDRTtj2FA+wzJUIlAL9ly1eovjLBu7uXUFR+jFULmg=")); - //LOG(LogTest) << l::string::to_hex2(l::serialization::base64_decode("MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE=")); + //LLOG(LogTest) << l::string::to_hex2(l::serialization::base64_decode("MCowBQYDK2VwAyEAhh0h5M77+TuNChqNfxFiOqAT5fy6UbHsO6M4pDGmEuE=")); + //LLOG(LogTest) << l::string::to_hex2(l::serialization::base64_decode("MCowBQYDK2VwAyEAgmDRTtj2FA+wzJUIlAL9ly1eovjLBu7uXUFR+jFULmg=")); + //LLOG(LogTest) << l::string::to_hex2(l::serialization::base64_decode("MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE=")); // MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE= return 0; @@ -105,10 +105,10 @@ TEST(Crypto, generate) { ed25519.CreateKeys(); auto message = "TestMessage"; auto sign = ed25519.GetSign(message); - LOG(LogTest) << "public key: " << ed25519.GetPubKeyHex(); - LOG(LogTest) << "private key: " << ed25519.GetPriKeyHex(); - LOG(LogTest) << "message: " << message; - LOG(LogTest) << "signature: " << l::serialization::base16_encode(sign); + LLOG(LogTest) << "public key: " << ed25519.GetPubKeyHex(); + LLOG(LogTest) << "private key: " << ed25519.GetPriKeyHex(); + LLOG(LogTest) << "message: " << message; + LLOG(LogTest) << "signature: " << l::serialization::base16_encode(sign); return 0; } @@ -119,10 +119,10 @@ TEST(Crypto, validation) { auto publicKey = l::string::hex_decode("ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf"); auto message = l::string::hex_decode("ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f"); auto signature = l::string::hex_decode("dc2a4459e7369633a52b1bf277839a00201009a3efbf3ecb69bea2186c26b58909351fc9ac90b3ecfdfbc7c66431e0303dca179c138ac17ad9bef1177331a704"); - LOG(LogTest) << "secret hex:" << l::string::to_hex2(secret); - LOG(LogTest) << "publicKey hex:" << l::string::to_hex2(publicKey); - LOG(LogTest) << "message hex:" << l::string::to_hex2(message); - LOG(LogTest) << "signature hex:" << l::string::to_hex2(signature); + LLOG(LogTest) << "secret hex:" << l::string::to_hex2(secret); + LLOG(LogTest) << "publicKey hex:" << l::string::to_hex2(publicKey); + LLOG(LogTest) << "message hex:" << l::string::to_hex2(message); + LLOG(LogTest) << "signature hex:" << l::string::to_hex2(signature); auto secretBase64 = l::serialization::base64_encode(secret); auto publicKeyBase64 = l::serialization::base64_encode(publicKey); diff --git a/packages/ecs/include/ecs/entityecs/BaseSystem.h b/packages/ecs/include/ecs/entityecs/BaseSystem.h index bf3b7858..7f9f132b 100644 --- a/packages/ecs/include/ecs/entityecs/BaseSystem.h +++ b/packages/ecs/include/ecs/entityecs/BaseSystem.h @@ -36,11 +36,11 @@ class BaseSystem : public EntitySystem2, } virtual void receive(class World*, const Events::OnEntityCreated& event) { - LOG(LogTest) << "An entity was created! " << event.entity->getEntityId(); + LLOG(LogTest) << "An entity was created! " << event.entity->getEntityId(); } virtual void receive(class World*, const Events::OnEntityDestroyed& event) { - LOG(LogTest) << "An entity was destroyed! " << event.entity->getEntityId(); + LLOG(LogTest) << "An entity was destroyed! " << event.entity->getEntityId(); } auto& getComponents() { diff --git a/packages/ecs/include/ecs/entityecs/ECSExt.h b/packages/ecs/include/ecs/entityecs/ECSExt.h index 362906cb..16298cc7 100644 --- a/packages/ecs/include/ecs/entityecs/ECSExt.h +++ b/packages/ecs/include/ecs/entityecs/ECSExt.h @@ -353,7 +353,7 @@ namespace l::ecs { } } if (!it->second) { - LOG(LogError) << "ComponeneViewCache has map entry, but is missing the actual cache for types: " << types_to_string(); + LLOG(LogError) << "ComponeneViewCache has map entry, but is missing the actual cache for types: " << types_to_string(); mComponentCacheMap.erase(it); return nullptr; } diff --git a/packages/ecs/tests/common/EntityECS2Test.cpp b/packages/ecs/tests/common/EntityECS2Test.cpp index ace7b919..49fb088d 100644 --- a/packages/ecs/tests/common/EntityECS2Test.cpp +++ b/packages/ecs/tests/common/EntityECS2Test.cpp @@ -61,7 +61,7 @@ class TestSystem2 : public EntitySystem2, virtual void receive(class World* world, const DeleteEvent& event) override { - LOG(LogTest) << "I received SomeEvent with value " << event.num << "!"; + LLOG(LogTest) << "I received SomeEvent with value " << event.num << "!"; // Let's delete an entity while iterating because why not? world->all([&](Entity* ent) { @@ -69,7 +69,7 @@ class TestSystem2 : public EntitySystem2, world->destroy(world->getById(event.num)); if (ent->getEntityId() == event.num) - LOG(LogInfo) << "Woah, we shouldn't get here!"; + LLOG(LogInfo) << "Woah, we shouldn't get here!"; }); } @@ -78,7 +78,7 @@ class TestSystem2 : public EntitySystem2, }; TEST(EntityECS2, Sample) { - LOG(LogInfo) << "EntityComponentSystem Test"; + LLOG(LogInfo) << "EntityComponentSystem Test"; auto world = World2::createWorld(); @@ -98,17 +98,17 @@ TEST(EntityECS2, Sample) { world->tick({ 0.0f, 10.f }); - LOG(LogInfo) << "After tick(10) and EnableSystem(testSystem): position(" << pos->x << ", " << pos->y << "), rotation(" << rot->angle << ")"; + LLOG(LogInfo) << "After tick(10) and EnableSystem(testSystem): position(" << pos->x << ", " << pos->y << "), rotation(" << rot->angle << ")"; int count = 0; - LOG(LogInfo) << "Counting entities with SomeComponent..."; + LLOG(LogInfo) << "Counting entities with SomeComponent..."; // range based for loop world->each2([&](Entity* ent, ComponentHandle p, ComponentHandle r) { ++count; - //LOG(LogInfo) << "Found entity #" << ent->getEntityId() << ", p{" << p->x << "," << p->y << "}" << ", r{" << r->angle << "}"; + //LLOG(LogInfo) << "Found entity #" << ent->getEntityId() << ", p{" << p->x << "," << p->y << "}" << ", r{" << r->angle << "}"; }); - LOG(LogInfo) << count << " entities have position and rotation!"; + LLOG(LogInfo) << count << " entities have position and rotation!"; for (int i = 0; i < 10; ++i) { @@ -117,7 +117,7 @@ TEST(EntityECS2, Sample) { } // Emitting events - LOG(LogInfo) << "Emit 'SomeEvent' to entity id 4"; + LLOG(LogInfo) << "Emit 'SomeEvent' to entity id 4"; world->emit({ 4 }); world->cleanup(); @@ -149,7 +149,7 @@ TEST(EntityECS2, BugMultipleEntitiesInViewCache) { world->tick({ 0.0f, 10.f }); world->each2([&](Entity* ent, ComponentHandle p, ComponentHandle r) { - LOG(LogInfo) << "Found entity #" << ent->getEntityId() << ", p{" << p->x << "," << p->y << "}" << ", r{" << r->angle << "}"; + LLOG(LogInfo) << "Found entity #" << ent->getEntityId() << ", p{" << p->x << "," << p->y << "}" << ", r{" << r->angle << "}"; }); auto cache = world->getComponentCache(); @@ -239,10 +239,10 @@ PERF_TEST(EntityECS2, EntityStressTest) }); } - LOG(LogInfo) << count << " entities have position and rotation!"; + LLOG(LogInfo) << count << " entities have position and rotation!"; // Emitting events - LOG(LogInfo) << "Emit 'SomeEvent' to entity id 4"; + LLOG(LogInfo) << "Emit 'SomeEvent' to entity id 4"; world->emit({ 5000 }); world->cleanup(); diff --git a/packages/ecs/tests/common/EntityECSTest.cpp b/packages/ecs/tests/common/EntityECSTest.cpp index f35dcbea..b57523e8 100644 --- a/packages/ecs/tests/common/EntityECSTest.cpp +++ b/packages/ecs/tests/common/EntityECSTest.cpp @@ -98,17 +98,17 @@ class TestSystem : public EntitySystem2, virtual void receive(class World* world, const Events::OnComponentRemoved& event) override { - LOG(LogTest) << "A position component was removed!"; + LLOG(LogTest) << "A position component was removed!"; } virtual void receive(class World* world, const Events::OnComponentRemoved& event) override { - LOG(LogTest) << "A rotation component was removed! "; + LLOG(LogTest) << "A rotation component was removed! "; } virtual void receive(class World* world, const DeleteEvent& event) override { - LOG(LogTest) << "I received SomeEvent with value " << event.num << "!"; + LLOG(LogTest) << "I received SomeEvent with value " << event.num << "!"; // Let's delete an entity while iterating because why not? world->all([&](Entity* ent) { @@ -116,7 +116,7 @@ class TestSystem : public EntitySystem2, world->destroy(world->getById(event.num)); if (ent->getEntityId() == event.num) - LOG(LogInfo) << "Woah, we shouldn't get here!"; + LLOG(LogInfo) << "Woah, we shouldn't get here!"; }); } @@ -138,7 +138,7 @@ TEST(EntityECS, ComponentCache) TEST(EntityECS, LifeCycle) { - LOG(LogInfo) << "EntityComponentSystem Test"; + LLOG(LogInfo) << "EntityComponentSystem Test"; auto world = World2::createWorld(); @@ -159,7 +159,7 @@ TEST(EntityECS, LifeCycle) TEST(EntityECS, Sample) { - LOG(LogInfo) << "EntityComponentSystem Test"; + LLOG(LogInfo) << "EntityComponentSystem Test"; auto world = World2::createWorld(); @@ -169,21 +169,21 @@ TEST(EntityECS, Sample) auto pos = ent->assign(0.f, 0.f); auto rot = ent->assign(0.f); - LOG(LogInfo) << "size of an entity: " << sizeof(Entity); - LOG(LogInfo) << "size of Position: " << sizeof(Position); - LOG(LogInfo) << "size of Rotation: " << sizeof(Rotation); + LLOG(LogInfo) << "size of an entity: " << sizeof(Entity); + LLOG(LogInfo) << "size of Position: " << sizeof(Position); + LLOG(LogInfo) << "size of Rotation: " << sizeof(Rotation); - LOG(LogInfo) << "Initial values: position(" << pos->x << ", " << pos->y << "), rotation(" << rot->angle << ")"; + LLOG(LogInfo) << "Initial values: position(" << pos->x << ", " << pos->y << "), rotation(" << rot->angle << ")"; world->tick({ 0.0f, 10.f }); - LOG(LogInfo) << "After tick(10): position(" << pos->x << ", " << pos->y << "), rotation(" << rot->angle << ")"; + LLOG(LogInfo) << "After tick(10): position(" << pos->x << ", " << pos->y << "), rotation(" << rot->angle << ")"; world->disableSystem(entitySystem); world->tick({ 0.0f, 10.f }); - LOG(LogInfo) << "After tick(10) and DisableSystem(testSystem): position(" << pos->x << ", " << pos->y << "), rotation(" << rot->angle << ")"; + LLOG(LogInfo) << "After tick(10) and DisableSystem(testSystem): position(" << pos->x << ", " << pos->y << "), rotation(" << rot->angle << ")"; world->enableSystem(entitySystem); @@ -193,12 +193,12 @@ TEST(EntityECS, Sample) TEST_FUZZY2(pos->y, 20.0f, ""); TEST_FUZZY2(rot->angle, 40.0f, ""); - LOG(LogInfo) << "After tick(10) and EnableSystem(testSystem): position(" << pos->x << ", " << pos->y << "), rotation(" << rot->angle << ")"; + LLOG(LogInfo) << "After tick(10) and EnableSystem(testSystem): position(" << pos->x << ", " << pos->y << "), rotation(" << rot->angle << ")"; ent->remove(); ent->remove(); - LOG(LogInfo) << "Creating more entities..."; + LLOG(LogInfo) << "Creating more entities..."; for (int i = 0; i < 10; ++i) { @@ -207,28 +207,28 @@ TEST(EntityECS, Sample) } int count = 0; - LOG(LogInfo) << "Counting entities with SomeComponent..."; + LLOG(LogInfo) << "Counting entities with SomeComponent..."; // range based for loop for (auto ent : world->each()) { ++count; - LOG(LogInfo) << "Found entity #" << ent->getEntityId(); + LLOG(LogInfo) << "Found entity #" << ent->getEntityId(); } - LOG(LogInfo) << count << " entities have SomeComponent!"; + LLOG(LogInfo) << count << " entities have SomeComponent!"; // Emitting events world->emit({ 4 }); TEST_EQ(world->getCount(), 11, ""); - LOG(LogInfo) << "We have " << world->getCount() << " entities right now."; + LLOG(LogInfo) << "We have " << world->getCount() << " entities right now."; world->cleanup(); TEST_EQ(world->getCount(), 10, ""); - LOG(LogInfo) << "After a cleanup, we have " << world->getCount() << " entities."; + LLOG(LogInfo) << "After a cleanup, we have " << world->getCount() << " entities."; - LOG(LogInfo) << "Destroying the world..."; + LLOG(LogInfo) << "Destroying the world..."; world->destroyWorld(); diff --git a/packages/filesystem/source/common/filesystem/File.cpp b/packages/filesystem/source/common/filesystem/File.cpp index 57d51a7e..ebeeda6d 100644 --- a/packages/filesystem/source/common/filesystem/File.cpp +++ b/packages/filesystem/source/common/filesystem/File.cpp @@ -238,7 +238,7 @@ namespace filesystem { size_t File::read(char* dst, size_t count) { if (!mFileStream) { - LOG(LogWarning) << "File not open:" << mFilePath; + LLOG(LogWarning) << "File not open:" << mFilePath; ASSERT(mFileStream.has_value()) << "File not open:" << mFilePath; return 0; } @@ -250,7 +250,7 @@ namespace filesystem { size_t File::write(const char* src, size_t count) { if (!mFileStream) { - LOG(LogWarning) << "File not open:" << mFilePath; + LLOG(LogWarning) << "File not open:" << mFilePath; ASSERT(mFileStream.has_value()) << "File not open:" << mFilePath; return 0; } @@ -260,7 +260,7 @@ namespace filesystem { size_t File::read(std::vector& dst) { if (!mFileStream) { - LOG(LogWarning) << "File not open:" << mFilePath; + LLOG(LogWarning) << "File not open:" << mFilePath; ASSERT(mFileStream.has_value()) << "File not open:" << mFilePath; return 0; } @@ -274,7 +274,7 @@ namespace filesystem { size_t File::write(const std::vector& src) { if (!mFileStream) { - LOG(LogWarning) << "File not open:" << mFilePath; + LLOG(LogWarning) << "File not open:" << mFilePath; ASSERT(mFileStream.has_value()) << "File not open:" << mFilePath; return 0; } @@ -284,7 +284,7 @@ namespace filesystem { size_t File::read(unsigned char* dst, size_t count) { if (!mFileStream) { - LOG(LogWarning) << "File not open:" << mFilePath; + LLOG(LogWarning) << "File not open:" << mFilePath; ASSERT(mFileStream.has_value()) << "File not open:" << mFilePath; return 0; } @@ -296,7 +296,7 @@ namespace filesystem { size_t File::write(const unsigned char* src, size_t count) { if (!mFileStream) { - LOG(LogWarning) << "File not open:" << mFilePath; + LLOG(LogWarning) << "File not open:" << mFilePath; ASSERT(mFileStream.has_value()) << "File not open:" << mFilePath; return 0; } @@ -306,7 +306,7 @@ namespace filesystem { size_t File::read(std::vector& dst) { if (!mFileStream) { - LOG(LogWarning) << "File not open:" << mFilePath; + LLOG(LogWarning) << "File not open:" << mFilePath; ASSERT(mFileStream.has_value()) << "File not open:" << mFilePath; return 0; } @@ -320,7 +320,7 @@ namespace filesystem { size_t File::write(const std::vector& src) { if (!mFileStream) { - LOG(LogWarning) << "File not open:" << mFilePath; + LLOG(LogWarning) << "File not open:" << mFilePath; ASSERT(mFileStream.has_value()) << "File not open:" << mFilePath; return 0; } @@ -330,7 +330,7 @@ namespace filesystem { size_t File::read(std::stringstream& dst, size_t count) { if (!mFileStream) { - LOG(LogWarning) << "File not open:" << mFilePath; + LLOG(LogWarning) << "File not open:" << mFilePath; ASSERT(mFileStream.has_value()) << "File not open:" << mFilePath; return 0; } @@ -352,7 +352,7 @@ namespace filesystem { size_t File::write(std::stringstream& src, size_t count) { if (!mFileStream) { - LOG(LogWarning) << "File not open:" << mFilePath; + LLOG(LogWarning) << "File not open:" << mFilePath; ASSERT(mFileStream.has_value()) << "File not open:" << mFilePath; return 0; } diff --git a/packages/hid/source/common/KeyState.cpp b/packages/hid/source/common/KeyState.cpp index 225821bf..f1c1e2e6 100644 --- a/packages/hid/source/common/KeyState.cpp +++ b/packages/hid/source/common/KeyState.cpp @@ -30,7 +30,7 @@ namespace l::hid { releasedPrev = released; //if (pressedNow || releasedNow || pressed) { - // LOG(LogInfo) << "pressed now: " << pressedNow << ", released now: " << releasedNow << ", pressed: " << pressed; + // LLOG(LogInfo) << "pressed now: " << pressedNow << ", released now: " << releasedNow << ", pressed: " << pressed; //} } diff --git a/packages/hid/source/common/Midi.cpp b/packages/hid/source/common/Midi.cpp index 178f1994..683afa41 100644 --- a/packages/hid/source/common/Midi.cpp +++ b/packages/hid/source/common/Midi.cpp @@ -14,28 +14,28 @@ namespace l::hid::midi { void HandleMidiData(uint32_t msg, uint32_t deviceId, uint32_t deviceOutId, uint32_t param1, uint32_t param2) { switch (msg) { case MIM_OPEN: - //LOG(LogInfo) << "MIM_OPEN"; + //LLOG(LogInfo) << "MIM_OPEN"; return; case MIM_CLOSE: - //LOG(LogInfo) << "MIM_CLOSE"; + //LLOG(LogInfo) << "MIM_CLOSE"; return; case MIM_LONGDATA: - LOG(LogInfo) << "Long data: " << msg << " " << deviceId << " " << param1 << " " << param2; + LLOG(LogInfo) << "Long data: " << msg << " " << deviceId << " " << param1 << " " << param2; return; case MIM_ERROR: - LOG(LogInfo) << "Error: " << msg << " " << deviceId << " " << param1 << " " << param2; + LLOG(LogInfo) << "Error: " << msg << " " << deviceId << " " << param1 << " " << param2; return; case MIM_LONGERROR: - LOG(LogInfo) << "Long error: " << msg << " " << deviceId << " " << param1 << " " << param2; + LLOG(LogInfo) << "Long error: " << msg << " " << deviceId << " " << param1 << " " << param2; return; case MIM_MOREDATA: - LOG(LogInfo) << "More data: " << msg << " " << deviceId << " " << param1 << " " << param2; + LLOG(LogInfo) << "More data: " << msg << " " << deviceId << " " << param1 << " " << param2; return; case MIM_DATA: - //LOG(LogInfo) << "Data: " << msg << " " << deviceId << " " << param1 << " " << param2; + //LLOG(LogInfo) << "Data: " << msg << " " << deviceId << " " << param1 << " " << param2; break; default: - LOG(LogInfo) << "default"; + LLOG(LogInfo) << "default"; break; } diff --git a/packages/hid/source/windows/MidiWindows.cpp b/packages/hid/source/windows/MidiWindows.cpp index 7e3b18bb..112b0c35 100644 --- a/packages/hid/source/windows/MidiWindows.cpp +++ b/packages/hid/source/windows/MidiWindows.cpp @@ -22,16 +22,16 @@ namespace l::hid::midi { //auto id = midiPtr->getDeviceOutId(deviceOut); switch (wMsg) { case MOM_OPEN: - //LOG(LogInfo) << "MOM_OPEN"; + //LLOG(LogInfo) << "MOM_OPEN"; break; case MOM_CLOSE: - //LOG(LogInfo) << "MOM_CLOSE"; + //LLOG(LogInfo) << "MOM_CLOSE"; break; case MOM_DONE: - //LOG(LogInfo) << "MOM_DONE"; + //LLOG(LogInfo) << "MOM_DONE"; break; default: - //LOG(LogInfo) << "Something else.."; + //LLOG(LogInfo) << "Something else.."; break; } @@ -47,14 +47,14 @@ namespace l::hid::midi { MMRESULT rv; rv = midiOutClose(device.second); if (rv != MMSYSERR_NOERROR) { - LOG(LogError) << "Failed to close midi out device" << deviceId; + LLOG(LogError) << "Failed to close midi out device" << deviceId; } rv = midiInStop(device.first); if (rv == MMSYSERR_NOERROR) { rv = midiInClose(device.first); } if (rv != MMSYSERR_NOERROR) { - LOG(LogError) << "Failed to close midi in device" << deviceId; + LLOG(LogError) << "Failed to close midi in device" << deviceId; } deviceId++; } @@ -76,8 +76,8 @@ namespace l::hid::midi { UINT nMidiOutDeviceNum = midiOutGetNumDevs(); - LOG(LogInfo) << "Number of midi in devices: " << nMidiInDeviceInNum; - LOG(LogInfo) << "Number of midi out devices: " << nMidiOutDeviceNum; + LLOG(LogInfo) << "Number of midi in devices: " << nMidiInDeviceInNum; + LLOG(LogInfo) << "Number of midi out devices: " << nMidiOutDeviceNum; for (uint32_t deviceId = 0; deviceId < nMidiInDeviceInNum || deviceId < nMidiOutDeviceNum; deviceId++) { MMRESULT rv; @@ -89,22 +89,22 @@ namespace l::hid::midi { if (deviceId < nMidiInDeviceInNum) { rv = midiInGetDevCaps(deviceId, &capsIn, sizeof(MIDIINCAPS)); if (rv != MMSYSERR_NOERROR) { - LOG(LogError) << "Failed to get midi in caps on device " << deviceId; + LLOG(LogError) << "Failed to get midi in caps on device " << deviceId; } - LOG(LogInfo) << "Midi in device id " << deviceId << " : " << capsIn.szPname << ", support : " << capsIn.dwSupport << ", pid : " << capsIn.wPid; + LLOG(LogInfo) << "Midi in device id " << deviceId << " : " << capsIn.szPname << ", support : " << capsIn.dwSupport << ", pid : " << capsIn.wPid; rv = midiInOpen(&hMidiDeviceIn, static_cast(deviceId), reinterpret_cast(&details::MidiInProc), (DWORD_PTR)(this), CALLBACK_FUNCTION | MIDI_IO_STATUS); if (rv == MMSYSERR_ALLOCATED) { return; } if (rv != MMSYSERR_NOERROR) { - LOG(LogError) << "Failed to open midi in device " << deviceId; + LLOG(LogError) << "Failed to open midi in device " << deviceId; continue; } rv = midiInStart(hMidiDeviceIn); if (rv != MMSYSERR_NOERROR) { - LOG(LogError) << "Failed to start midi in device" << deviceId; + LLOG(LogError) << "Failed to start midi in device" << deviceId; continue; } } @@ -112,16 +112,16 @@ namespace l::hid::midi { if (deviceId < nMidiOutDeviceNum) { rv = midiOutGetDevCaps(deviceId, &capsOut, sizeof(MIDIOUTCAPS)); if (rv != MMSYSERR_NOERROR) { - LOG(LogError) << "Failed to get midi out caps on device " << deviceId; + LLOG(LogError) << "Failed to get midi out caps on device " << deviceId; } - LOG(LogInfo) << "Midi out device id " << deviceId << " : " << capsOut.szPname << ", support : " << capsOut.dwSupport << ", pid : " << capsOut.wPid; + LLOG(LogInfo) << "Midi out device id " << deviceId << " : " << capsOut.szPname << ", support : " << capsOut.dwSupport << ", pid : " << capsOut.wPid; rv = midiOutOpen(&hMidiDeviceOut, static_cast(deviceId), reinterpret_cast(&details::MidiOutProc), (DWORD_PTR)(this), CALLBACK_FUNCTION); if (rv == MMSYSERR_ALLOCATED) { return; } if (rv != MMSYSERR_NOERROR) { - LOG(LogError) << "Failed to open midi out device " << deviceId; + LLOG(LogError) << "Failed to open midi out device " << deviceId; } } @@ -247,17 +247,17 @@ namespace l::hid::midi { MMRESULT rv = midiOutPrepareHeader(deviceOut, &mHeader, sizeof(MIDIHDR)); if (rv != MMSYSERR_NOERROR) { - LOG(LogError) << "Failed to prepare midi out buffer " << deviceId << ", error " << rv; + LLOG(LogError) << "Failed to prepare midi out buffer " << deviceId << ", error " << rv; } rv = midiOutLongMsg(deviceOut, &mHeader, sizeof(MIDIHDR)); if (rv != MMSYSERR_NOERROR) { - LOG(LogError) << "Failed to send buffer to midi out device " << deviceId << ", error " << rv; + LLOG(LogError) << "Failed to send buffer to midi out device " << deviceId << ", error " << rv; } rv = midiOutUnprepareHeader(deviceOut, &mHeader, sizeof(MIDIHDR)); if (rv != MMSYSERR_NOERROR) { - LOG(LogError) << "Failed to unprepare midi out buffer " << deviceId << ", error " << rv; + LLOG(LogError) << "Failed to unprepare midi out buffer " << deviceId << ", error " << rv; } } @@ -271,7 +271,7 @@ namespace l::hid::midi { MMRESULT rv = midiOutShortMsg(device, param1); if (rv != MMSYSERR_NOERROR) { - LOG(LogError) << "Failed to send to midi out device " << deviceId << ", error " << rv << ", data " << param1; + LLOG(LogError) << "Failed to send to midi out device " << deviceId << ", error " << rv << ", data " << param1; } } @@ -303,7 +303,7 @@ namespace l::hid::midi { mMidiDevice.initDevices(); RegisterCallback([](const MidiData&) { - //LOG(LogInfo) << "midi cb: device in:" << data.deviceIn << " device out:" << data.deviceOut << " stat:" << data.status << " ch:" << data.channel << " d1:" << data.data1 << " d2:" << data.data2; + //LLOG(LogInfo) << "midi cb: device in:" << data.deviceIn << " device out:" << data.deviceOut << " stat:" << data.status << " ch:" << data.channel << " d1:" << data.data1 << " d2:" << data.data2; }); } diff --git a/packages/logging/include/logging/Log.h b/packages/logging/include/logging/Log.h index 580a9fea..9d2c7164 100644 --- a/packages/logging/include/logging/Log.h +++ b/packages/logging/include/logging/Log.h @@ -95,7 +95,7 @@ namespace logging { #define LOG_LEVEL_ON(level) l::logging::SetLogLevelOn(l::logging::LogLevel::level, true) #define LOG_LEVEL_OFF(level) l::logging::SetLogLevelOn(l::logging::LogLevel::level, false) -#define LOG(level) l::logging::LogMessage(__FILE__, __LINE__, l::logging::LogLevel::level) +#define LLOG(level) l::logging::LogMessage(__FILE__, __LINE__, l::logging::LogLevel::level) #define ASSERT(condition) l::logging::LogMessage(__FILE__, __LINE__, l::logging::LogLevel::LogAssertion, condition) @@ -103,6 +103,12 @@ namespace logging { #define EXPECT(condition) l::logging::LogMessage(__FILE__, __LINE__, l::logging::LogLevel::LogExpection, condition) +#define LASSERT(condition) l::logging::LogMessage(__FILE__, __LINE__, l::logging::LogLevel::LogAssertion, condition) + +#define LASSERT_FUZZY(expr1, expr2, tolerance) l::logging::LogMessage(__FILE__, __LINE__, l::logging::LogLevel::LogAssertion, sqrt((expr1 - expr2)*(expr1 - expr2)) < tolerance) + +#define LEXPECT(condition) l::logging::LogMessage(__FILE__, __LINE__, l::logging::LogLevel::LogExpection, condition) + template T* require(T* ptr) { if (!(ptr)) { DEBUG_BREAK; } \ @@ -112,3 +118,6 @@ T* require(T* ptr) { #define REQUIRE(ptr) \ require(ptr); +#define LREQUIRE(ptr) \ + require(ptr); + diff --git a/packages/logging/include/logging/Static.h b/packages/logging/include/logging/Static.h index c2be1312..38d7b635 100644 --- a/packages/logging/include/logging/Static.h +++ b/packages/logging/include/logging/Static.h @@ -17,7 +17,7 @@ STATIC { .. statement }; */ -#define STATIC static l::Static_ UNIQUE(block) = [&]() -> void +#define STATIC_BLOCK static l::Static_ UNIQUE(block) = [&]() -> void /* Usage: STATIC_CALL([]() { diff --git a/packages/math/include/math/MathAlgorithm.h b/packages/math/include/math/MathAlgorithm.h index bb4ccc61..9a859049 100644 --- a/packages/math/include/math/MathAlgorithm.h +++ b/packages/math/include/math/MathAlgorithm.h @@ -85,7 +85,7 @@ namespace l::math::algorithm { c = (a + b) / 2.0; T cEval = eval(c); - LOG(LogDebug) << "bisect iteration " << n << "(" << iterations << ") val: " << c << "(convergence: " << cEval << ")"; + LLOG(LogDebug) << "bisect iteration " << n << "(" << iterations << ") val: " << c << "(convergence: " << cEval << ")"; if (cEval == 0.0 || abs(cEval) < tolerance) { return c; } diff --git a/packages/math/tests/common/MathTweenTest.cpp b/packages/math/tests/common/MathTweenTest.cpp index 576e6a62..febd0b65 100644 --- a/packages/math/tests/common/MathTweenTest.cpp +++ b/packages/math/tests/common/MathTweenTest.cpp @@ -15,7 +15,7 @@ TEST(MathTween, RecentWeightedAverage) { TEST_FUZZY(rwa.Value(), 1.0f, 0.1f, ""); for (int i = 0; i < 10; i++) { auto value = rwa.Next(); - LOG(LogInfo) << "RWA: " << value; + LLOG(LogInfo) << "RWA: " << value; } TEST_FUZZY(rwa.Value(), 0.0f, 0.1f, ""); @@ -30,7 +30,7 @@ TEST(MathTween, DynamicTween) { for (int i = 0; i < 10; i++) { tween.Update(); auto value = tween.Next(); - LOG(LogInfo) << "Tween: " << value; + LLOG(LogInfo) << "Tween: " << value; } TEST_FUZZY(tween.Value(), 0.0f, 0.01f, ""); @@ -47,7 +47,7 @@ TEST(MathTween, DynamicTweenVeryShortBatch) { tween.Update(10); } auto value = tween.Next(); - LOG(LogInfo) << "Tween (" << i << "): " << value; + LLOG(LogInfo) << "Tween (" << i << "): " << value; } TEST_FUZZY(tween.Value(), 0.0f, 0.01f, ""); @@ -64,7 +64,7 @@ TEST(MathTween, DynamicTweenShortBatch) { tween.Update(10); } auto value = tween.Next(); - LOG(LogInfo) << "Tween (" << i << "): " << value; + LLOG(LogInfo) << "Tween (" << i << "): " << value; } TEST_FUZZY(tween.Value(), 0.0f, 0.01f, ""); @@ -82,7 +82,7 @@ TEST(MathTween, DynamicTweenLongBatch) { tween.Update(updateRate); } auto value = tween.Next(); - LOG(LogInfo) << "Tween (" << i << "): " << value; + LLOG(LogInfo) << "Tween (" << i << "): " << value; } TEST_FUZZY(tween.Value(), 0.0f, 0.02f, ""); diff --git a/packages/memory/source/common/Arena.cpp b/packages/memory/source/common/Arena.cpp index e3751aa7..769e88a5 100644 --- a/packages/memory/source/common/Arena.cpp +++ b/packages/memory/source/common/Arena.cpp @@ -63,13 +63,13 @@ namespace l::memory { // pop some bytes off the 'stack' - the way to free void ArenaPop(Arena* arena, uint64_t size) { if (arena->mBlocks.empty()) { - LOG(LogError) << "Trying to pop from an empty arena"; + LLOG(LogError) << "Trying to pop from an empty arena"; return; } MemoryBlock& lastBlock = arena->mBlocks.back(); if (lastBlock.mSize - (reinterpret_cast(lastBlock.mBase) - reinterpret_cast(arena->mBlocks.back().mBase)) < size) { - LOG(LogError) << "Trying to pop more bytes than are available in the current block"; + LLOG(LogError) << "Trying to pop more bytes than are available in the current block"; return; } @@ -89,13 +89,13 @@ namespace l::memory { // also some useful popping helpers: void ArenaSetPosBack(Arena* arena, uint64_t pos) { if (arena->mBlocks.empty()) { - LOG(LogError) << "Trying to set position in an empty arena"; + LLOG(LogError) << "Trying to set position in an empty arena"; return; } MemoryBlock& lastBlock = arena->mBlocks.back(); if (lastBlock.mSize - (reinterpret_cast(lastBlock.mBase) - reinterpret_cast(arena->mBlocks.back().mBase)) < pos) { - LOG(LogError) << "Trying to set position past the end of the current block"; + LLOG(LogError) << "Trying to set position past the end of the current block"; return; } diff --git a/packages/memory/tests/common/ContainersTest.cpp b/packages/memory/tests/common/ContainersTest.cpp index 4f586fd7..bd27d0a8 100644 --- a/packages/memory/tests/common/ContainersTest.cpp +++ b/packages/memory/tests/common/ContainersTest.cpp @@ -5,7 +5,7 @@ TEST(Containers, VectorOps) { { - LOG(LogInfo) << l::string::get_unix_epoch_ms(); + LLOG(LogInfo) << l::string::get_unix_epoch_ms(); std::vector v = { 1, 3, 5, 32, 53, 2, 95 }; auto v_sub3 = l::container::vector_extract(v, 4u, 3u); diff --git a/packages/meta/tests/common/ReflectionTest.cpp b/packages/meta/tests/common/ReflectionTest.cpp index 19d0d25b..4526ffb9 100644 --- a/packages/meta/tests/common/ReflectionTest.cpp +++ b/packages/meta/tests/common/ReflectionTest.cpp @@ -43,12 +43,12 @@ TEST(ReflectionTest, ClassName) { class A {}; class B {}; class C {}; - LOG(LogInfo) << l::meta::Type::name(); - LOG(LogInfo) << l::meta::Type::full_name() << "\n"; - LOG(LogInfo) << l::meta::Type::name() << "\n"; - LOG(LogInfo) << l::meta::Type::full_name() << "\n"; - LOG(LogInfo) << l::meta::Type::name() << "\n"; - LOG(LogInfo) << l::meta::Type::type() << "\n"; + LLOG(LogInfo) << l::meta::Type::name(); + LLOG(LogInfo) << l::meta::Type::full_name() << "\n"; + LLOG(LogInfo) << l::meta::Type::name() << "\n"; + LLOG(LogInfo) << l::meta::Type::full_name() << "\n"; + LLOG(LogInfo) << l::meta::Type::name() << "\n"; + LLOG(LogInfo) << l::meta::Type::type() << "\n"; return 0; } @@ -103,9 +103,9 @@ TEST(ReflectionTest, Polymorphism) { TEST_TRUE(l::meta::Type::hash_code() != l::meta::Type::hash_code(), ""); TEST_TRUE(l::meta::Type::hash_code() != l::meta::Type::hash_code(), ""); - LOG(LogInfo) << l::meta::Type::hash_code(); - LOG(LogInfo) << l::meta::Type::hash_code(); - LOG(LogInfo) << l::meta::Type::hash_code(); + LLOG(LogInfo) << l::meta::Type::hash_code(); + LLOG(LogInfo) << l::meta::Type::hash_code(); + LLOG(LogInfo) << l::meta::Type::hash_code(); } return 0; diff --git a/packages/network/source/common/NetworkConnection.cpp b/packages/network/source/common/NetworkConnection.cpp index 7106d12f..47ddf82e 100644 --- a/packages/network/source/common/NetworkConnection.cpp +++ b/packages/network/source/common/NetworkConnection.cpp @@ -7,7 +7,7 @@ namespace l::network { if (request != nullptr) { request->NotifyClose(); } - LOG(LogDebug) << "Socket close: " << item; + LLOG(LogDebug) << "Socket close: " << item; return 0; } @@ -25,8 +25,8 @@ namespace l::network { if (request->IsWebSocket()) { auto wssMeta = request->GetWebSocketMeta(); if (wssMeta) { - LOG(LogDebug) << "wss meta flags " << wssMeta->flags; - LOG(LogDebug) << "wss meta length " << wssMeta->len; + LLOG(LogDebug) << "wss meta flags " << wssMeta->flags; + LLOG(LogDebug) << "wss meta length " << wssMeta->len; } request->NotifyAppendResponse(contents, size * nmemb); } @@ -40,7 +40,7 @@ namespace l::network { size_t CurlClientProgressCallback(void* clientp, double dltotal, double dlnow, double, double) { auto progress = reinterpret_cast(clientp); double progressTotal = dlnow / dltotal; - LOG(LogDebug) << "downloaded " << progress->size << " bytes" << " and progress at " << std::to_string(int(progressTotal * 100)) << "%"; + LLOG(LogDebug) << "downloaded " << progress->size << " bytes" << " and progress at " << std::to_string(int(progressTotal * 100)) << "%"; return 0; } @@ -110,7 +110,7 @@ namespace l::network { } curl_easy_setopt(mCurl, CURLOPT_URL, mRequestQuery.c_str()); - LOG(LogDebug) << mRequestQuery; + LLOG(LogDebug) << mRequestQuery; //curl_easy_setopt(mCurl, CURLOPT_FRESH_CONNECT, 0L); // only use if necessary to create a new connection auto res_verify_peer = curl_easy_setopt(mCurl, CURLOPT_SSL_VERIFYPEER, 0L); ASSERT(res_verify_peer == CURLE_OK) << "[Request] Failed to verify peer: " << std::to_string(res_verify_peer); @@ -143,7 +143,7 @@ namespace l::network { #endif auto curlMCode = curl_multi_add_handle(multiHandle, mCurl); if (curlMCode != CURLMcode::CURLM_OK) { - LOG(LogError) << "[Request] Curl failure " << std::to_string(curlMCode) << ": " << mRequestQueryArgs; + LLOG(LogError) << "[Request] Curl failure " << std::to_string(curlMCode) << ": " << mRequestQueryArgs; mSuccess = false; } } @@ -151,7 +151,7 @@ namespace l::network { auto curlCode = curl_easy_perform(mCurl); //curl_easy_header() if (curlCode != CURLE_OK) { - LOG(LogError) << "[Request] Curl failure " << std::to_string(curlCode) << ": " << mRequestQueryArgs; + LLOG(LogError) << "[Request] Curl failure " << std::to_string(curlCode) << ": " << mRequestQueryArgs; mSuccess = false; } } @@ -261,12 +261,12 @@ namespace l::network { int32_t ConnectionBase::WSKeepalive() { if (HasExpired()) { mWebSocketCanSendData = false; - LOG(LogWarning) << "[Keepalive] connection expired"; + LLOG(LogWarning) << "[Keepalive] connection expired"; return -101; } if (mCurl == nullptr) { mWebSocketCanSendData = false; - LOG(LogWarning) << "[Keepalive] no curl instance"; + LLOG(LogWarning) << "[Keepalive] no curl instance"; return -102; } @@ -274,10 +274,10 @@ namespace l::network { size_t sentBytes = 0; auto rc = curl_ws_send(mCurl, payload, strlen(payload), &sentBytes, 0, CURLWS_PONG); if (rc == CURLE_OK) { - //LOG(LogInfo) << "[Keepalive] Sent PONG"; + //LLOG(LogInfo) << "[Keepalive] Sent PONG"; } else { - LOG(LogWarning) << "[Keepalive] Failed to send PONG: " << curl_easy_strerror(rc); + LLOG(LogWarning) << "[Keepalive] Failed to send PONG: " << curl_easy_strerror(rc); } return rc; } @@ -285,12 +285,12 @@ namespace l::network { int32_t ConnectionBase::WSWrite(const char* buffer, size_t size) { if (HasExpired()) { mWebSocketCanSendData = false; - LOG(LogWarning) << "[Websocket] Failed write, connection expired"; + LLOG(LogWarning) << "[Websocket] Failed write, connection expired"; return -101; } if (mCurl == nullptr) { mWebSocketCanSendData = false; - LOG(LogWarning) << "[Websocket] Failed write, no curl instance"; + LLOG(LogWarning) << "[Websocket] Failed write, no curl instance"; return -102; } size_t sentBytes = 0; @@ -305,13 +305,13 @@ namespace l::network { } else if (res == CURLE_GOT_NOTHING) { if (mWebSocketCanSendData) { - LOG(LogWarning) << "[Websocket] Failed write: got nothing, error: " << res; + LLOG(LogWarning) << "[Websocket] Failed write: got nothing, error: " << res; } mWebSocketCanSendData = false; } else { if (mWebSocketCanSendData) { - LOG(LogWarning) << "[Websocket] Failed write, error: " << res; + LLOG(LogWarning) << "[Websocket] Failed write, error: " << res; } mWebSocketCanSendData = false; } @@ -322,12 +322,12 @@ namespace l::network { int32_t ConnectionBase::WSRead(char* buffer, size_t size) { if (HasExpired()) { mWebSocketCanReceiveData = false; - LOG(LogWarning) << "[Websocket] Failed read, connection expired"; + LLOG(LogWarning) << "[Websocket] Failed read, connection expired"; return -101; } if (mCurl == nullptr) { mWebSocketCanReceiveData = false; - LOG(LogWarning) << "[Websocket] Failed read, no curl instance"; + LLOG(LogWarning) << "[Websocket] Failed read, no curl instance"; return -102; } int32_t maxTries = 3; @@ -348,10 +348,10 @@ namespace l::network { recvLeft = static_cast(meta->bytesleft); if (meta->flags & CURLWS_PONG) { - LOG(LogInfo) << "[WebSocket] Received PONG: "; + LLOG(LogInfo) << "[WebSocket] Received PONG: "; } else if (meta->flags & CURLWS_PING) { - LOG(LogInfo) << "[WebSocket] Received PING: "; + LLOG(LogInfo) << "[WebSocket] Received PING: "; } //else if (meta->flags & CURLWS_TEXT) { //} @@ -390,25 +390,25 @@ namespace l::network { // In this path only if there's an error if (res == CURLE_GOT_NOTHING) { if (mWebSocketCanReceiveData) { - LOG(LogWarning) << "[Websocket] Failed read - 'curl got nothing' - connection closed, error: " << res; + LLOG(LogWarning) << "[Websocket] Failed read - 'curl got nothing' - connection closed, error: " << res; } mWebSocketCanReceiveData = false; } if (res == CURLE_RECV_ERROR) { if (mWebSocketCanReceiveData) { - LOG(LogWarning) << "[Websocket] Failed read - 'curl recieve error' - connection closed, error: " << res; + LLOG(LogWarning) << "[Websocket] Failed read - 'curl recieve error' - connection closed, error: " << res; } mWebSocketCanReceiveData = false; } if (res == CURLE_BAD_FUNCTION_ARGUMENT) { if (mWebSocketCanReceiveData) { - LOG(LogWarning) << "[Websocket] Failed read - 'curl bad function arg', error: " << res; + LLOG(LogWarning) << "[Websocket] Failed read - 'curl bad function arg', error: " << res; } mWebSocketCanReceiveData = false; } if (mWebSocketCanReceiveData) { - LOG(LogWarning) << "[Websocket] Failed read, connection closed, error: " << res; + LLOG(LogWarning) << "[Websocket] Failed read, connection closed, error: " << res; } mWebSocketCanReceiveData = false; SetRunningTimeout(20); @@ -418,11 +418,11 @@ namespace l::network { void ConnectionBase::WSClose() { if (HasExpired()) { mWebSocketCanSendData = false; - LOG(LogWarning) << "[Websocket] Failed close, connection expired"; + LLOG(LogWarning) << "[Websocket] Failed close, connection expired"; } if (mCurl == nullptr) { mWebSocketCanSendData = false; - LOG(LogWarning) << "[Websocket] Failed close, no curl instance"; + LLOG(LogWarning) << "[Websocket] Failed close, no curl instance"; } ASSERT(mOngoingRequest); @@ -435,7 +435,7 @@ namespace l::network { size_t sentBytes = 0; auto res = curl_ws_send(mCurl, nullptr, 0, &sentBytes, 0, CURLWS_CLOSE); if (res == CURLE_OK) { - LOG(LogInfo) << "[Websocket] Closed connection"; + LLOG(LogInfo) << "[Websocket] Closed connection"; } NotifyCompleteRequest(true); @@ -452,11 +452,11 @@ namespace l::network { void ConnectionBase::NotifyAppendHeader(const char* contents, size_t size) { if (HasExpired()) { mWebSocketCanSendData = false; - LOG(LogWarning) << "[Request] Failed notify append header, connection expired"; + LLOG(LogWarning) << "[Request] Failed notify append header, connection expired"; } if (mCurl == nullptr) { mWebSocketCanSendData = false; - LOG(LogWarning) << "[Request] Failed notify append header, no curl instance"; + LLOG(LogWarning) << "[Request] Failed notify append header, no curl instance"; } ASSERT(mOngoingRequest); @@ -490,11 +490,11 @@ namespace l::network { void ConnectionBase::NotifyAppendResponse(const char* contents, size_t size) { if (HasExpired()) { mWebSocketCanSendData = false; - LOG(LogWarning) << "[Request] Failed notify append response, connection expired"; + LLOG(LogWarning) << "[Request] Failed notify append response, connection expired"; } if (mCurl == nullptr) { mWebSocketCanSendData = false; - LOG(LogWarning) << "[Request] Failed notify append response, no curl instance"; + LLOG(LogWarning) << "[Request] Failed notify append response, no curl instance"; } ASSERT(mOngoingRequest); diff --git a/packages/network/source/common/NetworkInterfaceWS.cpp b/packages/network/source/common/NetworkInterfaceWS.cpp index 20c78071..d919d597 100644 --- a/packages/network/source/common/NetworkInterfaceWS.cpp +++ b/packages/network/source/common/NetworkInterfaceWS.cpp @@ -102,7 +102,7 @@ namespace l::network { queue.pop_front(); } else { - LOG(LogWarning) << "Failed to write to: " << interfaceName << " : error: " << written; + LLOG(LogWarning) << "Failed to write to: " << interfaceName << " : error: " << written; } maxQueued--; } @@ -141,7 +141,7 @@ namespace l::network { auto queryName = interfaceName; // With websocket, we have one query only per interface and it has the same name written = networkManager->WSKeepalive(queryName) >= 0; if (written < 0) { - LOG(LogWarning) << "Failed to send keepalive: " << interfaceName << " : error: " << written; + LLOG(LogWarning) << "Failed to send keepalive: " << interfaceName << " : error: " << written; } } } @@ -159,7 +159,7 @@ namespace l::network { auto queryName = interfaceName; // With websocket, we have one query only per interface and it has the same name written = networkManager->WSWrite(queryName, buffer, size) >= 0; if (written < 0) { - LOG(LogWarning) << "Failed to write to: " << interfaceName << " : error: " << written; + LLOG(LogWarning) << "Failed to write to: " << interfaceName << " : error: " << written; } } } diff --git a/packages/network/source/common/NetworkManager.cpp b/packages/network/source/common/NetworkManager.cpp index df2fe49b..c81988c9 100644 --- a/packages/network/source/common/NetworkManager.cpp +++ b/packages/network/source/common/NetworkManager.cpp @@ -48,18 +48,18 @@ namespace l::network { ASSERT(foundHandle); } else if (m) { - LOG(LogWarning) << "Not done"; + LLOG(LogWarning) << "Not done"; } } while (m != nullptr && messagesInQueue > 0); int numfds; mc = curl_multi_poll(mMultiHandle, NULL, 0, 1000, &numfds); if (mc != CURLM_OK) { - LOG(LogError) << "curl_multi_poll failed, code " << mc; + LLOG(LogError) << "curl_multi_poll failed, code " << mc; } } else { - LOG(LogError) << "curl_multi_perform failed, code " << mc; + LLOG(LogError) << "curl_multi_perform failed, code " << mc; } } while (runningHandles > 0 || mJobManager.get() != nullptr || !mConnections.empty()); }); @@ -212,7 +212,7 @@ namespace l::network { }); if (it == mConnections.end()) { - LOG(LogError) << "Failed to find connection: " << queryName; + LLOG(LogError) << "Failed to find connection: " << queryName; return -201; } auto request = it->get(); @@ -231,7 +231,7 @@ namespace l::network { }); if (it == mConnections.end()) { - LOG(LogError) << "Failed to find connection: " << queryName; + LLOG(LogError) << "Failed to find connection: " << queryName; return -201; } auto request = it->get(); @@ -250,7 +250,7 @@ namespace l::network { }); if (it == mConnections.end()) { - LOG(LogError) << "Failed to find connection: " << queryName; + LLOG(LogError) << "Failed to find connection: " << queryName; return -201; } auto request = it->get(); diff --git a/packages/network/tests/common/NetworkInterfaceTest.cpp b/packages/network/tests/common/NetworkInterfaceTest.cpp index f3ea0961..7165c710 100644 --- a/packages/network/tests/common/NetworkInterfaceTest.cpp +++ b/packages/network/tests/common/NetworkInterfaceTest.cpp @@ -39,8 +39,8 @@ TEST(NetworkInterface, Setup) { failed = !success; - LOG(LogInfo) << "Query arguments: '" << queryArguments << "'"; - LOG(LogInfo) << request.GetResponse().str(); + LLOG(LogInfo) << "Query arguments: '" << queryArguments << "'"; + LLOG(LogInfo) << request.GetResponse().str(); return success ? l::concurrency::RunnableResult::SUCCESS : l::concurrency::RunnableResult::FAILURE; }; diff --git a/packages/network/tests/common/NetworkManagerTest.cpp b/packages/network/tests/common/NetworkManagerTest.cpp index 328fd23e..d2e89671 100644 --- a/packages/network/tests/common/NetworkManagerTest.cpp +++ b/packages/network/tests/common/NetworkManagerTest.cpp @@ -20,7 +20,7 @@ TEST(NetworkManager, Setup) { [&](bool success, std::string_view queryArguments, l::network::RequestStringStream& request) { TEST_TRUE_NO_RET(success, ""); - LOG(LogInfo) << "Query arguments: '" << queryArguments << "'"; + LLOG(LogInfo) << "Query arguments: '" << queryArguments << "'"; file.modeWriteTrunc(); if (file.open()) { file.write(request.GetResponse()); @@ -34,8 +34,8 @@ TEST(NetworkManager, Setup) { [&](bool success, std::string_view queryArguments, l::network::RequestStringStream& request) { TEST_TRUE_NO_RET(success, ""); - LOG(LogInfo) << "Query arguments: '" << queryArguments << "'"; - LOG(LogInfo) << request.GetResponse().str(); + LLOG(LogInfo) << "Query arguments: '" << queryArguments << "'"; + LLOG(LogInfo) << request.GetResponse().str(); return l::concurrency::RunnableResult::SUCCESS; } ); @@ -66,8 +66,8 @@ TEST(NetworkManager, Setup) { [&](bool success, std::string_view queryArguments, l::network::RequestStringStream& request) { TEST_TRUE_NO_RET(success, ""); - LOG(LogInfo) << "Query arguments: '" << queryArguments << "'"; - LOG(LogInfo) << request.GetResponse().str(); + LLOG(LogInfo) << "Query arguments: '" << queryArguments << "'"; + LLOG(LogInfo) << request.GetResponse().str(); return l::concurrency::RunnableResult::SUCCESS; } ); diff --git a/packages/network/tests/common/NetworkWebSocketTest.cpp b/packages/network/tests/common/NetworkWebSocketTest.cpp index 104c235e..2f02c1dc 100644 --- a/packages/network/tests/common/NetworkWebSocketTest.cpp +++ b/packages/network/tests/common/NetworkWebSocketTest.cpp @@ -43,7 +43,7 @@ TEST(NetworkWebSocket, Setup) { TEST_TRUE(read > 0, ""); - LOG(LogInfo) << std::string_view(buffer, read); + LLOG(LogInfo) << std::string_view(buffer, read); networkInterfaceWS->Disconnect("Websocket"); @@ -69,7 +69,7 @@ TEST(NetworkWebSocket, BinanceKlines) { std::string_view, l::network::WebSocket& ws) { failed = !success; - LOG(LogInfo) << "Success: " << success; + LLOG(LogInfo) << "Success: " << success; return success ? l::concurrency::RunnableResult::SUCCESS : l::concurrency::RunnableResult::FAILURE; }; @@ -104,7 +104,7 @@ TEST(NetworkWebSocket, BinanceKlines) { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); read = networkInterfaceWS->Read("Binance", &buffer[0], 1024); if (read > 0) { - LOG(LogInfo) << std::string_view(buffer, read); + LLOG(LogInfo) << std::string_view(buffer, read); } } while (readCount-- >= 0); @@ -135,7 +135,7 @@ TEST(NetworkWebSocket, BinanceUIKlines) { std::string_view queryArguments, l::network::WebSocket& ws) { failed = !success; - LOG(LogInfo) << "Success: " << success; + LLOG(LogInfo) << "Success: " << success; return success ? l::concurrency::RunnableResult::SUCCESS : l::concurrency::RunnableResult::FAILURE; }; @@ -172,7 +172,7 @@ TEST(NetworkWebSocket, BinanceUIKlines) { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); read = networkInterfaceWS->Read("Binance", &buffer[0], 1024); if (read > 0) { - LOG(LogInfo) << std::string_view(buffer, read); + LLOG(LogInfo) << std::string_view(buffer, read); } } while (readCount-- >= 0); @@ -184,7 +184,7 @@ TEST(NetworkWebSocket, BinanceUIKlines) { std::this_thread::sleep_for(std::chrono::milliseconds(1000)); read = networkInterfaceWS->Read("Binance", &buffer[0], 1024); if (read > 0) { - LOG(LogInfo) << std::string_view(buffer, read); + LLOG(LogInfo) << std::string_view(buffer, read); } } while (readCount-- >= 0); diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h index 270873ce..ed9f1053 100644 --- a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h @@ -46,7 +46,7 @@ namespace l::nodegraph { mInputs.clear(); mOutputs.clear(); - //LOG(LogInfo) << "Node graph base destroyed"; + //LLOG(LogInfo) << "Node graph base destroyed"; } NodeGraphBase& operator=(NodeGraphBase&& other) noexcept { @@ -190,7 +190,7 @@ namespace l::nodegraph { mName(name) {} virtual ~NodeGraphOp() { - //LOG(LogInfo) << "Node operation destroyed"; + //LLOG(LogInfo) << "Node operation destroyed"; } NodeGraphOp& operator=(NodeGraphOp&& other) noexcept { @@ -270,7 +270,7 @@ namespace l::nodegraph { { } virtual ~NodeGraphOpCached() { - //LOG(LogInfo) << "Buffered operation destroyed"; + //LLOG(LogInfo) << "Buffered operation destroyed"; } NodeGraphOpCached& operator=(NodeGraphOpCached&& other) noexcept { @@ -313,7 +313,7 @@ namespace l::nodegraph { DefaultDataInit(); } virtual ~NodeGraph() { - //LOG(LogInfo) << "Node destroyed"; + //LLOG(LogInfo) << "Node destroyed"; } NodeGraph& operator=(NodeGraph&& other) noexcept { diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h b/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h index 4a6048b0..f3ceb6fc 100644 --- a/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h @@ -48,7 +48,7 @@ namespace l::nodegraph { } ~NodeGraphGroup() { Reset(); - //LOG(LogInfo) << "Node group destroyed"; + //LLOG(LogInfo) << "Node group destroyed"; } NodeGraphGroup& operator=(NodeGraphGroup&& other) noexcept { diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 32406d20..5faf9d0c 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -28,7 +28,7 @@ namespace l::nodegraph { bool NodeGraphSchema::NodeGraphNewNode(int32_t typeId, int32_t nodeId) { auto id = NewNode(typeId, nodeId); if (id != nodeId) { - LOG(LogError) << "Failed to create node"; + LLOG(LogError) << "Failed to create node"; return false; } return true; @@ -38,7 +38,7 @@ namespace l::nodegraph { auto srcNode = GetNode(srcId); auto dstNode = GetNode(dstId); if (srcNode && dstNode && !dstNode->SetInput(dstChannel, *srcNode, srcChannel)) { - LOG(LogError) << "Failed to wire nodes"; + LLOG(LogError) << "Failed to wire nodes"; return false; } return true; @@ -59,7 +59,7 @@ namespace l::nodegraph { bool NodeGraphSchema::Load(std::filesystem::path file) { if (!file.has_filename() || !std::filesystem::exists(file)) { - LOG(LogError) << "Failed to load schema: the file does not exist"; + LLOG(LogError) << "Failed to load schema: the file does not exist"; return false; } @@ -87,12 +87,12 @@ namespace l::nodegraph { bool NodeGraphSchema::Save(std::filesystem::path file, bool cloneOnly) { if (file.empty()) { - LOG(LogError) << "Failed to save schema: there is no file name or path"; + LLOG(LogError) << "Failed to save schema: there is no file name or path"; return false; } if (!file.has_filename()) { - LOG(LogError) << "Failed to save schema: there is no file name"; + LLOG(LogError) << "Failed to save schema: there is no file name"; return false; } @@ -109,7 +109,7 @@ namespace l::nodegraph { l::filesystem::File dataFile(file); dataFile.modeBinary().modeWriteTrunc(); if (dataFile.open() && dataFile.write(builder.GetStream()) > 0) { - LOG(LogInfo) << "Created " << file; + LLOG(LogInfo) << "Created " << file; return true; } return false; @@ -130,11 +130,11 @@ namespace l::nodegraph { } if (mVersionMajor < kVersionMajor) { - LOG(LogWarning) << "Schema major version mismatch. Performing automatic upgrade but schema should be saved."; + LLOG(LogWarning) << "Schema major version mismatch. Performing automatic upgrade but schema should be saved."; // Perform upgrade } else if (mVersionMinor < kVersionMinor) { - LOG(LogWarning) << "Schema minor version is of old version. Schema should still work but should be resaved when suitable."; + LLOG(LogWarning) << "Schema minor version is of old version. Schema should still work but should be resaved when suitable."; } if (nodeGraphSchema.has_key("Name")) { @@ -753,7 +753,7 @@ namespace l::nodegraph { RegisterNodeType("UI", 607, "UI Chart Lines 3"); } else { - LOG(LogWarning) << "Type group does not exist: " << typeGroup; + LLOG(LogWarning) << "Type group does not exist: " << typeGroup; } } diff --git a/packages/nodegraph/source/common/core/NodeGraphGroup.cpp b/packages/nodegraph/source/common/core/NodeGraphGroup.cpp index ca67ea84..ea23642f 100644 --- a/packages/nodegraph/source/common/core/NodeGraphGroup.cpp +++ b/packages/nodegraph/source/common/core/NodeGraphGroup.cpp @@ -50,7 +50,7 @@ namespace l::nodegraph { auto it = nodes.as_array(); for (; it.has_next();) { auto e = it.next(); - //LOG(LogInfo) << e.as_dbg_string(); + //LLOG(LogInfo) << e.as_dbg_string(); if (e.has_key("TypeId") && e.has_key("NodeId")) { auto typeId = e.get("TypeId").as_int32(); auto nodeId = e.get("NodeId").as_int32(); @@ -82,11 +82,11 @@ namespace l::nodegraph { auto it = nodeData.as_array(); for (; it.has_next();) { auto e = it.next(); - //LOG(LogInfo) << e.as_dbg_string(); + //LLOG(LogInfo) << e.as_dbg_string(); if (e.has_key("NodeId")) { auto nodeId = e.get("NodeId").as_int32(); auto inputInfo = e.get("InputInfo"); - //LOG(LogInfo) << inputInfo.as_dbg_string(); + //LLOG(LogInfo) << inputInfo.as_dbg_string(); auto node = GetNode(nodeId); ASSERT(node); @@ -100,13 +100,13 @@ namespace l::nodegraph { if (data.has_key("Value")) { auto value = data.get("Value").as_float(); if (!node->SetInput(channel, value)) { - LOG(LogError) << "Failed to set channel constant data"; + LLOG(LogError) << "Failed to set channel constant data"; } } else if (data.has_key("Text")) { auto text= data.get("Text").as_string(); if (!node->SetInput(channel, text)) { - LOG(LogError) << "Failed to set channel text data"; + LLOG(LogError) << "Failed to set channel text data"; } } else if (data.has_key("SrcNodeId") && data.has_key("SrcChannel")) { diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOInput.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOInput.cpp index 54393bd8..255a8a4c 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOInput.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOInput.cpp @@ -129,7 +129,7 @@ namespace l::nodegraph { } void GraphInputMidiKeyboard::MidiEvent(const l::hid::midi::MidiData& data) { - //LOG(LogInfo) << "listener 1: dev" << data.device << " stat " << data.status << " ch " << data.channel << " d1 " << data.data1 << " d2 " << data.data2; + //LLOG(LogInfo) << "listener 1: dev" << data.device << " stat " << data.status << " ch " << data.channel << " d1 " << data.data1 << " d2 " << data.data2; if (mMidiChannelKeys < 0 || data.channel != static_cast(mMidiChannelKeys)) { return; } diff --git a/packages/nodegraph/tests/common/NodeGraphBatchingTest.cpp b/packages/nodegraph/tests/common/NodeGraphBatchingTest.cpp index 42d71097..8e071cd9 100644 --- a/packages/nodegraph/tests/common/NodeGraphBatchingTest.cpp +++ b/packages/nodegraph/tests/common/NodeGraphBatchingTest.cpp @@ -24,13 +24,13 @@ TEST(NodeGraphBatching, Simple) { for (int32_t i = 0; i < 4; i++) { - LOG(LogInfo) << "batch " << i; + LLOG(LogInfo) << "batch " << i; group.ProcessSubGraph(8); // 8 samples per batch auto output = &group.GetOutput(0, 8); for (int32_t j = 0; j < 8; j++) { - LOG(LogInfo) << "sample " << (j+(i*8)) << ": " << *output++; + LLOG(LogInfo) << "sample " << (j+(i*8)) << ": " << *output++; } } diff --git a/packages/nodegraph/tests/common/NodeGraphDataTest.cpp b/packages/nodegraph/tests/common/NodeGraphDataTest.cpp index 6d572923..1199a031 100644 --- a/packages/nodegraph/tests/common/NodeGraphDataTest.cpp +++ b/packages/nodegraph/tests/common/NodeGraphDataTest.cpp @@ -34,7 +34,7 @@ class TestOp : public NodeGraphOp2 { *out0++ = value0; *out1++ = value1; - LOG(LogInfo) << "Node input(" << i << "): " << value0 << ", " << value1; + LLOG(LogInfo) << "Node input(" << i << "): " << value0 << ", " << value1; } } protected: @@ -57,7 +57,7 @@ class Copy : public NodeGraphOp { for (int i = 0; i < numSamples; i++) { auto in1 = *in++; *out++ = in1; - LOG(LogInfo) << "Node input(" << i << "): " << in1; + LLOG(LogInfo) << "Node input(" << i << "): " << in1; } } protected: @@ -114,7 +114,7 @@ class TestOp2 : public NodeGraphOp2 { *out0++ = value0; *out1++ = value1; - LOG(LogInfo) << "Node input(" << i << "): " << value0 << ", " << value1; + LLOG(LogInfo) << "Node input(" << i << "): " << value0 << ", " << value1; } } protected: @@ -165,7 +165,7 @@ TEST(NodeGraphData, CandleStickData) { auto out = &node1.GetOutput(0, 5); for (int i = 0; i < 5; i++) { - LOG(LogInfo) << "node1(0):" << *out++; + LLOG(LogInfo) << "node1(0):" << *out++; } } diff --git a/packages/nodegraph/tests/common/NodeGraphSchemaTest.cpp b/packages/nodegraph/tests/common/NodeGraphSchemaTest.cpp index ce86c37b..683c89eb 100644 --- a/packages/nodegraph/tests/common/NodeGraphSchemaTest.cpp +++ b/packages/nodegraph/tests/common/NodeGraphSchemaTest.cpp @@ -81,7 +81,7 @@ TEST(NodeGraph, NumericIntegral) { for (int i = 0; i < 30; i++) { input = sinf(2.0f * i * oneRev); nodeIntegral.ProcessSubGraph(1, 30); - //LOG(LogInfo) << nodeIntegral.Get(0); + //LLOG(LogInfo) << nodeIntegral.Get(0); } TEST_FUZZY(nodeIntegral.GetOutput(0), 0.00323272f, 0.0001f, ""); @@ -104,7 +104,7 @@ TEST(NodeGraph, FilterLowpass) { for (int i = 0; i < 30; i++) { input = sinf(2.0f * i * oneRev); nodeLowpass.ProcessSubGraph(1, 30); - //LOG(LogInfo) << nodeLowpass.GetOutput(0); + //LLOG(LogInfo) << nodeLowpass.GetOutput(0); } TEST_FUZZY(nodeLowpass.GetOutput(0), -0.287209, 0.0001f, ""); diff --git a/packages/nodegraph/tests/common/NodeGraphSerializationTest.cpp b/packages/nodegraph/tests/common/NodeGraphSerializationTest.cpp index 4159318a..bdb65575 100644 --- a/packages/nodegraph/tests/common/NodeGraphSerializationTest.cpp +++ b/packages/nodegraph/tests/common/NodeGraphSerializationTest.cpp @@ -32,8 +32,8 @@ TEST(NodeGraph, SerializationBasic) { builder.End(); auto d = builder.GetStr(); - LOG(LogInfo) << "Archive:"; - LOG(LogInfo) << "\n" << d; + LLOG(LogInfo) << "Archive:"; + LLOG(LogInfo) << "\n" << d; l::serialization::JsonParser<100> parser; auto [result, error] = parser.LoadJson(d.c_str(), d.size()); diff --git a/packages/physics/include/physics/Integration.h b/packages/physics/include/physics/Integration.h index 0e8c1638..72a94042 100644 --- a/packages/physics/include/physics/Integration.h +++ b/packages/physics/include/physics/Integration.h @@ -139,11 +139,11 @@ namespace physics { lambda *= 1.0 / forceConstant; V forceLimit = static_cast(1.0 / epsilon2); if (lambda > forceLimit) { - LOG(LogInfo) << "Force limit exceeded: " << lambda; + LLOG(LogInfo) << "Force limit exceeded: " << lambda; //lambda = forceLimit; } if (lambda < -forceLimit) { - LOG(LogInfo) << "Force limit exceeded: " << lambda; + LLOG(LogInfo) << "Force limit exceeded: " << lambda; //lambda = -forceLimit; } @@ -594,7 +594,7 @@ namespace physics { V dP0Sqr = dP0.sqr(); V dP1Sqr = dP1.sqr(); if (abs(dP0Sqr - dP1Sqr) > 0.00001) { - LOG(LogError) << "Something went wrong"; + LLOG(LogError) << "Something went wrong"; } } } @@ -629,7 +629,7 @@ namespace physics { V dP0Sqr = dP0.sqr(); V dP1Sqr = dP1.sqr(); if (abs(dP0Sqr - dP1Sqr) > 0.01) { - LOG(LogError) << "Something went wrong"; + LLOG(LogError) << "Something went wrong"; } } } diff --git a/packages/physics/tests/common/BoxSweepTest.cpp b/packages/physics/tests/common/BoxSweepTest.cpp index 6b5ceb0a..c2268e66 100644 --- a/packages/physics/tests/common/BoxSweepTest.cpp +++ b/packages/physics/tests/common/BoxSweepTest.cpp @@ -39,7 +39,7 @@ TEST(BoxSweep, Init) { sweeper.update(); sweeper.overlapAction([](uint32_t id0, uint32_t id1) { - LOG(LogInfo) << "id0:" << id0 << ", id1:" << id1; + LLOG(LogInfo) << "id0:" << id0 << ", id1:" << id1; }); return 0; } diff --git a/packages/physics/tests/common/GridMapTest.cpp b/packages/physics/tests/common/GridMapTest.cpp index 72effd6d..b73407e3 100644 --- a/packages/physics/tests/common/GridMapTest.cpp +++ b/packages/physics/tests/common/GridMapTest.cpp @@ -145,7 +145,7 @@ TEST(GridMap, StressTest) { count++; }); - LOG(LogInfo) << "Found " << count << " pairs"; + LLOG(LogInfo) << "Found " << count << " pairs"; TEST_TRUE(count > 500 && count < 1100, ""); return 0; diff --git a/packages/physics/tests/common/VectorTest.cpp b/packages/physics/tests/common/VectorTest.cpp index 4585938d..b128f282 100644 --- a/packages/physics/tests/common/VectorTest.cpp +++ b/packages/physics/tests/common/VectorTest.cpp @@ -10,7 +10,7 @@ using namespace l; TEST(Vector, Data2) { { l::vec::Data2 x(5.3, 4.4); - LOG(LogInfo) << x.to_string(); + LLOG(LogInfo) << x.to_string(); TEST_FUZZY(x.floor(1).x1, 5.0, EPSILON, "floor failed"); TEST_FUZZY(x.floor(1).x2, 4.0, EPSILON, "floor failed"); @@ -29,7 +29,7 @@ TEST(Vector, Data2) { } { l::vec::Data2 x(-5.3, -4.4); - LOG(LogInfo) << x.to_string(); + LLOG(LogInfo) << x.to_string(); TEST_FUZZY(x.floor(1).x1, -6.0, 0.001, "floor failed"); TEST_FUZZY(x.floor(1).x2, -5.0, 0.001, "floor failed"); @@ -48,7 +48,7 @@ TEST(Vector, Data2) { TEST(Vector, Data4) { { l::vec::Data4 x(5.3, 4.4, 5.3, 4.4); - LOG(LogInfo) << x.to_string(); + LLOG(LogInfo) << x.to_string(); TEST_FUZZY(x.floor(1).x1, 5.0, EPSILON, "floor failed"); TEST_FUZZY(x.floor(1).x2, 4.0, EPSILON, "floor failed"); @@ -67,7 +67,7 @@ TEST(Vector, Data4) { } { l::vec::Data4 x(-5.3, -4.4, -5.3, -4.4); - LOG(LogInfo) << x.to_string(); + LLOG(LogInfo) << x.to_string(); TEST_FUZZY(x.floor(1).x1, -6.0, 0.001, "floor failed"); TEST_FUZZY(x.floor(1).x2, -5.0, 0.001, "floor failed"); diff --git a/packages/rendering/include/rendering/DataConversion.h b/packages/rendering/include/rendering/DataConversion.h index 6da674f1..c961e810 100644 --- a/packages/rendering/include/rendering/DataConversion.h +++ b/packages/rendering/include/rendering/DataConversion.h @@ -106,7 +106,7 @@ namespace rendering { dstSize = index1 > dstSize ? index1 + 1 : dstSize; SourceInnerType* innerTypePtr = reinterpret_cast(src2 + index0); if (index1 * innerCount >= result.size()) { - LOG(LogError) << "Index too large?"; + LLOG(LogError) << "Index too large?"; result.resize((index1 + index1 / 4) * innerCount); } for (size_t j = 0; j < innerCount; j++) { diff --git a/packages/rendering/include/rendering/GLFWShaders.h b/packages/rendering/include/rendering/GLFWShaders.h index 825c4915..182010a0 100644 --- a/packages/rendering/include/rendering/GLFWShaders.h +++ b/packages/rendering/include/rendering/GLFWShaders.h @@ -65,7 +65,7 @@ namespace rendering { GLsizei logLength = 0; GLchar message[1024]; glGetShaderInfoLog(mVertexShaderId, 1024, &logLength, message); - LOG(LogError) << "Failed to compile vertex shader. Error: " << message; + LLOG(LogError) << "Failed to compile vertex shader. Error: " << message; } GL_ASSERT(); } @@ -79,7 +79,7 @@ namespace rendering { GLsizei logLength = 0; GLchar message[1024]; glGetShaderInfoLog(mFragmentShaderId, 1024, &logLength, message); - LOG(LogError) << "Failed to compile fragment shader. Error: " << message; + LLOG(LogError) << "Failed to compile fragment shader. Error: " << message; } GL_ASSERT(); } @@ -97,7 +97,7 @@ namespace rendering { GLchar message[1024]; glGetProgramInfoLog(mId, 1024, &logLength, message); - LOG(LogError) << "Failed to link. Error: " << message; + LLOG(LogError) << "Failed to link. Error: " << message; } GL_ASSERT(); } diff --git a/packages/rendering/include/rendering/GeometryManip.h b/packages/rendering/include/rendering/GeometryManip.h index de321c75..8287ef9c 100644 --- a/packages/rendering/include/rendering/GeometryManip.h +++ b/packages/rendering/include/rendering/GeometryManip.h @@ -197,7 +197,7 @@ namespace rendering { vec3_mul_cross(tmp, &normals[i], &tangent[i]); float dot2 = vec3_mul_inner(tmp, &tan2[i]); if (dot2 == 0) { - LOG(LogWarning) << "Vertex index " << i << " has an undefined bitangent handedness because:"; + LLOG(LogWarning) << "Vertex index " << i << " has an undefined bitangent handedness because:"; dot2 = 1.0; } if (dot2 < 0) { diff --git a/packages/rendering/include/rendering/ui/UIContainer.h b/packages/rendering/include/rendering/ui/UIContainer.h index 81887e23..80f65980 100644 --- a/packages/rendering/include/rendering/ui/UIContainer.h +++ b/packages/rendering/include/rendering/ui/UIContainer.h @@ -374,7 +374,7 @@ namespace l::ui { void SetParent(UIContainer* parent) {mParent = parent;} void SetCoParent(UIContainer* coParent) {mCoParent = coParent;} - void DebugLog() { LOG(LogDebug) << "UIContainer: " << mDisplayName << ", [" << mDisplayArea.mScale << "][" << mDisplayArea.mPosition.x << ", " << mDisplayArea.mPosition.y << "][" << mDisplayArea.mSize.x << ", " << mDisplayArea.mSize.y << "]"; } + void DebugLog() { LLOG(LogDebug) << "UIContainer: " << mDisplayName << ", [" << mDisplayArea.mScale << "][" << mDisplayArea.mPosition.x << ", " << mDisplayArea.mPosition.y << "][" << mDisplayArea.mSize.x << ", " << mDisplayArea.mSize.y << "]"; } protected: int32_t mId = 0; int32_t mNodeId = -1; diff --git a/packages/rendering/source/common/FPSInterface.cpp b/packages/rendering/source/common/FPSInterface.cpp index 7969a0be..00e82e6a 100644 --- a/packages/rendering/source/common/FPSInterface.cpp +++ b/packages/rendering/source/common/FPSInterface.cpp @@ -69,11 +69,11 @@ namespace l { } void FPSInterface::HandleTouch(int button, int action, int mods) { - LOG(LogInfo) << "button:" << button << ", action:" << action << ", mods:" << mods; + LLOG(LogInfo) << "button:" << button << ", action:" << action << ", mods:" << mods; } void FPSInterface::HandleScroll(float x, float y) { - LOG(LogInfo) << "xoffset:" << x << ", yoffset:" << y; + LLOG(LogInfo) << "xoffset:" << x << ", yoffset:" << y; } void FPSInterface::HandleKeyPress(int key, int, int action, int) { @@ -174,7 +174,7 @@ namespace l { mTurnAngle += x * f; mTiltAngle += y * f; if (fabs(x) > 0.0001f && fabs(y) > 0.0001f) { - //LOG(LogInfo) << "Camera direction: [" << mFront[0] << "," << mFront[1] << "," << mFront[2] << "]" << "[" << mRight[0] << "," << mRight[1] << "," << mRight[2] << "]"; + //LLOG(LogInfo) << "Camera direction: [" << mFront[0] << "," << mFront[1] << "," << mFront[2] << "]" << "[" << mRight[0] << "," << mRight[1] << "," << mRight[2] << "]"; } } @@ -252,7 +252,7 @@ namespace l { mVelocity[1] += velocityDirection[1] * acceleration; mVelocity[2] += velocityDirection[2] * acceleration; - //LOG(LogInfo) << "Camera velocity: [" << mPosition[0] << "," << mPosition[1] << "," << mPosition[2] << "]"; + //LLOG(LogInfo) << "Camera velocity: [" << mPosition[0] << "," << mPosition[1] << "," << mPosition[2] << "]"; } } } diff --git a/packages/rendering/source/common/GLFWRenderVAO.cpp b/packages/rendering/source/common/GLFWRenderVAO.cpp index b844dca9..aa9bf28b 100644 --- a/packages/rendering/source/common/GLFWRenderVAO.cpp +++ b/packages/rendering/source/common/GLFWRenderVAO.cpp @@ -132,10 +132,10 @@ namespace l { uint32_t index = mesh.vertex_indices.data[i]; const ufbx_vec2& value = mesh.vertex_uv[i]; if (uvs[index*2] != static_cast(value.x)) { - LOG(LogError) << ""; + LLOG(LogError) << ""; } if (uvs[index * 2+1] < static_cast(value.y)) { - LOG(LogError) << ""; + LLOG(LogError) << ""; } uvs[index * 2 + 0] = static_cast(value.x); uvs[index * 2 + 1] = static_cast(value.y); diff --git a/packages/rendering/source/common/GLFWWindow.cpp b/packages/rendering/source/common/GLFWWindow.cpp index 2feb7939..dfdd8de3 100644 --- a/packages/rendering/source/common/GLFWWindow.cpp +++ b/packages/rendering/source/common/GLFWWindow.cpp @@ -22,7 +22,7 @@ namespace { void glfw_error_callback(int error, const char* description) { - LOG(LogError) << "GLFW Error " << error << ":" << description << "\n"; + LLOG(LogError) << "GLFW Error " << error << ":" << description << "\n"; } struct Callbacks { @@ -120,7 +120,7 @@ namespace l { // Safe to call even if glfw is already initialized glfwSetErrorCallback(glfw_error_callback); if (!glfwInit()) { - LOG(LogError) << "Failed to initialize GLFW"; + LLOG(LogError) << "Failed to initialize GLFW"; return nullptr; } @@ -160,20 +160,20 @@ namespace l { } if (window == nullptr) { - LOG(LogError) << "Failed to create GLFW window"; + LLOG(LogError) << "Failed to create GLFW window"; return nullptr; } glfwMakeContextCurrent(window); - LOG(LogInfo) << "GLFW version:" << glfwGetVersionString(); + LLOG(LogInfo) << "GLFW version:" << glfwGetVersionString(); if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) { - LOG(LogInfo) << "Failed to load OpenGL procedures"; + LLOG(LogInfo) << "Failed to load OpenGL procedures"; return nullptr; } - LOG(LogInfo) << "OpenGL version:" << glGetString(GL_VERSION); + LLOG(LogInfo) << "OpenGL version:" << glGetString(GL_VERSION); glfwSetKeyCallback(window, invoke_key); glfwSetMouseButtonCallback(window, invoke_mouse); diff --git a/packages/rendering/source/common/Geometry.cpp b/packages/rendering/source/common/Geometry.cpp index 83670dce..a3773453 100644 --- a/packages/rendering/source/common/Geometry.cpp +++ b/packages/rendering/source/common/Geometry.cpp @@ -89,7 +89,7 @@ namespace l { // If the import failed, report it if (nullptr == scene) { - LOG(LogError) << importer.GetErrorString(); + LLOG(LogError) << importer.GetErrorString(); return false; } @@ -107,7 +107,7 @@ namespace l { LoadColladaAsset(file, [](const ColladaData& colladaData) { for (auto& geometry : colladaData.mGeometryNodes) { - LOG(LogInfo) << "Model '" << geometry.mName << "' was successfully loaded."; + LLOG(LogInfo) << "Model '" << geometry.mName << "' was successfully loaded."; } }); @@ -316,15 +316,15 @@ namespace l { // Calculate handedness if (dot2 == 0) { - LOG(LogWarning) << "Vertex index " << i << " has an undefined bitangent handedness because:"; + LLOG(LogWarning) << "Vertex index " << i << " has an undefined bitangent handedness because:"; if (l::vec::IsZeroVector(vertices.subspan(index0, 3))) { - LOG(LogError) << " Normal is zero"; + LLOG(LogError) << " Normal is zero"; } if (l::vec::IsZeroVector(vertices.subspan(index1, 3))) { - LOG(LogWarning) << " Tangent is zero"; + LLOG(LogWarning) << " Tangent is zero"; } if (l::vec::IsZeroVector(std::span(tan2.begin() + 3 * i, 3))) { - LOG(LogWarning) << " Bitangent is zero"; + LLOG(LogWarning) << " Bitangent is zero"; } } if (dot2 < 0) { diff --git a/packages/rendering/source/common/ImageSupport.cpp b/packages/rendering/source/common/ImageSupport.cpp index 704f8b60..8c9118a1 100644 --- a/packages/rendering/source/common/ImageSupport.cpp +++ b/packages/rendering/source/common/ImageSupport.cpp @@ -81,14 +81,14 @@ namespace l::rendering { lodepng::State state; auto result = lodepng_inspect(&w, &h, &state, data.data(), data.size()); if (result != 0) { - LOG(LogError) << "Failed to load image header"; + LLOG(LogError) << "Failed to load image header"; return false; } unsigned int e = lodepng::decode(pixels, w, h, data); if (e != 0) { - LOG(LogError) << "Failed loading PNG file %s"; + LLOG(LogError) << "Failed loading PNG file %s"; return false; } diff --git a/packages/rendering/source/common/ui/UINodeEditor.cpp b/packages/rendering/source/common/ui/UINodeEditor.cpp index f848f7ff..db9b451a 100644 --- a/packages/rendering/source/common/ui/UINodeEditor.cpp +++ b/packages/rendering/source/common/ui/UINodeEditor.cpp @@ -292,7 +292,7 @@ namespace l::ui { if (mNGSchema == nullptr) { return; } - //LOG(LogInfo) << "Container " << containerId << " moved to " << x << ", " << y; + //LLOG(LogInfo) << "Container " << containerId << " moved to " << x << ", " << y; auto node = mNGSchema->GetNode(nodeId); if (node != nullptr) { auto& uiData = node->GetUIData(); @@ -305,7 +305,7 @@ namespace l::ui { if (mNGSchema == nullptr) { return; } - //LOG(LogInfo) << "Container " << containerId << " resized to " << w << ", " << h; + //LLOG(LogInfo) << "Container " << containerId << " resized to " << w << ", " << h; auto node = mNGSchema->GetNode(nodeId); if (node != nullptr) { auto& uiData = node->GetUIData(); @@ -374,7 +374,7 @@ namespace l::ui { auto s = ImVec2(uiData.w, uiData.h); auto uiNode = l::ui::CreateUINode(mUIManager, *node, p, s); - //LOG(LogInfo) << "Replicated node type " << node->GetTypeId() << " as a ui node"; + //LLOG(LogInfo) << "Replicated node type " << node->GetTypeId() << " as a ui node"; mUIRoot->Add(uiNode); } diff --git a/packages/serialization/include/serialization/JsonParser.h b/packages/serialization/include/serialization/JsonParser.h index 298cb5c2..79c30b66 100644 --- a/packages/serialization/include/serialization/JsonParser.h +++ b/packages/serialization/include/serialization/JsonParser.h @@ -148,16 +148,16 @@ namespace l::serialization { mTokenCount = 0; switch (ret) { case JSMN_ERROR_INVAL: - LOG(LogError) << "Failure to parse json value"; + LLOG(LogError) << "Failure to parse json value"; return { false, ret }; case JSMN_ERROR_NOMEM: - LOG(LogError) << "Token buffer is to small"; + LLOG(LogError) << "Token buffer is to small"; return { false, ret }; case JSMN_ERROR_PART: - //LOG(LogInfo) << "Json data is not completed"; + //LLOG(LogInfo) << "Json data is not completed"; return { false, ret }; default: - LOG(LogError) << "Unknown error"; + LLOG(LogError) << "Unknown error"; return { false, -4 }; } } diff --git a/packages/serialization/source/common/SerializationBase.cpp b/packages/serialization/source/common/SerializationBase.cpp index 872d7431..cad7853f 100644 --- a/packages/serialization/source/common/SerializationBase.cpp +++ b/packages/serialization/source/common/SerializationBase.cpp @@ -103,11 +103,11 @@ namespace l::serialization { bool peekSuccessful = headerValidity.Peek(data); if (mExpectIdentifier) { if (!peekSuccessful || !headerValidity.IsIdentifierValid()) { - LOG(LogError) << "Expected serialization identifier: " << headerValidity.mIdentifier << " (version: " << headerValidity.mVersion << ")"; + LLOG(LogError) << "Expected serialization identifier: " << headerValidity.mIdentifier << " (version: " << headerValidity.mVersion << ")"; return; } if (!peekSuccessful || !headerValidity.IsVersionValid(mLatestVersion)) { - LOG(LogError) << "Expected serialization version: " << headerValidity.mVersion << " (identifier: " << headerValidity.mIdentifier << ")"; + LLOG(LogError) << "Expected serialization version: " << headerValidity.mVersion << " (identifier: " << headerValidity.mIdentifier << ")"; return; } mUseIdentifier = true; // if identifier is expected, we should continue using it even if user didn't not set it @@ -120,7 +120,7 @@ namespace l::serialization { mExpectIdentifier = true; if (!headerValidity.IsVersionValid(mLatestVersion)) { - LOG(LogError) << "Expected serialization version: " << headerValidity.mVersion; + LLOG(LogError) << "Expected serialization version: " << headerValidity.mVersion; return; } diff --git a/packages/serialization/tests/common/Base16Test.cpp b/packages/serialization/tests/common/Base16Test.cpp index a0c3643f..8c30c482 100644 --- a/packages/serialization/tests/common/Base16Test.cpp +++ b/packages/serialization/tests/common/Base16Test.cpp @@ -7,9 +7,9 @@ TEST(Base16, Basic) { auto message = "test#!%14+, tolerance) { LOG(LogError) << "TEST_FUZZY(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ")" << msg; LOG(LogTest) << "Test failed: "; return 1;} \ + if (sqrt((expr1 - expr2)*(expr1 - expr2)) > tolerance) { LLOG(LogError) << "TEST_FUZZY(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ")" << msg; LLOG(LogTest) << "Test failed: "; return 1;} \ #define TEST_FUZZY2(expr1, expr2, msg) \ - if (sqrt((expr1 - expr2)*(expr1 - expr2)) > 0.000000001) { LOG(LogError) << "TEST_FUZZY(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ")" << msg; LOG(LogTest) << "Test failed: "; return 1;} \ + if (sqrt((expr1 - expr2)*(expr1 - expr2)) > 0.000000001) { LLOG(LogError) << "TEST_FUZZY(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ")" << msg; LLOG(LogTest) << "Test failed: "; return 1;} \ #define TEST_TRUE_NO_RET(expr, msg) \ - if (!(expr)) { LOG(LogError) << msg; LOG(LogTest) << "Test failed";} \ + if (!(expr)) { LLOG(LogError) << msg; LLOG(LogTest) << "Test failed";} \ #define TEST_FALSE_NO_RET(expr, msg) \ - if (!!(expr)) { LOG(LogError) << msg; LOG(LogTest) << "Test failed";} \ + if (!!(expr)) { LLOG(LogError) << msg; LLOG(LogTest) << "Test failed";} \ #define TEST_EQ_NO_RET(expr1, expr2, msg) \ - if (expr1 != expr2) { LOG(LogError) << msg; LOG(LogTest) << "Test failed";} \ + if (expr1 != expr2) { LLOG(LogError) << msg; LLOG(LogTest) << "Test failed";} \ #define TEST_FUZZY_NO_RET(expr1, expr2, tolerance, msg) \ - if (sqrt((expr1 - expr2)*(expr1 - expr2)) > tolerance) { LOG(LogError) << "TEST_FUZZY(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ")" << msg; LOG(LogTest) << "Test failed: ";} \ + if (sqrt((expr1 - expr2)*(expr1 - expr2)) > tolerance) { LLOG(LogError) << "TEST_FUZZY(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ")" << msg; LLOG(LogTest) << "Test failed: ";} \ #define TEST_FUZZY2_NO_RET(expr1, expr2, msg) \ - if (sqrt((expr1 - expr2)*(expr1 - expr2)) > 0.000000001) { LOG(LogError) << "TEST_FUZZY(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ")" << msg; LOG(LogTest) << "Test failed: ";} \ + if (sqrt((expr1 - expr2)*(expr1 - expr2)) > 0.000000001) { LLOG(LogError) << "TEST_FUZZY(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ")" << msg; LLOG(LogTest) << "Test failed: ";} \ #else #define TEST_TRUE(expr, msg) \ - if (!(expr)) { LOG(LogError) << "TEST_TRUE(" << std::to_string(expr) << ") " << msg; LOG(LogTest) << "Test failed"; DEBUG_BREAK;return 1;} \ + if (!(expr)) { LLOG(LogError) << "TEST_TRUE(" << std::to_string(expr) << ") " << msg; LLOG(LogTest) << "Test failed"; DEBUG_BREAK;return 1;} \ #define TEST_FALSE(expr, msg) \ - if (!!(expr)) { LOG(LogError) << "TEST_FALSE(" << std::to_string(expr) << ") " << msg; LOG(LogTest) << "Test failed"; DEBUG_BREAK;return 1;} \ + if (!!(expr)) { LLOG(LogError) << "TEST_FALSE(" << std::to_string(expr) << ") " << msg; LLOG(LogTest) << "Test failed"; DEBUG_BREAK;return 1;} \ #define TEST_EQ(expr1, expr2, msg) \ - if (expr1 != expr2) { LOG(LogError) << "TEST_EQ(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ") " << msg; LOG(LogTest) << "Test failed"; DEBUG_BREAK;return 1;} \ + if (expr1 != expr2) { LLOG(LogError) << "TEST_EQ(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ") " << msg; LLOG(LogTest) << "Test failed"; DEBUG_BREAK;return 1;} \ #define TEST_FUZZY(expr1, expr2, tolerance, msg) \ - if (sqrt((expr1 - expr2)*(expr1 - expr2)) > tolerance) { LOG(LogError) << "TEST_FUZZY(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ") " << msg; LOG(LogTest) << "Test failed: "; DEBUG_BREAK;return 1;} \ + if (sqrt((expr1 - expr2)*(expr1 - expr2)) > tolerance) { LLOG(LogError) << "TEST_FUZZY(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ") " << msg; LLOG(LogTest) << "Test failed: "; DEBUG_BREAK;return 1;} \ #define TEST_FUZZY2(expr1, expr2, msg) \ - if (sqrt((expr1 - expr2)*(expr1 - expr2)) > 0.000000001) { LOG(LogError) << "TEST_FUZZY(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ") " << msg; LOG(LogTest) << "Test failed: "; DEBUG_BREAK;return 1;} \ + if (sqrt((expr1 - expr2)*(expr1 - expr2)) > 0.000000001) { LLOG(LogError) << "TEST_FUZZY(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ") " << msg; LLOG(LogTest) << "Test failed: "; DEBUG_BREAK;return 1;} \ #define TEST_TRUE_NO_RET(expr, msg) \ - if (!(expr)) { LOG(LogError) << "TEST_TRUE(" << std::to_string(expr) << ") " << msg; LOG(LogTest) << "Test failed"; DEBUG_BREAK;} \ + if (!(expr)) { LLOG(LogError) << "TEST_TRUE(" << std::to_string(expr) << ") " << msg; LLOG(LogTest) << "Test failed"; DEBUG_BREAK;} \ #define TEST_FALSE_NO_RET(expr, msg) \ - if (!!(expr)) { LOG(LogError) << "TEST_FALSE(" << std::to_string(expr) << ") " << msg; LOG(LogTest) << "Test failed"; DEBUG_BREAK;} \ + if (!!(expr)) { LLOG(LogError) << "TEST_FALSE(" << std::to_string(expr) << ") " << msg; LLOG(LogTest) << "Test failed"; DEBUG_BREAK;} \ #define TEST_EQ_NO_RET(expr1, expr2, msg) \ - if (expr1 != expr2) { LOG(LogError) << "TEST_EQ(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ") " << msg; LOG(LogTest) << "Test failed"; DEBUG_BREAK;} \ + if (expr1 != expr2) { LLOG(LogError) << "TEST_EQ(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ") " << msg; LLOG(LogTest) << "Test failed"; DEBUG_BREAK;} \ #define TEST_FUZZY_NO_RET(expr1, expr2, tolerance, msg) \ - if (sqrt((expr1 - expr2)*(expr1 - expr2)) > tolerance) { LOG(LogError) << "TEST_FUZZY(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ") " << msg; LOG(LogTest) << "Test failed: "; DEBUG_BREAK;} \ + if (sqrt((expr1 - expr2)*(expr1 - expr2)) > tolerance) { LLOG(LogError) << "TEST_FUZZY(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ") " << msg; LLOG(LogTest) << "Test failed: "; DEBUG_BREAK;} \ #define TEST_FUZZY2_NO_RET(expr1, expr2, msg) \ - if (sqrt((expr1 - expr2)*(expr1 - expr2)) > 0.000000001) { LOG(LogError) << "TEST_FUZZY(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ") " << msg; LOG(LogTest) << "Test failed: "; DEBUG_BREAK;} \ + if (sqrt((expr1 - expr2)*(expr1 - expr2)) > 0.000000001) { LLOG(LogError) << "TEST_FUZZY(" << std::to_string(expr1) << ", " << std::to_string(expr2) << ") " << msg; LLOG(LogTest) << "Test failed: "; DEBUG_BREAK;} \ #endif #define TEST_RUN(app) \ - if (!l::testing::run_tests(app)) { LOG(LogTest) << "Test run failed"; return 1;} \ - if (!l::testing::run_perfs(app)) { LOG(LogTest) << "Perf run failed"; return 1;} + if (!l::testing::run_tests(app)) { LLOG(LogTest) << "Test run failed"; return 1;} \ + if (!l::testing::run_perfs(app)) { LLOG(LogTest) << "Perf run failed"; return 1;} diff --git a/packages/testing/source/common/Test.cpp b/packages/testing/source/common/Test.cpp index 027157c6..8f7d70d4 100644 --- a/packages/testing/source/common/Test.cpp +++ b/packages/testing/source/common/Test.cpp @@ -56,7 +56,7 @@ namespace testing { } bool run_tests(const char* app) { - LOG(LogTitle) << "Unit tests " << app; + LLOG(LogTitle) << "Unit tests " << app; bool test_success = true; { @@ -67,9 +67,9 @@ namespace testing { auto& groups = get_test_groups(); for (auto& groupIt : groups) { size_t total = groupIt.second->size(); - LOG(LogTitle) << "# " << groupIt.first; + LLOG(LogTitle) << "# " << groupIt.first; for (auto& f : *groupIt.second) { - LOG(LogTitle) << "## " << groupIt.first + "::" + f.first; + LLOG(LogTitle) << "## " << groupIt.first + "::" + f.first; if (f.second()) { failed_tests++; test_success = false; @@ -77,17 +77,17 @@ namespace testing { } std::ostringstream msg; msg << "## Test result for '" + groupIt.first + "': successful tests(" << (total - failed_tests) << " / " << (total) << ")"; - LOG(LogTitle) << msg.str(); + LLOG(LogTitle) << msg.str(); summary.push_back(msg.str()); } - LOG(LogTitle) << "## Test summary "; + LLOG(LogTitle) << "## Test summary "; for (auto& str : summary) { - LOG(LogTitle) << str; + LLOG(LogTitle) << str; } if (!test_success) { - LOG(LogTitle) << "All tests did not go through successfully.."; + LLOG(LogTitle) << "All tests did not go through successfully.."; } } @@ -95,7 +95,7 @@ namespace testing { } bool run_perfs(const char* app) { - LOG(LogTitle) << "Performance tests " << app; + LLOG(LogTitle) << "Performance tests " << app; bool perf_success = true; { @@ -106,9 +106,9 @@ namespace testing { auto& groups = get_perf_groups(); for (auto& groupIt : groups) { size_t total = groupIt.second->size(); - LOG(LogTitle) << "## " << groupIt.first; + LLOG(LogTitle) << "## " << groupIt.first; for (auto& f : *groupIt.second) { - LOG(LogTitle) << groupIt.first + "::" + f.first; + LLOG(LogTitle) << groupIt.first + "::" + f.first; if (f.second()) { failed_perfs++; perf_success = false; @@ -117,23 +117,23 @@ namespace testing { auto& measures = get_time_measures(groupIt.first); for (auto& result : measures) { - LOG(LogInfo) << groupIt.first << "::" << result.first << ": " << result.second.mSeconds << " sec."; + LLOG(LogInfo) << groupIt.first << "::" << result.first << ": " << result.second.mSeconds << " sec."; } } std::ostringstream msg; msg << "Performance result for '" + groupIt.first + "': successful perfs(" << (total - failed_perfs) << " / " << (total) << ")"; - LOG(LogTitle) << msg.str(); + LLOG(LogTitle) << msg.str(); summary.push_back(msg.str()); } - LOG(LogTitle) << "----"; + LLOG(LogTitle) << "----"; for (auto& str : summary) { - LOG(LogTitle) << str; + LLOG(LogTitle) << str; } if (!perf_success) { - LOG(LogTitle) << "All perfs did not go through successfully.."; + LLOG(LogTitle) << "All perfs did not go through successfully.."; } } diff --git a/packages/testing/tests/common/LoggingTest.cpp b/packages/testing/tests/common/LoggingTest.cpp index f60bba47..61105ac6 100644 --- a/packages/testing/tests/common/LoggingTest.cpp +++ b/packages/testing/tests/common/LoggingTest.cpp @@ -54,13 +54,13 @@ TEST(Logging, StringToHex) { TEST(Logging, StringCharacterConversion) { //auto s0 = L"ž © Õ ñ Ď Ĺ Ť Ɓ Ǯ Ƕ ɘ ʓ"; auto s1 = std::wstring(L"© Õ ñ"); - LOG(LogInfo) << s1; + LLOG(LogInfo) << s1; auto s2 = string::narrow(s1); - LOG(LogInfo) << s2; + LLOG(LogInfo) << s2; auto s3 = string::widen(s2); - LOG(LogInfo) << s3; + LLOG(LogInfo) << s3; auto s4 = string::narrow(s3); - LOG(LogInfo) << s4; + LLOG(LogInfo) << s4; TEST_TRUE(s3 == s1, "s1 did not equal s3"); TEST_TRUE(s4 == s2, "s2 did not equal s4"); @@ -169,13 +169,13 @@ PERF_TEST(LoggingTest, LogTimings) { { PERF_TIMER("LogTimings::LogInfo"); for (int i = 0; i < 10; i++) { - LOG(LogInfo) << "Test logging"; + LLOG(LogInfo) << "Test logging"; } } { PERF_TIMER("LogTimings::LogDebug"); for (int i = 0; i < 10; i++) { - LOG(LogDebug) << "Test logging"; + LLOG(LogDebug) << "Test logging"; } } diff --git a/packages/tools/source/windows/platform/PlatformWindows.cpp b/packages/tools/source/windows/platform/PlatformWindows.cpp index 564de724..20ec7360 100644 --- a/packages/tools/source/windows/platform/PlatformWindows.cpp +++ b/packages/tools/source/windows/platform/PlatformWindows.cpp @@ -79,16 +79,16 @@ bool Proc::Execute(const std::wstring& file, const std::wstring& args, bool elev if (elevated) { ShExecInfo.lpVerb = L"runas"; - LOG(LogInfo) << "Attempt running application with elevated privileges.."; + LLOG(LogInfo) << "Attempt running application with elevated privileges.."; } if (!ShellExecuteExW(&ShExecInfo)) { auto err = GetLastError(); if (err) { - LOG(LogError) << "Error executing " << file << ". Error: " << err; + LLOG(LogError) << "Error executing " << file << ". Error: " << err; } else { - LOG(LogError) << "Unknown error occured"; + LLOG(LogError) << "Unknown error occured"; } return 1; } @@ -126,16 +126,16 @@ bool Proc::Fork(std::wstring title, std::wstring& file, const std::wstring& args &mProcessInfo) // Pointer to PROCESS_INFORMATION structure ) { - LOG(LogError) << "Failed to create process " << filename << ", " << std::to_string(static_cast(GetLastError())); + LLOG(LogError) << "Failed to create process " << filename << ", " << std::to_string(static_cast(GetLastError())); return false; } - LOG(LogInfo) << "Successfully started process '" << filename << " " << args << "'"; + LLOG(LogInfo) << "Successfully started process '" << filename << " " << args << "'"; if (!detach) { - LOG(LogInfo) << "Waiting for process exit"; + LLOG(LogInfo) << "Waiting for process exit"; DWORD waitResult = WaitForSingleObject(mProcessInfo.hProcess, INFINITE); if (waitResult == WAIT_FAILED) { - LOG(LogError) << "Wait for process failed " + std::to_string(static_cast(GetLastError())); + LLOG(LogError) << "Wait for process failed " + std::to_string(static_cast(GetLastError())); return false; } diff --git a/packages/tools/source/windows/utils/Opengl.cpp b/packages/tools/source/windows/utils/Opengl.cpp index bf59b696..b47005d3 100644 --- a/packages/tools/source/windows/utils/Opengl.cpp +++ b/packages/tools/source/windows/utils/Opengl.cpp @@ -21,7 +21,7 @@ namespace win32 { bool hasError = false; GLenum error; while((error = glGetError()) != GL_NO_ERROR) { - LOG(LogError) << "GL error: " << error; + LLOG(LogError) << "GL error: " << error; hasError = true; } return hasError; @@ -55,29 +55,29 @@ namespace win32 { HDC hDC = GetDC(windowData.mHWnd); if (!hDC) { - LOG(LogError) << "Failed to get window draw context (dc)"; + LLOG(LogError) << "Failed to get window draw context (dc)"; return std::nullopt; } int format = ChoosePixelFormat(hDC, &pfd); if (format == 0) { - LOG(LogError) << "Failed to choose pixel format"; + LLOG(LogError) << "Failed to choose pixel format"; return std::nullopt; } if (!SetPixelFormat(hDC, format, &pfd)) { - LOG(LogError) << "Failed to set pixel format"; + LLOG(LogError) << "Failed to set pixel format"; return std::nullopt; } HGLRC hRC = wglCreateContext(hDC); if (!wglMakeCurrent(hDC, hRC)) { - LOG(LogError) << "Failed to make current context"; + LLOG(LogError) << "Failed to make current context"; return std::nullopt; } - LOG(LogInfo) << "Available opengl version: " << glGetString(GL_VERSION); + LLOG(LogInfo) << "Available opengl version: " << glGetString(GL_VERSION); glEnable(GL_BLEND); @@ -96,7 +96,7 @@ namespace win32 { void glSwapBuffers(const OpenGLData& openGLData) { if (!wglSwapLayerBuffers(openGLData.mHandleDC, WGL_SWAP_MAIN_PLANE)) { - LOG(LogError) << "Failed to swap buffers"; + LLOG(LogError) << "Failed to swap buffers"; } } diff --git a/packages/tools/source/windows/utils/Process.cpp b/packages/tools/source/windows/utils/Process.cpp index 006b93ea..d67d6ac6 100644 --- a/packages/tools/source/windows/utils/Process.cpp +++ b/packages/tools/source/windows/utils/Process.cpp @@ -44,20 +44,20 @@ namespace process { &mProcessInfo) // Pointer to PROCESS_INFORMATION structure ) { - LOG(LogError) << "Failed to create process " << filename << ", " << std::to_string(static_cast(GetLastError())); + LLOG(LogError) << "Failed to create process " << filename << ", " << std::to_string(static_cast(GetLastError())); return FAILED_TO_CREATE_PROCESS; } if (!mDetach) { - LOG(LogInfo) << "Successfully started process " << filename << " " << mArgs; + LLOG(LogInfo) << "Successfully started process " << filename << " " << mArgs; // Wait until child process exits. DWORD waitResult = WaitForSingleObject(mProcessInfo.hProcess, INFINITE); if (waitResult == WAIT_FAILED) { - LOG(LogError) << "Wait for process failed " + std::to_string(static_cast(GetLastError())); + LLOG(LogError) << "Wait for process failed " + std::to_string(static_cast(GetLastError())); return FAILED_TO_WAIT_FOR_PROCESS; } else { - LOG(LogInfo) << "Wait ended for process " << filename; + LLOG(LogInfo) << "Wait ended for process " << filename; } } @@ -84,7 +84,7 @@ namespace process { return processRunner.get(); } else { - LOG(LogError) << "Failed to detach process"; + LLOG(LogError) << "Failed to detach process"; return FAILED_TO_DETACH_PROCESS; } } diff --git a/packages/tools/source/windows/utils/Socket.cpp b/packages/tools/source/windows/utils/Socket.cpp index d9125e73..a62351d8 100644 --- a/packages/tools/source/windows/utils/Socket.cpp +++ b/packages/tools/source/windows/utils/Socket.cpp @@ -12,11 +12,11 @@ namespace l { int xsend(SOCKET s, const char *buf, size_t len, int flags) { int result = send(s, (const char *)buf, (int)len, flags); if (result == SOCKET_ERROR) { - LOG(LogWarning) << "Failed to write to socket " << s << ", error: " << WSAGetLastError(); + LLOG(LogWarning) << "Failed to write to socket " << s << ", error: " << WSAGetLastError(); return result; } if (result == 0) { - LOG(LogWarning) << "Socket " << s << " closed gracefully"; + LLOG(LogWarning) << "Socket " << s << " closed gracefully"; return result; } return result; @@ -25,11 +25,11 @@ namespace l { int xrecv(SOCKET s, char *buf, size_t len, int flags) { int result = recv(s, (char *)buf, (int)len, flags); if (result == SOCKET_ERROR) { - LOG(LogWarning) << "Failed to read from socket " << s; + LLOG(LogWarning) << "Failed to read from socket " << s; return result; } if (result == 0) { - LOG(LogWarning) << "Socket " << s << " closed gracefully"; + LLOG(LogWarning) << "Socket " << s << " closed gracefully"; return result; } return result; @@ -38,7 +38,7 @@ namespace l { bool xclose(SOCKET clientSocket) { int result = shutdown(clientSocket, SD_SEND); if (result == SOCKET_ERROR) { - LOG(LogError) << "Shutdown failed with error: " << WSAGetLastError(); + LLOG(LogError) << "Shutdown failed with error: " << WSAGetLastError(); closesocket(clientSocket); return false; } @@ -58,7 +58,7 @@ namespace l { auto iResult = WSAStartup(version, &WSAData); if (iResult != 0) { - LOG(LogError) << "WSAStartup failed with error: " << iResult; + LLOG(LogError) << "WSAStartup failed with error: " << iResult; } if (LOBYTE(WSAData.wVersion) == LOBYTE(version) && HIBYTE(WSAData.wVersion) == HIBYTE(version)) { initialized = true; @@ -83,10 +83,10 @@ namespace l { SOCKET s = accept(mListenSocket, (SOCKADDR*)&addr, &addrlen); const char *ip = inet_ntoa(addr.sin_addr); if (s == INVALID_SOCKET) { - LOG(LogError) << "Failed connection from " << ip << ":" << addr.sin_port << ", error: " << WSAGetLastError(); + LLOG(LogError) << "Failed connection from " << ip << ":" << addr.sin_port << ", error: " << WSAGetLastError(); return nullptr; } - LOG(LogInfo) << "Accept connection from " << ip << ":" << addr.sin_port; + LLOG(LogInfo) << "Accept connection from " << ip << ":" << addr.sin_port; return std::make_unique(s, ip, addr.sin_port); } @@ -124,14 +124,14 @@ namespace l { // Resolve the server address and port int iResult = getaddrinfo(NULL, std::to_string(port).c_str(), &hints, &result); if (iResult != 0) { - LOG(LogError) << "getaddrinfo failed with error: " << iResult; + LLOG(LogError) << "getaddrinfo failed with error: " << iResult; return nullptr; } // Create a SOCKET for connecting to server SOCKET listenSocket = socket(result->ai_family, result->ai_socktype, result->ai_protocol); if (listenSocket == INVALID_SOCKET) { - LOG(LogError) << "socket failed with error: " << WSAGetLastError(); + LLOG(LogError) << "socket failed with error: " << WSAGetLastError(); freeaddrinfo(result); return nullptr; } @@ -139,7 +139,7 @@ namespace l { // Setup the TCP listening socket iResult = bind(listenSocket, result->ai_addr, (int)result->ai_addrlen); if (iResult == SOCKET_ERROR) { - LOG(LogError) << "bind failed with error: " << WSAGetLastError(); + LLOG(LogError) << "bind failed with error: " << WSAGetLastError(); freeaddrinfo(result); closesocket(listenSocket); return nullptr; @@ -149,7 +149,7 @@ namespace l { iResult = listen(listenSocket, SOMAXCONN); if (iResult == SOCKET_ERROR) { - LOG(LogError) << "listen failed with error: " << WSAGetLastError(); + LLOG(LogError) << "listen failed with error: " << WSAGetLastError(); closesocket(listenSocket); return nullptr; } @@ -173,7 +173,7 @@ namespace l { // Resolve the server address and port iResult = getaddrinfo(host, std::to_string(port).c_str(), &hints, &result); if (iResult != 0) { - LOG(LogError) << "getaddrinfo failed with error: " << iResult; + LLOG(LogError) << "getaddrinfo failed with error: " << iResult; return nullptr; } @@ -183,7 +183,7 @@ namespace l { // Create a SOCKET for connecting to server connectSocket = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol); if (connectSocket == INVALID_SOCKET) { - LOG(LogError) << "socket failed with error: " << WSAGetLastError(); + LLOG(LogError) << "socket failed with error: " << WSAGetLastError(); return nullptr; } @@ -200,7 +200,7 @@ namespace l { freeaddrinfo(result); if (connectSocket == INVALID_SOCKET) { - LOG(LogError) << "Unable to connect to server!"; + LLOG(LogError) << "Unable to connect to server!"; return nullptr; } diff --git a/packages/tools/source/windows/utils/Win32.cpp b/packages/tools/source/windows/utils/Win32.cpp index d2616ace..52f6492c 100644 --- a/packages/tools/source/windows/utils/Win32.cpp +++ b/packages/tools/source/windows/utils/Win32.cpp @@ -47,7 +47,7 @@ namespace { } } else { - LOG(LogError) << "Failed to locate window callback: " << l::string::narrow(className); + LLOG(LogError) << "Failed to locate window callback: " << l::string::narrow(className); } } } @@ -83,30 +83,30 @@ namespace l { switch (msg) { case WM_ACTIVATEAPP: - LOG(LogDebug) << "[" << hwnd << "] WM_ACTIVATEAPP recieved [" << wp << ", " << lp << "]"; + LLOG(LogDebug) << "[" << hwnd << "] WM_ACTIVATEAPP recieved [" << wp << ", " << lp << "]"; break; case WM_ACTIVATE: - LOG(LogDebug) << "[" << hwnd << "] WM_ACTIVATE recieved [" << wp << ", " << lp << "]"; + LLOG(LogDebug) << "[" << hwnd << "] WM_ACTIVATE recieved [" << wp << ", " << lp << "]"; break; case WM_NCCREATE: - LOG(LogDebug) << "[" << hwnd << "] WM_NCCREATE recieved [" << wp << ", " << lp << "]"; + LLOG(LogDebug) << "[" << hwnd << "] WM_NCCREATE recieved [" << wp << ", " << lp << "]"; break; case WM_GETMINMAXINFO: - //LOG(LogDebug) << "[" << hwnd << "] WM_GETMINMAXINFO recieved [" << wp << ", " << lp << "]"; + //LLOG(LogDebug) << "[" << hwnd << "] WM_GETMINMAXINFO recieved [" << wp << ", " << lp << "]"; break; case WM_CREATE: - LOG(LogDebug) << "[" << hwnd << "] WM_CREATE recieved [" << wp << ", " << lp << "]"; + LLOG(LogDebug) << "[" << hwnd << "] WM_CREATE recieved [" << wp << ", " << lp << "]"; break; case WM_GETICON: // Called regulary to update large and small app icon break; case WM_CLOSE: - LOG(LogDebug) << "[" << hwnd << "] WM_CLOSE recieved [" << wp << ", " << lp << "]"; + LLOG(LogDebug) << "[" << hwnd << "] WM_CLOSE recieved [" << wp << ", " << lp << "]"; break; case WM_DESTROY: - LOG(LogDebug) << "[" << hwnd << "] WM_DESTROY recieved [" << wp << ", " << lp << "]"; + LLOG(LogDebug) << "[" << hwnd << "] WM_DESTROY recieved [" << wp << ", " << lp << "]"; break; case WM_NCDESTROY: - LOG(LogDebug) << "[" << hwnd << "] WM_NCDESTROY recieved [" << wp << ", " << lp << "]"; + LLOG(LogDebug) << "[" << hwnd << "] WM_NCDESTROY recieved [" << wp << ", " << lp << "]"; EraseWindowCallback(hwnd); } return DefWindowProcW(hwnd, msg, wp, lp); @@ -141,13 +141,13 @@ namespace l { return std::make_optional(name, std::move(wndClassEx), hWnd); } else { - LOG(LogError) << "Failed to create window, error " << GetLastError(); + LLOG(LogError) << "Failed to create window, error " << GetLastError(); } } else { - LOG(LogError) << "Failed to register window class. Error: " << GetLastError(); + LLOG(LogError) << "Failed to register window class. Error: " << GetLastError(); } - LOG(LogError) << "See https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes for more info"; + LLOG(LogError) << "See https://learn.microsoft.com/en-us/windows/win32/debug/system-error-codes for more info"; return std::nullopt; } From 05a2d6c5bd4d653d401327a475963d96ce0c4f7c Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 19 Sep 2025 01:33:35 +0200 Subject: [PATCH 103/179] Add torch to nn. --- packages/nn/CMakeLists.txt | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/packages/nn/CMakeLists.txt b/packages/nn/CMakeLists.txt index cfe7cb5b..984e7f6d 100644 --- a/packages/nn/CMakeLists.txt +++ b/packages/nn/CMakeLists.txt @@ -15,12 +15,22 @@ set(deps_external tiny_dnn_static ) +if(TARGET libtorch) + list(APPEND deps_external + libtorch + ) +endif() + bs_generate_package(nn "tier1" "${deps}" "${deps_external}") set_target_properties(nn PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED YES) set_target_properties(nn_test PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED YES) +if(TARGET libtorch) + bs_copy_shared_libs_dir(nn_test "${LDEPS_LIBTORCH_LIB_DIR}") +endif() + if(MSVC) - target_compile_options(nn PRIVATE /W2 /bigobj) + target_compile_options(nn PRIVATE /WX- /bigobj) else() target_compile_options(nn PRIVATE -Werror -Wno-unused-result -Wno-ignored-qualifiers -Wno-unused-parameter) endif() From 64ad8e0e3974715d5d179b04a2f66268661a2faf Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 19 Sep 2025 11:14:46 +0200 Subject: [PATCH 104/179] Add torch test. --- packages/nn/include/nn/torch/TorchBase.h | 17 ++++++++ packages/nn/source/common/torch/TorchBase.cpp | 41 +++++++++++++++++++ packages/nn/tests/common/TorchTest.cpp | 11 +++++ 3 files changed, 69 insertions(+) create mode 100644 packages/nn/include/nn/torch/TorchBase.h create mode 100644 packages/nn/source/common/torch/TorchBase.cpp create mode 100644 packages/nn/tests/common/TorchTest.cpp diff --git a/packages/nn/include/nn/torch/TorchBase.h b/packages/nn/include/nn/torch/TorchBase.h new file mode 100644 index 00000000..0adb4162 --- /dev/null +++ b/packages/nn/include/nn/torch/TorchBase.h @@ -0,0 +1,17 @@ +#pragma once + +#include +#include + +#ifdef LDEPS_USE_LIBTORCH +#include +#endif + +namespace l::nn::libtorch { + class Transformer { + public: + void process(const std::vector& window); + }; + +} + diff --git a/packages/nn/source/common/torch/TorchBase.cpp b/packages/nn/source/common/torch/TorchBase.cpp new file mode 100644 index 00000000..cccb59ec --- /dev/null +++ b/packages/nn/source/common/torch/TorchBase.cpp @@ -0,0 +1,41 @@ +#include + +namespace l::nn::libtorch { + +#ifdef LDEPS_USE_LIBTORCH + struct TransformerNet : torch::nn::Module { + // Define transformer as in previous messages + torch::nn::Conv1d conv{ nullptr }; + torch::nn::Transformer transformer{ nullptr }; + torch::nn::Linear fc{ nullptr }; + TransformerNet(int window_size, int output_size) { + conv = register_module("conv", torch::nn::Conv1d(torch::nn::Conv1dOptions(1, 16, 5).stride(1).padding(2))); + transformer = register_module("transformer", torch::nn::Transformer(torch::nn::TransformerOptions(16, 8).d_model(16).nhead(8))); + fc = register_module("fc", torch::nn::Linear(16 * window_size, output_size)); + } + torch::Tensor forward(torch::Tensor x) { + x = x.unsqueeze(1); + x = torch::relu(conv->forward(x)); + x = transformer->forward(x, x); + x = x.view({ x.size(0), -1 }); + return fc->forward(x); + } + }; +#endif + + void Transformer::process(const std::vector& window) { +#ifdef LDEPS_USE_LIBTORCH + static TransformerNet model(window.size(), 10); // Predict 10 samples + model.eval(); + torch::NoGradGuard no_grad; + auto input = torch::tensor(window).reshape({ 1, -1 }); + auto output = model.forward(input); + std::vector result(output.data_ptr(), output.data_ptr() + 10); + + //LLOG(LogInfo) << "result[0]: " << result.at(0); +#else + // Fallback: Simple moving average or skip + std::cout << "Torch not available. Skipping transformer processing.\n"; +#endif + } +} diff --git a/packages/nn/tests/common/TorchTest.cpp b/packages/nn/tests/common/TorchTest.cpp new file mode 100644 index 00000000..844c79a3 --- /dev/null +++ b/packages/nn/tests/common/TorchTest.cpp @@ -0,0 +1,11 @@ +#include "testing/Test.h" +#include "logging/Log.h" + +#include + +TEST(Torch, Basic) { + + return 0; +} + + From b09ff025b66a5f2a0efdd7cb07741450d7a9c2f6 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 10 Oct 2025 22:23:47 +0200 Subject: [PATCH 105/179] NG: Fix bug in pow node. Add simple event system for node group and nodes. --- packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h | 2 ++ .../nodegraph/operations/NodeGraphOpMathAritmethic.h | 2 +- .../include/nodegraph/operations/NodeGraphOpTradingDataIO.h | 4 ++++ packages/nodegraph/source/common/core/NodeGraphGroup.cpp | 6 ++++++ .../source/common/operations/NodeGraphOpTradingDataIO.cpp | 6 ++++++ 5 files changed, 19 insertions(+), 1 deletion(-) diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h b/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h index f3ceb6fc..4c81ddd6 100644 --- a/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h @@ -134,6 +134,8 @@ namespace l::nodegraph { void ClearProcessFlags(); void ProcessSubGraph(int32_t numSamples, int32_t numCacheSamples = -1); void Tick(int32_t tickCount, float elapsed); + + void SendEvent(int32_t id, int32_t cmd = 0, void* userdata = nullptr); protected: NodeFactoryBase* mNodeFactory = nullptr; diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h index 6577911a..5fd9a52a 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h @@ -263,7 +263,7 @@ namespace l::nodegraph { virtual ~MathAritmethicPow() = default; virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { auto input0 = inputs.at(0).GetIterator(numSamples); - auto exponent = inputs.at(2).Get(); + auto exponent = inputs.at(1).Get(); auto output1 = &outputs.at(0).Get(numSamples); for (int32_t i = 0; i < numSamples; i++) { diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h index 16cb68e4..4272694f 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h @@ -89,6 +89,8 @@ namespace l::nodegraph { AddInput2("Base", 16, InputFlags(false, true, false, true)); AddInput("Index", 2.0f, 1, 0.0f, 10.0f); AddInput2("Now"); + AddInput2("PTick"); + AddInput2("QStep"); AddOutput2("Symbol", 16, OutputFlags(false, true)); AddOutput2("Base", 16, OutputFlags(false, true)); @@ -98,6 +100,8 @@ namespace l::nodegraph { AddOutput("Index#3", 3.0f); AddOutput("Now"); AddOutput("Reset"); + AddOutput("PTick"); + AddOutput("QStep"); } virtual ~TradingDataIOChartInfo() = default; diff --git a/packages/nodegraph/source/common/core/NodeGraphGroup.cpp b/packages/nodegraph/source/common/core/NodeGraphGroup.cpp index ea23642f..a9a017ec 100644 --- a/packages/nodegraph/source/common/core/NodeGraphGroup.cpp +++ b/packages/nodegraph/source/common/core/NodeGraphGroup.cpp @@ -361,4 +361,10 @@ namespace l::nodegraph { } mLastTickCount = tickCount; } + + void NodeGraphGroup::SendEvent(int32_t id, int32_t cmd, void* userdata) { + for (auto& node : mNodes) { + node->RecieveEvent(id, cmd, userdata); + } + } } \ No newline at end of file diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp index 5bded53b..1c2413e9 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp @@ -175,6 +175,8 @@ namespace l::nodegraph { auto baseInput = inputs.at(1).GetText(16); auto indexInput = l::math::clamp(inputs.at(2).Get(), 0.0f, 9.9999f); auto now = inputs.at(3).Get(); + auto ptick = inputs.at(4).Get(); + auto qstep = inputs.at(5).Get(); outputs.at(0).SetText(symbolInput); outputs.at(1).SetText(baseInput); @@ -184,6 +186,8 @@ namespace l::nodegraph { float* indexOut3 = &outputs.at(5).Get(); float* nowOutput = &outputs.at(6).Get(); float* resetOutput = &outputs.at(7).Get(); + float* ptickOutput = &outputs.at(8).Get(); + float* qstepOutput = &outputs.at(9).Get(); *indexOut0 = l::math::clamp(indexInput, 0.0f, 9.9999f); *indexOut1 = l::math::clamp(indexInput + 1.0f, 0.0f, 9.9999f); @@ -191,6 +195,8 @@ namespace l::nodegraph { *indexOut3 = l::math::clamp(indexInput + 3.0f, 0.0f, 9.9999f); *nowOutput = now; *resetOutput = mReadSamples == 0; + *ptickOutput = ptick; + *qstepOutput = qstep; mReadSamples += numSamples; if (mReadSamples >= numCacheSamples) { From 46a60c7b7374553caa614ab769814e424f51b04c Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 28 Oct 2025 15:16:45 +0100 Subject: [PATCH 106/179] Add a mean exponential regression convolution node. --- .../source/common/NetworkConnection.cpp | 4 +- .../operations/NodeGraphOpMathNumerical.h | 21 ++++++ .../source/common/NodeGraphSchema.cpp | 6 +- .../operations/NodeGraphOpMathNumerical.cpp | 74 +++++++++++++++++++ 4 files changed, 103 insertions(+), 2 deletions(-) diff --git a/packages/network/source/common/NetworkConnection.cpp b/packages/network/source/common/NetworkConnection.cpp index 47ddf82e..4250d2d0 100644 --- a/packages/network/source/common/NetworkConnection.cpp +++ b/packages/network/source/common/NetworkConnection.cpp @@ -333,9 +333,11 @@ namespace l::network { int32_t maxTries = 3; size_t readTotal = 0; CURLcode res = CURLE_OK; + + const struct curl_ws_frame* meta = nullptr; + while (!res) { size_t recv = 0; - const struct curl_ws_frame* meta = nullptr; auto recvMax = size - readTotal; res = curl_ws_recv(mCurl, buffer + readTotal, recvMax, &recv, &meta); readTotal += recv; diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index e6f95216..3ca94c92 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -268,4 +268,25 @@ namespace l::nodegraph { float mEmaAccum = 0.0f; }; + /*********************************************************************/ + class MathNumericalMeanExpRegression : public nodegraph::NodeGraphOp { + public: + MathNumericalMeanExpRegression(nodegraph::NodeGraphBase* node) : + NodeGraphOp(node, "Mean Regression") + { + AddInput2("In"); + AddInput("N", 14.0f, 1, 1.0f, 1000.0f); + AddInput("Exp", 2.0f, 1, 0.0f, 10.0f); + AddInput("Distribution", 2.0f, 1, 0.0f, 10.0f); + + AddOutput2("Out"); + } + + virtual ~MathNumericalMeanExpRegression() = default; + virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + protected: + int32_t mReadSamples = 0; + + std::vector mValues; + }; } \ No newline at end of file diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 5faf9d0c..cf4632ea 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -342,7 +342,10 @@ namespace l::nodegraph { case 150: node = mMainNodeGraph.NewNode(id, NodeType::Default); break; - + case 151: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; + // Trading data io case 200: node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 0); @@ -673,6 +676,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Numerical", 148, "Unitmap", "Maps the input to [-1,1] via a sigmoid function. A scale factor can be provided that changes the shape of the mapping"); RegisterNodeType("Math.Numerical", 149, "EMA", "Exponential moving average [ema1=(ema0*(n-1)+input)/n]"); RegisterNodeType("Math.Numerical", 150, "Change 2", "Temporal change 2. Computes the value: (v_now - v_prev) / abs(v_now)."); + RegisterNodeType("Math.Numerical", 151, "Mean Regression", "Computes the convolution of the exponential distances and can be used as a square root of the variance for computing the mean regression or the trend/direction of the input values."); } else if (typeGroup == "Trading.Data IO") { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index f34197e7..7023d52a 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -16,6 +16,10 @@ namespace l::nodegraph { auto frictionFactor = l::math::clamp(l::math::pow(friction, 0.25f), 0.0f, 1.0f); auto output = &outputs.at(0).Get(numSamples); + if (mReadSamples == 0) { + mOutput = *input0; + } + for (int32_t i = 0; i < numSamples; i++) { mOutput += *input0++; mOutput *= frictionFactor; @@ -428,4 +432,74 @@ namespace l::nodegraph { mReadSamples = 0; } } + + + /*********************************************************************/ + void MathNumericalMeanExpRegression::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + auto inInput = &inputs.at(0).Get(numSamples); + auto n = l::math::max2(inputs.at(1).Get(), 1.0f); + auto exp = inputs.at(2).Get(); + auto distribution = inputs.at(3).Get(); + + auto outOutput = &outputs.at(0).Get(numSamples); + + if (mReadSamples == 0) { + mValues.clear(); + } + + auto nFactor = 1.0f / n; + + for (int32_t i = 0; i < numSamples; i++) { + float in = *inInput++; + + if (mValues.size() >= n) { + mValues.erase(mValues.begin()); + } + else { + auto numToAdd = n - mValues.size() - 1; + for (int32_t i = 0; i < numToAdd; i++) { + mValues.push_back(in); + } + } + mValues.push_back(in); + + auto mean = 0.0f; + auto meanSumFactor = 0.0f; + { // calculate the mean value with the distribution in mind + auto count = 0; + for (auto& value : mValues) { + auto distributionFactor = l::math::pow(count / static_cast(n), distribution); + mean += value * distributionFactor; + meanSumFactor += distributionFactor; + count++; + } + mean *= nFactor; + if (meanSumFactor > 0.0f) { + mean /= meanSumFactor; + } + } + + auto meanSquareSum = 0.0f; + { // calculate the mean regression with the sum of the exponential distance to the mean, with distribution in mind + auto count = 0; + for (auto& value : mValues) { + auto distributionFactor = l::math::pow(count / static_cast(n), distribution); + meanSquareSum += l::math::pow(value - mean, exp); + count++; + } + meanSquareSum *= nFactor; + if (meanSumFactor > 0.0f) { + meanSquareSum /= meanSumFactor; + } + } + + *outOutput++ = meanSquareSum; + } + + mReadSamples += numSamples; + if (mReadSamples == numCacheSamples) { + mReadSamples = 0; + } + } + } From 2a46963a169dbe61b98d48ea67d16cc2f1d6dc48 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 28 Oct 2025 15:23:24 +0100 Subject: [PATCH 107/179] Fix some issues. --- .../operations/NodeGraphOpMathNumerical.cpp | 24 ++++++++++--------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 7023d52a..b2be330b 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -437,7 +437,7 @@ namespace l::nodegraph { /*********************************************************************/ void MathNumericalMeanExpRegression::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto inInput = &inputs.at(0).Get(numSamples); - auto n = l::math::max2(inputs.at(1).Get(), 1.0f); + auto n = static_cast(l::math::max2(inputs.at(1).Get(), 1.0f) + 0.00001f); auto exp = inputs.at(2).Get(); auto distribution = inputs.at(3).Get(); @@ -447,7 +447,7 @@ namespace l::nodegraph { mValues.clear(); } - auto nFactor = 1.0f / n; + auto nFactor = 1.0f / static_cast(n); for (int32_t i = 0; i < numSamples; i++) { float in = *inInput++; @@ -456,40 +456,42 @@ namespace l::nodegraph { mValues.erase(mValues.begin()); } else { - auto numToAdd = n - mValues.size() - 1; - for (int32_t i = 0; i < numToAdd; i++) { + auto numToAdd = static_cast(n - mValues.size() - 1); + for (int32_t j = 0; j < numToAdd; j++) { mValues.push_back(in); } } mValues.push_back(in); auto mean = 0.0f; - auto meanSumFactor = 0.0f; { // calculate the mean value with the distribution in mind auto count = 0; + auto sumFactor = 0.0f; for (auto& value : mValues) { auto distributionFactor = l::math::pow(count / static_cast(n), distribution); mean += value * distributionFactor; - meanSumFactor += distributionFactor; + sumFactor += distributionFactor; count++; } mean *= nFactor; - if (meanSumFactor > 0.0f) { - mean /= meanSumFactor; + if (sumFactor > 0.0f) { + mean /= sumFactor; } } auto meanSquareSum = 0.0f; { // calculate the mean regression with the sum of the exponential distance to the mean, with distribution in mind auto count = 0; + auto sumFactor = 0.0f; for (auto& value : mValues) { auto distributionFactor = l::math::pow(count / static_cast(n), distribution); - meanSquareSum += l::math::pow(value - mean, exp); + meanSquareSum += l::math::pow(value - mean, exp) * distributionFactor; + sumFactor += distributionFactor; count++; } meanSquareSum *= nFactor; - if (meanSumFactor > 0.0f) { - meanSquareSum /= meanSumFactor; + if (sumFactor > 0.0f) { + meanSquareSum /= sumFactor; } } From 8af18b10505602d9d5b07c3038f972ef59cf3f09 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 28 Oct 2025 17:01:03 +0100 Subject: [PATCH 108/179] Fix mean regression node. --- .../nodegraph/operations/NodeGraphOpMathNumerical.h | 3 ++- .../common/operations/NodeGraphOpMathNumerical.cpp | 12 +++++------- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 3ca94c92..5f140b86 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -279,7 +279,8 @@ namespace l::nodegraph { AddInput("Exp", 2.0f, 1, 0.0f, 10.0f); AddInput("Distribution", 2.0f, 1, 0.0f, 10.0f); - AddOutput2("Out"); + AddOutput2("Mean"); + AddOutput2("Mean Exp"); } virtual ~MathNumericalMeanExpRegression() = default; diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index b2be330b..977aad39 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -441,14 +441,13 @@ namespace l::nodegraph { auto exp = inputs.at(2).Get(); auto distribution = inputs.at(3).Get(); - auto outOutput = &outputs.at(0).Get(numSamples); + auto meanOutput = &outputs.at(0).Get(numSamples); + auto meanExpOutput = &outputs.at(1).Get(numSamples); if (mReadSamples == 0) { mValues.clear(); } - auto nFactor = 1.0f / static_cast(n); - for (int32_t i = 0; i < numSamples; i++) { float in = *inInput++; @@ -473,7 +472,6 @@ namespace l::nodegraph { sumFactor += distributionFactor; count++; } - mean *= nFactor; if (sumFactor > 0.0f) { mean /= sumFactor; } @@ -485,17 +483,17 @@ namespace l::nodegraph { auto sumFactor = 0.0f; for (auto& value : mValues) { auto distributionFactor = l::math::pow(count / static_cast(n), distribution); - meanSquareSum += l::math::pow(value - mean, exp) * distributionFactor; + meanSquareSum += l::math::pow(l::math::abs(value - mean), exp) * distributionFactor; sumFactor += distributionFactor; count++; } - meanSquareSum *= nFactor; if (sumFactor > 0.0f) { meanSquareSum /= sumFactor; } } - *outOutput++ = meanSquareSum; + *meanOutput++ = mean; + *meanExpOutput++ = meanSquareSum; } mReadSamples += numSamples; From b88a634db8a1c5db1c3bfc8772f22868a8f25430 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 31 Oct 2025 13:40:19 +0100 Subject: [PATCH 109/179] Change default bounds. --- .../include/nodegraph/operations/NodeGraphOpMathNumerical.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 5f140b86..7727ac79 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -124,8 +124,8 @@ namespace l::nodegraph { NodeGraphOp(node, "Level Trigger") { AddInput2("In"); - AddInput2("Max"); - AddInput2("Min"); + AddInput("Max", 1.0f); + AddInput("Min", -1.0f); AddInput("Num levels", 1.0f, 1, 1.0f, 100.0f, true, true); AddInput("Max", 1.0f, 1, 0.0f, 3.0f, true, true); AddInput("Min", 0.0f, 1, -3.0f, 1.0f, true, true); From 965abaa345c8aa46f4ef73b08af0a1ef410ebc71 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 31 Oct 2025 14:51:15 +0100 Subject: [PATCH 110/179] UI: clarified what container is currently operated on in linkio visitor and fixed the disconnect bug. --- .../rendering/source/common/ui/UIVisitors.cpp | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/packages/rendering/source/common/ui/UIVisitors.cpp b/packages/rendering/source/common/ui/UIVisitors.cpp index 711deba9..d568d16e 100644 --- a/packages/rendering/source/common/ui/UIVisitors.cpp +++ b/packages/rendering/source/common/ui/UIVisitors.cpp @@ -1,5 +1,4 @@ #include "rendering/ui/UIVisitors.h" -#include "hid/KeyboardPiano.h" namespace l::ui { @@ -525,11 +524,11 @@ namespace l::ui { // * input container co-parent -> link container // But a link container is still owned by only one container, the output container - { + if (container.HasConfigFlag(UIContainer_OutputFlag)) { // output node checks auto& outputContainer = container; // Create a link connection and attach it at a source node - if (outputContainer.HasConfigFlag(UIContainer_OutputFlag) && !mDragging && input.mStarted && mLinkContainer.Get() == nullptr) { + if (!mDragging && input.mStarted && mLinkContainer.Get() == nullptr) { ImVec2 pCenter = outputContainer.GetPosition(); ImVec2 size = outputContainer.GetSize(); auto& layoutArea = outputContainer.GetLayoutArea(); @@ -544,12 +543,11 @@ namespace l::ui { } } } - - { + else if (container.HasConfigFlag(UIContainer_LinkFlag)) { auto& linkContainer = container; // Detach a link connection from a destination node with an existing link connection - if (linkContainer.HasConfigFlag(UIContainer_LinkFlag) && !mDragging && input.mStarted && mLinkContainer.Get() == nullptr && linkContainer.GetCoParent() != nullptr) { + if (!mDragging && input.mStarted && mLinkContainer.Get() == nullptr && linkContainer.GetCoParent() != nullptr) { ImVec2 pCenter = linkContainer.GetCoParent()->GetPosition(); ImVec2 size = linkContainer.GetCoParent()->GetSize(); ImVec2 pT = linkContainer.GetCoParent()->GetLayoutArea().Transform(pCenter); @@ -565,7 +563,7 @@ namespace l::ui { } // Drag the link end - if (mDragging && mLinkContainer.Get() != nullptr && linkContainer.HasConfigFlag(UIContainer_LinkFlag) && mLinkContainer.Get() == &linkContainer) { + if (mDragging && mLinkContainer.Get() != nullptr && mLinkContainer.Get() == &linkContainer) { // On the newly created link container, drag the end point along the mouse movement auto& layoutArea = mLinkContainer->GetLayoutArea(); @@ -573,35 +571,37 @@ namespace l::ui { mLinkContainer->Move(move); } } - - { + else if (container.HasConfigFlag(UIContainer_InputFlag)) { auto& inputContainer = container; // Check containers with input flags, i.e. a node input channel area - if (mDragging && mLinkContainer.Get() != nullptr && inputContainer.HasConfigFlag(UIContainer_InputFlag)) { + if (mDragging && mLinkContainer.Get() != nullptr) { ImVec2 pCenter = inputContainer.GetPosition(); ImVec2 size = inputContainer.GetSize(); auto& layoutArea = inputContainer.GetLayoutArea(); ImVec2 pT = layoutArea.Transform(pCenter); - // if there is overlap we connect it + // we're dragging, so if there is overlap we connect it if (OverlapCircle(input.mCurPos, pT, 2.0f * size.x * layoutArea.mScale)) { - if (mLinkHandler(inputContainer.GetNodeId(), mLinkContainer->GetParent()->GetNodeId(), inputContainer.GetChannelId(), mLinkContainer->GetParent()->GetChannelId(), true)) { + if (mLinkContainer->GetCoParent() == nullptr && mLinkHandler(inputContainer.GetNodeId(), mLinkContainer->GetParent()->GetNodeId(), inputContainer.GetChannelId(), mLinkContainer->GetParent()->GetChannelId(), true)) { mLinkContainer->SetNotification(UIContainer_LinkFlag); mLinkContainer->SetCoParent(&inputContainer); inputContainer.SetCoParent(mLinkContainer.Get()); + //LLOG(LogInfo) << "Connected to " << inputContainer.GetChannelId(); } else { + //LLOG(LogInfo) << "Already connected"; // This link is already connected (or there is another link connected already) } } - // If this link if connected to this input node channel area, we detach it because the overlap failed (we moved it away) + // We're dragging, so if the overlap fail and this link is connected, we detach it (we moved it away) else if (mLinkContainer->GetCoParent() == &inputContainer) { mLinkHandler(inputContainer.GetNodeId(), mLinkContainer->GetParent()->GetNodeId(), inputContainer.GetChannelId(), mLinkContainer->GetParent()->GetChannelId(), false); mLinkContainer->ClearNotification(UIContainer_LinkFlag); mLinkContainer->SetCoParent(nullptr); inputContainer.SetCoParent(nullptr); + //LLOG(LogInfo) << "Disconnected from " << inputContainer.GetChannelId(); } if (input.mStopped) { From 2c7e9785bcf1d28e1e33147a0fd60d35510af0a0 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 1 Nov 2025 02:12:19 +0100 Subject: [PATCH 111/179] Fix warning. --- .../source/common/operations/NodeGraphOpMathNumerical.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 977aad39..16e5184c 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -437,7 +437,7 @@ namespace l::nodegraph { /*********************************************************************/ void MathNumericalMeanExpRegression::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto inInput = &inputs.at(0).Get(numSamples); - auto n = static_cast(l::math::max2(inputs.at(1).Get(), 1.0f) + 0.00001f); + auto n = static_cast(l::math::max2(inputs.at(1).Get(), 1.0f) + 0.00001f); auto exp = inputs.at(2).Get(); auto distribution = inputs.at(3).Get(); From 2dfaacee7f1b3092e49588cc3b426117eca66587 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 2 Nov 2025 17:53:52 +0100 Subject: [PATCH 112/179] NG: Add some error handling and logging to schema parsing. --- .../source/common/NodeGraphSchema.cpp | 12 ++++++------ .../source/common/core/NodeGraphGroup.cpp | 18 +++++++++--------- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index cf4632ea..da0b2a93 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -28,7 +28,7 @@ namespace l::nodegraph { bool NodeGraphSchema::NodeGraphNewNode(int32_t typeId, int32_t nodeId) { auto id = NewNode(typeId, nodeId); if (id != nodeId) { - LLOG(LogError) << "Failed to create node"; + LLOG(LogError) << "Failed to create node " << nodeId << " with type " << typeId << " in schema " << mFullPath; return false; } return true; @@ -38,7 +38,7 @@ namespace l::nodegraph { auto srcNode = GetNode(srcId); auto dstNode = GetNode(dstId); if (srcNode && dstNode && !dstNode->SetInput(dstChannel, *srcNode, srcChannel)) { - LLOG(LogError) << "Failed to wire nodes"; + LLOG(LogError) << "Failed to wire " << srcId << ":" << srcChannel << " to " << dstId << ":" << dstChannel << " in schema " << mFullPath; return false; } return true; @@ -87,12 +87,12 @@ namespace l::nodegraph { bool NodeGraphSchema::Save(std::filesystem::path file, bool cloneOnly) { if (file.empty()) { - LLOG(LogError) << "Failed to save schema: there is no file name or path"; + LLOG(LogError) << "Failed to save schema: there is no file name or path. In schema " << mFullPath; return false; } if (!file.has_filename()) { - LLOG(LogError) << "Failed to save schema: there is no file name"; + LLOG(LogError) << "Failed to save schema: there is no file name. In schema " << mFullPath; return false; } @@ -130,11 +130,11 @@ namespace l::nodegraph { } if (mVersionMajor < kVersionMajor) { - LLOG(LogWarning) << "Schema major version mismatch. Performing automatic upgrade but schema should be saved."; + LLOG(LogWarning) << "Schema major version mismatch. Performing automatic upgrade but schema should be saved. In schema " << mFullPath; // Perform upgrade } else if (mVersionMinor < kVersionMinor) { - LLOG(LogWarning) << "Schema minor version is of old version. Schema should still work but should be resaved when suitable."; + LLOG(LogWarning) << "Schema minor version is of old version. Schema should still work but should be resaved when suitable. In schema " << mFullPath; } if (nodeGraphSchema.has_key("Name")) { diff --git a/packages/nodegraph/source/common/core/NodeGraphGroup.cpp b/packages/nodegraph/source/common/core/NodeGraphGroup.cpp index a9a017ec..85a77500 100644 --- a/packages/nodegraph/source/common/core/NodeGraphGroup.cpp +++ b/packages/nodegraph/source/common/core/NodeGraphGroup.cpp @@ -62,15 +62,15 @@ namespace l::nodegraph { //auto name = e.get("Name").as_string(); //auto typeName = e.get("TypeName").as_string(); - mNodeFactory->NodeGraphNewNode(typeId, nodeId); - - if (e.has_key("x") && e.has_key("y")) { - GetNode(nodeId)->GetUIData().x = e.get("x").as_float(); - GetNode(nodeId)->GetUIData().y = e.get("y").as_float(); - } - if (e.has_key("w") && e.has_key("w")) { - GetNode(nodeId)->GetUIData().w = e.get("w").as_float(); - GetNode(nodeId)->GetUIData().h = e.get("h").as_float(); + if (mNodeFactory->NodeGraphNewNode(typeId, nodeId)) { + if (e.has_key("x") && e.has_key("y")) { + GetNode(nodeId)->GetUIData().x = e.get("x").as_float(); + GetNode(nodeId)->GetUIData().y = e.get("y").as_float(); + } + if (e.has_key("w") && e.has_key("w")) { + GetNode(nodeId)->GetUIData().w = e.get("w").as_float(); + GetNode(nodeId)->GetUIData().h = e.get("h").as_float(); + } } } } From 1af4fe509d51e81d68b4cee3d106a5e68de59a16 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 2 Nov 2025 18:12:01 +0100 Subject: [PATCH 113/179] NG: Better log info on node types, ids and channels. --- packages/nodegraph/source/common/NodeGraphSchema.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index da0b2a93..20d8d7a0 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -38,7 +38,9 @@ namespace l::nodegraph { auto srcNode = GetNode(srcId); auto dstNode = GetNode(dstId); if (srcNode && dstNode && !dstNode->SetInput(dstChannel, *srcNode, srcChannel)) { - LLOG(LogError) << "Failed to wire " << srcId << ":" << srcChannel << " to " << dstId << ":" << dstChannel << " in schema " << mFullPath; + auto srctype = srcNode->GetTypeId(); + auto dsttype = dstNode->GetTypeId(); + LLOG(LogError) << "Failed to wire [type,id,channel] [" << srctype << ":" << srcId << ":" << static_cast(srcChannel) << "] to [" << dsttype << ":" << dstId << ":" << static_cast(dstChannel) << "] in schema " << mFullPath; return false; } return true; From 3aa82a137be51ae47c383307933ad39cad1257cd Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 3 Nov 2025 13:21:28 +0100 Subject: [PATCH 114/179] NG: Replace shift+ctrl for ctrl+alt. --- packages/rendering/source/common/ui/UINodeEditor.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rendering/source/common/ui/UINodeEditor.cpp b/packages/rendering/source/common/ui/UINodeEditor.cpp index db9b451a..6d9f276d 100644 --- a/packages/rendering/source/common/ui/UINodeEditor.cpp +++ b/packages/rendering/source/common/ui/UINodeEditor.cpp @@ -218,7 +218,7 @@ namespace l::ui { nodeValue = &node->GetOutput(channelId, 1); } if (nodeValue != nullptr) { - if (!ImGui::IsKeyDown(ImGuiKey::ImGuiKey_LeftShift)) { + if (!ImGui::IsKeyDown(ImGuiKey::ImGuiKey_LeftAlt)) { if (!ImGui::IsKeyDown(ImGuiKey::ImGuiKey_LeftCtrl)) { *nodeValue -= dy / 100.0f; } From d76b4573939f3d965fee25e57ac10fc8564af3c8 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 7 Nov 2025 17:54:14 +0100 Subject: [PATCH 115/179] nn: Add so install for torch. --- packages/nn/CMakeLists.txt | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/packages/nn/CMakeLists.txt b/packages/nn/CMakeLists.txt index 984e7f6d..48e898cf 100644 --- a/packages/nn/CMakeLists.txt +++ b/packages/nn/CMakeLists.txt @@ -26,7 +26,14 @@ set_target_properties(nn PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED YES) set_target_properties(nn_test PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED YES) if(TARGET libtorch) - bs_copy_shared_libs_dir(nn_test "${LDEPS_LIBTORCH_LIB_DIR}") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/c10") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch_cpu") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch_cuda") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/fbgemm") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/libiomp5md") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/cupti64_2025.1.1") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/asmjit") endif() if(MSVC) From cb235dff6359093b0ab67a8893b8b0bb142467e6 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 8 Nov 2025 18:53:54 +0100 Subject: [PATCH 116/179] Remove an assert. --- packages/tools/source/common/utils/experimental/String.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tools/source/common/utils/experimental/String.cpp b/packages/tools/source/common/utils/experimental/String.cpp index d2a28a19..8b6dcce2 100644 --- a/packages/tools/source/common/utils/experimental/String.cpp +++ b/packages/tools/source/common/utils/experimental/String.cpp @@ -34,7 +34,7 @@ void string::Append(SString& dst, const char src) *(dst.str + dst.cur_len++) = src; EndString(dst); - ASSERT(dst.cur_len < dst.max_len) << "SString has a illegal size (size must be less " << std::to_string(dst.max_len) << ", but is " << std::to_string(dst.cur_len); + //ASSERT(dst.cur_len < dst.max_len) << "SString has a illegal size (size must be less " << std::to_string(dst.max_len) << ", but is " << std::to_string(dst.cur_len); } void string::Append(SString& dst, const char* src) From c846c4f93d54d65d7f068a5b97f5cae6149dbc09 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 8 Nov 2025 20:42:30 +0100 Subject: [PATCH 117/179] Remove more asserts. --- packages/logging/source/common/String.cpp | 28 +++++++++---------- .../math/source/common/MathFixedPoint.cpp | 4 +-- packages/memory/include/memory/Containers.h | 2 +- .../network/source/common/NetworkManager.cpp | 2 +- .../source/common/core/NodeGraphBase.cpp | 4 +-- .../source/common/core/NodeGraphInput.cpp | 2 +- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/packages/logging/source/common/String.cpp b/packages/logging/source/common/String.cpp index 7cd414a7..5fac60ec 100644 --- a/packages/logging/source/common/String.cpp +++ b/packages/logging/source/common/String.cpp @@ -141,7 +141,7 @@ namespace l::string { timeinfo->tm_year += 1900; timeinfo->tm_mon += 1; } - ASSERT(res == 0); + //ASSERT(res == 0); } int32_t get_unix_epoch() { @@ -174,7 +174,7 @@ namespace l::string { int ret = 0; if (date.size() > 10) { - ASSERT(date.size() == 19); + //ASSERT(date.size() == 19); #ifdef WIN32 ret = sscanf_s(date.data(), "%4d-%2d-%2d %2d:%2d:%2d", &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec); @@ -182,10 +182,10 @@ namespace l::string { ret = sscanf(date.data(), "%4d-%2d-%2d %2d:%2d:%2d", &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec); #endif - ASSERT(ret <= 6); + //ASSERT(ret <= 6); } else { - ASSERT(date.size() == 10); + //ASSERT(date.size() == 10); #ifdef WIN32 ret = sscanf_s(date.data(), "%4d-%2d-%2d", &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday); @@ -196,7 +196,7 @@ namespace l::string { timeinfo.tm_hour = 0; timeinfo.tm_min = 0; timeinfo.tm_sec = 0; - ASSERT(ret <= 3); + //ASSERT(ret <= 3); } // use _mkgmtime for gmt/utc time, use it when local time zone is unknown, for example in storage @@ -211,7 +211,7 @@ namespace l::string { int ret = 0; int microsec; - ASSERT(date.size() == 28); + //ASSERT(date.size() == 28); #ifdef WIN32 ret = sscanf_s(date.data(), "%4d-%2d-%2dT%2d:%2d:%2d.%7dZ", &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec, µsec); @@ -220,7 +220,7 @@ namespace l::string { &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec, µsec); #endif - ASSERT(ret <= 7); + //ASSERT(ret <= 7); // use _mkgmtime for gmt/utc time, use it when local time zone is unknown, for example in storage // use mktime for local time zone presentation @@ -258,7 +258,7 @@ namespace l::string { &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec); #endif - ASSERT(ret <= 6); + //ASSERT(ret <= 6); // use _mkgmtime for gmt/utc time, use it when local time zone is unknown, for example in storage // use mktime for local time zone presentation @@ -269,7 +269,7 @@ namespace l::string { int32_t to_unix_time_local2(std::string_view dateAndTime) { struct tm timeinfo = {}; int microsec; - ASSERT(dateAndTime.size() == 28); + //ASSERT(dateAndTime.size() == 28); #ifdef WIN32 int ret = sscanf_s(dateAndTime.data(), "%4d-%2d-%2dT%2d:%2d:%2d.%7dZ", &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec, µsec); @@ -278,7 +278,7 @@ namespace l::string { &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec, µsec); #endif - ASSERT(ret <= 7); + //ASSERT(ret <= 7); // use _mkgmtime for gmt/utc time, use it when local time zone is unknown, for example in storage // use mktime for local time zone presentation @@ -517,7 +517,7 @@ namespace l::string { std::locale loc; auto size = str.length(); - EXPECT(size > 0 && size < buffer_size) << "Failed to narrow string of size " << size << " characters"; + //EXPECT(size > 0 && size < buffer_size) << "Failed to narrow string of size " << size << " characters"; auto str_ptr = str.data(); @@ -532,7 +532,7 @@ namespace l::string { std::locale loc(""); auto size = str.length(); - EXPECT(size > 0 && size < buffer_size) << "Failed to widen string of size " << size << " characters"; + //EXPECT(size > 0 && size < buffer_size) << "Failed to widen string of size " << size << " characters"; auto str_ptr = str.data(); @@ -649,7 +649,7 @@ namespace l::string { out = 10 + (c - 97); } else { - ASSERT(false); + //ASSERT(false); out = 0; } return mostSignificant ? out << 4 : out; @@ -687,7 +687,7 @@ namespace l::string { out = 10 + (c - 97); } else { - ASSERT(false); + //ASSERT(false); out = 0; } return mostSignificant ? out << 4 : out; diff --git a/packages/math/source/common/MathFixedPoint.cpp b/packages/math/source/common/MathFixedPoint.cpp index 873e9d3e..752565ef 100644 --- a/packages/math/source/common/MathFixedPoint.cpp +++ b/packages/math/source/common/MathFixedPoint.cpp @@ -13,13 +13,13 @@ namespace l::math::fp { void FixedPoint::rescale(int64_t newScale) { if (newScale > scale_) { // scale up, no loss in precision int64_t diff = newScale / scale_; - ASSERT(l::math::abs(value_ * diff) < 100000000000000000); + //ASSERT(l::math::abs(value_ * diff) < 100000000000000000); value_ *= diff; scale_ *= diff; } else if (newScale < scale_) { int64_t diff = scale_ / newScale; - ASSERT(diff >= 10); + //ASSERT(diff >= 10); scale_ /= diff; diff /= 10; value_ /= diff; diff --git a/packages/memory/include/memory/Containers.h b/packages/memory/include/memory/Containers.h index 9c16cd3a..f5f09180 100644 --- a/packages/memory/include/memory/Containers.h +++ b/packages/memory/include/memory/Containers.h @@ -17,7 +17,7 @@ namespace l::container { template std::vector vector_extract(std::vector& v, size_t i, size_t count) { - ASSERT(i < v.size() && count <= v.size()); + //ASSERT(i < v.size() && count <= v.size()); std::vector dst; dst.insert(dst.end(), std::make_move_iterator(v.begin() + i), std::make_move_iterator(v.begin() + i + count)); v.erase(v.begin() + i, v.begin() + i + count); diff --git a/packages/network/source/common/NetworkManager.cpp b/packages/network/source/common/NetworkManager.cpp index c81988c9..bd647669 100644 --- a/packages/network/source/common/NetworkManager.cpp +++ b/packages/network/source/common/NetworkManager.cpp @@ -45,7 +45,7 @@ namespace l::network { } } } - ASSERT(foundHandle); + //ASSERT(foundHandle); } else if (m) { LLOG(LogWarning) << "Not done"; diff --git a/packages/nodegraph/source/common/core/NodeGraphBase.cpp b/packages/nodegraph/source/common/core/NodeGraphBase.cpp index a3ae9dea..5f64a496 100644 --- a/packages/nodegraph/source/common/core/NodeGraphBase.cpp +++ b/packages/nodegraph/source/common/core/NodeGraphBase.cpp @@ -184,7 +184,7 @@ namespace l::nodegraph { } bool NodeGraphBase::SetInput(int8_t inputChannel, float* floatPtr) { - ASSERT(inputChannel >= 0 && static_cast(inputChannel) < mInputs.size()); + //ASSERT(inputChannel >= 0 && static_cast(inputChannel) < mInputs.size()); if (!IsValidInOutNum(inputChannel, mInputs.size())) { return false; } @@ -213,7 +213,7 @@ namespace l::nodegraph { } bool NodeGraphBase::SetInputBound(int8_t inputChannel, InputBound bound, float boundMin, float boundMax) { - ASSERT(inputChannel >= 0 && static_cast(inputChannel) < mInputs.size()); + //ASSERT(inputChannel >= 0 && static_cast(inputChannel) < mInputs.size()); if (!IsValidInOutNum(inputChannel, mInputs.size())) { return false; } diff --git a/packages/nodegraph/source/common/core/NodeGraphInput.cpp b/packages/nodegraph/source/common/core/NodeGraphInput.cpp index d7bea70f..595b9622 100644 --- a/packages/nodegraph/source/common/core/NodeGraphInput.cpp +++ b/packages/nodegraph/source/common/core/NodeGraphInput.cpp @@ -90,7 +90,7 @@ namespace l::nodegraph { void NodeGraphInput::MinimizeBuffer(int32_t size) { if (mInputType == InputType::INPUT_NODE) { if (mInput.mInputNode != nullptr) { - ASSERT(mInput.mInputNode->GetOutputSize(mInputFromOutputChannel) == size); + //ASSERT(mInput.mInputNode->GetOutputSize(mInputFromOutputChannel) == size); //mInput.mInputNode->GetOutputOf(mInputFromOutputChannel).MinimizeBuffer(size); } } From 5109657543aaa115bb352871dc02a1be74ac819d Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 9 Nov 2025 02:03:33 +0100 Subject: [PATCH 118/179] Readd some asserts. Extract a math helper infinity-to-positive-unit mapping. --- packages/logging/source/common/String.cpp | 12 ++++++------ packages/math/include/math/MathFunc.h | 6 ++++++ 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/packages/logging/source/common/String.cpp b/packages/logging/source/common/String.cpp index 5fac60ec..29c113f6 100644 --- a/packages/logging/source/common/String.cpp +++ b/packages/logging/source/common/String.cpp @@ -141,7 +141,7 @@ namespace l::string { timeinfo->tm_year += 1900; timeinfo->tm_mon += 1; } - //ASSERT(res == 0); + ASSERT(res == 0); } int32_t get_unix_epoch() { @@ -182,7 +182,7 @@ namespace l::string { ret = sscanf(date.data(), "%4d-%2d-%2d %2d:%2d:%2d", &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec); #endif - //ASSERT(ret <= 6); + ASSERT(ret <= 6); } else { //ASSERT(date.size() == 10); @@ -196,7 +196,7 @@ namespace l::string { timeinfo.tm_hour = 0; timeinfo.tm_min = 0; timeinfo.tm_sec = 0; - //ASSERT(ret <= 3); + ASSERT(ret <= 3); } // use _mkgmtime for gmt/utc time, use it when local time zone is unknown, for example in storage @@ -220,7 +220,7 @@ namespace l::string { &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec, µsec); #endif - //ASSERT(ret <= 7); + ASSERT(ret <= 7); // use _mkgmtime for gmt/utc time, use it when local time zone is unknown, for example in storage // use mktime for local time zone presentation @@ -258,7 +258,7 @@ namespace l::string { &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec); #endif - //ASSERT(ret <= 6); + ASSERT(ret <= 6); // use _mkgmtime for gmt/utc time, use it when local time zone is unknown, for example in storage // use mktime for local time zone presentation @@ -278,7 +278,7 @@ namespace l::string { &timeinfo.tm_year, &timeinfo.tm_mon, &timeinfo.tm_mday, &timeinfo.tm_hour, &timeinfo.tm_min, &timeinfo.tm_sec, µsec); #endif - //ASSERT(ret <= 7); + ASSERT(ret <= 7); // use _mkgmtime for gmt/utc time, use it when local time zone is unknown, for example in storage // use mktime for local time zone presentation diff --git a/packages/math/include/math/MathFunc.h b/packages/math/include/math/MathFunc.h index efe46bc0..e2bb18f8 100644 --- a/packages/math/include/math/MathFunc.h +++ b/packages/math/include/math/MathFunc.h @@ -418,4 +418,10 @@ namespace l::math::functions { return static_cast(x > static_cast(0.0) ? static_cast(1.0) : static_cast(-1.0)); } } + + template + float infUnit(T x, T cutoff) { + return 1.0 / (1.0 + math::pow(2.71828, - x * 5.0 / cutoff)); + } + } From f7afe6811314808de21f75c5614be5df8283a095 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 10 Nov 2025 09:47:48 +0100 Subject: [PATCH 119/179] Only use torch cuda lib. --- packages/nn/CMakeLists.txt | 8 +- packages/nn/include/nn/torch/TorchBase.h | 4 +- packages/nn/tests/common/TorchTest.cpp | 303 +++++++++++++++++++++++ 3 files changed, 311 insertions(+), 4 deletions(-) diff --git a/packages/nn/CMakeLists.txt b/packages/nn/CMakeLists.txt index 48e898cf..c8f065ba 100644 --- a/packages/nn/CMakeLists.txt +++ b/packages/nn/CMakeLists.txt @@ -26,10 +26,12 @@ set_target_properties(nn PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED YES) set_target_properties(nn_test PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED YES) if(TARGET libtorch) + target_compile_definitions(nn PUBLIC HAS_LIBTORCH=1) + target_compile_definitions(nn_test PUBLIC HAS_LIBTORCH=1) bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch") - bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/c10") - bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch_cpu") bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch_cuda") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/c10") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/c10_cuda") bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/fbgemm") bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/libiomp5md") bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/cupti64_2025.1.1") @@ -38,6 +40,8 @@ endif() if(MSVC) target_compile_options(nn PRIVATE /WX- /bigobj) + target_compile_options(nn_test PRIVATE /WX- /bigobj) else() target_compile_options(nn PRIVATE -Werror -Wno-unused-result -Wno-ignored-qualifiers -Wno-unused-parameter) + target_compile_options(nn_test PRIVATE -Werror -Wno-unused-result -Wno-ignored-qualifiers -Wno-unused-parameter) endif() diff --git a/packages/nn/include/nn/torch/TorchBase.h b/packages/nn/include/nn/torch/TorchBase.h index 0adb4162..48a91dc5 100644 --- a/packages/nn/include/nn/torch/TorchBase.h +++ b/packages/nn/include/nn/torch/TorchBase.h @@ -3,8 +3,8 @@ #include #include -#ifdef LDEPS_USE_LIBTORCH -#include +#ifdef HAS_LIBTORCH +#include #endif namespace l::nn::libtorch { diff --git a/packages/nn/tests/common/TorchTest.cpp b/packages/nn/tests/common/TorchTest.cpp index 844c79a3..a523cf02 100644 --- a/packages/nn/tests/common/TorchTest.cpp +++ b/packages/nn/tests/common/TorchTest.cpp @@ -1,11 +1,314 @@ #include "testing/Test.h" #include "logging/Log.h" +#ifdef HAS_LIBTORCH #include +#include +#include +#include +#include +#include +#include +#include + +using namespace torch::indexing; + +// === 1. Multi-Octave Sliding Window Trainer === +struct OctaveTrainer : torch::nn::Module { + struct Window { + std::deque X, y; + int size; + + Window(int s) : size(s) {} + + void add(torch::Tensor x, torch::Tensor target) { + X.push_back(x); + y.push_back(target); + if ((int)X.size() > size) { + X.pop_front(); + y.pop_front(); + } + } + }; + + std::vector windows; + torch::nn::Linear model{ nullptr }; + std::unique_ptr optimizer; + torch::Device device; + + OctaveTrainer(int input_dim) : device(torch::kCPU) { + // Check for CUDA availability + if (torch::cuda::is_available()) { + std::cout << "CUDA is available! Training on GPU." << std::endl; + device = torch::Device(torch::kCUDA); + } + else { + std::cout << "CUDA is not available. Training on CPU." << std::endl; + } + + // Initialize windows correctly + windows.emplace_back(30); + windows.emplace_back(90); + windows.emplace_back(365); + + // Create the model properly using register_module + model = register_module("linear", torch::nn::Linear(input_dim, 2)); // mean + logvar + + // Move model to device + model->to(device); + + // Initialize weights and biases after registration + torch::nn::init::normal_(model->weight, 0.0, 0.1); + torch::nn::init::constant_(model->bias, 0.0); + + optimizer = std::make_unique(torch::optim::Adam(model->parameters(), torch::optim::AdamOptions(1e-3))); + } + + void train_step(torch::Tensor x, torch::Tensor target) { + // Move tensors to device + x = x.to(device); + target = target.to(device); + + model->train(); + optimizer->zero_grad(); + auto out = model->forward(x); + auto mean = out.slice(1, 0, 1); + auto logvar = out.slice(1, 1, 2); + auto loss = ((target - mean).square() / logvar.exp() + logvar).mean(); + loss.backward(); + optimizer->step(); + + // Update all windows + for (auto& w : windows) { + w.add(x.detach(), target.detach()); + } + } + + torch::Tensor predict(torch::Tensor x) { + model->eval(); + torch::NoGradGuard no_grad; + x = x.to(device); + return model->forward(x); + } +}; + +// === 2. OctaveConformal (for path weighting) === +struct OctaveConformal { + std::vector> residuals; + std::vector weights = { 1.0, 0.7, 0.4 }; // 30d, 90d, 365d + torch::Device device; + + OctaveConformal() : device(torch::kCPU) { + if (torch::cuda::is_available()) { + device = torch::Device(torch::kCUDA); + } + } + + void update(torch::nn::Linear model, const std::vector& windows) { + residuals.clear(); + for (size_t i = 0; i < windows.size(); ++i) { + std::deque res; + auto& w = windows[i]; + for (size_t j = 0; j < w.X.size(); ++j) { + // Move tensor to device before forward pass + auto x = w.X[j].to(device); + auto out = model->forward(x); + double mean = out[0][0].item(); + double true_y = w.y[j].item(); + res.push_back(std::abs(true_y - mean)); + } + residuals.push_back(res); + } + } + + double p_value(double residual) { + double count = 0, total = 0; + for (size_t i = 0; i < residuals.size(); ++i) { + double w = weights[i]; + for (double r : residuals[i]) { + if (r <= residual) count += w; + total += w; + } + } + return (count + 1.0) / (total + 1.0); + } +}; + +// === 3. Monte Carlo Path Generator === +std::vector> monte_carlo_forecast( + torch::nn::Linear model, + torch::Tensor current_x, + int steps, + int paths, + OctaveConformal& conformal, + std::mt19937& rng, + const torch::Device& device +) { + std::vector> all_paths(paths, std::vector(steps)); + std::normal_distribution noise(0, 1); + + for (int p = 0; p < paths; ++p) { + torch::Tensor x = current_x.clone().to(device); + for (int t = 0; t < steps; ++t) { + model->eval(); + auto out = model->forward(x); + double mean = out[0][0].item(); + double logvar = out[0][1].item(); + double sigma = std::exp(0.5 * logvar); + double y = mean + sigma * noise(rng); + all_paths[p][t] = y; + + // Update input for next step (autoregressive) + auto new_val = torch::tensor({ {y} }, torch::TensorOptions().device(device)); + x = torch::cat({ x.narrow(1, 1, x.size(1) - 1), new_val }, 1); + } + } + return all_paths; +} + + +TEST(Torch, ChecForCuda) { + std::cout << "=== CUDA Diagnostics ===" << std::endl; + std::cout << "PyTorch version: " << TORCH_VERSION_MAJOR << "." + << TORCH_VERSION_MINOR << "." << TORCH_VERSION_PATCH << std::endl; + std::cout << "CUDA available: " << torch::cuda::is_available() << std::endl; + std::cout << "cuDNN available: " << torch::cuda::cudnn_is_available() << std::endl; + + if (torch::cuda::is_available()) { + std::cout << "CUDA devices: " << torch::cuda::device_count() << std::endl; + for (int i = 0; i < torch::cuda::device_count(); ++i) { + std::cout << "CUDA device " << i << std::endl; + } + } else { + std::cout << "CUDA is not available. Common causes:" << std::endl; + std::cout << "1. LibTorch was built without CUDA support" << std::endl; + std::cout << "2. CUDA runtime not installed or incompatible version" << std::endl; + std::cout << "3. GPU driver issues" << std::endl; + std::cout << "4. Missing environment variables" << std::endl; + } + std::cout << "========================" << std::endl; + + return 0; +} + TEST(Torch, Basic) { + try { + // Check CUDA availability + std::cout << "PyTorch version: " << TORCH_VERSION_MAJOR << "." + << TORCH_VERSION_MINOR << "." << TORCH_VERSION_PATCH << std::endl; + std::cout << "CUDA available: " << torch::cuda::is_available() << std::endl; + + if (torch::cuda::is_available()) { + std::cout << "CUDA devices: " << torch::cuda::device_count() << std::endl; + for (int i = 0; i < torch::cuda::device_count(); ++i) { + std::cout << "CUDA device " << i << std::endl; + } + } + + std::mt19937 rng(42); + std::normal_distribution noise(0, 1); + int input_dim = 5; // [lag1, lag2, bed, bath, trend] + int steps_ahead = 30; + int paths = 1000; + + OctaveTrainer trainer(input_dim); + OctaveConformal conformal; + + // Simulate time series + std::vector true_series; + torch::Tensor x = torch::zeros({ 1, input_dim }); + + // Set device for initial tensor + if (torch::cuda::is_available()) { + x = x.to(torch::kCUDA); + } + + for (int t = 0; t < 600; ++t) { + double trend = 200 + 50 * std::sin(t / 365.0 * M_PI); + double shock = (t == 300) ? -80 : (t == 500) ? +60 : 0; + double price = trend + shock + 15 * noise(rng); + true_series.push_back(price); + + torch::Tensor target = torch::tensor({ {price} }); + // Move target to the same device as model + if (torch::cuda::is_available()) { + target = target.to(torch::kCUDA); + } + trainer.train_step(x, target); + + if (t >= 365) { + conformal.update(trainer.model, trainer.windows); + if (t == 500) { + std::cout << "FORECASTING 30 STEPS AHEAD FROM t=" << t << "\n"; + auto future_paths = monte_carlo_forecast( + trainer.model, x, steps_ahead, paths, conformal, rng, + torch::cuda::is_available() ? torch::kCUDA : torch::kCPU + ); + + // Weigh paths with conformal p-value + std::vector weights(paths); + double sum_w = 0; + for (int p = 0; p < paths; ++p) { + double path_residual = 0; + for (int s = 0; s < std::min(5, steps_ahead); ++s) + path_residual += std::abs(future_paths[p][s] - future_paths[p][0]); + path_residual /= 5; + weights[p] = conformal.p_value(path_residual); + sum_w += weights[p]; + } + for (auto& w : weights) w /= sum_w; + + // Compute 90% weighted prediction band + std::vector> sorted(steps_ahead); + for (int s = 0; s < steps_ahead; ++s) { + std::vector> vals; + for (int p = 0; p < paths; ++p) + vals.emplace_back(future_paths[p][s], weights[p]); + std::sort(vals.begin(), vals.end()); + double cum = 0; + for (auto& [v, w] : vals) { + cum += w; + if (cum >= 0.05) { sorted[s].push_back(v); break; } + } + cum = 0; + for (auto it = vals.rbegin(); it != vals.rend(); ++it) { + cum += it->second; + if (cum >= 0.05) { sorted[s].push_back(it->first); break; } + } + } + + // Output + std::ofstream out("forecast.csv"); + out << "step,true,lower,upper,mean\n"; + for (int s = 0; s < steps_ahead; ++s) { + double mean = 0; + for (int p = 0; p < paths; ++p) mean += future_paths[p][s] * weights[p]; + double true_val = (t + s < true_series.size()) ? true_series[t + s] : NAN; + out << s << "," << true_val << "," << sorted[s][0] << "," << sorted[s][1] << "," << mean << "\n"; + std::cout << "t+" << std::setw(2) << s + << " | True: $" << std::fixed << std::setprecision(1) << true_val + << "k | Band: [$" << sorted[s][0] << "k, $" << sorted[s][1] << "k]\n"; + } + std::cout << "\nforecast.csv written.\n"; + break; + } + } + + // Shift input window + x = torch::cat({ x.narrow(1, 1, input_dim - 1), target }, 1); + } + } + catch (const std::exception& e) { + std::cerr << "Error: " << e.what() << std::endl; + return 1; + } + + return 0; + } +#endif From 5fabe2b405fd8eb3ac566a30efb287efb9979d17 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Wed, 12 Nov 2025 22:11:23 +0100 Subject: [PATCH 120/179] Fix libtorch wrapper. --- packages/nn/CMakeLists.txt | 19 +-- packages/nn/source/common/torch/TorchBase.cpp | 25 ++-- packages/nn/tests/common/Torch1Test.cpp | 31 +++++ packages/nn/tests/common/Torch2Test.cpp | 116 ++++++++++++++++++ packages/nn/tests/common/TorchTest.cpp | 14 ++- 5 files changed, 181 insertions(+), 24 deletions(-) create mode 100644 packages/nn/tests/common/Torch1Test.cpp create mode 100644 packages/nn/tests/common/Torch2Test.cpp diff --git a/packages/nn/CMakeLists.txt b/packages/nn/CMakeLists.txt index c8f065ba..a9ebf5e1 100644 --- a/packages/nn/CMakeLists.txt +++ b/packages/nn/CMakeLists.txt @@ -15,9 +15,9 @@ set(deps_external tiny_dnn_static ) -if(TARGET libtorch) +if(TARGET libtorch_wrapper) list(APPEND deps_external - libtorch + libtorch_wrapper ) endif() @@ -25,17 +25,20 @@ bs_generate_package(nn "tier1" "${deps}" "${deps_external}") set_target_properties(nn PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED YES) set_target_properties(nn_test PROPERTIES CXX_STANDARD 17 CXX_STANDARD_REQUIRED YES) -if(TARGET libtorch) +if(TARGET libtorch_wrapper) + message("libtorch: ${LDEPS_LIBTORCH_LIB_DIR}") + message("cuda: ${CUDA_TOOLKIT_ROOT_DIR}") + target_compile_definitions(nn PUBLIC HAS_LIBTORCH=1) target_compile_definitions(nn_test PUBLIC HAS_LIBTORCH=1) - bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch") - bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch_cuda") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/c10") bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/c10_cuda") - bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/fbgemm") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch_cpu") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch_cuda") bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/libiomp5md") - bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/cupti64_2025.1.1") - bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/asmjit") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/cupti64_2025.3.0") endif() if(MSVC) diff --git a/packages/nn/source/common/torch/TorchBase.cpp b/packages/nn/source/common/torch/TorchBase.cpp index cccb59ec..45c3161d 100644 --- a/packages/nn/source/common/torch/TorchBase.cpp +++ b/packages/nn/source/common/torch/TorchBase.cpp @@ -3,13 +3,10 @@ namespace l::nn::libtorch { #ifdef LDEPS_USE_LIBTORCH - struct TransformerNet : torch::nn::Module { - // Define transformer as in previous messages - torch::nn::Conv1d conv{ nullptr }; - torch::nn::Transformer transformer{ nullptr }; - torch::nn::Linear fc{ nullptr }; - TransformerNet(int window_size, int output_size) { - conv = register_module("conv", torch::nn::Conv1d(torch::nn::Conv1dOptions(1, 16, 5).stride(1).padding(2))); + struct TransformerNetImpl : public torch::nn::Module { + TransformerNetImpl(int window_size, int output_size) { + auto copt = torch::nn::Conv1dOptions(1, 16, 5).stride(1).padding(2); + conv = register_module("conv", torch::nn::Conv1d(copt)); transformer = register_module("transformer", torch::nn::Transformer(torch::nn::TransformerOptions(16, 8).d_model(16).nhead(8))); fc = register_module("fc", torch::nn::Linear(16 * window_size, output_size)); } @@ -20,19 +17,25 @@ namespace l::nn::libtorch { x = x.view({ x.size(0), -1 }); return fc->forward(x); } + + // Define transformer as in previous messages + torch::nn::Conv1d conv = nullptr; + torch::nn::Transformer transformer = nullptr; + torch::nn::Linear fc = nullptr; }; + TORCH_MODULE(TransformerNet); #endif void Transformer::process(const std::vector& window) { #ifdef LDEPS_USE_LIBTORCH - static TransformerNet model(window.size(), 10); // Predict 10 samples - model.eval(); + TransformerNet model(window.size(), 10); // Predict 10 samples + model->eval(); torch::NoGradGuard no_grad; auto input = torch::tensor(window).reshape({ 1, -1 }); - auto output = model.forward(input); + auto output = model->forward(input); std::vector result(output.data_ptr(), output.data_ptr() + 10); - //LLOG(LogInfo) << "result[0]: " << result.at(0); + std::cout << "result[0]: " << result.at(0); #else // Fallback: Simple moving average or skip std::cout << "Torch not available. Skipping transformer processing.\n"; diff --git a/packages/nn/tests/common/Torch1Test.cpp b/packages/nn/tests/common/Torch1Test.cpp new file mode 100644 index 00000000..061d0264 --- /dev/null +++ b/packages/nn/tests/common/Torch1Test.cpp @@ -0,0 +1,31 @@ +#include "testing/Test.h" +#include "logging/Log.h" + +#include + +#include +#include +#include +#include +#include + +TEST(Torch1, Basic) { + return 0; + l::nn::libtorch::Transformer tf; + std::vector input; + + std::random_device rdev; + + srand(45924296592); + float acc = 1.0f; + for (int32_t i = 0; i < 100; i++) { + input.push_back(acc); + acc *= 1.0f + 0.1f * (rand() / static_cast(RAND_MAX) - 0.5f); + } + std::vector output; + tf.process(input); + + return 0; +} + + diff --git a/packages/nn/tests/common/Torch2Test.cpp b/packages/nn/tests/common/Torch2Test.cpp new file mode 100644 index 00000000..283975f9 --- /dev/null +++ b/packages/nn/tests/common/Torch2Test.cpp @@ -0,0 +1,116 @@ +#include "testing/Test.h" +#include "logging/Log.h" + +#include + +TEST(Torch2, TorchTensorBasic) { + torch::Tensor tensor = torch::eye(3); + std::cout << tensor << std::endl; + return 0; +} + +struct Net1Impl : torch::nn::Module { + Net1Impl(int64_t N, int64_t M) { + linear = register_module("linear", torch::nn::Linear(N, M)); + another_bias = register_parameter("b", torch::randn(M)); + } + torch::Tensor forward(torch::Tensor input) { + return linear(input) + another_bias; + } + torch::nn::Linear linear = nullptr; + torch::Tensor another_bias; +}; +TORCH_MODULE(Net1); + +TEST(Torch2, TorchNetBasic) { + return 0; + Net1 net(4, 5); + + for (const auto& p : net->parameters()) { + std::cout << p << std::endl; + } + return 0; +} + + +// Define a new Module. +struct Net2Impl : torch::nn::Module { + Net2Impl() { + // Construct and register two Linear submodules. + fc1 = register_module("fc1", torch::nn::Linear(784, 64)); + fc2 = register_module("fc2", torch::nn::Linear(64, 32)); + fc3 = register_module("fc3", torch::nn::Linear(32, 10)); + //fc1->to(torch::kCUDA); + //fc2->to(torch::kCUDA); + //fc3->to(torch::kCUDA); + } + + TORCH_API torch::serialize::OutputArchive& operator<<( + torch::serialize::OutputArchive& archive) { + archive << fc1; + archive << fc2; + archive << fc3; + } + + /// Deserializes a `Module` from an `InputArchive`. + TORCH_API torch::serialize::InputArchive& operator>>( + torch::serialize::InputArchive& archive) { + archive >> fc3; + archive >> fc2; + archive >> fc1; + } + + // Implement the Net's algorithm. + torch::Tensor forward(torch::Tensor x) { + // Use one of many tensor manipulation functions. + x = torch::relu(fc1->forward(x.reshape({ x.size(0), 784 }))); + x = torch::dropout(x, /*p=*/0.5, /*train=*/is_training()); + x = torch::relu(fc2->forward(x)); + x = torch::log_softmax(fc3->forward(x), /*dim=*/1); + return x; + } + + // Use one of many "standard library" modules. + torch::nn::Linear fc1{ nullptr }, fc2{ nullptr }, fc3{ nullptr }; +}; +TORCH_MODULE(Net2); + +TEST(Torch2, TorchAdvancedExample) { + return 0; + // Create a new Net. + auto net = std::make_shared(); + + // Create a multi-threaded data loader for the MNIST dataset. + auto data_loader = torch::data::make_data_loader( + torch::data::datasets::MNIST("./data").map( + torch::data::transforms::Stack<>()), + /*batch_size=*/64); + + // Instantiate an SGD optimization algorithm to update our Net's parameters. + torch::optim::SGD optimizer(net->get()->parameters(), /*lr=*/0.01); + + for (size_t epoch = 1; epoch <= 10; ++epoch) { + size_t batch_index = 0; + // Iterate the data loader to yield batches from the dataset. + for (auto& batch : *data_loader) { + // Reset gradients. + optimizer.zero_grad(); + // Execute the model on the input data. + torch::Tensor prediction = net->get()->forward(batch.data); + // Compute a loss value to judge the prediction of our model. + torch::Tensor loss = torch::nll_loss(prediction, batch.target); + // Compute gradients of the loss w.r.t. the parameters of our model. + loss.backward(); + // Update the parameters based on the calculated gradients. + optimizer.step(); + // Output the loss and checkpoint every 100 batches. + if (++batch_index % 100 == 0) { + std::cout << "Epoch: " << epoch << " | Batch: " << batch_index + << " | Loss: " << loss.item() << std::endl; + // Serialize your model periodically as a checkpoint. + //torch::save(net, "net.pt"); + } + } + } + return 0; +} diff --git a/packages/nn/tests/common/TorchTest.cpp b/packages/nn/tests/common/TorchTest.cpp index a523cf02..69734d46 100644 --- a/packages/nn/tests/common/TorchTest.cpp +++ b/packages/nn/tests/common/TorchTest.cpp @@ -15,7 +15,11 @@ using namespace torch::indexing; // === 1. Multi-Octave Sliding Window Trainer === -struct OctaveTrainer : torch::nn::Module { +class OctaveTrainer : torch::nn::Module { +public: + OctaveTrainer() = default; + ~OctaveTrainer() = default; + struct Window { std::deque X, y; int size; @@ -33,7 +37,7 @@ struct OctaveTrainer : torch::nn::Module { }; std::vector windows; - torch::nn::Linear model{ nullptr }; + torch::nn::Linear model{nullptr}; std::unique_ptr optimizer; torch::Device device; @@ -53,7 +57,7 @@ struct OctaveTrainer : torch::nn::Module { windows.emplace_back(365); // Create the model properly using register_module - model = register_module("linear", torch::nn::Linear(input_dim, 2)); // mean + logvar + model = register_module("linear", torch::nn::Linear(input_dim, 2)); // Move model to device model->to(device); @@ -168,7 +172,7 @@ std::vector> monte_carlo_forecast( } -TEST(Torch, ChecForCuda) { +TEST(Torch, CheckForCuda) { std::cout << "=== CUDA Diagnostics ===" << std::endl; std::cout << "PyTorch version: " << TORCH_VERSION_MAJOR << "." << TORCH_VERSION_MINOR << "." << TORCH_VERSION_PATCH << std::endl; @@ -193,7 +197,7 @@ TEST(Torch, ChecForCuda) { } TEST(Torch, Basic) { - + return 0; try { // Check CUDA availability std::cout << "PyTorch version: " << TORCH_VERSION_MAJOR << "." From 99ba4408f92d58e2b2168cd7ba96c2547342f9b4 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 14 Nov 2025 01:54:13 +0100 Subject: [PATCH 121/179] NG: Add a proper standard deviation node. --- .../operations/NodeGraphOpMathNumerical.h | 27 ++++++++++ .../source/common/NodeGraphSchema.cpp | 6 ++- .../operations/NodeGraphOpMathNumerical.cpp | 51 +++++++++++++++++++ 3 files changed, 83 insertions(+), 1 deletion(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 7727ac79..aca8d142 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -290,4 +290,31 @@ namespace l::nodegraph { std::vector mValues; }; + + /*********************************************************************/ + class MathNumericalStdDev : public nodegraph::NodeGraphOp { + public: + MathNumericalStdDev(nodegraph::NodeGraphBase* node) : + NodeGraphOp(node, "Standard Deviation") + { + AddInput2("In"); + AddInput2("N"); + AddInput("Band", 2.0f, 1, 0.0f, 10.0f); + + AddOutput2("Ewma"); + AddOutput2("Stddev"); + AddOutput2("Upper"); + AddOutput2("Lower"); + AddOutput2("Z-score"); + } + + virtual ~MathNumericalStdDev() = default; + virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + protected: + int32_t mReadSamples = 0; + + float alpha = 0.0f; + float ema_prev = 0.0f; + float variance_ewma = 0.0; + }; } \ No newline at end of file diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 20d8d7a0..61e5bc9e 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -347,7 +347,10 @@ namespace l::nodegraph { case 151: node = mMainNodeGraph.NewNode(id, NodeType::Default); break; - + case 152: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; + // Trading data io case 200: node = mMainNodeGraph.NewNode(id, NodeType::ExternalInput, 0); @@ -679,6 +682,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Numerical", 149, "EMA", "Exponential moving average [ema1=(ema0*(n-1)+input)/n]"); RegisterNodeType("Math.Numerical", 150, "Change 2", "Temporal change 2. Computes the value: (v_now - v_prev) / abs(v_now)."); RegisterNodeType("Math.Numerical", 151, "Mean Regression", "Computes the convolution of the exponential distances and can be used as a square root of the variance for computing the mean regression or the trend/direction of the input values."); + RegisterNodeType("Math.Numerical", 152, "Standard Deviation", "Computes the standard deviation and variance."); } else if (typeGroup == "Trading.Data IO") { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 16e5184c..13de3694 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -502,4 +502,55 @@ namespace l::nodegraph { } } + /********************************************************************/ + + void MathNumericalStdDev::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + auto inInput = &inputs.at(0).Get(numSamples); + auto period = static_cast(l::math::max2(inputs.at(1).Get(), 1.0f) + 0.00001f); + auto sigmaBand = inputs.at(2).Get(1); + + auto ewmaOutput = &outputs.at(0).Get(numSamples); + auto stddevOutput = &outputs.at(1).Get(numSamples); + auto upperOutput = &outputs.at(2).Get(numSamples); + auto lowerOutput = &outputs.at(3).Get(numSamples); + auto zscoreOutput = &outputs.at(4).Get(numSamples); + + if (mReadSamples == 0) { + alpha = 1.0f / period; + ema_prev = 0.0f; + variance_ewma = 0.0f; + } + + for (int32_t i = 0; i < numSamples; i++) { + auto in = *inInput++; + + // Deviation from EMA (for population std dev of the error) + float ema_current = alpha * in + (1.0f - alpha) * ema_prev; + ema_prev = ema_current; + + double deviation = in - ema_current; + auto deviationSquared = deviation * deviation; + + // Use exponentially weighted moving variance (more responsive) + // We maintain an EWMA of squared deviations + variance_ewma = alpha * deviationSquared + (1.0f - alpha) * variance_ewma; + auto stddev = l::math::sqrt(variance_ewma); + + auto upper_band = ema_current + sigmaBand * stddev; // e.g., 2-sigma band + auto lower_band = ema_current - sigmaBand * stddev; + auto z_score = (stddev > 0.0f) ? deviation / stddev : 0.0f; + + *ewmaOutput++ = ema_current; + *stddevOutput++ = stddev; + *upperOutput++ = upper_band; + *lowerOutput++ = lower_band; + *zscoreOutput++ = z_score; + } + + mReadSamples += numSamples; + if (mReadSamples == numCacheSamples) { + mReadSamples = 0; + } + } + } From 2b9c4184610ef64ca9689f2348d8ef7d46315b8a Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 14 Nov 2025 02:01:57 +0100 Subject: [PATCH 122/179] Fix minor issues. --- .../include/nodegraph/operations/NodeGraphOpMathNumerical.h | 2 +- .../source/common/operations/NodeGraphOpMathNumerical.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index aca8d142..eff8c55f 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -298,7 +298,7 @@ namespace l::nodegraph { NodeGraphOp(node, "Standard Deviation") { AddInput2("In"); - AddInput2("N"); + AddInput("N", 0.0f, 1, 0.0f, 1000.0f); AddInput("Band", 2.0f, 1, 0.0f, 10.0f); AddOutput2("Ewma"); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 13de3694..0ca11b20 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -525,10 +525,10 @@ namespace l::nodegraph { auto in = *inInput++; // Deviation from EMA (for population std dev of the error) - float ema_current = alpha * in + (1.0f - alpha) * ema_prev; + auto ema_current = alpha * in + (1.0f - alpha) * ema_prev; ema_prev = ema_current; - double deviation = in - ema_current; + auto deviation = in - ema_current; auto deviationSquared = deviation * deviation; // Use exponentially weighted moving variance (more responsive) From f82fdb312a3ba5bb414fd68e9ec8fe5f9ee4497d Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 14 Nov 2025 23:45:04 +0100 Subject: [PATCH 123/179] Add char checks for numeric and letter. --- packages/logging/include/logging/String.h | 12 ++++++++++++ .../nodegraph/operations/NodeGraphOpMathNumerical.h | 2 +- .../common/operations/NodeGraphOpMathNumerical.cpp | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/packages/logging/include/logging/String.h b/packages/logging/include/logging/String.h index e12842a6..975305fd 100644 --- a/packages/logging/include/logging/String.h +++ b/packages/logging/include/logging/String.h @@ -238,6 +238,18 @@ namespace l::string { bool equal_partial(std::string_view a, std::string_view b, size_t a_offset = 0, size_t b_offset = 0); int32_t equal_anywhere(std::string_view a, std::string_view b); + bool is_numeric(char c) { + return c >= '0' && c <= '9'; + } + bool is_letter(char c, bool lowercase = true) { + if (lowercase) { + return c >= 'a' && c <= 'z'; + } + else { + return c >= 'A' && c <= 'Z'; + } + } + std::vector split(std::wstring_view text, std::wstring_view delim = L" \t\n", char escapeChar = '\"'); std::vector split(std::string_view text, std::string_view delim = " \t\n", char escapeChar = '\"'); diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index eff8c55f..9befe9fc 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -298,7 +298,7 @@ namespace l::nodegraph { NodeGraphOp(node, "Standard Deviation") { AddInput2("In"); - AddInput("N", 0.0f, 1, 0.0f, 1000.0f); + AddInput("N", 1.0f, 1, 1.0f, 1000.0f); AddInput("Band", 2.0f, 1, 0.0f, 10.0f); AddOutput2("Ewma"); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 0ca11b20..31bd3506 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -506,7 +506,7 @@ namespace l::nodegraph { void MathNumericalStdDev::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto inInput = &inputs.at(0).Get(numSamples); - auto period = static_cast(l::math::max2(inputs.at(1).Get(), 1.0f) + 0.00001f); + auto period = l::math::max2(inputs.at(1).Get(), 1.0f); auto sigmaBand = inputs.at(2).Get(1); auto ewmaOutput = &outputs.at(0).Get(numSamples); From d144ffc1b2ad45b23851046d0c439c2526671af3 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 15 Nov 2025 00:22:43 +0100 Subject: [PATCH 124/179] Add is numeric and is letter char functions. --- packages/logging/include/logging/String.h | 13 ++----------- packages/logging/source/common/String.cpp | 12 ++++++++++++ 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/packages/logging/include/logging/String.h b/packages/logging/include/logging/String.h index 975305fd..45bb7697 100644 --- a/packages/logging/include/logging/String.h +++ b/packages/logging/include/logging/String.h @@ -238,17 +238,8 @@ namespace l::string { bool equal_partial(std::string_view a, std::string_view b, size_t a_offset = 0, size_t b_offset = 0); int32_t equal_anywhere(std::string_view a, std::string_view b); - bool is_numeric(char c) { - return c >= '0' && c <= '9'; - } - bool is_letter(char c, bool lowercase = true) { - if (lowercase) { - return c >= 'a' && c <= 'z'; - } - else { - return c >= 'A' && c <= 'Z'; - } - } + bool is_numeric(char c); + bool is_letter(char c, bool lowercase = true); std::vector split(std::wstring_view text, std::wstring_view delim = L" \t\n", char escapeChar = '\"'); std::vector split(std::string_view text, std::string_view delim = " \t\n", char escapeChar = '\"'); diff --git a/packages/logging/source/common/String.cpp b/packages/logging/source/common/String.cpp index 29c113f6..6d13d5d6 100644 --- a/packages/logging/source/common/String.cpp +++ b/packages/logging/source/common/String.cpp @@ -444,6 +444,18 @@ namespace l::string { return -1; } + bool is_numeric(char c) { + return c >= '0' && c <= '9'; + } + bool is_letter(char c, bool lowercase = true) { + if (lowercase) { + return c >= 'a' && c <= 'z'; + } + else { + return c >= 'A' && c <= 'Z'; + } + } + std::vector split(std::wstring_view text, std::wstring_view delim, char escapeChar) { std::vector out; From e0f4de9d78754731b426255300a264d8bbcc6643 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 15 Nov 2025 02:32:43 +0100 Subject: [PATCH 125/179] Fix error. --- packages/logging/source/common/String.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/logging/source/common/String.cpp b/packages/logging/source/common/String.cpp index 6d13d5d6..54f572ce 100644 --- a/packages/logging/source/common/String.cpp +++ b/packages/logging/source/common/String.cpp @@ -447,7 +447,7 @@ namespace l::string { bool is_numeric(char c) { return c >= '0' && c <= '9'; } - bool is_letter(char c, bool lowercase = true) { + bool is_letter(char c, bool lowercase) { if (lowercase) { return c >= 'a' && c <= 'z'; } From 3fe71118cb7cbcaaaf566f70f2ba97199cdd7f1e Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 16 Nov 2025 19:33:31 +0100 Subject: [PATCH 126/179] NG: Add sma node, remove zero quantization input. --- .../operations/NodeGraphOpMathNumerical.h | 21 +++++++++- .../source/common/NodeGraphSchema.cpp | 4 ++ .../operations/NodeGraphOpMathNumerical.cpp | 40 +++++++++++++++---- 3 files changed, 56 insertions(+), 9 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 9befe9fc..840d2d8e 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -255,7 +255,6 @@ namespace l::nodegraph { { AddInput2("In"); AddInput("N", 14.0f, 1, 1.0f, 1000.0f); - AddInput("Zero", 0.0f, 1, 0.0f, 1.0f); AddOutput2("Out"); } @@ -268,6 +267,26 @@ namespace l::nodegraph { float mEmaAccum = 0.0f; }; + /*********************************************************************/ + class MathNumericalSMA : public nodegraph::NodeGraphOp { + public: + MathNumericalSMA(nodegraph::NodeGraphBase* node) : + NodeGraphOp(node, "SMA") + { + AddInput2("In"); + AddInput("N", 14.0f, 1, 1.0f, 1000.0f); + + AddOutput2("Out"); + } + + virtual ~MathNumericalSMA() = default; + virtual void Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + protected: + int32_t mReadSamples = 0; + + float mSum = 0.0f; + float std::vector mValues; + }; /*********************************************************************/ class MathNumericalMeanExpRegression : public nodegraph::NodeGraphOp { public: diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 61e5bc9e..58f023ce 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -350,6 +350,9 @@ namespace l::nodegraph { case 152: node = mMainNodeGraph.NewNode(id, NodeType::Default); break; + case 153: + node = mMainNodeGraph.NewNode(id, NodeType::Default); + break; // Trading data io case 200: @@ -683,6 +686,7 @@ namespace l::nodegraph { RegisterNodeType("Math.Numerical", 150, "Change 2", "Temporal change 2. Computes the value: (v_now - v_prev) / abs(v_now)."); RegisterNodeType("Math.Numerical", 151, "Mean Regression", "Computes the convolution of the exponential distances and can be used as a square root of the variance for computing the mean regression or the trend/direction of the input values."); RegisterNodeType("Math.Numerical", 152, "Standard Deviation", "Computes the standard deviation and variance."); + RegisterNodeType("Math.Numerical", 153, "SMA", "Simple moving average"); } else if (typeGroup == "Trading.Data IO") { RegisterNodeType("Trading.Data IO", 200, "OCHLV Data In"); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 31bd3506..9af17cdb 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -407,8 +407,6 @@ namespace l::nodegraph { void MathNumericalEMA::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto inInput = &inputs.at(0).Get(numSamples); auto n = l::math::max2(inputs.at(1).Get(), 1.0f); - auto zero = inputs.at(2).Get(); - zero *= zero * zero; auto outOutput = &outputs.at(0).Get(numSamples); @@ -419,12 +417,7 @@ namespace l::nodegraph { for (int32_t i = 0; i < numSamples; i++) { float in = *inInput++; mEmaAccum = (mEmaAccum * (n - 1.0f) + in) / n; - if (l::math::abs(mEmaAccum) < zero) { - *outOutput++ = 0.0f; - } - else { - *outOutput++ = mEmaAccum; - } + *outOutput++ = mEmaAccum; } mReadSamples += numSamples; @@ -433,7 +426,38 @@ namespace l::nodegraph { } } + /*********************************************************************/ + void MathNumericalSMA::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { + auto inInput = &inputs.at(0).Get(numSamples); + auto n = l::math::max2(inputs.at(1).Get(), 1.0f); + + auto outOutput = &outputs.at(0).Get(numSamples); + + if (mReadSamples == 0) { + mValues.resize(n + 1); + for (auto& v : mValues) { + v = *inInput; + } + mSum = *inInput * mValues.size();; + } + + auto factor = 1.0f / mValues.size(); + + for (int32_t i = 0; i < numSamples; i++) { + float in = *inInput++; + + mValues.push_back(in); + auto last = mValues.erase(mValues.begin()); + mSum += in - last; + auto mean = mSum * factor; + *outOutput++ = mean; + } + mReadSamples += numSamples; + if (mReadSamples == numCacheSamples) { + mReadSamples = 0; + } + } /*********************************************************************/ void MathNumericalMeanExpRegression::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto inInput = &inputs.at(0).Get(numSamples); From 37a53608c87afce60a71ca5338b62ae13bd8af5d Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 17 Nov 2025 11:51:39 +0100 Subject: [PATCH 127/179] NG: Switch to deque in sma. --- .../include/nodegraph/operations/NodeGraphOpMathNumerical.h | 3 ++- .../source/common/operations/NodeGraphOpMathNumerical.cpp | 5 +++-- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 840d2d8e..97115b28 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -285,7 +286,7 @@ namespace l::nodegraph { int32_t mReadSamples = 0; float mSum = 0.0f; - float std::vector mValues; + std::deque mValues; }; /*********************************************************************/ class MathNumericalMeanExpRegression : public nodegraph::NodeGraphOp { diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 9af17cdb..f1590913 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -447,8 +447,9 @@ namespace l::nodegraph { float in = *inInput++; mValues.push_back(in); - auto last = mValues.erase(mValues.begin()); - mSum += in - last; + auto oldestValue = mValues.front(); + mValues.pop_front(); + mSum += in - oldestValue; auto mean = mSum * factor; *outOutput++ = mean; } From 76e3d19d3a6d1df65e09394b0dd3009b1e5f4cff Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 17 Nov 2025 14:07:18 +0100 Subject: [PATCH 128/179] NG: Improve sma filter buffer. --- .../common/operations/NodeGraphOpMathNumerical.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index f1590913..c77d4d33 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -434,11 +434,15 @@ namespace l::nodegraph { auto outOutput = &outputs.at(0).Get(numSamples); if (mReadSamples == 0) { - mValues.resize(n + 1); + auto len = static_cast(n); + if (mValues.size() != len) { + mValues.resize(len); + } + float in = *inInput; for (auto& v : mValues) { - v = *inInput; + v = in; } - mSum = *inInput * mValues.size();; + mSum = in * mValues.size();; } auto factor = 1.0f / mValues.size(); From d0ebe9c7f6acaac062f4a0369fb671d462511c0e Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 18 Nov 2025 12:35:09 +0100 Subject: [PATCH 129/179] Increase sma max size. --- .../include/nodegraph/operations/NodeGraphOpMathNumerical.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 97115b28..73c98f3f 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -275,7 +275,7 @@ namespace l::nodegraph { NodeGraphOp(node, "SMA") { AddInput2("In"); - AddInput("N", 14.0f, 1, 1.0f, 1000.0f); + AddInput("N", 14.0f, 1, 1.0f, 2000.0f); AddOutput2("Out"); } From fbc7d157348e1cc504775b93aee142e3a87bc74a Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 18 Nov 2025 13:12:22 +0100 Subject: [PATCH 130/179] Wrap torch related code in ifdef. --- packages/nn/source/common/torch/TorchBase.cpp | 4 ++-- packages/nn/tests/common/Torch1Test.cpp | 3 ++- packages/nn/tests/common/Torch2Test.cpp | 2 ++ 3 files changed, 6 insertions(+), 3 deletions(-) diff --git a/packages/nn/source/common/torch/TorchBase.cpp b/packages/nn/source/common/torch/TorchBase.cpp index 45c3161d..6ea5829f 100644 --- a/packages/nn/source/common/torch/TorchBase.cpp +++ b/packages/nn/source/common/torch/TorchBase.cpp @@ -2,7 +2,7 @@ namespace l::nn::libtorch { -#ifdef LDEPS_USE_LIBTORCH +#ifdef HAS_LIBTORCH struct TransformerNetImpl : public torch::nn::Module { TransformerNetImpl(int window_size, int output_size) { auto copt = torch::nn::Conv1dOptions(1, 16, 5).stride(1).padding(2); @@ -27,7 +27,7 @@ namespace l::nn::libtorch { #endif void Transformer::process(const std::vector& window) { -#ifdef LDEPS_USE_LIBTORCH +#ifdef HAS_LIBTORCH TransformerNet model(window.size(), 10); // Predict 10 samples model->eval(); torch::NoGradGuard no_grad; diff --git a/packages/nn/tests/common/Torch1Test.cpp b/packages/nn/tests/common/Torch1Test.cpp index 061d0264..f8105f16 100644 --- a/packages/nn/tests/common/Torch1Test.cpp +++ b/packages/nn/tests/common/Torch1Test.cpp @@ -1,6 +1,7 @@ #include "testing/Test.h" #include "logging/Log.h" +#ifdef HAS_LIBTORCH #include #include @@ -27,5 +28,5 @@ TEST(Torch1, Basic) { return 0; } - +#endif diff --git a/packages/nn/tests/common/Torch2Test.cpp b/packages/nn/tests/common/Torch2Test.cpp index 283975f9..88c4f75a 100644 --- a/packages/nn/tests/common/Torch2Test.cpp +++ b/packages/nn/tests/common/Torch2Test.cpp @@ -1,6 +1,7 @@ #include "testing/Test.h" #include "logging/Log.h" +#ifdef HAS_LIBTORCH #include TEST(Torch2, TorchTensorBasic) { @@ -114,3 +115,4 @@ TEST(Torch2, TorchAdvancedExample) { } return 0; } +#endif From b3d790f0d8146afa0ab6aac1034ddcf4fcfee715 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 18 Nov 2025 15:08:06 +0100 Subject: [PATCH 131/179] Fix sign. --- .../source/common/operations/NodeGraphOpMathNumerical.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index c77d4d33..749acd1d 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -434,7 +434,7 @@ namespace l::nodegraph { auto outOutput = &outputs.at(0).Get(numSamples); if (mReadSamples == 0) { - auto len = static_cast(n); + auto len = static_cast(n); if (mValues.size() != len) { mValues.resize(len); } From 46ee369bd4e1038cfd62653fa0487967aed2a7f1 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 18 Nov 2025 15:26:39 +0100 Subject: [PATCH 132/179] Remove semicolon. --- .../source/common/operations/NodeGraphOpMathNumerical.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 749acd1d..24f082f5 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -442,7 +442,7 @@ namespace l::nodegraph { for (auto& v : mValues) { v = in; } - mSum = in * mValues.size();; + mSum = in * mValues.size(); } auto factor = 1.0f / mValues.size(); From c149ab3fe5bcc9023a2ecf83a9412d8f5074def1 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 18 Nov 2025 16:09:57 +0100 Subject: [PATCH 133/179] Simplify uimodule base. --- packages/rendering/include/rendering/ui/UIModule.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/rendering/include/rendering/ui/UIModule.h b/packages/rendering/include/rendering/ui/UIModule.h index 9dbd8e13..44f09c2c 100644 --- a/packages/rendering/include/rendering/ui/UIModule.h +++ b/packages/rendering/include/rendering/ui/UIModule.h @@ -10,6 +10,6 @@ namespace l::ui { virtual ~UIModule() = default; virtual void UIModuleRenderControls(bool widget) = 0; - virtual void UIModuleRenderChart(std::string_view plotKey, float candleWidth) = 0; + virtual void UIModuleRenderChart(std::string_view plotKey) = 0; }; } From 48bf2b10274307534501aa96bb455a4352225636 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 18 Nov 2025 16:23:57 +0100 Subject: [PATCH 134/179] Fix linux build warnings. --- packages/nn/CMakeLists.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/nn/CMakeLists.txt b/packages/nn/CMakeLists.txt index a9ebf5e1..324f94c0 100644 --- a/packages/nn/CMakeLists.txt +++ b/packages/nn/CMakeLists.txt @@ -45,6 +45,6 @@ if(MSVC) target_compile_options(nn PRIVATE /WX- /bigobj) target_compile_options(nn_test PRIVATE /WX- /bigobj) else() - target_compile_options(nn PRIVATE -Werror -Wno-unused-result -Wno-ignored-qualifiers -Wno-unused-parameter) - target_compile_options(nn_test PRIVATE -Werror -Wno-unused-result -Wno-ignored-qualifiers -Wno-unused-parameter) + target_compile_options(nn PRIVATE -Wno-unused-variable -Wno-error -Wno-unused-variable -Wno-unused-result -Wno-ignored-qualifiers -Wno-unused-parameter) + target_compile_options(nn_test PRIVATE -Wno-unused-variable -Wno-error -Wno-unused-variable -Wno-unused-result -Wno-ignored-qualifiers -Wno-unused-parameter) endif() From 4345128cf9a237a7d96eee60cf9a5bf8d3f88753 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 18 Nov 2025 17:05:31 +0100 Subject: [PATCH 135/179] Remove unused code. --- packages/network/source/common/NetworkConnection.cpp | 2 +- packages/network/source/common/NetworkManager.cpp | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/network/source/common/NetworkConnection.cpp b/packages/network/source/common/NetworkConnection.cpp index 4250d2d0..387597ee 100644 --- a/packages/network/source/common/NetworkConnection.cpp +++ b/packages/network/source/common/NetworkConnection.cpp @@ -499,7 +499,7 @@ namespace l::network { LLOG(LogWarning) << "[Request] Failed notify append response, no curl instance"; } - ASSERT(mOngoingRequest); + //ASSERT(mOngoingRequest); if (mCompletedRequest) { // request probably timed out so discard data diff --git a/packages/network/source/common/NetworkManager.cpp b/packages/network/source/common/NetworkManager.cpp index bd647669..0b2a9f23 100644 --- a/packages/network/source/common/NetworkManager.cpp +++ b/packages/network/source/common/NetworkManager.cpp @@ -36,10 +36,10 @@ namespace l::network { if (m->data.result != CURLE_OK) { success = false; } - bool foundHandle = false; + //bool foundHandle = false; for (auto& it : mConnections) { if (it->IsHandle(e)) { - foundHandle = true; + //foundHandle = true; if (!it->IsWebSocket()) { it->NotifyCompleteRequest(success); } From 946e3b5446c17fcfdbb1093d83f7f0ae38eea301 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 18 Nov 2025 17:38:59 +0100 Subject: [PATCH 136/179] Fix incorrect log macro invocation. --- packages/tools/source/linux/utils/Process.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tools/source/linux/utils/Process.cpp b/packages/tools/source/linux/utils/Process.cpp index 8331695a..216216dd 100644 --- a/packages/tools/source/linux/utils/Process.cpp +++ b/packages/tools/source/linux/utils/Process.cpp @@ -34,7 +34,7 @@ namespace process { return processRunner.get(); } else { - LOG(LogError) << "Failed to detach process"; + LLOG(LogError) << "Failed to detach process"; return FAILED_TO_DETACH_PROCESS; } } From 8a858da09cc6525e8b8105ecec0a047270c527a6 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 20 Nov 2025 17:48:32 +0100 Subject: [PATCH 137/179] Remove uimodule as it has no use. --- .../rendering/include/rendering/ui/UIModule.h | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 packages/rendering/include/rendering/ui/UIModule.h diff --git a/packages/rendering/include/rendering/ui/UIModule.h b/packages/rendering/include/rendering/ui/UIModule.h deleted file mode 100644 index 44f09c2c..00000000 --- a/packages/rendering/include/rendering/ui/UIModule.h +++ /dev/null @@ -1,15 +0,0 @@ -#pragma once - -#include - -namespace l::ui { - - class UIModule { - public: - UIModule() = default; - virtual ~UIModule() = default; - - virtual void UIModuleRenderControls(bool widget) = 0; - virtual void UIModuleRenderChart(std::string_view plotKey) = 0; - }; -} From 0e1513b0f873f196c4b35d20519ad975707f721d Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 21 Nov 2025 13:00:59 +0100 Subject: [PATCH 138/179] NG: Fix error in minmax compare. --- .../include/nodegraph/operations/NodeGraphOpMathAritmethic.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h index 5fd9a52a..3db6a5fa 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h @@ -389,7 +389,7 @@ namespace l::nodegraph { auto in2 = *in2Input++; *minOutput++ = in1 < in2 ? in1 : in2; - *maxOutput++ = in2 < in1 ? in2 : in1; + *maxOutput++ = in1 > in2 ? in1 : in2; } } }; From a0d63dc07849553621d1d2c5c156c916aaec4506 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 22 Nov 2025 01:10:16 +0100 Subject: [PATCH 139/179] NG: Fix init problem. --- .../source/common/operations/NodeGraphOpMathNumerical.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 24f082f5..5b8b09f5 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -546,7 +546,7 @@ namespace l::nodegraph { if (mReadSamples == 0) { alpha = 1.0f / period; - ema_prev = 0.0f; + ema_prev = *inInput; variance_ewma = 0.0f; } From 265928870cdf49891886718d2ce35614f504b21b Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 22 Nov 2025 16:22:33 +0100 Subject: [PATCH 140/179] Add flag manipulation functions. Add flag to sequential cache for better control of block content state. --- packages/logging/include/logging/String.h | 15 +++++++++++++++ .../storage/include/storage/SequentialCache.h | 13 +++++++++++++ 2 files changed, 28 insertions(+) diff --git a/packages/logging/include/logging/String.h b/packages/logging/include/logging/String.h index 45bb7697..08cfba2c 100644 --- a/packages/logging/include/logging/String.h +++ b/packages/logging/include/logging/String.h @@ -341,5 +341,20 @@ namespace l::string { std::string hex_encode(std::string_view str); std::string hex_decode(std::string_view str); + + template >> + void clear_flags(I& allflags, const I flags) { + allflags &= ~flags; + } + + template >> + void set_flags(I& allflags, const I flags) { + allflags |= flags; + } + + template >> + bool has_flags(const I allflags, const I flags) { + return (allflags & (~flags)) == flags; + } } diff --git a/packages/storage/include/storage/SequentialCache.h b/packages/storage/include/storage/SequentialCache.h index 8ae966d2..c00aee99 100644 --- a/packages/storage/include/storage/SequentialCache.h +++ b/packages/storage/include/storage/SequentialCache.h @@ -165,6 +165,18 @@ namespace l::filecache { return l::concurrency::ObjectLock(mDataMutex, mData.get()); } + void ClearFlags(uint32_t flags) { + l::string::clear_flags(mFlags, flags); + } + + void SetFlags(uint32_t flags) { + l::string::set_flags(mFlags, flags); + } + + bool HasFlags(uint32_t flags) { + return l::string::has_flags(mFlags, flags); + } + protected: std::mutex mDataMutex; std::unique_ptr mData; @@ -174,6 +186,7 @@ namespace l::filecache { ICacheProvider* mCacheProvider; bool mPersistOnDestruction; + uint32_t mFlags = 0; }; template From d5e16789130c17a471a6de51c159694dcc8b9d56 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 24 Nov 2025 14:21:56 +0100 Subject: [PATCH 141/179] Add methods for setting persist on destruction. --- packages/storage/include/storage/SequentialCache.h | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/storage/include/storage/SequentialCache.h b/packages/storage/include/storage/SequentialCache.h index c00aee99..49d20a28 100644 --- a/packages/storage/include/storage/SequentialCache.h +++ b/packages/storage/include/storage/SequentialCache.h @@ -62,6 +62,14 @@ namespace l::filecache { archive(*self.mData.get()); } + void PersistOnDestruction() { + mPersistOnDestruction = true; + } + + void NoPersistOnDestruction() { + mPersistOnDestruction = false; + } + bool UnpersistData() { if (!mCacheProvider) { return false; @@ -76,7 +84,7 @@ namespace l::filecache { if (!mCacheProvider) { return false; } - + std::vector data; GetArchiveData(data); From ba792bc3f19cd1b8174f5031223c30098eee2028 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 24 Nov 2025 16:30:53 +0100 Subject: [PATCH 142/179] Make data on sequential cache blocks atomic. --- packages/storage/include/storage/SequentialCache.h | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/packages/storage/include/storage/SequentialCache.h b/packages/storage/include/storage/SequentialCache.h index 49d20a28..4984ffed 100644 --- a/packages/storage/include/storage/SequentialCache.h +++ b/packages/storage/include/storage/SequentialCache.h @@ -66,6 +66,10 @@ namespace l::filecache { mPersistOnDestruction = true; } + bool WillPersistOnDestruction() { + return mPersistOnDestruction; + } + void NoPersistOnDestruction() { mPersistOnDestruction = false; } @@ -174,15 +178,15 @@ namespace l::filecache { } void ClearFlags(uint32_t flags) { - l::string::clear_flags(mFlags, flags); + mFlags &= ~flags; } void SetFlags(uint32_t flags) { - l::string::set_flags(mFlags, flags); + mFlags |= flags; } bool HasFlags(uint32_t flags) { - return l::string::has_flags(mFlags, flags); + return (mFlags.load() & (~flags)) == flags; } protected: @@ -193,8 +197,8 @@ namespace l::filecache { std::mutex mPathMutex; ICacheProvider* mCacheProvider; - bool mPersistOnDestruction; - uint32_t mFlags = 0; + std::atomic_bool mPersistOnDestruction; + std::atomic_uint32_t mFlags = 0; }; template From f0b5881219bffa47e84b0db2c0e9e0656bc0be2b Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 24 Nov 2025 18:43:17 +0100 Subject: [PATCH 143/179] NG: Fix init error. --- .../source/common/operations/NodeGraphOpMathNumerical.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 5b8b09f5..581adc07 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -17,7 +17,7 @@ namespace l::nodegraph { auto output = &outputs.at(0).Get(numSamples); if (mReadSamples == 0) { - mOutput = *input0; + mOutput = 0.0f; } for (int32_t i = 0; i < numSamples; i++) { From e7365897fdca74ebace1f8b41d0b8060b549806d Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 27 Nov 2025 13:37:28 +0100 Subject: [PATCH 144/179] NG: Add more flexibility. --- .../nodegraph/operations/NodeGraphOpTradingDataIO.h | 2 +- packages/storage/include/storage/SequentialCache.h | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h index 4272694f..e81c0b4d 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h @@ -31,7 +31,7 @@ namespace l::nodegraph { } AddInput2("In", 16, InputFlags(false, false, false, false)); - AddInput2("Symbol", 16, InputFlags(false, true, false, true)); + AddInput2("Symbol", 16, InputFlags(false, true, true, true)); AddInput2("Base", 16, InputFlags(false, true, false, true)); AddInput("Index", 2.0f, 1, 0.0f, 10.0f); AddInput("Timeframe", 1.0f, 1, 1.0f, 1440.0f); diff --git a/packages/storage/include/storage/SequentialCache.h b/packages/storage/include/storage/SequentialCache.h index 4984ffed..9ba41dad 100644 --- a/packages/storage/include/storage/SequentialCache.h +++ b/packages/storage/include/storage/SequentialCache.h @@ -339,7 +339,8 @@ namespace l::filecache { int32_t beginPosition, int32_t endPosition, int32_t blockWidth, - std::function*)> callback) { + std::function*)> callback, + bool forceLoad = true) { std::unique_lock lock(mMutexSequentialCacheMap); auto it = mSequentialCacheMap.find(cacheKey.data()); @@ -361,7 +362,10 @@ namespace l::filecache { beginPosition = GetClampedPosition(beginPosition, cacheBlockWidth); if (beginPosition < endPosition) { do { - cacheBlock = sequentialCacheMap->Get(beginPosition); + cacheBlock = nullptr; + if (forceLoad || sequentialCacheMap->Has(beginPosition)) { + cacheBlock = sequentialCacheMap->Get(beginPosition); + } if (cacheBlock != nullptr) { if (!callback(beginPosition, cacheBlockWidth, cacheBlock)) { break; @@ -375,7 +379,10 @@ namespace l::filecache { } else { do { - cacheBlock = sequentialCacheMap->Get(beginPosition); + cacheBlock = nullptr; + if (forceLoad || sequentialCacheMap->Has(beginPosition)) { + cacheBlock = sequentialCacheMap->Get(beginPosition); + } if (cacheBlock != nullptr) { if (!callback(beginPosition, cacheBlockWidth, cacheBlock)) { break; From 368776bb61994f5c3cd8816118bf86c47b2eb12c Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 29 Nov 2025 18:45:31 +0100 Subject: [PATCH 145/179] NG: Add scaling to reversal in trend node. --- .../nodegraph/operations/NodeGraphOpTradingDetector.h | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDetector.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDetector.h index 33385c93..3b8528de 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDetector.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDetector.h @@ -206,6 +206,7 @@ namespace l::nodegraph { { AddInput("In", 0.0f, 1, -l::math::constants::FLTMAX, l::math::constants::FLTMAX, false, false); AddInput("Mean size", 6.0f, 1, 1.0f, 50.0f); + AddInput("Scale", 1.0f, 1, 0.0f, 1.0f); AddOutput("Trend Basic", 0.0f); AddOutput("Trend Mean", 0.0f); @@ -217,6 +218,7 @@ namespace l::nodegraph { virtual void Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) override { auto input1 = inputs.at(0).GetIterator(numSamples); auto numTrendSamples = static_cast(l::math::max2(inputs.at(1).Get(), 1.0f)); + auto reversalScale = l::math::clamp(inputs.at(2).Get(), 0.0f, 1.0f); auto outputTrendBasic = outputs.at(0).GetIterator(numSamples); auto outputTrendMean = outputs.at(1).GetIterator(numSamples); @@ -225,10 +227,10 @@ namespace l::nodegraph { for (int32_t i = 0; i < numSamples; i++) { float in = (*input1++); - + auto scale = l::math::abs(in) * reversalScale + (1.0f - reversalScale); auto trendBasic = mTrendBasic.process(in); auto trendMean = mTrendMean.process(in, numTrendSamples); - auto reversal = mReversal.process(in); + auto reversal = mReversal.process(in) * scale; auto acceleration = mAcceleration.process(in); *outputTrendBasic++ = trendBasic; From d27fdef1cf26bd433360bfd853f924f84dffd35a Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 4 Dec 2025 11:43:51 +0100 Subject: [PATCH 146/179] Fix silly bug. --- packages/storage/include/storage/SequentialCache.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/storage/include/storage/SequentialCache.h b/packages/storage/include/storage/SequentialCache.h index 9ba41dad..515fc83a 100644 --- a/packages/storage/include/storage/SequentialCache.h +++ b/packages/storage/include/storage/SequentialCache.h @@ -186,7 +186,7 @@ namespace l::filecache { } bool HasFlags(uint32_t flags) { - return (mFlags.load() & (~flags)) == flags; + return (mFlags.load() & flags) == flags; } protected: From 52461b76361785d80d7a4e56b62d5a2044eea87f Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 7 Dec 2025 22:44:09 +0100 Subject: [PATCH 147/179] Add buffer access to node graph input/output. Add general binary search. Add perf utils for app bottleneck measurement. --- packages/math/include/math/MathAlgorithm.h | 20 +++++++++++++ .../include/nodegraph/core/NodeGraphBase.h | 2 ++ .../include/nodegraph/core/NodeGraphInput.h | 1 + .../include/nodegraph/core/NodeGraphOutput.h | 1 + .../operations/NodeGraphOpTradingDataIO.h | 2 ++ .../source/common/core/NodeGraphBase.cpp | 8 +++++ .../source/common/core/NodeGraphInput.cpp | 15 ++++++++++ .../source/common/core/NodeGraphOutput.cpp | 7 +++++ .../operations/NodeGraphOpTradingDataIO.cpp | 3 ++ packages/testing/include/testing/Test.h | 1 + packages/testing/include/testing/Timer.h | 3 ++ packages/testing/source/common/Test.cpp | 30 +++++++++++++++++++ packages/testing/source/common/Timer.cpp | 21 +++++++++++-- 13 files changed, 112 insertions(+), 2 deletions(-) diff --git a/packages/math/include/math/MathAlgorithm.h b/packages/math/include/math/MathAlgorithm.h index 9a859049..4b283e6c 100644 --- a/packages/math/include/math/MathAlgorithm.h +++ b/packages/math/include/math/MathAlgorithm.h @@ -77,6 +77,26 @@ namespace l::math::algorithm { return result; } + template + int32_t binary_search_fn(const std::vector& elements, std::function fn, int32_t minIndex = 0, int32_t maxIndex = INT32_MAX) { + int32_t left = static_cast(minIndex < 0 ? 0 : minIndex); + int32_t right = static_cast((maxIndex < elements.size() ? maxIndex : elements.size()) - 1); + int32_t result = -1; // Default if no element is <= value + + while (left <= right) { + int32_t mid = left + (right - left) / 2; + + if (fn(elements.at(mid))) { + result = mid; // Valid candidate found + left = mid + 1; // Look for a better candidate to the right + } + else { + right = mid - 1; // Look to the left + } + } + return result; + } + template T bisect(T a, T b, T tolerance, int iterations, std::function eval) { int n = 0; diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h index ed9f1053..b754a79c 100644 --- a/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphBase.h @@ -90,9 +90,11 @@ namespace l::nodegraph { void SetOutput(int8_t inputChannel, float value); virtual float& GetInput(int8_t inputChannel, int32_t minSize = 1, int32_t offset = 0); + virtual std::optional> GetInputBuffer(int8_t inputChannel); virtual std::string_view GetInputText(int8_t inputChannel, int32_t minSize = 16); virtual float& GetOutput(int8_t outputChannel, int32_t minSize = 1, int32_t offset = 0); + virtual std::optional> GetOutputBuffer(int8_t outputChannel); virtual std::string_view GetOutputText(int8_t outputChannel, int32_t minSize = 16); virtual NodeGraphInput& GetInputOf(int8_t inputChannel); virtual NodeGraphOutput& GetOutputOf(int8_t outputChannel); diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphInput.h b/packages/nodegraph/include/nodegraph/core/NodeGraphInput.h index bb53028d..97a7c7b9 100644 --- a/packages/nodegraph/include/nodegraph/core/NodeGraphInput.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphInput.h @@ -68,6 +68,7 @@ namespace l::nodegraph { void MinimizeBuffer(int32_t size); float& Get(int32_t minSize = 1, int32_t offset = 0); + std::optional> GetBuffer(); float& GetArray(int32_t minSize = 1, int32_t offset = 0); std::string_view GetText(int32_t minSize = 16); NodeGraphBase* GetInputNode(); diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphOutput.h b/packages/nodegraph/include/nodegraph/core/NodeGraphOutput.h index 8227dcf5..f51cbbfc 100644 --- a/packages/nodegraph/include/nodegraph/core/NodeGraphOutput.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphOutput.h @@ -38,6 +38,7 @@ namespace l::nodegraph { void Clear(); void MinimizeBuffer(int32_t size); float& Get(int32_t minSize = 1, int32_t offset = 0); + std::optional> GetBuffer(); std::string_view GetText(int32_t minSize = 16); void SetText(std::string_view text); NodeDataIterator GetIterator(int32_t minSize, float lod = 1.0f); diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h index e81c0b4d..2e560dc2 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h @@ -91,6 +91,7 @@ namespace l::nodegraph { AddInput2("Now"); AddInput2("PTick"); AddInput2("QStep"); + AddInput2("Price"); AddOutput2("Symbol", 16, OutputFlags(false, true)); AddOutput2("Base", 16, OutputFlags(false, true)); @@ -102,6 +103,7 @@ namespace l::nodegraph { AddOutput("Reset"); AddOutput("PTick"); AddOutput("QStep"); + AddOutput("Price"); } virtual ~TradingDataIOChartInfo() = default; diff --git a/packages/nodegraph/source/common/core/NodeGraphBase.cpp b/packages/nodegraph/source/common/core/NodeGraphBase.cpp index 5f64a496..bac557b6 100644 --- a/packages/nodegraph/source/common/core/NodeGraphBase.cpp +++ b/packages/nodegraph/source/common/core/NodeGraphBase.cpp @@ -91,6 +91,10 @@ namespace l::nodegraph { return mInputs.at(inputChannel).Get(minSize, offset); } + std::optional> NodeGraphBase::GetInputBuffer(int8_t inputChannel) { + return mInputs.at(inputChannel).GetBuffer(); + } + std::string_view NodeGraphBase::GetInputText(int8_t inputChannel, int32_t minSize) { return mInputs.at(inputChannel).GetText(minSize); } @@ -99,6 +103,10 @@ namespace l::nodegraph { return mOutputs.at(outputChannel).Get(minSize, offset); } + std::optional> NodeGraphBase::GetOutputBuffer(int8_t outputChannel) { + return mOutputs.at(outputChannel).GetBuffer(); + } + std::string_view NodeGraphBase::GetOutputText(int8_t outputChannel, int32_t minSize) { return mOutputs.at(outputChannel).GetText(minSize); } diff --git a/packages/nodegraph/source/common/core/NodeGraphInput.cpp b/packages/nodegraph/source/common/core/NodeGraphInput.cpp index 595b9622..856cccc7 100644 --- a/packages/nodegraph/source/common/core/NodeGraphInput.cpp +++ b/packages/nodegraph/source/common/core/NodeGraphInput.cpp @@ -124,6 +124,21 @@ namespace l::nodegraph { return mInput.mInputFloatConstant; } + std::optional> NodeGraphInput::GetBuffer() { + switch (mInputType) { + case InputType::INPUT_NODE: + if (mInput.mInputNode != nullptr) { + return mInput.mInputNode->GetOutputBuffer(mInputFromOutputChannel); + } + break; + case InputType::INPUT_ARRAY: + if (mInput.mInputFloatBuf != nullptr && !mInput.mInputFloatBuf->empty()) { + return *mInput.mInputFloatBuf; + } + } + return std::nullopt; + } + float& NodeGraphInput::GetArray(int32_t minSize, int32_t offset) { if (mInputType == InputType::INPUT_ARRAY) { if (!mInput.mInputFloatBuf) { diff --git a/packages/nodegraph/source/common/core/NodeGraphOutput.cpp b/packages/nodegraph/source/common/core/NodeGraphOutput.cpp index cc56860f..2475b4b6 100644 --- a/packages/nodegraph/source/common/core/NodeGraphOutput.cpp +++ b/packages/nodegraph/source/common/core/NodeGraphOutput.cpp @@ -57,6 +57,13 @@ namespace l::nodegraph { return std::string_view(out); } + std::optional> NodeGraphOutput::GetBuffer() { + if (mOutputBuf != nullptr && !mOutputBuf->empty()) { + return *mOutputBuf; + } + return std::nullopt; + } + void NodeGraphOutput::SetText(std::string_view text) { auto p = reinterpret_cast(&Get(1 + static_cast(text.size()))); memcpy(p, text.data(), text.size()); diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp index 1c2413e9..07f0aff3 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp @@ -177,6 +177,7 @@ namespace l::nodegraph { auto now = inputs.at(3).Get(); auto ptick = inputs.at(4).Get(); auto qstep = inputs.at(5).Get(); + auto price = inputs.at(6).Get(); outputs.at(0).SetText(symbolInput); outputs.at(1).SetText(baseInput); @@ -188,6 +189,7 @@ namespace l::nodegraph { float* resetOutput = &outputs.at(7).Get(); float* ptickOutput = &outputs.at(8).Get(); float* qstepOutput = &outputs.at(9).Get(); + float* priceOutput = &outputs.at(10).Get(); *indexOut0 = l::math::clamp(indexInput, 0.0f, 9.9999f); *indexOut1 = l::math::clamp(indexInput + 1.0f, 0.0f, 9.9999f); @@ -197,6 +199,7 @@ namespace l::nodegraph { *resetOutput = mReadSamples == 0; *ptickOutput = ptick; *qstepOutput = qstep; + *priceOutput = price; mReadSamples += numSamples; if (mReadSamples >= numCacheSamples) { diff --git a/packages/testing/include/testing/Test.h b/packages/testing/include/testing/Test.h index d4ca290c..462128e9 100644 --- a/packages/testing/include/testing/Test.h +++ b/packages/testing/include/testing/Test.h @@ -18,6 +18,7 @@ namespace testing { bool run_tests(const char* app); bool run_perfs(const char* app); + void show_perfs(const char* app); } } diff --git a/packages/testing/include/testing/Timer.h b/packages/testing/include/testing/Timer.h index 3586f1d4..2a924280 100644 --- a/packages/testing/include/testing/Timer.h +++ b/packages/testing/include/testing/Timer.h @@ -24,6 +24,8 @@ namespace l::testing { struct TimeMeasure { double mSeconds = 0; + double mMin = 100000; + double mMax = 0.0f; uint64_t mCount = 0; }; @@ -38,6 +40,7 @@ namespace l::testing { std::map& get_time_measures(std::string_view groupName); TimeMeasure& get_time_measure(std::string_view groupName, std::string_view id); + void show_measurements(const std::string& group); } #define PERF_TIMER(name) auto UNIQUE(PerfTimer) = std::make_unique(l::testing::get_current_test_group(), name) diff --git a/packages/testing/source/common/Test.cpp b/packages/testing/source/common/Test.cpp index 8f7d70d4..20832d8b 100644 --- a/packages/testing/source/common/Test.cpp +++ b/packages/testing/source/common/Test.cpp @@ -139,5 +139,35 @@ namespace testing { return perf_success; } + + void show_perfs(const char* app) { + LLOG(LogTitle) << "Performance tests " << app; + + std::vector summary; + + auto& groups = get_perf_groups(); + for (auto& groupIt : groups) { + LLOG(LogTitle) << "## " << groupIt.first; + for (auto& f : *groupIt.second) { + LLOG(LogTitle) << groupIt.first + "::" + f.first; + auto& measures = get_time_measures(groupIt.first); + + for (auto& result : measures) { + LLOG(LogInfo) << groupIt.first << "::" << result.first << ": " << result.second.mSeconds << " sec."; + } + } + + std::ostringstream msg; + msg << "Performance result for '" + groupIt.first + "'"; + LLOG(LogTitle) << msg.str(); + summary.push_back(msg.str()); + } + + LLOG(LogTitle) << "----"; + for (auto& str : summary) { + LLOG(LogTitle) << str; + } + } + } } diff --git a/packages/testing/source/common/Timer.cpp b/packages/testing/source/common/Timer.cpp index 7524e1b2..7c84b77f 100644 --- a/packages/testing/source/common/Timer.cpp +++ b/packages/testing/source/common/Timer.cpp @@ -1,6 +1,7 @@ #include #include +#include "logging/Log.h" #include "testing/Timer.h" namespace l { @@ -57,11 +58,27 @@ namespace testing { PerformanceTimer::PerformanceTimer(std::string_view group, std::string_view id) : mGroup(group), mId(id), mTimer([&](uint64_t nanoseconds) { auto& measure = get_time_measure(mGroup, mId); - - measure.mSeconds += static_cast(nanoseconds) / 1000000000.0; + auto measurement = static_cast(nanoseconds) / 1000000000.0; + measure.mSeconds += measurement; + measure.mMax = measure.mMax < measurement ? measurement : measure.mMax; + measure.mMin = measure.mMin > measurement ? measurement : measure.mMin; measure.mCount++; }) {} + + void show_measurements(const std::string& group) { + std::vector summary; + + LLOG(LogTitle) << "## " << group; + for (auto& it : get_time_measures(group)) { + auto& measure = it.second; + LLOG(LogInfo) << it.first; + auto mean = measure.mSeconds / static_cast(measure.mCount); + LLOG(LogInfo) << " mean " << mean << " sec"; + LLOG(LogInfo) << " min " << measure.mMin << " sec"; + LLOG(LogInfo) << " max " << measure.mMax << " sec"; + } + } } } From 12a9d335b47c808112ccaeb39d9d3e74301b3e8c Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 9 Dec 2025 07:08:47 +0100 Subject: [PATCH 148/179] Fix missing cases. --- packages/nodegraph/source/common/core/NodeGraphInput.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/nodegraph/source/common/core/NodeGraphInput.cpp b/packages/nodegraph/source/common/core/NodeGraphInput.cpp index 856cccc7..8e37d406 100644 --- a/packages/nodegraph/source/common/core/NodeGraphInput.cpp +++ b/packages/nodegraph/source/common/core/NodeGraphInput.cpp @@ -135,8 +135,10 @@ namespace l::nodegraph { if (mInput.mInputFloatBuf != nullptr && !mInput.mInputFloatBuf->empty()) { return *mInput.mInputFloatBuf; } + break; + default: + return std::nullopt; } - return std::nullopt; } float& NodeGraphInput::GetArray(int32_t minSize, int32_t offset) { From 6ea94d3e1f8b3f8e30523c36e4fb07cb7810149f Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 9 Dec 2025 07:52:47 +0100 Subject: [PATCH 149/179] Fix error. --- packages/nodegraph/source/common/core/NodeGraphInput.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/nodegraph/source/common/core/NodeGraphInput.cpp b/packages/nodegraph/source/common/core/NodeGraphInput.cpp index 8e37d406..9a4d7b7f 100644 --- a/packages/nodegraph/source/common/core/NodeGraphInput.cpp +++ b/packages/nodegraph/source/common/core/NodeGraphInput.cpp @@ -139,6 +139,7 @@ namespace l::nodegraph { default: return std::nullopt; } + return std::nullopt; } float& NodeGraphInput::GetArray(int32_t minSize, int32_t offset) { From e5bec26f6f8e8ce33007eab015590363233ef15d Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 9 Dec 2025 08:22:31 +0100 Subject: [PATCH 150/179] Remove std::to_string() --- .../storage/include/storage/SequentialCache.h | 23 ++++++++++++++----- .../storage/source/common/SequentialCache.cpp | 8 ------- 2 files changed, 17 insertions(+), 14 deletions(-) diff --git a/packages/storage/include/storage/SequentialCache.h b/packages/storage/include/storage/SequentialCache.h index 515fc83a..ed06d8e1 100644 --- a/packages/storage/include/storage/SequentialCache.h +++ b/packages/storage/include/storage/SequentialCache.h @@ -25,10 +25,21 @@ namespace l::filecache { int32_t GetClampedPositionOffset(int32_t position, int32_t blockWidth); int32_t GetClampedPositionOffsetFromIndex(int32_t index, int32_t blockWidth, int32_t numBlockEntries); - std::string GetCacheBlockName( - std::string_view prefix, - int32_t blockWidth, - int32_t clampedPos); + template + l::string::string_buffer CreateCacheBlockName( + std::string_view prefix, + int32_t blockWidth, + int32_t clampedPos) { + + l::string::string_buffer key; + key.append(prefix); + key.append("_"); + key.printf("%i", blockWidth); + key.append("_"); + key.printf("%i", clampedPos); + return key; + } + template class CacheBlock { @@ -269,8 +280,8 @@ namespace l::filecache { std::lock_guard lock(mMutexCacheBlockMap); auto it = mCacheBlockMap.find(clampedPos); if (it == mCacheBlockMap.end()) { - auto filename = GetCacheBlockName(mCacheKey, mCacheBlockWidth, clampedPos); - mCacheBlockMap.emplace(clampedPos, std::make_unique>(filename, mCacheProvider, noProvisioning)); + auto filename = CreateCacheBlockName(mCacheKey, mCacheBlockWidth, clampedPos); + mCacheBlockMap.emplace(clampedPos, std::make_unique>(filename.str(), mCacheProvider, noProvisioning)); it = mCacheBlockMap.find(clampedPos); } diff --git a/packages/storage/source/common/SequentialCache.cpp b/packages/storage/source/common/SequentialCache.cpp index 34c185ce..47a35ae5 100644 --- a/packages/storage/source/common/SequentialCache.cpp +++ b/packages/storage/source/common/SequentialCache.cpp @@ -15,12 +15,4 @@ namespace l::filecache { return blockWidth * index / numBlockEntries; } - std::string GetCacheBlockName(std::string_view prefix, int32_t blockWidth, int32_t clampedPos) { - std::stringstream name; - name << prefix.data(); - name << "_" << blockWidth; - name << "_" << clampedPos; - return name.str(); - } - } From 42aff40ba3413acba9d4b10fb47df55e9aa43a8e Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 19 Dec 2025 20:36:06 +0100 Subject: [PATCH 151/179] Increase default buffer size in sequnce cache. --- packages/storage/include/storage/SequentialCache.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/packages/storage/include/storage/SequentialCache.h b/packages/storage/include/storage/SequentialCache.h index ed06d8e1..e5b51848 100644 --- a/packages/storage/include/storage/SequentialCache.h +++ b/packages/storage/include/storage/SequentialCache.h @@ -25,12 +25,11 @@ namespace l::filecache { int32_t GetClampedPositionOffset(int32_t position, int32_t blockWidth); int32_t GetClampedPositionOffsetFromIndex(int32_t index, int32_t blockWidth, int32_t numBlockEntries); - template + template l::string::string_buffer CreateCacheBlockName( std::string_view prefix, int32_t blockWidth, int32_t clampedPos) { - l::string::string_buffer key; key.append(prefix); key.append("_"); From 8b327399223ef057aa44aa54e7db32399298a37d Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sun, 21 Dec 2025 01:37:01 +0100 Subject: [PATCH 152/179] Fix a bug in max3/min3. --- packages/math/include/math/MathFunc.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/math/include/math/MathFunc.h b/packages/math/include/math/MathFunc.h index e2bb18f8..45ddfe10 100644 --- a/packages/math/include/math/MathFunc.h +++ b/packages/math/include/math/MathFunc.h @@ -47,12 +47,12 @@ namespace l::math { template auto min3(T val1, T val2, T val3) { - return val1 < val2 ? (val3 < val1 ? val3 : val1) : val2; + return val1 < val2 ? (val3 < val1 ? val3 : val1) : (val3 < val2 ? val3 : val2); } template auto max3(T val1, T val2, T val3) { - return val1 > val2 ? (val1 > val3 ? val1 : val3) : val2; + return val1 > val2 ? (val1 > val3 ? val1 : val3) : (val1 > val2 ? val1 : val2); } template From dbe853aa1baf2f2a79398a5afbcb702eb4b76a4f Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 25 Dec 2025 15:39:09 +0100 Subject: [PATCH 153/179] Return upper limit if outside the upper bound. --- packages/math/include/math/MathAlgorithm.h | 24 +++++++++++--- .../include/nodegraph/NodeGraphSchema.h | 13 ++++++++ .../include/nodegraph/core/NodeGraphGroup.h | 32 +++++++++++++++++++ .../operations/NodeGraphOpTradingDataIO.h | 1 + .../operations/NodeGraphOpTradingDataIO.cpp | 3 ++ 5 files changed, 68 insertions(+), 5 deletions(-) diff --git a/packages/math/include/math/MathAlgorithm.h b/packages/math/include/math/MathAlgorithm.h index 4b283e6c..12ded036 100644 --- a/packages/math/include/math/MathAlgorithm.h +++ b/packages/math/include/math/MathAlgorithm.h @@ -78,7 +78,7 @@ namespace l::math::algorithm { } template - int32_t binary_search_fn(const std::vector& elements, std::function fn, int32_t minIndex = 0, int32_t maxIndex = INT32_MAX) { + int32_t binary_search_fn(const std::vector& elements, std::function fn, bool defaultDirectionRight = true, int32_t minIndex = 0, int32_t maxIndex = INT32_MAX) { int32_t left = static_cast(minIndex < 0 ? 0 : minIndex); int32_t right = static_cast((maxIndex < elements.size() ? maxIndex : elements.size()) - 1); int32_t result = -1; // Default if no element is <= value @@ -86,13 +86,27 @@ namespace l::math::algorithm { while (left <= right) { int32_t mid = left + (right - left) / 2; - if (fn(elements.at(mid))) { - result = mid; // Valid candidate found - left = mid + 1; // Look for a better candidate to the right + auto direction = fn(elements.at(mid)); + if (direction > 0) { + left = mid + 1; // Look to the right } - else { + else if (direction < 0){ right = mid - 1; // Look to the left } + else { + result = mid; // Valid candidate found + if (defaultDirectionRight) { + left = mid + 1; // Look for a better candidate to the right + } + else { + right = mid - 1; // Look for a better candidate to the left + } + } + } + if (result < 0) { + if (left >= elements.size()) { + return elements.size(); + } } return result; } diff --git a/packages/nodegraph/include/nodegraph/NodeGraphSchema.h b/packages/nodegraph/include/nodegraph/NodeGraphSchema.h index 22d9b714..d7f73dad 100644 --- a/packages/nodegraph/include/nodegraph/NodeGraphSchema.h +++ b/packages/nodegraph/include/nodegraph/NodeGraphSchema.h @@ -180,6 +180,19 @@ namespace l::nodegraph { void ForEachInputNode(std::function cb); void ForEachOutputNode(std::function cb); + template + void ForEachNodeOftype(std::function cb) { + mMainNodeGraph.ForEachNodeOftype(std::move(cb)); + } + template + void ForEachInputNodeOftype(std::function cb) { + mMainNodeGraph.ForEachInputNodeOftype(std::move(cb)); + } + template + void ForEachOutputNodeOftype(std::function cb) { + mMainNodeGraph.ForEachOutputNodeOftype(std::move(cb)); + } + bool HasNodeType(const std::string& typeGroup, int32_t typeId); void ForEachNodeType(std::string_view search, std::function&)> cb) const; void RegisterNodeType(const std::string& typeGroup, int32_t uniqueTypeId, std::string_view typeName, std::string_view description = ""); diff --git a/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h b/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h index 4c81ddd6..436224b8 100644 --- a/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h +++ b/packages/nodegraph/include/nodegraph/core/NodeGraphGroup.h @@ -131,6 +131,38 @@ namespace l::nodegraph { void ForEachInputNode(std::function cb); void ForEachOutputNode(std::function cb); + template + void ForEachNodeOftype(std::function cb) { + for (auto& it : mNodes) { + if (it->IsOfOperation()) { + if (!cb(it)) { + break; + } + } + } + } + template + void ForEachInputNodeOftype(std::function cb) { + for (auto& it : mInputNodes) { + if (it->IsOfOperation()) { + if (!cb(it)) { + break; + } + } + } + } + template + void ForEachOutputNodeOftype(std::function cb) { + for (auto& it : mOutputNodes) { + if (it->IsOfOperation()) { + if (!cb(it)) { + break; + } + } + } + } + + void ClearProcessFlags(); void ProcessSubGraph(int32_t numSamples, int32_t numCacheSamples = -1); void Tick(int32_t tickCount, float elapsed); diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h index 2e560dc2..ea9eec50 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDataIO.h @@ -78,6 +78,7 @@ namespace l::nodegraph { float mBuyQuantMa = 0.0f; }; + /*********************************************************************/ class TradingDataIOChartInfo : public NodeGraphOp { diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp index 07f0aff3..ca1797ac 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp @@ -170,6 +170,9 @@ namespace l::nodegraph { } } + + /*********************************************************************/ + void TradingDataIOChartInfo::Process(int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { auto symbolInput = inputs.at(0).GetText(16); auto baseInput = inputs.at(1).GetText(16); From edeec5dbe820ddc5c6497151b63d2ca80c32af17 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 25 Dec 2025 19:59:07 +0100 Subject: [PATCH 154/179] Allow std containers in binary search functions. --- packages/math/include/math/MathAlgorithm.h | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/packages/math/include/math/MathAlgorithm.h b/packages/math/include/math/MathAlgorithm.h index 12ded036..0183db7a 100644 --- a/packages/math/include/math/MathAlgorithm.h +++ b/packages/math/include/math/MathAlgorithm.h @@ -1,7 +1,10 @@ #pragma once #include +#include #include +#include +#include #include #include #include @@ -36,13 +39,13 @@ namespace l::math::algorithm { d.sub(v); }; - template - uint32_t binary_search(const std::vector& elements, const T& data, int32_t minIndex = 1, int32_t maxIndex = INT32_MAX) { + template>::value || std::is_same>::value || std::is_same>::value>> + uint32_t binary_search(const S& elements, const T& data, int32_t minIndex = 1, int32_t maxIndex = INT32_MAX) { uint32_t L = static_cast(minIndex < 0 ? 0 : minIndex); uint32_t R = static_cast((maxIndex < elements.size() ? maxIndex : elements.size()) - 1); while (L <= R) { - uint32_t m = static_cast(floor((L + R) / 2.0)); + uint32_t m = static_cast(math::floor((L + R) / 2.0)); auto& e = elements.at(static_cast(m)); if (e < data) { L = m + 1; @@ -57,8 +60,8 @@ namespace l::math::algorithm { return 0; } - template - int32_t binary_search_leq(const std::vector& elements, const T& data, int32_t minIndex = 0, int32_t maxIndex = INT32_MAX) { + template>::value || std::is_same>::value || std::is_same>::value>> + int32_t binary_search_leq(const S& elements, const T& data, int32_t minIndex = 0, int32_t maxIndex = INT32_MAX) { int32_t left = static_cast(minIndex < 0 ? 0 : minIndex); int32_t right = static_cast((maxIndex < elements.size() ? maxIndex : elements.size()) - 1); int32_t result = -1; // Default if no element is <= value @@ -77,8 +80,8 @@ namespace l::math::algorithm { return result; } - template - int32_t binary_search_fn(const std::vector& elements, std::function fn, bool defaultDirectionRight = true, int32_t minIndex = 0, int32_t maxIndex = INT32_MAX) { + template>::value || std::is_same>::value || std::is_same>::value>> + int32_t binary_search_fn(const S& elements, std::function fn, bool defaultDirectionRight = true, int32_t minIndex = 0, int32_t maxIndex = INT32_MAX) { int32_t left = static_cast(minIndex < 0 ? 0 : minIndex); int32_t right = static_cast((maxIndex < elements.size() ? maxIndex : elements.size()) - 1); int32_t result = -1; // Default if no element is <= value From e27824cc7ce93bd7aa0c1d9fac016487daf71f1e Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 19 Jan 2026 20:41:44 +0100 Subject: [PATCH 155/179] Fix. --- packages/logging/include/logging/String.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/logging/include/logging/String.h b/packages/logging/include/logging/String.h index 08cfba2c..1c797014 100644 --- a/packages/logging/include/logging/String.h +++ b/packages/logging/include/logging/String.h @@ -354,7 +354,7 @@ namespace l::string { template >> bool has_flags(const I allflags, const I flags) { - return (allflags & (~flags)) == flags; + return (allflags & flags) == flags; } } From fb4fa382b2ef6d830af85d906d4bbaf8d347d6b7 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Thu, 22 Jan 2026 03:40:47 +0100 Subject: [PATCH 156/179] Keep precision until float conversion. --- packages/math/source/common/MathFixedPoint.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/math/source/common/MathFixedPoint.cpp b/packages/math/source/common/MathFixedPoint.cpp index 752565ef..41fd6363 100644 --- a/packages/math/source/common/MathFixedPoint.cpp +++ b/packages/math/source/common/MathFixedPoint.cpp @@ -46,7 +46,7 @@ namespace l::math::fp { } float FixedPoint::toFloat() const { - return static_cast(value_) / static_cast(scale_); + return static_cast(toDouble()); } std::string FixedPoint::toString() const { From a2e812ba321d7ba6940df75251e7eff1858f5abb Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 23 Jan 2026 19:18:42 +0100 Subject: [PATCH 157/179] Change fixed point to truncate values by default. --- packages/math/include/math/MathFixedPoint.h | 12 ++++++------ packages/math/source/common/MathFixedPoint.cpp | 6 +++--- 2 files changed, 9 insertions(+), 9 deletions(-) diff --git a/packages/math/include/math/MathFixedPoint.h b/packages/math/include/math/MathFixedPoint.h index c989be22..7b2a299a 100644 --- a/packages/math/include/math/MathFixedPoint.h +++ b/packages/math/include/math/MathFixedPoint.h @@ -50,15 +50,15 @@ namespace l::math::fp { auto v = l::math::abs(value); if (v < 1.0) { scale_ = 1000000000000000000; - value_ = static_cast(l::math::round(value * scale_)); + value_ = static_cast(value * scale_); } else if (v < 1000000000.0) { scale_ = 1000000000; - value_ = static_cast(l::math::round(value * scale_)); + value_ = static_cast(value * scale_); } else { scale_ = 1; - value_ = static_cast(l::math::round(value * scale_)); + value_ = static_cast(value * scale_); } round(numdecimals); } @@ -66,17 +66,17 @@ namespace l::math::fp { auto v = l::math::abs(value); if (v < 1.0) { scale_ = 1000000000000000000; - value_ = static_cast(l::math::round(value * scale_)); + value_ = static_cast(value * scale_); round(9); } else if (v < 1000000000.0) { scale_ = 1000000000; - value_ = static_cast(l::math::round(value * scale_)); + value_ = static_cast(value * scale_); round(9); } else { scale_ = 1; - value_ = static_cast(l::math::round(value * scale_)); + value_ = static_cast(value * scale_); round(0); } } diff --git a/packages/math/source/common/MathFixedPoint.cpp b/packages/math/source/common/MathFixedPoint.cpp index 41fd6363..54010119 100644 --- a/packages/math/source/common/MathFixedPoint.cpp +++ b/packages/math/source/common/MathFixedPoint.cpp @@ -21,10 +21,10 @@ namespace l::math::fp { int64_t diff = scale_ / newScale; //ASSERT(diff >= 10); scale_ /= diff; - diff /= 10; + //diff /= 10; value_ /= diff; - value_ += 5; // add 0.5 before floor - value_ /= 10; // round (floor(0.5 + x)) + //value_ += 5; // add 0.5 before floor + //value_ /= 10; // round (floor(0.5 + x)) } } From 16edbac024d50f249acdb588f369595d842b8f16 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Sat, 24 Jan 2026 23:54:28 +0100 Subject: [PATCH 158/179] Add a better to string function for string_buffer objects, for math fixed point class. --- packages/math/include/math/MathFixedPoint.h | 73 +++++--------- .../math/source/common/MathFixedPoint.cpp | 98 ++++++++++++++++++- .../math/tests/common/MathFixedPointTest.cpp | 38 +++++++ 3 files changed, 154 insertions(+), 55 deletions(-) diff --git a/packages/math/include/math/MathFixedPoint.h b/packages/math/include/math/MathFixedPoint.h index 7b2a299a..078453c6 100644 --- a/packages/math/include/math/MathFixedPoint.h +++ b/packages/math/include/math/MathFixedPoint.h @@ -41,63 +41,36 @@ namespace l::math::fp { return scale; } - FixedPoint() : value_(0), scale_(1) {} - FixedPoint(int64_t scaledValue, int64_t scale = 100000000) - : value_(scaledValue), scale_(scale) { - normalise(); - } - FixedPoint(double value, int8_t numdecimals) { - auto v = l::math::abs(value); - if (v < 1.0) { - scale_ = 1000000000000000000; - value_ = static_cast(value * scale_); - } - else if (v < 1000000000.0) { - scale_ = 1000000000; - value_ = static_cast(value * scale_); - } - else { - scale_ = 1; - value_ = static_cast(value * scale_); - } - round(numdecimals); - } - FixedPoint(double value) { - auto v = l::math::abs(value); - if (v < 1.0) { - scale_ = 1000000000000000000; - value_ = static_cast(value * scale_); - round(9); - } - else if (v < 1000000000.0) { - scale_ = 1000000000; - value_ = static_cast(value * scale_); - round(9); - } - else { - scale_ = 1; - value_ = static_cast(value * scale_); - round(0); - } - } - FixedPoint(float value, int8_t numdecimals) : FixedPoint(static_cast(value), numdecimals) {} - FixedPoint(float value) : FixedPoint(static_cast(value)) {} - - FixedPoint(std::string_view number) { - auto [n, d, s] = l::string::to_fixed_int(number); - value_ = n; - auto scale = static_cast(0.5f + l::math::pow(10.0f, static_cast(d))); - scale_ = scale; - normalise(); - } + FixedPoint(); + explicit FixedPoint(int64_t scaledValue, int64_t scale); + explicit FixedPoint(double value, int32_t numdecimals, bool floorValue = false); + explicit FixedPoint(double value, bool floorValue = false); + explicit FixedPoint(float value, int32_t numdecimals, bool floorValue = false); + explicit FixedPoint(float value, bool floorValue = false); + FixedPoint(std::string_view number, bool floorValue = false); int32_t numDigits() const; double toDouble() const; float toFloat() const; std::string toString() const; + + template + void getString(l::string::string_buffer& buf) const { + int64_t int_part = value_ / scale_; + int64_t frac_part = l::math::abs(value_ % scale_); + + buf.printf("%lld", int_part); + + if (scale_ > 1) { + int decimal_digits = static_cast(l::math::logx(10.0f, static_cast(scale_))); + buf.printf(".%0*d", decimal_digits, frac_part); + } + } + void normalise(); - void rescale(int64_t scale); + void rescale(int64_t scale, bool truncate = false); void round(int32_t numDecimals); + void floor(int32_t numDecimals); // Arithmetic FixedPoint operator+(const FixedPoint& other) const { diff --git a/packages/math/source/common/MathFixedPoint.cpp b/packages/math/source/common/MathFixedPoint.cpp index 54010119..1d58eef7 100644 --- a/packages/math/source/common/MathFixedPoint.cpp +++ b/packages/math/source/common/MathFixedPoint.cpp @@ -3,6 +3,82 @@ namespace l::math::fp { + + FixedPoint::FixedPoint() : value_(0), scale_(1) {} + + FixedPoint::FixedPoint(int64_t scaledValue, int64_t scale) + : value_(scaledValue), scale_(scale) { + normalise(); + } + + FixedPoint::FixedPoint(double value, int32_t numdecimals, bool floorValue) { + auto v = l::math::abs(value); + if (v < 1.0) { + scale_ = 1000000000000000000; + value_ = static_cast(value * scale_); + } + else if (v < 1000000000.0) { + scale_ = 1000000000; + value_ = static_cast(value * scale_); + } + else { + scale_ = 1; + value_ = static_cast(value * scale_); + } + if (!floorValue) { + round(numdecimals); + } + else { + floor(numdecimals); + } + } + + FixedPoint::FixedPoint(double value, bool floorValue) { + auto v = l::math::abs(value); + auto numdecimals = 0; + if (v < 1.0) { + scale_ = 1000000000000000000; + value_ = static_cast(value * scale_); + numdecimals = 9; + } + else if (v < 1000000000.0) { + scale_ = 1000000000; + value_ = static_cast(value * scale_); + numdecimals = 9; + } + else { + scale_ = 1; + value_ = static_cast(value * scale_); + numdecimals = 0; + } + if (!floorValue) { + round(numdecimals); + } + else { + floor(numdecimals); + } + } + + FixedPoint::FixedPoint(float value, int32_t numdecimals, bool floorValue) : FixedPoint(static_cast(value), numdecimals, floorValue) { + } + + FixedPoint::FixedPoint(float value, bool floorValue) : FixedPoint(static_cast(value), floorValue) { + } + + FixedPoint::FixedPoint(std::string_view number, bool floorValue) { + auto [n, d, s] = l::string::to_fixed_int(number); + value_ = n; + auto scale = static_cast(0.5f + l::math::pow(10.0f, static_cast(d))); + scale_ = scale; + + if (!floorValue) { + round(d); + } + else { + floor(d); + } + } + void FixedPoint::normalise() { while (scale_ >= 10 && value_ >= 10 && (value_ % 10) == 0) { value_ = value_ / 10; @@ -10,7 +86,7 @@ namespace l::math::fp { } } - void FixedPoint::rescale(int64_t newScale) { + void FixedPoint::rescale(int64_t newScale, bool truncate) { if (newScale > scale_) { // scale up, no loss in precision int64_t diff = newScale / scale_; //ASSERT(l::math::abs(value_ * diff) < 100000000000000000); @@ -21,10 +97,14 @@ namespace l::math::fp { int64_t diff = scale_ / newScale; //ASSERT(diff >= 10); scale_ /= diff; - //diff /= 10; + if (!truncate) { + diff /= 10; + } value_ /= diff; - //value_ += 5; // add 0.5 before floor - //value_ /= 10; // round (floor(0.5 + x)) + if (!truncate) { + value_ += 5; // add 0.5 before floor + value_ /= 10; // round (floor(0.5 + x)) + } } } @@ -37,6 +117,15 @@ namespace l::math::fp { normalise(); } + void FixedPoint::floor(int32_t numDecimals) { + int64_t scale = 1; + while (numDecimals-- > 0) { + scale *= 10; + }; + rescale(scale, true); + normalise(); + } + int32_t FixedPoint::numDigits() const { return static_cast(l::math::logx(10.0f, static_cast(scale_))); } @@ -68,5 +157,4 @@ namespace l::math::fp { return oss.str(); } - } diff --git a/packages/math/tests/common/MathFixedPointTest.cpp b/packages/math/tests/common/MathFixedPointTest.cpp index 0312504e..53d63c49 100644 --- a/packages/math/tests/common/MathFixedPointTest.cpp +++ b/packages/math/tests/common/MathFixedPointTest.cpp @@ -89,3 +89,41 @@ TEST(MathFixedPoint, Basic) { return 0; } + +TEST(MathFixedPoint, ToString) { + + { + l::string::string_buffer<20> buf; + FixedPoint fp("124.005154"); + fp.getString(buf); + TEST_TRUE(fp.toString() == buf.str(), ""); + LLOG(LogTest) << buf.str(); + } + { + l::string::string_buffer<20> buf; + FixedPoint fp("0.000000005154"); + fp.getString(buf); + TEST_TRUE(fp.toString() == buf.str(), ""); + + LLOG(LogTest) << buf.str(); + } + { + l::string::string_buffer<20> buf; + FixedPoint fp("0.000000005154", true); + fp.getString(buf); + TEST_TRUE(fp.toString() == buf.str(), ""); + + LLOG(LogTest) << buf.str(); + } + { + l::string::string_buffer<20> buf; + FixedPoint fp("1256.33204"); + fp.getString(buf); + TEST_TRUE(fp.toString() == buf.str(), ""); + + LLOG(LogTest) << buf.str(); + } + return 0; +} + + From cea71edaac3e806300db4a5015a257e0b6889ff9 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 27 Jan 2026 20:37:25 +0100 Subject: [PATCH 159/179] Add float formatting function. --- packages/logging/include/logging/String.h | 58 +++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/packages/logging/include/logging/String.h b/packages/logging/include/logging/String.h index 1c797014..f11dcbe4 100644 --- a/packages/logging/include/logging/String.h +++ b/packages/logging/include/logging/String.h @@ -356,5 +356,63 @@ namespace l::string { bool has_flags(const I allflags, const I flags) { return (allflags & flags) == flags; } + + template + void format_float(l::string::string_buffer& out, float value) { + auto onlypositive = l::math::abs(value); + + char format[7] = "%7.7f"; + + auto numdecimals = 0; + + if (onlypositive > 100000.0) { + numdecimals = 0; + } + else if (onlypositive > 10000.0) { + numdecimals = 1; + } + else if (onlypositive > 1000.0) { + numdecimals = 2; + } + else if (onlypositive > 100.0) { + numdecimals = 3; + } + else if (onlypositive > 10.0) { + numdecimals = 4; + } + else if (onlypositive > 1.0) { + numdecimals = 5; + } + else if (onlypositive > 0.1) { + numdecimals = 5; + } + else if (onlypositive > 0.01) { + numdecimals = 6; + } + else if (onlypositive > 0.001) { + numdecimals = 7; + } + else if (onlypositive > 0.0001) { + numdecimals = 8; + } + else if (onlypositive > 0.00001) { + numdecimals = 8; + } + else if (onlypositive > 0.000001) { + numdecimals = 8; + } + else if (onlypositive > 0.0) { + numdecimals = l::math::min2(numdecimals, 8); + } + else { + numdecimals = l::math::min2(numdecimals, 4); + } + + auto numnumbers = 9 - numdecimals; + format[1] = '0' + static_cast(numnumbers); + format[3] = '0' + static_cast(numdecimals); + + out.printf(format, value); + } } From 2d490fd9e82dca79f3d4e4dfaf5ae758c6e1fd0f Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 27 Jan 2026 20:42:41 +0100 Subject: [PATCH 160/179] Fix format float errors. --- packages/logging/include/logging/String.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/logging/include/logging/String.h b/packages/logging/include/logging/String.h index f11dcbe4..84cedc40 100644 --- a/packages/logging/include/logging/String.h +++ b/packages/logging/include/logging/String.h @@ -359,7 +359,7 @@ namespace l::string { template void format_float(l::string::string_buffer& out, float value) { - auto onlypositive = l::math::abs(value); + auto onlypositive = value < 0.0f ? -value : value; char format[7] = "%7.7f"; @@ -402,10 +402,10 @@ namespace l::string { numdecimals = 8; } else if (onlypositive > 0.0) { - numdecimals = l::math::min2(numdecimals, 8); + numdecimals = numdecimals < 8 ? numdecimals : 8; } else { - numdecimals = l::math::min2(numdecimals, 4); + numdecimals = numdecimals < 4 ? numdecimals : 4; } auto numnumbers = 9 - numdecimals; From 1de166d779522e928cc7709ed9d4497b87271785 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Tue, 3 Feb 2026 11:28:10 +0100 Subject: [PATCH 161/179] Add trunc function. Fix possible div with 0. --- packages/math/include/math/MathFunc.h | 23 +++++++++++++++++++ .../operations/NodeGraphOpTradingDataIO.cpp | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/packages/math/include/math/MathFunc.h b/packages/math/include/math/MathFunc.h index 45ddfe10..abfe2ce7 100644 --- a/packages/math/include/math/MathFunc.h +++ b/packages/math/include/math/MathFunc.h @@ -230,6 +230,29 @@ namespace l::math { } } + template + auto trunc(T val) { + if constexpr (std::is_floating_point_v) { + if constexpr (sizeof(T) == 4) { + return truncf(val); + } + else if constexpr (sizeof(T) == 8) { + return truncl(val); + } + } + } + + template + V trunc(T val) { + if constexpr (std::is_floating_point_v) { + if constexpr (sizeof(T) == 4) { + return static_cast(truncf(val)); + } + else if constexpr (sizeof(T) == 8) { + return static_cast(truncl(val)); + } + } + } template auto log(T val) { if constexpr (std::is_floating_point_v) { diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp index ca1797ac..dd6727db 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp @@ -29,7 +29,7 @@ namespace l::nodegraph { inputs.at(0).MinimizeBuffer(numCacheSamples * stride); auto in = &inputs.at(0).Get(numCacheSamples * stride, readSamples * stride); - auto timeframeMultiplier = static_cast(inputs.at(4).Get()); + auto timeframeMultiplier = l::math::max2(static_cast(inputs.at(4).Get()), 1); auto friction = inputs.at(5).Get(); float* out1 = &outputs.at(3).Get(numSamples); // unixtime From 871b64370e2c0532b0db1361c7c8bd54074214d3 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Fri, 6 Feb 2026 06:32:52 +0100 Subject: [PATCH 162/179] Add chart id to ui chart nodes. --- .../include/nodegraph/operations/NodeGraphOpUI.h | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index 2aebd678..ca45c379 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -96,6 +96,8 @@ namespace l::nodegraph { AddInput2("X", 1, InputFlags(false, false, false, false)); AddInput2("Y", 1, InputFlags(false, false, false, false)); AddInput2("Name", 1, InputFlags(false, true, true, true)); + AddInput("Chart ID", 0.0f, 1, 0.0f, 5.0f); // 0=main, 1=volume, 2=flow hist, 3=flow graph, 4=node chart 1, 5=node chart 2 + AddOutput("Data"); } virtual ~GraphUIChartLine() = default; @@ -104,7 +106,9 @@ namespace l::nodegraph { mNode->SetInput(2, "Chart Line"); } virtual void ProcessWriteCached(int32_t writtenSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + int32_t GetChartId() const { return mChartId; } protected: + int32_t mChartId = 0; int32_t mLatestUnixtime = 0; }; @@ -118,6 +122,8 @@ namespace l::nodegraph { AddInput2("Y1", 1, InputFlags(false, false, false, false)); AddInput2("Y2", 1, InputFlags(false, false, false, false)); AddInput2("Name", 1, InputFlags(false, true, true, true)); + AddInput("Chart ID", 0.0f, 1, 0.0f, 5.0f); // 0=main, 1=volume, 2=flow hist, 3=flow graph, 4=node chart 1, 5=node chart 2 + AddOutput("Data"); } virtual ~GraphUIChartLine2() = default; @@ -126,7 +132,9 @@ namespace l::nodegraph { mNode->SetInput(3, "Chart Line"); } virtual void ProcessWriteCached(int32_t writtenSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + int32_t GetChartId() const { return mChartId; } protected: + int32_t mChartId = 0; int32_t mLatestUnixtime = 0; }; @@ -141,6 +149,8 @@ namespace l::nodegraph { AddInput2("Y2", 1, InputFlags(false, false, false, false)); AddInput2("Y3", 1, InputFlags(false, false, false, false)); AddInput2("Name", 1, InputFlags(false, true, true, true)); + AddInput("Chart ID", 0.0f, 1, 0.0f, 5.0f); // 0=main, 1=volume, 2=flow hist, 3=flow graph, 4=node chart 1, 5=node chart 2 + AddOutput("Data"); } virtual ~GraphUIChartLine3() = default; @@ -149,7 +159,9 @@ namespace l::nodegraph { mNode->SetInput(4, "Chart Line"); } virtual void ProcessWriteCached(int32_t writtenSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + int32_t GetChartId() const { return mChartId; } protected: + int32_t mChartId = 0; int32_t mLatestUnixtime = 0; }; @@ -166,6 +178,8 @@ namespace l::nodegraph { AddInput2("Low", 1, InputFlags(false, false, false, false)); AddInput2("Volume", 1, InputFlags(false, false, false, false)); AddInput2("Name", 1, InputFlags(false, true, true, true)); + AddInput("Chart ID", 0.0f, 1, 0.0f, 5.0f); // 0=main, 1=volume, 2=flow hist, 3=flow graph, 4=node chart 1, 5=node chart 2 + AddOutput("Data"); } virtual ~GraphUICandleSticks() = default; @@ -174,7 +188,9 @@ namespace l::nodegraph { mNode->SetInput(6, "Candle Sticks"); } void ProcessWriteCached(int32_t writtenSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) override; + int32_t GetChartId() const { return mChartId; } protected: + int32_t mChartId = 0; int32_t mLatestUnixtime = 0; }; From d82508f6cf21be8004dcea3c426e4a3b89fcc1f9 Mon Sep 17 00:00:00 2001 From: wsl Date: Fri, 6 Feb 2026 10:34:55 +0100 Subject: [PATCH 163/179] Make sure input data is read. --- .../source/common/operations/NodeGraphOpUI.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index 48212890..e1a55047 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -102,6 +102,9 @@ namespace l::nodegraph { void GraphUIChartLine::ProcessWriteCached(int32_t writtenSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { int32_t mChannels = 2; + // Read Chart ID from input 3 + mChartId = static_cast(inputs.at(3).Get()); + outputs.at(0).MinimizeBuffer(numCacheSamples * mChannels); float* out = &outputs.at(0).Get(numCacheSamples * mChannels); @@ -127,6 +130,9 @@ namespace l::nodegraph { void GraphUIChartLine2::ProcessWriteCached(int32_t writtenSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { int32_t mChannels = 3; + // Read Chart ID from input 4 + mChartId = static_cast(inputs.at(4).Get()); + outputs.at(0).MinimizeBuffer(numCacheSamples * mChannels); float* out = &outputs.at(0).Get(numCacheSamples * mChannels); @@ -153,6 +159,9 @@ namespace l::nodegraph { void GraphUIChartLine3::ProcessWriteCached(int32_t writtenSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { int32_t mChannels = 4; + // Read Chart ID from input 5 + mChartId = static_cast(inputs.at(5).Get()); + outputs.at(0).MinimizeBuffer(numCacheSamples * mChannels); float* out = &outputs.at(0).Get(numCacheSamples * mChannels); @@ -178,6 +187,9 @@ namespace l::nodegraph { void GraphUICandleSticks::ProcessWriteCached(int32_t writtenSamples, int32_t numSamples, int32_t numCacheSamples, std::vector& inputs, std::vector& outputs) { const int32_t stride = 6; + // Read Chart ID from input 7 + mChartId = static_cast(inputs.at(7).Get()); + if (writtenSamples == 0) { outputs.at(0).MinimizeBuffer(numCacheSamples * stride); mLatestUnixtime = 0; From aade5377b1d92c46fbfe9de702a38da140b480a8 Mon Sep 17 00:00:00 2001 From: wsl Date: Fri, 6 Feb 2026 23:23:31 +0100 Subject: [PATCH 164/179] Build fixes. --- packages/math/include/math/MathFixedPoint.h | 2 +- packages/storage/include/storage/SequentialCache.h | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/packages/math/include/math/MathFixedPoint.h b/packages/math/include/math/MathFixedPoint.h index 078453c6..1125cc04 100644 --- a/packages/math/include/math/MathFixedPoint.h +++ b/packages/math/include/math/MathFixedPoint.h @@ -54,7 +54,7 @@ namespace l::math::fp { float toFloat() const; std::string toString() const; - template + template void getString(l::string::string_buffer& buf) const { int64_t int_part = value_ / scale_; int64_t frac_part = l::math::abs(value_ % scale_); diff --git a/packages/storage/include/storage/SequentialCache.h b/packages/storage/include/storage/SequentialCache.h index e5b51848..930b0e79 100644 --- a/packages/storage/include/storage/SequentialCache.h +++ b/packages/storage/include/storage/SequentialCache.h @@ -9,6 +9,7 @@ #include #include #include +#include #include "logging/LoggingAll.h" #include "math/MathConstants.h" @@ -25,7 +26,7 @@ namespace l::filecache { int32_t GetClampedPositionOffset(int32_t position, int32_t blockWidth); int32_t GetClampedPositionOffsetFromIndex(int32_t index, int32_t blockWidth, int32_t numBlockEntries); - template + template l::string::string_buffer CreateCacheBlockName( std::string_view prefix, int32_t blockWidth, From e0e11d092a96c80a8e260f8d9ef5a5f226adc6d0 Mon Sep 17 00:00:00 2001 From: wsl Date: Sat, 7 Feb 2026 13:37:29 +0100 Subject: [PATCH 165/179] In ui rendering, add draw mode filters for links. --- packages/rendering/include/rendering/ui/UIVisitors.h | 11 +++++++++++ packages/rendering/source/common/ui/UINodeEditor.cpp | 4 ++++ packages/rendering/source/common/ui/UIVisitors.cpp | 9 +++++++++ 3 files changed, 24 insertions(+) diff --git a/packages/rendering/include/rendering/ui/UIVisitors.h b/packages/rendering/include/rendering/ui/UIVisitors.h index efe26edd..70e7cc96 100644 --- a/packages/rendering/include/rendering/ui/UIVisitors.h +++ b/packages/rendering/include/rendering/ui/UIVisitors.h @@ -117,6 +117,12 @@ namespace l::ui { std::function mEditHandler = nullptr; }; + enum class UIDrawMode { + All, // Draw everything + LinksOnly, // Only draw link containers (for rendering behind nodes) + NoLinks // Draw everything except links (for rendering in front) + }; + class UIDraw : public UIVisitor { public: UIDraw(ImDrawList* drawList = nullptr) : mDrawList(drawList) {} @@ -128,6 +134,10 @@ namespace l::ui { mDrawList = drawList; } + void SetDrawMode(UIDrawMode mode) { + mDrawMode = mode; + } + void SetDrawChannelTextHandler(std::function handler) { mDrawChannelTextHandler = handler; } @@ -140,6 +150,7 @@ namespace l::ui { } protected: ImDrawList* mDrawList; + UIDrawMode mDrawMode = UIDrawMode::All; std::function mDrawChannelTextHandler = nullptr; std::function mDrawLineHandler = nullptr; ImColor mSelectColor = ImColor(pastellYellow); diff --git a/packages/rendering/source/common/ui/UINodeEditor.cpp b/packages/rendering/source/common/ui/UINodeEditor.cpp index 6d9f276d..abb90988 100644 --- a/packages/rendering/source/common/ui/UINodeEditor.cpp +++ b/packages/rendering/source/common/ui/UINodeEditor.cpp @@ -38,6 +38,10 @@ namespace l::ui { mUIRoot->SetLayoutSize(GetSize()); mUIRoot->SetLayoutPosition(GetPosition()); mUIRoot->Accept(updateVisitor, mUIInput, l::ui::UITraversalMode::BFS); + // Two-pass rendering: draw links first (behind), then nodes (in front) + mDrawVisitor.SetDrawMode(UIDrawMode::LinksOnly); + mUIRoot->Accept(mDrawVisitor, mUIInput, l::ui::UITraversalMode::BFS); + mDrawVisitor.SetDrawMode(UIDrawMode::NoLinks); mUIRoot->Accept(mDrawVisitor, mUIInput, l::ui::UITraversalMode::BFS); ImGui::PopItemWidth(); diff --git a/packages/rendering/source/common/ui/UIVisitors.cpp b/packages/rendering/source/common/ui/UIVisitors.cpp index d568d16e..6b23ce4a 100644 --- a/packages/rendering/source/common/ui/UIVisitors.cpp +++ b/packages/rendering/source/common/ui/UIVisitors.cpp @@ -332,6 +332,15 @@ namespace l::ui { return false; } + // Filter based on draw mode + bool isLink = container.HasConfigFlag(UIContainer_LinkFlag); + if (mDrawMode == UIDrawMode::LinksOnly && !isLink) { + return false; + } + if (mDrawMode == UIDrawMode::NoLinks && isLink) { + return false; + } + auto& layoutArea = container.GetLayoutArea(); float splineThickness = 2.0f; From 3793ea53f18ae01d584243941334d6fa783ac134 Mon Sep 17 00:00:00 2001 From: wsl Date: Mon, 9 Feb 2026 12:59:21 +0100 Subject: [PATCH 166/179] Add support for non-windows builds. --- packages/nodegraph/include/nodegraph/NodeGraphSchema.h | 6 ++++++ .../include/nodegraph/operations/NodeGraphOpDeviceIOInput.h | 4 ++++ .../nodegraph/operations/NodeGraphOpDeviceIOOutput.h | 4 ++++ .../nodegraph/include/nodegraph/operations/NodeGraphOpUI.h | 2 ++ .../source/common/operations/NodeGraphOpDeviceIOInput.cpp | 2 ++ 5 files changed, 18 insertions(+) diff --git a/packages/nodegraph/include/nodegraph/NodeGraphSchema.h b/packages/nodegraph/include/nodegraph/NodeGraphSchema.h index d7f73dad..2ce77a8a 100644 --- a/packages/nodegraph/include/nodegraph/NodeGraphSchema.h +++ b/packages/nodegraph/include/nodegraph/NodeGraphSchema.h @@ -110,9 +110,11 @@ namespace l::nodegraph { mMainNodeGraph.SetNodeFactory(this); // must set anew since schema (this) was moved as well mRegisteredNodeTypes = std::move(other.mRegisteredNodeTypes); mCustomNodeCreatorListeners = std::move(other.mCustomNodeCreatorListeners); +#ifndef HEADLESS_BUILD mKeyState = other.mKeyState; mAudioOutput = other.mAudioOutput; mMidiManager = other.mMidiManager; +#endif mRegisteredNodeTypes = std::move(other.mRegisteredNodeTypes); mPickerRootMenu = mPickerRootMenu; return *this; @@ -169,9 +171,11 @@ namespace l::nodegraph { virtual void GetArchiveData(l::serialization::JsonBuilder& jsonBuilder) override; void AddCustomNodeCreator(CustomCreateFunctionType customCreator); +#ifndef HEADLESS_BUILD void SetKeyState(l::hid::KeyState* keyState); void SetAudioOutput(l::audio::AudioStream* audioStream); void SetMidiManager(l::hid::midi::MidiManager* midiManager); +#endif int32_t NewNode(int32_t typeId, int32_t id = -1); bool RemoveNode(int32_t id); @@ -213,9 +217,11 @@ namespace l::nodegraph { NodeGraphGroup mMainNodeGraph; std::vector mCustomNodeCreatorListeners; +#ifndef HEADLESS_BUILD l::hid::KeyState* mKeyState = nullptr; l::audio::AudioStream* mAudioOutput = nullptr; l::hid::midi::MidiManager* mMidiManager = nullptr; +#endif std::map> mRegisteredNodeTypes; TreeMenuNode mPickerRootMenu; diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpDeviceIOInput.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpDeviceIOInput.h index 4a486283..1d1704bc 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpDeviceIOInput.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpDeviceIOInput.h @@ -3,12 +3,14 @@ #include "logging/LoggingAll.h" +#ifndef HEADLESS_BUILD #include "hid/KeyboardPiano.h" #include "hid/KeyState.h" #include "hid/Midi.h" #include "audio/PortAudio.h" #include "audio/AudioUtils.h" +#endif #include "math/MathFunc.h" @@ -23,6 +25,7 @@ namespace l::nodegraph { +#ifndef HEADLESS_BUILD /*********************************************************************/ class GraphInputKeyboardPiano : public NodeGraphOp, public l::audio::INoteProcessor { public: @@ -352,6 +355,7 @@ namespace l::nodegraph { l::audio::FilterRWA mFilterEnvelope; }; +#endif // HEADLESS_BUILD } diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpDeviceIOOutput.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpDeviceIOOutput.h index cc025f12..c02b8702 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpDeviceIOOutput.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpDeviceIOOutput.h @@ -3,11 +3,13 @@ #include "logging/LoggingAll.h" +#ifndef HEADLESS_BUILD #include "hid/KeyboardPiano.h" #include "hid/Midi.h" #include "audio/PortAudio.h" #include "audio/AudioUtils.h" +#endif #include "math/MathFunc.h" @@ -41,6 +43,7 @@ namespace l::nodegraph { float mValue = 0.0F; }; +#ifndef HEADLESS_BUILD /*********************************************************************/ class GraphOutputSpeaker : public NodeGraphOp { public: @@ -69,6 +72,7 @@ namespace l::nodegraph { float mRelease = 1.0f; l::audio::FilterRWA mFilterEnvelope; }; +#endif // HEADLESS_BUILD /*********************************************************************/ class GraphOutputPlot : public NodeGraphOp { diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index ca45c379..f2281e92 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -3,11 +3,13 @@ #include "logging/LoggingAll.h" +#ifndef HEADLESS_BUILD #include "hid/KeyboardPiano.h" #include "hid/Midi.h" #include "audio/PortAudio.h" #include "audio/AudioUtils.h" +#endif #include "math/MathFunc.h" diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOInput.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOInput.cpp index 255a8a4c..7e0f7c58 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOInput.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOInput.cpp @@ -1,5 +1,7 @@ #include "nodegraph/operations/NodeGraphOpDeviceIOInput.h" +#ifndef HEADLESS_BUILD + #include "logging/Log.h" #include "audio/AudioUtils.h" #include "hid/Midi.h" From ffa52f5b9557314cc178a7a1e9de224e840ff899 Mon Sep 17 00:00:00 2001 From: wsl Date: Mon, 9 Feb 2026 15:13:35 +0100 Subject: [PATCH 167/179] Add checks for headless builds. --- packages/nodegraph/source/common/NodeGraphSchema.cpp | 4 ++++ .../source/common/operations/NodeGraphOpDeviceIOInput.cpp | 2 ++ .../source/common/operations/NodeGraphOpDeviceIOOutput.cpp | 6 ++++++ 3 files changed, 12 insertions(+) diff --git a/packages/nodegraph/source/common/NodeGraphSchema.cpp b/packages/nodegraph/source/common/NodeGraphSchema.cpp index 58f023ce..24324fbd 100644 --- a/packages/nodegraph/source/common/NodeGraphSchema.cpp +++ b/packages/nodegraph/source/common/NodeGraphSchema.cpp @@ -188,6 +188,7 @@ namespace l::nodegraph { mCustomNodeCreatorListeners.emplace_back(std::move(customCreator)); } +#ifndef HEADLESS_BUILD void NodeGraphSchema::SetKeyState(l::hid::KeyState* keyState) { mKeyState = keyState; } @@ -199,6 +200,7 @@ namespace l::nodegraph { void NodeGraphSchema::SetMidiManager(l::hid::midi::MidiManager* midiManager) { mMidiManager = midiManager; } +#endif int32_t NodeGraphSchema::NewNode(int32_t typeId, int32_t id) { l::nodegraph::NodeGraphBase* node = nullptr; @@ -474,6 +476,7 @@ namespace l::nodegraph { break; +#ifndef HEADLESS_BUILD // DeviceIO (midi, keyboard piano) case 400: node = mMainNodeGraph.NewNode(id, NodeType::Default, mKeyState); @@ -511,6 +514,7 @@ namespace l::nodegraph { case 421: node = mMainNodeGraph.NewNode(id, NodeType::ExternalOutput, mAudioOutput); break; +#endif // HEADLESS_BUILD // DataIO input case 500: diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOInput.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOInput.cpp index 7e0f7c58..6f17f68a 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOInput.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOInput.cpp @@ -450,3 +450,5 @@ namespace l::nodegraph { } } + +#endif // HEADLESS_BUILD diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOOutput.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOOutput.cpp index 6c240f5b..f4fc297a 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOOutput.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOOutput.cpp @@ -1,7 +1,9 @@ #include "nodegraph/operations/NodeGraphOpDeviceIOOutput.h" #include "logging/Log.h" +#ifndef HEADLESS_BUILD #include "audio/AudioUtils.h" +#endif #include "math/MathFunc.h" @@ -17,6 +19,7 @@ namespace l::nodegraph { inputs.at(2).SetConstant(mValue); } +#ifndef HEADLESS_BUILD /*********************************************************************/ void GraphOutputSpeaker::Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector&) { if (mAudioStream == nullptr) { @@ -84,6 +87,7 @@ namespace l::nodegraph { } ); } +#endif // HEADLESS_BUILD /*********************************************************************/ void GraphOutputPlot::Process(int32_t numSamples, int32_t, std::vector& inputs, std::vector& outputs) { @@ -112,7 +116,9 @@ namespace l::nodegraph { mTimer = duration / 1000.0f; +#ifndef HEADLESS_BUILD l::audio::PCBeep(freq, duration); +#endif } if (value < 0.5f && mTriggered) { mTriggered = false; From 42018d58a4736fcd0d7cd6a43a3900e5572bd604 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 9 Feb 2026 16:21:02 +0100 Subject: [PATCH 168/179] Remove unused includes. --- .../include/nodegraph/operations/NodeGraphOpMathLogic.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathLogic.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathLogic.h index f7ebce51..5e49654d 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathLogic.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathLogic.h @@ -6,9 +6,6 @@ #include "hid/KeyboardPiano.h" #include "hid/Midi.h" -#include "audio/PortAudio.h" -#include "audio/AudioUtils.h" - #include "math/MathFunc.h" #include From c6693d5a185a6c7ee52ead559b4651adb06f8dcb Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 9 Feb 2026 16:23:26 +0100 Subject: [PATCH 169/179] Remove unused includes. --- .../include/nodegraph/operations/NodeGraphOpMathNumerical.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 73c98f3f..8877a63f 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -6,9 +6,6 @@ #include "hid/KeyboardPiano.h" #include "hid/Midi.h" -#include "audio/PortAudio.h" -#include "audio/AudioUtils.h" - #include "math/MathFunc.h" #include From 96aca87f5ae406b86611f3a04e45345c317077a5 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 9 Feb 2026 16:25:15 +0100 Subject: [PATCH 170/179] Remove unused includes. --- .../include/nodegraph/operations/NodeGraphOpMathAritmethic.h | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h index 3db6a5fa..98b1467a 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h @@ -6,9 +6,6 @@ #include "hid/KeyboardPiano.h" #include "hid/Midi.h" -#include "audio/PortAudio.h" -#include "audio/AudioUtils.h" - #include "math/MathFunc.h" #include From 4cbf46d7189e622aff013129c1277681cd0fa386 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 9 Feb 2026 16:29:21 +0100 Subject: [PATCH 171/179] Remove unused includes. --- .../nodegraph/operations/NodeGraphOpMathAritmethic.h | 3 --- .../include/nodegraph/operations/NodeGraphOpMathLogic.h | 3 --- .../include/nodegraph/operations/NodeGraphOpMathNumerical.h | 3 --- .../nodegraph/operations/NodeGraphOpTradingDetector.h | 6 ------ .../nodegraph/operations/NodeGraphOpTradingIndicator.h | 6 ------ .../source/common/operations/NodeGraphOpMathAritmethic.cpp | 1 - .../source/common/operations/NodeGraphOpMathLogic.cpp | 1 - .../source/common/operations/NodeGraphOpMathNumerical.cpp | 1 - .../source/common/operations/NodeGraphOpTradingDetector.cpp | 1 - .../common/operations/NodeGraphOpTradingIndicator.cpp | 1 - 10 files changed, 26 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h index 98b1467a..0eaedc61 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathAritmethic.h @@ -3,9 +3,6 @@ #include "logging/LoggingAll.h" -#include "hid/KeyboardPiano.h" -#include "hid/Midi.h" - #include "math/MathFunc.h" #include diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathLogic.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathLogic.h index 5e49654d..a27fe83b 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathLogic.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathLogic.h @@ -3,9 +3,6 @@ #include "logging/LoggingAll.h" -#include "hid/KeyboardPiano.h" -#include "hid/Midi.h" - #include "math/MathFunc.h" #include diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h index 8877a63f..f6338457 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpMathNumerical.h @@ -3,9 +3,6 @@ #include "logging/LoggingAll.h" -#include "hid/KeyboardPiano.h" -#include "hid/Midi.h" - #include "math/MathFunc.h" #include diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDetector.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDetector.h index 3b8528de..ce602ecd 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDetector.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingDetector.h @@ -3,12 +3,6 @@ #include "logging/LoggingAll.h" -#include "hid/KeyboardPiano.h" -#include "hid/Midi.h" - -#include "audio/PortAudio.h" -#include "audio/AudioUtils.h" - #include "math/MathFunc.h" #include diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingIndicator.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingIndicator.h index 671b497e..b6a359f8 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingIndicator.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingIndicator.h @@ -3,12 +3,6 @@ #include "logging/LoggingAll.h" -#include "hid/KeyboardPiano.h" -#include "hid/Midi.h" - -#include "audio/PortAudio.h" -#include "audio/AudioUtils.h" - #include "math/MathFunc.h" #include diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathAritmethic.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathAritmethic.cpp index fd97e3d0..d3dcb624 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathAritmethic.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathAritmethic.cpp @@ -1,7 +1,6 @@ #include "nodegraph/operations/NodeGraphOpMathAritmethic.h" #include "logging/Log.h" -#include "audio/AudioUtils.h" #include "math/MathFunc.h" diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathLogic.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathLogic.cpp index f9786148..462d09ed 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathLogic.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathLogic.cpp @@ -1,7 +1,6 @@ #include "nodegraph/operations/NodeGraphOpMathLogic.h" #include "logging/Log.h" -#include "audio/AudioUtils.h" #include "math/MathFunc.h" diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp index 581adc07..fc7c2ef2 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpMathNumerical.cpp @@ -1,7 +1,6 @@ #include "nodegraph/operations/NodeGraphOpMathNumerical.h" #include "logging/Log.h" -#include "audio/AudioUtils.h" #include "math/MathFunc.h" diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDetector.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDetector.cpp index 56401ad0..424718db 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDetector.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDetector.cpp @@ -1,7 +1,6 @@ #include "nodegraph/operations/NodeGraphOpTradingDetector.h" #include "logging/Log.h" -#include "audio/AudioUtils.h" #include "math/MathFunc.h" diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingIndicator.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingIndicator.cpp index daac797c..dced1134 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingIndicator.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingIndicator.cpp @@ -1,7 +1,6 @@ #include "nodegraph/operations/NodeGraphOpTradingIndicator.h" #include "logging/Log.h" -#include "audio/AudioUtils.h" #include "math/MathFunc.h" From d2455e0c9a80527ec98b0ba65eaf67c0f69799fc Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 9 Feb 2026 16:33:25 +0100 Subject: [PATCH 172/179] Fix some includes. --- packages/audio/include/audio/PortAudio.h | 2 +- packages/network/include/network/NetworkManager.h | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/audio/include/audio/PortAudio.h b/packages/audio/include/audio/PortAudio.h index e796eae2..11859511 100644 --- a/packages/audio/include/audio/PortAudio.h +++ b/packages/audio/include/audio/PortAudio.h @@ -7,7 +7,7 @@ #include #include -#include "../../include/portaudio.h" +#include namespace l::audio { diff --git a/packages/network/include/network/NetworkManager.h b/packages/network/include/network/NetworkManager.h index e5828e74..ed567bf8 100644 --- a/packages/network/include/network/NetworkManager.h +++ b/packages/network/include/network/NetworkManager.h @@ -6,15 +6,15 @@ #include #include -#include "curl/curl.h" +#include #ifndef CURLPIPE_MULTIPLEX #define CURLPIPE_MULTIPLEX 0 #endif -#include "logging/LoggingAll.h" -#include "concurrency/ExecutorService.h" -#include "network/NetworkConnection.h" +#include +#include +#include namespace l::network { From 4bb2ea6d697f17648618d54034b669ffc247325e Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 9 Feb 2026 16:37:54 +0100 Subject: [PATCH 173/179] Remove unused includes. --- .../nodegraph/operations/NodeGraphOpSignalFilter.h | 6 ------ .../nodegraph/operations/NodeGraphOpSignalGenerator.h | 6 ------ .../include/nodegraph/operations/NodeGraphOpSource.h | 6 ------ .../nodegraph/operations/NodeGraphOpTradingFilter.h | 6 ------ .../include/nodegraph/operations/NodeGraphOpUI.h | 8 -------- .../source/common/operations/NodeGraphOpSignalFilter.cpp | 1 - .../common/operations/NodeGraphOpSignalGenerator.cpp | 1 - .../source/common/operations/NodeGraphOpSource.cpp | 1 - .../source/common/operations/NodeGraphOpTradingDataIO.cpp | 1 - .../source/common/operations/NodeGraphOpTradingFilter.cpp | 1 - .../nodegraph/source/common/operations/NodeGraphOpUI.cpp | 1 - 11 files changed, 38 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalFilter.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalFilter.h index f314445d..7f43eedb 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalFilter.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalFilter.h @@ -3,12 +3,6 @@ #include "logging/LoggingAll.h" -#include "hid/KeyboardPiano.h" -#include "hid/Midi.h" - -#include "audio/PortAudio.h" -#include "audio/AudioUtils.h" - #include "math/MathFunc.h" #include diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalGenerator.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalGenerator.h index 22525d59..1030cadb 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalGenerator.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalGenerator.h @@ -3,12 +3,6 @@ #include "logging/LoggingAll.h" -#include "hid/KeyboardPiano.h" -#include "hid/Midi.h" - -#include "audio/PortAudio.h" -#include "audio/AudioUtils.h" - #include "math/MathFunc.h" #include diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSource.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSource.h index 626bc3e7..8376af82 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSource.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSource.h @@ -3,12 +3,6 @@ #include "logging/LoggingAll.h" -#include "hid/KeyboardPiano.h" -#include "hid/Midi.h" - -#include "audio/PortAudio.h" -#include "audio/AudioUtils.h" - #include "math/MathFunc.h" #include diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingFilter.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingFilter.h index b51f3c66..22adb3cc 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingFilter.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpTradingFilter.h @@ -3,12 +3,6 @@ #include "logging/LoggingAll.h" -#include "hid/KeyboardPiano.h" -#include "hid/Midi.h" - -#include "audio/PortAudio.h" -#include "audio/AudioUtils.h" - #include "math/MathFunc.h" #include diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h index f2281e92..27d5de93 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpUI.h @@ -3,14 +3,6 @@ #include "logging/LoggingAll.h" -#ifndef HEADLESS_BUILD -#include "hid/KeyboardPiano.h" -#include "hid/Midi.h" - -#include "audio/PortAudio.h" -#include "audio/AudioUtils.h" -#endif - #include "math/MathFunc.h" #include diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpSignalFilter.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpSignalFilter.cpp index ad4e3dec..95607e3f 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpSignalFilter.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpSignalFilter.cpp @@ -1,7 +1,6 @@ #include "nodegraph/operations/NodeGraphOpSignalFilter.h" #include "logging/Log.h" -#include "audio/AudioUtils.h" #include "math/MathFunc.h" diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpSignalGenerator.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpSignalGenerator.cpp index 4f4ce4df..ddd7b800 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpSignalGenerator.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpSignalGenerator.cpp @@ -1,7 +1,6 @@ #include "nodegraph/operations/NodeGraphOpSignalGenerator.h" #include "logging/Log.h" -#include "audio/AudioUtils.h" #include "math/MathFunc.h" diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpSource.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpSource.cpp index 6cb8d874..cc05dfa1 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpSource.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpSource.cpp @@ -1,7 +1,6 @@ #include "nodegraph/operations/NodeGraphOpSource.h" #include "logging/Log.h" -#include "audio/AudioUtils.h" #include "math/MathFunc.h" diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp index dd6727db..6f67f4bb 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingDataIO.cpp @@ -1,7 +1,6 @@ #include "nodegraph/operations/NodeGraphOpTradingDataIO.h" #include "logging/Log.h" -#include "audio/AudioUtils.h" #include diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpTradingFilter.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpTradingFilter.cpp index 2c547fd0..edbfff83 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpTradingFilter.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpTradingFilter.cpp @@ -1,7 +1,6 @@ #include "nodegraph/operations/NodeGraphOpTradingFilter.h" #include "logging/Log.h" -#include "audio/AudioUtils.h" #include "math/MathFunc.h" diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp index e1a55047..a17aeed8 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpUI.cpp @@ -1,7 +1,6 @@ #include "nodegraph/operations/NodeGraphOpUI.h" #include "logging/Log.h" -#include "audio/AudioUtils.h" #include "math/MathFunc.h" From 3f0b4340a54de7ac43135f83f9614836ff5236f3 Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 9 Feb 2026 19:09:07 +0100 Subject: [PATCH 174/179] Remove unused includes. --- .../include/nodegraph/operations/NodeGraphOpSignalControl.h | 6 ------ .../include/nodegraph/operations/NodeGraphOpSignalEffect.h | 6 ------ .../source/common/operations/NodeGraphOpDeviceIOInput.cpp | 1 - .../source/common/operations/NodeGraphOpDeviceIOOutput.cpp | 3 --- .../source/common/operations/NodeGraphOpSignalControl.cpp | 1 - .../source/common/operations/NodeGraphOpSignalEffect.cpp | 1 - 6 files changed, 18 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalControl.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalControl.h index 0f828361..ae3a9877 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalControl.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalControl.h @@ -3,12 +3,6 @@ #include "logging/LoggingAll.h" -#include "hid/KeyboardPiano.h" -#include "hid/Midi.h" - -#include "audio/PortAudio.h" -#include "audio/AudioUtils.h" - #include "math/MathFunc.h" #include diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalEffect.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalEffect.h index 13148512..5e355aa0 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalEffect.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpSignalEffect.h @@ -3,12 +3,6 @@ #include "logging/LoggingAll.h" -#include "hid/KeyboardPiano.h" -#include "hid/Midi.h" - -#include "audio/PortAudio.h" -#include "audio/AudioUtils.h" - #include "math/MathFunc.h" #include diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOInput.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOInput.cpp index 6f17f68a..bf3f95a0 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOInput.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOInput.cpp @@ -448,7 +448,6 @@ namespace l::nodegraph { } ); } - } #endif // HEADLESS_BUILD diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOOutput.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOOutput.cpp index f4fc297a..c74ce80d 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOOutput.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpDeviceIOOutput.cpp @@ -1,9 +1,6 @@ #include "nodegraph/operations/NodeGraphOpDeviceIOOutput.h" #include "logging/Log.h" -#ifndef HEADLESS_BUILD -#include "audio/AudioUtils.h" -#endif #include "math/MathFunc.h" diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpSignalControl.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpSignalControl.cpp index 329c62ca..bac97630 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpSignalControl.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpSignalControl.cpp @@ -1,7 +1,6 @@ #include "nodegraph/operations/NodeGraphOpSignalControl.h" #include "logging/Log.h" -#include "audio/AudioUtils.h" #include "math/MathFunc.h" #include "math/MathSmooth.h" diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpSignalEffect.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpSignalEffect.cpp index 0cb0edc7..6e8ee3fe 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpSignalEffect.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpSignalEffect.cpp @@ -1,7 +1,6 @@ #include "nodegraph/operations/NodeGraphOpSignalEffect.h" #include "logging/Log.h" -#include "audio/AudioUtils.h" #include "math/MathFunc.h" #include "math/MathSmooth.h" From 9887aa803ddf5717099c46d39f267c31ff0f89ed Mon Sep 17 00:00:00 2001 From: lnd3 Date: Mon, 9 Feb 2026 19:19:28 +0100 Subject: [PATCH 175/179] Remove unused include. --- .../include/nodegraph/operations/NodeGraphOpDataIO.h | 6 ------ .../source/common/operations/NodeGraphOpDataIO.cpp | 1 - 2 files changed, 7 deletions(-) diff --git a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpDataIO.h b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpDataIO.h index 1a29f7a0..409747ec 100644 --- a/packages/nodegraph/include/nodegraph/operations/NodeGraphOpDataIO.h +++ b/packages/nodegraph/include/nodegraph/operations/NodeGraphOpDataIO.h @@ -3,12 +3,6 @@ #include "logging/LoggingAll.h" -#include "hid/KeyboardPiano.h" -#include "hid/Midi.h" - -#include "audio/PortAudio.h" -#include "audio/AudioUtils.h" - #include "math/MathFunc.h" #include diff --git a/packages/nodegraph/source/common/operations/NodeGraphOpDataIO.cpp b/packages/nodegraph/source/common/operations/NodeGraphOpDataIO.cpp index faec935a..676e828c 100644 --- a/packages/nodegraph/source/common/operations/NodeGraphOpDataIO.cpp +++ b/packages/nodegraph/source/common/operations/NodeGraphOpDataIO.cpp @@ -1,7 +1,6 @@ #include "nodegraph/operations/NodeGraphOpDataIO.h" #include "logging/Log.h" -#include "audio/AudioUtils.h" #include "math/MathFunc.h" From cd0db4ce2d9cafdb923d7e840c7a78163aad1137 Mon Sep 17 00:00:00 2001 From: wsl Date: Mon, 9 Feb 2026 21:13:26 +0100 Subject: [PATCH 176/179] use more compatible template arg. --- packages/logging/include/logging/String.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/logging/include/logging/String.h b/packages/logging/include/logging/String.h index 84cedc40..ce0e40e7 100644 --- a/packages/logging/include/logging/String.h +++ b/packages/logging/include/logging/String.h @@ -183,14 +183,14 @@ namespace l::string { } } - template + template void get_local_time(string_buffer& buf, const int32_t unixtime) { struct std::tm tminfo = {}; convert_to_local_tm_from_utc_time(unixtime, &tminfo, false); buf.printf("%02d:%02d:%02d", tminfo.tm_hour, tminfo.tm_min, tminfo.tm_sec); } - template + template void get_local_date_and_time(string_buffer& buf, const int32_t unixtime, bool fullYear = false) { struct std::tm tminfo = {}; convert_to_local_tm_from_utc_time(unixtime, &tminfo, true); From ae1c74272f0ad0edcbca33cce0ab7c9f27f06ca0 Mon Sep 17 00:00:00 2001 From: wsl Date: Tue, 10 Feb 2026 22:25:39 +0100 Subject: [PATCH 177/179] Add claude.md. --- CLAUDE.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 CLAUDE.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 00000000..c146ffe2 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,21 @@ +# ltools project + +## What This Is +`ltools` is a modern c++ library consisting of a collection of packages and tools for modern c++ development, organized around the build system `bs` from `ldeps`. Packages found at `packages/**`. + +## Notable Packages +- **Node graph system**: Package `ecs`. Location `packages/ecs`. `NodeGraphOp` base class, inputs/outputs, cache blocks. +- **ECS**: Package `ecs`. Location `packages/nodegraph`. Entity component system. Entity contains components. Components contain data structures. Iterate over component groups in systems and do work on components and/or entities. Access any data by name or id. + +## Dependencies +- **ldeps**: Location `deps/ldeps`. See `deps/ldeps/CLAUDE.md`. + +## Coding Patterns +As required by `bs`, packages have a certain layout: `${package_name}/[include/${package_name}/|source/common|tests/common|]`. + +### Node graph +- Node inputs: `AddInput2("Name")` for connected, `AddInput("Name", default, size, min, max)` for params +- Node outputs: `AddOutput("name")` +- Process signature: `Process(int32_t numSamples, int32_t numCacheSamples, inputs, outputs)` +- Registration: `schema.RegisterNodeType("Category", ID, "Name", "Description")` + switch case + From 359326e0e850f12345346539542c93b5a86aac5a Mon Sep 17 00:00:00 2001 From: wsl Date: Tue, 10 Feb 2026 23:09:00 +0100 Subject: [PATCH 178/179] Fix and expand CLAUDE.md documentation. Fix swapped ecs/nodegraph descriptions. List all 19 packages with namespaces. Expand node graph coding patterns with cached variants, schema details, and NodeType requirements. Co-Authored-By: Claude Opus 4.6 --- CLAUDE.md | 32 ++++++++++++++++++++++++++------ 1 file changed, 26 insertions(+), 6 deletions(-) diff --git a/CLAUDE.md b/CLAUDE.md index c146ffe2..1bff7db7 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,11 +1,28 @@ # ltools project ## What This Is -`ltools` is a modern c++ library consisting of a collection of packages and tools for modern c++ development, organized around the build system `bs` from `ldeps`. Packages found at `packages/**`. +`ltools` is a modern C++ library consisting of a collection of packages and tools for modern C++ development, organized around the build system `bs` from `ldeps`. Packages found at `packages/**`. ## Notable Packages -- **Node graph system**: Package `ecs`. Location `packages/ecs`. `NodeGraphOp` base class, inputs/outputs, cache blocks. -- **ECS**: Package `ecs`. Location `packages/nodegraph`. Entity component system. Entity contains components. Components contain data structures. Iterate over component groups in systems and do work on components and/or entities. Access any data by name or id. +- **nodegraph**: Package `nodegraph`. Location `packages/nodegraph`. Node graph system. `NodeGraphOp` base class, `NodeGraphOpCached` for cached operations, inputs/outputs, cache blocks, `NodeGraphSchema` with Load/Save/JSON serialization and node factory. Includes trading-specific operations (data IO, detectors, filters, indicators). Namespace: `l::nodegraph`. +- **ecs**: Package `ecs`. Location `packages/ecs`. Entity component system. Entity contains components. Components contain data structures. Iterate over component groups in systems and do work on components and/or entities. Access any data by name or id. Namespace: `l::ecs`. +- **rendering**: Package `rendering`. Location `packages/rendering`. UI and rendering via ImGui/ImPlot. Namespace: `l::ui`. +- **serialization**: Package `serialization`. Location `packages/serialization`. JSON serialization framework (`JsonSerializationBase`, `JsonBuilder`, `JsonValue`). Used by `NodeGraphSchema` for persistence. Namespace: `l::serialization`. +- **math**: Package `math`. Location `packages/math`. Math utilities, tweening, algorithms. Namespace: `l::math`. +- **network**: Package `network`. Location `packages/network`. Network communication. Namespace: `l::network`. +- **nn**: Package `nn`. Location `packages/nn`. Neural network utilities. Namespace: `l::nn`. +- **memory**: Package `memory`. Location `packages/memory`. Containers and memory management. Namespace: `l::container`. +- **concurrency**: Package `concurrency`. Location `packages/concurrency`. Threading and synchronization. Namespace: `l::concurrency`. +- **audio**: Package `audio`. Location `packages/audio`. Audio utilities. Namespace: `l::audio`. +- **hid**: Package `hid`. Location `packages/hid`. Human input device and MIDI. Namespace: `l::hid`. +- **physics**: Package `physics`. Location `packages/physics`. Physics simulation and octree. Namespace: `l::physics`. +- **crypto**: Package `crypto`. Location `packages/crypto`. Cryptography utilities. Namespace: `l::crypto`. +- **filesystem**: Package `filesystem`. Location `packages/filesystem`. File system utilities. Namespace: `l::filesystem`. +- **storage**: Package `storage`. Location `packages/storage`. File caching and storage. Namespace: `l::filecache`. +- **logging**: Package `logging`. Location `packages/logging`. Logging system. Namespace: `l::logging`. +- **tools**: Package `tools`. Location `packages/tools`. Signal utilities and tools. Namespace: `l::signals`. +- **meta**: Package `meta`. Location `packages/meta`. Reflection and type info. Namespace: `l::meta`. +- **testing**: Package `testing`. Location `packages/testing`. Test utilities. Namespace: `l::testing`. ## Dependencies - **ldeps**: Location `deps/ldeps`. See `deps/ldeps/CLAUDE.md`. @@ -14,8 +31,11 @@ As required by `bs`, packages have a certain layout: `${package_name}/[include/${package_name}/|source/common|tests/common|]`. ### Node graph -- Node inputs: `AddInput2("Name")` for connected, `AddInput("Name", default, size, min, max)` for params +- Base class: `NodeGraphOp` in `packages/nodegraph/include/nodegraph/core/NodeGraphBase.h` +- Cached base class: `NodeGraphOpCached` — adds `ProcessWriteCached()` and `ProcessReadCached()` for buffered processing +- Schema: `NodeGraphSchema` inherits `JsonSerializationBase` and `NodeFactoryBase` — provides `Load()`, `Save()`, `RegisterNodeType()`, `NewNode()` +- Node inputs: `AddInput2("Name")` for connected, `AddInput("Name", default, size, min, max)` for params, `AddConstant("Name", default, size, min, max)` for constants - Node outputs: `AddOutput("name")` -- Process signature: `Process(int32_t numSamples, int32_t numCacheSamples, inputs, outputs)` +- Process signature: `Process(int32_t numSamples, int32_t numCacheSamples, std::vector&, std::vector&)` - Registration: `schema.RegisterNodeType("Category", ID, "Name", "Description")` + switch case - +- Node creation: `group.NewNode(id, NodeType::Default)` — NodeType required (`Default`, `ExternalInput`, `ExternalOutput`) From f97263917855bf98385ee2d4f162288b2ca32615 Mon Sep 17 00:00:00 2001 From: wsl Date: Wed, 11 Feb 2026 05:27:30 +0100 Subject: [PATCH 179/179] Fix nn shared lib copies for Linux and CPU-only libtorch. Co-Authored-By: Claude Opus 4.6 --- packages/nn/CMakeLists.txt | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/packages/nn/CMakeLists.txt b/packages/nn/CMakeLists.txt index 324f94c0..95d93e53 100644 --- a/packages/nn/CMakeLists.txt +++ b/packages/nn/CMakeLists.txt @@ -32,13 +32,25 @@ if(TARGET libtorch_wrapper) target_compile_definitions(nn PUBLIC HAS_LIBTORCH=1) target_compile_definitions(nn_test PUBLIC HAS_LIBTORCH=1) - bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/c10") - bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/c10_cuda") - bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch") - bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch_cpu") - bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch_cuda") - bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/libiomp5md") - bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/cupti64_2025.3.0") + if(WIN32) + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/c10") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch_cpu") + if(USE_LIBTORCH_CUDA) + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/c10_cuda") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/torch_cuda") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/libiomp5md") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/cupti64_2025.3.0") + endif() + else() + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/libc10") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/libtorch") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/libtorch_cpu") + if(USE_LIBTORCH_CUDA) + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/libc10_cuda") + bs_copy_shared_lib(nn_test "${LDEPS_LIBTORCH_LIB_DIR}/libtorch_cuda") + endif() + endif() endif() if(MSVC)