comparison Applications/Sdl/BasicSdlApplication.cpp @ 221:d7b2590744f8 am

wip: building applications reusable in SDL and WASM
author am@osimis.io
date Mon, 11 Jun 2018 14:01:02 +0200
parents
children 84844649a8fd
comparison
equal deleted inserted replaced
219:26e3bfe30e66 221:d7b2590744f8
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-2018 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
22 #if ORTHANC_ENABLE_SDL != 1
23 #error this file shall be included only with the ORTHANC_ENABLE_SDL set to 1
24 #endif
25
26 #include "BasicSdlApplication.h"
27
28 #include "../../Framework/Toolbox/MessagingToolbox.h"
29 #include "SdlEngine.h"
30
31 #include <Core/Logging.h>
32 #include <Core/HttpClient.h>
33 #include <Plugins/Samples/Common/OrthancHttpConnection.h>
34
35 namespace OrthancStone
36 {
37 // Anonymous namespace to avoid clashes against other compilation modules
38 namespace
39 {
40 class LogStatusBar : public IStatusBar
41 {
42 public:
43 virtual void ClearMessage()
44 {
45 }
46
47 virtual void SetMessage(const std::string& message)
48 {
49 LOG(WARNING) << message;
50 }
51 };
52 }
53
54
55 static void DeclareSdlCommandLineOptions(boost::program_options::options_description& options)
56 {
57 // Declare the supported parameters
58 boost::program_options::options_description generic("Generic options");
59 generic.add_options()
60 ("help", "Display this help and exit")
61 ("verbose", "Be verbose in logs")
62 ("orthanc", boost::program_options::value<std::string>()->default_value("http://localhost:8042/"),
63 "URL to the Orthanc server")
64 ("username", "Username for the Orthanc server")
65 ("password", "Password for the Orthanc server")
66 ("https-verify", boost::program_options::value<bool>()->default_value(true), "Check HTTPS certificates")
67 ;
68
69 options.add(generic);
70
71 boost::program_options::options_description sdl("SDL options");
72 sdl.add_options()
73 ("width", boost::program_options::value<int>()->default_value(1024), "Initial width of the SDL window")
74 ("height", boost::program_options::value<int>()->default_value(768), "Initial height of the SDL window")
75 ("opengl", boost::program_options::value<bool>()->default_value(true), "Enable OpenGL in SDL")
76 ;
77
78 options.add(sdl);
79 }
80
81 // void BasicSdlApplication::DeclareCommandLineOptions(boost::program_options::options_description &options) {
82 // boost::program_options::options_description app("Application specifi options");
83
84 // for (IBasicApplication::StartupOptions::const_iterator it = startupOptions_.begin(); it != startupOptions_.end(); it++) {
85 // switch (it->type) {
86 // case IBasicApplication::StartupOptionValue::boolean:
87 // app.add_options()
88 // (it->name.c_str(), boost::program_options::value<int>()->default_value(std::stoi(it->defaultValue)), it->helpText.c_str());
89 // break;
90 // case IBasicApplication::StartupOptionValue::integer:
91 // app.add_options()
92 // (it->name.c_str(), boost::program_options::value<bool>()->default_value(it->defaultValue == "true"), it->helpText.c_str());
93 // break;
94 // case IBasicApplication::StartupOptionValue::string:
95 // app.add_options()
96 // (it->name.c_str(), boost::program_options::value<std::string>()->default_value(it->defaultValue), it->helpText.c_str());
97 // break;
98 // default:
99 // throw Orthanc::OrthancException(Orthanc::ErrorCode_NotImplemented);
100 // }
101 // }
102 // options.add(app);
103 // }
104
105 int BasicSdlApplication::ExecuteWithSdl(BasicSdlApplication& application,
106 int argc,
107 char* argv[])
108 {
109 /******************************************************************
110 * Initialize all the subcomponents of Orthanc Stone
111 ******************************************************************/
112
113 Orthanc::Logging::Initialize();
114 Orthanc::HttpClient::InitializeOpenSsl();
115 Orthanc::HttpClient::GlobalInitialize();
116 SdlWindow::GlobalInitialize();
117
118
119 /******************************************************************
120 * Declare and parse the command-line options of the application
121 ******************************************************************/
122
123 boost::program_options::options_description options;
124 DeclareSdlCommandLineOptions(options);
125 application.DeclareStartupOptions(options);
126
127 boost::program_options::variables_map parameters;
128 bool error = false;
129
130 try
131 {
132 boost::program_options::store(boost::program_options::command_line_parser(argc, argv).
133 options(options).run(), parameters);
134 boost::program_options::notify(parameters);
135 }
136 catch (boost::program_options::error& e)
137 {
138 LOG(ERROR) << "Error while parsing the command-line arguments: " << e.what();
139 error = true;
140 }
141
142
143 /******************************************************************
144 * Configure the application with the command-line parameters
145 ******************************************************************/
146
147 if (error || parameters.count("help"))
148 {
149 std::cout << std::endl
150 << "Usage: " << argv[0] << " [OPTION]..."
151 << std::endl
152 << "Orthanc, lightweight, RESTful DICOM server for healthcare and medical research."
153 << std::endl << std::endl
154 << "Demonstration application of Orthanc Stone using SDL."
155 << std::endl;
156
157 std::cout << options << "\n";
158 return error ? -1 : 0;
159 }
160
161 if (parameters.count("https-verify") &&
162 !parameters["https-verify"].as<bool>())
163 {
164 LOG(WARNING) << "Turning off verification of HTTPS certificates (unsafe)";
165 Orthanc::HttpClient::ConfigureSsl(false, "");
166 }
167
168 if (parameters.count("verbose"))
169 {
170 Orthanc::Logging::EnableInfoLevel(true);
171 }
172
173 if (!parameters.count("width") ||
174 !parameters.count("height") ||
175 !parameters.count("opengl"))
176 {
177 LOG(ERROR) << "Parameter \"width\", \"height\" or \"opengl\" is missing";
178 return -1;
179 }
180
181 int w = parameters["width"].as<int>();
182 int h = parameters["height"].as<int>();
183 if (w <= 0 || h <= 0)
184 {
185 LOG(ERROR) << "Parameters \"width\" and \"height\" must be positive";
186 return -1;
187 }
188
189 unsigned int width = static_cast<unsigned int>(w);
190 unsigned int height = static_cast<unsigned int>(h);
191 LOG(WARNING) << "Initial display size: " << width << "x" << height;
192
193 bool opengl = parameters["opengl"].as<bool>();
194 if (opengl)
195 {
196 LOG(WARNING) << "OpenGL is enabled, disable it with option \"--opengl=off\" if the application crashes";
197 }
198 else
199 {
200 LOG(WARNING) << "OpenGL is disabled, enable it with option \"--opengl=on\" for best performance";
201 }
202
203 bool success = true;
204 try
205 {
206 /****************************************************************
207 * Initialize the connection to the Orthanc server
208 ****************************************************************/
209
210 Orthanc::WebServiceParameters webService;
211
212 if (parameters.count("orthanc"))
213 {
214 webService.SetUrl(parameters["orthanc"].as<std::string>());
215 }
216
217 if (parameters.count("username"))
218 {
219 webService.SetUsername(parameters["username"].as<std::string>());
220 }
221
222 if (parameters.count("password"))
223 {
224 webService.SetPassword(parameters["password"].as<std::string>());
225 }
226
227 LOG(WARNING) << "URL to the Orthanc REST API: " << webService.GetUrl();
228
229 {
230 OrthancPlugins::OrthancHttpConnection orthanc(webService);
231 if (!MessagingToolbox::CheckOrthancVersion(orthanc))
232 {
233 LOG(ERROR) << "Your version of Orthanc is incompatible with Stone of Orthanc, please upgrade";
234 throw Orthanc::OrthancException(Orthanc::ErrorCode_NetworkProtocol);
235 }
236 }
237
238
239 /****************************************************************
240 * Initialize the application
241 ****************************************************************/
242
243 LOG(WARNING) << "Creating the widgets of the application";
244
245 LogStatusBar statusBar;
246 BasicApplicationContext& context = application.CreateApplicationContext(webService);
247
248 application.Initialize(statusBar, parameters);
249
250 {
251 BasicApplicationContext::ViewportLocker locker(context);
252 locker.GetViewport().SetStatusBar(statusBar);
253 }
254
255 std::string title = application.GetTitle();
256 if (title.empty())
257 {
258 title = "Stone of Orthanc";
259 }
260
261 {
262 /**************************************************************
263 * Run the application inside a SDL window
264 **************************************************************/
265
266 LOG(WARNING) << "Starting the application";
267
268 SdlWindow window(title.c_str(), width, height, opengl);
269 SdlEngine sdl(window, context);
270
271 {
272 BasicApplicationContext::ViewportLocker locker(context);
273 locker.GetViewport().Register(sdl); // (*)
274 }
275
276 context.Start();
277 sdl.Run();
278
279 LOG(WARNING) << "Stopping the application";
280
281 // Don't move the "Stop()" command below out of the block,
282 // otherwise the application might crash, because the
283 // "SdlEngine" is an observer of the viewport (*) and the
284 // update thread started by "context.Start()" would call a
285 // destructed object (the "SdlEngine" is deleted with the
286 // lexical scope).
287 context.Stop();
288 }
289
290
291 /****************************************************************
292 * Finalize the application
293 ****************************************************************/
294
295 LOG(WARNING) << "The application has stopped";
296 application.Finalize();
297 }
298 catch (Orthanc::OrthancException& e)
299 {
300 LOG(ERROR) << "EXCEPTION: " << e.What();
301 success = false;
302 }
303
304
305 /******************************************************************
306 * Finalize all the subcomponents of Orthanc Stone
307 ******************************************************************/
308
309 SdlWindow::GlobalFinalize();
310 Orthanc::HttpClient::GlobalFinalize();
311 Orthanc::HttpClient::FinalizeOpenSsl();
312
313 return (success ? 0 : -1);
314 }
315
316 }