# HG changeset patch # User am@osimis.io # Date 1528718462 -7200 # Node ID d7b2590744f88bcec5f2d25c6b22ba450b8b74b2 # Parent 26e3bfe30e663426e9fd61549c88d326a8bcd36b wip: building applications reusable in SDL and WASM diff -r 26e3bfe30e66 -r d7b2590744f8 Applications/BasicApplication.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/BasicApplication.cpp Mon Jun 11 14:01:02 2018 +0200 @@ -0,0 +1,291 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "IBasicApplication.h" + +#include "../Framework/Toolbox/MessagingToolbox.h" +#include "Sdl/SdlEngine.h" + +#include +#include +#include + +namespace OrthancStone +{ + // Anonymous namespace to avoid clashes against other compilation modules + namespace + { + class LogStatusBar : public IStatusBar + { + public: + virtual void ClearMessage() + { + } + + virtual void SetMessage(const std::string& message) + { + LOG(WARNING) << message; + } + }; + } + + +#if ORTHANC_ENABLE_SDL == 1 + static void DeclareSdlCommandLineOptions(boost::program_options::options_description& options) + { + // Declare the supported parameters + boost::program_options::options_description generic("Generic options"); + generic.add_options() + ("help", "Display this help and exit") + ("verbose", "Be verbose in logs") + ("orthanc", boost::program_options::value()->default_value("http://localhost:8042/"), + "URL to the Orthanc server") + ("username", "Username for the Orthanc server") + ("password", "Password for the Orthanc server") + ("https-verify", boost::program_options::value()->default_value(true), "Check HTTPS certificates") + ; + + options.add(generic); + + boost::program_options::options_description sdl("SDL options"); + sdl.add_options() + ("width", boost::program_options::value()->default_value(1024), "Initial width of the SDL window") + ("height", boost::program_options::value()->default_value(768), "Initial height of the SDL window") + ("opengl", boost::program_options::value()->default_value(true), "Enable OpenGL in SDL") + ; + + options.add(sdl); + } + + + int IBasicApplication::ExecuteWithSdl(IBasicApplication& application, + int argc, + char* argv[]) + { + /****************************************************************** + * Initialize all the subcomponents of Orthanc Stone + ******************************************************************/ + + Orthanc::Logging::Initialize(); + Orthanc::HttpClient::InitializeOpenSsl(); + Orthanc::HttpClient::GlobalInitialize(); + SdlWindow::GlobalInitialize(); + + + /****************************************************************** + * Declare and parse the command-line options of the application + ******************************************************************/ + + boost::program_options::options_description options; + DeclareSdlCommandLineOptions(options); + application.DeclareCommandLineOptions(options); + + boost::program_options::variables_map parameters; + bool error = false; + + try + { + boost::program_options::store(boost::program_options::command_line_parser(argc, argv). + options(options).run(), parameters); + boost::program_options::notify(parameters); + } + catch (boost::program_options::error& e) + { + LOG(ERROR) << "Error while parsing the command-line arguments: " << e.what(); + error = true; + } + + + /****************************************************************** + * Configure the application with the command-line parameters + ******************************************************************/ + + if (error || parameters.count("help")) + { + std::cout << std::endl + << "Usage: " << argv[0] << " [OPTION]..." + << std::endl + << "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research." + << std::endl << std::endl + << "Demonstration application of Orthanc Stone using SDL." + << std::endl; + + std::cout << options << "\n"; + return error ? -1 : 0; + } + + if (parameters.count("https-verify") && + !parameters["https-verify"].as()) + { + LOG(WARNING) << "Turning off verification of HTTPS certificates (unsafe)"; + Orthanc::HttpClient::ConfigureSsl(false, ""); + } + + if (parameters.count("verbose")) + { + Orthanc::Logging::EnableInfoLevel(true); + } + + if (!parameters.count("width") || + !parameters.count("height") || + !parameters.count("opengl")) + { + LOG(ERROR) << "Parameter \"width\", \"height\" or \"opengl\" is missing"; + return -1; + } + + int w = parameters["width"].as(); + int h = parameters["height"].as(); + if (w <= 0 || h <= 0) + { + LOG(ERROR) << "Parameters \"width\" and \"height\" must be positive"; + return -1; + } + + unsigned int width = static_cast(w); + unsigned int height = static_cast(h); + LOG(WARNING) << "Initial display size: " << width << "x" << height; + + bool opengl = parameters["opengl"].as(); + if (opengl) + { + LOG(WARNING) << "OpenGL is enabled, disable it with option \"--opengl=off\" if the application crashes"; + } + else + { + LOG(WARNING) << "OpenGL is disabled, enable it with option \"--opengl=on\" for best performance"; + } + + bool success = true; + try + { + /**************************************************************** + * Initialize the connection to the Orthanc server + ****************************************************************/ + + Orthanc::WebServiceParameters webService; + + if (parameters.count("orthanc")) + { + webService.SetUrl(parameters["orthanc"].as()); + } + + if (parameters.count("username")) + { + webService.SetUsername(parameters["username"].as()); + } + + if (parameters.count("password")) + { + webService.SetPassword(parameters["password"].as()); + } + + LOG(WARNING) << "URL to the Orthanc REST API: " << webService.GetUrl(); + + { + OrthancPlugins::OrthancHttpConnection orthanc(webService); + if (!MessagingToolbox::CheckOrthancVersion(orthanc)) + { + LOG(ERROR) << "Your version of Orthanc is incompatible with Stone of Orthanc, please upgrade"; + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } + } + + + /**************************************************************** + * Initialize the application + ****************************************************************/ + + LOG(WARNING) << "Creating the widgets of the application"; + + LogStatusBar statusBar; + BasicApplicationContext context(webService); + + application.Initialize(context, statusBar, parameters); + + { + BasicApplicationContext::ViewportLocker locker(context); + locker.GetViewport().SetStatusBar(statusBar); + } + + std::string title = application.GetTitle(); + if (title.empty()) + { + title = "Stone of Orthanc"; + } + + { + /************************************************************** + * Run the application inside a SDL window + **************************************************************/ + + LOG(WARNING) << "Starting the application"; + + SdlWindow window(title.c_str(), width, height, opengl); + SdlEngine sdl(window, context); + + { + BasicApplicationContext::ViewportLocker locker(context); + locker.GetViewport().Register(sdl); // (*) + } + + context.Start(); + sdl.Run(); + + LOG(WARNING) << "Stopping the application"; + + // Don't move the "Stop()" command below out of the block, + // otherwise the application might crash, because the + // "SdlEngine" is an observer of the viewport (*) and the + // update thread started by "context.Start()" would call a + // destructed object (the "SdlEngine" is deleted with the + // lexical scope). + context.Stop(); + } + + + /**************************************************************** + * Finalize the application + ****************************************************************/ + + LOG(WARNING) << "The application has stopped"; + application.Finalize(); + } + catch (Orthanc::OrthancException& e) + { + LOG(ERROR) << "EXCEPTION: " << e.What(); + success = false; + } + + + /****************************************************************** + * Finalize all the subcomponents of Orthanc Stone + ******************************************************************/ + + SdlWindow::GlobalFinalize(); + Orthanc::HttpClient::GlobalFinalize(); + Orthanc::HttpClient::FinalizeOpenSsl(); + + return (success ? 0 : -1); + } +#endif + +} diff -r 26e3bfe30e66 -r d7b2590744f8 Applications/BasicApplication.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/BasicApplication.h Mon Jun 11 14:01:02 2018 +0200 @@ -0,0 +1,68 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "BasicApplicationContext.h" + +#include + +#if ORTHANC_ENABLE_SDL == 1 +# include // Necessary to avoid undefined reference to `SDL_main' +#endif + +namespace OrthancStone +{ + class IBasicApplication : public boost::noncopyable + { + public: + virtual ~IBasicApplication() + { + } + + virtual void DeclareStartupOption(const std::string& name, const std::string& defaultValue, const std::string& helpText) = 0; + virtual void Initialize(IStatusBar& statusBar, const std::map startupOptions); + + + virtual void DeclareCommandLineOptions(boost::program_options::options_description& options) = 0; + + virtual std::string GetTitle() const = 0; + + virtual void Initialize(BasicApplicationContext& context, + IStatusBar& statusBar, + const boost::program_options::variables_map& parameters) = 0; + + virtual void Finalize() = 0; + +#if ORTHANC_ENABLE_SDL == 1 + static int ExecuteWithSdl(IBasicApplication& application, + int argc, + char* argv[]); +#endif + }; + + class IBasicSdlApplication : public IBasicApplication + { + public: + + + } +} diff -r 26e3bfe30e66 -r d7b2590744f8 Applications/BasicApplicationContext.cpp --- a/Applications/BasicApplicationContext.cpp Fri Jun 08 14:41:45 2018 +0200 +++ b/Applications/BasicApplicationContext.cpp Mon Jun 11 14:01:02 2018 +0200 @@ -48,81 +48,18 @@ } - BasicApplicationContext::~BasicApplicationContext() - { - for (Interactors::iterator it = interactors_.begin(); it != interactors_.end(); ++it) - { - assert(*it != NULL); - delete *it; - } - - for (SlicedVolumes::iterator it = slicedVolumes_.begin(); it != slicedVolumes_.end(); ++it) - { - assert(*it != NULL); - delete *it; - } - - for (VolumeLoaders::iterator it = volumeLoaders_.begin(); it != volumeLoaders_.end(); ++it) - { - assert(*it != NULL); - delete *it; - } - } - - IWidget& BasicApplicationContext::SetCentralWidget(IWidget* widget) // Takes ownership { - viewport_.SetCentralWidget(widget); + centralViewport_.SetCentralWidget(widget); return *widget; } - ISlicedVolume& BasicApplicationContext::AddSlicedVolume(ISlicedVolume* volume) - { - if (volume == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - else - { - slicedVolumes_.push_back(volume); - return *volume; - } - } - - - IVolumeLoader& BasicApplicationContext::AddVolumeLoader(IVolumeLoader* loader) - { - if (loader == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - else - { - volumeLoaders_.push_back(loader); - return *loader; - } - } - - - IWorldSceneInteractor& BasicApplicationContext::AddInteractor(IWorldSceneInteractor* interactor) - { - if (interactor == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); - } - - interactors_.push_back(interactor); - - return *interactor; - } - - void BasicApplicationContext::Start() { oracle_.Start(); - if (viewport_.HasUpdateContent()) + if (centralViewport_.HasUpdateContent()) { stopped_ = false; updateThread_ = boost::thread(UpdateThread, this); diff -r 26e3bfe30e66 -r d7b2590744f8 Applications/BasicApplicationContext.h --- a/Applications/BasicApplicationContext.h Fri Jun 08 14:41:45 2018 +0200 +++ b/Applications/BasicApplicationContext.h Mon Jun 11 14:01:02 2018 +0200 @@ -35,19 +35,14 @@ class BasicApplicationContext : public boost::noncopyable { private: - typedef std::list SlicedVolumes; - typedef std::list VolumeLoaders; - typedef std::list Interactors; static void UpdateThread(BasicApplicationContext* that); + Oracle oracle_; OracleWebService webService_; boost::mutex viewportMutex_; - WidgetViewport viewport_; - SlicedVolumes slicedVolumes_; - VolumeLoaders volumeLoaders_; - Interactors interactors_; + WidgetViewport centralViewport_; boost::thread updateThread_; bool stopped_; unsigned int updateDelay_; @@ -62,7 +57,7 @@ public: ViewportLocker(BasicApplicationContext& that) : lock_(that.viewportMutex_), - viewport_(that.viewport_) + viewport_(that.centralViewport_) { } @@ -75,7 +70,7 @@ BasicApplicationContext(Orthanc::WebServiceParameters& orthanc); - ~BasicApplicationContext(); + virtual ~BasicApplicationContext() {} IWidget& SetCentralWidget(IWidget* widget); // Takes ownership @@ -84,12 +79,6 @@ return webService_; } - ISlicedVolume& AddSlicedVolume(ISlicedVolume* volume); - - IVolumeLoader& AddVolumeLoader(IVolumeLoader* loader); - - IWorldSceneInteractor& AddInteractor(IWorldSceneInteractor* interactor); - void Start(); void Stop(); diff -r 26e3bfe30e66 -r d7b2590744f8 Applications/IBasicApplication.cpp --- a/Applications/IBasicApplication.cpp Fri Jun 08 14:41:45 2018 +0200 +++ b/Applications/IBasicApplication.cpp Mon Jun 11 14:01:02 2018 +0200 @@ -30,262 +30,34 @@ namespace OrthancStone { - // Anonymous namespace to avoid clashes against other compilation modules - namespace - { - class LogStatusBar : public IStatusBar - { - public: - virtual void ClearMessage() - { - } - - virtual void SetMessage(const std::string& message) - { - LOG(WARNING) << message; - } - }; - } - - -#if ORTHANC_ENABLE_SDL == 1 - static void DeclareSdlCommandLineOptions(boost::program_options::options_description& options) - { - // Declare the supported parameters - boost::program_options::options_description generic("Generic options"); - generic.add_options() - ("help", "Display this help and exit") - ("verbose", "Be verbose in logs") - ("orthanc", boost::program_options::value()->default_value("http://localhost:8042/"), - "URL to the Orthanc server") - ("username", "Username for the Orthanc server") - ("password", "Password for the Orthanc server") - ("https-verify", boost::program_options::value()->default_value(true), "Check HTTPS certificates") - ; - - options.add(generic); - - boost::program_options::options_description sdl("SDL options"); - sdl.add_options() - ("width", boost::program_options::value()->default_value(1024), "Initial width of the SDL window") - ("height", boost::program_options::value()->default_value(768), "Initial height of the SDL window") - ("opengl", boost::program_options::value()->default_value(true), "Enable OpenGL in SDL") - ; - - options.add(sdl); - } - - - int IBasicApplication::ExecuteWithSdl(IBasicApplication& application, - int argc, - char* argv[]) - { - /****************************************************************** - * Initialize all the subcomponents of Orthanc Stone - ******************************************************************/ - - Orthanc::Logging::Initialize(); - Orthanc::HttpClient::InitializeOpenSsl(); - Orthanc::HttpClient::GlobalInitialize(); - SdlWindow::GlobalInitialize(); - - - /****************************************************************** - * Declare and parse the command-line options of the application - ******************************************************************/ + void IBasicApplication::DeclareStringStartupOption(const std::string& name, const std::string& defaultValue, const std::string& helpText) { + StartupOption option; + option.name = name; + option.defaultValue = defaultValue; + option.helpText = helpText = helpText; + option.type = StartupOption::string; - boost::program_options::options_description options; - DeclareSdlCommandLineOptions(options); - application.DeclareCommandLineOptions(options); - - boost::program_options::variables_map parameters; - bool error = false; - - try - { - boost::program_options::store(boost::program_options::command_line_parser(argc, argv). - options(options).run(), parameters); - boost::program_options::notify(parameters); - } - catch (boost::program_options::error& e) - { - LOG(ERROR) << "Error while parsing the command-line arguments: " << e.what(); - error = true; - } - - - /****************************************************************** - * Configure the application with the command-line parameters - ******************************************************************/ - - if (error || parameters.count("help")) - { - std::cout << std::endl - << "Usage: " << argv[0] << " [OPTION]..." - << std::endl - << "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research." - << std::endl << std::endl - << "Demonstration application of Orthanc Stone using SDL." - << std::endl; - - std::cout << options << "\n"; - return error ? -1 : 0; - } - - if (parameters.count("https-verify") && - !parameters["https-verify"].as()) - { - LOG(WARNING) << "Turning off verification of HTTPS certificates (unsafe)"; - Orthanc::HttpClient::ConfigureSsl(false, ""); - } - - if (parameters.count("verbose")) - { - Orthanc::Logging::EnableInfoLevel(true); - } - - if (!parameters.count("width") || - !parameters.count("height") || - !parameters.count("opengl")) - { - LOG(ERROR) << "Parameter \"width\", \"height\" or \"opengl\" is missing"; - return -1; - } - - int w = parameters["width"].as(); - int h = parameters["height"].as(); - if (w <= 0 || h <= 0) - { - LOG(ERROR) << "Parameters \"width\" and \"height\" must be positive"; - return -1; + startupOptions_.push_back(option); } - unsigned int width = static_cast(w); - unsigned int height = static_cast(h); - LOG(WARNING) << "Initial display size: " << width << "x" << height; + void IBasicApplication::DeclareBoolStartupOption(const std::string& name, bool defaultValue, const std::string& helpText) { + StartupOption option; + option.name = name; + option.defaultValue = (defaultValue ? "true" : "false"); + option.helpText = helpText = helpText; + option.type = StartupOption::boolean; - bool opengl = parameters["opengl"].as(); - if (opengl) - { - LOG(WARNING) << "OpenGL is enabled, disable it with option \"--opengl=off\" if the application crashes"; - } - else - { - LOG(WARNING) << "OpenGL is disabled, enable it with option \"--opengl=on\" for best performance"; + startupOptions_.push_back(option); } - bool success = true; - try - { - /**************************************************************** - * Initialize the connection to the Orthanc server - ****************************************************************/ - - Orthanc::WebServiceParameters webService; - - if (parameters.count("orthanc")) - { - webService.SetUrl(parameters["orthanc"].as()); - } - - if (parameters.count("username")) - { - webService.SetUsername(parameters["username"].as()); - } - - if (parameters.count("password")) - { - webService.SetPassword(parameters["password"].as()); - } - - LOG(WARNING) << "URL to the Orthanc REST API: " << webService.GetUrl(); - - { - OrthancPlugins::OrthancHttpConnection orthanc(webService); - if (!MessagingToolbox::CheckOrthancVersion(orthanc)) - { - LOG(ERROR) << "Your version of Orthanc is incompatible with Stone of Orthanc, please upgrade"; - throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); - } - } - - - /**************************************************************** - * Initialize the application - ****************************************************************/ - - LOG(WARNING) << "Creating the widgets of the application"; - - LogStatusBar statusBar; - BasicApplicationContext context(webService); - - application.Initialize(context, statusBar, parameters); + void IBasicApplication::DeclareIntegerStartupOption(const std::string& name, const int& defaultValue, const std::string& helpText) { + StartupOption option; + option.name = name; + option.defaultValue = std::to_string(defaultValue); + option.helpText = helpText = helpText; + option.type = StartupOption::integer; - { - BasicApplicationContext::ViewportLocker locker(context); - locker.GetViewport().SetStatusBar(statusBar); - } - - std::string title = application.GetTitle(); - if (title.empty()) - { - title = "Stone of Orthanc"; - } - - { - /************************************************************** - * Run the application inside a SDL window - **************************************************************/ - - LOG(WARNING) << "Starting the application"; - - SdlWindow window(title.c_str(), width, height, opengl); - SdlEngine sdl(window, context); - - { - BasicApplicationContext::ViewportLocker locker(context); - locker.GetViewport().Register(sdl); // (*) - } - - context.Start(); - sdl.Run(); - - LOG(WARNING) << "Stopping the application"; - - // Don't move the "Stop()" command below out of the block, - // otherwise the application might crash, because the - // "SdlEngine" is an observer of the viewport (*) and the - // update thread started by "context.Start()" would call a - // destructed object (the "SdlEngine" is deleted with the - // lexical scope). - context.Stop(); - } - - - /**************************************************************** - * Finalize the application - ****************************************************************/ - - LOG(WARNING) << "The application has stopped"; - application.Finalize(); - } - catch (Orthanc::OrthancException& e) - { - LOG(ERROR) << "EXCEPTION: " << e.What(); - success = false; + startupOptions_.push_back(option); } - - /****************************************************************** - * Finalize all the subcomponents of Orthanc Stone - ******************************************************************/ - - SdlWindow::GlobalFinalize(); - Orthanc::HttpClient::GlobalFinalize(); - Orthanc::HttpClient::FinalizeOpenSsl(); - - return (success ? 0 : -1); - } -#endif - } diff -r 26e3bfe30e66 -r d7b2590744f8 Applications/IBasicApplication.h --- a/Applications/IBasicApplication.h Fri Jun 08 14:41:45 2018 +0200 +++ b/Applications/IBasicApplication.h Mon Jun 11 14:01:02 2018 +0200 @@ -22,36 +22,62 @@ #pragma once #include "BasicApplicationContext.h" - #include -#if ORTHANC_ENABLE_SDL == 1 -# include // Necessary to avoid undefined reference to `SDL_main' -#endif - namespace OrthancStone { class IBasicApplication : public boost::noncopyable { + protected: +// struct StartupOptionValue { +// enum Type { +// boolean, +// string, +// integer +// }; +// Type type; +// std::string value; + +// int asInt() {return std::stoi(value);} +// bool asBool() {return value == "true"; } +// std::string asString() {return value; } +// }; + +// struct StartupOptionDefinition { +// std::string name; +// std::string helpText; +// std::string defaultValue; +// StartupOptionValue::Type type; +// }; + +// typedef std::list StartupOptions; + +// StartupOptions startupOptions_; + public: virtual ~IBasicApplication() { } - virtual void DeclareCommandLineOptions(boost::program_options::options_description& options) = 0; + virtual void DeclareStartupOptions(boost::program_options::options_description& options) = 0; + virtual void Initialize(IStatusBar& statusBar, + const boost::program_options::variables_map& parameters) = 0; + + virtual BasicApplicationContext& CreateApplicationContext(Orthanc::WebServiceParameters& orthanc) = 0; + virtual std::string GetTitle() const = 0; - virtual void Initialize(BasicApplicationContext& context, - IStatusBar& statusBar, - const boost::program_options::variables_map& parameters) = 0; +// virtual void Initialize(BasicApplicationContext& context, +// IStatusBar& statusBar, +// const std::map& startupOptions) = 0; virtual void Finalize() = 0; -#if ORTHANC_ENABLE_SDL == 1 - static int ExecuteWithSdl(IBasicApplication& application, - int argc, - char* argv[]); -#endif +//protected: +// virtual void DeclareStringStartupOption(const std::string& name, const std::string& defaultValue, const std::string& helpText); +// virtual void DeclareIntegerStartupOption(const std::string& name, const int& defaultValue, const std::string& helpText); +// virtual void DeclareBoolStartupOption(const std::string& name, bool defaultValue, const std::string& helpText); }; + } diff -r 26e3bfe30e66 -r d7b2590744f8 Applications/Samples/SampleApplicationBase.h --- a/Applications/Samples/SampleApplicationBase.h Fri Jun 08 14:41:45 2018 +0200 +++ b/Applications/Samples/SampleApplicationBase.h Mon Jun 11 14:01:02 2018 +0200 @@ -21,27 +21,38 @@ #pragma once -#include "../IBasicApplication.h" +#include "../../Applications/Sdl/BasicSdlApplication.h" +#include "SampleApplicationContext.h" namespace OrthancStone { namespace Samples { - class SampleApplicationBase : public IBasicApplication + +#ifdef ORTHANC_ENABLE_SDL + class SampleSdlApplicationBase : BasicSdlApplication { + private: + std::unique_ptr context_; + + BasicApplicationContext& CreateApplicationContext(Orthanc::WebServiceParameters& orthanc) { + context_.reset(new SampleApplicationContext(orthanc)); + } + }; + + typedef SampleApplicationBase_ SampleSdlApplicationBase; +#else + +#endif + + class SampleApplicationBase : public SampleApplicationBase_ { public: virtual std::string GetTitle() const { return "Stone of Orthanc - Sample"; } - - virtual void DeclareCommandLineOptions(boost::program_options::options_description& options) - { - } + }; - virtual void Finalize() - { - } - }; + } } diff -r 26e3bfe30e66 -r d7b2590744f8 Applications/Samples/SampleApplicationContext.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/SampleApplicationContext.cpp Mon Jun 11 14:01:02 2018 +0200 @@ -0,0 +1,94 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#include "SampleApplicationContext.h" + +namespace OrthancStone +{ + SampleApplicationContext::SampleApplicationContext(Orthanc::WebServiceParameters& orthanc) : + BaseApplicationContext(orthanc) + { + } + + + SampleApplicationContext::~SampleApplicationContext() + { + for (Interactors::iterator it = interactors_.begin(); it != interactors_.end(); ++it) + { + assert(*it != NULL); + delete *it; + } + + for (SlicedVolumes::iterator it = slicedVolumes_.begin(); it != slicedVolumes_.end(); ++it) + { + assert(*it != NULL); + delete *it; + } + + for (VolumeLoaders::iterator it = volumeLoaders_.begin(); it != volumeLoaders_.end(); ++it) + { + assert(*it != NULL); + delete *it; + } + } + + + ISlicedVolume& SampleApplicationContext::AddSlicedVolume(ISlicedVolume* volume) + { + if (volume == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + else + { + slicedVolumes_.push_back(volume); + return *volume; + } + } + + + IVolumeLoader& SampleApplicationContext::AddVolumeLoader(IVolumeLoader* loader) + { + if (loader == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + else + { + volumeLoaders_.push_back(loader); + return *loader; + } + } + + + IWorldSceneInteractor& SampleApplicationContext::AddInteractor(IWorldSceneInteractor* interactor) + { + if (interactor == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); + } + + interactors_.push_back(interactor); + + return *interactor; + } +} + diff -r 26e3bfe30e66 -r d7b2590744f8 Applications/Samples/SampleApplicationContext.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Samples/SampleApplicationContext.h Mon Jun 11 14:01:02 2018 +0200 @@ -0,0 +1,60 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "../../Framework/Viewport/WidgetViewport.h" +#include "../../Framework/Volumes/ISlicedVolume.h" +#include "../../Framework/Volumes/IVolumeLoader.h" +#include "../../Framework/Widgets/IWorldSceneInteractor.h" +#include "../../Platforms/Generic/OracleWebService.h" +#include "../BasicApplicationContext.h" + +#include +#include + + +namespace OrthancStone +{ + class SampleApplicationContext : public BasicApplicationContext + { + private: + typedef std::list SlicedVolumes; // this is actually used by the samples and shall be moved to a SampleApplicationContext + typedef std::list VolumeLoaders; + typedef std::list Interactors; + + SlicedVolumes slicedVolumes_; + VolumeLoaders volumeLoaders_; + Interactors interactors_; + + public: + + SampleApplicationContext(Orthanc::WebServiceParameters& orthanc); + + virtual ~SampleApplicationContext(); + + ISlicedVolume& AddSlicedVolume(ISlicedVolume* volume); + + IVolumeLoader& AddVolumeLoader(IVolumeLoader* loader); + + IWorldSceneInteractor& AddInteractor(IWorldSceneInteractor* interactor); + }; +} diff -r 26e3bfe30e66 -r d7b2590744f8 Applications/Sdl/BasicSdlApplication.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Sdl/BasicSdlApplication.cpp Mon Jun 11 14:01:02 2018 +0200 @@ -0,0 +1,316 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#if ORTHANC_ENABLE_SDL != 1 +#error this file shall be included only with the ORTHANC_ENABLE_SDL set to 1 +#endif + +#include "BasicSdlApplication.h" + +#include "../../Framework/Toolbox/MessagingToolbox.h" +#include "SdlEngine.h" + +#include +#include +#include + +namespace OrthancStone +{ + // Anonymous namespace to avoid clashes against other compilation modules + namespace + { + class LogStatusBar : public IStatusBar + { + public: + virtual void ClearMessage() + { + } + + virtual void SetMessage(const std::string& message) + { + LOG(WARNING) << message; + } + }; + } + + + static void DeclareSdlCommandLineOptions(boost::program_options::options_description& options) + { + // Declare the supported parameters + boost::program_options::options_description generic("Generic options"); + generic.add_options() + ("help", "Display this help and exit") + ("verbose", "Be verbose in logs") + ("orthanc", boost::program_options::value()->default_value("http://localhost:8042/"), + "URL to the Orthanc server") + ("username", "Username for the Orthanc server") + ("password", "Password for the Orthanc server") + ("https-verify", boost::program_options::value()->default_value(true), "Check HTTPS certificates") + ; + + options.add(generic); + + boost::program_options::options_description sdl("SDL options"); + sdl.add_options() + ("width", boost::program_options::value()->default_value(1024), "Initial width of the SDL window") + ("height", boost::program_options::value()->default_value(768), "Initial height of the SDL window") + ("opengl", boost::program_options::value()->default_value(true), "Enable OpenGL in SDL") + ; + + options.add(sdl); + } + +// void BasicSdlApplication::DeclareCommandLineOptions(boost::program_options::options_description &options) { +// boost::program_options::options_description app("Application specifi options"); + +// for (IBasicApplication::StartupOptions::const_iterator it = startupOptions_.begin(); it != startupOptions_.end(); it++) { +// switch (it->type) { +// case IBasicApplication::StartupOptionValue::boolean: +// app.add_options() +// (it->name.c_str(), boost::program_options::value()->default_value(std::stoi(it->defaultValue)), it->helpText.c_str()); +// break; +// case IBasicApplication::StartupOptionValue::integer: +// app.add_options() +// (it->name.c_str(), boost::program_options::value()->default_value(it->defaultValue == "true"), it->helpText.c_str()); +// break; +// case IBasicApplication::StartupOptionValue::string: +// app.add_options() +// (it->name.c_str(), boost::program_options::value()->default_value(it->defaultValue), it->helpText.c_str()); +// break; +// default: +// throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); +// } +// } +// options.add(app); +// } + + int BasicSdlApplication::ExecuteWithSdl(BasicSdlApplication& application, + int argc, + char* argv[]) + { + /****************************************************************** + * Initialize all the subcomponents of Orthanc Stone + ******************************************************************/ + + Orthanc::Logging::Initialize(); + Orthanc::HttpClient::InitializeOpenSsl(); + Orthanc::HttpClient::GlobalInitialize(); + SdlWindow::GlobalInitialize(); + + + /****************************************************************** + * Declare and parse the command-line options of the application + ******************************************************************/ + + boost::program_options::options_description options; + DeclareSdlCommandLineOptions(options); + application.DeclareStartupOptions(options); + + boost::program_options::variables_map parameters; + bool error = false; + + try + { + boost::program_options::store(boost::program_options::command_line_parser(argc, argv). + options(options).run(), parameters); + boost::program_options::notify(parameters); + } + catch (boost::program_options::error& e) + { + LOG(ERROR) << "Error while parsing the command-line arguments: " << e.what(); + error = true; + } + + + /****************************************************************** + * Configure the application with the command-line parameters + ******************************************************************/ + + if (error || parameters.count("help")) + { + std::cout << std::endl + << "Usage: " << argv[0] << " [OPTION]..." + << std::endl + << "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research." + << std::endl << std::endl + << "Demonstration application of Orthanc Stone using SDL." + << std::endl; + + std::cout << options << "\n"; + return error ? -1 : 0; + } + + if (parameters.count("https-verify") && + !parameters["https-verify"].as()) + { + LOG(WARNING) << "Turning off verification of HTTPS certificates (unsafe)"; + Orthanc::HttpClient::ConfigureSsl(false, ""); + } + + if (parameters.count("verbose")) + { + Orthanc::Logging::EnableInfoLevel(true); + } + + if (!parameters.count("width") || + !parameters.count("height") || + !parameters.count("opengl")) + { + LOG(ERROR) << "Parameter \"width\", \"height\" or \"opengl\" is missing"; + return -1; + } + + int w = parameters["width"].as(); + int h = parameters["height"].as(); + if (w <= 0 || h <= 0) + { + LOG(ERROR) << "Parameters \"width\" and \"height\" must be positive"; + return -1; + } + + unsigned int width = static_cast(w); + unsigned int height = static_cast(h); + LOG(WARNING) << "Initial display size: " << width << "x" << height; + + bool opengl = parameters["opengl"].as(); + if (opengl) + { + LOG(WARNING) << "OpenGL is enabled, disable it with option \"--opengl=off\" if the application crashes"; + } + else + { + LOG(WARNING) << "OpenGL is disabled, enable it with option \"--opengl=on\" for best performance"; + } + + bool success = true; + try + { + /**************************************************************** + * Initialize the connection to the Orthanc server + ****************************************************************/ + + Orthanc::WebServiceParameters webService; + + if (parameters.count("orthanc")) + { + webService.SetUrl(parameters["orthanc"].as()); + } + + if (parameters.count("username")) + { + webService.SetUsername(parameters["username"].as()); + } + + if (parameters.count("password")) + { + webService.SetPassword(parameters["password"].as()); + } + + LOG(WARNING) << "URL to the Orthanc REST API: " << webService.GetUrl(); + + { + OrthancPlugins::OrthancHttpConnection orthanc(webService); + if (!MessagingToolbox::CheckOrthancVersion(orthanc)) + { + LOG(ERROR) << "Your version of Orthanc is incompatible with Stone of Orthanc, please upgrade"; + throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol); + } + } + + + /**************************************************************** + * Initialize the application + ****************************************************************/ + + LOG(WARNING) << "Creating the widgets of the application"; + + LogStatusBar statusBar; + BasicApplicationContext& context = application.CreateApplicationContext(webService); + + application.Initialize(statusBar, parameters); + + { + BasicApplicationContext::ViewportLocker locker(context); + locker.GetViewport().SetStatusBar(statusBar); + } + + std::string title = application.GetTitle(); + if (title.empty()) + { + title = "Stone of Orthanc"; + } + + { + /************************************************************** + * Run the application inside a SDL window + **************************************************************/ + + LOG(WARNING) << "Starting the application"; + + SdlWindow window(title.c_str(), width, height, opengl); + SdlEngine sdl(window, context); + + { + BasicApplicationContext::ViewportLocker locker(context); + locker.GetViewport().Register(sdl); // (*) + } + + context.Start(); + sdl.Run(); + + LOG(WARNING) << "Stopping the application"; + + // Don't move the "Stop()" command below out of the block, + // otherwise the application might crash, because the + // "SdlEngine" is an observer of the viewport (*) and the + // update thread started by "context.Start()" would call a + // destructed object (the "SdlEngine" is deleted with the + // lexical scope). + context.Stop(); + } + + + /**************************************************************** + * Finalize the application + ****************************************************************/ + + LOG(WARNING) << "The application has stopped"; + application.Finalize(); + } + catch (Orthanc::OrthancException& e) + { + LOG(ERROR) << "EXCEPTION: " << e.What(); + success = false; + } + + + /****************************************************************** + * Finalize all the subcomponents of Orthanc Stone + ******************************************************************/ + + SdlWindow::GlobalFinalize(); + Orthanc::HttpClient::GlobalFinalize(); + Orthanc::HttpClient::FinalizeOpenSsl(); + + return (success ? 0 : -1); + } + +} diff -r 26e3bfe30e66 -r d7b2590744f8 Applications/Sdl/BasicSdlApplication.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Sdl/BasicSdlApplication.h Mon Jun 11 14:01:02 2018 +0200 @@ -0,0 +1,49 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "../BasicApplicationContext.h" +#include "../IBasicApplication.h" + +#include + +#if ORTHANC_ENABLE_SDL != 1 +#error this file shall be included only with the ORTHANC_ENABLE_SDL set to 1 +#endif + +#include // Necessary to avoid undefined reference to `SDL_main' + +namespace OrthancStone +{ + class BasicSdlApplication : public IBasicApplication + { + public: + virtual ~BasicSdlApplication() + { + } + + static int ExecuteWithSdl(BasicSdlApplication& application, + int argc, + char* argv[]); + }; + +} diff -r 26e3bfe30e66 -r d7b2590744f8 Applications/Wasm/BasicWasmApplication.cpp diff -r 26e3bfe30e66 -r d7b2590744f8 Applications/Wasm/BasicWasmApplication.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Applications/Wasm/BasicWasmApplication.h Mon Jun 11 14:01:02 2018 +0200 @@ -0,0 +1,45 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium + * + * This program is free software: you can redistribute it and/or + * modify it under the terms of the GNU Affero General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + **/ + + +#pragma once + +#include "../BasicApplicationContext.h" +#include "../IBasicApplication.h" + +#include + +#if ORTHANC_ENABLE_SDL == 1 +#error this file shall be included only with the ORTHANC_ENABLE_SDL set to 0 +#endif + +namespace OrthancStone +{ + class BasicWasmApplication : public IBasicApplication + { + public: + virtual ~BasicWasmApplication() + { + } + + //static int ExecuteWithWasm(BasicWasmApplication& application); + }; + +} diff -r 26e3bfe30e66 -r d7b2590744f8 Platforms/Generic/CMakeLists.txt --- a/Platforms/Generic/CMakeLists.txt Fri Jun 08 14:41:45 2018 +0200 +++ b/Platforms/Generic/CMakeLists.txt Mon Jun 11 14:01:02 2018 +0200 @@ -45,9 +45,13 @@ ## Build all the sample applications ##################################################################### -macro(BuildSample Target Sample) +macro(BuildSample Target Header Sample) add_executable(${Target} ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleMainSdl.cpp + ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleApplicationContext.cpp + ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleInteractor.h + ${ORTHANC_STONE_ROOT}/Applications/Samples/SampleApplicationBase.h + ${ORTHANC_STONE_ROOT}/Applications/Samples/${Header} ${APPLICATIONS_SOURCES} ) set_target_properties(${Target} PROPERTIES COMPILE_DEFINITIONS ORTHANC_STONE_SAMPLE=${Sample}) @@ -57,10 +61,10 @@ # TODO - Re-enable all these samples! -BuildSample(OrthancStoneEmpty 1) -BuildSample(OrthancStoneTestPattern 2) -BuildSample(OrthancStoneSingleFrame 3) -BuildSample(OrthancStoneSingleVolume 4) +BuildSample(OrthancStoneEmpty EmptyApplication.h 1) +BuildSample(OrthancStoneTestPattern TestPatternApplication.h 2) +BuildSample(OrthancStoneSingleFrame SingleFrameApplication.h 3) +BuildSample(OrthancStoneSingleVolume SingleVolumeApplication.h 4) #BuildSample(OrthancStoneBasicPetCtFusion 5) #BuildSample(OrthancStoneSynchronizedSeries 6) #BuildSample(OrthancStoneLayoutPetCtFusion 7) diff -r 26e3bfe30e66 -r d7b2590744f8 Platforms/WebAssembly/WasmWebService.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Platforms/WebAssembly/WasmWebService.cpp Mon Jun 11 14:01:02 2018 +0200 @@ -0,0 +1,90 @@ +#include "WasmWebService.h" + +#include + +#ifdef __cplusplus +extern "C" { +#endif + + extern void WasmWebService_ScheduleGetRequest(void* callback, + const char* uri, + void* payload); + + extern void WasmWebService_SchedulePostRequest(void* callback, + const char* uri, + const void* body, + size_t bodySize, + void* payload); + + void EMSCRIPTEN_KEEPALIVE WasmWebService_NotifyError(void* callback, + const char* uri, + void* payload) + { + if (callback == NULL) + { + throw; + } + else + { + reinterpret_cast(callback)-> + NotifyError(uri, reinterpret_cast(payload)); + } + } + + void EMSCRIPTEN_KEEPALIVE WasmWebService_NotifySuccess(void* callback, + const char* uri, + const void* body, + size_t bodySize, + void* payload) + { + if (callback == NULL) + { + throw; + } + else + { + reinterpret_cast(callback)-> + NotifySuccess(uri, body, bodySize, reinterpret_cast(payload)); + } + } + +#ifdef __cplusplus +} +#endif + + + +namespace OrthancStone +{ + void WasmWebService::SetBaseUrl(const std::string base) + { + // Make sure the base url ends with "/" + if (base.empty() || + base[base.size() - 1] != '/') + { + base_ = base + "/"; + } + else + { + base_ = base; + } + } + + void WasmWebService::ScheduleGetRequest(ICallback& callback, + const std::string& uri, + Orthanc::IDynamicObject* payload) + { + std::string url = base_ + uri; + WasmWebService_ScheduleGetRequest(&callback, url.c_str(), payload); + } + + void WasmWebService::SchedulePostRequest(ICallback& callback, + const std::string& uri, + const std::string& body, + Orthanc::IDynamicObject* payload) + { + std::string url = base_ + uri; + WasmWebService_SchedulePostRequest(&callback, url.c_str(), + body.c_str(), body.size(), payload); + } +} diff -r 26e3bfe30e66 -r d7b2590744f8 Platforms/WebAssembly/WasmWebService.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Platforms/WebAssembly/WasmWebService.h Mon Jun 11 14:01:02 2018 +0200 @@ -0,0 +1,44 @@ +#pragma once + +#include + +namespace OrthancStone +{ + class WasmWebService : public IWebService + { + private: + std::string base_; + + // Private constructor => Singleton design pattern + WasmWebService() : + base_("../../") + { + } + + public: + static WasmWebService& GetInstance() + { + static WasmWebService instance; + return instance; + } + + void SetBaseUrl(const std::string base); + + virtual void ScheduleGetRequest(ICallback& callback, + const std::string& uri, + Orthanc::IDynamicObject* payload); + + virtual void SchedulePostRequest(ICallback& callback, + const std::string& uri, + const std::string& body, + Orthanc::IDynamicObject* payload); + + virtual void Start() + { + } + + virtual void Stop() + { + } + }; +} diff -r 26e3bfe30e66 -r d7b2590744f8 Platforms/WebAssembly/WasmWebService.js --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Platforms/WebAssembly/WasmWebService.js Mon Jun 11 14:01:02 2018 +0200 @@ -0,0 +1,51 @@ +mergeInto(LibraryManager.library, { + WasmWebService_ScheduleGetRequest: function(callback, url, payload) { + // Directly use XMLHttpRequest (no jQuery) to retrieve the raw binary data + // http://www.henryalgus.com/reading-binary-files-using-jquery-ajax/ + var xhr = new XMLHttpRequest(); + var tmp = UTF8ToString(url); + xhr.open('GET', tmp, true); + xhr.responseType = 'arraybuffer'; + + xhr.onreadystatechange = function() { + if (this.readyState == XMLHttpRequest.DONE) { + if (xhr.status === 200) { + // TODO - Is "new Uint8Array()" necessary? This copies the + // answer to the WebAssembly stack, hence necessitating + // increasing the TOTAL_STACK parameter of Emscripten + WasmWebService_NotifySuccess(callback, tmp, new Uint8Array(this.response), + this.response.byteLength, payload); + } else { + WasmWebService_NotifyError(callback, tmp, payload); + } + } + } + + xhr.send(); + }, + + WasmWebService_SchedulePostRequest: function(callback, url, body, bodySize, payload) { + var xhr = new XMLHttpRequest(); + var tmp = UTF8ToString(url); + xhr.open('POST', tmp, true); + xhr.responseType = 'arraybuffer'; + xhr.setRequestHeader('Content-type', 'application/octet-stream'); + + xhr.onreadystatechange = function() { + if (this.readyState == XMLHttpRequest.DONE) { + if (xhr.status === 200) { + WasmWebService_NotifySuccess(callback, tmp, new Uint8Array(this.response), + this.response.byteLength, payload); + } else { + WasmWebService_NotifyError(callback, tmp, payload); + } + } + } + + xhr.send(new Uint8ClampedArray(HEAPU8.buffer, body, bodySize)); + }, + + ScheduleRedraw: function() { + ScheduleRedraw(); + } +}); diff -r 26e3bfe30e66 -r d7b2590744f8 Resources/CMake/OrthancStoneConfiguration.cmake --- a/Resources/CMake/OrthancStoneConfiguration.cmake Fri Jun 08 14:41:45 2018 +0200 +++ b/Resources/CMake/OrthancStoneConfiguration.cmake Mon Jun 11 14:01:02 2018 +0200 @@ -135,6 +135,10 @@ ## All the source files required to build Stone of Orthanc ##################################################################### +set(APPLICATIONS_SOURCES + ${ORTHANC_STONE_ROOT}/Applications/IBasicApplication.h + ) + if (NOT ORTHANC_SANDBOXED) set(PLATFORM_SOURCES ${ORTHANC_STONE_ROOT}/Platforms/Generic/WebServiceGetCommand.cpp @@ -142,14 +146,18 @@ ${ORTHANC_STONE_ROOT}/Platforms/Generic/Oracle.cpp ) - set(APPLICATIONS_SOURCES + list(APPEND APPLICATIONS_SOURCES ${ORTHANC_STONE_ROOT}/Applications/BasicApplicationContext.cpp - ${ORTHANC_STONE_ROOT}/Applications/IBasicApplication.cpp + ${ORTHANC_STONE_ROOT}/Applications/Sdl/BasicSdlApplication.cpp ${ORTHANC_STONE_ROOT}/Applications/Sdl/SdlEngine.cpp ${ORTHANC_STONE_ROOT}/Applications/Sdl/SdlCairoSurface.cpp ${ORTHANC_STONE_ROOT}/Applications/Sdl/SdlOrthancSurface.cpp ${ORTHANC_STONE_ROOT}/Applications/Sdl/SdlWindow.cpp ) +else() + list(APPEND APPLICATIONS_SOURCES + ${ORTHANC_STONE_ROOT}/Applications/Wasm/BasicWasmApplication.cpp + ) endif() list(APPEND ORTHANC_STONE_SOURCES @@ -222,3 +230,4 @@ ${SDL_SOURCES} ${BOOST_EXTENDED_SOURCES} ) +