changeset 518:40bb5eb247a5 bgo-commands-codegen

Reverted a couple of files to AM version (wrong changes on my end)
author Benjamin Golinvaux <bgo@osimis.io>
date Tue, 12 Mar 2019 09:19:06 +0100
parents 64ee3033e1ca
children 17106b29ed6d
files Applications/Samples/CMakeLists.txt Applications/Samples/CMakeLists.txt.old Applications/Samples/SingleFrameEditorApplication.h Applications/Samples/build-wasm.sh Applications/Samples/build-wasm.sh.old Applications/Samples/nginx.local.conf
diffstat 6 files changed, 370 insertions(+), 78 deletions(-) [+]
line wrap: on
line diff
--- a/Applications/Samples/CMakeLists.txt	Tue Mar 12 08:51:35 2019 +0100
+++ b/Applications/Samples/CMakeLists.txt	Tue Mar 12 09:19:06 2019 +0100
@@ -1,19 +1,9 @@
-# Usage: see README file
+# Usage (Linux):
+# to build the WASM samples
+# source ~/Downloads/emsdk/emsdk_env.sh && cmake -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=Release -DSTONE_SOURCES_DIR=$currentDir/../../../orthanc-stone -DORTHANC_FRAMEWORK_SOURCE=path -DORTHANC_FRAMEWORK_ROOT=$currentDir/../../../orthanc -DALLOW_DOWNLOADS=ON .. -DENABLE_WASM=ON
+# to build the Qt samples
 
 cmake_minimum_required(VERSION 2.8.3)
-
-# Automatically link Qt executables to qtmain target on Windows
-# ("OLD" == do not link)
-if(POLICY CMP0020)
-  cmake_policy(SET CMP0020 OLD)
-endif()
-
-# Only interpret if() arguments as variables or keywords when unquoted.
-# NEW = do NOT dereference *quoted* variables
-if(POLICY CMP0054)
-  cmake_policy(SET CMP0054 NEW)
-endif()
-
 project(OrthancStone)
 
 include(../../Resources/CMake/OrthancStoneParameters.cmake)
@@ -24,30 +14,39 @@
 set(ENABLE_QT OFF CACHE BOOL "Target Qt Native application")
 set(ENABLE_WASM OFF CACHE BOOL "Target WASM application")
 
-# TODO: replace or compute STONE_SOURCES_DIR from CMAKE_CURRENT_LIST_FILE
-
 if (ENABLE_WASM)
   #####################################################################
   ## Configuration of the Emscripten compiler for WebAssembly target
   #####################################################################
 
-  set(WASM_FLAGS "-s WASM=1 -O0 -g0")
-  message("*****************************************************************************")
-  message("WARNING: optimizations are disabled in emcc!!! Enable them for production use")
-  message("*****************************************************************************")
+  set(WASM_FLAGS "-s WASM=1")
+  set(WASM_FLAGS "${WASM_FLAGS} -s STRICT=1") # drops support for all deprecated build options
+  set(WASM_FLAGS "${WASM_FLAGS} -s FILESYSTEM=1") # if we don't include it, gen_uuid.c fails to build because srand, getpid(), ... are not defined
+  set(WASM_FLAGS "${WASM_FLAGS} -s DISABLE_EXCEPTION_CATCHING=0") # actually enable exception catching 
+  set(WASM_FLAGS "${WASM_FLAGS} -s ERROR_ON_MISSING_LIBRARIES=1")
+
+  if (CMAKE_BUILD_TYPE MATCHES DEBUG)
+    set(WASM_FLAGS "${WASM_FLAGS} -g4") # generate debug information
+    set(WASM_FLAGS "${WASM_FLAGS} -s ASSERTIONS=2") # more runtime checks
+  else()
+    set(WASM_FLAGS "${WASM_FLAGS} -Os") # optimize for web (speed and size)
+  endif()
+
   set(WASM_MODULE_NAME "StoneFrameworkModule" CACHE STRING "Name of the WebAssembly module")
+
   set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WASM_FLAGS}")
   set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WASM_FLAGS}")
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmWebService.js --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmDelayedCallExecutor.js --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/default-library.js  -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'")
 
-  # Handling of memory
-  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1")  # Resize
-  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_MEMORY=536870912")  # 512MB
-  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORT_NAME='\"${WASM_MODULE_NAME}\"' -s ALLOW_MEMORY_GROWTH=1 -s TOTAL_MEMORY=536870912 -s TOTAL_STACK=128000000")  # 512MB + resize
-  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1 -s TOTAL_MEMORY=1073741824")  # 1GB + resize
-
-  # To debug exceptions
-  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s DEMANGLE_SUPPORT=1 -s ASSERTIONS=2")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${WASM_FLAGS}")  # not always clear which flags are for the compiler and which one are for the linker -> pass them all to the linker too
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Applications/Samples/samples-library.js")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmWebService.js")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmDelayedCallExecutor.js")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/default-library.js")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORT_NAME='\"${WASM_MODULE_NAME}\"'")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_MEMORY=536870912")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_STACK=128000000")
 
   add_definitions(-DORTHANC_ENABLE_WASM=1)
   set(ORTHANC_SANDBOXED ON)
@@ -80,10 +79,12 @@
 set(ORTHANC_FRAMEWORK_ARCHIVE "" CACHE STRING "Path to the Orthanc archive, if ORTHANC_FRAMEWORK_SOURCE is \"archive\"")
 set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory, if ORTHANC_FRAMEWORK_SOURCE is \"path\"")
 
+
 #####################################################################
 ## Build a static library containing the Orthanc Stone framework
 #####################################################################
 
+
 LIST(APPEND ORTHANC_BOOST_COMPONENTS program_options)
 
 include(../../Resources/CMake/OrthancStoneConfiguration.cmake)
@@ -145,16 +146,6 @@
     )
   set_target_properties(${Target} PROPERTIES COMPILE_DEFINITIONS ORTHANC_STONE_SAMPLE=${Sample})
   target_link_libraries(${Target} OrthancStone)
-  
-  if (ENABLE_QT AND (CMAKE_SYSTEM_NAME STREQUAL "Windows"))
-    message("(ENABLE_QT and (CMAKE_SYSTEM_NAME matches \"Windows\")) is true")
-    add_custom_command(
-      TARGET ${Target} POST_BUILD
-      COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Core> $<TARGET_FILE_DIR:${Target}>
-      COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Widgets> $<TARGET_FILE_DIR:${Target}>
-      COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Gui> $<TARGET_FILE_DIR:${Target}>
-    )
-  endif()
 endmacro()
 
 #BuildSingleFileSample(OrthancStoneEmpty EmptyApplication.h 1)
@@ -171,12 +162,6 @@
 
 if (ENABLE_QT OR ENABLE_WASM)
 
-      # GenerateCodeFromFlatBufferSchema("${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/ApplicationCommands.fbs")
-
-      list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES ${FLATC_AUTOGENERATED_SOURCES})
-      message(STATUS "SIMPLE_VIEWER_APPLICATION_SOURCES = ${SIMPLE_VIEWER_APPLICATION_SOURCES}")
-      message(STATUS "FLATC_AUTOGENERATED_SOURCES = ${FLATC_AUTOGENERATED_SOURCES}")
-
     if (ENABLE_QT)
       list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES
         ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/CMakeLists.txt.old	Tue Mar 12 09:19:06 2019 +0100
@@ -0,0 +1,248 @@
+# Usage: see README file
+
+cmake_minimum_required(VERSION 2.8.3)
+
+# Automatically link Qt executables to qtmain target on Windows
+# ("OLD" == do not link)
+if(POLICY CMP0020)
+  cmake_policy(SET CMP0020 OLD)
+endif()
+
+# Only interpret if() arguments as variables or keywords when unquoted.
+# NEW = do NOT dereference *quoted* variables
+if(POLICY CMP0054)
+  cmake_policy(SET CMP0054 NEW)
+endif()
+
+project(OrthancStone)
+
+include(../../Resources/CMake/OrthancStoneParameters.cmake)
+
+#set(ENABLE_DCMTK ON)
+
+set(ENABLE_SDL OFF CACHE BOOL "Target SDL Native application")
+set(ENABLE_QT OFF CACHE BOOL "Target Qt Native application")
+set(ENABLE_WASM OFF CACHE BOOL "Target WASM application")
+
+# TODO: replace or compute STONE_SOURCES_DIR from CMAKE_CURRENT_LIST_FILE
+
+if (ENABLE_WASM)
+  #####################################################################
+  ## Configuration of the Emscripten compiler for WebAssembly target
+  #####################################################################
+
+  set(WASM_FLAGS "-s WASM=1 -O0 -g0")
+  message("*****************************************************************************")
+  message("WARNING: optimizations are disabled in emcc!!! Enable them for production use")
+  message("*****************************************************************************")
+  set(WASM_MODULE_NAME "StoneFrameworkModule" CACHE STRING "Name of the WebAssembly module")
+  set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${WASM_FLAGS}")
+  set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${WASM_FLAGS}")
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmWebService.js --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/WasmDelayedCallExecutor.js --js-library ${STONE_SOURCES_DIR}/Platforms/Wasm/default-library.js  -s EXTRA_EXPORTED_RUNTIME_METHODS='[\"ccall\", \"cwrap\"]'")
+
+  # Handling of memory
+  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1")  # Resize
+  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s TOTAL_MEMORY=536870912")  # 512MB
+  set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s EXPORT_NAME='\"${WASM_MODULE_NAME}\"' -s ALLOW_MEMORY_GROWTH=1 -s TOTAL_MEMORY=536870912 -s TOTAL_STACK=128000000")  # 512MB + resize
+  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s ALLOW_MEMORY_GROWTH=1 -s TOTAL_MEMORY=1073741824")  # 1GB + resize
+
+  # To debug exceptions
+  #set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -s DEMANGLE_SUPPORT=1 -s ASSERTIONS=2")
+
+  add_definitions(-DORTHANC_ENABLE_WASM=1)
+  set(ORTHANC_SANDBOXED ON)
+
+elseif (ENABLE_QT OR ENABLE_SDL)
+
+  set(ENABLE_NATIVE ON)
+  set(ORTHANC_SANDBOXED OFF)
+  set(ENABLE_CRYPTO_OPTIONS ON)
+  set(ENABLE_GOOGLE_TEST ON)
+  set(ENABLE_WEB_CLIENT ON)
+
+endif()
+
+#####################################################################
+## Configuration for Orthanc
+#####################################################################
+
+# include(../../Resources/CMake/Version.cmake)
+
+if (ORTHANC_STONE_VERSION STREQUAL "mainline")
+  set(ORTHANC_FRAMEWORK_VERSION "mainline")
+  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "hg")
+else()
+  set(ORTHANC_FRAMEWORK_VERSION "1.4.1")
+  set(ORTHANC_FRAMEWORK_DEFAULT_SOURCE "web")
+endif()
+
+set(ORTHANC_FRAMEWORK_SOURCE "${ORTHANC_FRAMEWORK_DEFAULT_SOURCE}" CACHE STRING "Source of the Orthanc source code (can be \"hg\", \"archive\", \"web\" or \"path\")")
+set(ORTHANC_FRAMEWORK_ARCHIVE "" CACHE STRING "Path to the Orthanc archive, if ORTHANC_FRAMEWORK_SOURCE is \"archive\"")
+set(ORTHANC_FRAMEWORK_ROOT "" CACHE STRING "Path to the Orthanc source directory, if ORTHANC_FRAMEWORK_SOURCE is \"path\"")
+
+#####################################################################
+## Build a static library containing the Orthanc Stone framework
+#####################################################################
+
+LIST(APPEND ORTHANC_BOOST_COMPONENTS program_options)
+
+include(../../Resources/CMake/OrthancStoneConfiguration.cmake)
+
+add_library(OrthancStone STATIC
+  ${ORTHANC_STONE_SOURCES}
+  )
+
+#####################################################################
+## Build all the sample applications
+#####################################################################
+
+include_directories(${ORTHANC_STONE_ROOT})
+
+# files common to all samples
+list(APPEND SAMPLE_APPLICATIONS_SOURCES
+  ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleInteractor.h
+  ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleApplicationBase.h
+  )
+
+if (ENABLE_QT)
+  list(APPEND SAMPLE_APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleQtApplicationRunner.h
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.cpp
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.cpp
+    )
+
+  ORTHANC_QT_WRAP_UI(SAMPLE_APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.ui
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.ui
+    )
+
+  ORTHANC_QT_WRAP_CPP(SAMPLE_APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Qt/QCairoWidget.h
+    ${ORTHANC_STONE_ROOT}/Applications/Qt/QStoneMainWindow.h
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindow.h
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/Qt/SampleMainWindowWithButtons.h
+    )
+endif()
+
+if (ENABLE_NATIVE)
+  list(APPEND SAMPLE_APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleMainNative.cpp
+    )
+
+elseif (ENABLE_WASM)
+
+  list(APPEND SAMPLE_APPLICATIONS_SOURCES
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleMainWasm.cpp
+    ${STONE_WASM_SOURCES}
+    )
+endif()
+
+
+macro(BuildSingleFileSample Target Header Sample)
+  add_executable(${Target}
+    ${ORTHANC_STONE_ROOT}/Applications/Samples/${Header}
+    ${SAMPLE_APPLICATIONS_SOURCES}
+    )
+  set_target_properties(${Target} PROPERTIES COMPILE_DEFINITIONS ORTHANC_STONE_SAMPLE=${Sample})
+  target_link_libraries(${Target} OrthancStone)
+  
+  if (ENABLE_QT AND (CMAKE_SYSTEM_NAME STREQUAL "Windows"))
+    message("(ENABLE_QT and (CMAKE_SYSTEM_NAME matches \"Windows\")) is true")
+    add_custom_command(
+      TARGET ${Target} POST_BUILD
+      COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Core> $<TARGET_FILE_DIR:${Target}>
+      COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Widgets> $<TARGET_FILE_DIR:${Target}>
+      COMMAND ${CMAKE_COMMAND} -E copy_if_different $<TARGET_FILE:Qt5::Gui> $<TARGET_FILE_DIR:${Target}>
+    )
+  endif()
+endmacro()
+
+#BuildSingleFileSample(OrthancStoneEmpty EmptyApplication.h 1)
+#BuildSingleFileSample(OrthancStoneTestPattern TestPatternApplication.h 2)
+BuildSingleFileSample(OrthancStoneSingleFrame SingleFrameApplication.h 3)
+#BuildSingleFileSample(OrthancStoneSingleVolume SingleVolumeApplication.h 4)
+#BuildSingleFileSample(OrthancStoneBasicPetCtFusion 5)
+#BuildSingleFileSample(OrthancStoneSynchronizedSeries 6)
+#BuildSingleFileSample(OrthancStoneLayoutPetCtFusion 7)
+BuildSingleFileSample(OrthancStoneSimpleViewerSingleFile SimpleViewerApplicationSingleFile.h 8)  # we keep that one just as a sample before we convert another sample to this pattern
+BuildSingleFileSample(OrthancStoneSingleFrameEditor SingleFrameEditorApplication.h 9)
+
+##### SimpleViewer sample (Qt and WASM only) #######
+
+if (ENABLE_QT OR ENABLE_WASM)
+
+      # GenerateCodeFromFlatBufferSchema("${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/ApplicationCommands.fbs")
+
+      list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES ${FLATC_AUTOGENERATED_SOURCES})
+      message(STATUS "SIMPLE_VIEWER_APPLICATION_SOURCES = ${SIMPLE_VIEWER_APPLICATION_SOURCES}")
+      message(STATUS "FLATC_AUTOGENERATED_SOURCES = ${FLATC_AUTOGENERATED_SOURCES}")
+
+    if (ENABLE_QT)
+      list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.cpp
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.ui
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/mainQt.cpp
+        )
+
+      ORTHANC_QT_WRAP_UI(SIMPLE_VIEWER_APPLICATION_SOURCES
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.ui
+        )
+
+      ORTHANC_QT_WRAP_CPP(SIMPLE_VIEWER_APPLICATION_SOURCES
+        ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Qt/SimpleViewerMainWindow.h
+        )
+
+elseif (ENABLE_WASM)
+        list(APPEND SIMPLE_VIEWER_APPLICATION_SOURCES
+            ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Wasm/mainWasm.cpp
+            ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Wasm/SimpleViewerWasmApplicationAdapter.cpp
+            ${STONE_WASM_SOURCES}
+          )
+    endif()
+
+    add_executable(OrthancStoneSimpleViewer
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/SimpleViewerApplication.cpp
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/ThumbnailInteractor.cpp
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/MainWidgetInteractor.cpp
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/AppStatus.h
+      ${ORTHANC_STONE_ROOT}/Applications/Samples/SimpleViewer/Messages.h
+      ${SIMPLE_VIEWER_APPLICATION_SOURCES}
+      )
+    target_link_libraries(OrthancStoneSimpleViewer OrthancStone)
+
+endif()
+
+#####################################################################
+## Build the unit tests
+#####################################################################
+
+if (ENABLE_NATIVE)
+  add_executable(UnitTests
+    ${GOOGLE_TEST_SOURCES}
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestCommands.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestExceptions.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestMessageBroker.cpp
+    ${ORTHANC_STONE_ROOT}/UnitTestsSources/UnitTestsMain.cpp
+    )
+
+  target_link_libraries(UnitTests OrthancStone)
+endif()
+
+#####################################################################
+## Generate the documentation if Doxygen is present
+#####################################################################
+
+find_package(Doxygen)
+if (DOXYGEN_FOUND)
+  configure_file(
+    ${ORTHANC_STONE_ROOT}/Resources/OrthancStone.doxygen
+    ${CMAKE_CURRENT_BINARY_DIR}/OrthancStone.doxygen
+    @ONLY)
+
+  add_custom_target(doc
+    ${DOXYGEN_EXECUTABLE} ${CMAKE_CURRENT_BINARY_DIR}/OrthancStone.doxygen
+    COMMENT "Generating documentation with Doxygen" VERBATIM
+    )
+else()
+  message("Doxygen not found. The documentation will not be built.")
+endif()
--- a/Applications/Samples/SingleFrameEditorApplication.h	Tue Mar 12 08:51:35 2019 +0100
+++ b/Applications/Samples/SingleFrameEditorApplication.h	Tue Mar 12 09:19:06 2019 +0100
@@ -24,6 +24,7 @@
 #include "SampleApplicationBase.h"
 
 #include "../../Framework/Radiography/RadiographyLayerCropTracker.h"
+#include "../../Framework/Radiography/RadiographyLayerMaskTracker.h"
 #include "../../Framework/Radiography/RadiographyLayerMoveTracker.h"
 #include "../../Framework/Radiography/RadiographyLayerResizeTracker.h"
 #include "../../Framework/Radiography/RadiographyLayerRotateTracker.h"
@@ -33,6 +34,7 @@
 #include "../../Framework/Radiography/RadiographyWindowingTracker.h"
 #include "../../Framework/Radiography/RadiographySceneWriter.h"
 #include "../../Framework/Radiography/RadiographySceneReader.h"
+#include "../../Framework/Radiography/RadiographyMaskLayer.h"
 
 #include <Core/HttpClient.h>
 #include <Core/Images/FontRegistry.h>
@@ -60,6 +62,7 @@
         Tool_Rotate,
         Tool_Crop,
         Tool_Resize,
+        Tool_Mask,
         Tool_Windowing
       };
 
@@ -67,6 +70,7 @@
       StoneApplicationContext*  context_;
       UndoRedoStack             undoRedoStack_;
       Tool                      tool_;
+      RadiographyMaskLayer*     maskLayer_;
 
 
       static double GetHandleSize()
@@ -79,7 +83,8 @@
       RadiographyEditorInteractor(MessageBroker& broker) :
         IObserver(broker),
         context_(NULL),
-        tool_(Tool_Move)
+        tool_(Tool_Move),
+        maskLayer_(NULL)
       {
       }
 
@@ -88,6 +93,10 @@
         context_ = &context;
       }
 
+      void SetMaskLayer(RadiographyMaskLayer* maskLayer)
+      {
+        maskLayer_ = maskLayer;
+      }
       virtual IWorldSceneMouseTracker* CreateMouseTracker(WorldSceneWidget& worldWidget,
                                                           const ViewportGeometry& view,
                                                           MouseButton button,
@@ -96,7 +105,8 @@
                                                           int viewportY,
                                                           double x,
                                                           double y,
-                                                          IStatusBar* statusBar)
+                                                          IStatusBar* statusBar,
+                                                          const std::vector<Touch>& displayTouches)
       {
         RadiographyWidget& widget = dynamic_cast<RadiographyWidget&>(worldWidget);
 
@@ -126,22 +136,27 @@
             return NULL;
           }
           else if (tool_ == Tool_Crop ||
-                   tool_ == Tool_Resize)
+                   tool_ == Tool_Resize ||
+                   tool_ == Tool_Mask)
           {
             RadiographyScene::LayerAccessor accessor(widget.GetScene(), selected);
             
-            ControlPoint corner;
-            if (accessor.GetLayer().LookupControlPoint(corner, x, y, view.GetZoom(), GetHandleSize()))
+            ControlPoint controlPoint;
+            if (accessor.GetLayer().LookupControlPoint(controlPoint, x, y, view.GetZoom(), GetHandleSize()))
             {
               switch (tool_)
               {
               case Tool_Crop:
                 return new RadiographyLayerCropTracker
-                    (undoRedoStack_, widget.GetScene(), view, selected, x, y, corner);
+                    (undoRedoStack_, widget.GetScene(), view, selected, controlPoint);
+
+              case Tool_Mask:
+                return new RadiographyLayerMaskTracker
+                    (undoRedoStack_, widget.GetScene(), view, selected, controlPoint);
 
               case Tool_Resize:
                 return new RadiographyLayerResizeTracker
-                    (undoRedoStack_, widget.GetScene(), selected, x, y, corner,
+                    (undoRedoStack_, widget.GetScene(), selected, controlPoint,
                      (modifiers & KeyboardModifiers_Shift));
 
               default:
@@ -207,6 +222,7 @@
         {
           return NULL;
         }
+        return NULL;
       }
 
       virtual void MouseOver(CairoContext& context,
@@ -231,25 +247,24 @@
 
         if (widget.LookupSelectedLayer(selected) &&
             (tool_ == Tool_Crop ||
-             tool_ == Tool_Resize))
+             tool_ == Tool_Resize ||
+             tool_ == Tool_Mask))
         {
           RadiographyScene::LayerAccessor accessor(widget.GetScene(), selected);
 
-          Corner corner;
-          if (accessor.GetLayer().LookupCorner(corner, x, y, view.GetZoom(), GetHandleSize()))
+          ControlPoint controlPoint;
+          if (accessor.GetLayer().LookupControlPoint(controlPoint, x, y, view.GetZoom(), GetHandleSize()))
           {
-            accessor.GetLayer().GetCorner(x, y, corner);
-
             double z = 1.0 / view.GetZoom();
 
             context.SetSourceColor(255, 0, 0);
             cairo_t* cr = context.GetObject();
             cairo_set_line_width(cr, 2.0 * z);
-            cairo_move_to(cr, x - GetHandleSize() * z, y - GetHandleSize() * z);
-            cairo_line_to(cr, x + GetHandleSize() * z, y - GetHandleSize() * z);
-            cairo_line_to(cr, x + GetHandleSize() * z, y + GetHandleSize() * z);
-            cairo_line_to(cr, x - GetHandleSize() * z, y + GetHandleSize() * z);
-            cairo_line_to(cr, x - GetHandleSize() * z, y - GetHandleSize() * z);
+            cairo_move_to(cr, controlPoint.x - GetHandleSize() * z, controlPoint.y - GetHandleSize() * z);
+            cairo_line_to(cr, controlPoint.x + GetHandleSize() * z, controlPoint.y - GetHandleSize() * z);
+            cairo_line_to(cr, controlPoint.x + GetHandleSize() * z, controlPoint.y + GetHandleSize() * z);
+            cairo_line_to(cr, controlPoint.x - GetHandleSize() * z, controlPoint.y + GetHandleSize() * z);
+            cairo_line_to(cr, controlPoint.x - GetHandleSize() * z, controlPoint.y - GetHandleSize() * z);
             cairo_stroke(cr);
           }
         }
@@ -280,6 +295,11 @@
           tool_ = Tool_Crop;
           break;
 
+        case 'm':
+          tool_ = Tool_Mask;
+          widget.Select(1);
+          break;
+
         case 'd':
         {
           // dump to json and reload
@@ -338,7 +358,7 @@
           widget.SwitchInvert();
           break;
 
-        case 'm':
+        case 't':
           tool_ = Tool_Move;
           break;
 
@@ -407,6 +427,7 @@
       boost::shared_ptr<RadiographyScene>   scene_;
       RadiographyEditorInteractor           interactor_;
       Orthanc::FontRegistry                 fontRegistry_;
+      RadiographyMaskLayer*                 maskLayer_;
 
     public:
       SingleFrameEditorApplication(MessageBroker& broker) :
@@ -447,10 +468,11 @@
         statusBar.SetMessage("Use the key \"e\" to export DICOM to the Orthanc server");
         statusBar.SetMessage("Use the key \"f\" to switch full screen");
         statusBar.SetMessage("Use the key \"i\" to invert contrast");
-        statusBar.SetMessage("Use the key \"m\" to move objects");
+        statusBar.SetMessage("Use the key \"m\" to modify the mask");
         statusBar.SetMessage("Use the key \"n\" to switch between nearest neighbor and bilinear interpolation");
         statusBar.SetMessage("Use the key \"r\" to rotate objects");
         statusBar.SetMessage("Use the key \"s\" to resize objects (not applicable to DICOM layers)");
+        statusBar.SetMessage("Use the key \"t\" to move (translate) objects");
         statusBar.SetMessage("Use the key \"w\" to change windowing");
         
         statusBar.SetMessage("Use the key \"ctrl-z\" to undo action");
@@ -468,7 +490,8 @@
         fontRegistry_.AddFromResource(Orthanc::EmbeddedResources::FONT_UBUNTU_MONO_BOLD_16);
         
         scene_.reset(new RadiographyScene(GetBroker()));
-        scene_->LoadDicomFrame(context->GetOrthancApiClient(), instance, 0, false, NULL);
+        //scene_->LoadDicomFrame(instance, frame, false); //.SetPan(200, 0);
+        RadiographyLayer& dicomLayer = scene_->LoadDicomFrame(context->GetOrthancApiClient(), "61f3143e-96f34791-ad6bbb8d-62559e75-45943e1b", 0, false, NULL);
 
 #if !defined(ORTHANC_ENABLE_WASM) || ORTHANC_ENABLE_WASM != 1
         Orthanc::HttpClient::ConfigureSsl(true, "/etc/ssl/certs/ca-certificates.crt");
@@ -476,6 +499,15 @@
         
         //scene_->LoadDicomWebFrame(context->GetWebService());
         
+        std::vector<Orthanc::ImageProcessing::ImagePoint> mask;
+        mask.push_back(Orthanc::ImageProcessing::ImagePoint(1100, 100));
+        mask.push_back(Orthanc::ImageProcessing::ImagePoint(1100, 1000));
+        mask.push_back(Orthanc::ImageProcessing::ImagePoint(2000, 1000));
+        mask.push_back(Orthanc::ImageProcessing::ImagePoint(2200, 150));
+        mask.push_back(Orthanc::ImageProcessing::ImagePoint(1500, 550));
+        maskLayer_ = dynamic_cast<RadiographyMaskLayer*>(&(scene_->LoadMask(mask, dynamic_cast<RadiographyDicomLayer&>(dicomLayer), 128.0f, NULL)));
+        interactor_.SetMaskLayer(maskLayer_);
+
         {
           RadiographyLayer& layer = scene_->LoadText(fontRegistry_.GetFont(0), "Hello\nworld", NULL);
           layer.SetResizeable(true);
--- a/Applications/Samples/build-wasm.sh	Tue Mar 12 08:51:35 2019 +0100
+++ b/Applications/Samples/build-wasm.sh	Tue Mar 12 09:19:06 2019 +0100
@@ -1,15 +1,16 @@
 #!/bin/bash
 #
 # usage:
-# to build all targets:
+# to build all targets in Debug:
 # ./build-wasm.sh
 #
-# to build a single target:
-# ./build-wasm.sh OrthancStoneSingleFrameEditor
+# to build a single target in release:
+# ./build-wasm.sh OrthancStoneSingleFrameEditor Release
 
 set -e
 
 target=${1:-all}
+buildType=${2:-Debug}
 
 currentDir=$(pwd)
 samplesRootDir=$(pwd)
@@ -18,16 +19,9 @@
 cd $samplesRootDir/build-wasm
 
 source ~/apps/emsdk/emsdk_env.sh
-cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake \
-  -DCMAKE_BUILD_TYPE=Release \
-  -DSTONE_SOURCES_DIR=$currentDir/../../../orthanc-stone \
-  -DORTHANC_FRAMEWORK_SOURCE=path \
-  -DORTHANC_FRAMEWORK_ROOT=$currentDir/../../../orthanc \
-  -DALLOW_DOWNLOADS=ON .. \
-  -DENABLE_WASM=ON
-
+cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake -DCMAKE_BUILD_TYPE=$buildType -DSTONE_SOURCES_DIR=$currentDir/../../../orthanc-stone -DORTHANC_FRAMEWORK_SOURCE=path -DORTHANC_FRAMEWORK_ROOT=$currentDir/../../../orthanc -DALLOW_DOWNLOADS=ON .. -DENABLE_WASM=ON
 ninja $target
 
 echo "-- building the web application -- "
 cd $currentDir
-./build-web.sh
+./build-web.sh
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Applications/Samples/build-wasm.sh.old	Tue Mar 12 09:19:06 2019 +0100
@@ -0,0 +1,33 @@
+#!/bin/bash
+#
+# usage:
+# to build all targets:
+# ./build-wasm.sh
+#
+# to build a single target:
+# ./build-wasm.sh OrthancStoneSingleFrameEditor
+
+set -e
+
+target=${1:-all}
+
+currentDir=$(pwd)
+samplesRootDir=$(pwd)
+
+mkdir -p $samplesRootDir/build-wasm
+cd $samplesRootDir/build-wasm
+
+source ~/apps/emsdk/emsdk_env.sh
+cmake -G Ninja -DCMAKE_TOOLCHAIN_FILE=${EMSCRIPTEN}/cmake/Modules/Platform/Emscripten.cmake \
+  -DCMAKE_BUILD_TYPE=Release \
+  -DSTONE_SOURCES_DIR=$currentDir/../../../orthanc-stone \
+  -DORTHANC_FRAMEWORK_SOURCE=path \
+  -DORTHANC_FRAMEWORK_ROOT=$currentDir/../../../orthanc \
+  -DALLOW_DOWNLOADS=ON .. \
+  -DENABLE_WASM=ON
+
+ninja $target
+
+echo "-- building the web application -- "
+cd $currentDir
+./build-web.sh
--- a/Applications/Samples/nginx.local.conf	Tue Mar 12 08:51:35 2019 +0100
+++ b/Applications/Samples/nginx.local.conf	Tue Mar 12 09:19:06 2019 +0100
@@ -30,7 +30,7 @@
     # reverse proxy orthanc
 	location /orthanc/ {
 		rewrite /orthanc(.*) $1 break;
-		proxy_pass http://127.0.0.1:8044;
+		proxy_pass http://127.0.0.1:8042;
 		proxy_set_header Host $http_host;
 		proxy_set_header my-auth-header good-token;
 		proxy_request_buffering off;