diff options
Diffstat (limited to '')
-rw-r--r-- | libraries/irrlicht-1.8.1/examples/25.XmlHandling/main.cpp | 505 |
1 files changed, 505 insertions, 0 deletions
diff --git a/libraries/irrlicht-1.8.1/examples/25.XmlHandling/main.cpp b/libraries/irrlicht-1.8.1/examples/25.XmlHandling/main.cpp new file mode 100644 index 0000000..3eb261d --- /dev/null +++ b/libraries/irrlicht-1.8.1/examples/25.XmlHandling/main.cpp | |||
@@ -0,0 +1,505 @@ | |||
1 | /** Example 025 Xml Handling | ||
2 | |||
3 | Demonstrates loading and saving of configurations via XML | ||
4 | |||
5 | @author Y.M. Bosman \<yoran.bosman@gmail.com\> | ||
6 | |||
7 | This demo features a fully usable system for configuration handling. The code | ||
8 | can easily be integrated into own apps. | ||
9 | |||
10 | */ | ||
11 | |||
12 | #include <irrlicht.h> | ||
13 | |||
14 | using namespace irr; | ||
15 | using namespace core; | ||
16 | using namespace scene; | ||
17 | using namespace video; | ||
18 | using namespace io; | ||
19 | using namespace gui; | ||
20 | |||
21 | #ifdef _IRR_WINDOWS_ | ||
22 | #pragma comment(lib, "Irrlicht.lib") | ||
23 | #endif | ||
24 | |||
25 | |||
26 | /* SettingManager class. | ||
27 | |||
28 | This class loads and writes the settings and manages the options. | ||
29 | |||
30 | The class makes use of irrMap which is a an associative arrays using a | ||
31 | red-black tree it allows easy mapping of a key to a value, along the way there | ||
32 | is some information on how to use it. | ||
33 | */ | ||
34 | |||
35 | class SettingManager | ||
36 | { | ||
37 | public: | ||
38 | |||
39 | // Construct setting managers and set default settings | ||
40 | SettingManager(const stringw& settings_file): SettingsFile(settings_file), NullDevice(0) | ||
41 | { | ||
42 | // Irrlicht null device, we want to load settings before we actually created our device, therefore, nulldevice | ||
43 | NullDevice = irr::createDevice(irr::video::EDT_NULL); | ||
44 | |||
45 | //DriverOptions is an irrlicht map, | ||
46 | //we can insert values in the map in two ways by calling insert(key,value) or by using the [key] operator | ||
47 | //the [] operator overrides values if they already exist | ||
48 | DriverOptions.insert(L"Software", EDT_SOFTWARE); | ||
49 | DriverOptions.insert(L"OpenGL", EDT_OPENGL); | ||
50 | DriverOptions.insert(L"Direct3D9", EDT_DIRECT3D9); | ||
51 | |||
52 | //some resolution options | ||
53 | ResolutionOptions.insert(L"640x480", dimension2du(640,480)); | ||
54 | ResolutionOptions.insert(L"800x600", dimension2du(800,600)); | ||
55 | ResolutionOptions.insert(L"1024x768", dimension2du(1024,768)); | ||
56 | |||
57 | //our preferred defaults | ||
58 | SettingMap.insert(L"driver", L"Direct3D9"); | ||
59 | SettingMap.insert(L"resolution", L"640x480"); | ||
60 | SettingMap.insert(L"fullscreen", L"0"); //0 is false | ||
61 | } | ||
62 | |||
63 | // Destructor, you could store settings automatically on exit of your | ||
64 | // application if you wanted to in our case we simply drop the | ||
65 | // nulldevice | ||
66 | ~SettingManager() | ||
67 | { | ||
68 | if (NullDevice) | ||
69 | { | ||
70 | NullDevice->closeDevice(); | ||
71 | NullDevice->drop(); | ||
72 | } | ||
73 | }; | ||
74 | |||
75 | /* | ||
76 | Load xml from disk, overwrite default settings | ||
77 | The xml we are trying to load has the following structure | ||
78 | settings nested in sections nested in the root node, like so | ||
79 | <pre> | ||
80 | <?xml version="1.0"?> | ||
81 | <mygame> | ||
82 | <video> | ||
83 | <setting name="driver" value="Direct3D9" /> | ||
84 | <setting name="fullscreen" value="0" /> | ||
85 | <setting name="resolution" value="1024x768" /> | ||
86 | </video> | ||
87 | </mygame> | ||
88 | </pre> | ||
89 | */ | ||
90 | bool load() | ||
91 | { | ||
92 | //if not able to create device don't attempt to load | ||
93 | if (!NullDevice) | ||
94 | return false; | ||
95 | |||
96 | irr::io::IXMLReader* xml = NullDevice->getFileSystem()->createXMLReader(SettingsFile); //create xml reader | ||
97 | if (!xml) | ||
98 | return false; | ||
99 | |||
100 | const stringw settingTag(L"setting"); //we'll be looking for this tag in the xml | ||
101 | stringw currentSection; //keep track of our current section | ||
102 | const stringw videoTag(L"video"); //constant for videotag | ||
103 | |||
104 | //while there is more to read | ||
105 | while (xml->read()) | ||
106 | { | ||
107 | //check the node type | ||
108 | switch (xml->getNodeType()) | ||
109 | { | ||
110 | //we found a new element | ||
111 | case irr::io::EXN_ELEMENT: | ||
112 | { | ||
113 | //we currently are in the empty or mygame section and find the video tag so we set our current section to video | ||
114 | if (currentSection.empty() && videoTag.equals_ignore_case(xml->getNodeName())) | ||
115 | { | ||
116 | currentSection = videoTag; | ||
117 | } | ||
118 | //we are in the video section and we find a setting to parse | ||
119 | else if (currentSection.equals_ignore_case(videoTag) && settingTag.equals_ignore_case(xml->getNodeName() )) | ||
120 | { | ||
121 | //read in the key | ||
122 | stringw key = xml->getAttributeValueSafe(L"name"); | ||
123 | //if there actually is a key to set | ||
124 | if (!key.empty()) | ||
125 | { | ||
126 | //set the setting in the map to the value, | ||
127 | //the [] operator overrides values if they already exist or inserts a new key value | ||
128 | //pair into the settings map if it was not defined yet | ||
129 | SettingMap[key] = xml->getAttributeValueSafe(L"value"); | ||
130 | } | ||
131 | } | ||
132 | |||
133 | //.. | ||
134 | // You can add your own sections and tags to read in here | ||
135 | //.. | ||
136 | } | ||
137 | break; | ||
138 | |||
139 | //we found the end of an element | ||
140 | case irr::io::EXN_ELEMENT_END: | ||
141 | //we were at the end of the video section so we reset our tag | ||
142 | currentSection=L""; | ||
143 | break; | ||
144 | } | ||
145 | } | ||
146 | |||
147 | // don't forget to delete the xml reader | ||
148 | xml->drop(); | ||
149 | |||
150 | return true; | ||
151 | } | ||
152 | |||
153 | // Save the xml to disk. We use the nulldevice. | ||
154 | bool save() | ||
155 | { | ||
156 | |||
157 | //if not able to create device don't attempt to save | ||
158 | if (!NullDevice) | ||
159 | return false; | ||
160 | |||
161 | //create xml writer | ||
162 | irr::io::IXMLWriter* xwriter = NullDevice->getFileSystem()->createXMLWriter( SettingsFile ); | ||
163 | if (!xwriter) | ||
164 | return false; | ||
165 | |||
166 | //write out the obligatory xml header. Each xml-file needs to have exactly one of those. | ||
167 | xwriter->writeXMLHeader(); | ||
168 | |||
169 | //start element mygame, you replace the label "mygame" with anything you want | ||
170 | xwriter->writeElement(L"mygame"); | ||
171 | xwriter->writeLineBreak(); //new line | ||
172 | |||
173 | //start section with video settings | ||
174 | xwriter->writeElement(L"video"); | ||
175 | xwriter->writeLineBreak(); //new line | ||
176 | |||
177 | // getIterator gets us a pointer to the first node of the settings map | ||
178 | // every iteration we increase the iterator which gives us the next map node | ||
179 | // until we reach the end we write settings one by one by using the nodes key and value functions | ||
180 | map<stringw, stringw>::Iterator i = SettingMap.getIterator(); | ||
181 | for(; !i.atEnd(); i++) | ||
182 | { | ||
183 | //write element as <setting name="key" value="x" /> | ||
184 | //the second parameter indicates this is an empty element with no children, just attributes | ||
185 | xwriter->writeElement(L"setting",true, L"name", i->getKey().c_str(), L"value",i->getValue().c_str() ); | ||
186 | xwriter->writeLineBreak(); | ||
187 | } | ||
188 | xwriter->writeLineBreak(); | ||
189 | |||
190 | //close video section | ||
191 | xwriter->writeClosingTag(L"video"); | ||
192 | xwriter->writeLineBreak(); | ||
193 | |||
194 | //.. | ||
195 | // You can add writing sound settings, savegame information etc | ||
196 | //.. | ||
197 | |||
198 | //close mygame section | ||
199 | xwriter->writeClosingTag(L"mygame"); | ||
200 | |||
201 | //delete xml writer | ||
202 | xwriter->drop(); | ||
203 | |||
204 | return true; | ||
205 | } | ||
206 | |||
207 | // Set setting in our manager | ||
208 | void setSetting(const stringw& name, const stringw& value) | ||
209 | { | ||
210 | SettingMap[name]=value; | ||
211 | } | ||
212 | |||
213 | // set setting overload to quickly assign integers to our setting map | ||
214 | void setSetting(const stringw& name, s32 value) | ||
215 | { | ||
216 | SettingMap[name]=stringw(value); | ||
217 | } | ||
218 | |||
219 | // Get setting as string | ||
220 | stringw getSetting(const stringw& key) const | ||
221 | { | ||
222 | //the find function or irrmap returns a pointer to a map Node | ||
223 | //if the key can be found, otherwise it returns null | ||
224 | //the map node has the function getValue and getKey, as we already know the key, we return node->getValue() | ||
225 | map<stringw, stringw>::Node* n = SettingMap.find(key); | ||
226 | if (n) | ||
227 | return n->getValue(); | ||
228 | else | ||
229 | return L""; | ||
230 | } | ||
231 | |||
232 | // | ||
233 | bool getSettingAsBoolean(const stringw& key ) const | ||
234 | { | ||
235 | stringw s = getSetting(key); | ||
236 | if (s.empty()) | ||
237 | return false; | ||
238 | return s.equals_ignore_case(L"1"); | ||
239 | } | ||
240 | |||
241 | // | ||
242 | s32 getSettingAsInteger(const stringw& key) const | ||
243 | { | ||
244 | //we implicitly cast to string instead of stringw because strtol10 does not accept wide strings | ||
245 | const stringc s = getSetting(key); | ||
246 | if (s.empty()) | ||
247 | return 0; | ||
248 | |||
249 | return strtol10(s.c_str()); | ||
250 | } | ||
251 | |||
252 | public: | ||
253 | map<stringw, s32> DriverOptions; //available options for driver config | ||
254 | map<stringw, dimension2du> ResolutionOptions; //available options for resolution config | ||
255 | private: | ||
256 | SettingManager(const SettingManager& other); // defined but not implemented | ||
257 | SettingManager& operator=(const SettingManager& other); // defined but not implemented | ||
258 | |||
259 | map<stringw, stringw> SettingMap; //current config | ||
260 | |||
261 | stringw SettingsFile; // location of the xml, usually the | ||
262 | irr::IrrlichtDevice* NullDevice; | ||
263 | }; | ||
264 | |||
265 | /* | ||
266 | Application context for global variables | ||
267 | */ | ||
268 | struct SAppContext | ||
269 | { | ||
270 | SAppContext() | ||
271 | : Device(0),Gui(0), Driver(0), Settings(0), ShouldQuit(false), | ||
272 | ButtonSave(0), ButtonExit(0), ListboxDriver(0), | ||
273 | ListboxResolution(0), CheckboxFullscreen(0) | ||
274 | { | ||
275 | } | ||
276 | |||
277 | ~SAppContext() | ||
278 | { | ||
279 | if (Settings) | ||
280 | delete Settings; | ||
281 | |||
282 | if (Device) | ||
283 | { | ||
284 | Device->closeDevice(); | ||
285 | Device->drop(); | ||
286 | } | ||
287 | } | ||
288 | |||
289 | IrrlichtDevice* Device; | ||
290 | IGUIEnvironment* Gui; | ||
291 | IVideoDriver* Driver; | ||
292 | SettingManager* Settings; | ||
293 | bool ShouldQuit; | ||
294 | |||
295 | //settings dialog | ||
296 | IGUIButton* ButtonSave; | ||
297 | IGUIButton* ButtonExit; | ||
298 | IGUIListBox* ListboxDriver; | ||
299 | IGUIListBox* ListboxResolution; | ||
300 | IGUICheckBox* CheckboxFullscreen; | ||
301 | }; | ||
302 | |||
303 | /* | ||
304 | A typical event receiver. | ||
305 | */ | ||
306 | class MyEventReceiver : public IEventReceiver | ||
307 | { | ||
308 | public: | ||
309 | MyEventReceiver(SAppContext & a) : App(a) { } | ||
310 | |||
311 | virtual bool OnEvent(const SEvent& event) | ||
312 | { | ||
313 | if (event.EventType == EET_GUI_EVENT ) | ||
314 | { | ||
315 | switch ( event.GUIEvent.EventType ) | ||
316 | { | ||
317 | //handle button click events | ||
318 | case EGET_BUTTON_CLICKED: | ||
319 | { | ||
320 | //Our save button was called so we obtain the settings from our dialog and save them | ||
321 | if ( event.GUIEvent.Caller == App.ButtonSave ) | ||
322 | { | ||
323 | //if there is a selection write it | ||
324 | if ( App.ListboxDriver->getSelected() != -1) | ||
325 | App.Settings->setSetting(L"driver", App.ListboxDriver->getListItem(App.ListboxDriver->getSelected())); | ||
326 | |||
327 | //if there is a selection write it | ||
328 | if ( App.ListboxResolution->getSelected() != -1) | ||
329 | App.Settings->setSetting(L"resolution", App.ListboxResolution->getListItem(App.ListboxResolution->getSelected())); | ||
330 | |||
331 | App.Settings->setSetting(L"fullscreen", App.CheckboxFullscreen->isChecked()); | ||
332 | |||
333 | |||
334 | if (App.Settings->save()) | ||
335 | { | ||
336 | App.Gui->addMessageBox(L"settings save",L"settings saved, please restart for settings to change effect","",true); | ||
337 | } | ||
338 | } | ||
339 | // cancel/exit button clicked, tell the application to exit | ||
340 | else if ( event.GUIEvent.Caller == App.ButtonExit) | ||
341 | { | ||
342 | App.ShouldQuit = true; | ||
343 | } | ||
344 | } | ||
345 | break; | ||
346 | } | ||
347 | } | ||
348 | |||
349 | return false; | ||
350 | } | ||
351 | |||
352 | private: | ||
353 | SAppContext & App; | ||
354 | }; | ||
355 | |||
356 | |||
357 | /* | ||
358 | Function to create a video settings dialog | ||
359 | This dialog shows the current settings from the configuration xml and allows them to be changed | ||
360 | */ | ||
361 | void createSettingsDialog(SAppContext& app) | ||
362 | { | ||
363 | // first get rid of alpha in gui | ||
364 | for (irr::s32 i=0; i<irr::gui::EGDC_COUNT ; ++i) | ||
365 | { | ||
366 | irr::video::SColor col = app.Gui->getSkin()->getColor((irr::gui::EGUI_DEFAULT_COLOR)i); | ||
367 | col.setAlpha(255); | ||
368 | app.Gui->getSkin()->setColor((irr::gui::EGUI_DEFAULT_COLOR)i, col); | ||
369 | } | ||
370 | |||
371 | //create video settings windows | ||
372 | gui::IGUIWindow* windowSettings = app.Gui->addWindow(rect<s32>(10,10,400,400),true,L"Videosettings"); | ||
373 | app.Gui->addStaticText (L"Select your desired video settings", rect< s32 >(10,20, 200, 40), false, true, windowSettings); | ||
374 | |||
375 | // add listbox for driver choice | ||
376 | app.Gui->addStaticText (L"Driver", rect< s32 >(10,50, 200, 60), false, true, windowSettings); | ||
377 | app.ListboxDriver = app.Gui->addListBox(rect<s32>(10,60,220,120), windowSettings, 1,true); | ||
378 | |||
379 | //add all available options to the driver choice listbox | ||
380 | map<stringw, s32>::Iterator i = app.Settings->DriverOptions.getIterator(); | ||
381 | for(; !i.atEnd(); i++) | ||
382 | app.ListboxDriver->addItem(i->getKey().c_str()); | ||
383 | |||
384 | //set currently selected driver | ||
385 | app.ListboxDriver->setSelected(app.Settings->getSetting("driver").c_str()); | ||
386 | |||
387 | // add listbox for resolution choice | ||
388 | app.Gui->addStaticText (L"Resolution", rect< s32 >(10,130, 200, 140), false, true, windowSettings); | ||
389 | app.ListboxResolution = app.Gui->addListBox(rect<s32>(10,140,220,200), windowSettings, 1,true); | ||
390 | |||
391 | //add all available options to the resolution listbox | ||
392 | map<stringw, dimension2du>::Iterator ri = app.Settings->ResolutionOptions.getIterator(); | ||
393 | for(; !ri.atEnd(); ri++) | ||
394 | app.ListboxResolution->addItem(ri->getKey().c_str()); | ||
395 | |||
396 | //set currently selected resolution | ||
397 | app.ListboxResolution->setSelected(app.Settings->getSetting("resolution").c_str()); | ||
398 | |||
399 | //add checkbox to toggle fullscreen, initially set to loaded setting | ||
400 | app.CheckboxFullscreen = app.Gui->addCheckBox( | ||
401 | app.Settings->getSettingAsBoolean("fullscreen"), | ||
402 | rect<s32>(10,220,220,240), windowSettings, -1, | ||
403 | L"Fullscreen"); | ||
404 | |||
405 | //last but not least add save button | ||
406 | app.ButtonSave = app.Gui->addButton( | ||
407 | rect<s32>(80,250,150,270), windowSettings, 2, | ||
408 | L"Save video settings"); | ||
409 | |||
410 | //exit/cancel button | ||
411 | app.ButtonExit = app.Gui->addButton( | ||
412 | rect<s32>(160,250,240,270), windowSettings, 2, | ||
413 | L"Cancel and exit"); | ||
414 | } | ||
415 | |||
416 | /* | ||
417 | The main function. Creates all objects and does the XML handling. | ||
418 | */ | ||
419 | int main() | ||
420 | { | ||
421 | //create new application context | ||
422 | SAppContext app; | ||
423 | |||
424 | //create device creation parameters that can get overwritten by our settings file | ||
425 | SIrrlichtCreationParameters param; | ||
426 | param.DriverType = EDT_SOFTWARE; | ||
427 | param.WindowSize.set(640,480); | ||
428 | |||
429 | // Try to load config. | ||
430 | // I leave it as an exercise of the reader to store the configuration in the local application data folder, | ||
431 | // the only logical place to store config data for games. For all other operating systems I redirect to your manuals | ||
432 | app.Settings = new SettingManager("../../media/settings.xml"); | ||
433 | if ( !app.Settings->load() ) | ||
434 | { | ||
435 | // ... | ||
436 | // Here add your own exception handling, for now we continue because there are defaults set in SettingManager constructor | ||
437 | // ... | ||
438 | } | ||
439 | else | ||
440 | { | ||
441 | //settings xml loaded from disk, | ||
442 | |||
443 | //map driversetting to driver type and test if the setting is valid | ||
444 | //the DriverOptions map contains string representations mapped to to irrlicht E_DRIVER_TYPE enum | ||
445 | //e.g "direct3d9" will become 4 | ||
446 | //see DriverOptions in the settingmanager class for details | ||
447 | map<stringw, s32>::Node* driver = app.Settings->DriverOptions.find( app.Settings->getSetting("driver") ); | ||
448 | |||
449 | if (driver) | ||
450 | { | ||
451 | if ( irr::IrrlichtDevice::isDriverSupported( static_cast<E_DRIVER_TYPE>( driver->getValue() ))) | ||
452 | { | ||
453 | // selected driver is supported, so we use it. | ||
454 | param.DriverType = static_cast<E_DRIVER_TYPE>( driver->getValue()); | ||
455 | } | ||
456 | } | ||
457 | |||
458 | //map resolution setting to dimension in a similar way as demonstrated above | ||
459 | map<stringw, dimension2du>::Node* res = app.Settings->ResolutionOptions.find( app.Settings->getSetting("resolution") ); | ||
460 | if (res) | ||
461 | { | ||
462 | param.WindowSize = res->getValue(); | ||
463 | } | ||
464 | |||
465 | //get fullscreen setting from config | ||
466 | param.Fullscreen = app.Settings->getSettingAsBoolean("fullscreen"); | ||
467 | } | ||
468 | |||
469 | //create the irrlicht device using the settings | ||
470 | app.Device = createDeviceEx(param); | ||
471 | if (app.Device == 0) | ||
472 | { | ||
473 | // You can add your own exception handling on driver failure | ||
474 | exit(0); | ||
475 | } | ||
476 | |||
477 | app.Device->setWindowCaption(L"Xmlhandling - Irrlicht engine tutorial"); | ||
478 | app.Driver = app.Device->getVideoDriver(); | ||
479 | app.Gui = app.Device->getGUIEnvironment(); | ||
480 | |||
481 | createSettingsDialog(app); | ||
482 | |||
483 | //set event receiver so we can respond to gui events | ||
484 | MyEventReceiver receiver(app); | ||
485 | app.Device->setEventReceiver(&receiver); | ||
486 | |||
487 | //enter main loop | ||
488 | while (!app.ShouldQuit && app.Device->run()) | ||
489 | { | ||
490 | if (app.Device->isWindowActive()) | ||
491 | { | ||
492 | app.Driver->beginScene(true, true, SColor(0,200,200,200)); | ||
493 | app.Gui->drawAll(); | ||
494 | app.Driver->endScene(); | ||
495 | } | ||
496 | app.Device->sleep(10); | ||
497 | } | ||
498 | |||
499 | //app destroys device in destructor | ||
500 | |||
501 | return 0; | ||
502 | } | ||
503 | |||
504 | /* | ||
505 | **/ | ||