Skip to content

Commit

Permalink
feat(wasm): externalize it better
Browse files Browse the repository at this point in the history
  • Loading branch information
jourdain committed Feb 20, 2024
1 parent a8ffd63 commit 41ff3a2
Show file tree
Hide file tree
Showing 14 changed files with 77 additions and 14,496 deletions.
28 changes: 24 additions & 4 deletions examples/vtk/cone.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
from trame.app import get_server
from trame.ui.html import DivLayout
from trame.widgets import vtklocal
from trame.widgets import vtklocal, html
from trame.decorators import TrameApp, change

from vtkmodules.vtkFiltersSources import vtkConeSource
from vtkmodules.vtkRenderingCore import (
Expand All @@ -18,6 +19,8 @@
# local rendering, but doesn't hurt to include it
import vtkmodules.vtkRenderingOpenGL2 # noqa

CLIENT_TYPE = "vue3"

# -----------------------------------------------------------------------------
# VTK pipeline
# -----------------------------------------------------------------------------
Expand All @@ -44,26 +47,43 @@ def create_vtk_pipeline():
renderer.SetBackground(1, 0, 0)
renderer.ResetCamera()

return renderWindow
return renderWindow, cone


# -----------------------------------------------------------------------------
# GUI
# -----------------------------------------------------------------------------


@TrameApp()
class DemoApp:
def __init__(self, server=None):
self.server = get_server(server, client_type="vue2")
self.render_window = create_vtk_pipeline()
self.server = get_server(server, client_type=CLIENT_TYPE)
self.render_window, self.cone = create_vtk_pipeline()
self.html_view = None
self.ui = self._ui()
print(self.ui)

@change("resolution")
def on_resolution_change(self, resolution, **kwargs):
if int(resolution) != 6:
self.cone.SetResolution(int(resolution))
self.render_window.Render()
self.html_view.update()

def _ui(self):
with DivLayout(self.server) as layout:
self.html_view = vtklocal.LocalView(
self.render_window, style="width: 100vw; height: 100vh;"
)
html.Input(
type="range",
v_model=("resolution", 6),
min=3,
max=60,
step=1,
style="position: absolute; top: 1rem; right: 1rem; z-index: 10;",
)

return layout

Expand Down
3 changes: 2 additions & 1 deletion examples/vtk/flow.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@
# local rendering, but doesn't hurt to include it
import vtkmodules.vtkRenderingOpenGL2 # noqa

CLIENT_TYPE = "vue3"
DATA_FILE = str((Path(__file__).parent.with_name("data") / "carotid.vtk").resolve())

# -----------------------------------------------------------------------------
Expand Down Expand Up @@ -138,7 +139,7 @@ def create_vtk_pipeline():

class DemoApp:
def __init__(self, server=None):
self.server = get_server(server, client_type="vue2")
self.server = get_server(server, client_type=CLIENT_TYPE)
self.render_window = create_vtk_pipeline()
self.html_view = None
self.ui = self._ui()
Expand Down
1 change: 1 addition & 0 deletions examples/vtk/mapper.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"ArrayAccessMode":0,"ArrayComponent":0,"ArrayId":-1,"ArrayName":"","ClassName":"vtkOpenGLPolyDataMapper","ColorMode":0,"ExtractedInputData":{"Id":9},"FieldDataTupleId":-1,"GhostLevel":0,"Id":8,"InterpolateScalarsBeforeMapping":0,"Length":1.7320508075688772,"LookupTable":{"Id":21},"MTime":1324,"NumberOfSubPieces":1,"ObjectDescription":"vtkOpenGLPolyDataMapper (0x1070fda00)","PauseShiftScale":false,"Piece":0,"PopulateSelectionSettings":1,"RenderTime":0.0,"ResolveCoincidentTopology":0,"ResolveCoincidentTopologyPolygonOffsetFaces":1,"ResolveCoincidentTopologyZShift":0.01,"ScalarMode":0,"ScalarRange":[0.0,1.0],"ScalarVisibility":1,"SeamlessU":false,"SeamlessV":false,"Static":0,"SuperClassNames":["vtkObjectBase","vtkAlgorithm","vtkAbstractMapper","vtkAbstractMapper3D","vtkMapper","vtkPolyDataMapper"],"SuperModuleNames":["(null)","vtkCommonExecutionModel","(null)","(null)","(null)","vtkRenderingCore"],"SupportsSelection":true,"UseLookupTableScalarRange":0,"UseProgramPointSize":false,"VBOShiftScaleMethod":1}
6 changes: 1 addition & 5 deletions trame_vtklocal/module/.gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1 @@
# serve
serve/*.map
serve/*.html
serve/*.common.*
serve/*.umd.js
serve/js
18 changes: 15 additions & 3 deletions trame_vtklocal/module/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,12 @@

serve_path = str(Path(__file__).with_name("serve").resolve())
serve = {"__trame_vtklocal": serve_path}
scripts = ["__trame_vtklocal/trame_vtklocal.umd.js"]
module_scripts = [
"__trame_vtklocal/wasm/vtkObjectManager.js",
]
scripts = [
"__trame_vtklocal/js/trame_vtklocal.umd.js",
]
vue_use = ["trame_vtklocal"]


Expand Down Expand Up @@ -43,6 +48,11 @@ def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.vtk_object_manager = vtkObjectManager()
self.vtk_object_manager.Initialize()
self.dirty_ids = set()

def update(self):
self.dirty_ids.update(self.vtk_object_manager.Update())
return self.dirty_ids

@export_rpc("vtklocal.get.state")
def get_state(self, obj_id):
Expand All @@ -59,8 +69,10 @@ def get_hash(self, hash):
@export_rpc("vtklocal.get.status")
def get_status(self, obj_id):
# print("get_status", obj_id)
ids = extract_ids(self.vtk_object_manager, [], obj_id)
hashes = list(self.vtk_object_manager.GetBlobHashes(ids))
ids = set(extract_ids(self.vtk_object_manager, [], obj_id))
ids.update(self.dirty_ids)
self.dirty_ids.clear()
hashes = list(self.vtk_object_manager.GetBlobHashes(list(ids)))
return dict(
ids=[map_id_mtime(self.vtk_object_manager, v) for v in ids],
hashes=hashes,
Expand Down
Binary file removed trame_vtklocal/module/serve/vtkObjectManager.wasm
Binary file not shown.
15 changes: 15 additions & 0 deletions trame_vtklocal/module/serve/wasm/vtkObjectManager.js

Large diffs are not rendered by default.

Binary file not shown.
13 changes: 10 additions & 3 deletions trame_vtklocal/widgets/vtklocal.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,21 +30,28 @@ def __init__(self, render_window, **kwargs):

# Must trigger update after registration
self._window_id = self.object_manager.RegisterObject(render_window)
self.object_manager.Update()
self.api.update()

self._attributes["rw_id"] = f':render-window="{self._window_id}"'
self._attributes["ref"] = f'ref="{self.__ref}"'
self._attr_names += []
self._event_names += []

@property
def api(self):
return module.get_helper(self.server).api

@property
def object_manager(self):
return module.get_helper(self.server).api.vtk_object_manager
return self.api.vtk_object_manager

def update(self):
updated_ids = self.object_manager.Update()
updated_ids = self.api.update()
# TODO broadcast modified [(id,mtime), ...]
print(f"update({updated_ids=})")
for vtk_id in updated_ids:
vtk_obj = self.object_manager.GetObjectWithId(vtk_id)
print(f" - {vtk_id}:{vtk_obj.GetClassName()}")
self.server.js_call(
self.__ref,
"update",
Expand Down
Binary file removed vue-components/public/vtkObjectManager.wasm
Binary file not shown.
9 changes: 6 additions & 3 deletions vue-components/src/components/VtkLocal.js
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,14 @@ export default {
const session = client.getConnection().getSession();
const serverState = await session.call("vtklocal.get.state", [vtkId]);
stateMTimes[vtkId] = serverState.mtime;
// console.log(`vtkLocal::state(${vtkId}) =`)
console.log(`vtkLocal::state(${vtkId})`)
objectManager.registerState(serverState);
return serverState;
}
async function fetchHash(hash) {
const session = client.getConnection().getSession();
const blob = await session.call("vtklocal.get.hash", [hash]);
console.log(`vtkLocal::hash(${hash})`)
const array = new Uint8Array(await blob.arrayBuffer());
objectManager.registerBlob(hash, array);
hashesAvailable.add(hash);
Expand All @@ -57,9 +58,13 @@ export default {
props.renderWindow,
]);
const pendingRequests = [];
console.log("ids", serverStatus.ids);
serverStatus.ids.forEach(([vtkId, mtime]) => {
if (!stateMTimes[vtkId] || stateMTimes[vtkId] < mtime) {
console.log("fetch", vtkId)
pendingRequests.push(fetchState(vtkId));
} else {
console.log("skip", vtkId)
}
});
serverStatus.hashes.forEach((hash) => {
Expand Down Expand Up @@ -105,8 +110,6 @@ export default {
ref="canvas"
style="position: absolute; left: 50%; top: 50%; transform: translate(-50%, -50%);"
tabindex="0"
@contextmenu.prevent
Expand Down
6 changes: 2 additions & 4 deletions vue-components/src/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
import vtkObjectManager from "./vtkObjectManager";

export async function createModule(canvas) {
const module = {
canvas,
locateFile() {
return "__trame_vtklocal/vtkObjectManager.wasm";
return "__trame_vtklocal/wasm/vtkObjectManager.wasm";
},
print() {
console.info(Array.prototype.slice.call(arguments).join(" "));
Expand All @@ -13,7 +11,7 @@ export async function createModule(canvas) {
console.error(Array.prototype.slice.call(arguments).join(" "));
},
};
const objectManager = await vtkObjectManager(module);
const objectManager = await window.vtkWASMObjectManager(module);
objectManager.initialize();
return objectManager;
}
Loading

0 comments on commit 41ff3a2

Please sign in to comment.