Mercurial > hg > orthanc-stone
comparison Samples/Sdl/BasicScene.cpp @ 897:9c2f6d6b9f4a am-dev
Merge
author | Alain Mazy <alain@mazy.be> |
---|---|
date | Tue, 16 Jul 2019 12:37:29 +0200 |
parents | 56e4e9281076 0aff28f15ea2 |
children | 64e5f3ff6360 |
comparison
equal
deleted
inserted
replaced
896:875bd6aca5e6 | 897:9c2f6d6b9f4a |
---|---|
18 * along with this program. If not, see <http://www.gnu.org/licenses/>. | 18 * along with this program. If not, see <http://www.gnu.org/licenses/>. |
19 **/ | 19 **/ |
20 | 20 |
21 | 21 |
22 // From Stone | 22 // From Stone |
23 #include "../../Applications/Sdl/SdlOpenGLWindow.h" | 23 #include "../../Framework/Viewport/SdlViewport.h" |
24 #include "../../Framework/Scene2D/CairoCompositor.h" | |
25 #include "../../Framework/Scene2D/ColorTextureSceneLayer.h" | |
24 #include "../../Framework/Scene2D/OpenGLCompositor.h" | 26 #include "../../Framework/Scene2D/OpenGLCompositor.h" |
27 #include "../../Framework/Scene2D/PanSceneTracker.h" | |
28 #include "../../Framework/Scene2D/RotateSceneTracker.h" | |
29 #include "../../Framework/Scene2D/ZoomSceneTracker.h" | |
30 #include "../../Framework/Scene2DViewport/ViewportController.h" | |
25 #include "../../Framework/Scene2DViewport/UndoStack.h" | 31 #include "../../Framework/Scene2DViewport/UndoStack.h" |
32 | |
26 #include "../../Framework/StoneInitialization.h" | 33 #include "../../Framework/StoneInitialization.h" |
27 #include "../../Framework/Messages/MessageBroker.h" | 34 #include "../../Framework/Messages/MessageBroker.h" |
28 | 35 |
29 // From Orthanc framework | 36 // From Orthanc framework |
30 #include <Core/Logging.h> | 37 #include <Core/Logging.h> |
31 #include <Core/OrthancException.h> | 38 #include <Core/OrthancException.h> |
39 #include <Core/Images/Image.h> | |
40 #include <Core/Images/ImageProcessing.h> | |
41 #include <Core/Images/PngWriter.h> | |
32 | 42 |
33 #include <boost/make_shared.hpp> | 43 #include <boost/make_shared.hpp> |
34 #include <boost/ref.hpp> | |
35 | 44 |
36 #include <SDL.h> | 45 #include <SDL.h> |
37 #include <stdio.h> | 46 #include <stdio.h> |
38 | 47 |
39 | 48 static const unsigned int FONT_SIZE = 32; |
40 #include "../Shared/SharedBasicScene.h" | 49 static const int LAYER_POSITION = 150; |
41 | 50 |
42 using namespace OrthancStone; | 51 |
43 | 52 void PrepareScene(OrthancStone::Scene2D& scene) |
44 boost::shared_ptr<BasicScene2DInteractor> interactor; | |
45 | |
46 void HandleApplicationEvent(boost::shared_ptr<OrthancStone::ViewportController> controller, | |
47 const OrthancStone::OpenGLCompositor& compositor, | |
48 const SDL_Event& event) | |
49 { | 53 { |
50 using namespace OrthancStone; | 54 using namespace OrthancStone; |
51 Scene2D& scene(*controller->GetScene()); | 55 |
52 if (event.type == SDL_MOUSEBUTTONDOWN || event.type == SDL_MOUSEBUTTONUP || event.type == SDL_MOUSEMOTION) | 56 // Texture of 2x2 size |
53 { | 57 { |
54 // TODO: this code is copy/pasted from GuiAdapter::Run() -> find the right place | 58 Orthanc::Image i(Orthanc::PixelFormat_RGB24, 2, 2, false); |
59 | |
60 uint8_t *p = reinterpret_cast<uint8_t*>(i.GetRow(0)); | |
61 p[0] = 255; | |
62 p[1] = 0; | |
63 p[2] = 0; | |
64 | |
65 p[3] = 0; | |
66 p[4] = 255; | |
67 p[5] = 0; | |
68 | |
69 p = reinterpret_cast<uint8_t*>(i.GetRow(1)); | |
70 p[0] = 0; | |
71 p[1] = 0; | |
72 p[2] = 255; | |
73 | |
74 p[3] = 255; | |
75 p[4] = 0; | |
76 p[5] = 0; | |
77 | |
78 scene.SetLayer(12, new ColorTextureSceneLayer(i)); | |
79 | |
80 std::auto_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i)); | |
81 l->SetOrigin(-3, 2); | |
82 l->SetPixelSpacing(1.5, 1); | |
83 l->SetAngle(20.0 / 180.0 * M_PI); | |
84 scene.SetLayer(14, l.release()); | |
85 } | |
86 | |
87 // Texture of 1x1 size | |
88 { | |
89 Orthanc::Image i(Orthanc::PixelFormat_RGB24, 1, 1, false); | |
90 | |
91 uint8_t *p = reinterpret_cast<uint8_t*>(i.GetRow(0)); | |
92 p[0] = 255; | |
93 p[1] = 0; | |
94 p[2] = 0; | |
95 | |
96 std::auto_ptr<ColorTextureSceneLayer> l(new ColorTextureSceneLayer(i)); | |
97 l->SetOrigin(-2, 1); | |
98 l->SetAngle(20.0 / 180.0 * M_PI); | |
99 scene.SetLayer(13, l.release()); | |
100 } | |
101 | |
102 // Some lines | |
103 { | |
104 std::auto_ptr<PolylineSceneLayer> layer(new PolylineSceneLayer); | |
105 | |
106 layer->SetThickness(10); | |
107 | |
108 PolylineSceneLayer::Chain chain; | |
109 chain.push_back(ScenePoint2D(0 - 0.5, 0 - 0.5)); | |
110 chain.push_back(ScenePoint2D(0 - 0.5, 2 - 0.5)); | |
111 chain.push_back(ScenePoint2D(2 - 0.5, 2 - 0.5)); | |
112 chain.push_back(ScenePoint2D(2 - 0.5, 0 - 0.5)); | |
113 layer->AddChain(chain, true, 255, 0, 0); | |
114 | |
115 chain.clear(); | |
116 chain.push_back(ScenePoint2D(-5, -5)); | |
117 chain.push_back(ScenePoint2D(5, -5)); | |
118 chain.push_back(ScenePoint2D(5, 5)); | |
119 chain.push_back(ScenePoint2D(-5, 5)); | |
120 layer->AddChain(chain, true, 0, 255, 0); | |
121 | |
122 double dy = 1.01; | |
123 chain.clear(); | |
124 chain.push_back(ScenePoint2D(-4, -4)); | |
125 chain.push_back(ScenePoint2D(4, -4 + dy)); | |
126 chain.push_back(ScenePoint2D(-4, -4 + 2.0 * dy)); | |
127 chain.push_back(ScenePoint2D(4, 2)); | |
128 layer->AddChain(chain, false, 0, 0, 255); | |
129 | |
130 scene.SetLayer(50, layer.release()); | |
131 } | |
132 | |
133 // Some text | |
134 { | |
135 std::auto_ptr<TextSceneLayer> layer(new TextSceneLayer); | |
136 layer->SetText("Hello"); | |
137 scene.SetLayer(100, layer.release()); | |
138 } | |
139 } | |
140 | |
141 | |
142 void TakeScreenshot(const std::string& target, | |
143 const OrthancStone::Scene2D& scene, | |
144 unsigned int canvasWidth, | |
145 unsigned int canvasHeight) | |
146 { | |
147 using namespace OrthancStone; | |
148 // Take a screenshot, then save it as PNG file | |
149 CairoCompositor compositor(scene, canvasWidth, canvasHeight); | |
150 compositor.SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, FONT_SIZE, Orthanc::Encoding_Latin1); | |
151 compositor.Refresh(); | |
152 | |
153 Orthanc::ImageAccessor canvas; | |
154 compositor.GetCanvas().GetReadOnlyAccessor(canvas); | |
155 | |
156 Orthanc::Image png(Orthanc::PixelFormat_RGB24, canvas.GetWidth(), canvas.GetHeight(), false); | |
157 Orthanc::ImageProcessing::Convert(png, canvas); | |
158 | |
159 Orthanc::PngWriter writer; | |
160 writer.WriteToFile(target, png); | |
161 } | |
162 | |
163 | |
164 void HandleApplicationEvent(const SDL_Event& event, | |
165 boost::shared_ptr<OrthancStone::ViewportController>& controller, | |
166 boost::shared_ptr<OrthancStone::IFlexiblePointerTracker>& activeTracker) | |
167 { | |
168 using namespace OrthancStone; | |
169 | |
170 Scene2D& scene = controller->GetScene(); | |
171 IViewport& viewport = controller->GetViewport(); | |
172 | |
173 if (event.type == SDL_MOUSEMOTION) | |
174 { | |
55 int scancodeCount = 0; | 175 int scancodeCount = 0; |
56 const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount); | 176 const uint8_t* keyboardState = SDL_GetKeyboardState(&scancodeCount); |
57 bool ctrlPressed(false); | 177 |
58 bool shiftPressed(false); | 178 if (activeTracker.get() == NULL && |
59 bool altPressed(false); | 179 SDL_SCANCODE_LCTRL < scancodeCount && |
60 | 180 keyboardState[SDL_SCANCODE_LCTRL]) |
61 if (SDL_SCANCODE_LCTRL < scancodeCount && keyboardState[SDL_SCANCODE_LCTRL]) | 181 { |
62 ctrlPressed = true; | 182 // The "left-ctrl" key is down, while no tracker is present |
63 if (SDL_SCANCODE_RCTRL < scancodeCount && keyboardState[SDL_SCANCODE_RCTRL]) | 183 |
64 ctrlPressed = true; | 184 PointerEvent e; |
65 if (SDL_SCANCODE_LSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_LSHIFT]) | 185 e.AddPosition(viewport.GetPixelCenterCoordinates(event.button.x, event.button.y)); |
66 shiftPressed = true; | 186 |
67 if (SDL_SCANCODE_RSHIFT < scancodeCount && keyboardState[SDL_SCANCODE_RSHIFT]) | 187 ScenePoint2D p = e.GetMainPosition().Apply(scene.GetCanvasToSceneTransform()); |
68 shiftPressed = true; | 188 |
69 if (SDL_SCANCODE_LALT < scancodeCount && keyboardState[SDL_SCANCODE_LALT]) | 189 char buf[64]; |
70 altPressed = true; | 190 sprintf(buf, "(%0.02f,%0.02f)", p.GetX(), p.GetY()); |
71 | 191 |
72 GuiAdapterMouseEvent guiEvent; | 192 if (scene.HasLayer(LAYER_POSITION)) |
73 ConvertFromPlatform(guiEvent, ctrlPressed, shiftPressed, altPressed, event); | 193 { |
74 PointerEvent pointerEvent; | 194 TextSceneLayer& layer = |
75 pointerEvent.AddPosition(compositor.GetPixelCenterCoordinates(event.button.x, event.button.y)); | 195 dynamic_cast<TextSceneLayer&>(scene.GetLayer(LAYER_POSITION)); |
76 | 196 layer.SetText(buf); |
77 interactor->OnMouseEvent(guiEvent, pointerEvent); | 197 layer.SetPosition(p.GetX(), p.GetY()); |
78 return; | 198 } |
79 } | 199 else |
80 else if ((event.type == SDL_KEYDOWN || event.type == SDL_KEYUP) && event.key.repeat == 0 /* Ignore key bounce */) | 200 { |
81 { | 201 std::auto_ptr<TextSceneLayer> |
82 GuiAdapterKeyboardEvent guiEvent; | 202 layer(new TextSceneLayer); |
83 ConvertFromPlatform(guiEvent, event); | 203 layer->SetColor(0, 255, 0); |
84 | 204 layer->SetText(buf); |
85 interactor->OnKeyboardEvent(guiEvent); | 205 layer->SetBorder(20); |
86 } | 206 layer->SetAnchor(BitmapAnchor_BottomCenter); |
87 | 207 layer->SetPosition(p.GetX(), p.GetY()); |
208 scene.SetLayer(LAYER_POSITION, layer.release()); | |
209 } | |
210 } | |
211 else | |
212 { | |
213 scene.DeleteLayer(LAYER_POSITION); | |
214 } | |
215 } | |
216 else if (event.type == SDL_MOUSEBUTTONDOWN) | |
217 { | |
218 PointerEvent e; | |
219 e.AddPosition(viewport.GetPixelCenterCoordinates(event.button.x, event.button.y)); | |
220 | |
221 switch (event.button.button) | |
222 { | |
223 case SDL_BUTTON_MIDDLE: | |
224 activeTracker = boost::make_shared<PanSceneTracker>(controller, e); | |
225 break; | |
226 | |
227 case SDL_BUTTON_RIGHT: | |
228 activeTracker = boost::make_shared<ZoomSceneTracker> | |
229 (controller, e, viewport.GetCanvasHeight()); | |
230 break; | |
231 | |
232 case SDL_BUTTON_LEFT: | |
233 activeTracker = boost::make_shared<RotateSceneTracker>(controller, e); | |
234 break; | |
235 | |
236 default: | |
237 break; | |
238 } | |
239 } | |
240 else if (event.type == SDL_KEYDOWN && | |
241 event.key.repeat == 0 /* Ignore key bounce */) | |
242 { | |
243 switch (event.key.keysym.sym) | |
244 { | |
245 case SDLK_s: | |
246 controller->FitContent(viewport.GetCanvasWidth(), | |
247 viewport.GetCanvasHeight()); | |
248 break; | |
249 | |
250 case SDLK_c: | |
251 TakeScreenshot("screenshot.png", scene, | |
252 viewport.GetCanvasWidth(), | |
253 viewport.GetCanvasHeight()); | |
254 break; | |
255 | |
256 default: | |
257 break; | |
258 } | |
259 } | |
88 } | 260 } |
89 | 261 |
90 | 262 |
91 static void GLAPIENTRY | 263 static void GLAPIENTRY |
92 OpenGLMessageCallback(GLenum source, | 264 OpenGLMessageCallback(GLenum source, |
104 type, severity, message ); | 276 type, severity, message ); |
105 } | 277 } |
106 } | 278 } |
107 | 279 |
108 | 280 |
109 void Run(boost::shared_ptr<OrthancStone::ViewportController> controller) | 281 void Run(OrthancStone::MessageBroker& broker, |
110 { | 282 OrthancStone::SdlViewport& viewport) |
111 SdlOpenGLWindow window("Hello", 1024, 768); | 283 { |
112 | 284 using namespace OrthancStone; |
113 controller->FitContent(window.GetCanvasWidth(), window.GetCanvasHeight()); | 285 |
286 boost::shared_ptr<ViewportController> controller( | |
287 new ViewportController(boost::make_shared<UndoStack>(), broker, viewport)); | |
114 | 288 |
115 glEnable(GL_DEBUG_OUTPUT); | 289 glEnable(GL_DEBUG_OUTPUT); |
116 glDebugMessageCallback(OpenGLMessageCallback, 0); | 290 glDebugMessageCallback(OpenGLMessageCallback, 0); |
117 | 291 |
118 boost::shared_ptr<OpenGLCompositor> compositor(new OpenGLCompositor(window, *controller->GetScene())); | 292 boost::shared_ptr<IFlexiblePointerTracker> tracker; |
119 compositor->SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, | 293 |
120 BASIC_SCENE_FONT_SIZE, Orthanc::Encoding_Latin1); | 294 bool firstShown = true; |
121 interactor->SetCompositor(compositor); | |
122 | |
123 bool stop = false; | 295 bool stop = false; |
124 while (!stop) | 296 while (!stop) |
125 { | 297 { |
126 compositor->Refresh(); | 298 viewport.Refresh(); |
127 | 299 |
128 SDL_Event event; | 300 SDL_Event event; |
129 while (!stop && | 301 while (!stop && |
130 SDL_PollEvent(&event)) | 302 SDL_PollEvent(&event)) |
131 { | 303 { |
132 if (event.type == SDL_QUIT) | 304 if (event.type == SDL_QUIT) |
133 { | 305 { |
134 stop = true; | 306 stop = true; |
135 break; | 307 break; |
136 } | 308 } |
137 else if (event.type == SDL_WINDOWEVENT && | 309 else if (event.type == SDL_MOUSEMOTION) |
138 event.window.event == SDL_WINDOWEVENT_SIZE_CHANGED) | 310 { |
139 { | 311 if (tracker) |
140 compositor->UpdateSize(); | 312 { |
313 PointerEvent e; | |
314 e.AddPosition(viewport.GetPixelCenterCoordinates( | |
315 event.button.x, event.button.y)); | |
316 tracker->PointerMove(e); | |
317 } | |
318 } | |
319 else if (event.type == SDL_MOUSEBUTTONUP) | |
320 { | |
321 if (tracker) | |
322 { | |
323 PointerEvent e; | |
324 e.AddPosition(viewport.GetPixelCenterCoordinates( | |
325 event.button.x, event.button.y)); | |
326 tracker->PointerUp(e); | |
327 if(!tracker->IsAlive()) | |
328 tracker.reset(); | |
329 } | |
330 } | |
331 else if (event.type == SDL_WINDOWEVENT) | |
332 { | |
333 switch (event.window.event) | |
334 { | |
335 case SDL_WINDOWEVENT_SIZE_CHANGED: | |
336 tracker.reset(); | |
337 break; | |
338 | |
339 case SDL_WINDOWEVENT_SHOWN: | |
340 if (firstShown) | |
341 { | |
342 // Once the window is first shown, fit the content to its size | |
343 controller->FitContent(viewport.GetCanvasWidth(), viewport.GetCanvasHeight()); | |
344 firstShown = false; | |
345 } | |
346 | |
347 break; | |
348 | |
349 default: | |
350 break; | |
351 } | |
141 } | 352 } |
142 else if (event.type == SDL_KEYDOWN && | 353 else if (event.type == SDL_KEYDOWN && |
143 event.key.repeat == 0 /* Ignore key bounce */) | 354 event.key.repeat == 0 /* Ignore key bounce */) |
144 { | 355 { |
145 switch (event.key.keysym.sym) | 356 switch (event.key.keysym.sym) |
146 { | 357 { |
147 case SDLK_f: | 358 case SDLK_f: |
148 window.GetWindow().ToggleMaximize(); | 359 viewport.GetContext().GetWindow().ToggleMaximize(); |
149 break; | 360 break; |
150 | 361 |
151 case SDLK_q: | 362 case SDLK_q: |
152 stop = true; | 363 stop = true; |
153 break; | 364 break; |
155 default: | 366 default: |
156 break; | 367 break; |
157 } | 368 } |
158 } | 369 } |
159 | 370 |
160 HandleApplicationEvent(controller, *compositor, event); | 371 HandleApplicationEvent(event, controller, tracker); |
161 } | 372 } |
162 | 373 |
163 SDL_Delay(1); | 374 SDL_Delay(1); |
164 } | 375 } |
165 interactor.reset(); | |
166 } | 376 } |
167 | 377 |
168 | 378 |
169 | 379 |
170 | 380 |
173 * Windows. Otherwise, one gets the linking error "undefined reference | 383 * Windows. Otherwise, one gets the linking error "undefined reference |
174 * to `SDL_main'". https://wiki.libsdl.org/FAQWindows | 384 * to `SDL_main'". https://wiki.libsdl.org/FAQWindows |
175 **/ | 385 **/ |
176 int main(int argc, char* argv[]) | 386 int main(int argc, char* argv[]) |
177 { | 387 { |
178 using namespace OrthancStone; | 388 OrthancStone::StoneInitialize(); |
179 StoneInitialize(); | |
180 Orthanc::Logging::EnableInfoLevel(true); | 389 Orthanc::Logging::EnableInfoLevel(true); |
181 | 390 |
182 try | 391 try |
183 { | 392 { |
184 MessageBroker broker; | 393 OrthancStone::SdlViewport viewport("Hello", 1024, 768); |
185 boost::shared_ptr<UndoStack> undoStack(new UndoStack); | 394 PrepareScene(viewport.GetScene()); |
186 boost::shared_ptr<ViewportController> controller = boost::make_shared<ViewportController>( | 395 |
187 undoStack, boost::ref(broker)); | 396 viewport.GetCompositor().SetFont(0, Orthanc::EmbeddedResources::UBUNTU_FONT, |
188 interactor.reset(new BasicScene2DInteractor(controller)); | 397 FONT_SIZE, Orthanc::Encoding_Latin1); |
189 PrepareScene(controller); | 398 |
190 Run(controller); | 399 OrthancStone::MessageBroker broker; |
400 Run(broker, viewport); | |
191 } | 401 } |
192 catch (Orthanc::OrthancException& e) | 402 catch (Orthanc::OrthancException& e) |
193 { | 403 { |
194 LOG(ERROR) << "EXCEPTION: " << e.What(); | 404 LOG(ERROR) << "EXCEPTION: " << e.What(); |
195 } | 405 } |
196 | 406 |
197 StoneFinalize(); | 407 OrthancStone::StoneFinalize(); |
198 | 408 |
199 return 0; | 409 return 0; |
200 } | 410 } |