Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

DYN-4224 / DYN-4225 Watch3d Updates (Persistent camera and node size between saves / Ignore Node preview state) #12150

Merged
merged 25 commits into from
Nov 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
17bc6dc
Use exisitng width, height, and camera during deserialization
saintentropy Aug 2, 2021
c497756
Allow Watch3D to tessellate directly connected nodes independent of p…
saintentropy Aug 2, 2021
0583c85
One more change for directly connected
saintentropy Aug 2, 2021
d81582e
Fix bug with port connection and disconnect events
saintentropy Aug 2, 2021
c564327
Merge remote-tracking branch 'upstream/master' into Watch3dUpdates
saintentropy Oct 15, 2021
b073fc3
pr comments
saintentropy Nov 8, 2021
f63a78f
Merge remote-tracking branch 'upstream/master' into Watch3dUpdates
saintentropy Nov 4, 2022
c1c9b17
Ignore certain cases
saintentropy Nov 4, 2022
a6244c3
PR comments
saintentropy Nov 4, 2022
1d0c23a
update comments
saintentropy Nov 5, 2022
749beb7
Update DefaultWatch3DViewModel.cs
saintentropy Nov 9, 2022
71a4c28
Added deserialization test for HelixWatch3D node
LongNguyenP Nov 11, 2022
03ceb2e
Added the dyn file for the HelixWatch3D node deserialization test
LongNguyenP Nov 11, 2022
372284d
Added testing for Width deserialization
LongNguyenP Nov 12, 2022
e8a003b
Renamed test dyn file
LongNguyenP Nov 12, 2022
77de095
Added test for ignoring IsVisible parameter by Watch3d node
LongNguyenP Nov 14, 2022
4165db0
Fixed wrong test geometry in dyn file
LongNguyenP Nov 14, 2022
5d64c4e
Added another Assert to the IgnoreIsVisible test
LongNguyenP Nov 14, 2022
37f711c
Fixed Assert statements
LongNguyenP Nov 15, 2022
ffc8edf
Merge branch 'master' of https://github.com/saintentropy/Dynamo into …
LongNguyenP Nov 16, 2022
c61d09b
Simplified a test
LongNguyenP Nov 16, 2022
019e541
Merge branch 'master' into Watch3dUpdates
twastvedt Nov 16, 2022
256c1a9
Remove node_modules.
twastvedt Nov 16, 2022
afc68a0
Fix test.
twastvedt Nov 16, 2022
f1ede34
Simplify
twastvedt Nov 16, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 21 additions & 1 deletion src/DynamoCore/Graph/Nodes/NodeModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2708,6 +2708,25 @@ internal void RequestValueUpdate(EngineController engine)
/// <returns>Flag which indicates if geometry update has been scheduled</returns>
public virtual bool RequestVisualUpdateAsync(IScheduler scheduler,
EngineController engine, IRenderPackageFactory factory, bool forceUpdate = false)
{
return RequestVisualUpdateAsync(scheduler, engine, factory, forceUpdate, false);
}

/// <summary>
/// Call this method to asynchronously regenerate render package for
/// this node. This method accesses core properties of a NodeModel and
/// therefore is typically called on the main/UI thread.
/// </summary>
/// <param name="scheduler">An IScheduler on which the task will be scheduled.</param>
/// <param name="engine">The EngineController which will be used to get MirrorData for the node.</param>
/// <param name="factory">An IRenderPackageFactory which will be used to generate IRenderPackage objects.</param>
/// <param name="forceUpdate">Normally, render packages are only generated when the node's IsUpdated parameter is true.
/// By setting forceUpdate to true, the render packages will be updated.</param>
/// <param name="ignoreIsVisible">Normally, render packages are only generated when the node's IsVisible parameter is true.
/// By setting ignore to true, the render package will be updated.</param>
/// <returns>Flag which indicates if geometry update has been scheduled</returns>
public virtual bool RequestVisualUpdateAsync(IScheduler scheduler,
EngineController engine, IRenderPackageFactory factory, bool forceUpdate, bool ignoreIsVisible = false)
{
var initParams = new UpdateRenderPackageParams()
{
Expand All @@ -2716,7 +2735,8 @@ public virtual bool RequestVisualUpdateAsync(IScheduler scheduler,
EngineController = engine,
DrawableIdMap = GetDrawableIdMap(),
PreviewIdentifierName = AstIdentifierForPreview.Name,
ForceUpdate = forceUpdate
ForceUpdate = forceUpdate,
IgnoreIsVisible = ignoreIsVisible
};

var task = new UpdateRenderPackageAsyncTask(scheduler);
Expand Down
10 changes: 10 additions & 0 deletions src/DynamoCore/Graph/Nodes/NodeModelExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,16 @@ internal static void VisibleUpstreamNodes(this NodeModel node, List<NodeModel> g
}
}

/// <summary>
/// Provide the upstream nodes that are imediately connected.
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
internal static HashSet<NodeModel> ImediateUpstreamNodes(this NodeModel node)
{
return node.InPorts.SelectMany(p => p.Connectors.Select(c => c.Start.Owner)).ToHashSet();
twastvedt marked this conversation as resolved.
Show resolved Hide resolved
}

internal static IEnumerable<NodeModel> UpstreamNodesMatchingPredicate(this NodeModel node, List<NodeModel> gathered, Predicate<NodeModel> match)
{
var upstream = node.InPorts.SelectMany(p => p.Connectors.Select(c => c.Start.Owner)).
Expand Down
15 changes: 12 additions & 3 deletions src/DynamoCore/Scheduler/UpdateRenderPackageAsyncTask.cs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ class UpdateRenderPackageParams
internal IEnumerable<KeyValuePair<Guid, string>> DrawableIdMap { get; set; }

internal bool ForceUpdate { get; set; }
/// <summary>
/// Set to true to ignore the preview state of the node
/// </summary>
internal bool IgnoreIsVisible { get; set; }
saintentropy marked this conversation as resolved.
Show resolved Hide resolved
}

/// <summary>
Expand Down Expand Up @@ -88,9 +92,14 @@ internal bool Initialize(UpdateRenderPackageParams initParams)
if (nodeModel.WasRenderPackageUpdatedAfterExecution && !initParams.ForceUpdate)
return false; // Not has not been updated at all.

// If a node is in either of the following states, then it will not
// produce any geometric output. Bail after clearing the render packages.
if (nodeModel.IsInErrorState || !nodeModel.IsVisible)
// If a node is in an error state it won't produce any geometric output.
// Bail after clearing the render packages.
if (nodeModel.IsInErrorState)
return false;

// If a node is not set as visible and the override is not set to true then
// bail after clearing the render packages.
if (!nodeModel.IsVisible && initParams.IgnoreIsVisible == false)
return false;

// Without AstIdentifierForPreview, a node cannot have MirrorData.
Expand Down
5 changes: 5 additions & 0 deletions src/DynamoCoreWpf/DynamoCoreWpf.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -1446,6 +1446,11 @@
<Project>{ccb6e56b-2da1-4eba-a1f9-e8510e129d12}</Project>
<Name>VMDataBridge</Name>
</ProjectReference>
<ProjectReference Include="..\Libraries\Watch3DNodeModels\Watch3DNodeModels.csproj">
<Project>{31183026-DE70-49CB-BC7C-0DFD0A088F62}</Project>
<Name>Watch3DNodeModels</Name>
<Private>False</Private>
</ProjectReference>
<ProjectReference Include="..\NodeServices\DynamoServices.csproj">
<Project>{ef879a10-041d-4c68-83e7-3192685f1bae}</Project>
<Name>DynamoServices</Name>
Expand Down
10 changes: 10 additions & 0 deletions src/DynamoCoreWpf/ViewModels/Watch3D/DefaultWatch3DViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
using System.Windows.Media;
using System.Windows.Media.Media3D;
using System.Xml;
using CoreNodeModels;
using Dynamo.Core;
using Dynamo.Graph.Connectors;
using Dynamo.Graph.Nodes;
Expand Down Expand Up @@ -610,6 +611,15 @@ protected virtual void OnRenderPackagesUpdated(NodeModel node, RenderPackageCach
// If there is no attached model update for all render packages
if (watchModel == null)
{
//When Watch3D nodes are in canvas we need to ignore the Node.RenderPackageUpdate event in some cases.
//The background preview does not request tesselation for non-visible nodes or the Watch / Watch3D nodes.
//When these nodes are connected to a Watch3D, tesselation is requested and the Node.RenderPacakgeUpdate
//event will be raised. The background preview needs to filter out those tesselation events.
if (node.IsVisible == false || node is Watch || node is Watch3DNodeModels.Watch3D)
{
return;
}

AddGeometryForRenderPackages(packages);
return;
}
Expand Down
4 changes: 2 additions & 2 deletions src/DynamoCoreWpf/ViewModels/Watch3D/HelixWatch3DViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1092,7 +1092,7 @@ private void OnSceneItemsChanged()
OnRequestViewRefresh();
}

private KeyValuePair<string, Element3D>[] FindAllGeometryModel3DsForNode(NodeModel node)
internal KeyValuePair<string, Element3D>[] FindAllGeometryModel3DsForNode(NodeModel node)
{
KeyValuePair<string, Element3D>[] geometryModels;

Expand All @@ -1118,7 +1118,7 @@ private KeyValuePair<string, Element3D>[] FindAllGeometryModel3DsForNode(string
return geometryModels;
}

private void SetGeometryFrozen(HashSet<NodeModel> gathered)
internal void SetGeometryFrozen(HashSet<NodeModel> gathered)
{

foreach (var node in gathered)
Expand Down
9 changes: 3 additions & 6 deletions src/Libraries/Watch3DNodeModels/Watch3D.cs
Original file line number Diff line number Diff line change
Expand Up @@ -122,8 +122,8 @@ internal void OnSerialized(XmlElement element)
}
}

public double WatchWidth { get; private set; }
public double WatchHeight { get; private set; }
public double WatchWidth { get; set; }
public double WatchHeight { get; set; }
public bool WasExecuted { get; internal set; }

public delegate void VoidHandler();
Expand All @@ -134,10 +134,7 @@ internal void OnSerialized(XmlElement element)
private Watch3D(IEnumerable<PortModel> inPorts, IEnumerable<PortModel> outPorts) : base(inPorts, outPorts)
{
ArgumentLacing = LacingStrategy.Disabled;
WatchWidth = 200;
WatchHeight = 200;
ShouldDisplayPreviewCore = false;
Camera = new Watch3DCamera();
}

public Watch3D()
Expand Down Expand Up @@ -211,7 +208,7 @@ public override IEnumerable<AssociativeNode> BuildOutputAst(List<AssociativeNode
public Watch3DCamera Camera
{
get;
private set;
set;
saintentropy marked this conversation as resolved.
Show resolved Hide resolved
}

#endregion
Expand Down
63 changes: 50 additions & 13 deletions src/Libraries/Watch3DNodeModelsWpf/HelixWatch3DNodeViewModel.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using System;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
Expand Down Expand Up @@ -50,18 +50,23 @@ void watchNode_Deserialized(XmlNode obj)

protected override void PortConnectedHandler(PortModel arg1, ConnectorModel arg2)
{
UpdateUpstream();
if (arg1.PortType == PortType.Input && watchModel == arg1.Owner)
{
UpdateUpstream();
}
}

protected internal override void UpdateUpstream()
{
OnClear();

var gathered = new List<NodeModel>();
watchModel.VisibleUpstreamNodes(gathered);
var connectedNodes = watchModel.ImediateUpstreamNodes();

gathered.ForEach(n => n.WasRenderPackageUpdatedAfterExecution = false);
gathered.ForEach(n => n.RequestVisualUpdateAsync(scheduler, engineManager.EngineController, renderPackageFactory));
foreach(var n in connectedNodes)
{
n.WasRenderPackageUpdatedAfterExecution = false;
n.RequestVisualUpdateAsync(scheduler, engineManager.EngineController, renderPackageFactory, false, true);
}
}

protected override void OnModelPropertyChanged(object sender, PropertyChangedEventArgs e)
Expand All @@ -74,22 +79,54 @@ protected override void OnModelPropertyChanged(object sender, PropertyChangedEve
}
}

protected override void OnNodePropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (!(sender is NodeModel node))
{
return;
}

if (e.PropertyName == nameof(node.CachedValue))
{
var connecteNodes = watchModel.ImediateUpstreamNodes();
if (!connecteNodes.Contains(node))
{
return;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when would this occur?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The DefaultWatch is wired up to every node.PropertyChanged event in the graph. In the case of the background preview you want all of them. For the Watch3D we want to only react to changes that are for the node that is directly connected

}

node.RequestVisualUpdateAsync(scheduler, engineManager.EngineController, renderPackageFactory, true, true);
}

if (e.PropertyName == "IsFrozen")
saintentropy marked this conversation as resolved.
Show resolved Hide resolved
{
if (!watchModel.UpstreamCache.Contains(node))
{
return;
}

var gathered = new HashSet<NodeModel>();
node.GetDownstreamNodes(node, gathered);
SetGeometryFrozen(gathered);
}

node.WasRenderPackageUpdatedAfterExecution = false;
}

protected override void PortDisconnectedHandler(PortModel obj)
{
OnClear();
if (obj.PortType == PortType.Input && watchModel == obj.Owner)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

when could it occur that obj is not a portModel of this node?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this case the PortConnected and PortDisconnected Handler are registered in the DefaultWatchViewModel as well. So we need to filter out port events unrelated to this node.

{
OnClear();
}
}


protected override void OnRenderPackagesUpdated(NodeModel node,
RenderPackageCache renderPackages)
{
var updatedNode = dynamoModel.CurrentWorkspace.Nodes.FirstOrDefault(n => n.GUID == node.GUID);
if (updatedNode == null) return;

var visibleUpstream = new List<NodeModel>();
watchModel.VisibleUpstreamNodes(visibleUpstream);
var connectedNodes = watchModel.ImediateUpstreamNodes();

if (!visibleUpstream.Contains(updatedNode))
if (!connectedNodes.Contains(node))
{
return;
}
Expand Down
23 changes: 17 additions & 6 deletions src/Libraries/Watch3DNodeModelsWpf/Watch3DNodeViewCustomization.cs
Original file line number Diff line number Diff line change
Expand Up @@ -56,15 +56,26 @@ public void CustomizeView(Watch3D model, NodeView nodeView)
watch3DViewModel.Setup(dynamoViewModel,
dynamoViewModel.RenderPackageFactoryViewModel.Factory);

if (model.initialCameraData != null)
if (model.Camera != null)
{
try
{
// The deserialization logic is unified between the view model and this node model.
// For the node model, we need to supply the deserialization method with the camera node.
var cameraNode = model.initialCameraData.ChildNodes.Cast<XmlNode>().FirstOrDefault(innerNode => innerNode.Name.Equals("camera", StringComparison.OrdinalIgnoreCase));
var cameraData = watch3DViewModel.DeserializeCamera(cameraNode);
watch3DViewModel.SetCameraData(cameraData);
var camera = model.Camera;
var camData = new CameraData
{
Name = camera.Name,
EyeX = camera.EyeX,
EyeY = camera.EyeY,
EyeZ = camera.EyeZ,
LookX = camera.LookX,
LookY = camera.LookY,
LookZ = camera.LookZ,
UpX = camera.UpX,
UpY = camera.UpY,
UpZ = camera.UpZ
};

watch3DViewModel.SetCameraData(camData);
}
catch
{
Expand Down
Loading