1//============================================================================
2//
3// SSSS tt lll lll
4// SS SS tt ll ll
5// SS tttttt eeee ll ll aaaa
6// SSSS tt ee ee ll ll aa
7// SS tt eeeeee ll ll aaaaa -- "An Atari 2600 VCS Emulator"
8// SS SS tt ee ll ll aa aa
9// SSSS ttt eeeee llll llll aaaaa
10//
11// Copyright (c) 1995-2019 by Bradford W. Mott, Stephen Anthony
12// and the Stella Team
13//
14// See the file "License.txt" for information on usage and redistribution of
15// this file, and for a DISCLAIMER OF ALL WARRANTIES.
16//============================================================================
17
18#ifndef OSYSTEM_HXX
19#define OSYSTEM_HXX
20
21class Console;
22class FrameBuffer;
23class EventHandler;
24class Properties;
25class PropertiesSet;
26class Random;
27class Sound;
28class StateManager;
29class TimerManager;
30class EmulationWorker;
31class AudioSettings;
32#ifdef CHEATCODE_SUPPORT
33 class CheatManager;
34#endif
35#ifdef DEBUGGER_SUPPORT
36 class Debugger;
37#endif
38#ifdef GUI_SUPPORT
39 class CommandMenu;
40 class Launcher;
41 class Menu;
42 class TimeMachine;
43 class VideoDialog;
44#endif
45#ifdef PNG_SUPPORT
46 class PNGLibrary;
47#endif
48#ifdef SQLITE_SUPPORT
49 class SettingsDb;
50#endif
51
52#include <chrono>
53
54#include "FSNode.hxx"
55#include "FrameBufferConstants.hxx"
56#include "EventHandlerConstants.hxx"
57#include "FpsMeter.hxx"
58#include "Settings.hxx"
59#include "Logger.hxx"
60#include "bspf.hxx"
61#include "repository/KeyValueRepository.hxx"
62
63/**
64 This class provides an interface for accessing operating system specific
65 functions. It also comprises an overall parent object, to which all the
66 other objects belong.
67
68 @author Stephen Anthony
69*/
70class OSystem
71{
72 friend class EventHandler;
73
74 public:
75 OSystem();
76 virtual ~OSystem();
77
78 /**
79 Create all child objects which belong to this OSystem
80 */
81 virtual bool create();
82
83 /**
84 Creates the various framebuffers/renderers available in this system.
85 Note that it will only create one type per run of Stella.
86
87 @return Success or failure of the framebuffer creation
88 */
89 FBInitStatus createFrameBuffer();
90
91 public:
92 /**
93 Get the event handler of the system.
94
95 @return The event handler
96 */
97 EventHandler& eventHandler() const { return *myEventHandler; }
98
99 /**
100 Get the frame buffer of the system.
101
102 @return The frame buffer
103 */
104 FrameBuffer& frameBuffer() const { return *myFrameBuffer; }
105
106 /**
107 Get the sound object of the system.
108
109 @return The sound object
110 */
111 Sound& sound() const { return *mySound; }
112
113 /**
114 Get the settings object of the system.
115
116 @return The settings object
117 */
118 Settings& settings() const { return *mySettings; }
119
120 /**
121 Get the random object of the system.
122
123 @return The random object
124 */
125 Random& random() const { return *myRandom; }
126
127 /**
128 Get the set of game properties for the system.
129
130 @return The properties set object
131 */
132 PropertiesSet& propSet() const { return *myPropSet; }
133
134 /**
135 Get the console of the system. The console won't always exist,
136 so we should test if it's available.
137
138 @return The console object
139 */
140 Console& console() const { return *myConsole; }
141 bool hasConsole() const;
142
143 /**
144 Get the audio settings object of the system.
145
146 @return The audio settings object
147 */
148 AudioSettings& audioSettings() { return *myAudioSettings; }
149
150 /**
151 Get the state manager of the system.
152
153 @return The statemanager object
154 */
155 StateManager& state() const { return *myStateManager; }
156
157 /**
158 Get the timer/callback manager of the system.
159
160 @return The timermanager object
161 */
162 TimerManager& timer() const { return *myTimerManager; }
163
164 /**
165 This method should be called to initiate the process of loading settings
166 from the config file. It takes care of loading settings, applying
167 commandline overrides, and finally validating all settings.
168 */
169 void loadConfig(const Settings::Options& options);
170
171 /**
172 This method should be called to save the current settings. It first asks
173 each subsystem to update its settings, then it saves all settings to the
174 config file.
175 */
176 void saveConfig();
177
178 #ifdef CHEATCODE_SUPPORT
179 /**
180 Get the cheat manager of the system.
181
182 @return The cheatmanager object
183 */
184 CheatManager& cheat() const { return *myCheatManager; }
185 #endif
186
187 #ifdef DEBUGGER_SUPPORT
188 /**
189 Get the ROM debugger of the system.
190
191 @return The debugger object
192 */
193 Debugger& debugger() const { return *myDebugger; }
194 #endif
195
196 #ifdef GUI_SUPPORT
197 /**
198 Get the settings menu of the system.
199
200 @return The settings menu object
201 */
202 Menu& menu() const { return *myMenu; }
203
204 /**
205 Get the command menu of the system.
206
207 @return The command menu object
208 */
209 CommandMenu& commandMenu() const { return *myCommandMenu; }
210
211 /**
212 Get the ROM launcher of the system.
213
214 @return The launcher object
215 */
216 Launcher& launcher() const { return *myLauncher; }
217
218 /**
219 Get the time machine of the system (manages state files).
220
221 @return The time machine object
222 */
223 TimeMachine& timeMachine() const { return *myTimeMachine; }
224 #endif
225
226 #ifdef PNG_SUPPORT
227 /**
228 Get the PNG handler of the system.
229
230 @return The PNGlib object
231 */
232 PNGLibrary& png() const { return *myPNGLib; }
233 #endif
234
235 /**
236 Set all config file paths for the OSystem.
237 */
238 void setConfigPaths();
239
240 /**
241 Return the default full/complete directory name for storing data.
242 */
243 const string& baseDir() const { return myBaseDir; }
244
245 /**
246 Return the full/complete directory name for storing state files.
247 */
248 const string& stateDir() const { return myStateDir; }
249
250 /**
251 Return the full/complete directory name for storing nvram
252 (flash/EEPROM) files.
253 */
254 const string& nvramDir() const { return myNVRamDir; }
255
256 #ifdef CHEATCODE_SUPPORT
257 /**
258 This method should be called to get the full path of the cheat file.
259
260 @return String representing the full path of the cheat filename.
261 */
262 const string& cheatFile() const { return myCheatFile; }
263 #endif
264
265 #ifdef PNG_SUPPORT
266 /**
267 Return the full/complete directory name for saving and loading
268 PNG snapshots.
269 */
270 const string& snapshotSaveDir() const { return mySnapshotSaveDir; }
271 const string& snapshotLoadDir() const { return mySnapshotLoadDir; }
272 #endif
273
274 /**
275 This method should be called to get the full path of the
276 (optional) palette file.
277
278 @return String representing the full path of the properties filename.
279 */
280 const string& paletteFile() const { return myPaletteFile; }
281
282 /**
283 This method should be called to get the full path of the currently
284 loaded ROM.
285
286 @return FSNode object representing the ROM file.
287 */
288 const FilesystemNode& romFile() const { return myRomFile; }
289
290 /**
291 The default locations for saving and loading various files that
292 don't already have a specific location.
293 */
294 const string& defaultSaveDir() const { return myDefaultSaveDir; }
295 const string& defaultLoadDir() const { return myDefaultLoadDir; }
296
297 /**
298 Open the given ROM and return an array containing its contents.
299 Also, the properties database is updated with a valid ROM name
300 for this ROM (if necessary).
301
302 @param rom The file node of the ROM to open (contains path)
303 @param md5 The md5 calculated from the ROM file
304 (will be recalculated if necessary)
305 @param size The amount of data read into the image array
306
307 @return Unique pointer to the array
308 */
309 ByteBuffer openROM(const FilesystemNode& rom, string& md5, uInt32& size);
310
311 /**
312 Creates a new game console from the specified romfile, and correctly
313 initializes the system state to start emulation of the Console.
314
315 @param rom The FSNode of the ROM to use (contains path, etc)
316 @param md5 The MD5sum of the ROM
317 @param newrom Whether this is a new ROM, or a reload of current one
318
319 @return String indicating any error message (EmptyString for no errors)
320 */
321 string createConsole(const FilesystemNode& rom, const string& md5 = "",
322 bool newrom = true);
323
324 /**
325 Reloads the current console (essentially deletes and re-creates it).
326 This can be thought of as a real console off/on toggle.
327
328 @return True on successful creation, otherwise false
329 */
330 bool reloadConsole();
331
332 /**
333 Creates a new ROM launcher, to select a new ROM to emulate.
334
335 @param startdir The directory to use when opening the launcher;
336 if blank, use 'romdir' setting.
337
338 @return True on successful creation, otherwise false
339 */
340 bool createLauncher(const string& startdir = "");
341
342 /**
343 Answers whether the ROM launcher was actually successfully used
344 at some point since the app started.
345
346 @return True if launcher was ever used, otherwise false
347 */
348 bool launcherUsed() const { return myLauncherUsed; }
349
350 /**
351 Gets all possible info about the ROM by creating a temporary
352 Console object and querying it.
353
354 @param romfile The file node of the ROM to use
355 @return Some information about this ROM
356 */
357 string getROMInfo(const FilesystemNode& romfile);
358
359 /**
360 The features which are conditionally compiled into Stella.
361
362 @return The supported features
363 */
364 const string& features() const { return myFeatures; }
365
366 /**
367 The build information for Stella (toolkit version, architecture, etc).
368
369 @return The build info
370 */
371 const string& buildInfo() const { return myBuildInfo; }
372
373 /**
374 Issue a quit event to the OSystem.
375 */
376 void quit() { myQuitLoop = true; }
377
378 /**
379 Get the system messages logged up to this point.
380
381 @return The list of log messages
382 */
383 const string& logMessages() const { return myLogMessages; }
384
385 /**
386 Reset FPS measurement.
387 */
388 void resetFps();
389
390 float frameRate() const;
391
392 /**
393 Attempt to override the base directory that will be used by derived
394 classes, and use this one instead. Note that this is only a hint;
395 derived classes are free to ignore this, as some can't use an
396 alternate base directory.
397
398 Alternatively, attempt to use the application directory directly.
399 Again, this is not supported on all systems, so it may be simply
400 ignored.
401 */
402 static void overrideBaseDir(const string& path) { ourOverrideBaseDir = path; }
403 static void overrideBaseDirWithApp() { ourOverrideBaseDirWithApp = true; }
404
405 public:
406 //////////////////////////////////////////////////////////////////////
407 // The following methods are system-specific and can be overrided in
408 // derived classes. Otherwise, the base methods will be used.
409 //////////////////////////////////////////////////////////////////////
410 /**
411 This method runs the main loop. Since different platforms
412 may use different timing methods and/or algorithms, this method can
413 be overrided. However, the port then takes all responsibility for
414 running the emulation and taking care of timing.
415 */
416 virtual void mainLoop();
417
418 /**
419 Informs the OSystem of a change in EventHandler state.
420 */
421 virtual void stateChanged(EventHandlerState state) { }
422
423 protected:
424
425 virtual shared_ptr<KeyValueRepository> createSettingsRepository();
426
427 /**
428 Append a message to the internal log
429 (a newline is automatically added).
430
431 @param message The message to be appended
432 @param level If 0, always output the message, only append when
433 level is less than or equal to that in 'loglevel'
434 */
435 void logMessage(const string& message, Logger::Level level);
436
437 //////////////////////////////////////////////////////////////////////
438 // The following methods are system-specific and *must* be
439 // implemented in derived classes.
440 //////////////////////////////////////////////////////////////////////
441 /**
442 Determine the base directory and main configuration file from the
443 derived class. It can also use hints, as described below.
444
445 @param basedir The base directory for all configuration files
446 @param cfgfile The fully qualified pathname of the config file
447 (including the base directory)
448 @param savedir The default directory to save various other files
449 @param loaddir The default directory to load various other files
450 @param useappdir A hint that the base dir should be set to the
451 app directory; not all ports can do this, so
452 they are free to ignore it
453 @param usedir A hint that the base dir should be set to this
454 parameter; not all ports can do this, so
455 they are free to ignore it
456 */
457 virtual void getBaseDirAndConfig(string& basedir, string& cfgfile,
458 string& savedir, string& loaddir,
459 bool useappdir, const string& usedir) = 0;
460
461 protected:
462 // Pointer to the EventHandler object
463 unique_ptr<EventHandler> myEventHandler;
464
465 // Pointer to the FrameBuffer object
466 unique_ptr<FrameBuffer> myFrameBuffer;
467
468 // Pointer to the Sound object
469 unique_ptr<Sound> mySound;
470
471 // Pointer to the Settings object
472 unique_ptr<Settings> mySettings;
473
474 // Pointer to the Random object
475 unique_ptr<Random> myRandom;
476
477 // Pointer to the PropertiesSet object
478 unique_ptr<PropertiesSet> myPropSet;
479
480 // Pointer to the (currently defined) Console object
481 unique_ptr<Console> myConsole;
482
483 // Pointer to audio settings object
484 unique_ptr<AudioSettings> myAudioSettings;
485
486 #ifdef CHEATCODE_SUPPORT
487 // Pointer to the CheatManager object
488 unique_ptr<CheatManager> myCheatManager;
489 #endif
490
491 #ifdef DEBUGGER_SUPPORT
492 // Pointer to the Debugger object
493 unique_ptr<Debugger> myDebugger;
494 #endif
495
496 #ifdef GUI_SUPPORT
497 // Pointer to the Menu object
498 unique_ptr<Menu> myMenu;
499
500 // Pointer to the CommandMenu object
501 unique_ptr<CommandMenu> myCommandMenu;
502
503 // Pointer to the Launcher object
504 unique_ptr<Launcher> myLauncher;
505
506 // Pointer to the TimeMachine object
507 unique_ptr<TimeMachine> myTimeMachine;
508 #endif
509
510 #ifdef PNG_SUPPORT
511 // PNG object responsible for loading/saving PNG images
512 unique_ptr<PNGLibrary> myPNGLib;
513 #endif
514
515 // Pointer to the StateManager object
516 unique_ptr<StateManager> myStateManager;
517
518 // Pointer to the TimerManager object
519 unique_ptr<TimerManager> myTimerManager;
520
521 // The list of log messages
522 string myLogMessages;
523
524 // Indicates whether ROM launcher was ever opened during this run
525 bool myLauncherUsed;
526
527 // Indicates whether to stop the main loop
528 bool myQuitLoop;
529
530 private:
531 string myBaseDir;
532 string myStateDir;
533 string mySnapshotSaveDir;
534 string mySnapshotLoadDir;
535 string myNVRamDir;
536 string myDefaultSaveDir;
537 string myDefaultLoadDir;
538
539 bool mySettingsLoaded;
540
541 string myCheatFile;
542 string myConfigFile;
543 string myPaletteFile;
544 string myPropertiesFile;
545
546 FilesystemNode myRomFile;
547 string myRomMD5;
548
549 string myFeatures;
550 string myBuildInfo;
551
552 FpsMeter myFpsMeter;
553
554 // If not empty, a hint for derived classes to use this as the
555 // base directory (where all settings are stored)
556 // Derived classes are free to ignore it and use their own defaults
557 static string ourOverrideBaseDir;
558 static bool ourOverrideBaseDirWithApp;
559
560 #ifdef SQLITE_SUPPORT
561 shared_ptr<SettingsDb> mySettingsDb;
562 #endif
563
564 private:
565 /**
566 Creates the various sound devices available in this system
567 */
568 void createSound();
569
570 /**
571 Creates an actual Console object based on the given info.
572
573 @param romfile The file node of the ROM to use (contains path)
574 @param md5 The MD5sum of the ROM
575
576 @return The actual Console object, otherwise nullptr.
577 */
578 unique_ptr<Console> openConsole(const FilesystemNode& romfile, string& md5);
579
580 /**
581 Close and finalize any currently open console.
582 */
583 void closeConsole();
584
585 /**
586 Gets all possible info about the given console.
587
588 @param console The console to use
589 @return Some information about this console
590 */
591 string getROMInfo(const Console& console);
592
593 double dispatchEmulation(EmulationWorker& emulationWorker);
594
595 // Following constructors and assignment operators not supported
596 OSystem(const OSystem&) = delete;
597 OSystem(OSystem&&) = delete;
598 OSystem& operator=(const OSystem&) = delete;
599 OSystem& operator=(OSystem&&) = delete;
600};
601
602#endif
603