changeset 227:c8f11437a6fd am

getting ready for multiple viewports
author am@osimis.io
date Thu, 14 Jun 2018 13:28:40 +0200
parents 1fa4c65c7e1b
children 210c1ce8e1a6
files Platforms/WebAssembly/Defaults.cpp Platforms/WebAssembly/Defaults.h Platforms/WebAssembly/wasm-application.js Platforms/WebAssembly/wasm-viewport.ts
diffstat 4 files changed, 162 insertions(+), 136 deletions(-) [+]
line wrap: on
line diff
--- a/Platforms/WebAssembly/Defaults.cpp	Thu Jun 14 12:32:08 2018 +0200
+++ b/Platforms/WebAssembly/Defaults.cpp	Thu Jun 14 13:28:40 2018 +0200
@@ -17,19 +17,43 @@
 static OrthancStone::StatusBar statusBar_;
 
 
+static std::list<std::shared_ptr<OrthancStone::WidgetViewport>> viewports_;
+
 #ifdef __cplusplus
 extern "C" {
 #endif
 
   using namespace OrthancStone;
-  
-  void EMSCRIPTEN_KEEPALIVE CreateWasmApplication() {
+
+  // when WASM needs a C++ viewport
+  ViewportHandle EMSCRIPTEN_KEEPALIVE CreateCppViewport() {
+    
+    std::shared_ptr<OrthancStone::WidgetViewport> viewport(new OrthancStone::WidgetViewport);
+    printf("viewport %x\n", viewport.get());
+
+    viewports_.push_back(viewport);
+
+    printf("There are now %d viewports in C++\n", viewports_.size());
+
+    viewport->SetStatusBar(statusBar_);
+    viewport->Register(changeObserver_);
+
+    // TODO: remove once we really want to handle multiple viewports
+    viewport_ = viewport;
+    return viewport.get();
+  }
+
+  // when WASM does not need a viewport anymore, it should release it 
+  void EMSCRIPTEN_KEEPALIVE ReleaseCppViewport(ViewportHandle viewport) {
+    viewports_.remove_if([viewport](const std::shared_ptr<OrthancStone::WidgetViewport>& v) { return v.get() == viewport;});
+
+    printf("There are now %d viewports in C++\n", viewports_.size());
+  }
+
+
+  void EMSCRIPTEN_KEEPALIVE CreateWasmApplication(ViewportHandle viewport) {
 
     printf("CreateWasmApplication\n");
-    viewport_.reset(new OrthancStone::WidgetViewport);
-    viewport_->SetStatusBar(statusBar_);
-    viewport_->Register(changeObserver_);
-
 
     application.reset(CreateUserApplication());
 
@@ -122,7 +146,8 @@
     }
   }
 
-  int EMSCRIPTEN_KEEPALIVE ViewportRender(unsigned int width,
+  int EMSCRIPTEN_KEEPALIVE ViewportRender(OrthancStone::WidgetViewport* viewport,
+                                          unsigned int width,
                                           unsigned int height,
                                           uint8_t* data)
   {
@@ -138,10 +163,7 @@
     Orthanc::ImageAccessor surface;
     surface.AssignWritable(Orthanc::PixelFormat_BGRA32, width, height, 4 * width, data);
 
-    if (viewport_.get() != NULL)
-    {
-      viewport_->Render(surface);
-    }
+    viewport->Render(surface);
 
     // Convert from BGRA32 memory layout (only color mode supported by
     // Cairo, which corresponds to CAIRO_FORMAT_ARGB32) to RGBA32 (as
--- a/Platforms/WebAssembly/Defaults.h	Thu Jun 14 12:32:08 2018 +0200
+++ b/Platforms/WebAssembly/Defaults.h	Thu Jun 14 13:28:40 2018 +0200
@@ -9,6 +9,8 @@
 #include <Applications/Wasm/BasicWasmApplication.h>
 #include <Applications/Wasm/BasicWasmApplicationContext.h>
 
+typedef OrthancStone::WidgetViewport* ViewportHandle; // the objects exchanged between JS and C++
+
 #ifdef __cplusplus
 extern "C" {
 #endif
@@ -17,7 +19,7 @@
   extern void ScheduleRedraw();
   
   // C++ methods accessible from JS
-  extern void EMSCRIPTEN_KEEPALIVE CreateWasmApplication();
+  extern void EMSCRIPTEN_KEEPALIVE CreateWasmApplication(ViewportHandle viewport);
 //   extern void EMSCRIPTEN_KEEPALIVE SetStartupParameter(const char* keyc, const char* value);
 //   extern void EMSCRIPTEN_KEEPALIVE StartWasmApplication();
 
--- a/Platforms/WebAssembly/wasm-application.js	Thu Jun 14 12:32:08 2018 +0200
+++ b/Platforms/WebAssembly/wasm-application.js	Thu Jun 14 13:28:40 2018 +0200
@@ -47,26 +47,23 @@
 function InitializeWasmApplication(canvasId)
 {
   console.log("Initializing wasm-app");
-  viewport = new Stone.WasmViewport(StoneFrameworkModule, 'canvas');
-  viewport.Initialize();
 
-  /******************** */
+  console.log("Connecting C++ methods to JS methods");
   SetStartupParameter = StoneFrameworkModule.cwrap('SetStartupParameter', null, [ 'string', 'string' ]);
-  CreateWasmApplication = StoneFrameworkModule.cwrap('CreateWasmApplication', null, [ ], [ ]);
+  CreateWasmApplication = StoneFrameworkModule.cwrap('CreateWasmApplication', null, [ 'any' ], [ ]);
+  CreateCppViewport = StoneFrameworkModule.cwrap('CreateCppViewport', 'any', [ ], [ ]);
+  ReleaseCppViewport = StoneFrameworkModule.cwrap('ReleaseCppViewport', null, [ 'any' ], [ ]);
   StartWasmApplication = StoneFrameworkModule.cwrap('StartWasmApplication', null, [ ], [ ]);
-                                 
-  /******************** */
-
-  // NotifyGlobalParameter = StoneFrameworkModule.cwrap('NotifyGlobalParameter', null,
-  //                                      [ 'string', 'string' ]);
-  // ViewportUpdate = StoneFrameworkModule.cwrap('ViewportUpdate', null,
-  //                                      [ 'string' ]);
   WasmWebService_NotifySuccess = StoneFrameworkModule.cwrap('WasmWebService_NotifySuccess', null,
                                               [ 'number', 'string', 'array', 'number', 'number' ]);
   WasmWebService_NotifyError = StoneFrameworkModule.cwrap('WasmWebService_NotifyError', null,
                                             [ 'number', 'string', 'number' ]);
-  //NotifyRestApiGet = Module.cwrap('NotifyRestApiGet', null, [ 'number', 'array', 'number' ]);
   NotifyUpdateContent = StoneFrameworkModule.cwrap('NotifyUpdateContent', null, [  ]);
+                                 
+  console.log("Creating main viewport");
+
+  viewport = new Stone.WasmViewport(StoneFrameworkModule, 'canvas');
+  viewport.Initialize(CreateCppViewport());
 
   // Prevent scrolling
   document.body.addEventListener('touchmove', function(event) {
--- a/Platforms/WebAssembly/wasm-viewport.ts	Thu Jun 14 12:32:08 2018 +0200
+++ b/Platforms/WebAssembly/wasm-viewport.ts	Thu Jun 14 13:28:40 2018 +0200
@@ -29,6 +29,8 @@
     private ViewportMouseWheel : Function;
     private ViewportKeyPressed : Function;
 
+    private pimpl_ : any; // Private pointer to the underlying WebAssembly C++ object
+
     public constructor(module: any, canvasId: string) {
       this.module_ = module;
       this.canvasId_ = canvasId;
@@ -36,7 +38,7 @@
       this.context_ = this.htmlCanvas_.getContext('2d');
 
       this.ViewportSetSize = this.module_.cwrap('ViewportSetSize', null, [ 'number', 'number' ]);
-      this.ViewportRender = this.module_.cwrap('ViewportRender', null, [ 'number', 'number', 'number', 'number' ]);
+      this.ViewportRender = this.module_.cwrap('ViewportRender', null, [ 'any', 'number', 'number', 'number' ]);
       this.ViewportMouseDown = this.module_.cwrap('ViewportMouseDown', null, [ 'number', 'number', 'number', 'number' ]);
       this.ViewportMouseMove = this.module_.cwrap('ViewportMouseMove', null, [ 'number', 'number' ]);
       this.ViewportMouseUp = this.module_.cwrap('ViewportMouseUp', null, [ ]);
@@ -49,7 +51,8 @@
     public Redraw() {
       if (this.imageData_ === null ||
           this.renderingBuffer_ === null ||
-          this.ViewportRender(this.imageData_.width,
+          this.ViewportRender(this.pimpl_,
+                         this.imageData_.width,
                          this.imageData_.height,
                          this.renderingBuffer_) == 0) {
         console.log('The rendering has failed');
@@ -90,127 +93,129 @@
       this.Redraw();
     }
 
-    public Initialize() {
-
-    // Force the rendering of the viewport for the first time
-    this.Resize();
-  
-    // Register an event listener to call the Resize() function 
-    // each time the window is resized.
-    window.addEventListener('resize', this.Resize, false);
-  
-    var that = this;
-  
-    this.htmlCanvas_.addEventListener('contextmenu', function(event) {
-      // Prevent right click on the canvas
-      event.preventDefault();
-    }, false);
-    
-    this.htmlCanvas_.addEventListener('mouseleave', function(event) {
-      that.ViewportMouseLeave();
-    });
+    public Initialize(cppViewport: any) {
+      this.pimpl_ = cppViewport;
+      
+      console.log(this.pimpl_);
+      // Force the rendering of the viewport for the first time
+      this.Resize();
     
-    this.htmlCanvas_.addEventListener('mouseenter', function(event) {
-      that.ViewportMouseEnter();
-    });
-  
-    this.htmlCanvas_.addEventListener('mousedown', function(event) {
-      var x = event.pageX - this.offsetLeft;
-      var y = event.pageY - this.offsetTop;
-      that.ViewportMouseDown(event.button, x, y, 0 /* TODO */);    
-    });
-  
-    this.htmlCanvas_.addEventListener('mousemove', function(event) {
-      var x = event.pageX - this.offsetLeft;
-      var y = event.pageY - this.offsetTop;
-      that.ViewportMouseMove(x, y);
-    });
-  
-    this.htmlCanvas_.addEventListener('mouseup', function(event) {
-      that.ViewportMouseUp();
-    });
-  
-    window.addEventListener('keydown', function(event) {
-      that.ViewportKeyPressed(event.key, event.shiftKey, event.ctrlKey, event.altKey);
-    });
+      // Register an event listener to call the Resize() function 
+      // each time the window is resized.
+      window.addEventListener('resize', this.Resize, false);
   
-    this.htmlCanvas_.addEventListener('wheel', function(event) {
-      var x = event.pageX - this.offsetLeft;
-      var y = event.pageY - this.offsetTop;
-      that.ViewportMouseWheel(event.deltaY, x, y, event.ctrlKey);
-      event.preventDefault();
-    });
-
-    var that = this;
-    this.htmlCanvas_.addEventListener('touchstart', function(event) {
-      that.ResetTouch();
-    });
-  
-    this.htmlCanvas_.addEventListener('touchend', function(event) {
-      that.ResetTouch();
-    });
+      var that = this;
+    
+      this.htmlCanvas_.addEventListener('contextmenu', function(event) {
+        // Prevent right click on the canvas
+        event.preventDefault();
+      }, false);
+      
+      this.htmlCanvas_.addEventListener('mouseleave', function(event) {
+        that.ViewportMouseLeave();
+      });
+      
+      this.htmlCanvas_.addEventListener('mouseenter', function(event) {
+        that.ViewportMouseEnter();
+      });
+    
+      this.htmlCanvas_.addEventListener('mousedown', function(event) {
+        var x = event.pageX - this.offsetLeft;
+        var y = event.pageY - this.offsetTop;
+        that.ViewportMouseDown(event.button, x, y, 0 /* TODO */);    
+      });
+    
+      this.htmlCanvas_.addEventListener('mousemove', function(event) {
+        var x = event.pageX - this.offsetLeft;
+        var y = event.pageY - this.offsetTop;
+        that.ViewportMouseMove(x, y);
+      });
+    
+      this.htmlCanvas_.addEventListener('mouseup', function(event) {
+        that.ViewportMouseUp();
+      });
+    
+      window.addEventListener('keydown', function(event) {
+        that.ViewportKeyPressed(event.key, event.shiftKey, event.ctrlKey, event.altKey);
+      });
     
-    this.htmlCanvas_.addEventListener('touchmove', function(event) {
-      if (that.touchTranslation_.length == 2) {
-        var t = that.GetTouchTranslation(event);
-        that.ViewportMouseMove(t[0], t[1]);
-      }
-      else if (that.touchZoom_.length == 3) {
-        var z0 = that.touchZoom_;
-        var z1 = that.GetTouchZoom(event);
-        that.ViewportMouseMove(z0[0], z0[1] - z0[2] + z1[2]);
-      }
-      else {
-        // Realize the gesture event
-        if (event.targetTouches.length == 1) {
-          // Exactly one finger inside the canvas => Setup a translation
-          that.touchTranslation_ = that.GetTouchTranslation(event);
-          that.ViewportMouseDown(1 /* middle button */,
-                                 that.touchTranslation_[0],
-                                 that.touchTranslation_[1], 0);
-        } else if (event.targetTouches.length == 2) {
-          // Exactly 2 fingers inside the canvas => Setup a pinch/zoom
-          that.touchZoom_ = that.GetTouchZoom(event);
+      this.htmlCanvas_.addEventListener('wheel', function(event) {
+        var x = event.pageX - this.offsetLeft;
+        var y = event.pageY - this.offsetTop;
+        that.ViewportMouseWheel(event.deltaY, x, y, event.ctrlKey);
+        event.preventDefault();
+      });
+
+      var that = this;
+      this.htmlCanvas_.addEventListener('touchstart', function(event) {
+        that.ResetTouch();
+      });
+    
+      this.htmlCanvas_.addEventListener('touchend', function(event) {
+        that.ResetTouch();
+      });
+    
+      this.htmlCanvas_.addEventListener('touchmove', function(event) {
+        if (that.touchTranslation_.length == 2) {
+          var t = that.GetTouchTranslation(event);
+          that.ViewportMouseMove(t[0], t[1]);
+        }
+        else if (that.touchZoom_.length == 3) {
           var z0 = that.touchZoom_;
-          that.ViewportMouseDown(2 /* right button */,
-                                 z0[0],
-                                 z0[1], 0);
-        }        
-      }
-    });
-  }  
+          var z1 = that.GetTouchZoom(event);
+          that.ViewportMouseMove(z0[0], z0[1] - z0[2] + z1[2]);
+        }
+        else {
+          // Realize the gesture event
+          if (event.targetTouches.length == 1) {
+            // Exactly one finger inside the canvas => Setup a translation
+            that.touchTranslation_ = that.GetTouchTranslation(event);
+            that.ViewportMouseDown(1 /* middle button */,
+                                  that.touchTranslation_[0],
+                                  that.touchTranslation_[1], 0);
+          } else if (event.targetTouches.length == 2) {
+            // Exactly 2 fingers inside the canvas => Setup a pinch/zoom
+            that.touchZoom_ = that.GetTouchZoom(event);
+            var z0 = that.touchZoom_;
+            that.ViewportMouseDown(2 /* right button */,
+                                  z0[0],
+                                  z0[1], 0);
+          }        
+        }
+      });
+    }  
 
   public ResetTouch() {
-      if (this.touchTranslation_ ||
-          this.touchZoom_) {
-        this.ViewportMouseUp();
-      }
-  
-      this.touchTranslation_ = false;
-      this.touchZoom_ = false;
+    if (this.touchTranslation_ ||
+        this.touchZoom_) {
+      this.ViewportMouseUp();
     }
+
+    this.touchTranslation_ = false;
+    this.touchZoom_ = false;
+  }
   
   public GetTouchTranslation(event) {
-      var touch = event.targetTouches[0];
-      return [
-        touch.pageX,
-        touch.pageY
-      ];
-    }
+    var touch = event.targetTouches[0];
+    return [
+      touch.pageX,
+      touch.pageY
+    ];
+  }
     
   public GetTouchZoom(event) {
-      var touch1 = event.targetTouches[0];
-      var touch2 = event.targetTouches[1];
-      var dx = (touch1.pageX - touch2.pageX);
-      var dy = (touch1.pageY - touch2.pageY);
-      var d = Math.sqrt(dx * dx + dy * dy);
-      return [
-        (touch1.pageX + touch2.pageX) / 2.0,
-        (touch1.pageY + touch2.pageY) / 2.0,
-        d
-      ];
-    }
+    var touch1 = event.targetTouches[0];
+    var touch2 = event.targetTouches[1];
+    var dx = (touch1.pageX - touch2.pageX);
+    var dy = (touch1.pageY - touch2.pageY);
+    var d = Math.sqrt(dx * dx + dy * dy);
+    return [
+      (touch1.pageX + touch2.pageX) / 2.0,
+      (touch1.pageY + touch2.pageY) / 2.0,
+      d
+    ];
+  }
     
-  }
+}
 }
   
\ No newline at end of file