Mercurial > hg > orthanc-stone
view Framework/Viewport/SdlViewport.cpp @ 1411:08fd094f9582
Merge
author | Benjamin Golinvaux <bgo@osimis.io> |
---|---|
date | Mon, 04 May 2020 13:34:46 +0200 |
parents | 32272ecfc6c2 |
children | 30deba7bc8e2 |
line wrap: on
line source
/** * 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 "SdlViewport.h" #include <Core/OrthancException.h> #include <boost/make_shared.hpp> namespace OrthancStone { ICompositor& SdlViewport::SdlLock::GetCompositor() { if (that_.compositor_.get() == NULL) { // The derived class should have called "AcquireCompositor()" throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); } else { return *that_.compositor_; } } void SdlViewport::AcquireCompositor(ICompositor* compositor /* takes ownership */) { if (compositor == NULL) { throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer); } compositor_.reset(compositor); } SdlViewport::SdlViewport() { refreshEvent_ = SDL_RegisterEvents(1); if (refreshEvent_ == static_cast<uint32_t>(-1)) { throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); } } void SdlViewport::PostConstructor() { controller_ = boost::make_shared<ViewportController>(shared_from_this()); } void SdlViewport::SendRefreshEvent() { SDL_Event event; SDL_memset(&event, 0, sizeof(event)); event.type = refreshEvent_; SDL_PushEvent(&event); // This function is thread-safe, and can be called from other threads safely. } SdlOpenGLViewport::SdlOpenGLViewport(const std::string& title, unsigned int width, unsigned int height, bool allowDpiScaling) : context_(title.c_str(), width, height, allowDpiScaling) { AcquireCompositor(new OpenGLCompositor(context_)); // (*) } boost::shared_ptr<SdlOpenGLViewport> SdlOpenGLViewport::Create( const std::string& title, unsigned int width, unsigned int height, bool allowDpiScaling) { boost::shared_ptr<SdlOpenGLViewport> that = boost::shared_ptr<SdlOpenGLViewport>(new SdlOpenGLViewport(title, width, height, allowDpiScaling)); that->SdlViewport::PostConstructor(); return that; } uint32_t SdlOpenGLViewport::GetSdlWindowId() { SdlWindow& sdlWindowWrapper = context_.GetWindow(); SDL_Window* sdlWindow = sdlWindowWrapper.GetObject(); Uint32 sdlWindowId = SDL_GetWindowID(sdlWindow); return sdlWindowId; } SdlOpenGLViewport::~SdlOpenGLViewport() { // Make sure that the "OpenGLCompositor" is destroyed BEFORE the // "OpenGLContext" it references (*) ClearCompositor(); } void SdlOpenGLViewport::Paint() { SdlLock lock(*this); lock.GetCompositor().Refresh(lock.GetController().GetScene()); } void SdlOpenGLViewport::UpdateSize(unsigned int width, unsigned int height) { // nothing to do in OpenGL, the OpenGLCompositor::UpdateSize will be called automatically SdlLock lock(*this); lock.Invalidate(); } void SdlOpenGLViewport::ToggleMaximize() { // No need to call "Invalidate()" here, as "UpdateSize()" will // be invoked after event "SDL_WINDOWEVENT_SIZE_CHANGED" SdlLock lock(*this); context_.ToggleMaximize(); } SdlCairoViewport::SdlCairoViewport(const char* title, unsigned int width, unsigned int height, bool allowDpiScaling) : window_(title, width, height, false /* enable OpenGL */, allowDpiScaling), sdlSurface_(NULL) { AcquireCompositor(new CairoCompositor(width, height)); } SdlCairoViewport::~SdlCairoViewport() { if (sdlSurface_) { SDL_FreeSurface(sdlSurface_); } } uint32_t SdlCairoViewport::GetSdlWindowId() { SDL_Window* sdlWindow = window_.GetObject(); Uint32 sdlWindowId = SDL_GetWindowID(sdlWindow); return sdlWindowId; } void SdlCairoViewport::Paint() { SdlLock lock(*this); lock.GetCompositor().Refresh(lock.GetController().GetScene()); CreateSdlSurfaceFromCompositor(dynamic_cast<CairoCompositor&>(lock.GetCompositor())); if (sdlSurface_ != NULL) { window_.Render(sdlSurface_); } } void SdlCairoViewport::UpdateSize(unsigned int width, unsigned int height) { SdlLock lock(*this); dynamic_cast<CairoCompositor&>(lock.GetCompositor()).UpdateSize(width, height); lock.Invalidate(); } void SdlCairoViewport::ToggleMaximize() { // No need to call "Invalidate()" here, as "UpdateSize()" will // be invoked after event "SDL_WINDOWEVENT_SIZE_CHANGED" SdlLock lock(*this); window_.ToggleMaximize(); } // Assumes that the mutex is locked void SdlCairoViewport::CreateSdlSurfaceFromCompositor(CairoCompositor& compositor) { static const uint32_t rmask = 0x00ff0000; static const uint32_t gmask = 0x0000ff00; static const uint32_t bmask = 0x000000ff; const unsigned int width = compositor.GetCanvas().GetWidth(); const unsigned int height = compositor.GetCanvas().GetHeight(); if (sdlSurface_ != NULL) { if (sdlSurface_->pixels == compositor.GetCanvas().GetBuffer() && sdlSurface_->w == static_cast<int>(width) && sdlSurface_->h == static_cast<int>(height) && sdlSurface_->pitch == static_cast<int>(compositor.GetCanvas().GetPitch())) { // The image from the compositor has not changed, no need to update the surface return; } else { SDL_FreeSurface(sdlSurface_); } } sdlSurface_ = SDL_CreateRGBSurfaceFrom((void*)(compositor.GetCanvas().GetBuffer()), width, height, 32, compositor.GetCanvas().GetPitch(), rmask, gmask, bmask, 0); if (!sdlSurface_) { LOG(ERROR) << "Cannot create a SDL surface from a Cairo surface"; throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError); } } }