mirror of
https://github.com/Microsoft/calculator.git
synced 2025-08-14 02:26:50 -07:00
refactor draft
This commit is contained in:
parent
2571d38a2e
commit
1de66142b5
6 changed files with 177 additions and 784 deletions
|
@ -97,19 +97,11 @@ namespace GraphControl
|
|||
{
|
||||
if (auto renderer = m_graph->GetRenderer())
|
||||
{
|
||||
m_renderMain->GetCriticalSection().lock();
|
||||
|
||||
if (SUCCEEDED(renderer->ScaleRange(centerX, centerY, scale)))
|
||||
{
|
||||
m_renderMain->GetCriticalSection().unlock();
|
||||
|
||||
m_renderMain->RunRenderPass();
|
||||
m_renderMain->FireRenderPass();
|
||||
GraphViewChangedEvent(this, GraphViewChangedReason::Manipulation);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_renderMain->GetCriticalSection().unlock();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -145,7 +137,7 @@ namespace GraphControl
|
|||
|
||||
if (SUCCEEDED(hr))
|
||||
{
|
||||
m_renderMain->RunRenderPass();
|
||||
m_renderMain->FireRenderPass();
|
||||
GraphViewChangedEvent(this, GraphViewChangedReason::Reset);
|
||||
}
|
||||
}
|
||||
|
@ -158,8 +150,8 @@ namespace GraphControl
|
|||
if (swapChainPanel)
|
||||
{
|
||||
swapChainPanel->AllowFocusOnInteraction = true;
|
||||
m_renderMain = ref new RenderMain(swapChainPanel);
|
||||
m_renderMain->BackgroundColor = GraphBackground;
|
||||
m_renderMain = std::make_unique<DX::RenderMain>(swapChainPanel, m_graph.get());
|
||||
m_renderMain->BackgroundColor(GraphBackground);
|
||||
}
|
||||
|
||||
TryUpdateGraph(false);
|
||||
|
@ -220,7 +212,7 @@ namespace GraphControl
|
|||
|
||||
if (m_renderMain)
|
||||
{
|
||||
m_renderMain->RunRenderPass();
|
||||
m_renderMain->FireRenderPass();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -404,11 +396,9 @@ namespace GraphControl
|
|||
UpdateGraphOptions(m_graph->GetOptions(), validEqs);
|
||||
SetGraphArgs(m_graph);
|
||||
|
||||
m_renderMain->Graph = m_graph;
|
||||
|
||||
// It is possible that the render fails, in that case fall through to explicit empty initialization
|
||||
co_await m_renderMain->RunRenderPassAsync(false);
|
||||
if (m_renderMain->IsRenderPassSuccesful())
|
||||
auto succ = co_await m_renderMain->RunRenderPassAsync();
|
||||
if (succ)
|
||||
{
|
||||
UpdateVariables();
|
||||
successful = true;
|
||||
|
@ -438,7 +428,6 @@ namespace GraphControl
|
|||
UpdateGraphOptions(m_graph->GetOptions(), vector<Equation ^>());
|
||||
SetGraphArgs(m_graph);
|
||||
|
||||
m_renderMain->Graph = m_graph;
|
||||
co_await m_renderMain->RunRenderPassAsync();
|
||||
|
||||
UpdateVariables();
|
||||
|
@ -479,8 +468,6 @@ namespace GraphControl
|
|||
{
|
||||
if (graph != nullptr && m_renderMain != nullptr)
|
||||
{
|
||||
critical_section::scoped_lock lock(m_renderMain->GetCriticalSection());
|
||||
|
||||
for (auto variablePair : Variables)
|
||||
{
|
||||
graph->SetArgValue(variablePair->Key->Data(), variablePair->Value->Value);
|
||||
|
@ -557,15 +544,8 @@ namespace GraphControl
|
|||
|
||||
if (m_graph != nullptr && m_renderMain != nullptr)
|
||||
{
|
||||
auto workItemHandler = ref new WorkItemHandler([this, variableName, newValue](IAsyncAction ^ action) {
|
||||
m_renderMain->GetCriticalSection().lock();
|
||||
m_graph->SetArgValue(variableName->Data(), newValue);
|
||||
m_renderMain->GetCriticalSection().unlock();
|
||||
|
||||
m_renderMain->RunRenderPass();
|
||||
});
|
||||
|
||||
ThreadPool::RunAsync(workItemHandler, WorkItemPriority::High, WorkItemOptions::None);
|
||||
m_graph->SetArgValue(variableName->Data(), newValue);
|
||||
m_renderMain->FireRenderPass();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -668,7 +648,7 @@ namespace GraphControl
|
|||
m_renderMain->DrawNearestPoint = true;
|
||||
Point currPosition = e->GetCurrentPoint(/* relativeTo */ this)->Position;
|
||||
|
||||
if (m_renderMain->ActiveTracing)
|
||||
if (m_renderMain->ActiveTracing())
|
||||
{
|
||||
PointerValueChangedEvent(currPosition);
|
||||
ActiveTraceCursorPosition = currPosition;
|
||||
|
@ -681,7 +661,7 @@ namespace GraphControl
|
|||
}
|
||||
else if (m_cachedCursor != nullptr)
|
||||
{
|
||||
m_renderMain->PointerLocation = currPosition;
|
||||
m_renderMain->PointerLocation(currPosition);
|
||||
|
||||
::CoreWindow::GetForCurrentThread()->PointerCursor = m_cachedCursor;
|
||||
m_cachedCursor = nullptr;
|
||||
|
@ -690,7 +670,7 @@ namespace GraphControl
|
|||
}
|
||||
else
|
||||
{
|
||||
m_renderMain->PointerLocation = currPosition;
|
||||
m_renderMain->PointerLocation(currPosition);
|
||||
UpdateTracingChanged();
|
||||
}
|
||||
|
||||
|
@ -783,15 +763,10 @@ namespace GraphControl
|
|||
translationX /= -width;
|
||||
translationY /= height;
|
||||
|
||||
m_renderMain->GetCriticalSection().lock();
|
||||
|
||||
if (FAILED(renderer->MoveRangeByRatio(translationX, translationY)))
|
||||
{
|
||||
m_renderMain->GetCriticalSection().unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
m_renderMain->GetCriticalSection().unlock();
|
||||
needsRenderPass = true;
|
||||
}
|
||||
|
||||
|
@ -805,21 +780,16 @@ namespace GraphControl
|
|||
const auto& pos = e->Position;
|
||||
const auto [centerX, centerY] = PointerPositionToGraphPosition(pos.X, pos.Y, width, height);
|
||||
|
||||
m_renderMain->GetCriticalSection().lock();
|
||||
|
||||
if (FAILED(renderer->ScaleRange(centerX, centerY, scale)))
|
||||
{
|
||||
m_renderMain->GetCriticalSection().unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
m_renderMain->GetCriticalSection().unlock();
|
||||
needsRenderPass = true;
|
||||
}
|
||||
|
||||
if (needsRenderPass)
|
||||
{
|
||||
m_renderMain->RunRenderPass();
|
||||
m_renderMain->FireRenderPass();
|
||||
GraphViewChangedEvent(this, GraphViewChangedReason::Manipulation);
|
||||
}
|
||||
}
|
||||
|
@ -1075,7 +1045,7 @@ void Grapher::OnGraphBackgroundPropertyChanged(Windows::UI::Color /*oldValue*/,
|
|||
{
|
||||
if (m_renderMain)
|
||||
{
|
||||
m_renderMain->BackgroundColor = newValue;
|
||||
m_renderMain->BackgroundColor(newValue);
|
||||
}
|
||||
if (m_graph)
|
||||
{
|
||||
|
@ -1091,7 +1061,7 @@ void Grapher::OnGridLinesColorPropertyChanged(Windows::UI::Color /*oldValue*/, W
|
|||
{
|
||||
auto gridLinesColor = Graphing::Color(newValue.R, newValue.G, newValue.B, newValue.A);
|
||||
m_graph->GetOptions().SetGridColor(gridLinesColor);
|
||||
m_renderMain->RunRenderPassAsync();
|
||||
m_renderMain->FireRenderPass();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1102,8 +1072,8 @@ void Grapher::OnLineWidthPropertyChanged(double oldValue, double newValue)
|
|||
UpdateGraphOptions(m_graph->GetOptions(), GetGraphableEquations());
|
||||
if (m_renderMain)
|
||||
{
|
||||
m_renderMain->SetPointRadius(LineWidth + 1);
|
||||
m_renderMain->RunRenderPass();
|
||||
m_renderMain->PointRadius(LineWidth + 1);
|
||||
m_renderMain->FireRenderPass();
|
||||
|
||||
TraceLogger::GetInstance()->LogLineWidthChanged();
|
||||
}
|
||||
|
@ -1112,7 +1082,6 @@ void Grapher::OnLineWidthPropertyChanged(double oldValue, double newValue)
|
|||
|
||||
optional<vector<shared_ptr<Graphing::IEquation>>> Grapher::TryInitializeGraph(bool keepCurrentView, const IExpression* graphingExp)
|
||||
{
|
||||
critical_section::scoped_lock lock(m_renderMain->GetCriticalSection());
|
||||
if (keepCurrentView || IsKeepCurrentView)
|
||||
{
|
||||
auto renderer = m_graph->GetRenderer();
|
||||
|
|
|
@ -25,11 +25,12 @@ public
|
|||
public
|
||||
delegate void PointerValueChangedEventHandler(Windows::Foundation::Point value);
|
||||
|
||||
public enum class GraphViewChangedReason
|
||||
{
|
||||
Manipulation,
|
||||
Reset
|
||||
};
|
||||
public
|
||||
enum class GraphViewChangedReason
|
||||
{
|
||||
Manipulation,
|
||||
Reset
|
||||
};
|
||||
|
||||
[Windows::UI::Xaml::Markup::ContentPropertyAttribute(Name = L"Equations")] public ref class Grapher sealed
|
||||
: public Windows::UI::Xaml::Controls::Control,
|
||||
|
@ -65,14 +66,14 @@ public enum class GraphViewChangedReason
|
|||
{
|
||||
bool get()
|
||||
{
|
||||
return m_renderMain != nullptr && m_renderMain->ActiveTracing;
|
||||
return m_renderMain != nullptr && m_renderMain->ActiveTracing();
|
||||
}
|
||||
|
||||
void set(bool value)
|
||||
{
|
||||
if (m_renderMain != nullptr && m_renderMain->ActiveTracing != value)
|
||||
if (m_renderMain != nullptr && m_renderMain->ActiveTracing() != value)
|
||||
{
|
||||
m_renderMain->ActiveTracing = value;
|
||||
m_renderMain->ActiveTracing(value);
|
||||
UpdateTracingChanged();
|
||||
PropertyChanged(this, ref new Windows::UI::Xaml::Data::PropertyChangedEventArgs(L"ActiveTracing"));
|
||||
}
|
||||
|
@ -86,7 +87,7 @@ public enum class GraphViewChangedReason
|
|||
{
|
||||
Windows::Foundation::Point get()
|
||||
{
|
||||
return m_renderMain->TraceLocation;
|
||||
return m_renderMain->TraceLocation();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -94,14 +95,14 @@ public enum class GraphViewChangedReason
|
|||
{
|
||||
Windows::Foundation::Point get()
|
||||
{
|
||||
return m_renderMain->ActiveTraceCursorPosition;
|
||||
return m_renderMain->ActiveTraceCursorPosition();
|
||||
}
|
||||
|
||||
void set(Windows::Foundation::Point newValue)
|
||||
{
|
||||
if (m_renderMain->ActiveTraceCursorPosition != newValue)
|
||||
if (m_renderMain->ActiveTraceCursorPosition() != newValue)
|
||||
{
|
||||
m_renderMain->ActiveTraceCursorPosition = newValue;
|
||||
m_renderMain->ActiveTraceCursorPosition(newValue);
|
||||
UpdateTracingChanged();
|
||||
}
|
||||
}
|
||||
|
@ -154,7 +155,7 @@ public enum class GraphViewChangedReason
|
|||
m_graph->GetOptions().SetDefaultXRange(newValue);
|
||||
if (m_renderMain != nullptr)
|
||||
{
|
||||
m_renderMain->RunRenderPass();
|
||||
m_renderMain->FireRenderPass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -174,7 +175,7 @@ public enum class GraphViewChangedReason
|
|||
m_graph->GetOptions().SetDefaultXRange(newValue);
|
||||
if (m_renderMain != nullptr)
|
||||
{
|
||||
m_renderMain->RunRenderPass();
|
||||
m_renderMain->FireRenderPass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -194,7 +195,7 @@ public enum class GraphViewChangedReason
|
|||
m_graph->GetOptions().SetDefaultYRange(newValue);
|
||||
if (m_renderMain != nullptr)
|
||||
{
|
||||
m_renderMain->RunRenderPass();
|
||||
m_renderMain->FireRenderPass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -214,7 +215,7 @@ public enum class GraphViewChangedReason
|
|||
m_graph->GetOptions().SetDefaultYRange(newValue);
|
||||
if (m_renderMain != nullptr)
|
||||
{
|
||||
m_renderMain->RunRenderPass();
|
||||
m_renderMain->FireRenderPass();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -228,7 +229,6 @@ public enum class GraphViewChangedReason
|
|||
{
|
||||
if (auto render = m_graph->GetRenderer())
|
||||
{
|
||||
Concurrency::critical_section::scoped_lock lock(m_renderMain->GetCriticalSection());
|
||||
render->GetDisplayRanges(*xMin, *xMax, *yMin, *yMax);
|
||||
}
|
||||
}
|
||||
|
@ -249,7 +249,7 @@ public enum class GraphViewChangedReason
|
|||
m_rangeUpdatedBySettings = true;
|
||||
if (m_renderMain)
|
||||
{
|
||||
m_renderMain->RunRenderPass();
|
||||
m_renderMain->FireRenderPass();
|
||||
GraphViewChangedEvent(this, GraphViewChangedReason::Manipulation);
|
||||
}
|
||||
}
|
||||
|
@ -304,12 +304,10 @@ public enum class GraphViewChangedReason
|
|||
|
||||
void SetEquationsAsValid();
|
||||
void SetEquationErrors();
|
||||
std::optional<std::vector<std::shared_ptr<Graphing::IEquation>>> TryInitializeGraph(bool keepCurrentView, _In_ const Graphing::IExpression* graphingExp = nullptr);
|
||||
|
||||
std::optional<std::vector<std::shared_ptr<Graphing::IEquation>>>
|
||||
TryInitializeGraph(bool keepCurrentView, _In_ const Graphing::IExpression* graphingExp = nullptr);
|
||||
|
||||
private:
|
||||
DX::RenderMain ^ m_renderMain = nullptr;
|
||||
|
||||
static Windows::UI::Xaml::DependencyProperty ^ s_equationTemplateProperty;
|
||||
|
||||
static Windows::UI::Xaml::DependencyProperty ^ s_equationsSourceProperty;
|
||||
|
@ -326,6 +324,7 @@ public enum class GraphViewChangedReason
|
|||
|
||||
const std::unique_ptr<Graphing::IMathSolver> m_solver;
|
||||
const std::shared_ptr<Graphing::IGraph> m_graph;
|
||||
std::unique_ptr<DX::RenderMain> m_renderMain;
|
||||
bool m_calculatedForceProportional = false;
|
||||
bool m_tracingTracking;
|
||||
bool m_trigUnitsChanged;
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace ScreenRotation
|
|||
namespace GraphControl::DX
|
||||
{
|
||||
// Constructor for DeviceResources.
|
||||
DeviceResources::DeviceResources(SwapChainPanel^ panel) :
|
||||
DeviceResources::DeviceResources(SwapChainPanel^ panel, IDeviceNotify* deviceNotify) :
|
||||
m_screenViewport(),
|
||||
m_d3dFeatureLevel(D3D_FEATURE_LEVEL_9_1),
|
||||
m_d3dRenderTargetSize(),
|
||||
|
@ -83,7 +83,7 @@ namespace GraphControl::DX
|
|||
m_effectiveDpi(-1.0f),
|
||||
m_compositionScaleX(1.0f),
|
||||
m_compositionScaleY(1.0f),
|
||||
m_deviceNotify(nullptr)
|
||||
m_deviceNotify(deviceNotify)
|
||||
{
|
||||
CreateDeviceIndependentResources();
|
||||
CreateDeviceResources();
|
||||
|
@ -612,12 +612,6 @@ namespace GraphControl::DX
|
|||
}
|
||||
}
|
||||
|
||||
// Register our DeviceNotify to be informed on device lost and creation.
|
||||
void DeviceResources::RegisterDeviceNotify(DX::IDeviceNotify^ deviceNotify)
|
||||
{
|
||||
m_deviceNotify = deviceNotify;
|
||||
}
|
||||
|
||||
// Call this method when the app suspends. It provides a hint to the driver that the app
|
||||
// is entering an idle state and that temporary buffers can be reclaimed for use by other apps.
|
||||
void DeviceResources::Trim()
|
||||
|
|
|
@ -8,17 +8,17 @@
|
|||
namespace GraphControl::DX
|
||||
{
|
||||
// Provides an interface for an application that owns DeviceResources to be notified of the device being lost or created.
|
||||
interface class IDeviceNotify
|
||||
struct IDeviceNotify
|
||||
{
|
||||
virtual void OnDeviceLost();
|
||||
virtual void OnDeviceRestored();
|
||||
virtual void OnDeviceLost() = 0;
|
||||
virtual void OnDeviceRestored() = 0;
|
||||
};
|
||||
|
||||
// Controls all the DirectX device resources.
|
||||
class DeviceResources
|
||||
{
|
||||
public:
|
||||
DeviceResources(Windows::UI::Xaml::Controls::SwapChainPanel^ panel);
|
||||
explicit DeviceResources(Windows::UI::Xaml::Controls::SwapChainPanel^ panel, IDeviceNotify* deviceNotify);
|
||||
void SetSwapChainPanel(Windows::UI::Xaml::Controls::SwapChainPanel^ panel);
|
||||
void SetLogicalSize(Windows::Foundation::Size logicalSize);
|
||||
void SetCurrentOrientation(Windows::Graphics::Display::DisplayOrientations currentOrientation);
|
||||
|
@ -26,7 +26,6 @@ namespace GraphControl::DX
|
|||
void SetCompositionScale(float compositionScaleX, float compositionScaleY);
|
||||
void ValidateDevice();
|
||||
void HandleDeviceLost();
|
||||
void RegisterDeviceNotify(IDeviceNotify^ deviceNotify);
|
||||
void Trim();
|
||||
void Present();
|
||||
|
||||
|
@ -106,6 +105,6 @@ namespace GraphControl::DX
|
|||
DirectX::XMFLOAT4X4 m_orientationTransform3D;
|
||||
|
||||
// The IDeviceNotify can be held directly as it owns the DeviceResources.
|
||||
IDeviceNotify^ m_deviceNotify;
|
||||
IDeviceNotify* m_deviceNotify;
|
||||
};
|
||||
}
|
||||
|
|
|
@ -5,16 +5,7 @@
|
|||
#include "RenderMain.h"
|
||||
#include "DirectXHelper.h"
|
||||
|
||||
using namespace Concurrency;
|
||||
using namespace Graphing;
|
||||
using namespace Platform;
|
||||
using namespace std;
|
||||
using namespace Windows::Foundation;
|
||||
using namespace Windows::Graphics::Display;
|
||||
using namespace Windows::System::Threading;
|
||||
using namespace Windows::UI::Core;
|
||||
using namespace Windows::UI::Xaml;
|
||||
using namespace Windows::UI::Xaml::Controls;
|
||||
namespace ctrls = Windows::UI::Xaml::Controls;
|
||||
|
||||
namespace
|
||||
{
|
||||
|
@ -23,524 +14,100 @@ namespace
|
|||
constexpr unsigned int s_BlueChannelIndex = 2;
|
||||
constexpr unsigned int s_AlphaChannelIndex = 3;
|
||||
constexpr float s_MaxChannelValue = 255.0f;
|
||||
|
||||
constexpr float nearestPointRadius = 3;
|
||||
|
||||
struct RenderMainHelper
|
||||
{
|
||||
static std::thread CreateRenderWorker(GraphControl::DX::RenderMain::RenderContext& context, ctrls::SwapChainPanel ^ panel, Graphing::IGraph* graph)
|
||||
{
|
||||
context.Graph = graph;
|
||||
return std::thread{ [&]
|
||||
{
|
||||
struct DeviceNotify : GraphControl::DX::IDeviceNotify
|
||||
{
|
||||
explicit DeviceNotify(GraphControl::DX::RenderMain::RenderContext& context)
|
||||
: Context(context)
|
||||
{
|
||||
}
|
||||
void OnDeviceLost() override
|
||||
{
|
||||
}
|
||||
void OnDeviceRestored() override
|
||||
{
|
||||
}
|
||||
|
||||
GraphControl::DX::RenderMain::RenderContext& Context;
|
||||
};
|
||||
DeviceNotify notify{ context };
|
||||
context.DxRes = std::make_unique<GraphControl::DX::DeviceResources>(panel, ¬ify);
|
||||
std::unique_lock lck{ context.Mtx };
|
||||
while (!context.Quit)
|
||||
{
|
||||
if (!context.Tasks.empty())
|
||||
{
|
||||
auto task = std::move(context.Tasks.front());
|
||||
context.Tasks.pop();
|
||||
lck.unlock();
|
||||
task(context);
|
||||
lck.lock();
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Cv.wait(lck);
|
||||
}
|
||||
}
|
||||
} };
|
||||
}
|
||||
|
||||
static void QuitWorker(GraphControl::DX::RenderMain& self)
|
||||
{
|
||||
{
|
||||
std::scoped_lock lck{ self.m_renderContext.Mtx };
|
||||
self.m_renderContext.Quit = true;
|
||||
}
|
||||
self.m_renderContext.Cv.notify_one();
|
||||
}
|
||||
|
||||
template <class F>
|
||||
static void SubmitTask(const GraphControl::DX::RenderMain& self, F&& task)
|
||||
{
|
||||
{
|
||||
std::scoped_lock lck{ self.m_renderContext.Mtx };
|
||||
self.m_renderContext.Tasks.push(std::forward<F>(task));
|
||||
}
|
||||
self.m_renderContext.Cv.notify_one();
|
||||
}
|
||||
};
|
||||
using Helper = RenderMainHelper;
|
||||
}
|
||||
|
||||
namespace GraphControl::DX
|
||||
{
|
||||
RenderMain::RenderMain(SwapChainPanel ^ panel)
|
||||
: m_deviceResources{ panel }
|
||||
, m_nearestPointRenderer{ &m_deviceResources }
|
||||
, m_backgroundColor{ {} }
|
||||
, m_swapChainPanel{ panel }
|
||||
, m_TraceLocation(Point(0, 0))
|
||||
, m_Tracing(false)
|
||||
RenderMain::RenderMain(ctrls::SwapChainPanel ^ panel, Graphing::IGraph* graph)
|
||||
: m_renderWorker(Helper::CreateRenderWorker(m_renderContext, panel, graph))
|
||||
{
|
||||
// Register to be notified if the Device is lost or recreated
|
||||
m_deviceResources.RegisterDeviceNotify(this);
|
||||
}
|
||||
|
||||
RegisterEventHandlers();
|
||||
void RenderMain::FireRenderPass() const
|
||||
{
|
||||
Helper::SubmitTask(
|
||||
*this,
|
||||
[](RenderContext& renderContext)
|
||||
{
|
||||
auto dx = renderContext.DxRes.get();
|
||||
auto d3dctx = dx->GetD3DDeviceContext();
|
||||
d3dctx->ClearRenderTargetView(dx->GetBackBufferRenderTargetView(), renderContext.BkgColor);
|
||||
});
|
||||
}
|
||||
|
||||
m_drawActiveTracing = false;
|
||||
concurrency::task<bool> RenderMain::RunRenderPassAsync() const
|
||||
{
|
||||
co_return true;
|
||||
}
|
||||
|
||||
RenderMain::~RenderMain()
|
||||
{
|
||||
UnregisterEventHandlers();
|
||||
}
|
||||
|
||||
void RenderMain::Graph::set(shared_ptr<IGraph> graph)
|
||||
{
|
||||
m_graph = move(graph);
|
||||
|
||||
if (m_graph)
|
||||
{
|
||||
if (auto renderer = m_graph->GetRenderer())
|
||||
{
|
||||
float dpi = m_deviceResources.GetDpi();
|
||||
renderer->SetDpi(dpi, dpi);
|
||||
|
||||
renderer->SetGraphSize(static_cast<unsigned int>(m_swapChainPanel->ActualWidth), static_cast<unsigned int>(m_swapChainPanel->ActualHeight));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderMain::BackgroundColor::set(Windows::UI::Color backgroundColor)
|
||||
{
|
||||
m_backgroundColor[s_RedChannelIndex] = static_cast<float>(backgroundColor.R) / s_MaxChannelValue;
|
||||
m_backgroundColor[s_GreenChannelIndex] = static_cast<float>(backgroundColor.G) / s_MaxChannelValue;
|
||||
m_backgroundColor[s_BlueChannelIndex] = static_cast<float>(backgroundColor.B) / s_MaxChannelValue;
|
||||
m_backgroundColor[s_AlphaChannelIndex] = static_cast<float>(backgroundColor.A) / s_MaxChannelValue;
|
||||
|
||||
RunRenderPass();
|
||||
}
|
||||
|
||||
void RenderMain::DrawNearestPoint::set(bool value)
|
||||
{
|
||||
if (m_drawNearestPoint != value)
|
||||
{
|
||||
m_drawNearestPoint = value;
|
||||
if (!m_drawNearestPoint)
|
||||
{
|
||||
m_Tracing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderMain::PointerLocation::set(Point location)
|
||||
{
|
||||
if (m_pointerLocation != location)
|
||||
{
|
||||
m_pointerLocation = location;
|
||||
|
||||
bool wasPointRendered = m_Tracing;
|
||||
if (CanRenderPoint() || wasPointRendered)
|
||||
{
|
||||
RunRenderPassAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderMain::ActiveTracing::set(bool value)
|
||||
{
|
||||
if (m_drawActiveTracing != value)
|
||||
{
|
||||
m_drawActiveTracing = value;
|
||||
|
||||
bool wasPointRendered = m_Tracing;
|
||||
if (CanRenderPoint() || wasPointRendered)
|
||||
{
|
||||
RunRenderPassAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderMain::ActiveTracing::get()
|
||||
{
|
||||
return m_drawActiveTracing;
|
||||
}
|
||||
|
||||
// Updates application state when the window size changes (e.g. device orientation change)
|
||||
void RenderMain::CreateWindowSizeDependentResources()
|
||||
{
|
||||
// TODO: Replace this with the sizedependent initialization of your app's content.
|
||||
RunRenderPass();
|
||||
|
||||
if (m_swapChainPanel != nullptr)
|
||||
{
|
||||
// Initialize the active tracing location to just above and to the right of the center of the graph area
|
||||
m_activeTracingPointerLocation.X = m_swapChainPanel->ActualWidth / 2 + 40;
|
||||
m_activeTracingPointerLocation.Y = m_swapChainPanel->ActualHeight / 2 - 40;
|
||||
}
|
||||
}
|
||||
|
||||
bool RenderMain::CanRenderPoint()
|
||||
{
|
||||
if (m_graph && (m_drawNearestPoint || m_drawActiveTracing))
|
||||
{
|
||||
Point trackPoint = m_pointerLocation;
|
||||
|
||||
if (m_drawActiveTracing)
|
||||
{
|
||||
trackPoint = m_activeTracingPointerLocation;
|
||||
}
|
||||
|
||||
if (!m_criticalSection.try_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_criticalSection.unlock();
|
||||
|
||||
critical_section::scoped_lock lock(m_criticalSection);
|
||||
|
||||
int formulaId = -1;
|
||||
double outNearestPointValueX, outNearestPointValueY;
|
||||
float outNearestPointLocationX, outNearestPointLocationY;
|
||||
double rhoValueOut, thetaValueOut, tValueOut;
|
||||
|
||||
double xAxisMin, xAxisMax, yAxisMin, yAxisMax;
|
||||
m_graph->GetRenderer()->GetDisplayRanges(xAxisMin, xAxisMax, yAxisMin, yAxisMax);
|
||||
double precision = this->GetPrecision(xAxisMax, xAxisMin);
|
||||
|
||||
m_Tracing = m_graph->GetRenderer()->GetClosePointData(
|
||||
trackPoint.X,
|
||||
trackPoint.Y,
|
||||
precision,
|
||||
formulaId,
|
||||
outNearestPointLocationX,
|
||||
outNearestPointLocationY,
|
||||
outNearestPointValueX,
|
||||
outNearestPointValueY,
|
||||
rhoValueOut,
|
||||
thetaValueOut,
|
||||
tValueOut)
|
||||
== S_OK;
|
||||
m_Tracing = m_Tracing && !isnan(outNearestPointLocationX) && !isnan(outNearestPointLocationY);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Tracing = false;
|
||||
}
|
||||
|
||||
return m_Tracing;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the precision value by computing the max and min
|
||||
/// through this formula:
|
||||
/// 10^(floor(log(max-min))-3)
|
||||
/// https://github.com/microsoft/calculator/issues/998
|
||||
/// </summary>
|
||||
/// <param name="maxAxis">max axis</param>
|
||||
/// <param name="minAxis">min axis</param>
|
||||
/// <returns>the precision value</returns>
|
||||
double RenderMain::GetPrecision(const double maxAxis, const double minAxis)
|
||||
{
|
||||
double exponent = static_cast<double>(floor(log10(maxAxis - minAxis)) - 3);
|
||||
double precision = pow(10, exponent);
|
||||
return precision;
|
||||
}
|
||||
|
||||
void RenderMain::SetPointRadius(float radius)
|
||||
{
|
||||
m_nearestPointRenderer.SetRadius(radius);
|
||||
}
|
||||
|
||||
bool RenderMain::RunRenderPass()
|
||||
{
|
||||
// Non async render passes cancel if they can't obtain the lock immediatly
|
||||
if (!m_criticalSection.try_lock())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
m_criticalSection.unlock();
|
||||
|
||||
critical_section::scoped_lock lock(m_criticalSection);
|
||||
|
||||
return RunRenderPassInternal();
|
||||
}
|
||||
|
||||
IAsyncAction ^ RenderMain::RunRenderPassAsync(bool allowCancel)
|
||||
{
|
||||
// Try to cancel the renderPass that is in progress
|
||||
if (m_renderPass != nullptr && m_renderPass->Status == ::AsyncStatus::Started)
|
||||
{
|
||||
m_renderPass->Cancel();
|
||||
}
|
||||
|
||||
auto device = m_deviceResources;
|
||||
auto workItemHandler = ref new WorkItemHandler([this, allowCancel](IAsyncAction ^ action) {
|
||||
critical_section::scoped_lock lock(m_criticalSection);
|
||||
|
||||
// allowCancel is passed as false when the grapher relies on the render pass to validate that an equation can be succesfully rendered.
|
||||
// Passing false garauntees that another render pass doesn't cancel this one.
|
||||
if (allowCancel && action->Status == ::AsyncStatus::Canceled)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
RunRenderPassInternal();
|
||||
});
|
||||
|
||||
m_renderPass = ThreadPool::RunAsync(workItemHandler, WorkItemPriority::High, WorkItemOptions::None);
|
||||
|
||||
return m_renderPass;
|
||||
}
|
||||
|
||||
bool RenderMain::RunRenderPassInternal()
|
||||
{
|
||||
// We are accessing Direct3D resources directly without Direct2D's knowledge, so we
|
||||
// must manually acquire and apply the Direct2D factory lock.
|
||||
ID2D1Multithread* m_D2DMultithread;
|
||||
m_deviceResources.GetD2DFactory()->QueryInterface(IID_PPV_ARGS(&m_D2DMultithread));
|
||||
m_D2DMultithread->Enter();
|
||||
|
||||
bool succesful = Render();
|
||||
|
||||
if (succesful)
|
||||
{
|
||||
m_deviceResources.Present();
|
||||
}
|
||||
|
||||
// It is absolutely critical that the factory lock be released upon
|
||||
// exiting this function, or else any consequent Direct2D calls will be blocked.
|
||||
m_D2DMultithread->Leave();
|
||||
|
||||
m_isRenderPassSuccesful = succesful;
|
||||
return m_isRenderPassSuccesful;
|
||||
}
|
||||
|
||||
// Renders the current frame according to the current application state.
|
||||
// Returns true if the frame was rendered and is ready to be displayed.
|
||||
bool RenderMain::Render()
|
||||
{
|
||||
bool successful = true;
|
||||
|
||||
// Must call BeginDraw before any draw commands.
|
||||
ID2D1Factory3* pFactory = m_deviceResources.GetD2DFactory();
|
||||
ID2D1DeviceContext* pRenderTarget = m_deviceResources.GetD2DDeviceContext();
|
||||
|
||||
auto context = m_deviceResources.GetD3DDeviceContext();
|
||||
|
||||
// Clear the back buffer and set the background color.
|
||||
context->ClearRenderTargetView(m_deviceResources.GetBackBufferRenderTargetView(), m_backgroundColor);
|
||||
|
||||
if (m_graph)
|
||||
{
|
||||
if (auto renderer = m_graph->GetRenderer())
|
||||
{
|
||||
pRenderTarget->BeginDraw();
|
||||
|
||||
bool hasMissingData = false;
|
||||
m_HResult = renderer->DrawD2D1(pFactory, pRenderTarget, hasMissingData);
|
||||
|
||||
successful = SUCCEEDED(m_HResult);
|
||||
|
||||
// We ignore D2DERR_RECREATE_TARGET here. This error indicates that the device
|
||||
// is lost. It will be handled during the next call to Present.
|
||||
HRESULT endDraw = pRenderTarget->EndDraw();
|
||||
if (endDraw != D2DERR_RECREATE_TARGET)
|
||||
{
|
||||
DX::ThrowIfFailed(endDraw);
|
||||
}
|
||||
|
||||
if (successful)
|
||||
{
|
||||
if (m_drawNearestPoint || m_drawActiveTracing)
|
||||
{
|
||||
Point trackPoint = m_pointerLocation;
|
||||
if (m_drawActiveTracing)
|
||||
{
|
||||
// Active tracing takes over for draw nearest point input from the mouse pointer.
|
||||
trackPoint = m_activeTracingPointerLocation;
|
||||
}
|
||||
|
||||
int formulaId = -1;
|
||||
double outNearestPointValueX, outNearestPointValueY;
|
||||
double rhoValueOut, thetaValueOut, tValueOut;
|
||||
float outNearestPointLocationX, outNearestPointLocationY;
|
||||
double xAxisMin, xAxisMax, yAxisMin, yAxisMax;
|
||||
renderer->GetDisplayRanges(xAxisMin, xAxisMax, yAxisMin, yAxisMax);
|
||||
double precision = this->GetPrecision(xAxisMax, xAxisMin);
|
||||
if (renderer->GetClosePointData(
|
||||
trackPoint.X,
|
||||
trackPoint.Y,
|
||||
precision,
|
||||
formulaId,
|
||||
outNearestPointLocationX,
|
||||
outNearestPointLocationY,
|
||||
outNearestPointValueX,
|
||||
outNearestPointValueY,
|
||||
rhoValueOut,
|
||||
thetaValueOut,
|
||||
tValueOut)
|
||||
== S_OK)
|
||||
{
|
||||
if (!isnan(outNearestPointLocationX) && !isnan(outNearestPointLocationY))
|
||||
{
|
||||
auto lineColors = m_graph->GetOptions().GetGraphColors();
|
||||
|
||||
if (formulaId >= 0 && static_cast<unsigned int>(formulaId) < lineColors.size())
|
||||
{
|
||||
auto dotColor = lineColors[formulaId];
|
||||
m_nearestPointRenderer.SetColor(D2D1::ColorF(dotColor.R * 65536 + dotColor.G * 256 + dotColor.B, 1.0));
|
||||
}
|
||||
|
||||
m_TraceLocation = Point(outNearestPointLocationX, outNearestPointLocationY);
|
||||
m_nearestPointRenderer.Render(m_TraceLocation);
|
||||
m_Tracing = true;
|
||||
m_TraceLocation = Point(outNearestPointLocationX, outNearestPointLocationY);
|
||||
m_XTraceValue = outNearestPointValueX;
|
||||
m_YTraceValue = outNearestPointValueY;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Tracing = false;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_Tracing = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return successful;
|
||||
}
|
||||
|
||||
HRESULT RenderMain::GetRenderError()
|
||||
{
|
||||
return m_HResult;
|
||||
}
|
||||
|
||||
void RenderMain::OnLoaded(Object ^ sender, RoutedEventArgs ^ e)
|
||||
{
|
||||
RunRenderPass();
|
||||
}
|
||||
|
||||
void RenderMain::RegisterEventHandlers()
|
||||
{
|
||||
UnregisterEventHandlers();
|
||||
|
||||
// Register event handlers for control lifecycle.
|
||||
m_coreWindow = Agile<CoreWindow>(Window::Current->CoreWindow);
|
||||
if (m_coreWindow != nullptr)
|
||||
{
|
||||
m_tokenVisibilityChanged = m_coreWindow->VisibilityChanged +=
|
||||
ref new TypedEventHandler<CoreWindow ^, VisibilityChangedEventArgs ^>(this, &RenderMain::OnVisibilityChanged);
|
||||
}
|
||||
|
||||
m_displayInformation = DisplayInformation::GetForCurrentView();
|
||||
if (m_displayInformation != nullptr)
|
||||
{
|
||||
m_tokenDpiChanged = m_displayInformation->DpiChanged += ref new TypedEventHandler<DisplayInformation ^, Object ^>(this, &RenderMain::OnDpiChanged);
|
||||
|
||||
m_tokenOrientationChanged = m_displayInformation->OrientationChanged +=
|
||||
ref new TypedEventHandler<DisplayInformation ^, Object ^>(this, &RenderMain::OnOrientationChanged);
|
||||
}
|
||||
|
||||
m_tokenDisplayContentsInvalidated = DisplayInformation::DisplayContentsInvalidated +=
|
||||
ref new TypedEventHandler<DisplayInformation ^, Object ^>(this, &RenderMain::OnDisplayContentsInvalidated);
|
||||
|
||||
if (m_swapChainPanel != nullptr)
|
||||
{
|
||||
m_tokenLoaded = m_swapChainPanel->Loaded += ref new RoutedEventHandler(this, &RenderMain::OnLoaded);
|
||||
|
||||
m_tokenCompositionScaleChanged = m_swapChainPanel->CompositionScaleChanged +=
|
||||
ref new TypedEventHandler<SwapChainPanel ^, Object ^>(this, &RenderMain::OnCompositionScaleChanged);
|
||||
|
||||
m_tokenSizeChanged = m_swapChainPanel->SizeChanged += ref new SizeChangedEventHandler(this, &RenderMain::OnSizeChanged);
|
||||
}
|
||||
}
|
||||
|
||||
void RenderMain::UnregisterEventHandlers()
|
||||
{
|
||||
if (m_coreWindow != nullptr)
|
||||
{
|
||||
if (m_tokenVisibilityChanged.Value != 0)
|
||||
{
|
||||
m_coreWindow->VisibilityChanged -= m_tokenVisibilityChanged;
|
||||
m_tokenVisibilityChanged.Value = 0;
|
||||
}
|
||||
m_coreWindow = nullptr;
|
||||
}
|
||||
|
||||
if (m_displayInformation != nullptr)
|
||||
{
|
||||
if (m_tokenDpiChanged.Value != 0)
|
||||
{
|
||||
m_displayInformation->DpiChanged -= m_tokenDpiChanged;
|
||||
m_tokenDpiChanged.Value = 0;
|
||||
}
|
||||
if (m_tokenOrientationChanged.Value != 0)
|
||||
{
|
||||
m_displayInformation->OrientationChanged -= m_tokenOrientationChanged;
|
||||
m_tokenOrientationChanged.Value = 0;
|
||||
}
|
||||
m_displayInformation = nullptr;
|
||||
}
|
||||
|
||||
if (m_tokenDisplayContentsInvalidated.Value != 0)
|
||||
{
|
||||
DisplayInformation::DisplayContentsInvalidated -= m_tokenDisplayContentsInvalidated;
|
||||
m_tokenDisplayContentsInvalidated.Value = 0;
|
||||
}
|
||||
|
||||
if (m_swapChainPanel != nullptr)
|
||||
{
|
||||
if (m_tokenLoaded.Value != 0)
|
||||
{
|
||||
m_swapChainPanel->Loaded -= m_tokenLoaded;
|
||||
m_tokenLoaded.Value = 0;
|
||||
}
|
||||
if (m_tokenCompositionScaleChanged.Value != 0)
|
||||
{
|
||||
m_swapChainPanel->CompositionScaleChanged -= m_tokenCompositionScaleChanged;
|
||||
m_tokenCompositionScaleChanged.Value = 0;
|
||||
}
|
||||
if (m_tokenSizeChanged.Value != 0)
|
||||
{
|
||||
m_swapChainPanel->SizeChanged -= m_tokenSizeChanged;
|
||||
m_tokenSizeChanged.Value = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void RenderMain::OnVisibilityChanged(CoreWindow ^ sender, VisibilityChangedEventArgs ^ args)
|
||||
{
|
||||
if (args->Visible)
|
||||
{
|
||||
RunRenderPass();
|
||||
}
|
||||
}
|
||||
|
||||
void RenderMain::OnDpiChanged(DisplayInformation ^ sender, Object ^ args)
|
||||
{
|
||||
// Note: The value for LogicalDpi retrieved here may not match the effective DPI of the app
|
||||
// if it is being scaled for high resolution devices. Once the DPI is set on DeviceResources,
|
||||
// you should always retrieve it using the GetDpi method.
|
||||
// See DeviceResources.cpp for more details.
|
||||
m_deviceResources.SetDpi(sender->LogicalDpi);
|
||||
|
||||
if (m_graph)
|
||||
{
|
||||
if (auto renderer = m_graph->GetRenderer())
|
||||
{
|
||||
float dpi = m_deviceResources.GetDpi();
|
||||
renderer->SetDpi(dpi, dpi);
|
||||
}
|
||||
}
|
||||
|
||||
CreateWindowSizeDependentResources();
|
||||
}
|
||||
|
||||
void RenderMain::OnOrientationChanged(DisplayInformation ^ sender, Object ^ args)
|
||||
{
|
||||
m_deviceResources.SetCurrentOrientation(sender->CurrentOrientation);
|
||||
CreateWindowSizeDependentResources();
|
||||
}
|
||||
|
||||
void RenderMain::OnDisplayContentsInvalidated(DisplayInformation ^ sender, Object ^ args)
|
||||
{
|
||||
m_deviceResources.ValidateDevice();
|
||||
}
|
||||
|
||||
void RenderMain::OnCompositionScaleChanged(SwapChainPanel ^ sender, Object ^ args)
|
||||
{
|
||||
m_deviceResources.SetCompositionScale(sender->CompositionScaleX, sender->CompositionScaleY);
|
||||
CreateWindowSizeDependentResources();
|
||||
}
|
||||
|
||||
void RenderMain::OnSizeChanged(Object ^ sender, SizeChangedEventArgs ^ e)
|
||||
{
|
||||
m_deviceResources.SetLogicalSize(e->NewSize);
|
||||
|
||||
if (m_graph)
|
||||
{
|
||||
if (auto renderer = m_graph->GetRenderer())
|
||||
{
|
||||
const auto& newSize = e->NewSize;
|
||||
renderer->SetGraphSize(static_cast<unsigned int>(newSize.Width), static_cast<unsigned int>(newSize.Height));
|
||||
}
|
||||
}
|
||||
|
||||
CreateWindowSizeDependentResources();
|
||||
}
|
||||
|
||||
// Notifies renderers that device resources need to be released.
|
||||
void RenderMain::OnDeviceLost()
|
||||
{
|
||||
m_nearestPointRenderer.ReleaseDeviceDependentResources();
|
||||
}
|
||||
|
||||
// Notifies renderers that device resources may now be recreated.
|
||||
void RenderMain::OnDeviceRestored()
|
||||
{
|
||||
m_nearestPointRenderer.CreateDeviceDependentResources();
|
||||
Helper::QuitWorker(*this);
|
||||
m_renderWorker.join();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,207 +3,72 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
// Taken from the default template for Xaml and Direct3D 11 apps.
|
||||
#include <condition_variable>
|
||||
#include <functional>
|
||||
#include <mutex>
|
||||
#include <queue>
|
||||
|
||||
// Taken from the default template for Xaml and Direct3D 11 apps.
|
||||
#include "DeviceResources.h"
|
||||
#include "NearestPointRenderer.h"
|
||||
#include "IGraph.h"
|
||||
|
||||
namespace
|
||||
{
|
||||
struct RenderMainHelper;
|
||||
}
|
||||
|
||||
// Renders Direct2D and 3D content on the screen.
|
||||
namespace GraphControl::DX
|
||||
{
|
||||
ref class RenderMain sealed : public IDeviceNotify
|
||||
class RenderMain
|
||||
{
|
||||
friend struct RenderMainHelper;
|
||||
|
||||
public:
|
||||
virtual ~RenderMain();
|
||||
explicit RenderMain(Windows::UI::Xaml::Controls::SwapChainPanel ^ panel, Graphing::IGraph* graph);
|
||||
~RenderMain();
|
||||
|
||||
// IDeviceNotify
|
||||
virtual void OnDeviceLost();
|
||||
virtual void OnDeviceRestored();
|
||||
void FireRenderPass() const;
|
||||
concurrency::task<bool> RunRenderPassAsync() const;
|
||||
|
||||
internal : RenderMain(Windows::UI::Xaml::Controls::SwapChainPanel ^ panel);
|
||||
|
||||
property std::shared_ptr<Graphing::IGraph> Graph
|
||||
bool ActiveTracing() const noexcept
|
||||
{
|
||||
void set(std::shared_ptr<Graphing::IGraph> graph);
|
||||
return m_renderContext.ActiveTracing;
|
||||
}
|
||||
Windows::Foundation::Point ActiveTraceCursorPosition() const noexcept
|
||||
{
|
||||
return m_renderContext.ActiveTraceCursorPosition;
|
||||
}
|
||||
Windows::Foundation::Point TraceLocation() const noexcept
|
||||
{
|
||||
std::scoped_lock lck{ m_renderContext.Mtx };
|
||||
return m_renderContext.TraceLocation;
|
||||
}
|
||||
|
||||
property Windows::UI::Color BackgroundColor
|
||||
{
|
||||
void set(Windows::UI::Color color);
|
||||
}
|
||||
|
||||
property bool DrawNearestPoint
|
||||
{
|
||||
void set(bool value);
|
||||
}
|
||||
|
||||
property Windows::Foundation::Point PointerLocation
|
||||
{
|
||||
void set(Windows::Foundation::Point location);
|
||||
}
|
||||
|
||||
void CreateWindowSizeDependentResources();
|
||||
|
||||
bool RenderMain::CanRenderPoint();
|
||||
|
||||
void SetPointRadius(float radius);
|
||||
|
||||
bool RunRenderPass();
|
||||
|
||||
Windows::Foundation::IAsyncAction ^ RunRenderPassAsync(bool allowCancel = true);
|
||||
|
||||
Concurrency::critical_section& GetCriticalSection()
|
||||
{
|
||||
return m_criticalSection;
|
||||
}
|
||||
|
||||
bool IsRenderPassSuccesful()
|
||||
{
|
||||
return m_isRenderPassSuccesful;
|
||||
}
|
||||
|
||||
HRESULT GetRenderError();
|
||||
|
||||
// Indicates if we are in active tracing mode (the tracing box is being used and controlled through keyboard input)
|
||||
property bool ActiveTracing
|
||||
{
|
||||
bool get();
|
||||
void set(bool value);
|
||||
}
|
||||
|
||||
property Windows::Foundation::Point ActiveTraceCursorPosition
|
||||
{
|
||||
Windows::Foundation::Point get()
|
||||
{
|
||||
return m_activeTracingPointerLocation;
|
||||
}
|
||||
|
||||
void set(Windows::Foundation::Point newValue)
|
||||
{
|
||||
if (m_activeTracingPointerLocation != newValue)
|
||||
{
|
||||
m_activeTracingPointerLocation = newValue;
|
||||
|
||||
bool wasPointRendered = m_Tracing;
|
||||
if (CanRenderPoint() || wasPointRendered)
|
||||
{
|
||||
RunRenderPassAsync();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
property double XTraceValue
|
||||
{
|
||||
double get()
|
||||
{
|
||||
return m_XTraceValue;
|
||||
}
|
||||
}
|
||||
|
||||
property double YTraceValue
|
||||
{
|
||||
double get()
|
||||
{
|
||||
return m_YTraceValue;
|
||||
}
|
||||
}
|
||||
|
||||
property Windows::Foundation::Point TraceLocation
|
||||
{
|
||||
Windows::Foundation::Point get()
|
||||
{
|
||||
return m_TraceLocation;
|
||||
}
|
||||
}
|
||||
|
||||
// Any time we should be showing the tracing popup (either active or passive tracing)
|
||||
property bool Tracing
|
||||
{
|
||||
bool get()
|
||||
{
|
||||
return m_Tracing;
|
||||
}
|
||||
}
|
||||
void ActiveTracing(bool value) noexcept;
|
||||
void ActiveTraceCursorPosition(const Windows::Foundation::Point& value) noexcept;
|
||||
void BackgroundColor(const Windows::UI::Color& value) noexcept;
|
||||
void PointerLocation(const Windows::Foundation::Point& value) noexcept;
|
||||
void PointRadius(float radius) noexcept;
|
||||
|
||||
private:
|
||||
bool Render();
|
||||
|
||||
bool RunRenderPassInternal();
|
||||
|
||||
// Loaded/Unloaded
|
||||
void OnLoaded(Platform::Object ^ sender, Windows::UI::Xaml::RoutedEventArgs ^ e);
|
||||
|
||||
// Dependent event registration
|
||||
void RegisterEventHandlers();
|
||||
void UnregisterEventHandlers();
|
||||
|
||||
// Window event handlers.
|
||||
void OnVisibilityChanged(Windows::UI::Core::CoreWindow ^ sender, Windows::UI::Core::VisibilityChangedEventArgs ^ args);
|
||||
|
||||
// DisplayInformation event handlers.
|
||||
void OnDpiChanged(Windows::Graphics::Display::DisplayInformation ^ sender, Platform::Object ^ args);
|
||||
void OnOrientationChanged(Windows::Graphics::Display::DisplayInformation ^ sender, Platform::Object ^ args);
|
||||
void OnDisplayContentsInvalidated(Windows::Graphics::Display::DisplayInformation ^ sender, Platform::Object ^ args);
|
||||
|
||||
// Other event handlers.
|
||||
void OnCompositionScaleChanged(Windows::UI::Xaml::Controls::SwapChainPanel ^ sender, Object ^ args);
|
||||
void OnSizeChanged(Platform::Object ^ sender, Windows::UI::Xaml::SizeChangedEventArgs ^ e);
|
||||
|
||||
double GetPrecision(const double maxAxis, const double minAxis);
|
||||
struct RenderContext
|
||||
{
|
||||
std::unique_ptr<DeviceResources> DxRes;
|
||||
Graphing::IGraph* Graph;
|
||||
mutable std::mutex Mtx;
|
||||
mutable std::condition_variable Cv;
|
||||
mutable std::queue<std::function<void(RenderContext& context)>> Tasks;
|
||||
Windows::Foundation::Point ActiveTraceCursorPosition = {};
|
||||
Windows::Foundation::Point TraceLocation = {};
|
||||
float BkgColor[4] = {};
|
||||
bool ActiveTracing = false;
|
||||
bool Quit = false;
|
||||
};
|
||||
|
||||
private:
|
||||
DX::DeviceResources m_deviceResources;
|
||||
NearestPointRenderer m_nearestPointRenderer;
|
||||
|
||||
// Cached Graph object with Renderer property.
|
||||
std::shared_ptr<Graphing::IGraph> m_graph = nullptr;
|
||||
|
||||
// Track current input pointer position.
|
||||
bool m_drawNearestPoint = false;
|
||||
Windows::Foundation::Point m_pointerLocation;
|
||||
|
||||
// Track current active tracing pointer position.
|
||||
bool m_drawActiveTracing = false;
|
||||
Windows::Foundation::Point m_activeTracingPointerLocation;
|
||||
|
||||
float m_backgroundColor[4];
|
||||
|
||||
// The SwapChainPanel^ surface.
|
||||
Windows::UI::Xaml::Controls::SwapChainPanel ^ m_swapChainPanel = nullptr;
|
||||
Windows::Foundation::EventRegistrationToken m_tokenLoaded;
|
||||
Windows::Foundation::EventRegistrationToken m_tokenCompositionScaleChanged;
|
||||
Windows::Foundation::EventRegistrationToken m_tokenSizeChanged;
|
||||
|
||||
// Cached references to event notifiers.
|
||||
Platform::Agile<Windows::UI::Core::CoreWindow> m_coreWindow = nullptr;
|
||||
Windows::Foundation::EventRegistrationToken m_tokenVisibilityChanged;
|
||||
|
||||
Windows::Graphics::Display::DisplayInformation ^ m_displayInformation = nullptr;
|
||||
Windows::Foundation::EventRegistrationToken m_tokenDpiChanged;
|
||||
Windows::Foundation::EventRegistrationToken m_tokenOrientationChanged;
|
||||
Windows::Foundation::EventRegistrationToken m_tokenDisplayContentsInvalidated;
|
||||
|
||||
// Track our independent input on a background worker thread.
|
||||
Windows::Foundation::IAsyncAction ^ m_inputLoopWorker = nullptr;
|
||||
Windows::UI::Core::CoreIndependentInputSource ^ m_coreInput = nullptr;
|
||||
|
||||
double m_XTraceValue;
|
||||
double m_YTraceValue;
|
||||
|
||||
// And where is it located on screen
|
||||
Windows::Foundation::Point m_TraceLocation;
|
||||
|
||||
// Are we currently showing the tracing value
|
||||
bool m_Tracing;
|
||||
|
||||
Concurrency::critical_section m_criticalSection;
|
||||
|
||||
Windows::Foundation::IAsyncAction ^ m_renderPass = nullptr;
|
||||
|
||||
bool m_isRenderPassSuccesful;
|
||||
|
||||
HRESULT m_HResult;
|
||||
RenderContext m_renderContext;
|
||||
std::thread m_renderWorker;
|
||||
};
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue