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 }