comparison Applications/Platforms/Sdl/SdlViewport.cpp @ 1591:5887a4f8594b

moving platform-specific files out of the "OrthancStone" folder
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 23 Oct 2020 13:15:03 +0200
parents OrthancStone/Sources/Viewport/SdlViewport.cpp@92fca2b3ba3d
children 9ac2a65d4172
comparison
equal deleted inserted replaced
1590:7b963bccafef 1591:5887a4f8594b
1 /**
2 * Stone of Orthanc
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2020 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU Affero General Public License
9 * as published by the Free Software Foundation, either version 3 of
10 * the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Affero General Public License for more details.
16 *
17 * You should have received a copy of the GNU Affero General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 **/
20
21 #include "SdlViewport.h"
22
23 #include "../../../OrthancStone/Sources/Scene2DViewport/ViewportController.h"
24
25 #include <OrthancException.h>
26
27 #include <boost/make_shared.hpp>
28
29 namespace OrthancStone
30 {
31 ICompositor& SdlViewport::SdlLock::GetCompositor()
32 {
33 if (that_.compositor_.get() == NULL)
34 {
35 // The derived class should have called "AcquireCompositor()"
36 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
37 }
38 else
39 {
40 return *that_.compositor_;
41 }
42 }
43
44
45 void SdlViewport::AcquireCompositor(ICompositor* compositor /* takes ownership */)
46 {
47 if (compositor == NULL)
48 {
49 throw Orthanc::OrthancException(Orthanc::ErrorCode_NullPointer);
50 }
51
52 compositor_.reset(compositor);
53 }
54
55
56 SdlViewport::SdlViewport()
57 {
58 refreshEvent_ = SDL_RegisterEvents(1);
59
60 if (refreshEvent_ == static_cast<uint32_t>(-1))
61 {
62 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
63 }
64 }
65
66 void SdlViewport::PostConstructor()
67 {
68 controller_ = boost::make_shared<ViewportController>(shared_from_this());
69 }
70
71 void SdlViewport::SendRefreshEvent()
72 {
73 SDL_Event event;
74 SDL_memset(&event, 0, sizeof(event));
75 event.type = refreshEvent_;
76 SDL_PushEvent(&event); // This function is thread-safe, and can be called from other threads safely.
77 }
78
79
80 void SdlViewport::UpdateSize(unsigned int width, unsigned int height)
81 {
82 SdlLock lock(*this);
83 lock.GetCompositor().SetCanvasSize(width, height);
84 lock.Invalidate();
85 }
86
87
88 SdlOpenGLViewport::SdlOpenGLViewport(const std::string& title,
89 unsigned int width,
90 unsigned int height,
91 bool allowDpiScaling) :
92 context_(title.c_str(), width, height, allowDpiScaling)
93 {
94 AcquireCompositor(new OpenGLCompositor(context_)); // (*)
95 }
96
97
98 void SdlOpenGLViewport::RefreshCanvasSize()
99 {
100 UpdateSize(context_.GetCanvasWidth(), context_.GetCanvasHeight());
101 }
102
103
104 boost::shared_ptr<SdlOpenGLViewport> SdlOpenGLViewport::Create(
105 const std::string& title,
106 unsigned int width,
107 unsigned int height,
108 bool allowDpiScaling)
109 {
110 boost::shared_ptr<SdlOpenGLViewport> that =
111 boost::shared_ptr<SdlOpenGLViewport>(new SdlOpenGLViewport(title, width, height, allowDpiScaling));
112 that->SdlViewport::PostConstructor();
113 return that;
114 }
115
116 uint32_t SdlOpenGLViewport::GetSdlWindowId()
117 {
118 const SdlWindow& sdlWindowWrapper = context_.GetWindow();
119 SDL_Window* sdlWindow = sdlWindowWrapper.GetObject();
120 Uint32 sdlWindowId = SDL_GetWindowID(sdlWindow);
121 return sdlWindowId;
122 }
123
124 SdlOpenGLViewport::~SdlOpenGLViewport()
125 {
126 // Make sure that the "OpenGLCompositor" is destroyed BEFORE the
127 // "OpenGLContext" it references (*)
128 ClearCompositor();
129 }
130
131
132 void SdlOpenGLViewport::Paint()
133 {
134 SdlLock lock(*this);
135 lock.GetCompositor().Refresh(lock.GetController().GetScene());
136 }
137
138
139 void SdlOpenGLViewport::ToggleMaximize()
140 {
141 // No need to call "Invalidate()" here, as "UpdateSize()" will
142 // be invoked after event "SDL_WINDOWEVENT_SIZE_CHANGED"
143 SdlLock lock(*this);
144 context_.ToggleMaximize();
145 }
146
147
148
149 void SdlCairoViewport::RefreshCanvasSize()
150 {
151 UpdateSize(window_.GetWidth(), window_.GetHeight());
152 }
153
154 SdlCairoViewport::SdlCairoViewport(const char* title,
155 unsigned int width,
156 unsigned int height,
157 bool allowDpiScaling) :
158 window_(title, width, height, false /* enable OpenGL */, allowDpiScaling),
159 sdlSurface_(NULL)
160 {
161 AcquireCompositor(new CairoCompositor(width, height));
162 }
163
164 SdlCairoViewport::~SdlCairoViewport()
165 {
166 if (sdlSurface_)
167 {
168 SDL_FreeSurface(sdlSurface_);
169 }
170 }
171
172 uint32_t SdlCairoViewport::GetSdlWindowId()
173 {
174 SDL_Window* sdlWindow = window_.GetObject();
175 Uint32 sdlWindowId = SDL_GetWindowID(sdlWindow);
176 return sdlWindowId;
177 }
178
179 void SdlCairoViewport::Paint()
180 {
181 SdlLock lock(*this);
182
183 lock.GetCompositor().Refresh(lock.GetController().GetScene());
184 CreateSdlSurfaceFromCompositor(dynamic_cast<CairoCompositor&>(lock.GetCompositor()));
185
186 if (sdlSurface_ != NULL)
187 {
188 window_.Render(sdlSurface_);
189 }
190 }
191
192
193 void SdlCairoViewport::ToggleMaximize()
194 {
195 // No need to call "Invalidate()" here, as "UpdateSize()" will
196 // be invoked after event "SDL_WINDOWEVENT_SIZE_CHANGED"
197 SdlLock lock(*this);
198 window_.ToggleMaximize();
199 }
200
201
202 // Assumes that the mutex is locked
203 void SdlCairoViewport::CreateSdlSurfaceFromCompositor(const CairoCompositor& compositor)
204 {
205 static const uint32_t rmask = 0x00ff0000;
206 static const uint32_t gmask = 0x0000ff00;
207 static const uint32_t bmask = 0x000000ff;
208
209 const unsigned int width = compositor.GetCanvas().GetWidth();
210 const unsigned int height = compositor.GetCanvas().GetHeight();
211
212 if (sdlSurface_ != NULL)
213 {
214 if (sdlSurface_->pixels == compositor.GetCanvas().GetBuffer() &&
215 sdlSurface_->w == static_cast<int>(width) &&
216 sdlSurface_->h == static_cast<int>(height) &&
217 sdlSurface_->pitch == static_cast<int>(compositor.GetCanvas().GetPitch()))
218 {
219 // The image from the compositor has not changed, no need to update the surface
220 return;
221 }
222 else
223 {
224 SDL_FreeSurface(sdlSurface_);
225 }
226 }
227
228 sdlSurface_ = SDL_CreateRGBSurfaceFrom((void*)(compositor.GetCanvas().GetBuffer()), width, height, 32,
229 compositor.GetCanvas().GetPitch(), rmask, gmask, bmask, 0);
230 if (!sdlSurface_)
231 {
232 LOG(ERROR) << "Cannot create a SDL surface from a Cairo surface";
233 throw Orthanc::OrthancException(Orthanc::ErrorCode_InternalError);
234 }
235 }
236 }