# HG changeset patch # User Benjamin Golinvaux # Date 1557845653 -7200 # Node ID 002d9562c8f5411da218ad0470b5b7a5a31f37b6 # Parent 1e26bb5f2a02a91033372db7fe622b5b7678ee90 Added support to DISABLE legacy scaling in SDL Windows (only in WIN32... this might also be needed on macos and GNU/Linux ?) + fixed text info overlay pos for angle measure (this requires the app to be aware of the compositor) diff -r 1e26bb5f2a02 -r 002d9562c8f5 Applications/Sdl/SdlOpenGLWindow.cpp --- a/Applications/Sdl/SdlOpenGLWindow.cpp Tue May 14 13:51:32 2019 +0200 +++ b/Applications/Sdl/SdlOpenGLWindow.cpp Tue May 14 16:54:13 2019 +0200 @@ -37,8 +37,9 @@ { SdlOpenGLWindow::SdlOpenGLWindow(const char* title, unsigned int width, - unsigned int height) : - window_(title, width, height, true /* enable OpenGL */) + unsigned int height, + bool allowDpiScaling) : + window_(title, width, height, true /* enable OpenGL */, allowDpiScaling) { context_ = SDL_GL_CreateContext(window_.GetObject()); diff -r 1e26bb5f2a02 -r 002d9562c8f5 Applications/Sdl/SdlOpenGLWindow.h --- a/Applications/Sdl/SdlOpenGLWindow.h Tue May 14 13:51:32 2019 +0200 +++ b/Applications/Sdl/SdlOpenGLWindow.h Tue May 14 16:54:13 2019 +0200 @@ -37,7 +37,8 @@ public: SdlOpenGLWindow(const char* title, unsigned int width, - unsigned int height); + unsigned int height, + bool allowDpiScaling = true); ~SdlOpenGLWindow(); diff -r 1e26bb5f2a02 -r 002d9562c8f5 Applications/Sdl/SdlWindow.cpp --- a/Applications/Sdl/SdlWindow.cpp Tue May 14 13:51:32 2019 +0200 +++ b/Applications/Sdl/SdlWindow.cpp Tue May 14 16:54:13 2019 +0200 @@ -26,6 +26,11 @@ #include #include +#ifdef WIN32 +#include // for SetProcessDpiAware +#endif +// WIN32 + #include namespace OrthancStone @@ -33,7 +38,8 @@ SdlWindow::SdlWindow(const char* title, unsigned int width, unsigned int height, - bool enableOpenGl) : + bool enableOpenGl, + bool allowDpiScaling) : maximized_(false) { // TODO Understand why, with SDL_WINDOW_OPENGL + MinGW32 + Release @@ -51,6 +57,33 @@ windowFlags = SDL_WINDOW_RESIZABLE; rendererFlags = SDL_RENDERER_SOFTWARE; } + +// TODO: probably required on MacOS X, too +#ifdef WIN32 + 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, diff -r 1e26bb5f2a02 -r 002d9562c8f5 Applications/Sdl/SdlWindow.h --- a/Applications/Sdl/SdlWindow.h Tue May 14 13:51:32 2019 +0200 +++ b/Applications/Sdl/SdlWindow.h Tue May 14 16:54:13 2019 +0200 @@ -40,7 +40,8 @@ SdlWindow(const char* title, unsigned int width, unsigned int height, - bool enableOpenGl); + bool enableOpenGl, + bool allowDpiScaling = true); ~SdlWindow(); diff -r 1e26bb5f2a02 -r 002d9562c8f5 Samples/Common/AngleMeasureTool.cpp --- a/Samples/Common/AngleMeasureTool.cpp Tue May 14 13:51:32 2019 +0200 +++ b/Samples/Common/AngleMeasureTool.cpp Tue May 14 16:54:13 2019 +0200 @@ -87,7 +87,6 @@ { if (IsEnabled()) { - // get the scaling factor const double pixelToScene = GetScene().GetCanvasToSceneTransform().ComputeZoom(); @@ -160,29 +159,43 @@ { PolylineSceneLayer::Chain chain; + const double ARC_RADIUS_CANVAS_COORD = 20.0; AddShortestArc(chain, GetScene(), side1End_, center_, side2End_, - 20.0*pixelToScene); + ARC_RADIUS_CANVAS_COORD*pixelToScene); polylineLayer->AddChain(chain, false); } } { - // Set the text layer proporeties + // Set the text layer - // the angle is measured in a clockwise way between the points - double angleRad = MeasureAngle(side1End_, center_, side2End_); - double angleDeg = RadiansToDegrees(angleRad); - + double p1cAngle = atan2( + side1End_.GetY() - center_.GetY(), + side1End_.GetX() - center_.GetX()); + double p2cAngle = atan2( + side2End_.GetY() - center_.GetY(), + side2End_.GetX() - center_.GetX()); + double delta = NormalizeAngle(p2cAngle - p1cAngle); + double theta = delta/2; + + const double TEXT_CENTER_DISTANCE_CANVAS_COORD = 40.0; + + double offsetX = TEXT_CENTER_DISTANCE_CANVAS_COORD * cos(theta); + double offsetY = TEXT_CENTER_DISTANCE_CANVAS_COORD * sin(theta); + double pointX = center_.GetX() + offsetX; + double pointY = center_.GetY() + offsetY; + TextSceneLayer* textLayer = GetTextLayer(); char buf[64]; + double angleDeg = RadiansToDegrees(delta); sprintf(buf, "%0.02f deg", angleDeg); textLayer->SetText(buf); textLayer->SetColor(0, 223, 21); ScenePoint2D textAnchor; - GetPositionOnBisectingLine( - textAnchor, side1End_, center_, side2End_, 40.0*pixelToScene); - textLayer->SetPosition(textAnchor.GetX(), textAnchor.GetY()); + //GetPositionOnBisectingLine( + // textAnchor, side1End_, center_, side2End_, 40.0*pixelToScene); + textLayer->SetPosition(pointX, pointY); } } else diff -r 1e26bb5f2a02 -r 002d9562c8f5 Samples/Sdl/TrackerSample.cpp --- a/Samples/Sdl/TrackerSample.cpp Tue May 14 13:51:32 2019 +0200 +++ b/Samples/Sdl/TrackerSample.cpp Tue May 14 16:54:13 2019 +0200 @@ -53,77 +53,8 @@ using namespace OrthancStone; -static void GLAPIENTRY -OpenGLMessageCallback(GLenum source, - GLenum type, - GLuint id, - GLenum severity, - GLsizei length, - const GLchar* message, - const void* userParam) -{ - if (severity != GL_DEBUG_SEVERITY_NOTIFICATION) - { - fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n", - (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), - type, severity, message); - } -} - -bool g_stopApplication = false; - -void Run(TrackerSampleApp* app) -{ - SdlOpenGLWindow window("Hello", 1024, 768); - - app->GetScene().FitContent(window.GetCanvasWidth(), window.GetCanvasHeight()); - - glEnable(GL_DEBUG_OUTPUT); - glDebugMessageCallback(OpenGLMessageCallback, 0); - - OpenGLCompositor compositor(window, app->GetScene()); - compositor.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, - FONT_SIZE, Orthanc::Encoding_Latin1); - - while (!g_stopApplication) - { - compositor.Refresh(); - SDL_Event event; - while (!g_stopApplication && SDL_PollEvent(&event)) - { - if (event.type == SDL_QUIT) - { - g_stopApplication = true; - break; - } - else if (event.type == SDL_WINDOWEVENT && - event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) - { - app->DisableTracker(); // was: tracker.reset(NULL); - compositor.UpdateSize(); - } - else if (event.type == SDL_KEYDOWN && - event.key.repeat == 0 /* Ignore key bounce */) - { - switch (event.key.keysym.sym) - { - case SDLK_f: - window.GetWindow().ToggleMaximize(); - break; - case SDLK_q: - g_stopApplication = true; - break; - default: - break; - } - } - app->HandleApplicationEvent(compositor, event); - } - SDL_Delay(1); - } -} /** @@ -143,7 +74,7 @@ MessageBroker broker; TrackerSampleApp app(broker); app.PrepareScene(); - Run(&app); + app.Run(); } catch (Orthanc::OrthancException& e) { diff -r 1e26bb5f2a02 -r 002d9562c8f5 Samples/Sdl/TrackerSampleApp.cpp --- a/Samples/Sdl/TrackerSampleApp.cpp Tue May 14 13:51:32 2019 +0200 +++ b/Samples/Sdl/TrackerSampleApp.cpp Tue May 14 16:54:13 2019 +0200 @@ -80,17 +80,51 @@ printf("Current tool is now: %s\n", MeasureToolToString(currentTool_)); } - void TrackerSampleApp::DisplayInfoText(const PointerEvent& e) + void TrackerSampleApp::DisplayInfoText() + { + char buf[256]; + sprintf(buf, "INFO TEXT\n*** INFO TEXT ***\ntoto tata tutu titi\nprrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrrout"); + + TextSceneLayer* layerP = NULL; + if (scene_.HasLayer(FIXED_INFOTEXT_LAYER_ZINDEX)) + { + TextSceneLayer& layer = dynamic_cast( + scene_.GetLayer(FIXED_INFOTEXT_LAYER_ZINDEX)); + layerP = &layer; + } + else + { + std::auto_ptr layer(new TextSceneLayer); + layerP = layer.get(); + layer->SetColor(0, 255, 0); + layer->SetFontIndex(1); + layer->SetText(buf); + layer->SetBorder(20); + layer->SetAnchor(BitmapAnchor_TopLeft); + //layer->SetPosition(0,0); + scene_.SetLayer(FIXED_INFOTEXT_LAYER_ZINDEX, layer.release()); + } + // position the fixed info text in the upper right corner + layerP->SetText(buf); + double cX = compositor_->GetCanvasWidth() * (-0.5); + double cY = compositor_->GetCanvasHeight() * (-0.5); + scene_.GetCanvasToSceneTransform().Apply(cX,cY); + layerP->SetPosition(cX, cY); + } + + void TrackerSampleApp::DisplayFloatingCtrlInfoText(const PointerEvent& e) { ScenePoint2D p = e.GetMainPosition().Apply(scene_.GetCanvasToSceneTransform()); - char buf[64]; - sprintf(buf, "(%0.02f,%0.02f)", p.GetX(), p.GetY()); + char buf[128]; + sprintf(buf, "S:(%0.02f,%0.02f) C:(%0.02f,%0.02f)", + p.GetX(), p.GetY(), + e.GetMainPosition().GetX(), e.GetMainPosition().GetY()); - if (scene_.HasLayer(INFOTEXT_LAYER_ZINDEX)) + if (scene_.HasLayer(FLOATING_INFOTEXT_LAYER_ZINDEX)) { TextSceneLayer& layer = - dynamic_cast(scene_.GetLayer(INFOTEXT_LAYER_ZINDEX)); + dynamic_cast(scene_.GetLayer(FLOATING_INFOTEXT_LAYER_ZINDEX)); layer.SetText(buf); layer.SetPosition(p.GetX(), p.GetY()); } @@ -102,19 +136,20 @@ layer->SetBorder(20); layer->SetAnchor(BitmapAnchor_BottomCenter); layer->SetPosition(p.GetX(), p.GetY()); - scene_.SetLayer(INFOTEXT_LAYER_ZINDEX, layer.release()); + scene_.SetLayer(FLOATING_INFOTEXT_LAYER_ZINDEX, layer.release()); } } void TrackerSampleApp::HideInfoText() { - scene_.DeleteLayer(INFOTEXT_LAYER_ZINDEX); + scene_.DeleteLayer(FLOATING_INFOTEXT_LAYER_ZINDEX); } void TrackerSampleApp::HandleApplicationEvent( - const OpenGLCompositor & compositor, const SDL_Event & event) { + DisplayInfoText(); + if (event.type == SDL_MOUSEMOTION) { int scancodeCount = 0; @@ -127,8 +162,10 @@ // The "left-ctrl" key is down, while no tracker is present // Let's display the info text PointerEvent e; - e.AddPosition(compositor.GetPixelCenterCoordinates(event.button.x, event.button.y)); - DisplayInfoText(e); + e.AddPosition(compositor_->GetPixelCenterCoordinates( + event.button.x, event.button.y)); + + DisplayFloatingCtrlInfoText(e); } else { @@ -138,11 +175,14 @@ { //LOG(TRACE) << "(activeTracker_.get() != NULL)"; PointerEvent e; - e.AddPosition(compositor.GetPixelCenterCoordinates(event.button.x, event.button.y)); + e.AddPosition(compositor_->GetPixelCenterCoordinates( + event.button.x, event.button.y)); + //LOG(TRACE) << "event.button.x = " << event.button.x << " " << // "event.button.y = " << event.button.y; //LOG(TRACE) << "activeTracker_->PointerMove(e); " << // e.GetMainPosition().GetX() << " " << e.GetMainPosition().GetY(); + activeTracker_->PointerMove(e); if (!activeTracker_->IsActive()) activeTracker_ = NULL; @@ -154,7 +194,7 @@ if (activeTracker_) { PointerEvent e; - e.AddPosition(compositor.GetPixelCenterCoordinates(event.button.x, event.button.y)); + e.AddPosition(compositor_->GetPixelCenterCoordinates(event.button.x, event.button.y)); activeTracker_->PointerUp(e); if (!activeTracker_->IsActive()) activeTracker_ = NULL; @@ -163,7 +203,7 @@ else if (event.type == SDL_MOUSEBUTTONDOWN) { PointerEvent e; - e.AddPosition(compositor.GetPixelCenterCoordinates( + e.AddPosition(compositor_->GetPixelCenterCoordinates( event.button.x, event.button.y)); if (activeTracker_) { @@ -174,7 +214,7 @@ else { // we ATTEMPT to create a tracker if need be - activeTracker_ = CreateSuitableTracker(event, e, compositor); + activeTracker_ = CreateSuitableTracker(event, e); } } else if (event.type == SDL_KEYDOWN && @@ -202,15 +242,15 @@ break; case SDLK_s: - scene_.FitContent(compositor.GetCanvasWidth(), - compositor.GetCanvasHeight()); + scene_.FitContent(compositor_->GetCanvasWidth(), + compositor_->GetCanvasHeight()); break; case SDLK_c: TakeScreenshot( "screenshot.png", - compositor.GetCanvasWidth(), - compositor.GetCanvasHeight()); + compositor_->GetCanvasWidth(), + compositor_->GetCanvasHeight()); break; default: @@ -219,10 +259,17 @@ } } + + void TrackerSampleApp::OnSceneTransformChanged(const Scene2D::SceneTransformChanged& message) + { + // do not try to call this too early! + if(compositor_.get() != NULL) + DisplayInfoText(); + } + FlexiblePointerTrackerPtr TrackerSampleApp::CreateSuitableTracker( const SDL_Event & event, - const PointerEvent & e, - const OpenGLCompositor & compositor) + const PointerEvent & e) { switch (event.button.button) { @@ -232,7 +279,7 @@ case SDL_BUTTON_RIGHT: return CreateSimpleTrackerAdapter(PointerTrackerPtr( - new ZoomSceneTracker(scene_, e, compositor.GetCanvasHeight()))); + new ZoomSceneTracker(scene_, e, compositor_->GetCanvasHeight()))); case SDL_BUTTON_LEFT: { @@ -264,7 +311,7 @@ new PanSceneTracker(scene_, e))); case GuiTool_Zoom: return CreateSimpleTrackerAdapter(PointerTrackerPtr( - new ZoomSceneTracker(scene_, e, compositor.GetCanvasHeight()))); + new ZoomSceneTracker(scene_, e, compositor_->GetCanvasHeight()))); //case GuiTool_AngleMeasure: // return new AngleMeasureTracker(scene_, measureTools_, undoStack_, e); //case GuiTool_CircleMeasure: @@ -397,9 +444,8 @@ unsigned int canvasWidth, unsigned int canvasHeight) { - // Take a screenshot, then save it as PNG file CairoCompositor compositor(scene_, canvasWidth, canvasHeight); - compositor.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, FONT_SIZE, Orthanc::Encoding_Latin1); + compositor.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, FONT_SIZE_0, Orthanc::Encoding_Latin1); compositor.Refresh(); Orthanc::ImageAccessor canvas; @@ -419,6 +465,84 @@ return nullptr; } + static void GLAPIENTRY + OpenGLMessageCallback(GLenum source, + GLenum type, + GLuint id, + GLenum severity, + GLsizei length, + const GLchar* message, + const void* userParam) + { + if (severity != GL_DEBUG_SEVERITY_NOTIFICATION) + { + fprintf(stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n", + (type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : ""), + type, severity, message); + } + } + + static bool g_stopApplication = false; + + void TrackerSampleApp::Run() + { + // False means we do NOT let Windows treat this as a legacy application + // that needs to be scaled + SdlOpenGLWindow window("Hello", 1024, 1024, false); + + GetScene().FitContent(window.GetCanvasWidth(), window.GetCanvasHeight()); + + glEnable(GL_DEBUG_OUTPUT); + glDebugMessageCallback(OpenGLMessageCallback, 0); + + compositor_.reset(new OpenGLCompositor(window, GetScene())); + + compositor_->SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, + FONT_SIZE_0, Orthanc::Encoding_Latin1); + compositor_->SetFont(1, Orthanc::EmbeddedResources::UBUNTU_FONT, + FONT_SIZE_1, Orthanc::Encoding_Latin1); + + while (!g_stopApplication) + { + compositor_->Refresh(); + + SDL_Event event; + while (!g_stopApplication && SDL_PollEvent(&event)) + { + if (event.type == SDL_QUIT) + { + g_stopApplication = true; + break; + } + else if (event.type == SDL_WINDOWEVENT && + event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) + { + DisableTracker(); // was: tracker.reset(NULL); + compositor_->UpdateSize(); + } + else if (event.type == SDL_KEYDOWN && + event.key.repeat == 0 /* Ignore key bounce */) + { + switch (event.key.keysym.sym) + { + case SDLK_f: + window.GetWindow().ToggleMaximize(); + break; + + case SDLK_q: + g_stopApplication = true; + break; + default: + break; + } + } + HandleApplicationEvent(event); + } + SDL_Delay(1); + } + compositor_.reset(NULL); + } + } diff -r 1e26bb5f2a02 -r 002d9562c8f5 Samples/Sdl/TrackerSampleApp.h --- a/Samples/Sdl/TrackerSampleApp.h Tue May 14 13:51:32 2019 +0200 +++ b/Samples/Sdl/TrackerSampleApp.h Tue May 14 16:54:13 2019 +0200 @@ -48,7 +48,8 @@ const char* MeasureToolToString(size_t i); - static const unsigned int FONT_SIZE = 32; + static const unsigned int FONT_SIZE_0 = 32; + static const unsigned int FONT_SIZE_1 = 24; class Scene2D; @@ -61,22 +62,32 @@ , currentTool_(GuiTool_Rotate) , scene_(broker) { + scene_.RegisterObserverCallback( + new Callable + (*this, &TrackerSampleApp::OnSceneTransformChanged)); + TEXTURE_2x2_1_ZINDEX = 1; TEXTURE_1x1_ZINDEX = 2; TEXTURE_2x2_2_ZINDEX = 3; LINESET_1_ZINDEX = 4; LINESET_2_ZINDEX = 5; - INFOTEXT_LAYER_ZINDEX = 6; + FLOATING_INFOTEXT_LAYER_ZINDEX = 6; + FIXED_INFOTEXT_LAYER_ZINDEX = 7; } void PrepareScene(); + void Run(); void DisableTracker(); Scene2D& GetScene(); - void HandleApplicationEvent( - const OpenGLCompositor& compositor, - const SDL_Event& event); + void HandleApplicationEvent(const SDL_Event& event); + + /** + This method is called when the scene transform changes. It allows to + recompute the visual elements whose content depend upon the scene transform + */ + void OnSceneTransformChanged(const Scene2D::SceneTransformChanged& message); private: void SelectNextTool(); @@ -86,8 +97,7 @@ FlexiblePointerTrackerPtr CreateSuitableTracker( const SDL_Event& event, - const PointerEvent& e, - const OpenGLCompositor& compositor); + const PointerEvent& e); void TakeScreenshot( const std::string& target, @@ -102,10 +112,12 @@ void Redo(); private: - void DisplayInfoText(const PointerEvent& e); + void DisplayFloatingCtrlInfoText(const PointerEvent& e); + void DisplayInfoText(); void HideInfoText(); private: + std::auto_ptr compositor_; /** WARNING: the measuring tools do store a reference to the scene, and it paramount that the scene gets destroyed AFTER the measurement tools. @@ -119,21 +131,16 @@ std::vector measureTools_; //static const int LAYER_POSITION = 150; -#if 0 - int TEXTURE_2x2_1_ZINDEX = 12; - int TEXTURE_1x1_ZINDEX = 13; - int TEXTURE_2x2_2_ZINDEX = 14; - int LINESET_1_ZINDEX = 50; - int LINESET_2_ZINDEX = 100; - int INFOTEXT_LAYER_ZINDEX = 150; -#else + + int TEXTURE_2x2_1_ZINDEX; int TEXTURE_1x1_ZINDEX; int TEXTURE_2x2_2_ZINDEX; int LINESET_1_ZINDEX; int LINESET_2_ZINDEX; - int INFOTEXT_LAYER_ZINDEX; -#endif + int FLOATING_INFOTEXT_LAYER_ZINDEX; + int FIXED_INFOTEXT_LAYER_ZINDEX; + GuiTool currentTool_; };