Mercurial > hg > orthanc-stone
diff Resources/Graveyard/Deprecated/Platforms/Wasm/Defaults.cpp @ 1503:553084468225
moving /Deprecated/ to /Resources/Graveyard/Deprecated/
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 30 Jun 2020 11:38:13 +0200 |
parents | Deprecated/Platforms/Wasm/Defaults.cpp@fbc5bfde6c95 |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Graveyard/Deprecated/Platforms/Wasm/Defaults.cpp Tue Jun 30 11:38:13 2020 +0200 @@ -0,0 +1,437 @@ +/** + * Stone of Orthanc + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2020 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 <http://www.gnu.org/licenses/>. + **/ + + +#include "Defaults.h" + +#include "WasmWebService.h" +#include "WasmDelayedCallExecutor.h" +#include "../../../Framework/Deprecated/Widgets/TestCairoWidget.h" +#include "../../../Framework/Deprecated/Viewport/WidgetViewport.h" +#include <Applications/Wasm/StartupParametersBuilder.h> +#include <Platforms/Wasm/WasmPlatformApplicationAdapter.h> +#include <Framework/StoneInitialization.h> +#include <Core/Logging.h> +#include <sstream> + +#include <algorithm> + + +static unsigned int width_ = 0; +static unsigned int height_ = 0; + +/**********************************/ + +static std::unique_ptr<OrthancStone::IStoneApplication> application; +static std::unique_ptr<OrthancStone::WasmPlatformApplicationAdapter> applicationWasmAdapter = NULL; +static std::unique_ptr<OrthancStone::StoneApplicationContext> context; +static OrthancStone::StartupParametersBuilder startupParametersBuilder; +static OrthancStone::MessageBroker broker; + +static OrthancStone::ViewportContentChangedObserver viewportContentChangedObserver_(broker); +static OrthancStone::StatusBar statusBar_; + +static std::list<std::shared_ptr<Deprecated::WidgetViewport>> viewports_; + +std::shared_ptr<Deprecated::WidgetViewport> FindViewportSharedPtr(ViewportHandle viewport) { + for (const auto& v : viewports_) { + if (v.get() == viewport) { + return v; + } + } + assert(false); + return std::shared_ptr<Deprecated::WidgetViewport>(); +} + +#ifdef __cplusplus +extern "C" { +#endif + +#if 0 + // rewrite malloc/free in order to monitor allocations. We actually only monitor large allocations (like images ...) + + size_t bigChunksTotalSize = 0; + std::map<void*, size_t> allocatedBigChunks; + + extern void* emscripten_builtin_malloc(size_t bytes); + extern void emscripten_builtin_free(void* mem); + + void * __attribute__((noinline)) malloc(size_t size) + { + void *ptr = emscripten_builtin_malloc(size); + if (size > 100000) + { + bigChunksTotalSize += size; + printf("++ Allocated %zu bytes, got %p. (%zu MB consumed by big chunks)\n", size, ptr, bigChunksTotalSize/(1024*1024)); + allocatedBigChunks[ptr] = size; + } + return ptr; + } + + void __attribute__((noinline)) free(void *ptr) + { + emscripten_builtin_free(ptr); + + std::map<void*, size_t>::iterator it = allocatedBigChunks.find(ptr); + if (it != allocatedBigChunks.end()) + { + bigChunksTotalSize -= it->second; + printf("-- Freed %zu bytes at %p. (%zu MB consumed by big chunks)\n", it->second, ptr, bigChunksTotalSize/(1024*1024)); + allocatedBigChunks.erase(it); + } + } +#endif // 0 + + using namespace OrthancStone; + + // when WASM needs a C++ viewport + ViewportHandle EMSCRIPTEN_KEEPALIVE CreateCppViewport() { + + std::shared_ptr<Deprecated::WidgetViewport> viewport(new Deprecated::WidgetViewport(broker)); + printf("viewport %x\n", (int)viewport.get()); + + viewports_.push_back(viewport); + + printf("There are now %lu viewports in C++\n", viewports_.size()); + + viewport->SetStatusBar(statusBar_); + + viewport->RegisterObserverCallback( + new Callable<ViewportContentChangedObserver, Deprecated::IViewport::ViewportChangedMessage> + (viewportContentChangedObserver_, &ViewportContentChangedObserver::OnViewportChanged)); + + return viewport.get(); + } + + // when WASM does not need a viewport anymore, it should release it + void EMSCRIPTEN_KEEPALIVE ReleaseCppViewport(ViewportHandle viewport) { + viewports_.remove_if([viewport](const std::shared_ptr<Deprecated::WidgetViewport>& v) { return v.get() == viewport;}); + + printf("There are now %lu viewports in C++\n", viewports_.size()); + } + + void EMSCRIPTEN_KEEPALIVE CreateWasmApplication(ViewportHandle viewport) { + printf("Initializing Stone\n"); + OrthancStone::StoneInitialize(); + printf("CreateWasmApplication\n"); + + application.reset(CreateUserApplication(broker)); + applicationWasmAdapter.reset(CreateWasmApplicationAdapter(broker, application.get())); + Deprecated::WasmWebService::SetBroker(broker); + Deprecated::WasmDelayedCallExecutor::SetBroker(broker); + + startupParametersBuilder.Clear(); + } + + void EMSCRIPTEN_KEEPALIVE SetStartupParameter(const char* keyc, + const char* value) { + startupParametersBuilder.SetStartupParameter(keyc, value); + } + + void EMSCRIPTEN_KEEPALIVE StartWasmApplication(const char* baseUri) { + + printf("StartWasmApplication\n"); + + Orthanc::Logging::SetErrorWarnInfoTraceLoggingFunctions( + stone_console_error, stone_console_warning, + stone_console_info, stone_console_trace); + + // recreate a command line from uri arguments and parse it + boost::program_options::variables_map parameters; + boost::program_options::options_description options; + application->DeclareStartupOptions(options); + startupParametersBuilder.GetStartupParameters(parameters, options); + + context.reset(new OrthancStone::StoneApplicationContext(broker)); + context->SetOrthancBaseUrl(baseUri); + printf("Base URL to Orthanc API: [%s]\n", baseUri); + context->SetWebService(Deprecated::WasmWebService::GetInstance()); + context->SetDelayedCallExecutor(Deprecated::WasmDelayedCallExecutor::GetInstance()); + application->Initialize(context.get(), statusBar_, parameters); + application->InitializeWasm(); + +// viewport->SetSize(width_, height_); + printf("StartWasmApplication - completed\n"); + } + + bool EMSCRIPTEN_KEEPALIVE WasmIsTraceLevelEnabled() + { + return Orthanc::Logging::IsTraceLevelEnabled(); + } + + bool EMSCRIPTEN_KEEPALIVE WasmIsInfoLevelEnabled() + { + return Orthanc::Logging::IsInfoLevelEnabled(); + } + + void EMSCRIPTEN_KEEPALIVE WasmDoAnimation() + { + for (auto viewport : viewports_) { + // TODO Only launch the JavaScript timer if "HasAnimation()" + if (viewport->HasAnimation()) + { + viewport->DoAnimation(); + } + + } + + } + + + void EMSCRIPTEN_KEEPALIVE ViewportSetSize(ViewportHandle viewport, unsigned int width, unsigned int height) + { + width_ = width; + height_ = height; + + viewport->SetSize(width, height); + } + + int EMSCRIPTEN_KEEPALIVE ViewportRender(ViewportHandle viewport, + unsigned int width, + unsigned int height, + uint8_t* data) + { + viewportContentChangedObserver_.Reset(); + + //printf("ViewportRender called %dx%d\n", width, height); + if (width == 0 || + height == 0) + { + return 1; + } + + Orthanc::ImageAccessor surface; + surface.AssignWritable(Orthanc::PixelFormat_BGRA32, width, height, 4 * width, data); + + viewport->Render(surface); + + // Convert from BGRA32 memory layout (only color mode supported by + // Cairo, which corresponds to CAIRO_FORMAT_ARGB32) to RGBA32 (as + // expected by HTML5 canvas). This simply amounts to swapping the + // B and R channels. + uint8_t* p = data; + for (unsigned int y = 0; y < height; y++) { + for (unsigned int x = 0; x < width; x++) { + uint8_t tmp = p[0]; + p[0] = p[2]; + p[2] = tmp; + + p += 4; + } + } + + return 1; + } + + + void EMSCRIPTEN_KEEPALIVE ViewportMouseDown(ViewportHandle viewport, + unsigned int rawButton, + int x, + int y, + unsigned int rawModifiers) + { + OrthancStone::MouseButton button; + switch (rawButton) + { + case 0: + button = OrthancStone::MouseButton_Left; + break; + + case 1: + button = OrthancStone::MouseButton_Middle; + break; + + case 2: + button = OrthancStone::MouseButton_Right; + break; + + default: + return; // Unknown button + } + + viewport->MouseDown(button, x, y, OrthancStone::KeyboardModifiers_None, std::vector<Deprecated::Touch>()); + } + + + void EMSCRIPTEN_KEEPALIVE ViewportMouseWheel(ViewportHandle viewport, + int deltaY, + int x, + int y, + int isControl) + { + if (deltaY != 0) + { + OrthancStone::MouseWheelDirection direction = (deltaY < 0 ? + OrthancStone::MouseWheelDirection_Up : + OrthancStone::MouseWheelDirection_Down); + OrthancStone::KeyboardModifiers modifiers = OrthancStone::KeyboardModifiers_None; + + if (isControl != 0) + { + modifiers = OrthancStone::KeyboardModifiers_Control; + } + + viewport->MouseWheel(direction, x, y, modifiers); + } + } + + + void EMSCRIPTEN_KEEPALIVE ViewportMouseMove(ViewportHandle viewport, + int x, + int y) + { + viewport->MouseMove(x, y, std::vector<Deprecated::Touch>()); + } + + void GetTouchVector(std::vector<Deprecated::Touch>& output, + int touchCount, + float x0, + float y0, + float x1, + float y1, + float x2, + float y2) + { + // TODO: it might be nice to try to pass all the x0,y0 coordinates as arrays but that's not so easy to pass array between JS and C++ + if (touchCount > 0) + { + output.push_back(Deprecated::Touch(x0, y0)); + } + if (touchCount > 1) + { + output.push_back(Deprecated::Touch(x1, y1)); + } + if (touchCount > 2) + { + output.push_back(Deprecated::Touch(x2, y2)); + } + + } + + void EMSCRIPTEN_KEEPALIVE ViewportTouchStart(ViewportHandle viewport, + int touchCount, + float x0, + float y0, + float x1, + float y1, + float x2, + float y2) + { + // printf("touch start with %d touches\n", touchCount); + + std::vector<Deprecated::Touch> touches; + GetTouchVector(touches, touchCount, x0, y0, x1, y1, x2, y2); + viewport->TouchStart(touches); + } + + void EMSCRIPTEN_KEEPALIVE ViewportTouchMove(ViewportHandle viewport, + int touchCount, + float x0, + float y0, + float x1, + float y1, + float x2, + float y2) + { + // printf("touch move with %d touches\n", touchCount); + + std::vector<Deprecated::Touch> touches; + GetTouchVector(touches, touchCount, x0, y0, x1, y1, x2, y2); + viewport->TouchMove(touches); + } + + void EMSCRIPTEN_KEEPALIVE ViewportTouchEnd(ViewportHandle viewport, + int touchCount, + float x0, + float y0, + float x1, + float y1, + float x2, + float y2) + { + // printf("touch end with %d touches remaining\n", touchCount); + + std::vector<Deprecated::Touch> touches; + GetTouchVector(touches, touchCount, x0, y0, x1, y1, x2, y2); + viewport->TouchEnd(touches); + } + + void EMSCRIPTEN_KEEPALIVE ViewportKeyPressed(ViewportHandle viewport, + int key, + const char* keyChar, + bool isShiftPressed, + bool isControlPressed, + bool isAltPressed) + + { + OrthancStone::KeyboardModifiers modifiers = OrthancStone::KeyboardModifiers_None; + if (isShiftPressed) { + modifiers = static_cast<OrthancStone::KeyboardModifiers>(modifiers + OrthancStone::KeyboardModifiers_Shift); + } + if (isControlPressed) { + modifiers = static_cast<OrthancStone::KeyboardModifiers>(modifiers + OrthancStone::KeyboardModifiers_Control); + } + if (isAltPressed) { + modifiers = static_cast<OrthancStone::KeyboardModifiers>(modifiers + OrthancStone::KeyboardModifiers_Alt); + } + + char c = 0; + if (keyChar != NULL && key == OrthancStone::KeyboardKeys_Generic) { + c = keyChar[0]; + } + viewport->KeyPressed(static_cast<OrthancStone::KeyboardKeys>(key), c, modifiers); + } + + + void EMSCRIPTEN_KEEPALIVE ViewportMouseUp(ViewportHandle viewport) + { + viewport->MouseUp(); + } + + + void EMSCRIPTEN_KEEPALIVE ViewportMouseEnter(ViewportHandle viewport) + { + viewport->MouseEnter(); + } + + + void EMSCRIPTEN_KEEPALIVE ViewportMouseLeave(ViewportHandle viewport) + { + viewport->MouseLeave(); + } + + const char* EMSCRIPTEN_KEEPALIVE SendSerializedMessageToStoneApplication(const char* message) + { + static std::string output; // we don't want the string to be deallocated when we return to JS code so we always use the same string (this is fine since JS is single-thread) + + //printf("SendSerializedMessageToStoneApplication\n"); + //printf("%s", message); + + if (applicationWasmAdapter.get() != NULL) { + applicationWasmAdapter->HandleSerializedMessageFromWeb(output, std::string(message)); + return output.c_str(); + } + printf("This Stone application does not have a Web Adapter, unable to send messages"); + return NULL; + } + +#ifdef __cplusplus +} +#endif