port from perforce
This commit is contained in:
35
intromat/Intromat/Actions/Hierarchy/CreateFileAction.cs
Normal file
35
intromat/Intromat/Actions/Hierarchy/CreateFileAction.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System;
|
||||
using DynamicData;
|
||||
using Intromat.Interfaces;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Actions.Hierarchy
|
||||
{
|
||||
public class CreateFileAction : IUndoItem
|
||||
{
|
||||
private readonly FileViewModel _file;
|
||||
private readonly FolderViewModel _parent;
|
||||
|
||||
public CreateFileAction(MainViewModel mainVm, FileViewModel file, ModuleViewModel module, FolderViewModel parent)
|
||||
{
|
||||
_file = file;
|
||||
_parent = parent;
|
||||
File = module;
|
||||
}
|
||||
|
||||
public IFile File { get; }
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
_parent.Files.Add(_file);
|
||||
_parent.IsExpanded = true;
|
||||
_file.IsSelected = true;
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
_parent.Files.Remove(_file);
|
||||
_parent.IsSelected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
34
intromat/Intromat/Actions/Hierarchy/CreateFolderAction.cs
Normal file
34
intromat/Intromat/Actions/Hierarchy/CreateFolderAction.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using DynamicData;
|
||||
using Intromat.Interfaces;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Actions.Hierarchy
|
||||
{
|
||||
public class CreateFolderAction : IUndoItem
|
||||
{
|
||||
private readonly FolderViewModel _folder;
|
||||
private readonly FolderViewModel _parent;
|
||||
|
||||
public CreateFolderAction(string name, ModuleViewModel module, FolderViewModel parent)
|
||||
{
|
||||
_folder = new FolderViewModel(module, parent, name);
|
||||
_parent = parent;
|
||||
File = module;
|
||||
}
|
||||
|
||||
public IFile File { get; }
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
_parent.Folders.Add(_folder);
|
||||
_parent.IsExpanded = true;
|
||||
_folder.IsSelected = true;
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
_parent.Folders.Remove(_folder);
|
||||
_parent.IsSelected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
34
intromat/Intromat/Actions/Hierarchy/CreateModuleAction.cs
Normal file
34
intromat/Intromat/Actions/Hierarchy/CreateModuleAction.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.IO;
|
||||
using Intromat.Interfaces;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Actions.Hierarchy
|
||||
{
|
||||
public class CreateModuleAction : IUndoItem
|
||||
{
|
||||
private readonly ModuleViewModel _module;
|
||||
private readonly ProjectViewModel _parent;
|
||||
|
||||
public CreateModuleAction(string name, ProjectViewModel parent)
|
||||
{
|
||||
var modulePath = Path.GetFullPath(Path.Combine(Path.GetDirectoryName(parent.FullPath)!, name, $"{name}.imodule"));
|
||||
_module = new ModuleViewModel(parent, name, modulePath);
|
||||
File = _parent = parent;
|
||||
}
|
||||
|
||||
public IFile File { get; }
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
_parent.Modules.Add(_module);
|
||||
_parent.IsExpanded = true;
|
||||
_module.IsSelected = true;
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
_parent.Modules.Remove(_module);
|
||||
_parent.IsSelected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
intromat/Intromat/Actions/Hierarchy/DeleteFileAction.cs
Normal file
33
intromat/Intromat/Actions/Hierarchy/DeleteFileAction.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using DynamicData;
|
||||
using Intromat.Interfaces;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Actions.Hierarchy
|
||||
{
|
||||
public class DeleteFileAction : IUndoItem
|
||||
{
|
||||
private readonly FileViewModel _file;
|
||||
private readonly FolderViewModel _parent;
|
||||
|
||||
public DeleteFileAction(FileViewModel file)
|
||||
{
|
||||
_parent = file.Parent;
|
||||
File = _parent.Module;
|
||||
_file = file;
|
||||
}
|
||||
|
||||
public IFile File { get; }
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
_parent.Files.Remove(_file);
|
||||
_parent.IsSelected = true;
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
_parent.Files.Add(_file);
|
||||
_file.IsSelected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
33
intromat/Intromat/Actions/Hierarchy/DeleteFolderAction.cs
Normal file
33
intromat/Intromat/Actions/Hierarchy/DeleteFolderAction.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using DynamicData;
|
||||
using Intromat.Interfaces;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Actions.Hierarchy
|
||||
{
|
||||
public class DeleteFolderAction : IUndoItem
|
||||
{
|
||||
private readonly FolderViewModel _folder;
|
||||
private readonly FolderViewModel _parent;
|
||||
|
||||
public DeleteFolderAction(FolderViewModel folder)
|
||||
{
|
||||
File = folder.Module;
|
||||
_parent = (FolderViewModel)folder.Parent;
|
||||
_folder = folder;
|
||||
}
|
||||
|
||||
public IFile File { get; }
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
_parent.Folders.Remove(_folder);
|
||||
_parent.IsSelected = true;
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
_parent.Folders.Add(_folder);
|
||||
_folder.IsSelected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
31
intromat/Intromat/Actions/Hierarchy/DeleteModuleAction.cs
Normal file
31
intromat/Intromat/Actions/Hierarchy/DeleteModuleAction.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using Intromat.Interfaces;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Actions.Hierarchy
|
||||
{
|
||||
public class DeleteModuleAction : IUndoItem
|
||||
{
|
||||
private readonly ModuleViewModel _module;
|
||||
private readonly ProjectViewModel _parent;
|
||||
|
||||
public DeleteModuleAction(ModuleViewModel module)
|
||||
{
|
||||
File = _parent = (ProjectViewModel)module.Parent;
|
||||
_module = module;
|
||||
}
|
||||
|
||||
public IFile File { get; }
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
_parent.Modules.Remove(_module);
|
||||
_parent.IsSelected = true;
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
_parent.Modules.Add(_module);
|
||||
_module.IsSelected = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
32
intromat/Intromat/Actions/Network/AddConnectionAction.cs
Normal file
32
intromat/Intromat/Actions/Network/AddConnectionAction.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using DynamicData;
|
||||
using Intromat.Interfaces;
|
||||
using Intromat.ViewModels;
|
||||
using NodeNetwork.ViewModels;
|
||||
|
||||
namespace Intromat.Actions.Network
|
||||
{
|
||||
public class AddConnectionAction : IUndoItem
|
||||
{
|
||||
private readonly CodeGenNetworkViewModel _network;
|
||||
private readonly ConnectionViewModel _connection;
|
||||
|
||||
public AddConnectionAction(DocumentViewModel document, CodeGenNetworkViewModel network, ConnectionViewModel connection)
|
||||
{
|
||||
File = document;
|
||||
_network = network;
|
||||
_connection = connection;
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
_network.Connections.Add(_connection);
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
_network.Connections.Remove(_connection);
|
||||
}
|
||||
|
||||
public IFile File { get; }
|
||||
}
|
||||
}
|
||||
32
intromat/Intromat/Actions/Network/AddNodeAction.cs
Normal file
32
intromat/Intromat/Actions/Network/AddNodeAction.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using DynamicData;
|
||||
using Intromat.Interfaces;
|
||||
using Intromat.ViewModels;
|
||||
using NodeNetwork.ViewModels;
|
||||
|
||||
namespace Intromat.Actions.Network
|
||||
{
|
||||
public class AddNodeAction : IUndoItem
|
||||
{
|
||||
private readonly CodeGenNetworkViewModel _network;
|
||||
private readonly NodeViewModel _node;
|
||||
|
||||
public AddNodeAction(DocumentViewModel document, CodeGenNetworkViewModel network, NodeViewModel node)
|
||||
{
|
||||
File = document;
|
||||
_network = network;
|
||||
_node = node;
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
_network.Nodes.Add(_node);
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
_network.Nodes.Remove(_node);
|
||||
}
|
||||
|
||||
public IFile File { get; }
|
||||
}
|
||||
}
|
||||
32
intromat/Intromat/Actions/Network/DeleteConnectionAction.cs
Normal file
32
intromat/Intromat/Actions/Network/DeleteConnectionAction.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using DynamicData;
|
||||
using Intromat.Interfaces;
|
||||
using Intromat.ViewModels;
|
||||
using NodeNetwork.ViewModels;
|
||||
|
||||
namespace Intromat.Actions.Network
|
||||
{
|
||||
public class DeleteConnectionAction : IUndoItem
|
||||
{
|
||||
private readonly CodeGenNetworkViewModel _network;
|
||||
private readonly ConnectionViewModel _connection;
|
||||
|
||||
public DeleteConnectionAction(DocumentViewModel document, CodeGenNetworkViewModel network, ConnectionViewModel connection)
|
||||
{
|
||||
File = document;
|
||||
_network = network;
|
||||
_connection = connection;
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
_network.Connections.Remove(_connection);
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
_network.Connections.Add(_connection);
|
||||
}
|
||||
|
||||
public IFile File { get; }
|
||||
}
|
||||
}
|
||||
32
intromat/Intromat/Actions/Network/DeleteNodeAction.cs
Normal file
32
intromat/Intromat/Actions/Network/DeleteNodeAction.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using DynamicData;
|
||||
using Intromat.Interfaces;
|
||||
using Intromat.ViewModels;
|
||||
using NodeNetwork.ViewModels;
|
||||
|
||||
namespace Intromat.Actions.Network
|
||||
{
|
||||
public class DeleteNodeAction : IUndoItem
|
||||
{
|
||||
private readonly CodeGenNetworkViewModel _network;
|
||||
private readonly NodeViewModel _node;
|
||||
|
||||
public DeleteNodeAction(DocumentViewModel document, CodeGenNetworkViewModel network, NodeViewModel node)
|
||||
{
|
||||
File = document;
|
||||
_network = network;
|
||||
_node = node;
|
||||
}
|
||||
|
||||
public void Redo()
|
||||
{
|
||||
_network.Nodes.Remove(_node);
|
||||
}
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
_network.Nodes.Add(_node);
|
||||
}
|
||||
|
||||
public IFile File { get; }
|
||||
}
|
||||
}
|
||||
32
intromat/Intromat/AkavacheSuspensionDriver.cs
Normal file
32
intromat/Intromat/AkavacheSuspensionDriver.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Reactive;
|
||||
using Akavache;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Intromat
|
||||
{
|
||||
public class AkavacheSuspensionDriver<TAppState> : ISuspensionDriver where TAppState : class
|
||||
{
|
||||
private const string AppStateKey = "appState";
|
||||
|
||||
public AkavacheSuspensionDriver()
|
||||
{
|
||||
BlobCache.ApplicationName = "Your Application Name";
|
||||
}
|
||||
|
||||
public IObservable<Unit> InvalidateState()
|
||||
{
|
||||
return BlobCache.UserAccount.InvalidateObject<TAppState>(AppStateKey);
|
||||
}
|
||||
|
||||
public IObservable<object> LoadState()
|
||||
{
|
||||
return BlobCache.UserAccount.GetObject<TAppState>(AppStateKey)!;
|
||||
}
|
||||
|
||||
public IObservable<Unit> SaveState(object state)
|
||||
{
|
||||
return BlobCache.UserAccount.InsertObject(AppStateKey, (TAppState)state);
|
||||
}
|
||||
}
|
||||
}
|
||||
18
intromat/Intromat/App.xaml
Normal file
18
intromat/Intromat/App.xaml
Normal file
@@ -0,0 +1,18 @@
|
||||
<Application x:Class="Intromat.App"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
|
||||
<Application.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="Themes/ColorfulDarkTheme.xaml" />
|
||||
<ResourceDictionary Source="Themes/CodeGenNodeView.xaml" />
|
||||
<ResourceDictionary Source="Themes/CodeGenNodeInputView.xaml" />
|
||||
<ResourceDictionary Source="Themes/CodeGenNodeOutputView.xaml" />
|
||||
<ResourceDictionary Source="Themes/Resources.xaml" />
|
||||
<ResourceDictionary Source="Themes/ExtendedWpfToolkit.xaml" />
|
||||
<ResourceDictionary Source="Themes/Icons.xaml" />
|
||||
<ResourceDictionary Source="Themes/EditorStyles.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Application.Resources>
|
||||
</Application>
|
||||
51
intromat/Intromat/App.xaml.cs
Normal file
51
intromat/Intromat/App.xaml.cs
Normal file
@@ -0,0 +1,51 @@
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Windows;
|
||||
using Intromat.Graphics;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork;
|
||||
using NodeNetwork.Toolkit;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat
|
||||
{
|
||||
public partial class App : Application
|
||||
{
|
||||
public AutoSuspendHelper SuspendHelper { get; }
|
||||
|
||||
public App()
|
||||
{
|
||||
// Initialize the suspension driver after AutoSuspendHelper.
|
||||
SuspendHelper = new AutoSuspendHelper(this);
|
||||
RxApp.SuspensionHost.CreateNewAppState = () => new AppStateViewModel();
|
||||
RxApp.SuspensionHost.SetupDefaultSuspendResume(new AkavacheSuspensionDriver<AppStateViewModel>());
|
||||
}
|
||||
|
||||
protected override void OnStartup(StartupEventArgs e)
|
||||
{
|
||||
var splashScreen = new SplashScreenWindow();
|
||||
MainWindow = splashScreen;
|
||||
splashScreen.Show();
|
||||
|
||||
var dxHost = new DxHost();
|
||||
Locator.CurrentMutable.RegisterConstant(dxHost);
|
||||
var mainWindow = new MainWindow { Visibility = Visibility.Collapsed };
|
||||
|
||||
base.OnStartup(e);
|
||||
|
||||
foreach (var assemblyType in typeof(NNViewRegistrar).Assembly.GetTypes())
|
||||
RuntimeHelpers.RunClassConstructor(assemblyType.TypeHandle);
|
||||
foreach (var assemblyType in typeof(NodeTemplate).Assembly.GetTypes())
|
||||
RuntimeHelpers.RunClassConstructor(assemblyType.TypeHandle);
|
||||
foreach (var assemblyType in GetType().Assembly.GetTypes())
|
||||
RuntimeHelpers.RunClassConstructor(assemblyType.TypeHandle);
|
||||
|
||||
NNViewRegistrar.RegisterSplat();
|
||||
MainWindow = mainWindow;
|
||||
mainWindow.Show();
|
||||
splashScreen.Close();
|
||||
mainWindow.Visibility = Visibility.Visible;
|
||||
}
|
||||
}
|
||||
}
|
||||
66
intromat/Intromat/Controls/SourceEditor.cs
Normal file
66
intromat/Intromat/Controls/SourceEditor.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Windows;
|
||||
using ICSharpCode.AvalonEdit;
|
||||
|
||||
namespace Intromat.Controls
|
||||
{
|
||||
public class SourceEditor : TextEditor, INotifyPropertyChanged
|
||||
{
|
||||
/// <summary>
|
||||
/// The bindable text property dependency property
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty TextProperty = DependencyProperty.Register("Text", typeof(string), typeof(SourceEditor), new FrameworkPropertyMetadata
|
||||
{
|
||||
DefaultValue = default(string),
|
||||
BindsTwoWayByDefault = true,
|
||||
PropertyChangedCallback = OnDependencyPropertyChanged
|
||||
});
|
||||
|
||||
/// <summary>
|
||||
/// A bindable Text property
|
||||
/// </summary>
|
||||
public new string Text
|
||||
{
|
||||
get => (string)GetValue(TextProperty);
|
||||
set
|
||||
{
|
||||
SetValue(TextProperty, value);
|
||||
RaisePropertyChanged("Text");
|
||||
}
|
||||
}
|
||||
|
||||
public event PropertyChangedEventHandler? PropertyChanged;
|
||||
|
||||
protected static void OnDependencyPropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs args)
|
||||
{
|
||||
var target = (SourceEditor)obj;
|
||||
if (target.Document == null)
|
||||
return;
|
||||
|
||||
var caretOffset = target.CaretOffset;
|
||||
var newValue = args.NewValue ?? "";
|
||||
|
||||
target.Document.Text = (string)newValue;
|
||||
target.CaretOffset = Math.Min(caretOffset, target.Document.Text.Length);
|
||||
}
|
||||
|
||||
protected override void OnTextChanged(EventArgs e)
|
||||
{
|
||||
if (Document != null)
|
||||
Text = Document.Text;
|
||||
|
||||
base.OnTextChanged(e);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Raises a property changed event
|
||||
/// </summary>
|
||||
/// <param name="property">The name of the property that updates</param>
|
||||
public void RaisePropertyChanged(string property)
|
||||
{
|
||||
if (PropertyChanged != null)
|
||||
PropertyChanged(this, new PropertyChangedEventArgs(property));
|
||||
}
|
||||
}
|
||||
}
|
||||
23
intromat/Intromat/Converters/WidthToMarginConverter.cs
Normal file
23
intromat/Intromat/Converters/WidthToMarginConverter.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
|
||||
namespace Intromat.Converters
|
||||
{
|
||||
public class WidthToMarginConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
var width = (double)value;
|
||||
return Side ? new Thickness(-width, 0, 0, 0) : new Thickness(0, 0, -width, 0);
|
||||
}
|
||||
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
public bool Side { get; set; }
|
||||
}
|
||||
}
|
||||
8
intromat/Intromat/GlobalSuppressions.cs
Normal file
8
intromat/Intromat/GlobalSuppressions.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
// This file is used by Code Analysis to maintain SuppressMessage
|
||||
// attributes that are applied to this project.
|
||||
// Project-level suppressions either have no target or are given
|
||||
// a specific target and scoped to a namespace, type, member, etc.
|
||||
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
|
||||
[assembly: SuppressMessage("Interoperability", "CA1416:Validate platform compatibility", Justification = "<Pending>")]
|
||||
52
intromat/Intromat/Graphics/DebugInterface.cs
Normal file
52
intromat/Intromat/Graphics/DebugInterface.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using Intromat.DXExt;
|
||||
using SharpDX;
|
||||
|
||||
namespace Intromat.Graphics
|
||||
{
|
||||
internal static class DebugInterface
|
||||
{
|
||||
[Flags]
|
||||
public enum LoadLibraryFlags : uint
|
||||
{
|
||||
LoadLibrarySearchSystem32 = 0x00000800
|
||||
}
|
||||
|
||||
private static readonly GetDebugInterface? getDebugInterface;
|
||||
|
||||
static DebugInterface()
|
||||
{
|
||||
var moduleHandle = LoadLibraryEx("dxgi.dll", IntPtr.Zero, LoadLibraryFlags.LoadLibrarySearchSystem32);
|
||||
if (moduleHandle != IntPtr.Zero)
|
||||
{
|
||||
var procedureHandle = GetProcAddress(moduleHandle, "DXGIGetDebugInterface1");
|
||||
if (procedureHandle != IntPtr.Zero)
|
||||
getDebugInterface = (GetDebugInterface)Marshal.GetDelegateForFunctionPointer(procedureHandle, typeof(GetDebugInterface));
|
||||
}
|
||||
}
|
||||
|
||||
public static GraphicsAnalysis? TryCreateGraphicsAnalysis()
|
||||
{
|
||||
if (getDebugInterface == null)
|
||||
return null;
|
||||
|
||||
var guid = typeof(GraphicsAnalysis).GetTypeInfo().GUID;
|
||||
var result = getDebugInterface(0, ref guid, out var comPtr);
|
||||
if (result.Failure)
|
||||
return null;
|
||||
|
||||
return comPtr != IntPtr.Zero ? (GraphicsAnalysis)comPtr : null;
|
||||
}
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hReservedNull, LoadLibraryFlags dwFlags);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern IntPtr GetProcAddress(IntPtr hModule, string procName);
|
||||
|
||||
[UnmanagedFunctionPointer(CallingConvention.Winapi)]
|
||||
private delegate Result GetDebugInterface(uint flags, ref Guid guid, out IntPtr result);
|
||||
}
|
||||
}
|
||||
134
intromat/Intromat/Graphics/DxHost.cs
Normal file
134
intromat/Intromat/Graphics/DxHost.cs
Normal file
@@ -0,0 +1,134 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
using Intromat.DXExt;
|
||||
using Intromat.Pipelines;
|
||||
using SharpDX.Direct3D;
|
||||
using SharpDX.Direct3D9;
|
||||
using Splat;
|
||||
using D3D11 = SharpDX.Direct3D11;
|
||||
|
||||
namespace Intromat.Graphics
|
||||
{
|
||||
public class DxHost
|
||||
{
|
||||
public delegate void RenderDelegate(D3D11.Device device, D3D11.DeviceContext deviceContext);
|
||||
|
||||
public readonly ConcurrentQueue<RenderDelegate> _actionQueue;
|
||||
public readonly D3D11.Device Device;
|
||||
private readonly Thread _renderThread;
|
||||
private IntPtr _renderWindowHandle;
|
||||
public DeviceEx? D3D9Device;
|
||||
public Dispatcher? RenderDispatcher;
|
||||
public Dispatcher? MainDispatcher;
|
||||
private readonly ManualResetEvent _renderThreadStarted = new(false);
|
||||
public readonly D3D11.UserDefinedAnnotation? _annotation;
|
||||
public readonly GraphicsAnalysis? _graphicsAnalysis;
|
||||
|
||||
public DxHost()
|
||||
{
|
||||
#if DEBUG
|
||||
var flags = D3D11.DeviceCreationFlags.Debug;
|
||||
#else
|
||||
var flags = D3D11.DeviceCreationFlags.None;
|
||||
#endif
|
||||
Device = new D3D11.Device(DriverType.Hardware, flags);
|
||||
_annotation = Device.ImmediateContext.QueryInterface<D3D11.UserDefinedAnnotation>();
|
||||
_graphicsAnalysis = DebugInterface.TryCreateGraphicsAnalysis();
|
||||
|
||||
_actionQueue = new();
|
||||
_renderThread = new(RenderThreadStart) { Name = "WPF SwapChain" };
|
||||
_renderThread.SetApartmentState(ApartmentState.STA);
|
||||
_renderThread.Start();
|
||||
_renderThreadStarted.WaitOne();
|
||||
|
||||
var device = Device;
|
||||
var context = Device.ImmediateContext;
|
||||
MainDispatcher = Dispatcher.CurrentDispatcher;
|
||||
Locator.CurrentMutable.Register(() => new DisplayTexturePipeline(device, context));
|
||||
}
|
||||
|
||||
public void Load(Window window)
|
||||
{
|
||||
_renderWindowHandle = Process.GetCurrentProcess().MainWindowHandle;
|
||||
CreateDevice();
|
||||
}
|
||||
|
||||
public void Unload()
|
||||
{
|
||||
RenderDispatcher?.BeginInvokeShutdown(DispatcherPriority.Background);
|
||||
RenderDispatcher = null;
|
||||
}
|
||||
|
||||
private void RenderThreadStart(object? o)
|
||||
{
|
||||
RenderDispatcher = Dispatcher.CurrentDispatcher;
|
||||
RenderDispatcher.BeginInvoke(new Action(UpdateFrameTick));
|
||||
_renderThreadStarted.Set();
|
||||
Dispatcher.Run();
|
||||
}
|
||||
|
||||
private void UpdateFrameTick()
|
||||
{
|
||||
if (RenderDispatcher == null)
|
||||
return;
|
||||
|
||||
if (_actionQueue.Count == 0)
|
||||
{
|
||||
RenderDispatcher.BeginInvoke(new Action(UpdateFrameTick), DispatcherPriority.Background);
|
||||
return;
|
||||
}
|
||||
|
||||
EnsureTargetDevice();
|
||||
while (_actionQueue.TryDequeue(out var action))
|
||||
action(Device, Device.ImmediateContext);
|
||||
|
||||
RenderDispatcher?.BeginInvoke(new Action(UpdateFrameTick), DispatcherPriority.Render);
|
||||
}
|
||||
|
||||
public void EnqueueAction(RenderDelegate action)
|
||||
{
|
||||
_actionQueue.Enqueue(action);
|
||||
}
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern IntPtr MonitorFromWindow(IntPtr hWnd, int flags);
|
||||
|
||||
private void EnsureTargetDevice()
|
||||
{
|
||||
if (D3D9Device != null)
|
||||
return;
|
||||
|
||||
MainDispatcher!.Invoke(CreateDevice);
|
||||
}
|
||||
|
||||
private void CreateDevice()
|
||||
{
|
||||
var d3d9Ex = new Direct3DEx();
|
||||
var adapter = 0;
|
||||
|
||||
if (d3d9Ex.AdapterCount > 1)
|
||||
{
|
||||
const int monitorDefaultToNearest = 2;
|
||||
var hMon = MonitorFromWindow(_renderWindowHandle, monitorDefaultToNearest);
|
||||
|
||||
foreach (var a in d3d9Ex.AdaptersEx)
|
||||
if (a.Monitor == hMon)
|
||||
adapter = a.Adapter;
|
||||
}
|
||||
|
||||
var parameters = new PresentParameters
|
||||
{
|
||||
PresentationInterval = PresentInterval.Immediate,
|
||||
SwapEffect = SwapEffect.Discard,
|
||||
Windowed = true
|
||||
};
|
||||
|
||||
D3D9Device = new DeviceEx(d3d9Ex, adapter, DeviceType.Hardware, _renderWindowHandle, CreateFlags.HardwareVertexProcessing | CreateFlags.FpuPreserve | CreateFlags.Multithreaded, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
32
intromat/Intromat/Helpers/IOHelper.cs
Normal file
32
intromat/Intromat/Helpers/IOHelper.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Intromat.Helpers
|
||||
{
|
||||
public static class IOHelper
|
||||
{
|
||||
public static string GetRelativePath(string basePath, string fullPath)
|
||||
{
|
||||
if (string.IsNullOrEmpty(basePath))
|
||||
return fullPath ?? "";
|
||||
|
||||
if (string.IsNullOrEmpty(fullPath))
|
||||
return "";
|
||||
|
||||
if (basePath.Last() != '\\')
|
||||
basePath += "\\";
|
||||
|
||||
var builder = new StringBuilder(4096);
|
||||
_ = PathRelativePathTo(builder, basePath, 0, fullPath, 0);
|
||||
return builder.ToString()[2..];
|
||||
}
|
||||
|
||||
|
||||
[DllImport("shlwapi.dll", EntryPoint = "PathRelativePathTo", CharSet = CharSet.Unicode)]
|
||||
private static extern bool PathRelativePathTo(StringBuilder lpszDst, string from, uint attrFrom, string to, uint attrTo);
|
||||
}
|
||||
}
|
||||
20
intromat/Intromat/Interfaces/IExpressionEditor.cs
Normal file
20
intromat/Intromat/Interfaces/IExpressionEditor.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using Intromat.Nodes.Code;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Interfaces
|
||||
{
|
||||
public interface IExpressionEditor
|
||||
{
|
||||
ERelativeSource RelativeSource
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
bool HasParentSource { get; }
|
||||
|
||||
bool HasInputSource { get; }
|
||||
|
||||
CodeGenPortViewModel CodeGenPort { get; }
|
||||
}
|
||||
}
|
||||
24
intromat/Intromat/Interfaces/IFile.cs
Normal file
24
intromat/Intromat/Interfaces/IFile.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Interfaces
|
||||
{
|
||||
public interface IFile
|
||||
{
|
||||
bool IsDirty
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
|
||||
string FullPath
|
||||
{
|
||||
get;
|
||||
}
|
||||
|
||||
string Name
|
||||
{
|
||||
get;
|
||||
set;
|
||||
}
|
||||
}
|
||||
}
|
||||
7
intromat/Intromat/Interfaces/IPipeline.cs
Normal file
7
intromat/Intromat/Interfaces/IPipeline.cs
Normal file
@@ -0,0 +1,7 @@
|
||||
namespace Intromat.Interfaces
|
||||
{
|
||||
public interface IPipeline
|
||||
{
|
||||
void Apply();
|
||||
}
|
||||
}
|
||||
15
intromat/Intromat/Interfaces/IRefreshProperties.cs
Normal file
15
intromat/Intromat/Interfaces/IRefreshProperties.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using DynamicData;
|
||||
|
||||
namespace Intromat.Interfaces
|
||||
{
|
||||
public interface IRefreshProperties
|
||||
{
|
||||
IObservableList<PropertyDescriptor>? PropertyDescriptors { get; }
|
||||
}
|
||||
}
|
||||
9
intromat/Intromat/Interfaces/ITreeItem.cs
Normal file
9
intromat/Intromat/Interfaces/ITreeItem.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Intromat.Interfaces
|
||||
{
|
||||
public interface ITreeItem
|
||||
{
|
||||
string Name { get; }
|
||||
bool IsExpanded { get; set; }
|
||||
bool IsSelected { get; set; }
|
||||
}
|
||||
}
|
||||
9
intromat/Intromat/Interfaces/IUndoItem.cs
Normal file
9
intromat/Intromat/Interfaces/IUndoItem.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Intromat.Interfaces
|
||||
{
|
||||
public interface IUndoItem
|
||||
{
|
||||
void Redo();
|
||||
void Undo();
|
||||
IFile File { get; }
|
||||
}
|
||||
}
|
||||
62
intromat/Intromat/Intromat.csproj
Normal file
62
intromat/Intromat/Intromat.csproj
Normal file
@@ -0,0 +1,62 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<TargetFrameworks>net7.0-windows</TargetFrameworks>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<GenerateAssemblyInfo>false</GenerateAssemblyInfo>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<UseWPF>true</UseWPF>
|
||||
<Nullable>enable</Nullable>
|
||||
<StartupObject>Intromat.App</StartupObject>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<None Remove="Resources\grid.png" />
|
||||
<None Remove="Resources\HLSL-Mode.xshd" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\HLSL-Mode.xshd" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Resource Include="Resources\grid.png" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\NodeNetworkToolkit\NodeNetworkToolkit.csproj" />
|
||||
<ProjectReference Include="..\NodeNetwork\NodeNetwork.csproj" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="akavache" Version="7.3.1" />
|
||||
<PackageReference Include="AvalonEdit" Version="6.1.3.50" />
|
||||
<PackageReference Include="Dirkster.AvalonDock.Themes.VS2013" Version="4.60.0" />
|
||||
<PackageReference Include="log4net" Version="2.0.12" />
|
||||
<PackageReference Include="Microsoft.CSharp" Version="4.7.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="PresentationFramework.Aero2" Version="1.0.1">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
<PackageReference Include="RxFileSystemWatcher" Version="1.0.0" />
|
||||
<PackageReference Include="SharpDX" Version="4.2.0" />
|
||||
<PackageReference Include="SharpDX.D3DCompiler" Version="4.2.0" />
|
||||
<PackageReference Include="SharpDX.Direct3D11" Version="4.2.0" />
|
||||
<PackageReference Include="SharpDX.Direct3D9" Version="4.2.0" />
|
||||
<PackageReference Include="Extended.Wpf.Toolkit" Version="4.1.0">
|
||||
<NoWarn>NU1701</NoWarn>
|
||||
</PackageReference>
|
||||
<PackageReference Include="MoonSharp" Version="2.0.0.0" />
|
||||
<PackageReference Include="morelinq" Version="3.3.2" />
|
||||
<PackageReference Include="ReactiveUI" Version="13.2.18" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="System.Data.DataSetExtensions" Version="4.5.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Reference Include="Intromat.DXExt">
|
||||
<HintPath>..\Intromat.DXExt\Intromat.DXExt.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
128
intromat/Intromat/Intromat.csproj.user
Normal file
128
intromat/Intromat/Intromat.csproj.user
Normal file
@@ -0,0 +1,128 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup />
|
||||
<ItemGroup>
|
||||
<Compile Update="Views\CodeGenNetworkView.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\DocumentView.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\Editors\BooleanExpressionEditorView.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\Editors\BooleanValueEditorView.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\Editors\DimensionEditorView.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\Editors\EditorHeader.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\Editors\EnumEditorView.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\Editors\FloatExpressionEditorView.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\Editors\FloatValueEditorView.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\ExplorerView.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\NewFileWindow.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\Preview2DView.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\Preview3DView.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\Previews\DxMeshPreview.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\Previews\DxTexturePreview.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\Previews\StringPreview.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\PropertiesView.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\ShaderFileView.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Views\SplashScreenWindow.xaml.cs">
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Page Update="Themes\CodeGenNodeView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Themes\CodeGenNodeInputView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Themes\CodeGenNodeOutputView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Themes\Endpoint.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Themes\ExtendedWpfToolkit.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Themes\Icons.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Themes\Resources.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\CodeGenNetworkView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\DocumentView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\Editors\EditorHeader.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Themes\EditorStyles.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\ExplorerView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\NewFileWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\Preview2DView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\Preview3DView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\Previews\DxMeshPreview.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\Previews\DxTexturePreview.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\Previews\StringPreview.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\PropertiesView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\ShaderFileView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
<Page Update="Views\SplashScreenWindow.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
</Page>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
49
intromat/Intromat/Model/Compiler/CompilerContext.cs
Normal file
49
intromat/Intromat/Model/Compiler/CompilerContext.cs
Normal file
@@ -0,0 +1,49 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
|
||||
namespace Intromat.Model.Compiler
|
||||
{
|
||||
public class ScopeDefinition
|
||||
{
|
||||
public ScopeDefinition(string identifier)
|
||||
{
|
||||
Identifier = identifier;
|
||||
}
|
||||
|
||||
public string Identifier { get; }
|
||||
|
||||
public List<IVariableDefinition> Variables { get; } = new();
|
||||
}
|
||||
|
||||
public class CompilerContext
|
||||
{
|
||||
public Stack<ScopeDefinition> VariablesScopesStack { get; } = new();
|
||||
|
||||
public string FindFreeVariableName()
|
||||
{
|
||||
return "v" + VariablesScopesStack.SelectMany(s => s.Variables).Count();
|
||||
}
|
||||
|
||||
public void AddVariableToCurrentScope(IVariableDefinition variable)
|
||||
{
|
||||
VariablesScopesStack.Peek().Variables.Add(variable);
|
||||
}
|
||||
|
||||
public void EnterNewScope(string scopeIdentifier)
|
||||
{
|
||||
VariablesScopesStack.Push(new ScopeDefinition(scopeIdentifier));
|
||||
}
|
||||
|
||||
public void LeaveScope()
|
||||
{
|
||||
VariablesScopesStack.Pop();
|
||||
}
|
||||
|
||||
public bool IsInScope(IVariableDefinition variable)
|
||||
{
|
||||
if (variable == null) return false;
|
||||
|
||||
return VariablesScopesStack.Any(s => s.Variables.Contains(variable));
|
||||
}
|
||||
}
|
||||
}
|
||||
15
intromat/Intromat/Model/Compiler/Error/CompilerException.cs
Normal file
15
intromat/Intromat/Model/Compiler/Error/CompilerException.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
|
||||
namespace Intromat.Model.Compiler.Error
|
||||
{
|
||||
public class CompilerException : Exception
|
||||
{
|
||||
public CompilerException(string msg) : base(msg)
|
||||
{
|
||||
}
|
||||
|
||||
public CompilerException(string msg, Exception inner) : base(msg, inner)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace Intromat.Model.Compiler.Error
|
||||
{
|
||||
public class VariableOutOfScopeException : CompilerException
|
||||
{
|
||||
public VariableOutOfScopeException(string variableName)
|
||||
: base($"The variable '{variableName}' was referenced outside its scope.")
|
||||
{
|
||||
VariableName = variableName;
|
||||
}
|
||||
|
||||
public string VariableName { get; }
|
||||
}
|
||||
}
|
||||
10
intromat/Intromat/Model/Compiler/IStatement.cs
Normal file
10
intromat/Intromat/Model/Compiler/IStatement.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Intromat.Model.Compiler
|
||||
{
|
||||
public interface IStatement
|
||||
{
|
||||
void Compile(CompilerContext context, StringBuilder sb);
|
||||
void CompileHeader(CompilerContext context, StringBuilder sb);
|
||||
}
|
||||
}
|
||||
15
intromat/Intromat/Model/Compiler/ITypedExpression.cs
Normal file
15
intromat/Intromat/Model/Compiler/ITypedExpression.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Text;
|
||||
|
||||
namespace Intromat.Model.Compiler
|
||||
{
|
||||
public interface IExpression
|
||||
{
|
||||
void Compile(CompilerContext context, StringBuilder sb);
|
||||
}
|
||||
|
||||
public interface ITypedExpression<T> : IExpression
|
||||
{
|
||||
string? PreviewValue { get; }
|
||||
T Evaluate();
|
||||
}
|
||||
}
|
||||
15
intromat/Intromat/Model/Compiler/MeshValue.cs
Normal file
15
intromat/Intromat/Model/Compiler/MeshValue.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using SharpDX.Direct3D11;
|
||||
|
||||
namespace Intromat.Model.Compiler
|
||||
{
|
||||
public class MeshValue
|
||||
{
|
||||
public MeshValue()
|
||||
{
|
||||
}
|
||||
|
||||
public MeshValue(MeshValue other)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
24
intromat/Intromat/Model/Compiler/TextureValue.cs
Normal file
24
intromat/Intromat/Model/Compiler/TextureValue.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using SharpDX.Direct3D11;
|
||||
|
||||
namespace Intromat.Model.Compiler
|
||||
{
|
||||
public class TextureValue
|
||||
{
|
||||
public TextureValue()
|
||||
{
|
||||
}
|
||||
|
||||
public TextureValue(TextureValue other)
|
||||
{
|
||||
Width = other.Width;
|
||||
Height = other.Height;
|
||||
ShaderResourceView = other.ShaderResourceView;
|
||||
UnorderedAccessView = other.UnorderedAccessView;
|
||||
}
|
||||
|
||||
public int Width { get; set; }
|
||||
public int Height { get; set; }
|
||||
public ShaderResourceView? ShaderResourceView { get; set; }
|
||||
public UnorderedAccessView? UnorderedAccessView { get; set; }
|
||||
}
|
||||
}
|
||||
13
intromat/Intromat/Model/ITypedVariableDefinition.cs
Normal file
13
intromat/Intromat/Model/ITypedVariableDefinition.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using Intromat.Model.Compiler;
|
||||
|
||||
namespace Intromat.Model
|
||||
{
|
||||
public interface IVariableDefinition : IStatement
|
||||
{
|
||||
string? VariableName { get; }
|
||||
}
|
||||
|
||||
public interface ITypedVariableDefinition<T> : IVariableDefinition
|
||||
{
|
||||
}
|
||||
}
|
||||
25
intromat/Intromat/Model/InlineVariableDefinition.cs
Normal file
25
intromat/Intromat/Model/InlineVariableDefinition.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Intromat.Model.Compiler;
|
||||
|
||||
namespace Intromat.Model
|
||||
{
|
||||
public class InlineVariableDefinition<T> : ITypedVariableDefinition<T>
|
||||
{
|
||||
public ITypedExpression<T>? Value { get; set; }
|
||||
public string? VariableName { get; private set; }
|
||||
|
||||
public void Compile(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
VariableName = context.FindFreeVariableName();
|
||||
context.AddVariableToCurrentScope(this);
|
||||
sb.Append($"{VariableName} = ");
|
||||
Debug.Assert(Value != null, nameof(Value) + " != null");
|
||||
Value.Compile(context, sb);
|
||||
}
|
||||
|
||||
public void CompileHeader(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
24
intromat/Intromat/Model/LocalVariableDefinition.cs
Normal file
24
intromat/Intromat/Model/LocalVariableDefinition.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Intromat.Model.Compiler;
|
||||
|
||||
namespace Intromat.Model
|
||||
{
|
||||
public class LocalVariableDefinition<T> : ITypedVariableDefinition<T>
|
||||
{
|
||||
public string? Value { get; set; }
|
||||
public string? VariableName { get; private set; }
|
||||
|
||||
public void Compile(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
VariableName = context.FindFreeVariableName();
|
||||
context.AddVariableToCurrentScope(this);
|
||||
Debug.Assert(Value != null, nameof(Value) + " != null");
|
||||
sb.Append($"local {VariableName} = {Value}\n");
|
||||
}
|
||||
|
||||
public void CompileHeader(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
14
intromat/Intromat/Nodes/Code/BooleanLiteralModel.cs
Normal file
14
intromat/Intromat/Nodes/Code/BooleanLiteralModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
[XmlRoot("BooleanLiteral", Namespace = _namespace)]
|
||||
public sealed class BooleanLiteralModel : LiteralModelBase<bool>
|
||||
{
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new BooleanLiteralNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
66
intromat/Intromat/Nodes/Code/BooleanLiteralNode.cs
Normal file
66
intromat/Intromat/Nodes/Code/BooleanLiteralNode.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.ViewModels.Previews;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class BooleanLiteralNode : CodeGenNodeViewModel
|
||||
{
|
||||
static BooleanLiteralNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<BooleanLiteralNode>));
|
||||
}
|
||||
|
||||
public BooleanLiteralNode() : base(NodeType.Literal)
|
||||
{
|
||||
Name = "Boolean";
|
||||
|
||||
Output = new CodeGenOutputViewModel<ITypedExpression<bool>>(EPortType.Boolean)
|
||||
{
|
||||
Name = "Value",
|
||||
Editor = ValueEditor,
|
||||
Value = ValueEditor.ValueChanged.Select(v => new BooleanLiteralValue { Value = v })
|
||||
};
|
||||
Outputs.Add(Output);
|
||||
|
||||
var stringPreview = new StringPreviewViewModel();
|
||||
Preview = stringPreview;
|
||||
|
||||
this.WhenAnyValue(vm => vm.Output.CurrentValue)
|
||||
.Where(v => v != null)
|
||||
.Subscribe(_ => stringPreview.Value = Output.CurrentValue.PreviewValue ?? "False");
|
||||
}
|
||||
|
||||
public BooleanValueEditorViewModel ValueEditor { get; } = new();
|
||||
|
||||
public ValueNodeOutputViewModel<ITypedExpression<bool>> Output { get; }
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new BooleanLiteralModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var booleanLiteral = (BooleanLiteralModel)model;
|
||||
ValueEditor.Value = booleanLiteral.Value;
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var booleanLiteral = (BooleanLiteralModel)model;
|
||||
booleanLiteral.Value = ValueEditor.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
6
intromat/Intromat/Nodes/Code/BooleanLiteralValue.cs
Normal file
6
intromat/Intromat/Nodes/Code/BooleanLiteralValue.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class BooleanLiteralValue : LiteralValueBase<bool>
|
||||
{
|
||||
}
|
||||
}
|
||||
14
intromat/Intromat/Nodes/Code/FloatLiteralModel.cs
Normal file
14
intromat/Intromat/Nodes/Code/FloatLiteralModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
[XmlRoot("FloatLiteral", Namespace = _namespace)]
|
||||
public sealed class FloatLiteralModel : LiteralModelBase<float>
|
||||
{
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new FloatLiteralNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
66
intromat/Intromat/Nodes/Code/FloatLiteralNode.cs
Normal file
66
intromat/Intromat/Nodes/Code/FloatLiteralNode.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.ViewModels.Previews;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class FloatLiteralNode : CodeGenNodeViewModel
|
||||
{
|
||||
static FloatLiteralNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<FloatLiteralNode>));
|
||||
}
|
||||
|
||||
public FloatLiteralNode() : base(NodeType.Literal)
|
||||
{
|
||||
Name = "Float";
|
||||
|
||||
Output = new CodeGenOutputViewModel<ITypedExpression<float>>(EPortType.Float)
|
||||
{
|
||||
Name = "Value",
|
||||
Editor = ValueEditor,
|
||||
Value = ValueEditor.ValueChanged.Select(v => new FloatLiteralValue { Value = v })
|
||||
};
|
||||
Outputs.Add(Output);
|
||||
|
||||
var stringPreview = new StringPreviewViewModel();
|
||||
Preview = stringPreview;
|
||||
|
||||
this.WhenAnyValue(vm => vm.Output.CurrentValue)
|
||||
.Where(v => v != null)
|
||||
.Subscribe(_ => stringPreview.Value = Output.CurrentValue.PreviewValue ?? "0.0");
|
||||
}
|
||||
|
||||
public FloatValueEditorViewModel ValueEditor { get; } = new();
|
||||
|
||||
public ValueNodeOutputViewModel<ITypedExpression<float>> Output { get; }
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new FloatLiteralModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var floatLiteral = (FloatLiteralModel)model;
|
||||
ValueEditor.Value = floatLiteral.Value;
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var floatLiteral = (FloatLiteralModel)model;
|
||||
floatLiteral.Value = ValueEditor.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
9
intromat/Intromat/Nodes/Code/FloatLiteralValue.cs
Normal file
9
intromat/Intromat/Nodes/Code/FloatLiteralValue.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using System.Globalization;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class FloatLiteralValue : LiteralValueBase<float>
|
||||
{
|
||||
public override string? PreviewValue => Value.ToString(CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
19
intromat/Intromat/Nodes/Code/ForLoopModel.cs
Normal file
19
intromat/Intromat/Nodes/Code/ForLoopModel.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
[XmlRoot("ForLoop", Namespace = _namespace)]
|
||||
public sealed class ForLoopModel : NodeModelBase
|
||||
{
|
||||
public IntLiteralModel FirstIndex { get; set; } = null!;
|
||||
|
||||
public IntLiteralModel LastIndex { get; set; } = null!;
|
||||
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new ForLoopNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
114
intromat/Intromat/Nodes/Code/ForLoopNode.cs
Normal file
114
intromat/Intromat/Nodes/Code/ForLoopNode.cs
Normal file
@@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.ViewModels.Previews;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using NodeNetwork.ViewModels;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class ForLoopNode : ExecutionNodeBase
|
||||
{
|
||||
static ForLoopNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<ForLoopNode>));
|
||||
}
|
||||
|
||||
public ForLoopNode() : base(NodeType.Code)
|
||||
{
|
||||
var boundsGroup = new EndpointGroup("Bounds");
|
||||
|
||||
Name = "For Loop";
|
||||
|
||||
LoopBodyFlow = new CodeGenInputViewModel<IStatement>(EPortType.Execution)
|
||||
{
|
||||
Name = "Loop Body",
|
||||
Group = _executionFlowGroup
|
||||
};
|
||||
Inputs.Add(LoopBodyFlow);
|
||||
|
||||
FirstIndex = new CodeGenInputViewModel<ITypedExpression<int>>(EPortType.Integer)
|
||||
{
|
||||
Name = "First Index",
|
||||
Group = boundsGroup,
|
||||
Editor = FirstIndexEditor
|
||||
};
|
||||
Inputs.Add(FirstIndex);
|
||||
|
||||
LastIndex = new CodeGenInputViewModel<ITypedExpression<int>>(EPortType.Integer)
|
||||
{
|
||||
Name = "Last Index",
|
||||
Group = boundsGroup,
|
||||
Editor = LastIndexEditor
|
||||
};
|
||||
|
||||
Inputs.Add(LastIndex);
|
||||
|
||||
var loopBodyChanged = LoopBodyFlow.ValueChanged.Select(_ => Unit.Default).StartWith(Unit.Default);
|
||||
FlowIn.Value = loopBodyChanged
|
||||
.CombineLatest(FlowOutChanged, FirstIndex.ValueChanged, LastIndex.ValueChanged, (bodyChange, endChange, firstI, lastI) => (BodyChange: bodyChange, EndChange: endChange, FirstI: firstI, LastI: lastI))
|
||||
.Select(v => new ForLoopValue
|
||||
{
|
||||
LoopBody = LoopBodyFlow.Value,
|
||||
FlowOut = FlowOut.Value,
|
||||
LowerBound = v.FirstI,
|
||||
UpperBound = v.LastI
|
||||
});
|
||||
|
||||
CurrentIndex = new CodeGenOutputViewModel<ITypedExpression<int>>(EPortType.Integer)
|
||||
{
|
||||
Name = "Current Index",
|
||||
Value = FlowIn.Value.Select(v => new VariableReference<int> { LocalVariable = ((ForLoopValue)v).CurrentIndex })
|
||||
};
|
||||
Outputs.Add(CurrentIndex);
|
||||
|
||||
var stringPreview = new StringPreviewViewModel();
|
||||
Preview = stringPreview;
|
||||
|
||||
FlowIn.Value.Subscribe(v =>
|
||||
{
|
||||
var forLoop = (ForLoopValue)v;
|
||||
stringPreview.Value = $"[{forLoop.LowerBound?.PreviewValue ?? "0"}..{forLoop.UpperBound?.PreviewValue ?? "0"}]";
|
||||
});
|
||||
}
|
||||
|
||||
public ValueNodeInputViewModel<IStatement> LoopBodyFlow { get; }
|
||||
|
||||
public IntegerExpressionEditorViewModel FirstIndexEditor { get; } = new();
|
||||
public ValueNodeInputViewModel<ITypedExpression<int>> FirstIndex { get; }
|
||||
|
||||
public IntegerExpressionEditorViewModel LastIndexEditor { get; } = new();
|
||||
public ValueNodeInputViewModel<ITypedExpression<int>> LastIndex { get; }
|
||||
|
||||
public ValueNodeOutputViewModel<ITypedExpression<int>> CurrentIndex { get; }
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new ForLoopModel();
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var forLoop = (ForLoopModel)model;
|
||||
forLoop.FirstIndex = FirstIndexEditor.CreateModel();
|
||||
forLoop.LastIndex = LastIndexEditor.CreateModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var forLoop = (ForLoopModel)model;
|
||||
FirstIndexEditor.LoadModel(forLoop.FirstIndex);
|
||||
LastIndexEditor.LoadModel(forLoop.LastIndex);
|
||||
}
|
||||
}
|
||||
}
|
||||
48
intromat/Intromat/Nodes/Code/ForLoopValue.cs
Normal file
48
intromat/Intromat/Nodes/Code/ForLoopValue.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Intromat.Model;
|
||||
using Intromat.Model.Compiler;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class ForLoopValue : ExecutionValueBase
|
||||
{
|
||||
public IStatement? LoopBody { get; set; }
|
||||
|
||||
public ITypedExpression<int>? LowerBound { get; set; }
|
||||
public ITypedExpression<int>? UpperBound { get; set; }
|
||||
|
||||
public InlineVariableDefinition<int> CurrentIndex { get; } = new();
|
||||
|
||||
public override void Compile(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
Debug.Assert(UpperBound != null, nameof(UpperBound) + " != null");
|
||||
|
||||
context.EnterNewScope("For loop");
|
||||
|
||||
CurrentIndex.Value = LowerBound;
|
||||
sb.Append("for (");
|
||||
CurrentIndex.Compile(context, sb);
|
||||
sb.Append("; ");
|
||||
sb.Append(CurrentIndex.VariableName);
|
||||
sb.Append(" <= ");
|
||||
UpperBound.Compile(context, sb);
|
||||
sb.Append("; ++");
|
||||
sb.Append(CurrentIndex.VariableName);
|
||||
sb.Append(")\n{\n");
|
||||
LoopBody?.Compile(context, sb);
|
||||
sb.Append("\n}\n");
|
||||
|
||||
context.LeaveScope();
|
||||
|
||||
base.Compile(context, sb);
|
||||
}
|
||||
|
||||
public override void CompileHeader(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
LoopBody?.CompileHeader(context, sb);
|
||||
|
||||
base.CompileHeader(context, sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
31
intromat/Intromat/Nodes/Code/FunctionCall.cs
Normal file
31
intromat/Intromat/Nodes/Code/FunctionCall.cs
Normal file
@@ -0,0 +1,31 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Intromat.Model.Compiler;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class FunctionCall : ExecutionValueBase
|
||||
{
|
||||
public string? FunctionName { get; set; }
|
||||
public List<IExpression> Parameters { get; } = new();
|
||||
|
||||
public override void Compile(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
Debug.Assert(FunctionName != null, nameof(FunctionName) + " != null");
|
||||
|
||||
sb.Append($"{FunctionName}(");
|
||||
for (int i = 0, n = Parameters.Count; i < n; ++i)
|
||||
{
|
||||
var p = Parameters[i];
|
||||
p.Compile(context, sb);
|
||||
if (i != n - 1)
|
||||
sb.Append(", ");
|
||||
}
|
||||
|
||||
sb.Append(")\n");
|
||||
|
||||
base.Compile(context, sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
14
intromat/Intromat/Nodes/Code/IntLiteralModel.cs
Normal file
14
intromat/Intromat/Nodes/Code/IntLiteralModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
[XmlRoot("IntLiteral", Namespace = _namespace)]
|
||||
public sealed class IntLiteralModel : LiteralModelBase<int>
|
||||
{
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new IntLiteralNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
66
intromat/Intromat/Nodes/Code/IntLiteralNode.cs
Normal file
66
intromat/Intromat/Nodes/Code/IntLiteralNode.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.ViewModels.Previews;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class IntLiteralNode : CodeGenNodeViewModel
|
||||
{
|
||||
static IntLiteralNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<IntLiteralNode>));
|
||||
}
|
||||
|
||||
public IntLiteralNode() : base(NodeType.Literal)
|
||||
{
|
||||
Name = "Integer";
|
||||
|
||||
Output = new CodeGenOutputViewModel<ITypedExpression<int>>(EPortType.Integer)
|
||||
{
|
||||
Name = "Value",
|
||||
Editor = ValueEditor,
|
||||
Value = ValueEditor.ValueChanged.Select(v => new IntLiteralValue { Value = v })
|
||||
};
|
||||
Outputs.Add(Output);
|
||||
|
||||
var stringPreview = new StringPreviewViewModel();
|
||||
Preview = stringPreview;
|
||||
|
||||
this.WhenAnyValue(vm => vm.Output.CurrentValue)
|
||||
.Where(v => v != null)
|
||||
.Subscribe(_ => stringPreview.Value = Output.CurrentValue.PreviewValue ?? "0");
|
||||
}
|
||||
|
||||
public IntegerValueEditorViewModel ValueEditor { get; } = new();
|
||||
|
||||
public ValueNodeOutputViewModel<ITypedExpression<int>> Output { get; }
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new IntLiteralModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var intLiteral = (IntLiteralModel)model;
|
||||
ValueEditor.Value = intLiteral.Value;
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var intLiteral = (IntLiteralModel)model;
|
||||
intLiteral.Value = ValueEditor.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
25
intromat/Intromat/Nodes/Code/IntLiteralValue.cs
Normal file
25
intromat/Intromat/Nodes/Code/IntLiteralValue.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
using System;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class IntLiteralValue : LiteralValueBase<int>
|
||||
{
|
||||
public int EvaluateDimension()
|
||||
{
|
||||
var relativeDimension = RelativeSource switch
|
||||
{
|
||||
ERelativeSource.Parent => 1 << ParentValue,
|
||||
ERelativeSource.Input => InputValue,
|
||||
_ => 1
|
||||
};
|
||||
|
||||
var result = Value switch
|
||||
{
|
||||
< 0 => relativeDimension >> -Value,
|
||||
> 0 => relativeDimension << Value,
|
||||
_ => relativeDimension
|
||||
};
|
||||
return Math.Max(1, Math.Min(8192, result));
|
||||
}
|
||||
}
|
||||
}
|
||||
34
intromat/Intromat/Nodes/Code/LiteralModelBase.cs
Normal file
34
intromat/Intromat/Nodes/Code/LiteralModelBase.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.Nodes.Textures;
|
||||
using Intromat.PersistentModel;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public enum ERelativeSource
|
||||
{
|
||||
Custom,
|
||||
Parent,
|
||||
Input
|
||||
}
|
||||
|
||||
[XmlInclude(typeof(IntLiteralModel))]
|
||||
[XmlInclude(typeof(StringLiteralModel))]
|
||||
[XmlInclude(typeof(FloatLiteralModel))]
|
||||
[XmlInclude(typeof(BooleanLiteralModel))]
|
||||
[XmlInclude(typeof(SamplerLiteralModel))]
|
||||
public abstract class LiteralModelBase : NodeModelBase
|
||||
{
|
||||
public ERelativeSource RelativeSource { get; set; }
|
||||
}
|
||||
|
||||
public class LiteralModelEntry
|
||||
{
|
||||
public string Key { get; set; } = null!;
|
||||
public LiteralModelBase Literal { get; set; } = null!;
|
||||
}
|
||||
|
||||
public abstract class LiteralModelBase<T> : LiteralModelBase
|
||||
{
|
||||
public T Value { get; set; } = default!;
|
||||
}
|
||||
}
|
||||
28
intromat/Intromat/Nodes/Code/LiteralValueBase.cs
Normal file
28
intromat/Intromat/Nodes/Code/LiteralValueBase.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System.Text;
|
||||
using Intromat.Model.Compiler;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public abstract class LiteralValueBase<T> : ITypedExpression<T>
|
||||
{
|
||||
public virtual string? PreviewValue => Value?.ToString();
|
||||
|
||||
public T ParentValue { get; set; } = default!;
|
||||
|
||||
public T InputValue { get; set; } = default!;
|
||||
|
||||
public T Value { get; set; } = default!;
|
||||
|
||||
public ERelativeSource RelativeSource { get; set; }
|
||||
|
||||
public virtual void Compile(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
sb.Append(Value);
|
||||
}
|
||||
|
||||
public virtual T Evaluate()
|
||||
{
|
||||
return Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
17
intromat/Intromat/Nodes/Code/PrintModel.cs
Normal file
17
intromat/Intromat/Nodes/Code/PrintModel.cs
Normal file
@@ -0,0 +1,17 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
[XmlRoot("Print", Namespace = _namespace)]
|
||||
public sealed class PrintModel : NodeModelBase
|
||||
{
|
||||
public string? Text { get; set; }
|
||||
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new PrintNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
75
intromat/Intromat/Nodes/Code/PrintNode.cs
Normal file
75
intromat/Intromat/Nodes/Code/PrintNode.cs
Normal file
@@ -0,0 +1,75 @@
|
||||
using System;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.ViewModels.Previews;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class PrintNode : ExecutionNodeBase
|
||||
{
|
||||
static PrintNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<PrintNode>));
|
||||
}
|
||||
|
||||
public PrintNode() : base(NodeType.Code)
|
||||
{
|
||||
Name = "Print";
|
||||
|
||||
Text = new CodeGenInputViewModel<ITypedExpression<string>>(EPortType.String)
|
||||
{
|
||||
Name = "Text",
|
||||
Editor = TextEditor
|
||||
};
|
||||
Inputs.Add(Text);
|
||||
|
||||
FlowIn.Value = FlowOutChanged
|
||||
.CombineLatest(Text.ValueChanged, (flowOutChanged, textValueChanged) => (FlowOutChanged: flowOutChanged, StringExpression: textValueChanged))
|
||||
.Select(v => new FunctionCall
|
||||
{
|
||||
FunctionName = "print",
|
||||
FlowOut = FlowOut.Value,
|
||||
Parameters = { v.StringExpression ?? new StringLiteralValue { Value = "" } }
|
||||
});
|
||||
|
||||
var stringPreview = new StringPreviewViewModel();
|
||||
Preview = stringPreview;
|
||||
|
||||
this.WhenAnyValue(vm => vm.Text.Value)
|
||||
.Where(v => v != null)
|
||||
.Subscribe(_ => stringPreview.Value = Text.Value.PreviewValue ?? string.Empty);
|
||||
}
|
||||
|
||||
public StringExpressionEditorViewModel TextEditor { get; } = new();
|
||||
|
||||
public ValueNodeInputViewModel<ITypedExpression<string>> Text { get; }
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new PrintModel();
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var print = (PrintModel)model;
|
||||
print.Text = TextEditor.Value is StringLiteralValue text ? text.Value : null;
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var print = (PrintModel)model;
|
||||
if (print.Text != null)
|
||||
TextEditor.Value = new StringLiteralValue { Value = print.Text };
|
||||
}
|
||||
}
|
||||
}
|
||||
14
intromat/Intromat/Nodes/Code/StringFileModel.cs
Normal file
14
intromat/Intromat/Nodes/Code/StringFileModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
[XmlRoot("StringFile", Namespace = _namespace)]
|
||||
public sealed class StringFileModel : LiteralModelBase<string?>
|
||||
{
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new StringFileNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
121
intromat/Intromat/Nodes/Code/StringFileNode.cs
Normal file
121
intromat/Intromat/Nodes/Code/StringFileNode.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.ViewModels.Previews;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using NodeNetwork.Utilities;
|
||||
using ReactiveUI;
|
||||
using RxFileSystemWatcher;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class StringFileNode : CodeGenNodeViewModel
|
||||
{
|
||||
private readonly ObservableAsPropertyHelper<ObservableFileSystemWatcher> _fileWatcher;
|
||||
private readonly ObservableAsPropertyHelper<string> _fullPath;
|
||||
|
||||
static StringFileNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<StringFileNode>));
|
||||
}
|
||||
|
||||
public StringFileNode()
|
||||
: base(NodeType.Literal)
|
||||
{
|
||||
Name = "String (file)";
|
||||
|
||||
Path = new CodeGenInputViewModel<string?>(EPortType.String)
|
||||
{
|
||||
Name = "Path",
|
||||
Editor = PathEditor,
|
||||
};
|
||||
Inputs.Add(Path);
|
||||
|
||||
Contents = new CodeGenOutputViewModel<ITypedExpression<string?>>(EPortType.String)
|
||||
{
|
||||
Name = "Contents",
|
||||
};
|
||||
|
||||
var stringPreview = new StringPreviewViewModel();
|
||||
Preview = stringPreview;
|
||||
|
||||
this.WhenAnyValue(vm => vm.Parent, vm => vm.Path.Value)
|
||||
.Where(pair => pair.Item1 != null && pair.Item2 != null)
|
||||
.Select(pair => System.IO.Path.Combine(((CodeGenNetworkViewModel)pair.Item1).Document.Parent.FullPath, pair.Item2!))
|
||||
.StartWith(string.Empty)
|
||||
.ToProperty(this, vm => vm.FullPath, out _fullPath);
|
||||
|
||||
this.WhenAnyValue(vm => vm.FullPath)
|
||||
.Where(File.Exists)
|
||||
.Select(path => new ObservableFileSystemWatcher(c =>
|
||||
{
|
||||
c.Path = System.IO.Path.GetDirectoryName(path)!;
|
||||
}))
|
||||
.ToProperty(this, vm => vm.FileWatcher, out _fileWatcher);
|
||||
|
||||
Contents.Value = this.WhenAnyValue(vm => vm.FileWatcher)
|
||||
.PairWithPreviousValue()
|
||||
.Select(pair =>
|
||||
{
|
||||
var oldWatcher = pair.OldValue;
|
||||
var newWatcher = pair.NewValue;
|
||||
|
||||
oldWatcher?.Dispose();
|
||||
if (newWatcher != null)
|
||||
{
|
||||
stringPreview.Value = Path.Value!;
|
||||
var result =
|
||||
newWatcher.Renamed.Where(e => e.FullPath == FullPath)
|
||||
.Merge(newWatcher.Changed.Where(e => e.FullPath == FullPath))
|
||||
.Throttle(TimeSpan.FromMilliseconds(100))
|
||||
.Select(_ => new StringLiteralValue() { Value = File.ReadAllText(FullPath) })
|
||||
.StartWith(new StringLiteralValue() { Value = File.ReadAllText(FullPath) });
|
||||
newWatcher.Start();
|
||||
return result;
|
||||
}
|
||||
|
||||
stringPreview.Value = string.Empty;
|
||||
return Observable.Empty<StringLiteralValue>();
|
||||
})
|
||||
.Switch();
|
||||
|
||||
Outputs.Add(Contents);
|
||||
}
|
||||
|
||||
public ObservableFileSystemWatcher FileWatcher => _fileWatcher.Value;
|
||||
|
||||
public string FullPath => _fullPath.Value;
|
||||
|
||||
public StringValueEditorViewModel PathEditor { get; } = new();
|
||||
|
||||
public ValueNodeInputViewModel<string?> Path { get; }
|
||||
|
||||
public ValueNodeOutputViewModel<ITypedExpression<string?>> Contents { get; }
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new StringFileModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var fileModel = (StringFileModel)model;
|
||||
PathEditor.Value = fileModel.Value;
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var fileModel = (StringFileModel)model;
|
||||
fileModel.Value = PathEditor.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
14
intromat/Intromat/Nodes/Code/StringLiteralModel.cs
Normal file
14
intromat/Intromat/Nodes/Code/StringLiteralModel.cs
Normal file
@@ -0,0 +1,14 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
[XmlRoot("StringLiteral", Namespace = _namespace)]
|
||||
public sealed class StringLiteralModel : LiteralModelBase<string?>
|
||||
{
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new StringLiteralNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
66
intromat/Intromat/Nodes/Code/StringLiteralNode.cs
Normal file
66
intromat/Intromat/Nodes/Code/StringLiteralNode.cs
Normal file
@@ -0,0 +1,66 @@
|
||||
using System;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.ViewModels.Previews;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class StringLiteralNode : CodeGenNodeViewModel
|
||||
{
|
||||
static StringLiteralNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<StringLiteralNode>));
|
||||
}
|
||||
|
||||
public StringLiteralNode() : base(NodeType.Literal)
|
||||
{
|
||||
Name = "String";
|
||||
|
||||
Output = new CodeGenOutputViewModel<ITypedExpression<string?>>(EPortType.String)
|
||||
{
|
||||
Name = "Value",
|
||||
Editor = ValueEditor,
|
||||
Value = ValueEditor.ValueChanged.Select(v => new StringLiteralValue { Value = v })
|
||||
};
|
||||
Outputs.Add(Output);
|
||||
|
||||
var stringPreview = new StringPreviewViewModel();
|
||||
Preview = stringPreview;
|
||||
|
||||
this.WhenAnyValue(vm => vm.Output.CurrentValue)
|
||||
.Where(v => v != null)
|
||||
.Subscribe(_ => stringPreview.Value = ((StringLiteralValue)Output.CurrentValue).Value ?? string.Empty);
|
||||
}
|
||||
|
||||
public StringValueEditorViewModel ValueEditor { get; } = new();
|
||||
|
||||
public ValueNodeOutputViewModel<ITypedExpression<string?>> Output { get; }
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new StringLiteralModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var textLiteral = (StringLiteralModel)model;
|
||||
ValueEditor.Value = textLiteral.Value;
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var textLiteral = (StringLiteralModel)model;
|
||||
textLiteral.Value = ValueEditor.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
21
intromat/Intromat/Nodes/Code/StringLiteralValue.cs
Normal file
21
intromat/Intromat/Nodes/Code/StringLiteralValue.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Intromat.Model.Compiler;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class StringLiteralValue : LiteralValueBase<string?>
|
||||
{
|
||||
public override string? PreviewValue => Value;
|
||||
|
||||
public override void Compile(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
sb.Append($"\"{Value}\"");
|
||||
}
|
||||
|
||||
public override string Evaluate()
|
||||
{
|
||||
return Value ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
32
intromat/Intromat/Nodes/Code/VariableReference.cs
Normal file
32
intromat/Intromat/Nodes/Code/VariableReference.cs
Normal file
@@ -0,0 +1,32 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Text;
|
||||
using Intromat.Model;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.Model.Compiler.Error;
|
||||
|
||||
namespace Intromat.Nodes.Code
|
||||
{
|
||||
public class VariableReference<T> : ITypedExpression<T>
|
||||
{
|
||||
public string? PreviewValue => LocalVariable?.VariableName;
|
||||
|
||||
public ITypedVariableDefinition<T>? LocalVariable { get; set; }
|
||||
|
||||
public void Compile(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
var localVariable = LocalVariable;
|
||||
Debug.Assert(localVariable != null, nameof(localVariable) + " != null");
|
||||
Debug.Assert(localVariable.VariableName != null, $"{nameof(localVariable)}.{nameof(localVariable.VariableName)} != null");
|
||||
|
||||
if (!context.IsInScope(localVariable))
|
||||
throw new VariableOutOfScopeException(localVariable.VariableName);
|
||||
|
||||
sb.Append(localVariable.VariableName);
|
||||
}
|
||||
public T Evaluate()
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
28
intromat/Intromat/Nodes/DxNodeBase.cs
Normal file
28
intromat/Intromat/Nodes/DxNodeBase.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using System;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.ViewModels;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using NodeNetwork.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes
|
||||
{
|
||||
public abstract class DxNodeBase : CodeGenNodeViewModel
|
||||
{
|
||||
protected DxNodeBase()
|
||||
: base(NodeType.Literal)
|
||||
{
|
||||
AnyInputChanged = Inputs
|
||||
.Connect()
|
||||
.Filter(input => input is ValueNodeInputViewModelBase)
|
||||
.WhenValueChanged(input => ((ValueNodeInputViewModelBase)input).UnitValueChanged)
|
||||
.SelectMany(i => i!);
|
||||
|
||||
AnyInputChanged.Subscribe(_ => { });
|
||||
Resizable = ResizeOrientation.HorizontalAndVertical;
|
||||
}
|
||||
|
||||
public IObservable<Unit> AnyInputChanged { get; }
|
||||
}
|
||||
}
|
||||
44
intromat/Intromat/Nodes/ExecutionNodeBase.cs
Normal file
44
intromat/Intromat/Nodes/ExecutionNodeBase.cs
Normal file
@@ -0,0 +1,44 @@
|
||||
using System;
|
||||
using System.Reactive;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.ViewModels;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using NodeNetwork.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes
|
||||
{
|
||||
public abstract class ExecutionNodeBase : CodeGenNodeViewModel
|
||||
{
|
||||
protected readonly EndpointGroup _executionFlowGroup;
|
||||
|
||||
protected ExecutionNodeBase(NodeType type)
|
||||
: base(type)
|
||||
{
|
||||
_executionFlowGroup = new EndpointGroup("Execution Flow");
|
||||
|
||||
FlowOut = new CodeGenInputViewModel<IStatement>(EPortType.Execution)
|
||||
{
|
||||
Name = "Flow",
|
||||
Group = _executionFlowGroup
|
||||
};
|
||||
Inputs.Add(FlowOut);
|
||||
|
||||
FlowOutChanged = FlowOut.ValueChanged.Select(_ => Unit.Default).StartWith(Unit.Default);
|
||||
|
||||
FlowIn = new CodeGenOutputViewModel<IStatement>(EPortType.Execution)
|
||||
{
|
||||
Name = "Flow",
|
||||
Group = _executionFlowGroup
|
||||
};
|
||||
Outputs.Add(FlowIn);
|
||||
}
|
||||
|
||||
public ValueNodeOutputViewModel<IStatement> FlowIn { get; }
|
||||
|
||||
public ValueNodeInputViewModel<IStatement> FlowOut { get; }
|
||||
|
||||
public IObservable<Unit> FlowOutChanged { get; }
|
||||
}
|
||||
}
|
||||
24
intromat/Intromat/Nodes/ExecutionValueBase.cs
Normal file
24
intromat/Intromat/Nodes/ExecutionValueBase.cs
Normal file
@@ -0,0 +1,24 @@
|
||||
using System.Text;
|
||||
using Intromat.Model.Compiler;
|
||||
|
||||
namespace Intromat.Nodes
|
||||
{
|
||||
public abstract class ExecutionValueBase : IStatement
|
||||
{
|
||||
public IStatement? FlowOut { get; set; }
|
||||
|
||||
public virtual void Compile(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
if (FlowOut != null)
|
||||
{
|
||||
FlowOut.Compile(context, sb);
|
||||
sb.Append("\n");
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void CompileHeader(CompilerContext context, StringBuilder sb)
|
||||
{
|
||||
FlowOut?.CompileHeader(context, sb);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
intromat/Intromat/Nodes/MainEntryPointModel.cs
Normal file
15
intromat/Intromat/Nodes/MainEntryPointModel.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes
|
||||
{
|
||||
[XmlRoot("MainEntryPoint", Namespace = _namespace)]
|
||||
public sealed class MainEntryPointModel : NodeModelBase
|
||||
{
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new MainEntryPointNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
36
intromat/Intromat/Nodes/MainEntryPointNode.cs
Normal file
36
intromat/Intromat/Nodes/MainEntryPointNode.cs
Normal file
@@ -0,0 +1,36 @@
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using ReactiveUI;
|
||||
using Splat;
|
||||
|
||||
namespace Intromat.Nodes
|
||||
{
|
||||
public class MainEntryPointNode : CodeGenNodeViewModel
|
||||
{
|
||||
static MainEntryPointNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<MainEntryPointNode>));
|
||||
}
|
||||
|
||||
public MainEntryPointNode()
|
||||
: base(NodeType.Special)
|
||||
{
|
||||
Name = "Main";
|
||||
|
||||
OnClickFlow = new CodeGenInputViewModel<IStatement>(EPortType.Execution) { Name = "Entry point" };
|
||||
|
||||
Inputs.Add(OnClickFlow);
|
||||
}
|
||||
|
||||
public ValueNodeInputViewModel<IStatement> OnClickFlow { get; }
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new MainEntryPointModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
8
intromat/Intromat/Nodes/Meshes/DxMeshModelBase.cs
Normal file
8
intromat/Intromat/Nodes/Meshes/DxMeshModelBase.cs
Normal file
@@ -0,0 +1,8 @@
|
||||
using Intromat.PersistentModel;
|
||||
|
||||
namespace Intromat.Nodes.Meshes
|
||||
{
|
||||
public abstract class DxMeshModelBase : NodeModelBase
|
||||
{
|
||||
}
|
||||
}
|
||||
97
intromat/Intromat/Nodes/Meshes/DxMeshNodeBase.cs
Normal file
97
intromat/Intromat/Nodes/Meshes/DxMeshNodeBase.cs
Normal file
@@ -0,0 +1,97 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Graphics;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.Nodes.Code;
|
||||
using Intromat.Nodes.Meshes;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.ViewModels.Previews;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using NodeNetwork.ViewModels;
|
||||
using ReactiveUI;
|
||||
using SharpDX.Direct3D11;
|
||||
using SharpDX.DXGI;
|
||||
using Splat;
|
||||
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||
using Device = SharpDX.Direct3D11.Device;
|
||||
|
||||
namespace Intromat.Nodes.Meshs
|
||||
{
|
||||
[CategoryOrder("Mesh", 0)]
|
||||
public abstract class DxMeshNodeBase : DxNodeBase
|
||||
{
|
||||
protected MeshValue? _output;
|
||||
protected bool _resourcesCreated;
|
||||
|
||||
protected DxMeshNodeBase()
|
||||
{
|
||||
var meshGroup = new EndpointGroup("Mesh");
|
||||
Outputs.Add(Output = new CodeGenOutputViewModel<MeshValue?>(EPortType.Mesh)
|
||||
{
|
||||
Name = "Output",
|
||||
Group = meshGroup
|
||||
});
|
||||
|
||||
var dxHost = Locator.Current.GetService<DxHost>()!;
|
||||
Output.Value = this
|
||||
.WhenAnyObservable(vm => vm.ParentChanged, vm => vm.AnyInputChanged, (parent, _) => parent)
|
||||
.Where(parent => parent != null)
|
||||
.Throttle(TimeSpan.FromMilliseconds(1))
|
||||
.ObserveOn(dxHost.RenderDispatcher)
|
||||
.Do(_ => { UpdateFrame(dxHost.Device, dxHost.Device.ImmediateContext); })
|
||||
.Select(_ => new MeshValue(_output!));
|
||||
|
||||
var dxMeshPreviewViewModel = new DxMeshPreviewViewModel(this, Output.Value);
|
||||
Preview = dxMeshPreviewViewModel;
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(_output))]
|
||||
protected bool EnsureBuffers(Device device)
|
||||
{
|
||||
return EnsureMesh(device, ref _output);
|
||||
}
|
||||
|
||||
protected bool EnsureMesh(Device device, [NotNull] ref MeshValue? meshValue)
|
||||
{
|
||||
meshValue = null!;
|
||||
//if (false) // TODO: changed
|
||||
//{
|
||||
// return true;
|
||||
//}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual void UpdateFrame(Device device, DeviceContext deviceContext)
|
||||
{
|
||||
if (!_resourcesCreated)
|
||||
{
|
||||
_resourcesCreated = true;
|
||||
CreateDeviceResources(device);
|
||||
}
|
||||
EnsureBuffers(device);
|
||||
}
|
||||
|
||||
protected virtual void CreateDeviceResources(Device device)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var meshModel = (DxMeshModelBase)model;
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var meshModel = (DxMeshModelBase)model;
|
||||
}
|
||||
|
||||
public ValueNodeOutputViewModel<MeshValue?> Output { get; }
|
||||
}
|
||||
}
|
||||
22
intromat/Intromat/Nodes/Textures/Blend2DColorModel.cs
Normal file
22
intromat/Intromat/Nodes/Textures/Blend2DColorModel.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System;
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Textures
|
||||
{
|
||||
[XmlRoot("Blend2DColor", Namespace = _namespace)]
|
||||
public class Blend2DColorModel : DxTextureModelBase
|
||||
{
|
||||
public enum EBlendMode
|
||||
{
|
||||
Multiply
|
||||
}
|
||||
|
||||
public EBlendMode BlendMode { get; set; }
|
||||
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new Blend2DColorNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
129
intromat/Intromat/Nodes/Textures/Blend2DColorNode.cs
Normal file
129
intromat/Intromat/Nodes/Textures/Blend2DColorNode.cs
Normal file
@@ -0,0 +1,129 @@
|
||||
using System;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using ReactiveUI;
|
||||
using SharpDX.D3DCompiler;
|
||||
using SharpDX.Direct3D11;
|
||||
using Splat;
|
||||
using Buffer = SharpDX.Direct3D11.Buffer;
|
||||
|
||||
namespace Intromat.Nodes.Textures
|
||||
{
|
||||
public class Blend2DColorNode : DxTextureFilterNodeBase
|
||||
{
|
||||
private Buffer? _constantBuffer;
|
||||
private ComputeShader? _cs;
|
||||
private const string _computeShader = @"cbuffer cb
|
||||
{
|
||||
int m;
|
||||
}
|
||||
|
||||
Texture2D tSource;
|
||||
Texture2D tTarget;
|
||||
SamplerState ss;
|
||||
RWTexture2D<float4> o;
|
||||
[numthreads(16,16,1)]
|
||||
void main(in uint3 i : SV_DispatchThreadID)
|
||||
{
|
||||
float2 dim;
|
||||
o.GetDimensions(dim.x, dim.y);
|
||||
float2 uv = i.xy / dim;
|
||||
float4 src = tSource.SampleLevel(ss, uv, 0);
|
||||
float4 dst = tTarget.SampleLevel(ss, uv, 0);
|
||||
switch (m)
|
||||
{
|
||||
case 0: o[i.xy] = src * dst; break;
|
||||
}
|
||||
}";
|
||||
|
||||
static Blend2DColorNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<Blend2DColorNode>));
|
||||
}
|
||||
|
||||
public Blend2DColorNode()
|
||||
{
|
||||
Name = "Blend";
|
||||
|
||||
Inputs.Add(Target = new CodeGenInputViewModel<TextureValue?>(EPortType.Texture)
|
||||
{
|
||||
Name = "Target",
|
||||
Group = Width.Group
|
||||
});
|
||||
|
||||
Inputs.Add(BlendMode = new CodeGenInputViewModel<int>(EPortType.None)
|
||||
{
|
||||
Name = "Blend mode",
|
||||
Group = Width.Group,
|
||||
Editor = BlendModeEditor
|
||||
});
|
||||
}
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new Blend2DColorModel();
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var blend2D = (Blend2DColorModel)model;
|
||||
blend2D.BlendMode = (Blend2DColorModel.EBlendMode)BlendModeEditor.Value;
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var blend2D = (Blend2DColorModel)model;
|
||||
BlendModeEditor.Value = (int)blend2D.BlendMode;
|
||||
}
|
||||
|
||||
protected override void CreateDeviceResources(Device device)
|
||||
{
|
||||
base.CreateDeviceResources(device);
|
||||
|
||||
var bufferDesc = new BufferDescription(16, ResourceUsage.Dynamic, BindFlags.ConstantBuffer, CpuAccessFlags.Write, ResourceOptionFlags.None, 0);
|
||||
_constantBuffer = new Buffer(device, bufferDesc);
|
||||
var flags = ShaderFlags.None;
|
||||
#if DEBUG
|
||||
flags |= ShaderFlags.Debug;
|
||||
#endif
|
||||
_cs = new ComputeShader(device, ShaderBytecode.Compile(_computeShader, "main", "cs_5_0", flags).Bytecode.Data);
|
||||
}
|
||||
|
||||
protected override unsafe void UpdateFrame(Device device, DeviceContext context)
|
||||
{
|
||||
base.UpdateFrame(device, context);
|
||||
var srvSource = Input.Value?.ShaderResourceView;
|
||||
var srvTarget = Target.Value?.ShaderResourceView;
|
||||
if (srvSource == null || srvTarget == null)
|
||||
return;
|
||||
|
||||
context.MapSubresource(_constantBuffer, 0, MapMode.WriteDiscard, MapFlags.None, out var stream);
|
||||
var ints = new Span<int>((void*)stream.DataPointer, 4);
|
||||
ints[0] = BlendMode.Value;
|
||||
context.UnmapSubresource(_constantBuffer, 0);
|
||||
|
||||
context.ComputeShader.SetConstantBuffer(0, _constantBuffer);
|
||||
context.ComputeShader.SetShaderResource(0, srvSource);
|
||||
context.ComputeShader.SetShaderResource(1, srvTarget);
|
||||
context.ComputeShader.SetSampler(0, _samplerState);
|
||||
context.ComputeShader.SetShader(_cs, null, 0);
|
||||
context.ComputeShader.SetUnorderedAccessView(0, _output!.UnorderedAccessView);
|
||||
context.Dispatch(_texDesc.Width / 16, _texDesc.Height / 16, 1);
|
||||
context.ComputeShader.SetShaderResource(0, null);
|
||||
context.ComputeShader.SetShaderResource(1, null);
|
||||
context.ComputeShader.SetUnorderedAccessView(0, null);
|
||||
}
|
||||
|
||||
public ValueNodeInputViewModel<TextureValue?> Target { get; }
|
||||
|
||||
public EnumEditorViewModel BlendModeEditor { get; } = new(typeof(Blend2DColorModel.EBlendMode));
|
||||
public ValueNodeInputViewModel<int> BlendMode { get; }
|
||||
}
|
||||
}
|
||||
39
intromat/Intromat/Nodes/Textures/DxTextureFilterNodeBase.cs
Normal file
39
intromat/Intromat/Nodes/Textures/DxTextureFilterNodeBase.cs
Normal file
@@ -0,0 +1,39 @@
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.ViewModels;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using SharpDX.Direct3D11;
|
||||
|
||||
namespace Intromat.Nodes.Textures
|
||||
{
|
||||
public abstract class DxTextureFilterNodeBase : DxTextureNodeBase
|
||||
{
|
||||
protected SamplerState? _samplerState;
|
||||
|
||||
protected DxTextureFilterNodeBase()
|
||||
{
|
||||
Inputs.Add(Input = new CodeGenInputViewModel<TextureValue?>(EPortType.Texture)
|
||||
{
|
||||
Name = "Input",
|
||||
Group = Width.Group
|
||||
});
|
||||
var inputObservable = Input.ValueChanged;
|
||||
WidthEditor.InputValueProvider = inputObservable.Select(input => input?.Width ?? 0);
|
||||
HeightEditor.InputValueProvider = inputObservable.Select(input => input?.Height ?? 0);
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(_samplerState))]
|
||||
protected override void CreateDeviceResources(Device device)
|
||||
{
|
||||
base.CreateDeviceResources(device);
|
||||
|
||||
var samplerDesc = SamplerStateDescription.Default();
|
||||
samplerDesc.Filter = Filter.MinMagMipLinear;
|
||||
_samplerState = new SamplerState(device, samplerDesc);
|
||||
}
|
||||
|
||||
public ValueNodeInputViewModel<TextureValue?> Input { get; }
|
||||
}
|
||||
}
|
||||
12
intromat/Intromat/Nodes/Textures/DxTextureModelBase.cs
Normal file
12
intromat/Intromat/Nodes/Textures/DxTextureModelBase.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using Intromat.Nodes.Code;
|
||||
using Intromat.PersistentModel;
|
||||
|
||||
namespace Intromat.Nodes.Textures
|
||||
{
|
||||
public abstract class DxTextureModelBase : NodeModelBase
|
||||
{
|
||||
public IntLiteralModel Width { get; set; } = null!;
|
||||
|
||||
public IntLiteralModel Height { get; set; } = null!;
|
||||
}
|
||||
}
|
||||
157
intromat/Intromat/Nodes/Textures/DxTextureNodeBase.cs
Normal file
157
intromat/Intromat/Nodes/Textures/DxTextureNodeBase.cs
Normal file
@@ -0,0 +1,157 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Graphics;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.Nodes.Code;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.ViewModels.Previews;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using NodeNetwork.ViewModels;
|
||||
using ReactiveUI;
|
||||
using SharpDX.Direct3D11;
|
||||
using SharpDX.DXGI;
|
||||
using Splat;
|
||||
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||
using Device = SharpDX.Direct3D11.Device;
|
||||
|
||||
namespace Intromat.Nodes.Textures
|
||||
{
|
||||
[CategoryOrder("Texture", 0)]
|
||||
public abstract class DxTextureNodeBase : DxNodeBase
|
||||
{
|
||||
protected TextureValue? _output;
|
||||
protected Texture2DDescription _texDesc;
|
||||
protected bool _resourcesCreated;
|
||||
|
||||
protected DxTextureNodeBase()
|
||||
{
|
||||
var textureGroup = new EndpointGroup("Texture");
|
||||
var parentObservable = this.WhenAnyObservable(vm => vm.ParentChanged).Select(parent => (CodeGenNetworkViewModel?)parent);
|
||||
Inputs.Add(Width = new CodeGenInputViewModel<ITypedExpression<int>>(EPortType.None)
|
||||
{
|
||||
Name = "Width",
|
||||
Group = textureGroup,
|
||||
Editor = WidthEditor = new()
|
||||
{
|
||||
ParentValueProvider = parentObservable.Select(parent => parent?.DefaultWidth ?? -1),
|
||||
MinValue = -16,
|
||||
MaxValue = 16,
|
||||
CustomValue = 0,
|
||||
RelativeSource = ERelativeSource.Parent
|
||||
}
|
||||
});
|
||||
Inputs.Add(Height = new CodeGenInputViewModel<ITypedExpression<int>>(EPortType.None)
|
||||
{
|
||||
Name = "Height",
|
||||
Group = textureGroup,
|
||||
Editor = HeightEditor = new()
|
||||
{
|
||||
ParentValueProvider = parentObservable.Select(parent => parent?.DefaultHeight ?? -1),
|
||||
MinValue = -16,
|
||||
MaxValue = 16,
|
||||
CustomValue = 0,
|
||||
RelativeSource = ERelativeSource.Parent
|
||||
}
|
||||
});
|
||||
Outputs.Add(Output = new CodeGenOutputViewModel<TextureValue?>(EPortType.Texture)
|
||||
{
|
||||
Name = "Output",
|
||||
Group = textureGroup
|
||||
});
|
||||
|
||||
var dxHost = Locator.Current.GetService<DxHost>()!;
|
||||
Output.Value = this
|
||||
.WhenAnyObservable(vm => vm.ParentChanged, vm => vm.AnyInputChanged, (parent, _) => parent)
|
||||
.Where(parent => parent != null)
|
||||
.Throttle(TimeSpan.FromMilliseconds(1))
|
||||
.ObserveOn(dxHost.RenderDispatcher)
|
||||
.Do(_ => { UpdateFrame(dxHost.Device, dxHost.Device.ImmediateContext); })
|
||||
.Select(_ => new TextureValue(_output!));
|
||||
|
||||
var dxTexturePreviewViewModel = new DxTexturePreviewViewModel(this, Output.Value);
|
||||
Preview = dxTexturePreviewViewModel;
|
||||
|
||||
_texDesc = new Texture2DDescription
|
||||
{
|
||||
ArraySize = 1,
|
||||
Format = Format.R16G16B16A16_Float,
|
||||
BindFlags = BindFlags.ShaderResource | BindFlags.UnorderedAccess,
|
||||
Usage = ResourceUsage.Default,
|
||||
SampleDescription = new(1, 0)
|
||||
};
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(_output))]
|
||||
protected bool EnsureBuffers(Device device)
|
||||
{
|
||||
return EnsureTexture(device, ref _output);
|
||||
}
|
||||
|
||||
protected bool EnsureTexture(Device device, [NotNull] ref TextureValue? textureValue)
|
||||
{
|
||||
var width = ((IntLiteralValue)Width.Value).EvaluateDimension();
|
||||
var height = ((IntLiteralValue)Height.Value).EvaluateDimension();
|
||||
if (_texDesc.Width != width || _texDesc.Height != height || textureValue == null)
|
||||
{
|
||||
textureValue?.ShaderResourceView?.Resource?.Dispose();
|
||||
textureValue?.ShaderResourceView?.Dispose();
|
||||
textureValue?.UnorderedAccessView?.Dispose();
|
||||
|
||||
_texDesc.Width = width;
|
||||
_texDesc.Height = height;
|
||||
var texture = new Texture2D(device, _texDesc);
|
||||
|
||||
textureValue ??= new TextureValue();
|
||||
textureValue.Width = width;
|
||||
textureValue.Height = height;
|
||||
textureValue.ShaderResourceView = new ShaderResourceView(device, texture);
|
||||
textureValue.UnorderedAccessView = new UnorderedAccessView(device, texture);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
protected virtual void UpdateFrame(Device device, DeviceContext deviceContext)
|
||||
{
|
||||
if (!_resourcesCreated)
|
||||
{
|
||||
_resourcesCreated = true;
|
||||
CreateDeviceResources(device);
|
||||
}
|
||||
EnsureBuffers(device);
|
||||
}
|
||||
|
||||
protected virtual void CreateDeviceResources(Device device)
|
||||
{
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var textureModel = (DxTextureModelBase)model;
|
||||
textureModel.Width = WidthEditor.CreateModel();
|
||||
textureModel.Height = HeightEditor.CreateModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var textureModel = (DxTextureModelBase)model;
|
||||
WidthEditor.LoadModel(textureModel.Width);
|
||||
HeightEditor.LoadModel(textureModel.Height);
|
||||
}
|
||||
|
||||
public DimensionEditorViewModel WidthEditor { get; }
|
||||
public ValueNodeInputViewModel<ITypedExpression<int>> Width { get; }
|
||||
|
||||
public DimensionEditorViewModel HeightEditor { get; }
|
||||
public ValueNodeInputViewModel<ITypedExpression<int>> Height { get; }
|
||||
|
||||
public ValueNodeOutputViewModel<TextureValue?> Output { get; }
|
||||
}
|
||||
}
|
||||
23
intromat/Intromat/Nodes/Textures/SamplerDesc.cs
Normal file
23
intromat/Intromat/Nodes/Textures/SamplerDesc.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using ReactiveUI;
|
||||
using SharpDX.Direct3D11;
|
||||
|
||||
namespace Intromat.Nodes.Textures
|
||||
{
|
||||
public class SamplerDesc : ReactiveObject
|
||||
{
|
||||
private Filter _filter = SamplerStateDescription.Default().Filter;
|
||||
private TextureAddressMode _address = SamplerStateDescription.Default().AddressU;
|
||||
|
||||
public Filter Filter
|
||||
{
|
||||
get => _filter;
|
||||
set => this.RaiseAndSetIfChanged(ref _filter, value);
|
||||
}
|
||||
|
||||
public TextureAddressMode Address
|
||||
{
|
||||
get => _address;
|
||||
set => this.RaiseAndSetIfChanged(ref _address, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
16
intromat/Intromat/Nodes/Textures/SamplerLiteralModel.cs
Normal file
16
intromat/Intromat/Nodes/Textures/SamplerLiteralModel.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.Nodes.Code;
|
||||
using Intromat.ViewModels;
|
||||
using SharpDX.Direct3D11;
|
||||
|
||||
namespace Intromat.Nodes.Textures
|
||||
{
|
||||
[XmlRoot("SamplerLiteral", Namespace = _namespace)]
|
||||
public sealed class SamplerLiteralModel : LiteralModelBase<SamplerDesc>
|
||||
{
|
||||
public override CodeGenNodeViewModel? CreateViewModel()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
10
intromat/Intromat/Nodes/Textures/SamplerLiteralValue.cs
Normal file
10
intromat/Intromat/Nodes/Textures/SamplerLiteralValue.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
using Intromat.Nodes.Code;
|
||||
using SharpDX.Direct3D11;
|
||||
|
||||
namespace Intromat.Nodes.Textures
|
||||
{
|
||||
public class SamplerLiteralValue : LiteralValueBase<SamplerDesc>
|
||||
{
|
||||
public SamplerState? SamplerState { get; set; }
|
||||
}
|
||||
}
|
||||
18
intromat/Intromat/Nodes/Textures/ShaderTextureModel.cs
Normal file
18
intromat/Intromat/Nodes/Textures/ShaderTextureModel.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.Nodes.Code;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Textures
|
||||
{
|
||||
[XmlRoot("ShaderTexture", Namespace = _namespace)]
|
||||
public sealed class ShaderTextureModel : DxTextureModelBase
|
||||
{
|
||||
public StringLiteralModel Source { get; set; } = null!;
|
||||
public LiteralModelEntry[] InputValues { get; set; } = null!;
|
||||
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new ShaderTextureNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
477
intromat/Intromat/Nodes/Textures/ShaderTextureNode.cs
Normal file
477
intromat/Intromat/Nodes/Textures/ShaderTextureNode.cs
Normal file
@@ -0,0 +1,477 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reactive.Linq;
|
||||
using DynamicData;
|
||||
using Intromat.Graphics;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.Nodes.Code;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.ViewModels;
|
||||
using ReactiveUI;
|
||||
using SharpDX;
|
||||
using SharpDX.D3DCompiler;
|
||||
using SharpDX.Direct3D;
|
||||
using SharpDX.Direct3D11;
|
||||
using Splat;
|
||||
using Buffer = SharpDX.Direct3D11.Buffer;
|
||||
|
||||
namespace Intromat.Nodes.Textures
|
||||
{
|
||||
public class ShaderTextureNode : DxTextureNodeBase
|
||||
{
|
||||
private readonly List<Buffer> _constantBuffers = new();
|
||||
private ComputeShader? _cs;
|
||||
private byte[]? _byteCode;
|
||||
private TextureValue[]? _customOutputs;
|
||||
private readonly List<(NodeInputViewModel, InputDesc)> _customInputs = new();
|
||||
private readonly EndpointGroup _group;
|
||||
private readonly Dictionary<string, object> _inputValues = new();
|
||||
|
||||
public record InputDesc(int ConstantBufferIndex, int Offset, Type VariableType, string Name);
|
||||
|
||||
static ShaderTextureNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<ShaderTextureNode>));
|
||||
}
|
||||
|
||||
public ShaderTextureNode()
|
||||
{
|
||||
Name = "Shader Texture";
|
||||
_group = new EndpointGroup("Shader Texture");
|
||||
Inputs.Add(Source = new CodeGenInputViewModel<ITypedExpression<string>>(EPortType.String)
|
||||
{
|
||||
Name = "Source",
|
||||
Group = _group,
|
||||
Editor = SourceEditor
|
||||
});
|
||||
|
||||
var dxHost = Locator.Current.GetService<DxHost>()!;
|
||||
Source.ValueChanged
|
||||
.ObserveOn(dxHost.RenderDispatcher)
|
||||
.Subscribe(_ =>
|
||||
{
|
||||
_resourcesCreated = false;
|
||||
UpdateFrame(dxHost.Device, dxHost.Device.ImmediateContext);
|
||||
});
|
||||
}
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new ShaderTextureModel();
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var shaderTexture = (ShaderTextureModel)model;
|
||||
shaderTexture.Source = SourceEditor.CreateModel();
|
||||
shaderTexture.InputValues = _customInputs
|
||||
.Where(i => i.Item1.Editor != null)
|
||||
.Select(i => new LiteralModelEntry()
|
||||
{
|
||||
Key = i.Item1.Name,
|
||||
Literal = CreateLiteralModel((dynamic)i.Item1.Editor)
|
||||
})
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private TModel CreateLiteralModel<T, TValue, TModel>(ExpressionEditorBaseViewModel<T, TValue, TModel> editor) where TValue : LiteralValueBase<T>, new() where TModel : LiteralModelBase<T>, new()
|
||||
{
|
||||
return editor.CreateModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var shaderTexture = (ShaderTextureModel)model;
|
||||
SourceEditor.LoadModel(shaderTexture.Source);
|
||||
foreach (var inputValue in shaderTexture.InputValues)
|
||||
{
|
||||
_inputValues[inputValue.Key] = inputValue.Literal;
|
||||
}
|
||||
|
||||
var dxHost = Locator.Current.GetService<DxHost>()!;
|
||||
_resourcesCreated = true;
|
||||
CreateDeviceResources(dxHost.Device);
|
||||
}
|
||||
|
||||
protected override void CreateDeviceResources(Device device)
|
||||
{
|
||||
foreach (var cb in _constantBuffers)
|
||||
cb.Dispose();
|
||||
|
||||
_constantBuffers.Clear();
|
||||
|
||||
var flags = ShaderFlags.None;
|
||||
#if DEBUG
|
||||
flags |= ShaderFlags.Debug;
|
||||
#endif
|
||||
var errors = new List<string>();
|
||||
var shader = Source.Value.Evaluate();
|
||||
if (string.IsNullOrEmpty(shader))
|
||||
{
|
||||
errors.Add("Shader is empty");
|
||||
}
|
||||
else
|
||||
{
|
||||
try
|
||||
{
|
||||
var compilationResult = ShaderBytecode.Compile(shader, "main", "cs_5_0", flags);
|
||||
if (compilationResult.HasErrors)
|
||||
{
|
||||
errors.Add(compilationResult.Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
_byteCode = compilationResult.Bytecode.Data;
|
||||
var reflection = new ShaderReflection(_byteCode);
|
||||
var newInputs = new List<InputDesc>();
|
||||
var newOutputs = new List<InputDesc>();
|
||||
for (int i = 0; i < reflection.Description.BoundResources; ++i)
|
||||
{
|
||||
var resBindingDesc = reflection.GetResourceBindingDescription(i);
|
||||
switch (resBindingDesc.Type)
|
||||
{
|
||||
case ShaderInputType.ConstantBuffer:
|
||||
{
|
||||
var cb = reflection.GetConstantBuffer(resBindingDesc.Name);
|
||||
var cbIndex = resBindingDesc.BindPoint;
|
||||
var cbSize = cb.Description.Size;
|
||||
var bufferDesc = new BufferDescription(cbSize, ResourceUsage.Dynamic, BindFlags.ConstantBuffer, CpuAccessFlags.Write, ResourceOptionFlags.None, 0);
|
||||
_constantBuffers.Add(new Buffer(device, bufferDesc));
|
||||
for (int j = 0; j < cb.Description.VariableCount; ++j)
|
||||
{
|
||||
var variable = cb.GetVariable(j);
|
||||
var varTypeDesc = variable.GetVariableType()
|
||||
.Description;
|
||||
var type = varTypeDesc.Type switch
|
||||
{
|
||||
ShaderVariableType.Float => typeof(float),
|
||||
ShaderVariableType.Int => typeof(int),
|
||||
ShaderVariableType.Bool => typeof(bool),
|
||||
_ => null
|
||||
};
|
||||
if (type == null)
|
||||
{
|
||||
errors.Add($"Constant buffer {resBindingDesc.Name} at slot {cbIndex} has a variable {variable.Description.Name} with unsupported type {varTypeDesc.Type}");
|
||||
continue;
|
||||
}
|
||||
|
||||
for (int k = 0; k < varTypeDesc.ColumnCount; ++k)
|
||||
{
|
||||
var suffix = "" + 'X' + k;
|
||||
var inputName = varTypeDesc.ColumnCount == 1 ? variable.Description.Name : $"{variable.Description.Name}.{suffix}";
|
||||
newInputs.Add(new(cbIndex, variable.Description.StartOffset + k * variable.Description.Size, type, inputName));
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
case ShaderInputType.Texture:
|
||||
{
|
||||
var texName = resBindingDesc.Name;
|
||||
newInputs.Add(new(-1, resBindingDesc.BindPoint, typeof(TextureValue), texName));
|
||||
break;
|
||||
}
|
||||
case ShaderInputType.Sampler:
|
||||
{
|
||||
var texName = resBindingDesc.Name;
|
||||
newInputs.Add(new(-1, resBindingDesc.BindPoint, typeof(SamplerLiteralValue), texName));
|
||||
break;
|
||||
}
|
||||
case ShaderInputType.UnorderedAccessViewRWTyped:
|
||||
{
|
||||
var texName = resBindingDesc.Name;
|
||||
if (resBindingDesc.Dimension != ShaderResourceViewDimension.Texture2D)
|
||||
{
|
||||
errors.Add($"UAV {texName} at slot {resBindingDesc.BindPoint} has unsupported dimension {resBindingDesc.Dimension}");
|
||||
break;
|
||||
}
|
||||
|
||||
newOutputs.Add(new(-1, resBindingDesc.BindPoint, typeof(TextureValue), texName));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
errors.Add($"Resource {resBindingDesc.Name} at slot {resBindingDesc.BindPoint} has unsupported type {resBindingDesc.Type}");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (newOutputs.Count == 0)
|
||||
{
|
||||
errors.Add("The shader doesn't contain any UAV suitable for the texture output");
|
||||
}
|
||||
|
||||
Inputs.Edit(inputs =>
|
||||
{
|
||||
var maxSamplerStateIndex = 0;
|
||||
for (var i = _customInputs.Count - 1; i >= 0; --i)
|
||||
{
|
||||
var existingInput = _customInputs[i];
|
||||
if (newInputs.All(inputDesc => inputDesc.Name != existingInput.Item1.Name))
|
||||
{
|
||||
inputs.Remove(existingInput.Item1);
|
||||
_customInputs.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (var newInputDesc in newInputs)
|
||||
{
|
||||
if (_customInputs.Any(i => i.Item2 == newInputDesc))
|
||||
continue;
|
||||
|
||||
NodeInputViewModel newInput;
|
||||
if (newInputDesc.VariableType == typeof(float))
|
||||
{
|
||||
newInput = new CodeGenInputViewModel<ITypedExpression<float>>(EPortType.Float)
|
||||
{
|
||||
Name = newInputDesc.Name,
|
||||
Group = _group,
|
||||
Editor = new FloatExpressionEditorViewModel { MaxValue = 1 }
|
||||
};
|
||||
if (_inputValues.TryGetValue(newInputDesc.Name, out var inputValue) && inputValue is FloatLiteralModel model)
|
||||
((FloatExpressionEditorViewModel)newInput.Editor).LoadModel(model);
|
||||
}
|
||||
else if (newInputDesc.VariableType == typeof(int))
|
||||
{
|
||||
newInput = new CodeGenInputViewModel<ITypedExpression<int>>(EPortType.Integer)
|
||||
{
|
||||
Name = newInputDesc.Name,
|
||||
Group = _group,
|
||||
Editor = new IntegerExpressionEditorViewModel { MaxValue = 100 }
|
||||
};
|
||||
if (_inputValues.TryGetValue(newInputDesc.Name, out var inputValue) && inputValue is IntLiteralModel model)
|
||||
((IntegerExpressionEditorViewModel)newInput.Editor).LoadModel(model);
|
||||
}
|
||||
else if (newInputDesc.VariableType == typeof(bool))
|
||||
{
|
||||
newInput = new CodeGenInputViewModel<ITypedExpression<bool>>(EPortType.Boolean)
|
||||
{
|
||||
Name = newInputDesc.Name,
|
||||
Group = _group,
|
||||
Editor = new BooleanExpressionEditorViewModel()
|
||||
};
|
||||
if (_inputValues.TryGetValue(newInputDesc.Name, out var inputValue) && inputValue is BooleanLiteralModel model)
|
||||
((BooleanExpressionEditorViewModel)newInput.Editor).LoadModel(model);
|
||||
}
|
||||
else if (newInputDesc.VariableType == typeof(TextureValue))
|
||||
{
|
||||
newInput = new CodeGenInputViewModel<TextureValue>(EPortType.Texture) { Name = newInputDesc.Name };
|
||||
if (newInputDesc.Offset == 0)
|
||||
{
|
||||
var inputObservable = ((CodeGenInputViewModel<TextureValue>)newInput).ValueChanged;
|
||||
WidthEditor.InputValueProvider = inputObservable.Select(input => input?.Width ?? 0);
|
||||
HeightEditor.InputValueProvider = inputObservable.Select(input => input?.Height ?? 0);
|
||||
}
|
||||
}
|
||||
else if (newInputDesc.VariableType == typeof(SamplerLiteralValue))
|
||||
{
|
||||
maxSamplerStateIndex = Math.Max(maxSamplerStateIndex, newInputDesc.Offset);
|
||||
newInput = new CodeGenInputViewModel<ITypedExpression<SamplerDesc>>(EPortType.None)
|
||||
{
|
||||
Name = newInputDesc.Name,
|
||||
Group = _group,
|
||||
Editor = new SamplerEditorViewModel { CustomValue = new SamplerDesc() }
|
||||
};
|
||||
if (_inputValues.TryGetValue(newInputDesc.Name, out var inputValue) && inputValue is SamplerLiteralModel model)
|
||||
((SamplerEditorViewModel)newInput.Editor).LoadModel(model);
|
||||
}
|
||||
else
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_customInputs.Add((newInput, newInputDesc));
|
||||
inputs.Add(newInput);
|
||||
}
|
||||
});
|
||||
|
||||
Outputs.Edit(outputs =>
|
||||
{
|
||||
if (outputs.Count > newOutputs.Count)
|
||||
{
|
||||
if (newOutputs.Count == 0)
|
||||
{
|
||||
if (outputs.Count > 1)
|
||||
outputs.RemoveRange(1, outputs.Count - 1);
|
||||
outputs[0]
|
||||
.Name = "Output";
|
||||
}
|
||||
else
|
||||
{
|
||||
outputs.RemoveRange(newOutputs.Count, outputs.Count - newOutputs.Count);
|
||||
}
|
||||
}
|
||||
|
||||
var outputIndex = 0;
|
||||
if (outputIndex < newOutputs.Count)
|
||||
for (; outputIndex < outputs.Count; ++outputIndex)
|
||||
outputs[outputIndex]
|
||||
.Name = newOutputs[outputIndex]
|
||||
.Name;
|
||||
|
||||
for (; outputIndex < newOutputs.Count; ++outputIndex)
|
||||
{
|
||||
var newOutputDesc = newOutputs[outputIndex];
|
||||
NodeOutputViewModel newOutput;
|
||||
if (newOutputDesc.VariableType == typeof(TextureValue))
|
||||
newOutput = new CodeGenOutputViewModel<TextureValue>(EPortType.Texture) { Name = newOutputDesc.Name };
|
||||
else
|
||||
continue;
|
||||
|
||||
outputs.Add(newOutput);
|
||||
}
|
||||
|
||||
_customOutputs = new TextureValue[outputs.Count];
|
||||
});
|
||||
}
|
||||
}
|
||||
catch (CompilationException e)
|
||||
{
|
||||
errors.Add(e.Message);
|
||||
}
|
||||
}
|
||||
|
||||
_cs?.Dispose();
|
||||
_cs = errors.Count == 0 ? new ComputeShader(device, _byteCode) : null;
|
||||
|
||||
Errors.Edit(e =>
|
||||
{
|
||||
e.Clear();
|
||||
e.AddRange(errors);
|
||||
});
|
||||
}
|
||||
|
||||
protected override unsafe void UpdateFrame(Device device, DeviceContext context)
|
||||
{
|
||||
if (!_resourcesCreated)
|
||||
{
|
||||
_resourcesCreated = true;
|
||||
var dxHost = Locator.Current.GetService<DxHost>()!;
|
||||
dxHost.MainDispatcher!.Invoke(() => CreateDeviceResources(device));
|
||||
}
|
||||
|
||||
EnsureBuffers(device);
|
||||
if (_customOutputs == null || _cs == null)
|
||||
return;
|
||||
|
||||
_customOutputs[0] = _output;
|
||||
for (int i = 1; i < Outputs.Count; ++i)
|
||||
{
|
||||
EnsureTexture(device, ref _customOutputs![i]);
|
||||
}
|
||||
|
||||
var cbData = _constantBuffers.Select(cb =>
|
||||
{
|
||||
context.MapSubresource(cb, 0, MapMode.WriteDiscard, MapFlags.None, out var stream);
|
||||
return stream.DataPointer;
|
||||
}).ToArray();
|
||||
|
||||
int maxSrvIndex = 0;
|
||||
foreach (var input in _customInputs)
|
||||
{
|
||||
var desc = input.Item2;
|
||||
if (desc.ConstantBufferIndex >= 0)
|
||||
{
|
||||
var dataPtr = cbData[desc.ConstantBufferIndex] + desc.Offset;
|
||||
if (desc.VariableType == typeof(float))
|
||||
{
|
||||
_inputValues[input.Item1.Name] = ((FloatExpressionEditorViewModel)input.Item1.Editor).CreateModel();
|
||||
*(float*)dataPtr = ((CodeGenInputViewModel<ITypedExpression<float>>)input.Item1).Value.Evaluate();
|
||||
}
|
||||
else if (desc.VariableType == typeof(int))
|
||||
{
|
||||
_inputValues[input.Item1.Name] = ((IntegerExpressionEditorViewModel)input.Item1.Editor).CreateModel();
|
||||
*(int*)dataPtr = ((CodeGenInputViewModel<ITypedExpression<int>>)input.Item1).Value.Evaluate();
|
||||
}
|
||||
else if (desc.VariableType == typeof(bool))
|
||||
{
|
||||
_inputValues[input.Item1.Name] = ((BooleanExpressionEditorViewModel)input.Item1.Editor).CreateModel();
|
||||
*(bool*)dataPtr = ((CodeGenInputViewModel<ITypedExpression<bool>>)input.Item1).Value.Evaluate();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (desc.VariableType == typeof(TextureValue))
|
||||
{
|
||||
maxSrvIndex = Math.Max(maxSrvIndex, desc.Offset);
|
||||
context.ComputeShader.SetShaderResource(desc.Offset, ((CodeGenInputViewModel<TextureValue>)input.Item1).Value?.ShaderResourceView);
|
||||
}
|
||||
else if (desc.VariableType == typeof(SamplerLiteralValue))
|
||||
{
|
||||
_inputValues[input.Item1.Name] = ((SamplerEditorViewModel)input.Item1.Editor).CreateModel();
|
||||
var samplerValue = (SamplerLiteralValue)((CodeGenInputViewModel<ITypedExpression<SamplerDesc>>)input.Item1).Value;
|
||||
EnsureSamplerState(device, ref samplerValue);
|
||||
context.ComputeShader.SetSampler(desc.Offset, samplerValue.SamplerState);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (var i = 0; i < _customOutputs!.Length; i++)
|
||||
{
|
||||
var output = _customOutputs![i];
|
||||
context.ComputeShader.SetUnorderedAccessView(i, output.UnorderedAccessView);
|
||||
}
|
||||
|
||||
for (int i = 0; i < _constantBuffers.Count; ++i)
|
||||
{
|
||||
context.UnmapSubresource(_constantBuffers[i], 0);
|
||||
context.ComputeShader.SetConstantBuffer(i, _constantBuffers[i]);
|
||||
}
|
||||
|
||||
context.ComputeShader.SetShader(_cs, null, 0);
|
||||
context.Dispatch(_texDesc.Width / 16, _texDesc.Height / 16, 1);
|
||||
|
||||
for (var i = 0; i < _customOutputs!.Length; i++)
|
||||
{
|
||||
context.ComputeShader.SetUnorderedAccessView(i, null);
|
||||
}
|
||||
|
||||
for (var i = 0; i <= maxSrvIndex; i++)
|
||||
{
|
||||
context.ComputeShader.SetShaderResource(i, null);
|
||||
}
|
||||
}
|
||||
|
||||
private void EnsureSamplerState(Device device, ref SamplerLiteralValue samplerLiteralValue)
|
||||
{
|
||||
if (samplerLiteralValue.SamplerState == null || samplerLiteralValue.SamplerState.Description.AddressU != samplerLiteralValue.Value.Address || samplerLiteralValue.SamplerState.Description.Filter != samplerLiteralValue.Value.Filter)
|
||||
{
|
||||
var desc = SamplerStateDescription.Default();
|
||||
desc.AddressU = desc.AddressV = desc.AddressW = samplerLiteralValue.Value.Address;
|
||||
desc.Filter = samplerLiteralValue.Value.Filter;
|
||||
samplerLiteralValue.SamplerState = new SamplerState(device, desc);
|
||||
}
|
||||
}
|
||||
|
||||
public ISourceList<string> Errors { get; } = new SourceList<string>();
|
||||
public CodeGenInputViewModel<ITypedExpression<string>> Source { get; }
|
||||
|
||||
public StringExpressionEditorViewModel SourceEditor { get; } = new()
|
||||
{
|
||||
CustomValue = @"
|
||||
cbuffer cb
|
||||
{
|
||||
float f;
|
||||
}
|
||||
Texture2D t0;
|
||||
SamplerState ss;
|
||||
RWTexture2D<float4> o;
|
||||
[numthreads(16,16,1)]
|
||||
void main(uint3 i : SV_DispatchThreadID)
|
||||
{
|
||||
float2 s;
|
||||
o.GetDimensions(s.x, s.y);
|
||||
float2 uv = i.xy/s;
|
||||
float4 c = t0.SampleLevel(ss, uv, 0);
|
||||
o[i.xy] = float4(c.xyz, 1);
|
||||
}"
|
||||
};
|
||||
}
|
||||
}
|
||||
34
intromat/Intromat/Nodes/Textures/Shape2DGrayscaleModel.cs
Normal file
34
intromat/Intromat/Nodes/Textures/Shape2DGrayscaleModel.cs
Normal file
@@ -0,0 +1,34 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.Nodes.Code;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Textures
|
||||
{
|
||||
[XmlRoot("Shape2DGrayscale", Namespace = _namespace)]
|
||||
public class Shape2DGrayscaleModel : DxTextureModelBase
|
||||
{
|
||||
public enum EPattern
|
||||
{
|
||||
Square
|
||||
}
|
||||
|
||||
public IntLiteralModel Tiling { get; set; } = default!;
|
||||
|
||||
public EPattern Pattern { get; set; }
|
||||
|
||||
public FloatLiteralModel Scale { get; set; } = default!;
|
||||
|
||||
public FloatLiteralModel SizeX { get; set; } = default!;
|
||||
|
||||
public FloatLiteralModel SizeY { get; set; } = default!;
|
||||
|
||||
public FloatLiteralModel Angle { get; set; } = default!;
|
||||
|
||||
public BooleanLiteralModel Rotate45 { get; set; } = default!;
|
||||
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new Shape2DGrayscaleNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
213
intromat/Intromat/Nodes/Textures/Shape2DGrayscaleNode.cs
Normal file
213
intromat/Intromat/Nodes/Textures/Shape2DGrayscaleNode.cs
Normal file
@@ -0,0 +1,213 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using NodeNetwork.ViewModels;
|
||||
using ReactiveUI;
|
||||
using SharpDX.D3DCompiler;
|
||||
using SharpDX.Direct3D11;
|
||||
using Splat;
|
||||
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||
using Buffer = SharpDX.Direct3D11.Buffer;
|
||||
|
||||
namespace Intromat.Nodes.Textures
|
||||
{
|
||||
[CategoryOrder("Shape 2D", 1)]
|
||||
public class Shape2DGrayscaleNode : DxTextureNodeBase
|
||||
{
|
||||
private Buffer? _constantBuffer;
|
||||
private ComputeShader? _cs;
|
||||
private const string _computeShader = @"cbuffer cb
|
||||
{
|
||||
int t;
|
||||
int p;
|
||||
float s;
|
||||
float sx;
|
||||
float sy;
|
||||
float a;
|
||||
int r;
|
||||
}
|
||||
|
||||
float Square(float2 uv)
|
||||
{
|
||||
return step(uv.x, sx) * step(-sx, uv.x) * step(uv.y, sy) * step(-sy, uv.y);
|
||||
}
|
||||
|
||||
RWTexture2D<float> o;
|
||||
[numthreads(16,16,1)]
|
||||
void main(in uint3 i : SV_DispatchThreadID)
|
||||
{
|
||||
float sa, ca;
|
||||
sincos(a, sa, ca);
|
||||
float2 dim;
|
||||
o.GetDimensions(dim.x, dim.y);
|
||||
float2 uv = i.xy / dim;
|
||||
if (r > 0)
|
||||
{
|
||||
float f = sqrt(2)/2;
|
||||
uv = uv * 2 - 1;
|
||||
uv = mul(uv, float2x2(f, -f, f, f));
|
||||
uv = uv * .5 + .5;
|
||||
}
|
||||
uv *= t;
|
||||
uv = frac(uv);
|
||||
uv = uv * 2 - 1;
|
||||
uv /= s;
|
||||
uv = mul(uv, float2x2(ca, -sa, sa, ca));
|
||||
float z = 0;
|
||||
switch (p)
|
||||
{
|
||||
case 0: z = Square(uv); break;
|
||||
}
|
||||
o[i.xy] = z;
|
||||
}";
|
||||
|
||||
static Shape2DGrayscaleNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<Shape2DGrayscaleNode>));
|
||||
}
|
||||
|
||||
public Shape2DGrayscaleNode()
|
||||
{
|
||||
Name = "Shape 2D";
|
||||
var group = new EndpointGroup("Shape 2D");
|
||||
Inputs.Add(Tiling = new CodeGenInputViewModel<ITypedExpression<int>>(EPortType.Integer)
|
||||
{
|
||||
Name = "Tiling",
|
||||
Group = group,
|
||||
Editor = TilingEditor
|
||||
});
|
||||
Inputs.Add(Pattern = new CodeGenInputViewModel<int>(EPortType.None)
|
||||
{
|
||||
Name = "Pattern",
|
||||
Group = group,
|
||||
Editor = PatternEditor
|
||||
});
|
||||
Inputs.Add(Scale = new CodeGenInputViewModel<ITypedExpression<float>>(EPortType.Float)
|
||||
{
|
||||
Name = "Scale",
|
||||
Group = group,
|
||||
Editor = ScaleEditor
|
||||
});
|
||||
Inputs.Add(SizeX = new CodeGenInputViewModel<ITypedExpression<float>>(EPortType.Float)
|
||||
{
|
||||
Name = "Size X",
|
||||
Group = group,
|
||||
Editor = SizeXEditor
|
||||
});
|
||||
Inputs.Add(SizeY = new CodeGenInputViewModel<ITypedExpression<float>>(EPortType.Float)
|
||||
{
|
||||
Name = "Size Y",
|
||||
Group = group,
|
||||
Editor = SizeYEditor
|
||||
});
|
||||
Inputs.Add(Angle = new CodeGenInputViewModel<ITypedExpression<float>>(EPortType.Float)
|
||||
{
|
||||
Name = "Angle",
|
||||
Group = group,
|
||||
Editor = AngleEditor
|
||||
});
|
||||
Inputs.Add(Rotate45 = new CodeGenInputViewModel<ITypedExpression<bool>>(EPortType.Float)
|
||||
{
|
||||
Name = "Rotate 45°",
|
||||
Group = group,
|
||||
Editor = Rotate45Editor
|
||||
});
|
||||
}
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new Shape2DGrayscaleModel();
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var shape2D = (Shape2DGrayscaleModel)model;
|
||||
shape2D.Tiling = TilingEditor.CreateModel();
|
||||
shape2D.Pattern = (Shape2DGrayscaleModel.EPattern)PatternEditor.Value;
|
||||
shape2D.Scale = ScaleEditor.CreateModel();
|
||||
shape2D.SizeX = SizeXEditor.CreateModel();
|
||||
shape2D.SizeY = SizeYEditor.CreateModel();
|
||||
shape2D.Angle = AngleEditor.CreateModel();
|
||||
shape2D.Rotate45 = Rotate45Editor.CreateModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var shape2D = (Shape2DGrayscaleModel)model;
|
||||
TilingEditor.LoadModel(shape2D.Tiling);
|
||||
PatternEditor.Value = (int)shape2D.Pattern;
|
||||
ScaleEditor.LoadModel(shape2D.Scale);
|
||||
SizeXEditor.LoadModel(shape2D.SizeX);
|
||||
SizeYEditor.LoadModel(shape2D.SizeY);
|
||||
AngleEditor.LoadModel(shape2D.Angle);
|
||||
Rotate45Editor.LoadModel(shape2D.Rotate45);
|
||||
}
|
||||
|
||||
protected override unsafe void UpdateFrame(Device device, DeviceContext context)
|
||||
{
|
||||
base.UpdateFrame(device, context);
|
||||
|
||||
context.MapSubresource(_constantBuffer, 0, MapMode.WriteDiscard, MapFlags.None, out var stream);
|
||||
var floats = new Span<float>((void*)stream.DataPointer, 8);
|
||||
var ints = new Span<int>((void*)stream.DataPointer, 8);
|
||||
ints[0] = Tiling.Value.Evaluate();
|
||||
ints[1] = Pattern.Value;
|
||||
floats[2] = Scale.Value.Evaluate();
|
||||
floats[3] = SizeX.Value.Evaluate();
|
||||
floats[4] = SizeY.Value.Evaluate();
|
||||
floats[5] = Angle.Value.Evaluate();
|
||||
ints[6] = Rotate45.Value.Evaluate() ? 1 : 0;
|
||||
context.UnmapSubresource(_constantBuffer, 0);
|
||||
|
||||
context.ComputeShader.SetConstantBuffer(0, _constantBuffer);
|
||||
context.ComputeShader.SetShader(_cs, null, 0);
|
||||
context.ComputeShader.SetUnorderedAccessView(0, _output!.UnorderedAccessView);
|
||||
context.Dispatch(_texDesc.Width / 16, _texDesc.Height / 16, 1);
|
||||
context.ComputeShader.SetUnorderedAccessView(0, null);
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(_constantBuffer))]
|
||||
[MemberNotNull(nameof(_cs))]
|
||||
protected override void CreateDeviceResources(Device device)
|
||||
{
|
||||
base.CreateDeviceResources(device);
|
||||
|
||||
var bufferDesc = new BufferDescription(32, ResourceUsage.Dynamic, BindFlags.ConstantBuffer, CpuAccessFlags.Write, ResourceOptionFlags.None, 0);
|
||||
_constantBuffer = new Buffer(device, bufferDesc);
|
||||
var flags = ShaderFlags.None;
|
||||
#if DEBUG
|
||||
flags |= ShaderFlags.Debug;
|
||||
#endif
|
||||
_cs = new ComputeShader(device, ShaderBytecode.Compile(_computeShader, "main", "cs_5_0", flags).Bytecode.Data);
|
||||
}
|
||||
|
||||
public IntegerExpressionEditorViewModel TilingEditor { get; } = new() { CustomValue = 1, MinValue = 1, MaxValue = 16 };
|
||||
public ValueNodeInputViewModel<ITypedExpression<int>> Tiling { get; }
|
||||
|
||||
public EnumEditorViewModel PatternEditor { get; } = new(typeof(Shape2DGrayscaleModel.EPattern));
|
||||
public ValueNodeInputViewModel<int> Pattern { get; }
|
||||
|
||||
public FloatExpressionEditorViewModel ScaleEditor { get; } = new() { CustomValue = 1, MaxValue = 1 };
|
||||
public ValueNodeInputViewModel<ITypedExpression<float>> Scale { get; }
|
||||
|
||||
public FloatExpressionEditorViewModel SizeXEditor { get; } = new() { CustomValue = .5f, MaxValue = 1 };
|
||||
public ValueNodeInputViewModel<ITypedExpression<float>> SizeX { get; }
|
||||
|
||||
public FloatExpressionEditorViewModel SizeYEditor { get; } = new() { CustomValue = .5f, MaxValue = 1 };
|
||||
public ValueNodeInputViewModel<ITypedExpression<float>> SizeY { get; }
|
||||
|
||||
public FloatExpressionEditorViewModel AngleEditor { get; } = new() { MaxValue = (float)(2 * Math.PI) };
|
||||
public ValueNodeInputViewModel<ITypedExpression<float>> Angle { get; }
|
||||
|
||||
public BooleanExpressionEditorViewModel Rotate45Editor { get; } = new();
|
||||
public ValueNodeInputViewModel<ITypedExpression<bool>> Rotate45 { get; }
|
||||
}
|
||||
}
|
||||
19
intromat/Intromat/Nodes/Textures/SolidColorModel.cs
Normal file
19
intromat/Intromat/Nodes/Textures/SolidColorModel.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.Nodes.Code;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Textures
|
||||
{
|
||||
[XmlRoot("SolidColor", Namespace = _namespace)]
|
||||
public sealed class SolidColorModel : DxTextureModelBase
|
||||
{
|
||||
public IntLiteralModel Red { get; set; } = null!;
|
||||
public IntLiteralModel Green { get; set; } = null!;
|
||||
public IntLiteralModel Blue { get; set; } = null!;
|
||||
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new SolidColorNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
90
intromat/Intromat/Nodes/Textures/SolidColorNode.cs
Normal file
90
intromat/Intromat/Nodes/Textures/SolidColorNode.cs
Normal file
@@ -0,0 +1,90 @@
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using NodeNetwork.ViewModels;
|
||||
using ReactiveUI;
|
||||
using SharpDX.Direct3D11;
|
||||
using SharpDX.Mathematics.Interop;
|
||||
using Splat;
|
||||
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||
|
||||
namespace Intromat.Nodes.Textures
|
||||
{
|
||||
[CategoryOrder("Solid Color", 1)]
|
||||
public class SolidColorNode : DxTextureNodeBase
|
||||
{
|
||||
static SolidColorNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<SolidColorNode>));
|
||||
}
|
||||
|
||||
public SolidColorNode()
|
||||
{
|
||||
Name = "Solid Color";
|
||||
var group = new EndpointGroup("SolidColor");
|
||||
Inputs.Add(Red = new CodeGenInputViewModel<ITypedExpression<int>>(EPortType.Integer)
|
||||
{
|
||||
Name = "Input",
|
||||
Group = group,
|
||||
Editor = RedEditor
|
||||
});
|
||||
Inputs.Add(Green = new CodeGenInputViewModel<ITypedExpression<int>>(EPortType.Integer)
|
||||
{
|
||||
Name = "Green",
|
||||
Group = group,
|
||||
Editor = GreenEditor
|
||||
});
|
||||
Inputs.Add(Blue = new CodeGenInputViewModel<ITypedExpression<int>>(EPortType.Integer)
|
||||
{
|
||||
Name = "Blue",
|
||||
Group = group,
|
||||
Editor = BlueEditor
|
||||
});
|
||||
}
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new SolidColorModel();
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var solidColor = (SolidColorModel)model;
|
||||
solidColor.Red = RedEditor.CreateModel();
|
||||
solidColor.Green = GreenEditor.CreateModel();
|
||||
solidColor.Blue = BlueEditor.CreateModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var solidColor = (SolidColorModel)model;
|
||||
RedEditor.LoadModel(solidColor.Red);
|
||||
GreenEditor.LoadModel(solidColor.Green);
|
||||
BlueEditor.LoadModel(solidColor.Blue);
|
||||
}
|
||||
|
||||
protected override void UpdateFrame(Device device, DeviceContext context)
|
||||
{
|
||||
base.UpdateFrame(device, context);
|
||||
float r = Red.Value.Evaluate() / 255.0f;
|
||||
float g = Green.Value.Evaluate() / 255.0f;
|
||||
float b = Blue.Value.Evaluate() / 255.0f;
|
||||
context.ClearUnorderedAccessView(_output!.UnorderedAccessView, new RawVector4(r, g, b, 1.0f));
|
||||
}
|
||||
|
||||
public IntegerExpressionEditorViewModel RedEditor { get; } = new() { MinValue = 0, MaxValue = 255};
|
||||
public ValueNodeInputViewModel<ITypedExpression<int>> Red { get; }
|
||||
|
||||
public IntegerExpressionEditorViewModel GreenEditor { get; } = new() { MinValue = 0, MaxValue = 255};
|
||||
public ValueNodeInputViewModel<ITypedExpression<int>> Green { get; }
|
||||
|
||||
public IntegerExpressionEditorViewModel BlueEditor { get; } = new() { MinValue = 0, MaxValue = 255};
|
||||
public ValueNodeInputViewModel<ITypedExpression<int>> Blue { get; }
|
||||
}
|
||||
}
|
||||
22
intromat/Intromat/Nodes/Textures/Transform2DColorModel.cs
Normal file
22
intromat/Intromat/Nodes/Textures/Transform2DColorModel.cs
Normal file
@@ -0,0 +1,22 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.Nodes.Code;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.Nodes.Textures
|
||||
{
|
||||
[XmlRoot("Transform2DColor", Namespace = _namespace)]
|
||||
public sealed class Transform2DColorModel : DxTextureModelBase
|
||||
{
|
||||
public BooleanLiteralModel Clamp { get; set; } = default!;
|
||||
public FloatLiteralModel ScaleX { get; set; } = default!;
|
||||
public FloatLiteralModel ScaleY { get; set; } = default!;
|
||||
public FloatLiteralModel OffsetX { get; set; } = default!;
|
||||
public FloatLiteralModel OffsetY { get; set; } = default!;
|
||||
public FloatLiteralModel Rotate { get; set; } = default!;
|
||||
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new Transform2DColorNode();
|
||||
}
|
||||
}
|
||||
}
|
||||
190
intromat/Intromat/Nodes/Textures/Transform2DColorNode.cs
Normal file
190
intromat/Intromat/Nodes/Textures/Transform2DColorNode.cs
Normal file
@@ -0,0 +1,190 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using DynamicData;
|
||||
using Intromat.Model.Compiler;
|
||||
using Intromat.PersistentModel;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Editors;
|
||||
using Intromat.Views;
|
||||
using NodeNetwork.Toolkit.ValueNode;
|
||||
using NodeNetwork.ViewModels;
|
||||
using ReactiveUI;
|
||||
using SharpDX.D3DCompiler;
|
||||
using SharpDX.Direct3D11;
|
||||
using Splat;
|
||||
using Xceed.Wpf.Toolkit.PropertyGrid.Attributes;
|
||||
using Buffer = SharpDX.Direct3D11.Buffer;
|
||||
|
||||
namespace Intromat.Nodes.Textures
|
||||
{
|
||||
[CategoryOrder("Transform 2D", 1)]
|
||||
public class Transform2DColorNode : DxTextureFilterNodeBase
|
||||
{
|
||||
private Buffer? _constantBuffer;
|
||||
private ComputeShader? _cs;
|
||||
private const string _computeShader = @"cbuffer cb
|
||||
{
|
||||
float2 s;
|
||||
float2 p;
|
||||
float r;
|
||||
int c;
|
||||
}
|
||||
|
||||
Texture2D t;
|
||||
SamplerState ss;
|
||||
RWTexture2D<float4> o;
|
||||
[numthreads(16,16,1)]
|
||||
void main(in uint3 i : SV_DispatchThreadID)
|
||||
{
|
||||
float sa, ca;
|
||||
sincos(r, sa, ca);
|
||||
float2 dim;
|
||||
o.GetDimensions(dim.x, dim.y);
|
||||
float2 uv = i.xy / dim;
|
||||
uv -= p;
|
||||
uv = uv * 2 - 1;
|
||||
uv = mul(uv, float2x2(ca, -sa, sa, ca));
|
||||
uv /= s;
|
||||
uv = uv * .5 + .5;
|
||||
if (c == 0) uv = frac(uv);
|
||||
o[i.xy] = t.SampleLevel(ss, uv, 0);
|
||||
}";
|
||||
|
||||
static Transform2DColorNode()
|
||||
{
|
||||
Locator.CurrentMutable.Register(() => new CodeGenNodeView(), typeof(IViewFor<Transform2DColorNode>));
|
||||
}
|
||||
|
||||
public Transform2DColorNode()
|
||||
{
|
||||
Name = "Transform 2D";
|
||||
var group = new EndpointGroup("Transform 2D");
|
||||
Inputs.Add(Clamp = new CodeGenInputViewModel<ITypedExpression<bool>>(EPortType.Boolean)
|
||||
{
|
||||
Name = "Clamp",
|
||||
Group = group,
|
||||
Editor = ClampEditor
|
||||
});
|
||||
Inputs.Add(ScaleX = new CodeGenInputViewModel<ITypedExpression<float>>(EPortType.Float)
|
||||
{
|
||||
Name = "Scale X",
|
||||
Group = group,
|
||||
Editor = ScaleXEditor
|
||||
});
|
||||
Inputs.Add(ScaleY = new CodeGenInputViewModel<ITypedExpression<float>>(EPortType.Float)
|
||||
{
|
||||
Name = "Scale Y",
|
||||
Group = group,
|
||||
Editor = ScaleYEditor
|
||||
});
|
||||
Inputs.Add(OffsetX = new CodeGenInputViewModel<ITypedExpression<float>>(EPortType.Float)
|
||||
{
|
||||
Name = "Offset X",
|
||||
Group = group,
|
||||
Editor = OffsetXEditor
|
||||
});
|
||||
Inputs.Add(OffsetY = new CodeGenInputViewModel<ITypedExpression<float>>(EPortType.Float)
|
||||
{
|
||||
Name = "Offset Y",
|
||||
Group = group,
|
||||
Editor = OffsetYEditor
|
||||
});
|
||||
Inputs.Add(Rotate = new CodeGenInputViewModel<ITypedExpression<float>>(EPortType.Float)
|
||||
{
|
||||
Name = "Rotate",
|
||||
Group = group,
|
||||
Editor = RotateEditor
|
||||
});
|
||||
}
|
||||
|
||||
public override NodeModelBase CreateModel()
|
||||
{
|
||||
return new Transform2DColorModel();
|
||||
}
|
||||
|
||||
public override void SaveModel(NodeModelBase model)
|
||||
{
|
||||
base.SaveModel(model);
|
||||
var transform2DColor = (Transform2DColorModel)model;
|
||||
transform2DColor.ScaleX = ScaleXEditor.CreateModel();
|
||||
transform2DColor.ScaleY = ScaleYEditor.CreateModel();
|
||||
transform2DColor.OffsetX = OffsetXEditor.CreateModel();
|
||||
transform2DColor.OffsetY = OffsetYEditor.CreateModel();
|
||||
transform2DColor.Rotate = RotateEditor.CreateModel();
|
||||
transform2DColor.Clamp = ClampEditor.CreateModel();
|
||||
}
|
||||
|
||||
public override void LoadModel(NodeModelBase model)
|
||||
{
|
||||
base.LoadModel(model);
|
||||
var transform2DColor = (Transform2DColorModel)model;
|
||||
ScaleXEditor.LoadModel(transform2DColor.ScaleX);
|
||||
ScaleYEditor.LoadModel(transform2DColor.ScaleY);
|
||||
OffsetXEditor.LoadModel(transform2DColor.OffsetX);
|
||||
OffsetYEditor.LoadModel(transform2DColor.OffsetY);
|
||||
RotateEditor.LoadModel(transform2DColor.Rotate);
|
||||
ClampEditor.LoadModel(transform2DColor.Clamp);
|
||||
}
|
||||
|
||||
[MemberNotNull(nameof(_constantBuffer))]
|
||||
[MemberNotNull(nameof(_cs))]
|
||||
protected override void CreateDeviceResources(Device device)
|
||||
{
|
||||
base.CreateDeviceResources(device);
|
||||
|
||||
var bufferDesc = new BufferDescription(32, ResourceUsage.Dynamic, BindFlags.ConstantBuffer, CpuAccessFlags.Write, ResourceOptionFlags.None, 0);
|
||||
_constantBuffer = new Buffer(device, bufferDesc);
|
||||
var flags = ShaderFlags.None;
|
||||
#if DEBUG
|
||||
flags |= ShaderFlags.Debug;
|
||||
#endif
|
||||
_cs = new ComputeShader(device, ShaderBytecode.Compile(_computeShader, "main", "cs_5_0", flags).Bytecode.Data);
|
||||
}
|
||||
|
||||
protected override unsafe void UpdateFrame(Device device, DeviceContext context)
|
||||
{
|
||||
base.UpdateFrame(device, context);
|
||||
var srv = Input.Value?.ShaderResourceView;
|
||||
if (srv == null)
|
||||
return;
|
||||
|
||||
context.MapSubresource(_constantBuffer, 0, MapMode.WriteDiscard, MapFlags.None, out var stream);
|
||||
var floats = new Span<float>((void*)stream.DataPointer, 8);
|
||||
var ints = new Span<int>((void*)stream.DataPointer, 8);
|
||||
floats[0] = ScaleX.Value.Evaluate();
|
||||
floats[1] = ScaleY.Value.Evaluate();
|
||||
floats[2] = OffsetX.Value.Evaluate();
|
||||
floats[3] = OffsetY.Value.Evaluate();
|
||||
floats[4] = Rotate.Value.Evaluate();
|
||||
ints[5] = Clamp.Value.Evaluate() ? 1 : 0;
|
||||
context.UnmapSubresource(_constantBuffer, 0);
|
||||
|
||||
context.ComputeShader.SetConstantBuffer(0, _constantBuffer);
|
||||
context.ComputeShader.SetShaderResource(0, srv);
|
||||
context.ComputeShader.SetSampler(0, _samplerState);
|
||||
context.ComputeShader.SetShader(_cs, null, 0);
|
||||
context.ComputeShader.SetUnorderedAccessView(0, _output!.UnorderedAccessView);
|
||||
context.Dispatch(_texDesc.Width / 16, _texDesc.Height / 16, 1);
|
||||
context.ComputeShader.SetShaderResource(0, null);
|
||||
context.ComputeShader.SetUnorderedAccessView(0, null);
|
||||
}
|
||||
|
||||
public ValueNodeInputViewModel<ITypedExpression<bool>> Clamp { get; }
|
||||
public BooleanExpressionEditorViewModel ClampEditor { get; } = new();
|
||||
|
||||
public ValueNodeInputViewModel<ITypedExpression<float>> ScaleX { get; }
|
||||
public FloatExpressionEditorViewModel ScaleXEditor { get; } = new() { CustomValue = 1, MaxValue = 4 };
|
||||
|
||||
public ValueNodeInputViewModel<ITypedExpression<float>> ScaleY { get; }
|
||||
public FloatExpressionEditorViewModel ScaleYEditor { get; } = new() { CustomValue = 1, MaxValue = 4 };
|
||||
|
||||
public ValueNodeInputViewModel<ITypedExpression<float>> OffsetX { get; }
|
||||
public FloatExpressionEditorViewModel OffsetXEditor { get; } = new() { MinValue = -1, MaxValue = 1 };
|
||||
|
||||
public ValueNodeInputViewModel<ITypedExpression<float>> OffsetY { get; }
|
||||
public FloatExpressionEditorViewModel OffsetYEditor { get; } = new() { MinValue = -1, MaxValue = 1 };
|
||||
|
||||
public ValueNodeInputViewModel<ITypedExpression<float>> Rotate { get; }
|
||||
public FloatExpressionEditorViewModel RotateEditor { get; } = new() { MaxValue = (float)(2 * Math.PI) };
|
||||
}
|
||||
}
|
||||
9
intromat/Intromat/PersistentModel/ConnectionModel.cs
Normal file
9
intromat/Intromat/PersistentModel/ConnectionModel.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
namespace Intromat.PersistentModel
|
||||
{
|
||||
public class ConnectionModel
|
||||
{
|
||||
public EndpointModel Input { get; set; } = null!;
|
||||
|
||||
public EndpointModel Output { get; set; } = null!;
|
||||
}
|
||||
}
|
||||
16
intromat/Intromat/PersistentModel/EndpointModel.cs
Normal file
16
intromat/Intromat/PersistentModel/EndpointModel.cs
Normal file
@@ -0,0 +1,16 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace Intromat.PersistentModel
|
||||
{
|
||||
public class EndpointModel
|
||||
{
|
||||
[XmlAttribute]
|
||||
public Guid Node { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
[DefaultValue(null)]
|
||||
public string Name { get; set; } = null!;
|
||||
}
|
||||
}
|
||||
27
intromat/Intromat/PersistentModel/GroupEndpointModel.cs
Normal file
27
intromat/Intromat/PersistentModel/GroupEndpointModel.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System.ComponentModel;
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.PersistentModel
|
||||
{
|
||||
public class GroupEndpointModel
|
||||
{
|
||||
[XmlAttribute]
|
||||
public string EndpointType { get; set; } = null!;
|
||||
|
||||
[XmlAttribute]
|
||||
public EPortType PortType { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
[DefaultValue(false)]
|
||||
public bool List { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
[DefaultValue(null)]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[XmlAttribute]
|
||||
[DefaultValue(0)]
|
||||
public int SortIndex { get; set; }
|
||||
}
|
||||
}
|
||||
21
intromat/Intromat/PersistentModel/NetworkModel.cs
Normal file
21
intromat/Intromat/PersistentModel/NetworkModel.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace Intromat.PersistentModel
|
||||
{
|
||||
[XmlRoot("Network", Namespace = NodeModelBase._namespace)]
|
||||
public class NetworkModel
|
||||
{
|
||||
[XmlElement]
|
||||
public NodeCollectionModel Nodes { get; set; } = new();
|
||||
|
||||
[XmlArray]
|
||||
public List<ConnectionModel> Connections { get; set; } = new();
|
||||
|
||||
[XmlArray]
|
||||
public List<NodeMetaData> MetaData { get; set; } = new();
|
||||
|
||||
[XmlArray]
|
||||
public List<NetworkModel> SubNetworks { get; set; } = new();
|
||||
}
|
||||
}
|
||||
74
intromat/Intromat/PersistentModel/NodeCollectionModel.cs
Normal file
74
intromat/Intromat/PersistentModel/NodeCollectionModel.cs
Normal file
@@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Xml;
|
||||
using System.Xml.Schema;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace Intromat.PersistentModel
|
||||
{
|
||||
public class NodeCollectionModel : IXmlSerializable
|
||||
{
|
||||
public static readonly Dictionary<string, Type> _nodeTypes;
|
||||
public static readonly XmlSerializerNamespaces _nameSpaces;
|
||||
|
||||
static NodeCollectionModel()
|
||||
{
|
||||
_nodeTypes = typeof(NodeModelBase)
|
||||
.Assembly
|
||||
.GetTypes()
|
||||
.Where(t => typeof(NodeModelBase).IsAssignableFrom(t) && !t.IsAbstract)
|
||||
.Select(type =>
|
||||
{
|
||||
var attrib = (XmlRootAttribute)type.GetCustomAttribute(typeof(XmlRootAttribute))!;
|
||||
return (attrib.ElementName, Type: type);
|
||||
})
|
||||
.ToDictionary(pair => pair.ElementName, pair => pair.Type);
|
||||
|
||||
_nameSpaces = new XmlSerializerNamespaces();
|
||||
_nameSpaces.Add(string.Empty, NodeModelBase._namespace);
|
||||
_nameSpaces.Add("x", "http://www.w3.org/2001/XMLSchema-instance");
|
||||
}
|
||||
|
||||
public List<NodeModelBase> Items { get; set; } = new();
|
||||
|
||||
public XmlSchema? GetSchema()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
public void ReadXml(XmlReader reader)
|
||||
{
|
||||
reader.MoveToContent();
|
||||
var isEmptyElement = reader.IsEmptyElement;
|
||||
reader.ReadStartElement();
|
||||
if (!isEmptyElement)
|
||||
{
|
||||
while (reader.NodeType != XmlNodeType.EndElement)
|
||||
{
|
||||
if (_nodeTypes.TryGetValue(reader.Name, out var nodeType))
|
||||
{
|
||||
var serializer = new XmlSerializer(nodeType);
|
||||
var node = (NodeModelBase)serializer.Deserialize(reader)!;
|
||||
Items.Add(node);
|
||||
}
|
||||
}
|
||||
|
||||
reader.ReadEndElement();
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteXml(XmlWriter writer)
|
||||
{
|
||||
if (Items.Count == 0)
|
||||
return;
|
||||
|
||||
foreach (var node in Items)
|
||||
{
|
||||
var serializer = new XmlSerializer(node.GetType());
|
||||
serializer.Serialize(writer, node, _nameSpaces);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
15
intromat/Intromat/PersistentModel/NodeMetaData.cs
Normal file
15
intromat/Intromat/PersistentModel/NodeMetaData.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace Intromat.PersistentModel
|
||||
{
|
||||
public class NodeMetaData
|
||||
{
|
||||
public Guid Node { get; set; }
|
||||
|
||||
public PositionModel Position { get; set; }
|
||||
|
||||
[DefaultValue(false)]
|
||||
public bool IsCollapsed { get; set; }
|
||||
}
|
||||
}
|
||||
21
intromat/Intromat/PersistentModel/NodeModelBase.cs
Normal file
21
intromat/Intromat/PersistentModel/NodeModelBase.cs
Normal file
@@ -0,0 +1,21 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.ViewModels;
|
||||
|
||||
namespace Intromat.PersistentModel
|
||||
{
|
||||
public abstract class NodeModelBase
|
||||
{
|
||||
public abstract CodeGenNodeViewModel? CreateViewModel();
|
||||
|
||||
[XmlAttribute]
|
||||
public Guid Guid { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
[DefaultValue("")]
|
||||
public string Name { get; set; } = "";
|
||||
|
||||
public const string _namespace = "http://blu-flame.org/intromat";
|
||||
}
|
||||
}
|
||||
27
intromat/Intromat/PersistentModel/Nodes/GroupModel.cs
Normal file
27
intromat/Intromat/PersistentModel/Nodes/GroupModel.cs
Normal file
@@ -0,0 +1,27 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Nodes;
|
||||
|
||||
namespace Intromat.PersistentModel.Nodes
|
||||
{
|
||||
[XmlRoot("Group", Namespace = _namespace)]
|
||||
public class GroupModel : NodeModelBase
|
||||
{
|
||||
public NetworkModel Network { get; set; } = null!;
|
||||
|
||||
public Guid Entrance { get; set; }
|
||||
|
||||
public Guid Exit { get; set; }
|
||||
|
||||
public List<GroupEndpointModel> Inputs { get; set; } = new();
|
||||
|
||||
public List<GroupEndpointModel> Outputs { get; set; } = new();
|
||||
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new GroupNodeViewModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
using System.Xml.Serialization;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Nodes;
|
||||
|
||||
namespace Intromat.PersistentModel.Nodes
|
||||
{
|
||||
[XmlRoot("GroupSubnetIO", Namespace = _namespace)]
|
||||
public class GroupSubnetIOModel : NodeModelBase
|
||||
{
|
||||
[XmlAttribute]
|
||||
public bool IsEntrance { get; set; }
|
||||
|
||||
public override CodeGenNodeViewModel CreateViewModel()
|
||||
{
|
||||
return new GroupSubnetIONodeViewModel();
|
||||
}
|
||||
}
|
||||
}
|
||||
19
intromat/Intromat/PersistentModel/PositionModel.cs
Normal file
19
intromat/Intromat/PersistentModel/PositionModel.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System.Windows;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace Intromat.PersistentModel
|
||||
{
|
||||
public struct PositionModel
|
||||
{
|
||||
[XmlAttribute]
|
||||
public double X { get; set; }
|
||||
|
||||
[XmlAttribute]
|
||||
public double Y { get; set; }
|
||||
|
||||
public static implicit operator Point(PositionModel position)
|
||||
{
|
||||
return new(position.X, position.Y);
|
||||
}
|
||||
}
|
||||
}
|
||||
15
intromat/Intromat/PersistentModel/ProjectModel.cs
Normal file
15
intromat/Intromat/PersistentModel/ProjectModel.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Serialization;
|
||||
|
||||
namespace Intromat.PersistentModel
|
||||
{
|
||||
[XmlRoot("Project", Namespace = NodeModelBase._namespace)]
|
||||
public class ProjectModel
|
||||
{
|
||||
[XmlAttribute]
|
||||
public string Name { get; set; } = null!;
|
||||
|
||||
[XmlElement("Module")]
|
||||
public List<string> Modules { get; set; } = new();
|
||||
}
|
||||
}
|
||||
296
intromat/Intromat/PersistentModel/ProjectSerializer.cs
Normal file
296
intromat/Intromat/PersistentModel/ProjectSerializer.cs
Normal file
@@ -0,0 +1,296 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Xml;
|
||||
using System.Xml.Serialization;
|
||||
using DynamicData;
|
||||
using Intromat.Helpers;
|
||||
using Intromat.PersistentModel.Nodes;
|
||||
using Intromat.ViewModels;
|
||||
using Intromat.ViewModels.Nodes;
|
||||
using NodeNetwork.ViewModels;
|
||||
|
||||
namespace Intromat.PersistentModel
|
||||
{
|
||||
internal class ProjectSerializer
|
||||
{
|
||||
public static async Task<ProjectViewModel?> LoadProject(MainViewModel mainVm, string fullPath)
|
||||
{
|
||||
await using var stream = new FileStream(fullPath, FileMode.Open);
|
||||
var projectSerializer = new XmlSerializer(typeof(ProjectModel));
|
||||
var project = (ProjectModel)projectSerializer.Deserialize(stream)!;
|
||||
var projectVm = new ProjectViewModel(project.Name, Path.GetFullPath(fullPath));
|
||||
var directory = Path.GetDirectoryName(projectVm.FullPath)!;
|
||||
foreach (var modulePath in project.Modules)
|
||||
{
|
||||
var moduleFullPath = Path.Combine(directory, modulePath);
|
||||
var moduleVm = await LoadModule(mainVm, projectVm, moduleFullPath);
|
||||
projectVm.Modules.Add(moduleVm);
|
||||
}
|
||||
|
||||
return projectVm;
|
||||
}
|
||||
|
||||
public static async Task<ModuleViewModel> LoadModule(MainViewModel mainVm, ProjectViewModel parent, string fullPath)
|
||||
{
|
||||
var moduleVm = new ModuleViewModel(parent, Path.GetFileName(fullPath)!, fullPath);
|
||||
await LoadFolder(mainVm, moduleVm, moduleVm, moduleVm, fullPath);
|
||||
return moduleVm;
|
||||
}
|
||||
|
||||
private static async Task LoadFolder(MainViewModel mainVm, ModuleViewModel moduleVm, FolderViewModel parent, FolderViewModel target, string folderPath)
|
||||
{
|
||||
foreach (var subFolderPath in Directory.EnumerateDirectories(folderPath))
|
||||
{
|
||||
var subFolderVm = new FolderViewModel(moduleVm, parent, Path.GetDirectoryName(folderPath)!);
|
||||
await LoadFolder(mainVm, moduleVm, target, subFolderVm, subFolderPath);
|
||||
target.Folders.Add(subFolderVm);
|
||||
}
|
||||
|
||||
foreach (var filePath in Directory.EnumerateFiles(folderPath))
|
||||
{
|
||||
switch (Path.GetExtension(filePath))
|
||||
{
|
||||
case ".igraph":
|
||||
{
|
||||
target.Files.Add(await LoadDocument(mainVm, moduleVm, target, filePath));
|
||||
break;
|
||||
}
|
||||
case ".hlsl":
|
||||
{
|
||||
target.Files.Add(await LoadShader(mainVm, moduleVm, target, filePath));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task<DocumentViewModel> LoadDocument(MainViewModel mainVm, ModuleViewModel moduleVm, FolderViewModel folderVm, string filePath)
|
||||
{
|
||||
await using var stream = new FileStream(filePath, FileMode.Open);
|
||||
var networkSerializer = new XmlSerializer(typeof(NetworkModel));
|
||||
var network = (NetworkModel)networkSerializer.Deserialize(stream)!;
|
||||
var documentVm = new DocumentViewModel(mainVm, moduleVm, folderVm, Path.GetFileNameWithoutExtension(filePath));
|
||||
LoadNetwork(documentVm.MainNetwork, network, documentVm);
|
||||
return documentVm;
|
||||
}
|
||||
|
||||
private static async Task<ShaderFileViewModel> LoadShader(MainViewModel mainVm, ModuleViewModel moduleVm, FolderViewModel folderVm, string filePath)
|
||||
{
|
||||
await using var stream = new FileStream(filePath, FileMode.Open);
|
||||
var shaderFileVm = new ShaderFileViewModel(mainVm, moduleVm, folderVm, Path.GetFileNameWithoutExtension(filePath));
|
||||
using var reader = new StreamReader(stream);
|
||||
shaderFileVm.Source = await reader.ReadToEndAsync();
|
||||
return shaderFileVm;
|
||||
}
|
||||
|
||||
public static CodeGenNetworkViewModel LoadNetwork(CodeGenNetworkViewModel networkVm, NetworkModel network, DocumentViewModel documentVm, GroupNodeViewModel? baseGroup = null)
|
||||
{
|
||||
PreLoadNetwork(network, documentVm, baseGroup, networkVm, out var nodeMap);
|
||||
PostLoadNetwork(network, networkVm, nodeMap);
|
||||
|
||||
return networkVm;
|
||||
}
|
||||
|
||||
private static void PreLoadNetwork(NetworkModel network, DocumentViewModel documentVm, GroupNodeViewModel? baseGroup, CodeGenNetworkViewModel networkVm, out Dictionary<Guid, NodeViewModel> outNodeMap)
|
||||
{
|
||||
var nodeMap = outNodeMap = new Dictionary<Guid, NodeViewModel>();
|
||||
GroupSubnetIONodeViewModel? entrance = null, exit = null;
|
||||
var groups = new List<GroupModel>();
|
||||
networkVm.Nodes.Edit(nodes =>
|
||||
{
|
||||
foreach (var node in network.Nodes.Items)
|
||||
{
|
||||
var nodeVm = node.CreateViewModel()!;
|
||||
nodeVm.LoadModel(node);
|
||||
nodes.Add(nodeVm);
|
||||
nodeMap.Add(node.Guid, nodeVm);
|
||||
if (nodeVm is GroupSubnetIONodeViewModel subnetIONodeVm)
|
||||
{
|
||||
Debug.Assert(baseGroup != null, nameof(baseGroup) + " != null");
|
||||
if (subnetIONodeVm.IsEntranceNode)
|
||||
{
|
||||
entrance = subnetIONodeVm;
|
||||
}
|
||||
else
|
||||
{
|
||||
exit = subnetIONodeVm;
|
||||
}
|
||||
}
|
||||
else if (node is GroupModel group)
|
||||
{
|
||||
groups.Add(group);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (baseGroup != null && entrance != null && exit != null)
|
||||
{
|
||||
var groupBinding = new CodeNodeGroupIOBinding(baseGroup, entrance, exit);
|
||||
baseGroup.IOBinding = groupBinding;
|
||||
entrance.IOBinding = groupBinding;
|
||||
exit.IOBinding = groupBinding;
|
||||
}
|
||||
|
||||
foreach (var group in groups)
|
||||
{
|
||||
var groupVm = (GroupNodeViewModel)nodeMap[group.Guid];
|
||||
var subNetworkVm = new CodeGenNetworkViewModel(documentVm, group.Name);
|
||||
PreLoadNetwork(group.Network, documentVm, groupVm, subNetworkVm, out var subNetworkNodeMap);
|
||||
var ioBinding = groupVm.IOBinding!;
|
||||
groupVm.Inputs.Edit(inputs =>
|
||||
{
|
||||
foreach (var input in group.Inputs)
|
||||
{
|
||||
var valueType = Type.GetType(input.EndpointType)!;
|
||||
var inputVm = ioBinding.CreateInput(input.PortType, input.Name, valueType);
|
||||
inputVm.SortIndex = input.SortIndex;
|
||||
inputs.Add(inputVm);
|
||||
}
|
||||
});
|
||||
groupVm.Outputs.Edit(outputs =>
|
||||
{
|
||||
foreach (var output in group.Outputs)
|
||||
{
|
||||
var valueType = Type.GetType(output.EndpointType)!;
|
||||
var outputVm = ioBinding.CreateOutput(output.PortType, output.Name, valueType, output.List);
|
||||
outputVm.SortIndex = output.SortIndex;
|
||||
outputs.Add(outputVm);
|
||||
}
|
||||
});
|
||||
|
||||
groupVm.Subnet = subNetworkVm;
|
||||
groupVm.Name = subNetworkVm.Name;
|
||||
PostLoadNetwork(group.Network, subNetworkVm, subNetworkNodeMap);
|
||||
}
|
||||
}
|
||||
|
||||
private static void PostLoadNetwork(NetworkModel network, CodeGenNetworkViewModel networkVm, Dictionary<Guid, NodeViewModel> nodeMap)
|
||||
{
|
||||
networkVm.Connections.Edit(connections =>
|
||||
{
|
||||
foreach (var connection in network.Connections)
|
||||
{
|
||||
var inputVm = nodeMap[connection.Input.Node];
|
||||
var outputVm = nodeMap[connection.Output.Node];
|
||||
var input = inputVm.Inputs.Items.Single(i => i.Name == connection.Input.Name);
|
||||
var output = outputVm.Outputs.Items.Single(o => o.Name == connection.Output.Name);
|
||||
((CodeGenPortViewModel)input.Port).IsPortVisible = true;
|
||||
((CodeGenPortViewModel)output.Port).IsPortVisible = true;
|
||||
var connectionVm = new ConnectionViewModel(networkVm, input, output);
|
||||
connections.Add(connectionVm);
|
||||
}
|
||||
});
|
||||
|
||||
foreach (var metaData in network.MetaData)
|
||||
{
|
||||
var nodeVm = nodeMap[metaData.Node];
|
||||
nodeVm.Position = new Point(metaData.Position.X, metaData.Position.Y);
|
||||
nodeVm.IsCollapsed = metaData.IsCollapsed;
|
||||
}
|
||||
}
|
||||
|
||||
public static async Task<ProjectModel> SaveModel(ProjectViewModel projectVm)
|
||||
{
|
||||
var directoryName = Path.GetDirectoryName(projectVm.FullPath)!;
|
||||
Directory.CreateDirectory(directoryName);
|
||||
await using var stream = new FileStream(projectVm.FullPath, FileMode.Create);
|
||||
await using var writer = new XmlTextWriter(stream, Encoding.UTF8) { Formatting = Formatting.Indented };
|
||||
var project = new ProjectModel { Name = projectVm.Name };
|
||||
foreach (var moduleVm in projectVm.Modules)
|
||||
{
|
||||
project.Modules.Add(IOHelper.GetRelativePath(directoryName, moduleVm.FullPath));
|
||||
await SaveModel(moduleVm);
|
||||
}
|
||||
var projectSerializer = new XmlSerializer(typeof(ProjectModel));
|
||||
projectSerializer.Serialize(writer, project, NodeCollectionModel._nameSpaces);
|
||||
return project;
|
||||
}
|
||||
|
||||
public static async Task SaveModel(FolderViewModel folderVm)
|
||||
{
|
||||
foreach (var subFolderVm in folderVm.Folders.Items)
|
||||
{
|
||||
await SaveModel(subFolderVm);
|
||||
}
|
||||
foreach (var documentVm in folderVm.Files.Items)
|
||||
{
|
||||
await SaveModel(documentVm);
|
||||
}
|
||||
}
|
||||
|
||||
private static async Task SaveModel(FileViewModel fileVm)
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(fileVm.FullPath)!);
|
||||
await using var stream = new FileStream(fileVm.FullPath, FileMode.Create);
|
||||
switch (fileVm)
|
||||
{
|
||||
case DocumentViewModel documentVm:
|
||||
{
|
||||
var network = SaveModel(documentVm.MainNetwork);
|
||||
await using var writer = new XmlTextWriter(stream, Encoding.UTF8) { Formatting = Formatting.Indented };
|
||||
var moduleSerializer = new XmlSerializer(typeof(NetworkModel));
|
||||
moduleSerializer.Serialize(writer, network, NodeCollectionModel._nameSpaces);
|
||||
break;
|
||||
}
|
||||
case ShaderFileViewModel shaderVm:
|
||||
{
|
||||
var shader = shaderVm.Source;
|
||||
await using var writer = new StreamWriter(stream);
|
||||
await writer.WriteAsync(shader);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static NetworkModel SaveModel(CodeGenNetworkViewModel networkVm)
|
||||
{
|
||||
Debug.Assert(networkVm.Name != null, $"{nameof(networkVm)}.{nameof(networkVm.Name)} != null");
|
||||
var network = new NetworkModel();
|
||||
|
||||
foreach (var item in networkVm.Nodes.Items)
|
||||
{
|
||||
var nodeVm = (CodeGenNodeViewModel)item;
|
||||
var node = nodeVm.CreateModel();
|
||||
nodeVm.SaveModel(node);
|
||||
network.Nodes.Items.Add(node);
|
||||
}
|
||||
|
||||
foreach (var connectionVm in networkVm.Connections.Items)
|
||||
{
|
||||
var connection = new ConnectionModel
|
||||
{
|
||||
Input = new EndpointModel { Name = connectionVm.Input.Name, Node = ((CodeGenNodeViewModel)connectionVm.Input.Parent).Guid },
|
||||
Output = new EndpointModel { Name = connectionVm.Output.Name, Node = ((CodeGenNodeViewModel)connectionVm.Output.Parent).Guid },
|
||||
};
|
||||
network.Connections.Add(connection);
|
||||
}
|
||||
|
||||
foreach (var nodeVm in networkVm.Nodes.Items)
|
||||
{
|
||||
var metaData = new NodeMetaData
|
||||
{
|
||||
Position = new PositionModel
|
||||
{
|
||||
X = nodeVm.Position.X,
|
||||
Y = nodeVm.Position.Y
|
||||
},
|
||||
IsCollapsed = nodeVm.IsCollapsed,
|
||||
Node = ((CodeGenNodeViewModel)nodeVm).Guid
|
||||
};
|
||||
network.MetaData.Add(metaData);
|
||||
}
|
||||
|
||||
return network;
|
||||
}
|
||||
}
|
||||
}
|
||||
71
intromat/Intromat/Pipelines/DisplayMeshPipeline.cs
Normal file
71
intromat/Intromat/Pipelines/DisplayMeshPipeline.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using SharpDX.D3DCompiler;
|
||||
using SharpDX.Direct3D;
|
||||
using SharpDX.Direct3D11;
|
||||
using SharpDX.Mathematics.Interop;
|
||||
|
||||
namespace Intromat.Pipelines
|
||||
{
|
||||
public class DisplayMeshPipeline
|
||||
{
|
||||
private readonly VertexShader _vs;
|
||||
private readonly PixelShader _ps;
|
||||
private readonly DeviceContext _context;
|
||||
private readonly SamplerState _sampler;
|
||||
private ShaderResourceView? _srv;
|
||||
private readonly RasterizerState _rs;
|
||||
private readonly DepthStencilState _dss;
|
||||
private const string _vertexShader = "void main(in uint i : SV_VertexID, out float2 uv : TEXCOORD, out float4 pos : SV_Position) { uv = float2(i % 2, i / 2); pos = float4(uv * 2 - 1, 0.5, 1); }";
|
||||
private const string _pixelShader = "Texture2D t; SamplerState s; float4 main(in float2 uv : TEXCOORD) : SV_Target0 { return float4(t.Sample(s, uv).xyz, 1); }";
|
||||
|
||||
public DisplayMeshPipeline(Device device, DeviceContext context)
|
||||
{
|
||||
var flags = ShaderFlags.None;
|
||||
#if DEBUG
|
||||
flags |= ShaderFlags.Debug;
|
||||
#endif
|
||||
_vs = new VertexShader(device, ShaderBytecode.Compile(_vertexShader, "main", "vs_5_0", flags).Bytecode.Data);
|
||||
_ps = new PixelShader(device, ShaderBytecode.Compile(_pixelShader, "main", "ps_5_0", flags).Bytecode.Data);
|
||||
_context = context;
|
||||
var samplerDesc = new SamplerStateDescription
|
||||
{
|
||||
Filter = Filter.MinMagMipLinear,
|
||||
AddressU = TextureAddressMode.Clamp,
|
||||
AddressV = TextureAddressMode.Clamp,
|
||||
AddressW = TextureAddressMode.Clamp
|
||||
};
|
||||
_sampler = new SamplerState(device, samplerDesc);
|
||||
var rasterizerDesc = RasterizerStateDescription.Default();
|
||||
rasterizerDesc.CullMode = CullMode.None;
|
||||
rasterizerDesc.IsDepthClipEnabled = false;
|
||||
_rs = new RasterizerState(device, rasterizerDesc);
|
||||
var depthStencilStateDesc = DepthStencilStateDescription.Default();
|
||||
depthStencilStateDesc.IsDepthEnabled = false;
|
||||
_dss = new DepthStencilState(device, depthStencilStateDesc);
|
||||
}
|
||||
|
||||
public void Apply()
|
||||
{
|
||||
var viewport = _context.Rasterizer.GetViewports<RawViewportF>()[0];
|
||||
var dim = Math.Min(viewport.Width, viewport.Height);
|
||||
var offsetX = dim < viewport.Width ? (viewport.Width - dim) / 2 : 0;
|
||||
var offsetY = dim < viewport.Height ? (viewport.Height - dim) / 2 : 0;
|
||||
_context.Rasterizer.SetViewport(offsetX, offsetY, dim, dim);
|
||||
_context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleStrip;
|
||||
_context.VertexShader.Set(_vs);
|
||||
_context.PixelShader.Set(_ps);
|
||||
_context.PixelShader.SetShaderResources(0, _srv);
|
||||
_context.PixelShader.SetSampler(0, _sampler);
|
||||
_context.Rasterizer.State = _rs;
|
||||
_context.OutputMerger.DepthStencilState = _dss;
|
||||
_context.Draw(4, 0);
|
||||
_context.PixelShader.SetShaderResources(0, (ShaderResourceView?)null);
|
||||
}
|
||||
|
||||
public ShaderResourceView? ShaderResourceView
|
||||
{
|
||||
get => _srv;
|
||||
set => _srv = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
71
intromat/Intromat/Pipelines/DisplayTexturePipeline.cs
Normal file
71
intromat/Intromat/Pipelines/DisplayTexturePipeline.cs
Normal file
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using SharpDX.D3DCompiler;
|
||||
using SharpDX.Direct3D;
|
||||
using SharpDX.Direct3D11;
|
||||
using SharpDX.Mathematics.Interop;
|
||||
|
||||
namespace Intromat.Pipelines
|
||||
{
|
||||
public class DisplayTexturePipeline
|
||||
{
|
||||
private readonly VertexShader _vs;
|
||||
private readonly PixelShader _ps;
|
||||
private readonly DeviceContext _context;
|
||||
private readonly SamplerState _sampler;
|
||||
private ShaderResourceView? _srv;
|
||||
private readonly RasterizerState _rs;
|
||||
private readonly DepthStencilState _dss;
|
||||
private const string _vertexShader = "void main(in uint i : SV_VertexID, out float2 uv : TEXCOORD, out float4 pos : SV_Position) { uv = float2(i % 2, i / 2); pos = float4(uv * 2 - 1, 0.5, 1); }";
|
||||
private const string _pixelShader = "Texture2D t; SamplerState s; float4 main(in float2 uv : TEXCOORD) : SV_Target0 { return float4(t.Sample(s, uv).xyz, 1); }";
|
||||
|
||||
public DisplayTexturePipeline(Device device, DeviceContext context)
|
||||
{
|
||||
var flags = ShaderFlags.None;
|
||||
#if DEBUG
|
||||
flags |= ShaderFlags.Debug;
|
||||
#endif
|
||||
_vs = new VertexShader(device, ShaderBytecode.Compile(_vertexShader, "main", "vs_5_0", flags).Bytecode.Data);
|
||||
_ps = new PixelShader(device, ShaderBytecode.Compile(_pixelShader, "main", "ps_5_0", flags).Bytecode.Data);
|
||||
_context = context;
|
||||
var samplerDesc = new SamplerStateDescription
|
||||
{
|
||||
Filter = Filter.MinMagMipLinear,
|
||||
AddressU = TextureAddressMode.Clamp,
|
||||
AddressV = TextureAddressMode.Clamp,
|
||||
AddressW = TextureAddressMode.Clamp
|
||||
};
|
||||
_sampler = new SamplerState(device, samplerDesc);
|
||||
var rasterizerDesc = RasterizerStateDescription.Default();
|
||||
rasterizerDesc.CullMode = CullMode.None;
|
||||
rasterizerDesc.IsDepthClipEnabled = false;
|
||||
_rs = new RasterizerState(device, rasterizerDesc);
|
||||
var depthStencilStateDesc = DepthStencilStateDescription.Default();
|
||||
depthStencilStateDesc.IsDepthEnabled = false;
|
||||
_dss = new DepthStencilState(device, depthStencilStateDesc);
|
||||
}
|
||||
|
||||
public void Apply()
|
||||
{
|
||||
var viewport = _context.Rasterizer.GetViewports<RawViewportF>()[0];
|
||||
var dim = Math.Min(viewport.Width, viewport.Height);
|
||||
var offsetX = dim < viewport.Width ? (viewport.Width - dim) / 2 : 0;
|
||||
var offsetY = dim < viewport.Height ? (viewport.Height - dim) / 2 : 0;
|
||||
_context.Rasterizer.SetViewport(offsetX, offsetY, dim, dim);
|
||||
_context.InputAssembler.PrimitiveTopology = PrimitiveTopology.TriangleStrip;
|
||||
_context.VertexShader.Set(_vs);
|
||||
_context.PixelShader.Set(_ps);
|
||||
_context.PixelShader.SetShaderResources(0, _srv);
|
||||
_context.PixelShader.SetSampler(0, _sampler);
|
||||
_context.Rasterizer.State = _rs;
|
||||
_context.OutputMerger.DepthStencilState = _dss;
|
||||
_context.Draw(4, 0);
|
||||
_context.PixelShader.SetShaderResources(0, (ShaderResourceView?)null);
|
||||
}
|
||||
|
||||
public ShaderResourceView? ShaderResourceView
|
||||
{
|
||||
get => _srv;
|
||||
set => _srv = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
53
intromat/Intromat/Properties/AssemblyInfo.cs
Normal file
53
intromat/Intromat/Properties/AssemblyInfo.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using System.Reflection;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyTitle("Intromat")]
|
||||
[assembly: AssemblyDescription("")]
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("Intromat")]
|
||||
[assembly: AssemblyCopyright("Copyright (c) BluFlame")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
[assembly: AssemblyCulture("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
//In order to begin building localizable applications, set
|
||||
//<UICulture>CultureYouAreCodingWith</UICulture> in your .csproj file
|
||||
//inside a <PropertyGroup>. For example, if you are using US english
|
||||
//in your source files, set the <UICulture> to en-US. Then uncomment
|
||||
//the NeutralResourceLanguage attribute below. Update the "en-US" in
|
||||
//the line below to match the UICulture setting in the project file.
|
||||
|
||||
//[assembly: NeutralResourcesLanguage("en-US", UltimateResourceFallbackLocation.Satellite)]
|
||||
|
||||
|
||||
[assembly: ThemeInfo(
|
||||
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||
//(used if a resource is not found in the page,
|
||||
// or application resource dictionaries)
|
||||
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||
//(used if a resource is not found in the page,
|
||||
// app, or any theme specific resource dictionaries)
|
||||
)]
|
||||
|
||||
|
||||
// Version information for an assembly consists of the following four values:
|
||||
//
|
||||
// Major Version
|
||||
// Minor Version
|
||||
// Build Number
|
||||
// Revision
|
||||
//
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.0.0.0")]
|
||||
[assembly: AssemblyFileVersion("1.0.0.0")]
|
||||
8
intromat/Intromat/Properties/launchSettings.json
Normal file
8
intromat/Intromat/Properties/launchSettings.json
Normal file
@@ -0,0 +1,8 @@
|
||||
{
|
||||
"profiles": {
|
||||
"Intromat": {
|
||||
"commandName": "Project",
|
||||
"nativeDebugging": false
|
||||
}
|
||||
}
|
||||
}
|
||||
436
intromat/Intromat/Resources/HLSL-Mode.xshd
Normal file
436
intromat/Intromat/Resources/HLSL-Mode.xshd
Normal file
@@ -0,0 +1,436 @@
|
||||
<?xml version="1.0"?>
|
||||
<SyntaxDefinition name="C#" extensions=".cs" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
|
||||
<Color name="Comment" foreground="#FF57A64A" exampleText="// comment" />
|
||||
<Color name="Preprocessor" foreground="#FF9B9B9B" exampleText="#region Title"/>
|
||||
<Color name="Metadata" foreground="#FF4A57A6" exampleText="[numthreads(16, 16, 1)]"/>
|
||||
<Color name="Punctuation" foreground="#FFFFFFFF" exampleText="a(b.c);"/>
|
||||
<Color name="MethodCall" foreground="#FFdcdcaa" exampleText="o.ToString();"/>
|
||||
<Color name="FunctionCall" foreground="#FF88cdcd" exampleText="float a = clamp(b);"/>
|
||||
<Color name="Attributes" foreground="#FFdcdcaa" fontWeight="bold" exampleText="float a = clamp(b);"/>
|
||||
<Color name="NumberLiteral" foreground="#FFb5cea8" exampleText="3.1415f"/>
|
||||
<Color name="Keywords" foreground="#FFd8a0df" exampleText="if (a) {} else {}"/>
|
||||
<Color name="Modifiers" foreground="#FF559CD6" fontWeight="bold" exampleText="static readonly int a;"/>
|
||||
<Color name="TrueFalse" foreground="#FF00A0FF" exampleText="b = false; a = true;"/>
|
||||
<Color name="TypeKeywords" foreground="#FF559CD6" exampleText="if (x is int) { a = x as int; type = typeof(int); size = sizeof(int); c = new object(); }"/>
|
||||
<Color name="SemanticKeywords" foreground="#FF88cdcd" fontWeight="bold" exampleText="if (args == null) throw new ArgumentNullException(nameof(args));" />
|
||||
<Color name="CommentMarkerSetTodo" foreground="#FF008B8B" fontWeight="bold" />
|
||||
|
||||
<RuleSet name="CommentMarkerSet">
|
||||
<Keywords color="CommentMarkerSetTodo">
|
||||
<Word>TODO</Word>
|
||||
<Word>FIXME</Word>
|
||||
</Keywords>
|
||||
</RuleSet>
|
||||
|
||||
<!-- This is the main ruleset. -->
|
||||
<RuleSet>
|
||||
<Span color="Preprocessor">
|
||||
<Begin>\#</Begin>
|
||||
<RuleSet name="PreprocessorSet">
|
||||
<Span> <!-- preprocessor directives that allows comments -->
|
||||
<Begin fontWeight="bold">
|
||||
(define|undef|if|elif|else|endif|line)\b
|
||||
</Begin>
|
||||
<RuleSet>
|
||||
<Span color="Comment" ruleSet="CommentMarkerSet">
|
||||
<Begin>//</Begin>
|
||||
</Span>
|
||||
</RuleSet>
|
||||
</Span>
|
||||
<Span> <!-- preprocessor directives that don't allow comments -->
|
||||
<Begin fontWeight="bold">
|
||||
(region|endregion|error|warning|pragma)\b
|
||||
</Begin>
|
||||
</Span>
|
||||
</RuleSet>
|
||||
</Span>
|
||||
|
||||
<Span color="Comment" ruleSet="CommentMarkerSet">
|
||||
<Begin>//</Begin>
|
||||
</Span>
|
||||
|
||||
<Span color="Comment" ruleSet="CommentMarkerSet" multiline="true">
|
||||
<Begin>/\*</Begin>
|
||||
<End>\*/</End>
|
||||
</Span>
|
||||
|
||||
<Rule color="TypeKeywords">\b(Buffer|bool|int|uint|half|byte|short|ushort|float|double|long|ulong)([1-4]?)\b</Rule>
|
||||
<Rule color="TypeKeywords">\b(RW)?(Buffer|ByteAddressBuffer|StructuredBuffer)\b</Rule>
|
||||
<Rule color="TypeKeywords">\b(AppendStructuredBuffer|ConsumeStructuredBuffer|AppendBuffer|ConsumeBuffer)\b</Rule>
|
||||
<Rule color="TypeKeywords">\b(Texture1D|Texture1DArray|Texture2D|Texture2DArray|Texture3D|TextureCube)\b</Rule>
|
||||
<Rule color="TypeKeywords">\b(sampler|sampler1D|sampler2D|sampler3D|samplerCUBE|sampler_state|SamplerState)\b</Rule>
|
||||
|
||||
<Keywords color="TrueFalse">
|
||||
<Word>true</Word>
|
||||
<Word>false</Word>
|
||||
</Keywords>
|
||||
|
||||
<Keywords color="Keywords">
|
||||
<Word>if</Word>
|
||||
<Word>else</Word>
|
||||
<Word>break</Word>
|
||||
<Word>continue</Word>
|
||||
<Word>do</Word>
|
||||
<Word>for</Word>
|
||||
<Word>switch</Word>
|
||||
<Word>while</Word>
|
||||
<Word>return</Word>
|
||||
<Word>technique</Word>
|
||||
<Word>pass</Word>
|
||||
<Word>compile</Word>
|
||||
<Word>sampler</Word>
|
||||
<Word>register</Word>
|
||||
<Word>typedef</Word>
|
||||
<Word>struct</Word>
|
||||
<Word>cbuffer</Word>
|
||||
<Word>class</Word>
|
||||
<Word>goto</Word>
|
||||
<Word>union</Word>
|
||||
</Keywords>
|
||||
|
||||
<Span>
|
||||
<Begin>\[</Begin>
|
||||
<End>\]</End>
|
||||
<RuleSet>
|
||||
<Keywords color="Attributes">
|
||||
<Word>unroll</Word>
|
||||
<Word>loop</Word>
|
||||
<Word>domain</Word>
|
||||
<Word>earlydepthstencil</Word>
|
||||
<Word>instance</Word>
|
||||
<Word>maxtessfactor</Word>
|
||||
<Word>numthreads</Word>
|
||||
<Word>outputcontrolpoints</Word>
|
||||
<Word>outputtopology</Word>
|
||||
<Word>partitioning</Word>
|
||||
<Word>patchconstantfunc</Word>
|
||||
</Keywords>
|
||||
</RuleSet>
|
||||
</Span>
|
||||
|
||||
<Keywords color="Modifiers">
|
||||
<Word>in</Word>
|
||||
<Word>out</Word>
|
||||
<Word>inout</Word>
|
||||
<Word>precise</Word>
|
||||
</Keywords>
|
||||
|
||||
<Rule color="SemanticKeywords">
|
||||
:\s*\b
|
||||
(SV_ClipDistance\d
|
||||
|SV_CullDistance\d
|
||||
|SV_Coverage
|
||||
|SV_Depth
|
||||
|SV_DepthGreaterEqual
|
||||
|SV_DepthLessEqual
|
||||
|SV_DispatchThreadID
|
||||
|SV_DomainLocation
|
||||
|SV_GroupID
|
||||
|SV_GroupIndex
|
||||
|SV_GroupThreadID
|
||||
|SV_GSInstanceID
|
||||
|SV_InnerCoverage
|
||||
|SV_InsideTessFactor
|
||||
|SV_InstanceID
|
||||
|SV_IsFrontFace
|
||||
|SV_OutputControlPointID
|
||||
|SV_Position
|
||||
|SV_PrimitiveID
|
||||
|SV_RenderTargetArrayIndex
|
||||
|SV_SampleIndex
|
||||
|SV_StencilRef
|
||||
|SV_Target\d
|
||||
|SV_TessFactor
|
||||
|SV_VertexID
|
||||
|SV_ViewportArrayIndex
|
||||
|SV_ShadingRate
|
||||
|([A-Z][A-Z\d_]+))\b
|
||||
</Rule>
|
||||
|
||||
<Rule color="FunctionCall">
|
||||
\b
|
||||
(abs
|
||||
|acos
|
||||
|all
|
||||
|AllMemoryBarrier
|
||||
|AllMemoryBarrierWithGroupSync
|
||||
|any
|
||||
|asdouble
|
||||
|asfloat
|
||||
|asin
|
||||
|asint
|
||||
|asuint
|
||||
|atan
|
||||
|atan2
|
||||
|ceil
|
||||
|clamp
|
||||
|clip
|
||||
|cos
|
||||
|cosh
|
||||
|countbits
|
||||
|cross
|
||||
|D3DCOLORtoUBYTE4
|
||||
|ddx
|
||||
|ddx_coarse
|
||||
|ddx_fine
|
||||
|ddy
|
||||
|ddy_coarse
|
||||
|ddy_fine
|
||||
|degrees
|
||||
|determinant
|
||||
|DeviceMemoryBarrier
|
||||
|DeviceMemoryBarrierWithGroupSync
|
||||
|distance
|
||||
|dot
|
||||
|dst
|
||||
|EvaluateAttributeAtCentroid
|
||||
|EvaluateAttributeAtSample
|
||||
|EvaluateAttributeSnapped
|
||||
|exp
|
||||
|exp2
|
||||
|f16tof32
|
||||
|f32tof16
|
||||
|facetoforward
|
||||
|firstbithigh
|
||||
|firstbitlow
|
||||
|floor
|
||||
|fmod
|
||||
|frac
|
||||
|frexp
|
||||
|fwidth
|
||||
|GetRenderTargetSampleCount
|
||||
|GetRenderTargetSamplePosition
|
||||
|GroupMamoryBarrier
|
||||
|GroupMamoryBarrierWithGroupSync
|
||||
|InterlockedAdd
|
||||
|InterlockedCompareExchange
|
||||
|InterlockedCompareStore
|
||||
|InterlockedExchange
|
||||
|InterlockedMax
|
||||
|InterlockedMin
|
||||
|InterlockedOr
|
||||
|InterlockedXor
|
||||
|isfinite
|
||||
|isinf
|
||||
|isnan
|
||||
|ldexp
|
||||
|lerp
|
||||
|lit
|
||||
|log
|
||||
|log10
|
||||
|log2
|
||||
|mad
|
||||
|max
|
||||
|min
|
||||
|modf
|
||||
|mul
|
||||
|noise
|
||||
|normalize
|
||||
|pow
|
||||
|Process2DQuadTessFactorsAvg
|
||||
|Process2DQuadTessFactorsMax
|
||||
|Process2DQuadTessFactorsMin
|
||||
|ProcessIsolineTessFactors
|
||||
|ProcessQuadTessFactorsAvg
|
||||
|ProcessQuadTessFactorsMax
|
||||
|ProcessQuadTessFactorsMin
|
||||
|ProcessTriTessFactorsAvg
|
||||
|ProcessTriTessFactorsMax
|
||||
|ProcessTriTessFactorsMin
|
||||
|radians
|
||||
|rcp
|
||||
|reflect
|
||||
|refract
|
||||
|reversebits
|
||||
|round
|
||||
|rsqrt
|
||||
|saturate
|
||||
|sign
|
||||
|sin
|
||||
|sincos
|
||||
|sinh
|
||||
|smoothstep
|
||||
|sqrt
|
||||
|step
|
||||
|tan
|
||||
|tanh
|
||||
|tex1D
|
||||
|tex1Dbias
|
||||
|tex1Dgrad
|
||||
|tex1Dlod
|
||||
|tex1Dproj
|
||||
|tex2D
|
||||
|tex2Dbias
|
||||
|tex2Dgrad
|
||||
|tex2Dlod
|
||||
|tex3D
|
||||
|tex3Dbias
|
||||
|tex3Dgrad
|
||||
|tex3Dlod
|
||||
|tex3Dproj
|
||||
|texCUBE
|
||||
|texCUBEbias
|
||||
|texCUBEgrad
|
||||
|texCUBElod
|
||||
|texCUBEproj
|
||||
|transpose
|
||||
|trunc)
|
||||
(?=\s*\() # followed by (
|
||||
</Rule>
|
||||
|
||||
<Rule color="MethodCall">
|
||||
\b
|
||||
[\d\w_]+ # an identifier
|
||||
(?=\s*\() # followed by (
|
||||
</Rule>
|
||||
|
||||
<!-- Digits -->
|
||||
<Rule color="NumberLiteral">
|
||||
\b0[xX][0-9a-fA-F]+ # hex number
|
||||
|
|
||||
( \b\d+(\.[0-9]+)? #number with optional floating point
|
||||
| \.[0-9]+ #or just starting with floating point
|
||||
)
|
||||
([eE][+-]?[0-9]+)? # optional exponent
|
||||
</Rule>
|
||||
|
||||
<Rule color="Punctuation">
|
||||
[?,.;()\[\]{}+\-/%*<>^+~!|&]+
|
||||
</Rule>
|
||||
</RuleSet>
|
||||
</SyntaxDefinition>
|
||||
|
||||
<!--
|
||||
<SyntaxDefinition name="HLSL" xmlns="http://icsharpcode.net/sharpdevelop/syntaxdefinition/2008">
|
||||
<RuleSet>
|
||||
<Rule color="Functions">
|
||||
(abs
|
||||
|acos
|
||||
|all
|
||||
|AllMemoryBarrier
|
||||
|AllMemoryBarrierWithGroupSync
|
||||
|any
|
||||
|asdouble
|
||||
|asfloat
|
||||
|asin
|
||||
|asint
|
||||
|asuint
|
||||
|atan
|
||||
|atan2
|
||||
|ceil
|
||||
|clamp
|
||||
|clip
|
||||
|cos
|
||||
|cosh
|
||||
|countbits
|
||||
|cross
|
||||
|D3DCOLORtoUBYTE4
|
||||
|ddx
|
||||
|ddx_coarse
|
||||
|ddx_fine
|
||||
|ddy
|
||||
|ddy_coarse
|
||||
|ddy_fine
|
||||
|degrees
|
||||
|determinant
|
||||
|DeviceMemoryBarrier
|
||||
|DeviceMemoryBarrierWithGroupSync
|
||||
|distance
|
||||
|dot
|
||||
|dst
|
||||
|EvaluateAttributeAtCentroid
|
||||
|EvaluateAttributeAtSample
|
||||
|EvaluateAttributeSnapped
|
||||
|exp
|
||||
|exp2
|
||||
|f16tof32
|
||||
|f32tof16
|
||||
|facetoforward
|
||||
|firstbithigh
|
||||
|firstbitlow
|
||||
|floor
|
||||
|fmod
|
||||
|frac
|
||||
|frexp
|
||||
|fwidth
|
||||
|GetRenderTargetSampleCount
|
||||
|GetRenderTargetSamplePosition
|
||||
|GroupMamoryBarrier
|
||||
|GroupMamoryBarrierWithGroupSync
|
||||
|InterlockedAdd
|
||||
|InterlockedCompareExchange
|
||||
|InterlockedCompareStore
|
||||
|InterlockedExchange
|
||||
|InterlockedMax
|
||||
|InterlockedMin
|
||||
|InterlockedOr
|
||||
|InterlockedXor
|
||||
|isfinite
|
||||
|isinf
|
||||
|isnan
|
||||
|ldexp
|
||||
|lerp
|
||||
|lit
|
||||
|log
|
||||
|log10
|
||||
|log2
|
||||
|mad
|
||||
|max
|
||||
|min
|
||||
|modf
|
||||
|mul
|
||||
|noise
|
||||
|normalize
|
||||
|pow
|
||||
|Process2DQuadTessFactorsAvg
|
||||
|Process2DQuadTessFactorsMax
|
||||
|Process2DQuadTessFactorsMin
|
||||
|ProcessIsolineTessFactors
|
||||
|ProcessQuadTessFactorsAvg
|
||||
|ProcessQuadTessFactorsMax
|
||||
|ProcessQuadTessFactorsMin
|
||||
|ProcessTriTessFactorsAvg
|
||||
|ProcessTriTessFactorsMax
|
||||
|ProcessTriTessFactorsMin
|
||||
|radians
|
||||
|rcp
|
||||
|reflect
|
||||
|refract
|
||||
|reversebits
|
||||
|round
|
||||
|rsqrt
|
||||
|saturate
|
||||
|sign
|
||||
|sin
|
||||
|sincos
|
||||
|sinh
|
||||
|smoothstep
|
||||
|sqrt
|
||||
|step
|
||||
|tan
|
||||
|tanh
|
||||
|tex1D
|
||||
|tex1Dbias
|
||||
|tex1Dgrad
|
||||
|tex1Dlod
|
||||
|tex1Dproj
|
||||
|tex2D
|
||||
|tex2Dbias
|
||||
|tex2Dgrad
|
||||
|tex2Dlod
|
||||
|tex3D
|
||||
|tex3Dbias
|
||||
|tex3Dgrad
|
||||
|tex3Dlod
|
||||
|tex3Dproj
|
||||
|texCUBE
|
||||
|texCUBEbias
|
||||
|texCUBEgrad
|
||||
|texCUBElod
|
||||
|texCUBEproj
|
||||
|transpose
|
||||
|trunc)(\s*[(])
|
||||
</Rule>
|
||||
</RuleSet>
|
||||
</SyntaxDefinition>
|
||||
-->
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user