# HG changeset patch # User Benjamin Golinvaux # Date 1571129693 -7200 # Node ID 2d6237221ff107b9fc179c45826768cdd5470216 # Parent eb28dfe432f71942b14cd376ee5ac08815b5acd0# Parent 5df50e0f039019d3ec01297c0daa9a6f3b97d270 Merge diff -r eb28dfe432f7 -r 2d6237221ff1 Applications/Samples/CMakeLists.txt --- a/Applications/Samples/CMakeLists.txt Tue Oct 15 10:53:28 2019 +0200 +++ b/Applications/Samples/CMakeLists.txt Tue Oct 15 10:54:53 2019 +0200 @@ -232,7 +232,6 @@ 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/TestStrategy.cpp ${ORTHANC_STONE_ROOT}/UnitTestsSources/TestStructureSet.cpp diff -r eb28dfe432f7 -r 2d6237221ff1 Applications/Samples/SingleFrameEditorApplication.h --- a/Applications/Samples/SingleFrameEditorApplication.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Applications/Samples/SingleFrameEditorApplication.h Tue Oct 15 10:54:53 2019 +0200 @@ -117,12 +117,12 @@ if (tool_ == Tool_Windowing) { return new RadiographyWindowingTracker( - undoRedoStack_, widget.GetScene(), - viewportX, viewportY, - RadiographyWindowingTracker::Action_DecreaseWidth, - RadiographyWindowingTracker::Action_IncreaseWidth, - RadiographyWindowingTracker::Action_DecreaseCenter, - RadiographyWindowingTracker::Action_IncreaseCenter); + undoRedoStack_, widget.GetScene(), widget, ImageInterpolation_Nearest, + viewportX, viewportY, + RadiographyWindowingTracker::Action_DecreaseWidth, + RadiographyWindowingTracker::Action_IncreaseWidth, + RadiographyWindowingTracker::Action_DecreaseCenter, + RadiographyWindowingTracker::Action_IncreaseCenter); } else if (!widget.LookupSelectedLayer(selected)) { diff -r eb28dfe432f7 -r 2d6237221ff1 Applications/Sdl/SdlCairoSurface.h --- a/Applications/Sdl/SdlCairoSurface.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Applications/Sdl/SdlCairoSurface.h Tue Oct 15 10:54:53 2019 +0200 @@ -23,7 +23,7 @@ #if ORTHANC_ENABLE_SDL == 1 -#include "SdlWindow.h" +#include "../../Framework/Viewport/SdlWindow.h" #include "../../Framework/Wrappers/CairoSurface.h" #include "../../Framework/Deprecated/Viewport/IViewport.h" diff -r eb28dfe432f7 -r 2d6237221ff1 Applications/Sdl/SdlOpenGLContext.cpp --- a/Applications/Sdl/SdlOpenGLContext.cpp Tue Oct 15 10:53:28 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,162 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 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 "SdlOpenGLContext.h" -#include "../../Framework/StoneException.h" - -#if ORTHANC_ENABLE_SDL == 1 - -#if !defined(ORTHANC_ENABLE_GLEW) -# error Macro ORTHANC_ENABLE_GLEW must be defined -#endif - -#if ORTHANC_ENABLE_GLEW == 1 -# include -#endif - -#include - -namespace OrthancStone -{ - SdlOpenGLContext::SdlOpenGLContext(const char* title, - unsigned int width, - unsigned int height, - bool allowDpiScaling) - : window_(title, width, height, true /* enable OpenGL */, allowDpiScaling) - , context_(NULL) - , contextLost_(false) - { - context_ = SDL_GL_CreateContext(window_.GetObject()); - - if (context_ == NULL) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, - "Cannot initialize OpenGL"); - } - -#if ORTHANC_ENABLE_GLEW == 1 - // The initialization function of glew (i.e. "glewInit()") can - // only be called once an OpenGL is setup. - // https://stackoverflow.com/a/45033669/881731 - { - static boost::mutex mutex_; - static bool isGlewInitialized_ = false; - - boost::mutex::scoped_lock lock(mutex_); - - if (!isGlewInitialized_) - { - LOG(INFO) << "Initializing glew"; - - GLenum err = glewInit(); - if (GLEW_OK != err) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, - "Cannot initialize glew"); - } - - isGlewInitialized_ = true; - } - } -#endif - } - - - SdlOpenGLContext::~SdlOpenGLContext() - { - SDL_GL_DeleteContext(context_); - } - - - bool SdlOpenGLContext::IsContextLost() - { - return contextLost_; - } - - void SdlOpenGLContext::SetLostContext() - { - contextLost_ = true; - } - - void SdlOpenGLContext::RestoreLostContext() - { - contextLost_ = false; - } - - // extern bool Debug_MustContextBeKilled(std::string title); - // extern void Debug_Context_ClearKillFlag(std::string title); - - void SdlOpenGLContext::MakeCurrent() - { - if (IsContextLost()) - throw OpenGLContextLostException(context_); - - // - // This is used for context loss simulation - // SDL_Window* internalWindow = GetWindow().GetObject(); - // std::string title(SDL_GetWindowTitle(internalWindow)); - - // if (Debug_MustContextBeKilled(title)) - // { - // Debug_Context_ClearKillFlag(title); - // SetLostContext(); - // throw OpenGLContextLostException(context_); - // } - // - - if (SDL_GL_MakeCurrent(window_.GetObject(), context_) != 0) - { - const char* errText = SDL_GetError(); - std::stringstream ss; - ss << "Cannot set current OpenGL context. SDL error text: " << errText; - std::string errStr = ss.str(); - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, errStr.c_str()); - } - - // This makes our buffer swap synchronized with the monitor's vertical refresh - SDL_GL_SetSwapInterval(1); - } - - - void SdlOpenGLContext::SwapBuffer() - { - // Swap our buffer to display the current contents of buffer on screen - SDL_GL_SwapWindow(window_.GetObject()); - } - - - unsigned int SdlOpenGLContext::GetCanvasWidth() const - { - int w = 0; - SDL_GL_GetDrawableSize(window_.GetObject(), &w, NULL); - return static_cast(w); - } - - - unsigned int SdlOpenGLContext::GetCanvasHeight() const - { - int h = 0; - SDL_GL_GetDrawableSize(window_.GetObject(), NULL, &h); - return static_cast(h); - } -} - -#endif diff -r eb28dfe432f7 -r 2d6237221ff1 Applications/Sdl/SdlOpenGLContext.h --- a/Applications/Sdl/SdlOpenGLContext.h Tue Oct 15 10:53:28 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,73 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 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 - -#if ORTHANC_ENABLE_SDL == 1 - -#include "../../Framework/OpenGL/IOpenGLContext.h" -#include "SdlWindow.h" - -#include - -namespace OrthancStone -{ - class SdlOpenGLContext : public OpenGL::IOpenGLContext - { - private: - SdlWindow window_; - SDL_GLContext context_; - bool contextLost_; - - public: - SdlOpenGLContext(const char* title, - unsigned int width, - unsigned int height, - bool allowDpiScaling = true); - - ~SdlOpenGLContext(); - - SdlWindow& GetWindow() - { - return window_; - } - - virtual bool IsContextLost() ORTHANC_OVERRIDE; - - virtual void SetLostContext() ORTHANC_OVERRIDE; - virtual void RestoreLostContext() ORTHANC_OVERRIDE; - - virtual void MakeCurrent() ORTHANC_OVERRIDE; - - virtual void SwapBuffer() ORTHANC_OVERRIDE; - - virtual unsigned int GetCanvasWidth() const ORTHANC_OVERRIDE; - - virtual unsigned int GetCanvasHeight() const ORTHANC_OVERRIDE; - - virtual void* DebugGetInternalContext() const ORTHANC_OVERRIDE - { - return context_; - } - }; -} - -#endif diff -r eb28dfe432f7 -r 2d6237221ff1 Applications/Sdl/SdlOrthancSurface.h --- a/Applications/Sdl/SdlOrthancSurface.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Applications/Sdl/SdlOrthancSurface.h Tue Oct 15 10:54:53 2019 +0200 @@ -23,7 +23,7 @@ #if ORTHANC_ENABLE_SDL == 1 -#include "SdlWindow.h" +#include "../../Framework/Viewport/SdlWindow.h" #include #include diff -r eb28dfe432f7 -r 2d6237221ff1 Applications/Sdl/SdlWindow.cpp --- a/Applications/Sdl/SdlWindow.cpp Tue Oct 15 10:53:28 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,201 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 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 "SdlWindow.h" - -#if ORTHANC_ENABLE_SDL == 1 - -#include -#include - -#ifdef WIN32 -#include // for SetProcessDpiAware -#endif -// WIN32 - -#include - -namespace OrthancStone -{ - SdlWindow::SdlWindow(const char* title, - unsigned int width, - unsigned int height, - bool enableOpenGl, - bool allowDpiScaling) : - maximized_(false) - { - // TODO Understand why, with SDL_WINDOW_OPENGL + MinGW32 + Release - // build mode, the application crashes whenever the SDL window is - // resized or maximized - - uint32_t windowFlags, rendererFlags; - if (enableOpenGl) - { - windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; - rendererFlags = SDL_RENDERER_ACCELERATED; - } - else - { - windowFlags = SDL_WINDOW_RESIZABLE; - rendererFlags = SDL_RENDERER_SOFTWARE; - } - -// TODO: probably required on MacOS X, too -#if defined(WIN32) && (_WIN32_WINNT >= 0x0600) - if (!allowDpiScaling) - { - // if we do NOT allow DPI scaling, it means an SDL pixel will be a real - // monitor pixel. This is needed for high-DPI applications - - // Enable high-DPI support on Windows - - // THE FOLLOWING HAS BEEN COMMENTED OUT BECAUSE IT WILL CRASH UNDER - // OLD WINDOWS VERSIONS - // ADD THIS AT THE TOP TO ENABLE IT: - // - //#pragma comment(lib, "Shcore.lib") THIS IS ONLY REQUIRED FOR SetProcessDpiAwareness - //#include - //#include THIS IS ONLY REQUIRED FOR SetProcessDpiAwareness - //#include THIS IS ONLY REQUIRED FOR SetProcessDpiAwareness - // SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); - - // This is supported on Vista+ - SetProcessDPIAware(); - - windowFlags |= SDL_WINDOW_ALLOW_HIGHDPI; - } -#endif -// WIN32 - - window_ = SDL_CreateWindow(title, - SDL_WINDOWPOS_UNDEFINED, - SDL_WINDOWPOS_UNDEFINED, - width, height, windowFlags); - - if (window_ == NULL) - { - LOG(ERROR) << "Cannot create the SDL window: " << SDL_GetError(); - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - - renderer_ = SDL_CreateRenderer(window_, -1, rendererFlags); - if (!renderer_) - { - LOG(ERROR) << "Cannot create the SDL renderer: " << SDL_GetError(); - SDL_DestroyWindow(window_); - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } - - - SdlWindow::~SdlWindow() - { - if (renderer_ != NULL) - { - SDL_DestroyRenderer(renderer_); - } - - if (window_ != NULL) - { - SDL_DestroyWindow(window_); - } - } - - - unsigned int SdlWindow::GetWidth() const - { - int w = -1; - SDL_GetWindowSize(window_, &w, NULL); - - if (w < 0) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - else - { - return static_cast(w); - } - } - - - unsigned int SdlWindow::GetHeight() const - { - int h = -1; - SDL_GetWindowSize(window_, NULL, &h); - - if (h < 0) - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - else - { - return static_cast(h); - } - } - - - void SdlWindow::Render(SDL_Surface* surface) - { - //SDL_RenderClear(renderer_); - - SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer_, surface); - if (texture != NULL) - { - SDL_RenderCopy(renderer_, texture, NULL, NULL); - SDL_DestroyTexture(texture); - } - - SDL_RenderPresent(renderer_); - } - - - void SdlWindow::ToggleMaximize() - { - if (maximized_) - { - SDL_RestoreWindow(window_); - maximized_ = false; - } - else - { - SDL_MaximizeWindow(window_); - maximized_ = true; - } - } - - - void SdlWindow::GlobalInitialize() - { - if (SDL_Init(SDL_INIT_VIDEO) != 0) - { - LOG(ERROR) << "Cannot initialize SDL"; - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - } - - - void SdlWindow::GlobalFinalize() - { - SDL_Quit(); - } -} - -#endif diff -r eb28dfe432f7 -r 2d6237221ff1 Applications/Sdl/SdlWindow.h --- a/Applications/Sdl/SdlWindow.h Tue Oct 15 10:53:28 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,67 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 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 - -#if ORTHANC_ENABLE_SDL == 1 - -#include -#include -#include - -namespace OrthancStone -{ - class SdlWindow : public boost::noncopyable - { - private: - SDL_Window *window_; - SDL_Renderer *renderer_; - bool maximized_; - - public: - SdlWindow(const char* title, - unsigned int width, - unsigned int height, - bool enableOpenGl, - bool allowDpiScaling = true); - - ~SdlWindow(); - - SDL_Window *GetObject() const - { - return window_; - } - - unsigned int GetWidth() const; - - unsigned int GetHeight() const; - - void Render(SDL_Surface* surface); - - void ToggleMaximize(); - - static void GlobalInitialize(); - - static void GlobalFinalize(); - }; -} - -#endif diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Deprecated/Toolbox/IWebService.h --- a/Framework/Deprecated/Toolbox/IWebService.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Deprecated/Toolbox/IWebService.h Tue Oct 15 10:54:53 2019 +0200 @@ -24,6 +24,7 @@ #include "../../Messages/IObserver.h" #include "../../Messages/ICallable.h" +#include #include #include diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Deprecated/Toolbox/OrthancApiClient.h --- a/Framework/Deprecated/Toolbox/OrthancApiClient.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Deprecated/Toolbox/OrthancApiClient.h Tue Oct 15 10:54:53 2019 +0200 @@ -26,7 +26,6 @@ #include "IWebService.h" #include "../../Messages/IObservable.h" -#include "../../Messages/Promise.h" namespace Deprecated { diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Loaders/DicomStructureSetLoader.cpp --- a/Framework/Loaders/DicomStructureSetLoader.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Loaders/DicomStructureSetLoader.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -22,8 +22,11 @@ #include "DicomStructureSetLoader.h" #include "../Scene2D/PolylineSceneLayer.h" +#include "../StoneException.h" #include "../Toolbox/GeometryToolbox.h" +#include + #include #if 0 diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Loaders/LoaderCache.cpp --- a/Framework/Loaders/LoaderCache.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Loaders/LoaderCache.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -20,6 +20,7 @@ #include "LoaderCache.h" +#include "../StoneException.h" #include "OrthancSeriesVolumeProgressiveLoader.h" #include "OrthancMultiframeVolumeLoader.h" #include "DicomStructureSetLoader.h" diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Messages/IObserver.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Messages/IObserver.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -0,0 +1,93 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 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 "IObserver.h" + +#include "IMessage.h" +#include "../StoneException.h" + +#include +#include + +namespace OrthancStone +{ + IObserver::IObserver(MessageBroker& broker) + : broker_(broker) + , fingerprint_() + { + // we store the fingerprint_ as a char array to avoid problems when + // reading it in a deceased object. + // remember this is panic-level code to track zombie object usage + std::string fingerprint = Orthanc::Toolbox::GenerateUuid(); + const char* fingerprintRaw = fingerprint.c_str(); + memcpy(fingerprint_, fingerprintRaw, 37); + broker_.Register(*this); + } + + + IObserver::~IObserver() + { + try + { + LOG(TRACE) << "IObserver(" << std::hex << this << std::dec << ")::~IObserver : fingerprint_ == " << fingerprint_; + const char* deadMarker = "deadbeef-dead-dead-0000-0000deadbeef"; + ORTHANC_ASSERT(strlen(deadMarker) == 36); + memcpy(fingerprint_, deadMarker, 37); + broker_.Unregister(*this); + } + catch (const Orthanc::OrthancException& e) + { + if (e.HasDetails()) + { + LOG(ERROR) << "OrthancException in ~IObserver: " << e.What() << " Details: " << e.GetDetails(); + } + else + { + LOG(ERROR) << "OrthancException in ~IObserver: " << e.What(); + } + } + catch (const std::exception& e) + { + LOG(ERROR) << "std::exception in ~IObserver: " << e.what(); + } + catch (...) + { + LOG(ERROR) << "Unknown exception in ~IObserver"; + } + } + + + bool IObserver::DoesFingerprintLookGood() const + { + for (size_t i = 0; i < 36; ++i) { + bool ok = false; + if (fingerprint_[i] >= 'a' && fingerprint_[i] <= 'f') + ok = true; + if (fingerprint_[i] >= '0' && fingerprint_[i] <= '9') + ok = true; + if (fingerprint_[i] == '-') + ok = true; + if (!ok) + return false; + } + return fingerprint_[36] == 0; + } +} diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Messages/IObserver.h --- a/Framework/Messages/IObserver.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Messages/IObserver.h Tue Oct 15 10:54:53 2019 +0200 @@ -22,9 +22,6 @@ #pragma once #include "MessageBroker.h" -#include "IMessage.h" - -#include namespace OrthancStone { @@ -35,71 +32,18 @@ // the following is a UUID that is used to disambiguate different observers // that may have the same address char fingerprint_[37]; - public: - IObserver(MessageBroker& broker) - : broker_(broker) - , fingerprint_() - { - // we store the fingerprint_ as a char array to avoid problems when - // reading it in a deceased object. - // remember this is panic-level code to track zombie object usage - std::string fingerprint = Orthanc::Toolbox::GenerateUuid(); - const char* fingerprintRaw = fingerprint.c_str(); - memcpy(fingerprint_, fingerprintRaw, 37); - broker_.Register(*this); - } - virtual ~IObserver() - { - try - { - LOG(TRACE) << "IObserver(" << std::hex << this << std::dec << ")::~IObserver : fingerprint_ == " << fingerprint_; - const char* deadMarker = "deadbeef-dead-dead-0000-0000deadbeef"; - ORTHANC_ASSERT(strlen(deadMarker) == 36); - memcpy(fingerprint_, deadMarker, 37); - broker_.Unregister(*this); - } - catch (const Orthanc::OrthancException& e) - { - if (e.HasDetails()) - { - LOG(ERROR) << "OrthancException in ~IObserver: " << e.What() << " Details: " << e.GetDetails(); - } - else - { - LOG(ERROR) << "OrthancException in ~IObserver: " << e.What(); - } - } - catch (const std::exception& e) - { - LOG(ERROR) << "std::exception in ~IObserver: " << e.what(); - } - catch (...) - { - LOG(ERROR) << "Unknown exception in ~IObserver"; - } - } + public: + IObserver(MessageBroker& broker); + + virtual ~IObserver(); const char* GetFingerprint() const { return fingerprint_; } - bool DoesFingerprintLookGood() const - { - for (size_t i = 0; i < 36; ++i) { - bool ok = false; - if (fingerprint_[i] >= 'a' && fingerprint_[i] <= 'f') - ok = true; - if (fingerprint_[i] >= '0' && fingerprint_[i] <= '9') - ok = true; - if (fingerprint_[i] == '-') - ok = true; - if (!ok) - return false; - } - return fingerprint_[36] == 0; - } + bool DoesFingerprintLookGood() const; MessageBroker& GetBroker() const { diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Messages/MessageBroker.h --- a/Framework/Messages/MessageBroker.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Messages/MessageBroker.h Tue Oct 15 10:54:53 2019 +0200 @@ -20,8 +20,6 @@ #pragma once -#include "../StoneException.h" - #include "boost/noncopyable.hpp" #include diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Messages/Promise.h --- a/Framework/Messages/Promise.h Tue Oct 15 10:53:28 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 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 "MessageBroker.h" -#include "ICallable.h" -#include "IMessage.h" - -#include -#include - -namespace OrthancStone { - - class Promise : public boost::noncopyable - { - protected: - MessageBroker& broker_; - - std::auto_ptr successCallable_; - std::auto_ptr failureCallable_; - - public: - Promise(MessageBroker& broker) - : broker_(broker) - { - } - - void Success(const IMessage& message) - { - // check the target is still alive in the broker - if (successCallable_.get() != NULL && - broker_.IsActive(*successCallable_->GetObserver())) - { - successCallable_->Apply(message); - } - } - - void Failure(const IMessage& message) - { - // check the target is still alive in the broker - if (failureCallable_.get() != NULL && - broker_.IsActive(*failureCallable_->GetObserver())) - { - failureCallable_->Apply(message); - } - } - - Promise& Then(ICallable* successCallable) // Takes ownership - { - if (successCallable_.get() != NULL) - { - // TODO: throw throw new "Promise may only have a single success target" - } - successCallable_.reset(successCallable); - return *this; - } - - Promise& Else(ICallable* failureCallable) // Takes ownership - { - if (failureCallable_.get() != NULL) - { - // TODO: throw throw new "Promise may only have a single failure target" - } - failureCallable_.reset(failureCallable); - return *this; - } - }; -} diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/OpenGL/IOpenGLContext.h --- a/Framework/OpenGL/IOpenGLContext.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/OpenGL/IOpenGLContext.h Tue Oct 15 10:54:53 2019 +0200 @@ -34,7 +34,7 @@ { } - virtual bool IsContextLost() = 0; + virtual bool IsContextLost() = 0; virtual void MakeCurrent() = 0; @@ -43,14 +43,6 @@ virtual unsigned int GetCanvasWidth() const = 0; virtual unsigned int GetCanvasHeight() const = 0; - - virtual void* DebugGetInternalContext() const = 0; - - // This is for manual context loss (debug purposes) - virtual void SetLostContext() = 0; - virtual void RestoreLostContext() = 0; - }; } } - diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/OpenGL/OpenGLIncludes.h --- a/Framework/OpenGL/OpenGLIncludes.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/OpenGL/OpenGLIncludes.h Tue Oct 15 10:54:53 2019 +0200 @@ -58,7 +58,6 @@ # define ORTHANC_OPENGL_CHECK(name) # define ORTHANC_OPENGL_TRACE_CURRENT_CONTEXT(msg) -# define ORTHANC_CHECK_CURRENT_CONTEXT(context) # else @@ -80,17 +79,6 @@ LOG(TRACE) << msg << " | Current OpenGL context is " << std::hex << ctx; \ } else (void)0 -# define ORTHANC_CHECK_CURRENT_CONTEXT(context) \ -if(true) \ -{ \ - SDL_GLContext actualCtx = SDL_GL_GetCurrentContext(); \ - void* expectedCtx = context.DebugGetInternalContext(); \ - if(expectedCtx != actualCtx) \ - { \ - LOG(ERROR) << "Expected context was " << std::hex << expectedCtx << " while actual context is " << std::hex << actualCtx; \ - } \ -} else (void)0 - # endif #endif diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/OpenGL/OpenGLProgram.cpp --- a/Framework/OpenGL/OpenGLProgram.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/OpenGL/OpenGLProgram.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -49,7 +49,6 @@ { if (!context_.IsContextLost()) { - ORTHANC_CHECK_CURRENT_CONTEXT(context_); ORTHANC_OPENGL_TRACE_CURRENT_CONTEXT("About to call glDeleteProgram"); assert(program_ != 0); glDeleteProgram(program_); diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/OpenGL/OpenGLTexture.cpp --- a/Framework/OpenGL/OpenGLTexture.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/OpenGL/OpenGLTexture.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -35,8 +35,6 @@ { if (!context_.IsContextLost()) { - // context is made current externally. Let's check this! - ORTHANC_CHECK_CURRENT_CONTEXT(context_); // Generate a texture object glGenTextures(1, &texture_); if (texture_ == 0) @@ -53,8 +51,6 @@ { if (!context_.IsContextLost()) { - // context is made current externally. Let's check this! - ORTHANC_CHECK_CURRENT_CONTEXT(context_); assert(texture_ != 0); ORTHANC_OPENGL_TRACE_CURRENT_CONTEXT("About to call glDeleteTextures"); glDeleteTextures(1, &texture_); @@ -84,8 +80,6 @@ void OpenGLTexture::Load(const Orthanc::ImageAccessor& image, bool isLinearInterpolation) { - // context is made current externally. Let's check this! - ORTHANC_CHECK_CURRENT_CONTEXT(context_); if (!context_.IsContextLost()) { glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // Disable byte-alignment restriction diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/OpenGL/SdlOpenGLContext.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/OpenGL/SdlOpenGLContext.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -0,0 +1,126 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 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 "SdlOpenGLContext.h" +#include "../../Framework/StoneException.h" + +#if ORTHANC_ENABLE_SDL == 1 + +#if !defined(ORTHANC_ENABLE_GLEW) +# error Macro ORTHANC_ENABLE_GLEW must be defined +#endif + +#if ORTHANC_ENABLE_GLEW == 1 +# include +#endif + +#include + +namespace OrthancStone +{ + SdlOpenGLContext::SdlOpenGLContext(const char* title, + unsigned int width, + unsigned int height, + bool allowDpiScaling) + : window_(title, width, height, true /* enable OpenGL */, allowDpiScaling) + , context_(NULL) + { + context_ = SDL_GL_CreateContext(window_.GetObject()); + + if (context_ == NULL) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, + "Cannot initialize OpenGL"); + } + +#if ORTHANC_ENABLE_GLEW == 1 + // The initialization function of glew (i.e. "glewInit()") can + // only be called once an OpenGL is setup. + // https://stackoverflow.com/a/45033669/881731 + { + static boost::mutex mutex_; + static bool isGlewInitialized_ = false; + + boost::mutex::scoped_lock lock(mutex_); + + if (!isGlewInitialized_) + { + LOG(INFO) << "Initializing glew"; + + GLenum err = glewInit(); + if (GLEW_OK != err) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, + "Cannot initialize glew"); + } + + isGlewInitialized_ = true; + } + } +#endif + } + + + SdlOpenGLContext::~SdlOpenGLContext() + { + SDL_GL_DeleteContext(context_); + } + + void SdlOpenGLContext::MakeCurrent() + { + if (SDL_GL_MakeCurrent(window_.GetObject(), context_) != 0) + { + const char* errText = SDL_GetError(); + std::stringstream ss; + ss << "Cannot set current OpenGL context. SDL error text: " << errText; + std::string errStr = ss.str(); + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError, errStr.c_str()); + } + + // This makes our buffer swap synchronized with the monitor's vertical refresh + SDL_GL_SetSwapInterval(1); + } + + + void SdlOpenGLContext::SwapBuffer() + { + // Swap our buffer to display the current contents of buffer on screen + SDL_GL_SwapWindow(window_.GetObject()); + } + + + unsigned int SdlOpenGLContext::GetCanvasWidth() const + { + int w = 0; + SDL_GL_GetDrawableSize(window_.GetObject(), &w, NULL); + return static_cast(w); + } + + + unsigned int SdlOpenGLContext::GetCanvasHeight() const + { + int h = 0; + SDL_GL_GetDrawableSize(window_.GetObject(), NULL, &h); + return static_cast(h); + } +} + +#endif diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/OpenGL/SdlOpenGLContext.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/OpenGL/SdlOpenGLContext.h Tue Oct 15 10:54:53 2019 +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-2019 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 + +#if ORTHANC_ENABLE_SDL == 1 + +#include "IOpenGLContext.h" +#include "../Viewport/SdlWindow.h" + +#include + +namespace OrthancStone +{ + class SdlOpenGLContext : public OpenGL::IOpenGLContext + { + private: + SdlWindow window_; + SDL_GLContext context_; + + public: + SdlOpenGLContext(const char* title, + unsigned int width, + unsigned int height, + bool allowDpiScaling = true); + + ~SdlOpenGLContext(); + + SdlWindow& GetWindow() + { + return window_; + } + + virtual bool IsContextLost() ORTHANC_OVERRIDE + { + // On desktop applications, an OpenGL context should never be lost + return false; + } + + virtual void MakeCurrent() ORTHANC_OVERRIDE; + + virtual void SwapBuffer() ORTHANC_OVERRIDE; + + virtual unsigned int GetCanvasWidth() const ORTHANC_OVERRIDE; + + virtual unsigned int GetCanvasHeight() const ORTHANC_OVERRIDE; + }; +} + +#endif diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/OpenGL/WebAssemblyOpenGLContext.cpp --- a/Framework/OpenGL/WebAssemblyOpenGLContext.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/OpenGL/WebAssemblyOpenGLContext.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -123,14 +123,14 @@ if (IsContextLost()) { LOG(ERROR) << "MakeCurrent() called on lost context " << context_; - throw OpenGLContextLostException(reinterpret_cast(context_)); + throw StoneException(ErrorCode_WebGLContextLost); } if (emscripten_is_webgl_context_lost(context_)) { LOG(ERROR) << "OpenGL context has been lost for canvas: " << canvas_; SetLostContext(); - throw OpenGLContextLostException(reinterpret_cast(context_)); + throw StoneException(ErrorCode_WebGLContextLost); } if (emscripten_webgl_make_context_current(context_) != EMSCRIPTEN_RESULT_SUCCESS) @@ -248,11 +248,6 @@ return pimpl_->IsContextLost(); } - void WebAssemblyOpenGLContext::RestoreLostContext() - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - void WebAssemblyOpenGLContext::SetLostContext() { pimpl_->SetLostContext(); diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/OpenGL/WebAssemblyOpenGLContext.h --- a/Framework/OpenGL/WebAssemblyOpenGLContext.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/OpenGL/WebAssemblyOpenGLContext.h Tue Oct 15 10:54:53 2019 +0200 @@ -58,9 +58,6 @@ virtual bool IsContextLost() ORTHANC_OVERRIDE; - virtual void SetLostContext() ORTHANC_OVERRIDE; - virtual void RestoreLostContext() ORTHANC_OVERRIDE; - virtual void MakeCurrent() ORTHANC_OVERRIDE; virtual void SwapBuffer() ORTHANC_OVERRIDE; @@ -69,8 +66,6 @@ virtual unsigned int GetCanvasHeight() const ORTHANC_OVERRIDE; - virtual void* DebugGetInternalContext() const ORTHANC_OVERRIDE; - /** Returns true if the underlying context has been successfully recreated */ @@ -79,6 +74,13 @@ void UpdateSize(); const std::string& GetCanvasIdentifier() const; + + + /** + * This is for manual context loss (debug purposes) + **/ + void* DebugGetInternalContext() const; + void SetLostContext(); }; } } diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Radiography/RadiographyScene.h --- a/Framework/Radiography/RadiographyScene.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Radiography/RadiographyScene.h Tue Oct 15 10:54:53 2019 +0200 @@ -263,9 +263,9 @@ Extent2D GetSceneExtent() const; - void Render(Orthanc::ImageAccessor& buffer, - const AffineTransform2D& viewTransform, - ImageInterpolation interpolation) const; + virtual void Render(Orthanc::ImageAccessor& buffer, + const AffineTransform2D& viewTransform, + ImageInterpolation interpolation) const; bool LookupLayer(size_t& index /* out */, double x, diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Radiography/RadiographyWindowingTracker.cpp --- a/Framework/Radiography/RadiographyWindowingTracker.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Radiography/RadiographyWindowingTracker.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -20,6 +20,7 @@ #include "RadiographyWindowingTracker.h" +#include "RadiographyWidget.h" #include @@ -115,6 +116,8 @@ RadiographyWindowingTracker::RadiographyWindowingTracker(UndoRedoStack& undoRedoStack, RadiographyScene& scene, + RadiographyWidget& widget, + ImageInterpolation interpolationDuringTracking, int x, int y, Action leftAction, @@ -123,6 +126,8 @@ Action downAction) : undoRedoStack_(undoRedoStack), scene_(scene), + widget_(widget), + initialWidgetInterpolation_(widget.GetInterpolation()), clickX_(x), clickY_(y), leftAction_(leftAction), @@ -131,6 +136,7 @@ downAction_(downAction) { scene_.GetWindowingWithDefault(sourceCenter_, sourceWidth_); + widget_.SetInterpolation(interpolationDuringTracking); float minValue, maxValue; scene.GetRange(minValue, maxValue); @@ -156,6 +162,7 @@ void RadiographyWindowingTracker::MouseUp() { + widget_.SetInterpolation(initialWidgetInterpolation_); undoRedoStack_.Add(new UndoRedoCommand(*this)); } diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Radiography/RadiographyWindowingTracker.h --- a/Framework/Radiography/RadiographyWindowingTracker.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Radiography/RadiographyWindowingTracker.h Tue Oct 15 10:54:53 2019 +0200 @@ -27,6 +27,9 @@ namespace OrthancStone { + + class RadiographyWidget; + class RadiographyWindowingTracker : public Deprecated::IWorldSceneMouseTracker { public: @@ -43,6 +46,8 @@ UndoRedoStack& undoRedoStack_; RadiographyScene& scene_; + RadiographyWidget& widget_; + ImageInterpolation initialWidgetInterpolation_; int clickX_; int clickY_; Action leftAction_; @@ -62,6 +67,8 @@ public: RadiographyWindowingTracker(UndoRedoStack& undoRedoStack, RadiographyScene& scene, + RadiographyWidget& widget, + ImageInterpolation interpolationDuringTracking, int x, int y, Action leftAction, diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Scene2D/ICompositor.h --- a/Framework/Scene2D/ICompositor.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Scene2D/ICompositor.h Tue Oct 15 10:54:53 2019 +0200 @@ -1,29 +1,29 @@ -#pragma once - -#include -#include -#include - -namespace OrthancStone -{ - class ICompositor : public boost::noncopyable - { - - public: - virtual ~ICompositor() {} - - virtual unsigned int GetCanvasWidth() const = 0; - - virtual unsigned int GetCanvasHeight() const = 0; - - virtual void Refresh() = 0; - -#if ORTHANC_ENABLE_LOCALE == 1 - virtual void SetFont(size_t index, - Orthanc::EmbeddedResources::FileResourceId resource, - unsigned int fontSize, - Orthanc::Encoding codepage) = 0; -#endif - - }; -} +#pragma once + +#include +#include +#include + +namespace OrthancStone +{ + class ICompositor : public boost::noncopyable + { + public: + virtual ~ICompositor() + { + } + + virtual unsigned int GetCanvasWidth() const = 0; + + virtual unsigned int GetCanvasHeight() const = 0; + + virtual void Refresh() = 0; + +#if ORTHANC_ENABLE_LOCALE == 1 + virtual void SetFont(size_t index, + Orthanc::EmbeddedResources::FileResourceId resource, + unsigned int fontSize, + Orthanc::Encoding codepage) = 0; +#endif + }; +} diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Scene2D/Internals/OpenGLLookupTableTextureRenderer.cpp --- a/Framework/Scene2D/Internals/OpenGLLookupTableTextureRenderer.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Scene2D/Internals/OpenGLLookupTableTextureRenderer.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -21,6 +21,8 @@ #include "OpenGLLookupTableTextureRenderer.h" +#include + namespace OrthancStone { namespace Internals diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Scene2DViewport/AngleMeasureTool.cpp --- a/Framework/Scene2DViewport/AngleMeasureTool.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Scene2DViewport/AngleMeasureTool.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -22,6 +22,7 @@ #include "MeasureToolsToolbox.h" #include "EditAngleMeasureTracker.h" #include "LayerHolder.h" +#include "../StoneException.h" #include diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Scene2DViewport/EditAngleMeasureTracker.cpp --- a/Framework/Scene2DViewport/EditAngleMeasureTracker.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Scene2DViewport/EditAngleMeasureTracker.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -21,6 +21,8 @@ #include "EditAngleMeasureTracker.h" #include "EditAngleMeasureCommand.h" +#include "../StoneException.h" + namespace OrthancStone { EditAngleMeasureTracker::EditAngleMeasureTracker( diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Scene2DViewport/EditLineMeasureTracker.cpp --- a/Framework/Scene2DViewport/EditLineMeasureTracker.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Scene2DViewport/EditLineMeasureTracker.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -21,6 +21,8 @@ #include "EditLineMeasureTracker.h" #include "EditLineMeasureCommand.h" +#include "../StoneException.h" + namespace OrthancStone { diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Scene2DViewport/LineMeasureTool.cpp --- a/Framework/Scene2DViewport/LineMeasureTool.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Scene2DViewport/LineMeasureTool.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -22,6 +22,7 @@ #include "MeasureToolsToolbox.h" #include "EditLineMeasureTracker.h" #include "LayerHolder.h" +#include "../StoneException.h" #include diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Scene2DViewport/MeasureCommands.cpp --- a/Framework/Scene2DViewport/MeasureCommands.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Scene2DViewport/MeasureCommands.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -71,8 +71,8 @@ DeleteMeasureCommand::DeleteMeasureCommand(boost::shared_ptr measureTool, boost::weak_ptr controllerW) : MeasureCommand(controllerW) + , mementoOriginal_(measureTool->GetMemento()) , measureTool_(measureTool) - , mementoOriginal_(measureTool->GetMemento()) , mementoModified_(measureTool->GetMemento()) { GetMeasureTool()->Disable(); diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Scene2DViewport/MeasureToolsToolbox.cpp --- a/Framework/Scene2DViewport/MeasureToolsToolbox.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Scene2DViewport/MeasureToolsToolbox.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -25,6 +25,7 @@ #include "../Scene2D/TextSceneLayer.h" #include "../Scene2D/Scene2D.h" +#include "../StoneException.h" #include diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Scene2DViewport/ViewportController.cpp --- a/Framework/Scene2DViewport/ViewportController.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Scene2DViewport/ViewportController.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -113,7 +113,7 @@ bool ViewportController::HandlePointerEvent(PointerEvent e) { - throw StoneException(ErrorCode_NotImplemented); + throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); } std::vector > ViewportController::HitTestMeasureTools( @@ -168,8 +168,12 @@ void ViewportController::FitContent() { - viewport_.GetScene().FitContent(viewport_.GetCanvasWidth(), viewport_.GetCanvasHeight()); - BroadcastMessage(SceneTransformChanged(*this)); + if (viewport_.HasCompositor()) + { + const ICompositor& compositor = viewport_.GetCompositor(); + viewport_.GetScene().FitContent(compositor.GetCanvasWidth(), compositor.GetCanvasHeight()); + BroadcastMessage(SceneTransformChanged(*this)); + } } void ViewportController::AddMeasureTool(boost::shared_ptr measureTool) @@ -219,4 +223,3 @@ return TEXT_CENTER_DISTANCE_CANVAS_COORD * GetCanvasToSceneFactor(); } } - diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/StoneException.h --- a/Framework/StoneException.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/StoneException.h Tue Oct 15 10:54:53 2019 +0200 @@ -36,9 +36,6 @@ ErrorCode_ApplicationException, // this StoneException is specific to an application (and should have its own internal error code) ErrorCode_NotImplemented, // case not implemented - ErrorCode_PromiseSingleSuccessHandler, // a Promise can only have a single success handler - ErrorCode_PromiseSingleFailureHandler, // a Promise can only have a single failure handler - ErrorCode_CanOnlyAddOneLayerAtATime, ErrorCode_CommandJsonInvalidFormat, ErrorCode_WebGLContextLost, @@ -46,7 +43,6 @@ }; - class StoneException { protected: @@ -70,71 +66,6 @@ return "TODO: EnumerationToString for StoneException"; } }; - - class OpenGLContextLostException : public StoneException - { - public: - explicit OpenGLContextLostException(void* context) - : StoneException(ErrorCode_WebGLContextLost) - , context_(context) - { - } - virtual const char* What() const - { - return "The OpenGL/WebGL context has been lost!"; - } - void* context_; - }; - - class StoneOrthancException : public StoneException - { - protected: - Orthanc::OrthancException& orthancException_; - - public: - explicit StoneOrthancException(Orthanc::OrthancException& orthancException) : - StoneException(ErrorCode_OrthancError), - orthancException_(orthancException) - { - } - - Orthanc::ErrorCode GetOrthancErrorCode() const - { - return orthancException_.GetErrorCode(); - } - - virtual const char* What() const - { - return orthancException_.What(); - } - }; - - class StoneApplicationException : public StoneException - { - protected: - int applicationErrorCode_; - mutable std::string errorMessage_; - - public: - explicit StoneApplicationException(int applicationErrorCode) : - StoneException(ErrorCode_ApplicationException), - applicationErrorCode_(applicationErrorCode) - { - } - - int GetApplicationErrorCode() const - { - return applicationErrorCode_; - } - - virtual const char* What() const - { - if (errorMessage_.size() == 0) - errorMessage_ = boost::lexical_cast(applicationErrorCode_); - - return errorMessage_.c_str(); - } - }; } // See https://isocpp.org/wiki/faq/misc-technical-issues#macros-with-multi-stmts @@ -163,14 +94,6 @@ - - - - - - - - /* Explanation: diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/StoneInitialization.cpp --- a/Framework/StoneInitialization.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/StoneInitialization.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -28,7 +28,7 @@ #endif #if ORTHANC_ENABLE_SDL == 1 -# include "../Applications/Sdl/SdlWindow.h" +# include "Viewport/SdlWindow.h" #endif #if ORTHANC_ENABLE_CURL == 1 diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Toolbox/AffineTransform2D.h --- a/Framework/Toolbox/AffineTransform2D.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Toolbox/AffineTransform2D.h Tue Oct 15 10:54:53 2019 +0200 @@ -77,6 +77,7 @@ const AffineTransform2D& c, const AffineTransform2D& d); + // transformations are applied right to left: e is the first transfo applied, a is the last one static AffineTransform2D Combine(const AffineTransform2D& a, const AffineTransform2D& b, const AffineTransform2D& c, diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Viewport/IViewport.h --- a/Framework/Viewport/IViewport.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Viewport/IViewport.h Tue Oct 15 10:54:53 2019 +0200 @@ -42,32 +42,10 @@ virtual void Refresh() = 0; - virtual unsigned int GetCanvasWidth() const = 0; - - virtual unsigned int GetCanvasHeight() const = 0; - - virtual const std::string& GetCanvasIdentifier() const = 0; - - virtual ScenePoint2D GetPixelCenterCoordinates(int x, int y) const = 0; - - virtual bool IsContextLost() = 0; - - virtual void* DebugGetInternalContext() const = 0; + virtual ScenePoint2D GetPixelCenterCoordinates(int x, int y) = 0; -#if ORTHANC_ENABLE_LOCALE == 1 - virtual void SetFont(size_t index, - Orthanc::EmbeddedResources::FileResourceId resource, - unsigned int fontSize, - Orthanc::Encoding codepage) = 0; -#endif + virtual bool HasCompositor() const = 0; - protected: - virtual ICompositor* GetCompositor() = 0; - - virtual const ICompositor* GetCompositor() const - { - IViewport* self = const_cast(this); - return self->GetCompositor(); - } + virtual ICompositor& GetCompositor() = 0; }; } diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Viewport/SdlViewport.cpp --- a/Framework/Viewport/SdlViewport.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Viewport/SdlViewport.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -30,7 +30,6 @@ unsigned int width, unsigned int height, bool allowDpiScaling) : - SdlViewport(title), context_(title, width, height, allowDpiScaling) { compositor_.reset(new OpenGLCompositor(context_, GetScene())); @@ -41,134 +40,28 @@ unsigned int height, boost::shared_ptr& scene, bool allowDpiScaling) : - SdlViewport(title, scene), + SdlViewport(scene), context_(title, width, height, allowDpiScaling) { compositor_.reset(new OpenGLCompositor(context_, GetScene())); } - - void* SdlOpenGLViewport::DebugGetInternalContext() const - { - return context_.DebugGetInternalContext(); - } - - bool SdlOpenGLViewport::IsContextLost() { - return context_.IsContextLost(); - } - - bool SdlOpenGLViewport::OpenGLContextLost() - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - - bool SdlOpenGLViewport::OpenGLContextRestored() - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - - void SdlOpenGLViewport::DisableCompositor() - { - compositor_.reset(NULL); - } - - void SdlOpenGLViewport::RestoreCompositor() - { - // the context must have been restored! - ORTHANC_ASSERT(!context_.IsContextLost()); - - if (compositor_.get() == NULL) - { - compositor_.reset(new OpenGLCompositor(context_, GetScene())); - } - else - { - std::string windowTitle(SDL_GetWindowTitle(GetWindow().GetObject())); - LOG(WARNING) << "RestoreCompositor() called for \"" << windowTitle << "\" while it was NOT lost! Nothing done."; - } - } - - // extern bool Debug_MustContextBeRestored(std::string title); - // extern void Debug_Context_ClearRestoreFlag(std::string title); - // extern void Debug_Context_ClearKillFlag(std::string title); - - bool Debug_SdlOpenGLViewport_Refresh_BP = false; - void SdlOpenGLViewport::Refresh() { - // - // try to restore the context if requested - // Debug_Context_ClearRestoreFlag - // Debug_SdlOpenGLViewport_Refresh_BP = true; - // try - // { - // if (Debug_MustContextBeRestored(GetCanvasIdentifier())) - // { - // // to prevent a bug where the context is both labelled as "to be lost" and "to be restored" - // // (occurs when one is hammering away at the keyboard like there's no tomorrow) - // Debug_Context_ClearKillFlag(GetCanvasIdentifier()); - // // this is called manually for loss/restore simulation - // context_.RestoreLostContext(); - // RestoreCompositor(); - // Debug_Context_ClearRestoreFlag(GetCanvasIdentifier()); - // } - // } - // catch (const OpenGLContextLostException& e) - // { - // LOG(ERROR) << "OpenGLContextLostException in SdlOpenGLViewport::Refresh() part 1"; - // } - // Debug_SdlOpenGLViewport_Refresh_BP = false; - // - - try - { - // the compositor COULD be dead! - if (GetCompositor()) - GetCompositor()->Refresh(); - } - catch (const OpenGLContextLostException& e) - { - // we need to wait for the "context restored" callback - LOG(WARNING) << "Context " << std::hex << e.context_ << " is lost! Compositor will be disabled."; - DisableCompositor(); - - // - // in case this was externally triggered... - //Debug_Context_ClearKillFlag(GetCanvasIdentifier()); - // - } - catch (...) - { - // something else nasty happened - throw; - } + compositor_->Refresh(); } - - - SdlCairoViewport::SdlCairoViewport(const char* title, unsigned int width, unsigned int height, bool allowDpiScaling) : - SdlViewport(title), window_(title, width, height, false /* enable OpenGL */, allowDpiScaling), compositor_(GetScene(), width, height) { UpdateSdlSurfaceSize(width, height); } - void SdlCairoViewport::DisableCompositor() - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - - void SdlCairoViewport::RestoreCompositor() - { - throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented); - } - SdlCairoViewport::~SdlCairoViewport() { if (sdlSurface_) @@ -179,7 +72,7 @@ void SdlCairoViewport::Refresh() { - GetCompositor()->Refresh(); + compositor_.Refresh(); window_.Render(sdlSurface_); } @@ -206,5 +99,4 @@ throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); } } - } diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Viewport/SdlViewport.h --- a/Framework/Viewport/SdlViewport.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Viewport/SdlViewport.h Tue Oct 15 10:54:53 2019 +0200 @@ -36,7 +36,7 @@ # error Support for OpenGL is disabled #endif -#include "../../Applications/Sdl/SdlOpenGLContext.h" +#include "../OpenGL/SdlOpenGLContext.h" #include "../Scene2D/OpenGLCompositor.h" #include "../Scene2D/CairoCompositor.h" #include "ViewportBase.h" @@ -46,23 +46,21 @@ class SdlViewport : public ViewportBase { public: - SdlViewport(const std::string& identifier) - : ViewportBase(identifier) - {} + SdlViewport() + { + } - SdlViewport(const std::string& identifier, - boost::shared_ptr& scene) - : ViewportBase(identifier, scene) + SdlViewport(boost::shared_ptr& scene) : + ViewportBase(scene) { - } virtual SdlWindow& GetWindow() = 0; virtual void UpdateSize(unsigned int width, unsigned int height) = 0; + }; - }; class SdlOpenGLViewport : public SdlViewport { @@ -87,25 +85,21 @@ return context_.GetWindow(); } - virtual void* DebugGetInternalContext() const ORTHANC_OVERRIDE; - - virtual bool IsContextLost() ORTHANC_OVERRIDE; - bool OpenGLContextLost(); - bool OpenGLContextRestored(); + virtual void Refresh() ORTHANC_OVERRIDE; virtual void UpdateSize(unsigned int width, unsigned int height) ORTHANC_OVERRIDE { // nothing to do in OpenGL, the OpenGLCompositor::UpdateSize will be called automatically } - virtual void Refresh() ORTHANC_OVERRIDE; - protected: - virtual void DisableCompositor() ORTHANC_OVERRIDE; - virtual void RestoreCompositor() ORTHANC_OVERRIDE; + virtual bool HasCompositor() const ORTHANC_OVERRIDE + { + return true; + } - virtual ICompositor* GetCompositor() ORTHANC_OVERRIDE + virtual ICompositor& GetCompositor() ORTHANC_OVERRIDE { - return compositor_.get(); + return *compositor_.get(); } }; @@ -117,6 +111,10 @@ CairoCompositor compositor_; SDL_Surface* sdlSurface_; + private: + void UpdateSdlSurfaceSize(unsigned int width, + unsigned int height); + public: SdlCairoViewport(const char* title, unsigned int width, @@ -135,22 +133,20 @@ { return window_; } - - virtual void DisableCompositor() ORTHANC_OVERRIDE; - virtual void RestoreCompositor() ORTHANC_OVERRIDE; - + virtual void Refresh() ORTHANC_OVERRIDE; virtual void UpdateSize(unsigned int width, unsigned int height) ORTHANC_OVERRIDE; - protected: - virtual ICompositor* GetCompositor() ORTHANC_OVERRIDE + + virtual bool HasCompositor() const ORTHANC_OVERRIDE { - return &compositor_; + return true; } - private: - void UpdateSdlSurfaceSize(unsigned int width, - unsigned int height); + virtual ICompositor& GetCompositor() ORTHANC_OVERRIDE + { + return compositor_; + } }; } diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Viewport/SdlWindow.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Viewport/SdlWindow.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -0,0 +1,201 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 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 "SdlWindow.h" + +#if ORTHANC_ENABLE_SDL == 1 + +#include +#include + +#ifdef WIN32 +#include // for SetProcessDpiAware +#endif +// WIN32 + +#include + +namespace OrthancStone +{ + SdlWindow::SdlWindow(const char* title, + unsigned int width, + unsigned int height, + bool enableOpenGl, + bool allowDpiScaling) : + maximized_(false) + { + // TODO Understand why, with SDL_WINDOW_OPENGL + MinGW32 + Release + // build mode, the application crashes whenever the SDL window is + // resized or maximized + + uint32_t windowFlags, rendererFlags; + if (enableOpenGl) + { + windowFlags = SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE; + rendererFlags = SDL_RENDERER_ACCELERATED; + } + else + { + windowFlags = SDL_WINDOW_RESIZABLE; + rendererFlags = SDL_RENDERER_SOFTWARE; + } + +// TODO: probably required on MacOS X, too +#if defined(WIN32) && (_WIN32_WINNT >= 0x0600) + if (!allowDpiScaling) + { + // if we do NOT allow DPI scaling, it means an SDL pixel will be a real + // monitor pixel. This is needed for high-DPI applications + + // Enable high-DPI support on Windows + + // THE FOLLOWING HAS BEEN COMMENTED OUT BECAUSE IT WILL CRASH UNDER + // OLD WINDOWS VERSIONS + // ADD THIS AT THE TOP TO ENABLE IT: + // + //#pragma comment(lib, "Shcore.lib") THIS IS ONLY REQUIRED FOR SetProcessDpiAwareness + //#include + //#include THIS IS ONLY REQUIRED FOR SetProcessDpiAwareness + //#include THIS IS ONLY REQUIRED FOR SetProcessDpiAwareness + // SetProcessDpiAwareness(PROCESS_PER_MONITOR_DPI_AWARE); + + // This is supported on Vista+ + SetProcessDPIAware(); + + windowFlags |= SDL_WINDOW_ALLOW_HIGHDPI; + } +#endif +// WIN32 + + window_ = SDL_CreateWindow(title, + SDL_WINDOWPOS_UNDEFINED, + SDL_WINDOWPOS_UNDEFINED, + width, height, windowFlags); + + if (window_ == NULL) + { + LOG(ERROR) << "Cannot create the SDL window: " << SDL_GetError(); + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + + renderer_ = SDL_CreateRenderer(window_, -1, rendererFlags); + if (!renderer_) + { + LOG(ERROR) << "Cannot create the SDL renderer: " << SDL_GetError(); + SDL_DestroyWindow(window_); + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + + + SdlWindow::~SdlWindow() + { + if (renderer_ != NULL) + { + SDL_DestroyRenderer(renderer_); + } + + if (window_ != NULL) + { + SDL_DestroyWindow(window_); + } + } + + + unsigned int SdlWindow::GetWidth() const + { + int w = -1; + SDL_GetWindowSize(window_, &w, NULL); + + if (w < 0) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + else + { + return static_cast(w); + } + } + + + unsigned int SdlWindow::GetHeight() const + { + int h = -1; + SDL_GetWindowSize(window_, NULL, &h); + + if (h < 0) + { + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + else + { + return static_cast(h); + } + } + + + void SdlWindow::Render(SDL_Surface* surface) + { + //SDL_RenderClear(renderer_); + + SDL_Texture *texture = SDL_CreateTextureFromSurface(renderer_, surface); + if (texture != NULL) + { + SDL_RenderCopy(renderer_, texture, NULL, NULL); + SDL_DestroyTexture(texture); + } + + SDL_RenderPresent(renderer_); + } + + + void SdlWindow::ToggleMaximize() + { + if (maximized_) + { + SDL_RestoreWindow(window_); + maximized_ = false; + } + else + { + SDL_MaximizeWindow(window_); + maximized_ = true; + } + } + + + void SdlWindow::GlobalInitialize() + { + if (SDL_Init(SDL_INIT_VIDEO) != 0) + { + LOG(ERROR) << "Cannot initialize SDL"; + throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); + } + } + + + void SdlWindow::GlobalFinalize() + { + SDL_Quit(); + } +} + +#endif diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Viewport/SdlWindow.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Framework/Viewport/SdlWindow.h Tue Oct 15 10:54:53 2019 +0200 @@ -0,0 +1,67 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2019 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 + +#if ORTHANC_ENABLE_SDL == 1 + +#include +#include +#include + +namespace OrthancStone +{ + class SdlWindow : public boost::noncopyable + { + private: + SDL_Window *window_; + SDL_Renderer *renderer_; + bool maximized_; + + public: + SdlWindow(const char* title, + unsigned int width, + unsigned int height, + bool enableOpenGl, + bool allowDpiScaling = true); + + ~SdlWindow(); + + SDL_Window *GetObject() const + { + return window_; + } + + unsigned int GetWidth() const; + + unsigned int GetHeight() const; + + void Render(SDL_Surface* surface); + + void ToggleMaximize(); + + static void GlobalInitialize(); + + static void GlobalFinalize(); + }; +} + +#endif diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Viewport/ViewportBase.cpp --- a/Framework/Viewport/ViewportBase.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Viewport/ViewportBase.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -26,16 +26,13 @@ namespace OrthancStone { - ViewportBase::ViewportBase(const std::string& identifier) : - identifier_(identifier), + ViewportBase::ViewportBase() : scene_(boost::make_shared()) { } - ViewportBase::ViewportBase(const std::string& identifier, - boost::shared_ptr& scene) : - identifier_(identifier), + ViewportBase::ViewportBase(boost::shared_ptr& scene) : scene_(scene) { if (scene.get() == NULL) @@ -45,10 +42,18 @@ } - ScenePoint2D ViewportBase::GetPixelCenterCoordinates(int x, int y) const + ScenePoint2D ViewportBase::GetPixelCenterCoordinates(int x, int y) { - return ScenePoint2D( - static_cast(x) + 0.5 - static_cast(GetCanvasWidth()) / 2.0, - static_cast(y) + 0.5 - static_cast(GetCanvasHeight()) / 2.0); + if (HasCompositor()) + { + const ICompositor& compositor = GetCompositor(); + return ScenePoint2D( + static_cast(x) + 0.5 - static_cast(compositor.GetCanvasWidth()) / 2.0, + static_cast(y) + 0.5 - static_cast(compositor.GetCanvasHeight()) / 2.0); + } + else + { + return ScenePoint2D(0, 0); + } } } diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Viewport/ViewportBase.h --- a/Framework/Viewport/ViewportBase.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Viewport/ViewportBase.h Tue Oct 15 10:54:53 2019 +0200 @@ -28,55 +28,19 @@ { class ViewportBase : public IViewport { - public: - ViewportBase(const std::string& identifier); + private: + boost::shared_ptr scene_; - ViewportBase(const std::string& identifier, - boost::shared_ptr& scene); + public: + ViewportBase(); + + ViewportBase(boost::shared_ptr& scene); virtual Scene2D& GetScene() ORTHANC_OVERRIDE { return *scene_; } - virtual const std::string& GetCanvasIdentifier() const ORTHANC_OVERRIDE - { - return identifier_; - } - - virtual ScenePoint2D GetPixelCenterCoordinates(int x, int y) const ORTHANC_OVERRIDE; - - virtual unsigned int GetCanvasWidth() const ORTHANC_OVERRIDE - { - if (GetCompositor()) - return GetCompositor()->GetCanvasWidth(); - else - return 0; - } - - virtual unsigned int GetCanvasHeight() const ORTHANC_OVERRIDE - { - if (GetCompositor()) - return GetCompositor()->GetCanvasHeight(); - else - return 0; - } - -#if ORTHANC_ENABLE_LOCALE == 1 - virtual void SetFont(size_t index, - Orthanc::EmbeddedResources::FileResourceId resource, - unsigned int fontSize, - Orthanc::Encoding codepage) ORTHANC_OVERRIDE - { - return GetCompositor()->SetFont(index, resource, fontSize, codepage); - } -#endif - - private: - std::string identifier_; - boost::shared_ptr scene_; - protected: - virtual void RestoreCompositor() = 0; - virtual void DisableCompositor() = 0; + virtual ScenePoint2D GetPixelCenterCoordinates(int x, int y) ORTHANC_OVERRIDE; }; } diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Viewport/WebAssemblyViewport.cpp --- a/Framework/Viewport/WebAssemblyViewport.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Viewport/WebAssemblyViewport.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -20,6 +20,9 @@ #include "WebAssemblyViewport.h" + +#include "../StoneException.h" + #include namespace OrthancStone @@ -82,14 +85,31 @@ void WebAssemblyOpenGLViewport::DisableCompositor() { - compositor_.reset(NULL); + compositor_.reset(); + } + + ICompositor& WebAssemblyOpenGLViewport::GetCompositor() + { + if (compositor_.get() == NULL) + { + // "HasCompositor()" should have been called + throw Orthanc::OrthancException(Orthanc::ErrorCode_BadSequenceOfCalls); + } + else + { + return *compositor_; + } } void WebAssemblyOpenGLViewport::Refresh() { try { - if (!GetCompositor()) + if (HasCompositor()) + { + GetCompositor().Refresh(); + } + else { // this block was added because of (perceived?) bugs in the // browser where the WebGL contexts are NOT automatically restored @@ -99,22 +119,27 @@ //LOG(ERROR) << "About to call WebAssemblyOpenGLContext::TryRecreate()."; //LOG(ERROR) << "Before calling it, isContextLost == " << context_.IsContextLost(); - if (!context_.IsContextLost()) { + if (!context_.IsContextLost()) + { LOG(TRACE) << "Context restored!"; //LOG(ERROR) << "After calling it, isContextLost == " << context_.IsContextLost(); RestoreCompositor(); UpdateSize(); } } - if (GetCompositor()) { - GetCompositor()->Refresh(); + } + catch (const StoneException& e) + { + if (e.GetErrorCode() == ErrorCode_WebGLContextLost) + { + LOG(WARNING) << "Context is lost! Compositor will be disabled."; + DisableCompositor(); + // we now need to wait for the "context restored" callback } - } - catch (const OpenGLContextLostException& e) - { - LOG(WARNING) << "Context " << std::hex << e.context_ << " is lost! Compositor will be disabled."; - DisableCompositor(); - // we now need to wait for the "context restored" callback + else + { + throw; + } } catch (...) { @@ -122,11 +147,6 @@ throw; } } - - bool WebAssemblyOpenGLViewport::IsContextLost() - { - return context_.IsContextLost(); - } void WebAssemblyOpenGLViewport::RestoreCompositor() { @@ -155,7 +175,7 @@ // maybe the context has already been restored by other means (the // Refresh() function) - if (!GetCompositor()) + if (!HasCompositor()) { RestoreCompositor(); UpdateSize(); @@ -163,11 +183,6 @@ return false; } - void* WebAssemblyOpenGLViewport::DebugGetInternalContext() const - { - return context_.DebugGetInternalContext(); - } - void WebAssemblyOpenGLViewport::RegisterContextCallbacks() { #if 0 @@ -248,6 +263,6 @@ void WebAssemblyCairoViewport::Refresh() { LOG(INFO) << "refreshing cairo viewport, TODO: blit to the canvans.getContext('2d')"; - GetCompositor()->Refresh(); + GetCompositor().Refresh(); } } diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Viewport/WebAssemblyViewport.h --- a/Framework/Viewport/WebAssemblyViewport.h Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Viewport/WebAssemblyViewport.h Tue Oct 15 10:54:53 2019 +0200 @@ -30,19 +30,29 @@ { class WebAssemblyViewport : public ViewportBase { + private: + std::string canvasIdentifier_; + public: - WebAssemblyViewport(const std::string& identifier) - : ViewportBase(identifier) + WebAssemblyViewport(const std::string& canvasIdentifier) : + canvasIdentifier_(canvasIdentifier) { } - WebAssemblyViewport(const std::string& identifier, - boost::shared_ptr& scene) - : ViewportBase(identifier, scene) + WebAssemblyViewport(const std::string& canvasIdentifier, + boost::shared_ptr& scene) : + ViewportBase(scene), + canvasIdentifier_(canvasIdentifier) { } + + const std::string& GetCanvasIdentifier() const + { + return canvasIdentifier_; + } }; + class WebAssemblyOpenGLViewport : public WebAssemblyViewport { private: @@ -58,15 +68,15 @@ // This function must be called each time the browser window is resized void UpdateSize(); - virtual ICompositor* GetCompositor() ORTHANC_OVERRIDE + virtual bool HasCompositor() const ORTHANC_OVERRIDE { - return compositor_.get(); + return (compositor_.get() != NULL); } + + virtual ICompositor& GetCompositor() ORTHANC_OVERRIDE; virtual void Refresh() ORTHANC_OVERRIDE; - virtual bool IsContextLost() ORTHANC_OVERRIDE; - // this does NOT return whether the context is lost! This is called to // tell Stone that the context has been lost bool OpenGLContextLost(); @@ -74,16 +84,14 @@ // This should be called to indicate that the context has been lost bool OpenGLContextRestored(); - - virtual void* DebugGetInternalContext() const ORTHANC_OVERRIDE; - private: - virtual void DisableCompositor() ORTHANC_OVERRIDE; - virtual void RestoreCompositor() ORTHANC_OVERRIDE; + void DisableCompositor(); + void RestoreCompositor(); void RegisterContextCallbacks(); }; + class WebAssemblyCairoViewport : public WebAssemblyViewport { private: @@ -98,12 +106,16 @@ void UpdateSize(); - virtual void Refresh(); + virtual void Refresh() ORTHANC_OVERRIDE; - virtual ICompositor* GetCompositor() + virtual bool HasCompositor() const ORTHANC_OVERRIDE { - return &compositor_; + return true; + } + + virtual ICompositor& GetCompositor() ORTHANC_OVERRIDE + { + return compositor_; } }; - } diff -r eb28dfe432f7 -r 2d6237221ff1 Framework/Volumes/DicomVolumeImage.cpp --- a/Framework/Volumes/DicomVolumeImage.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Framework/Volumes/DicomVolumeImage.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -21,8 +21,6 @@ #include "DicomVolumeImage.h" -#include "../StoneException.h" - #include diff -r eb28dfe432f7 -r 2d6237221ff1 Resources/CMake/LinuxStandardBaseUic.py --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/CMake/LinuxStandardBaseUic.py Tue Oct 15 10:54:53 2019 +0200 @@ -0,0 +1,36 @@ +#!/usr/bin/env python + +import subprocess +import sys + +if len(sys.argv) <= 1: + sys.stderr.write('Please provide arguments for uic\n') + sys.exit(-1) + +path = '' +pos = 1 +while pos < len(sys.argv): + if sys.argv[pos].startswith('-'): + pos += 2 + else: + path = sys.argv[pos] + break + +if len(path) == 0: + sys.stderr.write('Unable to find the input file in the arguments to uic\n') + sys.exit(-1) + +with open(path, 'r') as f: + lines = f.read().split('\n') + if (len(lines) > 1 and + lines[0].startswith('" + # header that is automatically added by Qt Creator + set(QT_UIC_EXECUTABLE ${CMAKE_CURRENT_LIST_DIR}/LinuxStandardBaseUic.py) + + set(QT_MOC_EXECUTABLE ${LSB_PATH}/bin/moc) + + include_directories( + ${LSB_PATH}/include/QtCore + ${LSB_PATH}/include/QtGui + ${LSB_PATH}/include/QtOpenGL ) - # Create aliases for the CMake commands - macro(ORTHANC_QT_WRAP_UI) - QT5_WRAP_UI(${ARGN}) - endmacro() + link_libraries(QtCore QtGui QtOpenGL) + + + ## + ## This part is adapted from file "Qt4Macros.cmake" shipped with + ## CMake 3.5.1, released under the following license: + ## + ##============================================================================= + ## Copyright 2005-2009 Kitware, Inc. + ## + ## Distributed under the OSI-approved BSD License (the "License"); + ## see accompanying file Copyright.txt for details. + ## + ## This software is distributed WITHOUT ANY WARRANTY; without even the + ## implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + ## See the License for more information. + ##============================================================================= + ## + macro (ORTHANC_QT_WRAP_UI outfiles) + QT4_EXTRACT_OPTIONS(ui_files ui_options ui_target ${ARGN}) + foreach (it ${ui_files}) + get_filename_component(outfile ${it} NAME_WE) + get_filename_component(infile ${it} ABSOLUTE) + set(outfile ${CMAKE_CURRENT_BINARY_DIR}/ui_${outfile}.h) + add_custom_command(OUTPUT ${outfile} + COMMAND ${QT_UIC_EXECUTABLE} + ARGS ${ui_options} -o ${outfile} ${infile} + MAIN_DEPENDENCY ${infile} VERBATIM) + set(${outfiles} ${${outfiles}} ${outfile}) + endforeach () + endmacro () - macro(ORTHANC_QT_WRAP_CPP) - QT5_WRAP_CPP(${ARGN}) - endmacro() - + macro (ORTHANC_QT_WRAP_CPP outfiles ) + QT4_GET_MOC_FLAGS(moc_flags) + QT4_EXTRACT_OPTIONS(moc_files moc_options moc_target ${ARGN}) + foreach (it ${moc_files}) + get_filename_component(outfile ${it} NAME_WE) + get_filename_component(infile ${it} ABSOLUTE) + set(outfile ${CMAKE_CURRENT_BINARY_DIR}/moc_${outfile}.cxx) + add_custom_command(OUTPUT ${outfile} + COMMAND ${QT_MOC_EXECUTABLE} + ARGS ${infile} "${moc_flags}" -o ${outfile} + MAIN_DEPENDENCY ${infile} VERBATIM) + set(${outfiles} ${${outfiles}} ${outfile}) + endforeach () + endmacro () + ## + ## End of "Qt4Macros.cmake" adaptation. + ## + else() - message("Qt5 has not been found, trying with Qt4") - find_package(Qt4 REQUIRED QtGui) - link_libraries( - Qt4::QtGui - ) + # Not using Linux Standard Base + # Find the QtWidgets library + find_package(Qt5Widgets QUIET) + + if (Qt5Widgets_FOUND) + message("Qt5 has been detected") + find_package(Qt5Core REQUIRED) + link_libraries( + Qt5::Widgets + Qt5::Core + ) - # Create aliases for the CMake commands - macro(ORTHANC_QT_WRAP_UI) - QT4_WRAP_UI(${ARGN}) - endmacro() - - macro(ORTHANC_QT_WRAP_CPP) - QT4_WRAP_CPP(${ARGN}) - endmacro() - + if (ENABLE_OPENGL) + find_package(Qt5OpenGL REQUIRED) + link_libraries( + Qt5::OpenGL + ) + endif() + + # Create aliases for the CMake commands + macro(ORTHANC_QT_WRAP_UI) + QT5_WRAP_UI(${ARGN}) + endmacro() + + macro(ORTHANC_QT_WRAP_CPP) + QT5_WRAP_CPP(${ARGN}) + endmacro() + + else() + message("Qt5 has not been found, trying with Qt4") + find_package(Qt4 REQUIRED QtGui) + link_libraries( + Qt4::QtGui + ) + + if (ENABLE_OPENGL) + find_package(Qt4 REQUIRED QtOpenGL) + link_libraries( + Qt4::QtOpenGL + ) + endif() + + # Create aliases for the CMake commands + macro(ORTHANC_QT_WRAP_UI) + QT4_WRAP_UI(${ARGN}) + endmacro() + + macro(ORTHANC_QT_WRAP_CPP) + QT4_WRAP_CPP(${ARGN}) + endmacro() + endif() endif() -list(APPEND QT_SOURCES - ${ORTHANC_STONE_ROOT}/Applications/Qt/QCairoWidget.cpp - ) - -ORTHANC_QT_WRAP_CPP(QT_SOURCES - ${ORTHANC_STONE_ROOT}/Applications/Qt/QCairoWidget.h - ) - if (ENABLE_STONE_DEPRECATED) list(APPEND QT_SOURCES + ${ORTHANC_STONE_ROOT}/Applications/Qt/QCairoWidget.cpp + ${ORTHANC_STONE_ROOT}/Applications/Qt/QStoneMainWindow.cpp ${ORTHANC_STONE_ROOT}/Applications/Qt/QtStoneApplicationRunner.cpp - ${ORTHANC_STONE_ROOT}/Applications/Qt/QStoneMainWindow.cpp ) ORTHANC_QT_WRAP_CPP(QT_SOURCES + ${ORTHANC_STONE_ROOT}/Applications/Qt/QCairoWidget.h ${ORTHANC_STONE_ROOT}/Applications/Qt/QStoneMainWindow.h ) endif() diff -r eb28dfe432f7 -r 2d6237221ff1 Samples/Sdl/FusionMprSdl.cpp --- a/Samples/Sdl/FusionMprSdl.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Samples/Sdl/FusionMprSdl.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -20,7 +20,7 @@ #include "FusionMprSdl.h" -#include "../../Applications/Sdl/SdlOpenGLContext.h" +#include "../../Framework/OpenGL/SdlOpenGLContext.h" #include "../../Framework/StoneInitialization.h" diff -r eb28dfe432f7 -r 2d6237221ff1 Samples/Sdl/TrackerSample.cpp --- a/Samples/Sdl/TrackerSample.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Samples/Sdl/TrackerSample.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -21,7 +21,7 @@ #include "TrackerSampleApp.h" // From Stone -#include "../../Applications/Sdl/SdlOpenGLContext.h" +#include "../../Framework/OpenGL/SdlOpenGLContext.h" #include "../../Framework/Scene2D/CairoCompositor.h" #include "../../Framework/Scene2D/ColorTextureSceneLayer.h" #include "../../Framework/Scene2D/OpenGLCompositor.h" diff -r eb28dfe432f7 -r 2d6237221ff1 Samples/Sdl/TrackerSampleApp.cpp --- a/Samples/Sdl/TrackerSampleApp.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/Samples/Sdl/TrackerSampleApp.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -20,8 +20,7 @@ #include "TrackerSampleApp.h" -#include "../../Applications/Sdl/SdlOpenGLContext.h" - +#include "../../Framework/OpenGL/SdlOpenGLContext.h" #include "../../Framework/Scene2D/CairoCompositor.h" #include "../../Framework/Scene2D/ColorTextureSceneLayer.h" #include "../../Framework/Scene2D/OpenGLCompositor.h" diff -r eb28dfe432f7 -r 2d6237221ff1 UnitTestsSources/TestExceptions.cpp --- a/UnitTestsSources/TestExceptions.cpp Tue Oct 15 10:53:28 2019 +0200 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,43 +0,0 @@ -/** - * Stone of Orthanc - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017-2019 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 "gtest/gtest.h" - -#include "../Framework/StoneException.h" - - - -TEST(StoneExceptions, OrthancToStoneConversion) -{ - bool hasBeenCatched = false; - try { - throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); - } - catch (Orthanc::OrthancException& orthancException) - { - hasBeenCatched = true; - OrthancStone::StoneOrthancException stoneException(orthancException); - ASSERT_EQ(OrthancStone::ErrorCode_OrthancError, stoneException.GetErrorCode()); - ASSERT_EQ(Orthanc::ErrorCode_InternalError, stoneException.GetOrthancErrorCode()); - } - - ASSERT_TRUE(hasBeenCatched); -} diff -r eb28dfe432f7 -r 2d6237221ff1 UnitTestsSources/TestMessageBroker.cpp --- a/UnitTestsSources/TestMessageBroker.cpp Tue Oct 15 10:53:28 2019 +0200 +++ b/UnitTestsSources/TestMessageBroker.cpp Tue Oct 15 10:54:53 2019 +0200 @@ -22,7 +22,6 @@ #include "gtest/gtest.h" #include "Framework/Messages/MessageBroker.h" -#include "Framework/Messages/Promise.h" #include "Framework/Messages/IObservable.h" #include "Framework/Messages/IObserver.h" #include "Framework/Messages/MessageForwarder.h" @@ -82,67 +81,6 @@ observedObject_.RegisterObserverCallback(new MessageForwarder(broker, *this)); } }; - - - class MyPromiseSource : public IObservable - { - Promise* currentPromise_; - - public: - struct MyPromiseMessage: public IMessage - { - ORTHANC_STONE_MESSAGE(__FILE__, __LINE__); - - int increment; - - MyPromiseMessage(int increment) : - increment(increment) - { - } - }; - - MyPromiseSource(MessageBroker& broker) - : IObservable(broker), - currentPromise_(NULL) - {} - - Promise& StartSomethingAsync() - { - currentPromise_ = new Promise(GetBroker()); - return *currentPromise_; - } - - void CompleteSomethingAsyncWithSuccess(int payload) - { - currentPromise_->Success(MyPromiseMessage(payload)); - delete currentPromise_; - } - - void CompleteSomethingAsyncWithFailure(int payload) - { - currentPromise_->Failure(MyPromiseMessage(payload)); - delete currentPromise_; - } - }; - - - class MyPromiseTarget : public IObserver - { - public: - MyPromiseTarget(MessageBroker& broker) - : IObserver(broker) - {} - - void IncrementCounter(const MyPromiseSource::MyPromiseMessage& args) - { - testCounter += args.increment; - } - - void DecrementCounter(const MyPromiseSource::MyPromiseMessage& args) - { - testCounter -= args.increment; - } - }; } @@ -254,60 +192,6 @@ } -TEST(MessageBroker, TestPromiseSuccessFailure) -{ - MessageBroker broker; - MyPromiseSource source(broker); - MyPromiseTarget target(broker); - - // test a successful promise - source.StartSomethingAsync() - .Then(new Callable(target, &MyPromiseTarget::IncrementCounter)) - .Else(new Callable(target, &MyPromiseTarget::DecrementCounter)); - - testCounter = 0; - source.CompleteSomethingAsyncWithSuccess(10); - ASSERT_EQ(10, testCounter); - - // test a failing promise - source.StartSomethingAsync() - .Then(new Callable(target, &MyPromiseTarget::IncrementCounter)) - .Else(new Callable(target, &MyPromiseTarget::DecrementCounter)); - - testCounter = 0; - source.CompleteSomethingAsyncWithFailure(15); - ASSERT_EQ(-15, testCounter); -} - -TEST(MessageBroker, TestPromiseDeleteTarget) -{ - MessageBroker broker; - MyPromiseSource source(broker); - MyPromiseTarget* target = new MyPromiseTarget(broker); - - // create the promise - source.StartSomethingAsync() - .Then(new Callable(*target, &MyPromiseTarget::IncrementCounter)) - .Else(new Callable(*target, &MyPromiseTarget::DecrementCounter)); - - // delete the promise target - delete target; - - // trigger the promise, make sure it does not throw and does not call the callback - testCounter = 0; - source.CompleteSomethingAsyncWithSuccess(10); - ASSERT_EQ(0, testCounter); - - // test a failing promise - source.StartSomethingAsync() - .Then(new Callable(*target, &MyPromiseTarget::IncrementCounter)) - .Else(new Callable(*target, &MyPromiseTarget::DecrementCounter)); - - testCounter = 0; - source.CompleteSomethingAsyncWithFailure(15); - ASSERT_EQ(0, testCounter); -} - #if 0 /* __cplusplus >= 201103L*/ TEST(MessageBroker, TestLambdaSimpleUseCase)