Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 46 additions & 8 deletions SeeSharp.Blazor/FlipViewer.razor
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,29 @@

public record struct OnClickEventArgs
(
int X,
int Y,
bool CtrlKey
int mouseButton,
// Mouse X/Y relative to an image in Flipbook ((0, 0) at top left of image)
int mouseX,
int mouseY,
int deltaY,

string FlipbookID,
int selectedIndex,

string keyPressed,
bool isPressed
)
{
}

[Parameter]
public EventCallback<OnClickEventArgs> OnClick { get; set; }
[Parameter]
public EventCallback<OnClickEventArgs> OnWheel { get; set; }
[Parameter]
public EventCallback<OnClickEventArgs> OnMouseOver { get; set; }
[Parameter]
public EventCallback<OnClickEventArgs> OnKey { get; set; }

protected override async Task OnParametersSetAsync()
{
Expand All @@ -52,23 +66,47 @@
lastFlip = Flip;
}

public struct _OnFlipClickArgs
[JSInvokable]
public void _OnFlipClick(int mouseButton, int mouseX, int mouseY, int deltaY, string ID, int selectedIdx, string keyPressed, bool isPressed)
{
OnClick.InvokeAsync(new(mouseButton: mouseButton, mouseX: mouseX, mouseY: mouseY, deltaY: deltaY, FlipbookID: ID, selectedIndex: selectedIdx, keyPressed: keyPressed, isPressed: isPressed)).Wait();
}

[JSInvokable]
public void _OnFlipWheel(int mouseButton, int mouseX, int mouseY, int deltaY, string ID, int selectedIdx, string keyPressed, bool isPressed)
{
OnWheel.InvokeAsync(new(mouseButton: mouseButton, mouseX: mouseX, mouseY: mouseY, deltaY: deltaY, FlipbookID: ID, selectedIndex: selectedIdx, keyPressed: keyPressed, isPressed: isPressed)).Wait();
}

[JSInvokable]
public void _OnFlipMouseOver(int mouseButton, int mouseX, int mouseY, int deltaY, string ID, int selectedIdx, string keyPressed, bool isPressed)
{
[JsonInclude] public bool ctrlKey;
OnMouseOver.InvokeAsync(new(mouseButton: mouseButton, mouseX: mouseX, mouseY: mouseY, deltaY: deltaY, FlipbookID: ID, selectedIndex: selectedIdx, keyPressed: keyPressed, isPressed: isPressed)).Wait();
}

[JSInvokable]
public void _OnFlipClick(int x, int y, _OnFlipClickArgs eventArgs)
public void _OnFlipKey(int mouseButton, int mouseX, int mouseY, int deltaY, string ID, int selectedIdx, string keyPressed, bool isPressed)
{
OnClick.InvokeAsync(new(x, y, eventArgs.ctrlKey)).Wait();
OnKey.InvokeAsync(new(mouseButton: mouseButton, mouseX: mouseX, mouseY: mouseY, deltaY: deltaY, FlipbookID: ID, selectedIndex: selectedIdx, keyPressed: keyPressed, isPressed: isPressed)).Wait();
}

protected override async Task OnAfterRenderAsync(bool firstRender)
{
// 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;
}
}
Expand Down
46 changes: 37 additions & 9 deletions SeeSharp.Blazor/Scripts.cs
Original file line number Diff line number Diff line change
@@ -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);
Expand All @@ -20,14 +20,32 @@ static string ReadResourceText(string filename)
$$"""
<script>
{{SimpleImageIO.FlipBook.HeaderScript}}
function makeFlipBook(jsonArgs, onClickObj, onClickMethodName) {
function makeFlipBook(jsonArgs, onClickObj, onClickMethodName, onWheelObj, onWheelMethodName, onMouseOverObj, onMouseOverMethodName, onKeyObj, onKeyMethodName) {
let onClick = null;
if (onClickObj && onClickMethodName) {
onClick = (col, row, evt) =>
onClickObj.invokeMethodAsync(onClickMethodName, col, row, { ctrlKey: evt.ctrlKey })
onClick = (mouseButton, mouseX, mouseY, deltaY, ID, selectedIdx, keyPressed, isPressed) =>
onClickObj.invokeMethodAsync(onClickMethodName, mouseButton, mouseX, mouseY, deltaY, ID, selectedIdx, keyPressed, isPressed)
}

window['flipbook']['MakeFlipBook'](jsonArgs, onClick);
let onWheel = null
if (onWheelObj && onWheelMethodName) {
onWheel = (mouseButton, mouseX, mouseY, deltaY, ID, selectedIdx, keyPressed, isPressed) =>
onWheelObj.invokeMethodAsync(onWheelMethodName, mouseButton, mouseX, mouseY, deltaY, ID, selectedIdx, keyPressed, isPressed)
}

let onMouseOver = null
if (onMouseOverObj && onMouseOverMethodName) {
onMouseOver = (mouseButton, mouseX, mouseY, deltaY, ID, selectedIdx, keyPressed, isPressed) =>
onMouseOverObj.invokeMethodAsync(onMouseOverMethodName, mouseButton, mouseX, mouseY, deltaY, ID, selectedIdx, keyPressed, isPressed)
}

let onKey = null
if (onKeyObj && onKeyMethodName) {
onKey = (mouseButton, mouseX, mouseY, deltaY, ID, selectedIdx, keyPressed, isPressed) =>
onKeyObj.invokeMethodAsync(onKeyMethodName, mouseButton, mouseX, mouseY, deltaY, ID, selectedIdx, keyPressed, isPressed)
}

window['flipbook']['MakeFlipBook'](jsonArgs, onClick, onWheel, onMouseOver, onKey);
}
</script>
""";
Expand Down Expand Up @@ -59,7 +77,17 @@ function makeFlipBook(jsonArgs, onClickObj, onClickMethodName) {
</script>
""";

public static readonly string AllScripts = FlipBookScript + DownloadScript + WidgetScripts;
public static readonly string UpdateImageScript =
$$"""
<script>
function updateImage(jsonArgs) {
window['flipbook']['UpdateImage'](jsonArgs);
return;
}
</script>
""";

public static readonly string AllScripts = FlipBookScript + DownloadScript + WidgetScripts + UpdateImageScript;

/// <summary>
/// Downloads a stream to the client with the given file name. Requires that <see cref="DownloadScript" />
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
using System.Threading.Tasks;
using Microsoft.AspNetCore.Components;
using Microsoft.JSInterop;
using SeeSharp.Blazor;

namespace SeeSharp.Blazor.Template.Pages;

public struct ListenerState {
public ListenerState() { }

/// <summary>
/// The index of the selected image of the current selected flipbook (selected by clicking on it)
/// </summary>
public int selectedIndex = 0;

/// <summary>
/// Number between 0 and NumSamples. Can be used if data is stored from different iterations
/// </summary>
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;

/// <summary>
/// The ID of the current flipbook
/// </summary>
public string currFlipID = "";
}

/// <summary>
/// Differences between event type so update methods for flipbooks can ignore events
/// </summary>
public enum FiredType {
Click = 0,
Move = 1,
Wheel = 2,
KeyDown = 4,
KeyUp = 8,
}

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;

/// <summary>
/// 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
/// </summary>
protected Dictionary<string, FlipBook> registry = new Dictionary<string, FlipBook>();
protected ListenerState state = new ListenerState();
public static string Reverse(string s) {
char[] charArray = s.ToCharArray();
Array.Reverse(charArray);
return new string(charArray);
}

/// <summary>
/// Is fired when clicked on an image in the flipbook
/// </summary>
/// <param name="args">ListenerState from HMTL side</param>
public virtual void OnFlipClick(FlipViewer.OnClickEventArgs args) {
updateFlipbook(FiredType.Click);
}

/// <summary>
/// Is fired when the mouse wheel state changes over an image.
/// This gets only called when the alt key is pressed (from HTML side)
/// </summary>
/// <param name="args">ListenerState from HMTL side.</param>
public virtual void OnFlipWheel(FlipViewer.OnClickEventArgs 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);
}
}
}
}

/// <summary>
/// Is fired when mouse position changes over the selected flipbook
/// </summary>
/// <param name="args">ListenerState from HMTL side.</param>
public virtual void OnFlipMouseOver(FlipViewer.OnClickEventArgs 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);
}

/// <summary>
/// Is fired when key is pressed or released
/// </summary>
/// <param name="args">ListenerState from HMTL side.</param>
public virtual void OnFlipKey(FlipViewer.OnClickEventArgs args) {
if (args.keyPressed == state.actionKey1)
state.actionKey1Pressed = args.isPressed;

if (args.keyPressed == state.actionKey2)
state.actionKey2Pressed = args.isPressed;

state.currFlipID = args.FlipbookID;
state.selectedIndex = args.selectedIndex;

if (args.keyPressed == state.actionKey1 && !args.isPressed)
state.currIteration = 0;

if (args.isPressed)
updateFlipbook(FiredType.KeyDown);
else
updateFlipbook(FiredType.KeyUp);
}

/// <summary>
/// Catches fired events and forward events to selected flipbooks
/// </summary>
/// <param name="fired">Fired type</param>
public virtual void updateFlipbook(FiredType fired) {
if (String.IsNullOrEmpty(state.currFlipID))
return;
}

/// <summary>
/// Runs the experiment when "..." is pressed on the HTML
/// </summary>
public virtual void RunExperiment() {
}

/// <summary>
/// Is executed when Download button is pressed on the HTML
/// </summary>
/// <returns></returns>
public virtual async Task OnDownloadClick() {
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@

@inject IJSRuntime JS

@inherits SeeSharp.Blazor.Template.Pages.BaseExperiment

@page "/Experiment"

<h1>Example experiment</h1>
Expand Down Expand Up @@ -33,16 +35,16 @@
<div class="experiment-results">
<FlipViewer Flip="@flip" OnClick="@OnFlipClick"></FlipViewer>

@if (selected.HasValue && selected.Value)
@* @if (selected.HasValue && selected.Value)
{
<table>
<tr><th>Mesh</th><td>@(selected.Value.Mesh.Name)</td></tr>
<tr><th>Material</th><td>@(selected.Value.Mesh.Material.Name) (roughness: @(selected.Value.Mesh.Material.GetRoughness(selected.Value)), transmissive: @(selected.Value.Mesh.Material.IsTransmissive(selected.Value)))</td></tr>
<tr><th>Distance</th><td>@(selected.Value.Distance)</td></tr>
<tr><th>Position</th><td>@(selected.Value.Position)</td></tr>
</table>
}
<button @onclick="OnDownloadClick">Download results</button>
} *@
@* <button @onclick="OnDownloadClick">Download results</button> *@
</div>
}
}
Expand All @@ -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;
Expand Down
Loading