diff --git a/MaterialTest/Pages/Experiment.razor.cs b/MaterialTest/Pages/Experiment.razor.cs index 26359bf1..cf492398 100644 --- a/MaterialTest/Pages/Experiment.razor.cs +++ b/MaterialTest/Pages/Experiment.razor.cs @@ -126,7 +126,7 @@ void RunExperiment() { RunRenderTest(); } - void OnFlipClick(FlipViewer.OnClickEventArgs args) { + void OnFlipClick(FlipViewer.OnEventArgs args) { if (args.CtrlKey) { float p = args.X / (float)Width * 2.0f * float.Pi; float t = args.Y / (float)Height * float.Pi; @@ -141,7 +141,7 @@ void OnFlipClick(FlipViewer.OnClickEventArgs args) { } } - void OnFlipRenderClick(FlipViewer.OnClickEventArgs args) { + void OnFlipRenderClick(FlipViewer.OnEventArgs args) { if (args.CtrlKey) { RNG rng = new(1337, (uint)args.X, 1); for (int j = 0; j < args.Y; ++j) { diff --git a/MaterialTest/Pages/IntegratorTest.razor.cs b/MaterialTest/Pages/IntegratorTest.razor.cs index 521cf499..e7cf79ef 100644 --- a/MaterialTest/Pages/IntegratorTest.razor.cs +++ b/MaterialTest/Pages/IntegratorTest.razor.cs @@ -34,7 +34,7 @@ void RunExperiment() SurfacePoint? selected; - void OnFlipClick(FlipViewer.OnClickEventArgs args) + void OnFlipClick(FlipViewer.OnEventArgs args) { if (args.CtrlKey) { diff --git a/SeeSharp.Blazor/FlipViewer.razor b/SeeSharp.Blazor/FlipViewer.razor index f2f2294e..f42e0593 100644 --- a/SeeSharp.Blazor/FlipViewer.razor +++ b/SeeSharp.Blazor/FlipViewer.razor @@ -15,17 +15,30 @@ public SimpleImageIO.FlipBook Flip { get; set; } SimpleImageIO.FlipBook lastFlip; - public record struct OnClickEventArgs + public record struct OnEventArgs ( - int X, - int Y, - bool CtrlKey + int mouseButton, + // Mouse X/Y pixel coordinates relative to an image in Flipbook (Pixel (0, 0) at top left of image) + int mouseX, + int mouseY, + int deltaY, + + string FlipbookID, + int selectedIndex, + + HashSet keysPressed ) { } [Parameter] - public EventCallback OnClick { get; set; } + public EventCallback OnClick { get; set; } + [Parameter] + public EventCallback OnWheel { get; set; } + [Parameter] + public EventCallback OnMouseOver { get; set; } + [Parameter] + public EventCallback OnKey { get; set; } protected override async Task OnParametersSetAsync() { @@ -52,15 +65,34 @@ lastFlip = Flip; } - public struct _OnFlipClickArgs + [JSInvokable] + public void _OnFlipClick(int mouseButton, int mouseX, int mouseY, string ID, int selectedIdx, String[] keysPressed) + { + HashSet set = new HashSet(keysPressed); + OnClick.InvokeAsync(new(mouseButton: mouseButton, mouseX: mouseX, mouseY: mouseY, deltaY: -1, FlipbookID: ID, selectedIndex: selectedIdx, keysPressed: set)).Wait(); + } + + [JSInvokable] + + public void _OnFlipWheel(int mouseX, int mouseY, int deltaY, string ID, int selectedIdx, String[] keysPressed) + { + HashSet set = new HashSet(keysPressed); + OnWheel.InvokeAsync(new(mouseButton: -1, mouseX: mouseX, mouseY: mouseY, deltaY: deltaY, FlipbookID: ID, selectedIndex: selectedIdx, keysPressed: set)).Wait(); + } + + [JSInvokable] + public void _OnFlipMouseOver(int mouseX, int mouseY, string ID, int selectedIdx, String[] keysPressed) { - [JsonInclude] public bool ctrlKey; + HashSet set = new HashSet(keysPressed); + OnMouseOver.InvokeAsync(new(mouseButton: -1, mouseX: mouseX, mouseY: mouseY, deltaY: -1, FlipbookID: ID, selectedIndex: selectedIdx, keysPressed: set)).Wait(); } [JSInvokable] - public void _OnFlipClick(int x, int y, _OnFlipClickArgs eventArgs) + + public void _OnFlipKey(int mouseX, int mouseY, string ID, int selectedIdx, String[] keysPressed) { - OnClick.InvokeAsync(new(x, y, eventArgs.ctrlKey)).Wait(); + HashSet set = new HashSet(keysPressed); + OnKey.InvokeAsync(new(mouseButton: -1, mouseX: mouseX, mouseY: mouseY, deltaY: -1, FlipbookID: ID, selectedIndex: selectedIdx, keysPressed: set)).Wait(); } protected override async Task OnAfterRenderAsync(bool firstRender) @@ -68,7 +100,18 @@ // Need to wait with invoking the JS code until the HTML got added to the DOM on the client side if (flipJson != null) { - await JSRuntime.InvokeVoidAsync("makeFlipBook", flipJson, DotNetObjectReference.Create(this), nameof(_OnFlipClick)); + await JSRuntime.InvokeVoidAsync( + "makeFlipBook", + flipJson, + DotNetObjectReference.Create(this), + nameof(_OnFlipClick), + DotNetObjectReference.Create(this), + nameof(_OnFlipWheel), + DotNetObjectReference.Create(this), + nameof(_OnFlipMouseOver), + DotNetObjectReference.Create(this), + nameof(_OnFlipKey) + ); flipJson = null; } } diff --git a/SeeSharp.Blazor/Scripts.cs b/SeeSharp.Blazor/Scripts.cs index 1abe35d9..42f5b972 100644 --- a/SeeSharp.Blazor/Scripts.cs +++ b/SeeSharp.Blazor/Scripts.cs @@ -1,12 +1,12 @@ +using Microsoft.AspNetCore.StaticAssets; using Microsoft.JSInterop; +using System.Net.Http.Headers; using System.Reflection; namespace SeeSharp.Blazor; -public static class Scripts -{ - static string ReadResourceText(string filename) - { +public static class Scripts { + static string ReadResourceText(string filename) { var assembly = typeof(Scripts).GetTypeInfo().Assembly; var stream = assembly.GetManifestResourceStream("SeeSharp.Blazor." + filename) ?? throw new FileNotFoundException("resource file not found", filename); @@ -20,14 +20,32 @@ static string ReadResourceText(string filename) $$""" """; @@ -59,7 +77,17 @@ function makeFlipBook(jsonArgs, onClickObj, onClickMethodName) { """; - public static readonly string AllScripts = FlipBookScript + DownloadScript + WidgetScripts; + public static readonly string UpdateImageScript = + $$""" + + """; + + public static readonly string AllScripts = FlipBookScript + DownloadScript + WidgetScripts + UpdateImageScript; /// /// Downloads a stream to the client with the given file name. Requires that diff --git a/SeeSharp.Templates/content/SeeSharp.Blazor.Template/Pages/BaseExperiment.razor.cs b/SeeSharp.Templates/content/SeeSharp.Blazor.Template/Pages/BaseExperiment.razor.cs new file mode 100644 index 00000000..c8b58d5f --- /dev/null +++ b/SeeSharp.Templates/content/SeeSharp.Blazor.Template/Pages/BaseExperiment.razor.cs @@ -0,0 +1,156 @@ +using System.Threading.Tasks; +using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; +using SeeSharp.Blazor; + +namespace SeeSharp.Blazor.Template.Pages; + +public struct ListenerState { + public ListenerState() { } + + /// + /// The index of the selected image of the current selected flipbook (selected by clicking on it) + /// + public int selectedIndex = 0; + + /// + /// Number between 0 and NumSamples. Can be used if data is stored from different iterations + /// + public int currIteration = 0; + + // Add here all action keys for your functionalities + // Attention: any key press disables the default html scrolling! + public string actionKey1 = "a"; + public string actionKey2 = "d"; + public bool actionKey1Pressed = false; + public bool actionKey2Pressed = false; + + public int currX = 0; + public int currY = 0; + + /// + /// The ID of the current flipbook + /// + public string currFlipID = ""; +} + +/// +/// Differences between event type so update methods for flipbooks can ignore events +/// +public enum FiredType { + Click = 0, + Move = 1, + Wheel = 2, + Key = 4, +} + +public partial class BaseExperiment : ComponentBase { + protected const int Width = 1280; + protected const int Height = 720; + protected const int FlipWidth = 660; + protected const int FlipHeight = 580; + protected const int MaxDepth = 10; + public int NumSamples = 2; + + /// + /// Registers all Flipbooks + /// Key will be the stringified key of a Flipbook which is set by Flipbook.SetKey + /// A Flipbook key is an array of ints + /// + protected Dictionary registry = new Dictionary(); + protected ListenerState state = new ListenerState(); + public static string Reverse(string s) { + char[] charArray = s.ToCharArray(); + Array.Reverse(charArray); + return new string(charArray); + } + + /// + /// Is fired when clicked on an image in the flipbook + /// + /// ListenerState from HMTL side + public virtual void OnFlipClick(FlipViewer.OnEventArgs args) { + updateFlipbook(FiredType.Click); + } + + /// + /// Is fired when the mouse wheel state changes over an image. + /// This gets only called when the alt key is pressed (from HTML side) + /// + /// ListenerState from HMTL side. + public virtual void OnFlipWheel(FlipViewer.OnEventArgs args) { + if (state.actionKey1Pressed) { + // scrolled up + if (args.deltaY < 0) { + if (state.currIteration < NumSamples - 1) { + state.currIteration++; + updateFlipbook(FiredType.Wheel); + } + } + // scrolled down + if (args.deltaY >= 0) { + if (state.currIteration > 0) { + state.currIteration--; + updateFlipbook(FiredType.Wheel); + } + } + } + } + + /// + /// Is fired when mouse position changes over the selected flipbook + /// + /// ListenerState from HMTL side. + public virtual void OnFlipMouseOver(FlipViewer.OnEventArgs args) { + if (state.currX == args.mouseX && state.currY == args.mouseY) + return; + + if (args.mouseX >= 0 && args.mouseX <= Width - 1) + state.currX = args.mouseX; + if (args.mouseY >= 0 && args.mouseY <= Height - 1) + state.currY = args.mouseY; + + updateFlipbook(FiredType.Move); + } + + /// + /// Is fired when key is pressed or released + /// + /// ListenerState from HMTL side. + public virtual void OnFlipKey(FlipViewer.OnEventArgs args) { + bool wasKey1Pressed = state.actionKey1Pressed; + + state.actionKey1Pressed = args.keysPressed.Contains(state.actionKey1); + state.actionKey2Pressed = args.keysPressed.Contains(state.actionKey2); + + state.currFlipID = args.FlipbookID; + state.selectedIndex = args.selectedIndex; + + if (!state.actionKey1Pressed && wasKey1Pressed) + state.currIteration = 0; + + updateFlipbook(FiredType.Key); + } + + /// + /// Catches fired events and forward events to selected flipbooks + /// + /// Fired type + public virtual void updateFlipbook(FiredType fired) { + if (String.IsNullOrEmpty(state.currFlipID)) + return; + } + + /// + /// Runs the experiment when "..." is pressed on the HTML + /// + public virtual void RunExperiment() { + } + + /// + /// Is executed when Download button is pressed on the HTML + /// + /// + public virtual async Task OnDownloadClick() { + } +} \ No newline at end of file diff --git a/SeeSharp.Templates/content/SeeSharp.Blazor.Template/Pages/Experiment.razor b/SeeSharp.Templates/content/SeeSharp.Blazor.Template/Pages/Experiment.razor index 76543c49..3ed66a10 100644 --- a/SeeSharp.Templates/content/SeeSharp.Blazor.Template/Pages/Experiment.razor +++ b/SeeSharp.Templates/content/SeeSharp.Blazor.Template/Pages/Experiment.razor @@ -4,6 +4,8 @@ @inject IJSRuntime JS +@inherits SeeSharp.Blazor.Template.Pages.BaseExperiment + @page "/Experiment"

Example experiment

@@ -33,7 +35,7 @@
- @if (selected.HasValue && selected.Value) + @* @if (selected.HasValue && selected.Value) { @@ -41,8 +43,8 @@
Mesh@(selected.Value.Mesh.Name)
Distance@(selected.Value.Distance)
Position@(selected.Value.Position)
- } - + } *@ + @* *@
} } @@ -63,12 +65,12 @@ bool resultsAvailable = false; ElementReference runButton; - SimpleImageIO.FlipBook flip; - async Task OnSceneLoaded(SceneFromFile sceneFromFile) { await Task.Run(() => scene = sceneFromFile.MakeScene()); + flip = null; + resultsAvailable = false; readyToRun = true; sceneJustLoaded = true; diff --git a/SeeSharp.Templates/content/SeeSharp.Blazor.Template/Pages/Experiment.razor.cs b/SeeSharp.Templates/content/SeeSharp.Blazor.Template/Pages/Experiment.razor.cs index 109cc8db..802e15c2 100644 --- a/SeeSharp.Templates/content/SeeSharp.Blazor.Template/Pages/Experiment.razor.cs +++ b/SeeSharp.Templates/content/SeeSharp.Blazor.Template/Pages/Experiment.razor.cs @@ -1,30 +1,35 @@ using Microsoft.AspNetCore.Components; +using Microsoft.JSInterop; using SeeSharp.Blazor; namespace SeeSharp.Blazor.Template.Pages; -public partial class Experiment : ComponentBase -{ - const int Width = 1280; - const int Height = 720; - const int MaxDepth = 10; - - int NumSamples = 2; +public partial class Experiment : BaseExperiment { + public SimpleImageIO.FlipBook flip; long renderTimePT, renderTimeVCM; - void RunExperiment() - { - flip = new FlipBook(660, 580) + //Methods + PathTracer pathTracer; + VertexConnectionAndMerging vcm; + + /// + /// Initializes all flipbooks + /// + void InitFlipbooks() { + flip = new FlipBook(FlipWidth, FlipHeight) .SetZoom(FlipBook.InitialZoom.FillWidth) .SetToneMapper(FlipBook.InitialTMO.Exposure(scene.RecommendedExposure)) .SetToolVisibility(false); + } + + public override void RunExperiment() { + InitFlipbooks(); scene.FrameBuffer = new(Width, Height, ""); scene.Prepare(); - PathTracer pathTracer = new() - { + pathTracer = new() { TotalSpp = NumSamples, MaxDepth = MaxDepth, }; @@ -33,8 +38,7 @@ void RunExperiment() renderTimePT = scene.FrameBuffer.RenderTimeMs; scene.FrameBuffer = new(Width, Height, ""); - VertexConnectionAndMerging vcm = new() - { + vcm = new() { NumIterations = NumSamples, MaxDepth = MaxDepth, }; @@ -43,18 +47,11 @@ void RunExperiment() renderTimeVCM = scene.FrameBuffer.RenderTimeMs; } - SurfacePoint? selected; - - void OnFlipClick(FlipViewer.OnClickEventArgs args) - { - if (args.CtrlKey) - { - selected = scene.RayCast(new(args.X, args.Y)); - } - } - - async Task OnDownloadClick() - { + /// + /// Safes HTML of experiment + /// + /// + public override async Task OnDownloadClick() { HtmlReport report = new(); report.AddMarkdown(""" # Example experiment diff --git a/SeeSharp.Templates/content/SeeSharp.Blazor.Template/Program.cs b/SeeSharp.Templates/content/SeeSharp.Blazor.Template/Program.cs index 01ab1f6f..9245b9cb 100644 --- a/SeeSharp.Templates/content/SeeSharp.Blazor.Template/Program.cs +++ b/SeeSharp.Templates/content/SeeSharp.Blazor.Template/Program.cs @@ -9,8 +9,11 @@ var app = builder.Build(); -if (!app.Environment.IsDevelopment()) -{ +// Register scene folder +var scenesPath = "Scenes"; +SceneRegistry.AddSource(scenesPath); + +if (!app.Environment.IsDevelopment()) { // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts. app.UseHsts(); } diff --git a/SeeSharp.Templates/content/SeeSharp.Blazor.Template/wwwroot/css/site.css b/SeeSharp.Templates/content/SeeSharp.Blazor.Template/wwwroot/css/site.css index ddc98cca..edac4442 100644 --- a/SeeSharp.Templates/content/SeeSharp.Blazor.Template/wwwroot/css/site.css +++ b/SeeSharp.Templates/content/SeeSharp.Blazor.Template/wwwroot/css/site.css @@ -59,6 +59,7 @@ button { flex-direction: column; float: left; margin-right: 1em; + height: 10000px; /*Sets height of parameter window on the left site. Only visual benefits*/ } .experiment-results { @@ -68,6 +69,14 @@ button { align-items: flex-start; } +.compare { + display: flex; + gap: 10px; + margin-bottom: 10px; + flex-wrap: wrap; + align-items: flex-start; +} + table { border-collapse: collapse; }