~ubuntu-branches/debian/squeeze/stella/squeeze

« back to all changes in this revision

Viewing changes to src/emucore/OSystem.cxx

  • Committer: Bazaar Package Importer
  • Author(s): Stephen Kitt
  • Date: 2010-07-12 23:49:36 UTC
  • mfrom: (1.1.4 upstream)
  • Revision ID: james.westby@ubuntu.com-20100712234936-juawrr3etzhr2qpv
Tags: 3.1.2-1
* New maintainer (closes: #532039).
* New upstream version (closes: #461121):
  - includes launcher (closes: #396058).
* Fix the reference to the X Window System in the description (closes:
  #411815).
* Move to main, DFSG-free ROMs are available (see README.Debian).
* Enhance the package description.
* Drop the libslang2-dev dependency (closes: #560274).
* Remove the Encoding entry from stella.desktop.
* Avoid ignoring errors when cleaning.
* Add ${misc:Depends} to the package dependencies.
* Provide a doc-base file to install the documentation using doc-base.
* Switch to debhelper 7 with a simplified rules file.
* Use autotools-dev to provide updated configuration files.
* Update to Standards-Version 3.9.0:
  - Move to menu section Applications/Emulators.
  - Move the homepage declaration.
* Re-write the manpage.

Show diffs side-by-side

added added

removed removed

Lines of Context:
8
8
//  SS  SS   tt   ee      ll   ll  aa  aa
9
9
//   SSSS     ttt  eeeee llll llll  aaaaa
10
10
//
11
 
// Copyright (c) 1995-2008 by Bradford W. Mott and the Stella team
 
11
// Copyright (c) 1995-2010 by Bradford W. Mott, Stephen Anthony
 
12
// and the Stella Team
12
13
//
13
 
// See the file "license" for information on usage and redistribution of
 
14
// See the file "License.txt" for information on usage and redistribution of
14
15
// this file, and for a DISCLAIMER OF ALL WARRANTIES.
15
16
//
16
 
// $Id: OSystem.cxx,v 1.130 2008/05/21 21:01:40 stephena Exp $
 
17
// $Id: OSystem.cxx 2029 2010-04-29 12:46:07Z stephena $
17
18
//============================================================================
18
19
 
19
20
#include <cassert>
21
22
#include <fstream>
22
23
#include <zlib.h>
23
24
 
 
25
#ifdef HAVE_GETTIMEOFDAY
 
26
  #include <time.h>
 
27
  #include <sys/time.h>
 
28
#endif
 
29
 
24
30
#include "bspf.hxx"
25
31
 
26
32
#include "MediaFactory.hxx"
53
59
#include "Launcher.hxx"
54
60
#include "Font.hxx"
55
61
#include "StellaFont.hxx"
 
62
#include "StellaMediumFont.hxx"
56
63
#include "StellaLargeFont.hxx"
57
64
#include "ConsoleFont.hxx"
58
65
#include "Widget.hxx"
59
66
#include "Console.hxx"
60
67
#include "Random.hxx"
61
68
#include "StateManager.hxx"
 
69
#include "Version.hxx"
62
70
 
63
71
#include "OSystem.hxx"
64
72
 
81
89
    myStateManager(NULL),
82
90
    myQuitLoop(false),
83
91
    myRomFile(""),
 
92
    myRomMD5(""),
84
93
    myFeatures(""),
 
94
    myBuildInfo(""),
85
95
    myFont(NULL),
86
96
    myConsoleFont(NULL)
87
97
{
88
 
#ifdef DISPLAY_OPENGL
89
 
  myFeatures += "OpenGL ";
90
 
#endif
91
 
#ifdef SOUND_SUPPORT
92
 
  myFeatures += "Sound ";
93
 
#endif
94
 
#ifdef JOYSTICK_SUPPORT
95
 
  myFeatures += "Joystick ";
96
 
#endif
97
 
#ifdef DEBUGGER_SUPPORT
98
 
  myFeatures += "Debugger ";
99
 
#endif
100
 
#ifdef CHEATCODE_SUPPORT
101
 
  myFeatures += "Cheats";
102
 
#endif
 
98
  // Get built-in features
 
99
  #ifdef DISPLAY_OPENGL
 
100
    myFeatures += "OpenGL ";
 
101
  #endif
 
102
  #ifdef SOUND_SUPPORT
 
103
    myFeatures += "Sound ";
 
104
  #endif
 
105
  #ifdef JOYSTICK_SUPPORT
 
106
    myFeatures += "Joystick ";
 
107
  #endif
 
108
  #ifdef DEBUGGER_SUPPORT
 
109
    myFeatures += "Debugger ";
 
110
  #endif
 
111
  #ifdef CHEATCODE_SUPPORT
 
112
    myFeatures += "Cheats";
 
113
  #endif
 
114
 
 
115
  // Get build info
 
116
  ostringstream info;
 
117
  const SDL_version* ver = SDL_Linked_Version();
 
118
 
 
119
  info << "Build " << STELLA_BUILD << ", using ";
 
120
  info << "SDL " << (int)ver->major << "." << (int)ver->minor << "." << (int)ver->patch << " ";
 
121
  info << "[" << BSPF_ARCH << "]";
 
122
  myBuildInfo = info.str();
103
123
 
104
124
#if 0
105
125
  // Debugging info for the GUI widgets
106
 
  cerr << "  kStaticTextWidget   = " << kStaticTextWidget   << endl;
107
 
  cerr << "  kEditTextWidget     = " << kEditTextWidget     << endl;
108
 
  cerr << "  kButtonWidget       = " << kButtonWidget       << endl;
109
 
  cerr << "  kCheckboxWidget     = " << kCheckboxWidget     << endl;
110
 
  cerr << "  kSliderWidget       = " << kSliderWidget       << endl;
111
 
  cerr << "  kListWidget         = " << kListWidget         << endl;
112
 
  cerr << "  kScrollBarWidget    = " << kScrollBarWidget    << endl;
113
 
  cerr << "  kPopUpWidget        = " << kPopUpWidget        << endl;
114
 
  cerr << "  kTabWidget          = " << kTabWidget              << endl;
115
 
  cerr << "  kEventMappingWidget = " << kEventMappingWidget << endl;
116
 
  cerr << "  kEditableWidget     = " << kEditableWidget     << endl;
117
 
  cerr << "  kAudioWidget        = " << kAudioWidget        << endl;
118
 
  cerr << "  kColorWidget        = " << kColorWidget        << endl;
119
 
  cerr << "  kCpuWidget          = " << kCpuWidget          << endl;
120
 
  cerr << "  kDataGridOpsWidget  = " << kDataGridOpsWidget  << endl;
121
 
  cerr << "  kDataGridWidget     = " << kDataGridWidget     << endl;
122
 
  cerr << "  kPromptWidget       = " << kPromptWidget       << endl;
123
 
  cerr << "  kRamWidget          = " << kRamWidget          << endl;
124
 
  cerr << "  kRomListWidget      = " << kRomListWidget      << endl;
125
 
  cerr << "  kRomWidget          = " << kRomWidget          << endl;
126
 
  cerr << "  kTiaInfoWidget      = " << kTiaInfoWidget      << endl;
127
 
  cerr << "  kTiaOutputWidget    = " << kTiaOutputWidget    << endl;
128
 
  cerr << "  kTiaWidget          = " << kTiaWidget          << endl;
129
 
  cerr << "  kTiaZoomWidget      = " << kTiaZoomWidget      << endl;
130
 
  cerr << "  kToggleBitWidget    = " << kToggleBitWidget    << endl;
131
 
  cerr << "  kTogglePixelWidget  = " << kTogglePixelWidget  << endl;
132
 
  cerr << "  kToggleWidget       = " << kToggleWidget       << endl;
 
126
  ostringstream buf;
 
127
  buf << "  kStaticTextWidget   = " << kStaticTextWidget   << endl
 
128
      << "  kEditTextWidget     = " << kEditTextWidget     << endl
 
129
      << "  kButtonWidget       = " << kButtonWidget       << endl
 
130
      << "  kCheckboxWidget     = " << kCheckboxWidget     << endl
 
131
      << "  kSliderWidget       = " << kSliderWidget       << endl
 
132
      << "  kListWidget         = " << kListWidget         << endl
 
133
      << "  kScrollBarWidget    = " << kScrollBarWidget    << endl
 
134
      << "  kPopUpWidget        = " << kPopUpWidget        << endl
 
135
      << "  kTabWidget          = " << kTabWidget          << endl
 
136
      << "  kEventMappingWidget = " << kEventMappingWidget << endl
 
137
      << "  kEditableWidget     = " << kEditableWidget     << endl
 
138
      << "  kAudioWidget        = " << kAudioWidget        << endl
 
139
      << "  kColorWidget        = " << kColorWidget        << endl
 
140
      << "  kCpuWidget          = " << kCpuWidget          << endl
 
141
      << "  kDataGridOpsWidget  = " << kDataGridOpsWidget  << endl
 
142
      << "  kDataGridWidget     = " << kDataGridWidget     << endl
 
143
      << "  kPromptWidget       = " << kPromptWidget       << endl
 
144
      << "  kRamWidget          = " << kRamWidget          << endl
 
145
      << "  kRomListWidget      = " << kRomListWidget      << endl
 
146
      << "  kRomWidget          = " << kRomWidget          << endl
 
147
      << "  kTiaInfoWidget      = " << kTiaInfoWidget      << endl
 
148
      << "  kTiaOutputWidget    = " << kTiaOutputWidget    << endl
 
149
      << "  kTiaWidget          = " << kTiaWidget          << endl
 
150
      << "  kTiaZoomWidget      = " << kTiaZoomWidget      << endl
 
151
      << "  kToggleBitWidget    = " << kToggleBitWidget    << endl
 
152
      << "  kTogglePixelWidget  = " << kTogglePixelWidget  << endl
 
153
      << "  kToggleWidget       = " << kToggleWidget       << endl;
 
154
  logMessage(buf.str(), 0);
133
155
#endif
134
156
}
135
157
 
140
162
  delete myCommandMenu;
141
163
  delete myLauncher;
142
164
  delete myFont;
 
165
  delete mySmallFont;
143
166
  delete myConsoleFont;
 
167
  delete myLauncherFont;
144
168
 
145
169
  // Remove any game console that is currently attached
146
170
  deleteConsole();
172
196
{
173
197
  // Get updated paths for all configuration files
174
198
  setConfigPaths();
 
199
  ostringstream buf;
 
200
  buf << "Base directory:       '" << myBaseDir << "'" << endl
 
201
      << "Configuration file:   '" << myConfigFile << "'" << endl
 
202
      << "User game properties: '" << myPropertiesFile << "'" << endl
 
203
      << endl;
 
204
  logMessage(buf.str(), 1);
175
205
 
176
206
  // Get relevant information about the video hardware
177
207
  // This must be done before any graphics context is created, since
178
208
  // it may be needed to initialize the size of graphical objects
179
 
  queryVideoHardware();
 
209
  if(!queryVideoHardware())
 
210
    return false;
180
211
 
 
212
  ////////////////////////////////////////////////////////////////////
181
213
  // Create fonts to draw text
182
 
  // TODO - this should be configurable, and also depend on the minimum
183
 
  //        size of the launcher and maximum size of the TIA window
184
 
  //        The logic must be taken care of here, so the GUI classes
185
 
  //        can just create the interface and not worry about checking
186
 
  myFont         = new GUI::Font(GUI::stellaDesc);
 
214
  // NOTE: the logic determining appropriate font sizes is done here,
 
215
  //       so that the UI classes can just use the font they expect,
 
216
  //       and not worry about it
 
217
  //       This logic should also take into account the size of the
 
218
  //       framebuffer, and try to be intelligent about font sizes
 
219
  //       We can probably add ifdefs to take care of corner cases,
 
220
  //       but that means we've failed to abstract it enough ...
 
221
  ////////////////////////////////////////////////////////////////////
 
222
  bool smallScreen = myDesktopWidth < 640 || myDesktopHeight < 480;
 
223
 
 
224
  // This font is used in a variety of situations when a really small
 
225
  // font is needed; we let the specific widget/dialog decide when to
 
226
  // use it
 
227
  mySmallFont = new GUI::Font(GUI::stellaDesc);
 
228
 
 
229
  // The console font is always the same size (for now at least)
187
230
  myConsoleFont  = new GUI::Font(GUI::consoleDesc);
188
 
  if(mySettings->getString("launcherfont") == "small")
 
231
 
 
232
  // The general font used in all UI elements
 
233
  // This is determined by the size of the framebuffer
 
234
  myFont = new GUI::Font(smallScreen ? GUI::stellaDesc : GUI::stellaMediumDesc);
 
235
 
 
236
  // The font used by the ROM launcher
 
237
  // Normally, this is configurable by the user, except in the case of
 
238
  // very small screens
 
239
  if(!smallScreen)
 
240
  {    
 
241
    if(mySettings->getString("launcherfont") == "small")
 
242
      myLauncherFont = new GUI::Font(GUI::consoleDesc);
 
243
    else if(mySettings->getString("launcherfont") == "medium")
 
244
      myLauncherFont = new GUI::Font(GUI::stellaMediumDesc);
 
245
    else
 
246
      myLauncherFont = new GUI::Font(GUI::stellaLargeDesc);
 
247
  }
 
248
  else
189
249
    myLauncherFont = new GUI::Font(GUI::stellaDesc);
190
 
  else
191
 
    myLauncherFont = new GUI::Font(GUI::stellaLargeDesc);
192
250
 
193
251
  // Create the event handler for the system
194
252
  myEventHandler = new EventHandler(this);
239
297
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
240
298
void OSystem::setConfigPaths()
241
299
{
242
 
  myStateDir = mySettings->getString("statedir");
243
 
  if(myStateDir == "")
244
 
    myStateDir = myBaseDir + BSPF_PATH_SEPARATOR + "state";
245
 
  if(!FilesystemNode::dirExists(myStateDir))
246
 
    FilesystemNode::makeDir(myStateDir);
247
 
  mySettings->setString("statedir", myStateDir);
248
 
 
249
 
  mySnapshotDir = mySettings->getString("ssdir");
250
 
  if(mySnapshotDir == "")
251
 
    mySnapshotDir = myBaseDir + BSPF_PATH_SEPARATOR + "snapshots";
252
 
  if(!FilesystemNode::dirExists(mySnapshotDir))
253
 
    FilesystemNode::makeDir(mySnapshotDir);
254
 
  mySettings->setString("ssdir", mySnapshotDir);
255
 
 
256
 
  myCheatFile = mySettings->getString("cheatfile");
257
 
  if(myCheatFile == "")
258
 
    myCheatFile = myBaseDir + BSPF_PATH_SEPARATOR + "stella.cht";
259
 
  mySettings->setString("cheatfile", myCheatFile);
260
 
 
261
 
  myPaletteFile = mySettings->getString("palettefile");
262
 
  if(myPaletteFile == "")
263
 
    myPaletteFile = myBaseDir + BSPF_PATH_SEPARATOR + "stella.pal";
264
 
  mySettings->setString("palettefile", myPaletteFile);
265
 
 
266
 
  myPropertiesFile = mySettings->getString("propsfile");
267
 
  if(myPropertiesFile == "")
268
 
    myPropertiesFile = myBaseDir + BSPF_PATH_SEPARATOR + "stella.pro";
269
 
  mySettings->setString("propsfile", myPropertiesFile);
 
300
  // Paths are saved with special characters preserved ('~' or '.')
 
301
  // We do some error checking here, so the rest of the codebase doesn't
 
302
  // have to worry about it
 
303
  FilesystemNode node;
 
304
  string s;
 
305
 
 
306
  s = mySettings->getString("statedir");
 
307
  if(s == "") s = myBaseDir + BSPF_PATH_SEPARATOR + "state";
 
308
  node = FilesystemNode(s);
 
309
  myStateDir = node.getPath();
 
310
  mySettings->setString("statedir", node.getRelativePath());
 
311
  if(!node.isDirectory())
 
312
    AbstractFilesystemNode::makeDir(myStateDir);
 
313
 
 
314
  s = mySettings->getString("ssdir");
 
315
  if(s == "") s = myBaseDir + BSPF_PATH_SEPARATOR + "snapshots";
 
316
  node = FilesystemNode(s);
 
317
  mySnapshotDir = node.getPath();
 
318
  mySettings->setString("ssdir", node.getRelativePath());
 
319
  if(!node.isDirectory())
 
320
    AbstractFilesystemNode::makeDir(mySnapshotDir);
 
321
 
 
322
  s = mySettings->getString("eepromdir");
 
323
  if(s == "") s = myBaseDir;
 
324
  node = FilesystemNode(s);
 
325
  myEEPROMDir = node.getPath();
 
326
  mySettings->setString("eepromdir", node.getRelativePath());
 
327
  if(!node.isDirectory())
 
328
    AbstractFilesystemNode::makeDir(myEEPROMDir);
 
329
 
 
330
  s = mySettings->getString("cheatfile");
 
331
  if(s == "") s = myBaseDir + BSPF_PATH_SEPARATOR + "stella.cht";
 
332
  node = FilesystemNode(s);
 
333
  myCheatFile = node.getPath();
 
334
  mySettings->setString("cheatfile", node.getRelativePath());
 
335
 
 
336
  s = mySettings->getString("palettefile");
 
337
  if(s == "") s = myBaseDir + BSPF_PATH_SEPARATOR + "stella.pal";
 
338
  node = FilesystemNode(s);
 
339
  myPaletteFile = node.getPath();
 
340
  mySettings->setString("palettefile", node.getRelativePath());
 
341
 
 
342
  s = mySettings->getString("propsfile");
 
343
  if(s == "") s = myBaseDir + BSPF_PATH_SEPARATOR + "stella.pro";
 
344
  node = FilesystemNode(s);
 
345
  myPropertiesFile = node.getPath();
 
346
  mySettings->setString("propsfile", node.getRelativePath());
270
347
}
271
348
 
272
349
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
275
352
  int palette = mySettings->getInt("uipalette") - 1;
276
353
  if(palette < 0 || palette >= kNumUIPalettes) palette = 0;
277
354
  myFrameBuffer->setUIPalette(&ourGUIColors[palette][0]);
278
 
  myEventHandler->refreshDisplay();
 
355
  myFrameBuffer->refresh();
279
356
}
280
357
 
281
358
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
282
359
void OSystem::setBaseDir(const string& basedir)
283
360
{
284
 
  myBaseDir = basedir;
285
 
  if(!FilesystemNode::dirExists(myBaseDir))
286
 
    FilesystemNode::makeDir(myBaseDir);
 
361
  FilesystemNode node(basedir);
 
362
  myBaseDir = node.getPath();
 
363
  if(!node.isDirectory())
 
364
    AbstractFilesystemNode::makeDir(myBaseDir);
 
365
}
 
366
 
 
367
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
368
void OSystem::setConfigFile(const string& file)
 
369
{
 
370
  FilesystemNode node(file);
 
371
  myConfigFile = node.getPath();
287
372
}
288
373
 
289
374
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
290
375
void OSystem::setFramerate(float framerate)
291
376
{
292
 
  myDisplayFrameRate = framerate;
293
 
  myTimePerFrame = (uInt32)(1000000.0 / myDisplayFrameRate);
 
377
  if(framerate > 0.0)
 
378
  {
 
379
    myDisplayFrameRate = framerate;
 
380
    myTimePerFrame = (uInt32)(1000000.0 / myDisplayFrameRate);
 
381
  }
294
382
}
295
383
 
296
384
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
297
 
bool OSystem::createFrameBuffer(bool showmessage)
 
385
bool OSystem::createFrameBuffer()
298
386
{
299
 
  // Check if we can re-use the current framebuffer
300
 
  bool changeBuffer = (myFrameBuffer == NULL);
301
 
  if(!changeBuffer)
302
 
  {
303
 
    if((mySettings->getString("video") == "soft" &&
304
 
        myFrameBuffer->type() != kSoftBuffer) ||
305
 
       (mySettings->getString("video") == "gl" &&
306
 
        myFrameBuffer->type() != kGLBuffer))
307
 
      changeBuffer = true;
308
 
  }
309
 
  // Now we only create when absolutely necessary
310
 
  if(changeBuffer)
311
 
  {
312
 
    delete myFrameBuffer;
 
387
  // There is only ever one FrameBuffer created per run of Stella
 
388
  // Due to the multi-surface nature of the FrameBuffer, repeatedly
 
389
  // creating and destroying framebuffer objects causes crashes which
 
390
  // are far too invasive to fix right now
 
391
  // Besides, how often does one really switch between software and
 
392
  // OpenGL rendering modes, and even when they do, does it really
 
393
  // need to be dynamic?
 
394
 
 
395
  bool firstTime = (myFrameBuffer == NULL);
 
396
  if(firstTime)
313
397
    myFrameBuffer = MediaFactory::createVideo(this);
314
 
  }
315
398
 
316
399
  // Re-initialize the framebuffer to current settings
317
400
  switch(myEventHandler->state())
320
403
    case EventHandler::S_PAUSE:
321
404
    case EventHandler::S_MENU:
322
405
    case EventHandler::S_CMDMENU:
323
 
      myConsole->initializeVideo();
 
406
      if(!myConsole->initializeVideo())
 
407
        goto fallback;
324
408
      break;  // S_EMULATE, S_PAUSE, S_MENU, S_CMDMENU
325
409
 
326
410
    case EventHandler::S_LAUNCHER:
327
 
      myLauncher->initializeVideo();
 
411
      if(!myLauncher->initializeVideo())
 
412
        goto fallback;
328
413
      break;  // S_LAUNCHER
329
414
 
330
415
#ifdef DEBUGGER_SUPPORT
331
416
    case EventHandler::S_DEBUGGER:
332
 
      myDebugger->initializeVideo();
 
417
      if(!myDebugger->initializeVideo())
 
418
        goto fallback;
333
419
      break;  // S_DEBUGGER
334
420
#endif
335
421
 
336
 
    default:
 
422
    default:  // Should never happen
 
423
      logMessage("ERROR: Unknown emulation state in createFrameBuffer()\n", 0);
337
424
      break;
338
425
  }
339
426
 
340
 
  // Setup the SDL joysticks (must be done after FrameBuffer is created)
341
 
  if(changeBuffer) myEventHandler->setupJoysticks();
342
 
 
343
 
  // Let the system know that we've possibly resized the display
344
 
  if(changeBuffer) myEventHandler->handleResizeEvent();
345
 
 
346
 
  // Update the UI palette
347
 
  setUIPalette();
348
 
 
349
 
  if(showmessage)
350
 
  {
351
 
    switch(myFrameBuffer->type())
 
427
  // The following only need to be done once
 
428
  if(firstTime)
 
429
  {
 
430
    // Setup the SDL joysticks (must be done after FrameBuffer is created)
 
431
    myEventHandler->setupJoysticks();
 
432
 
 
433
    // Update the UI palette
 
434
    setUIPalette();
 
435
  }
 
436
 
 
437
  return true;
 
438
 
 
439
  // GOTO are normally considered evil, unless well documented :)
 
440
  // If initialization of video system fails while in OpenGL mode,
 
441
  // attempt to fallback to software mode
 
442
fallback:
 
443
  if(myFrameBuffer && myFrameBuffer->type() == kGLBuffer)
 
444
  {
 
445
    logMessage("ERROR: OpenGL mode failed, fallback to software\n", 0);
 
446
    delete myFrameBuffer; myFrameBuffer = NULL;
 
447
    mySettings->setString("video", "soft");
 
448
    bool ret = createFrameBuffer();
 
449
    if(ret)
352
450
    {
353
 
      case kSoftBuffer:
354
 
        myFrameBuffer->showMessage("Software mode");
355
 
        break;
356
 
      case kGLBuffer:
357
 
        myFrameBuffer->showMessage("OpenGL mode");
358
 
        break;
 
451
      setFramerate(60);
 
452
      myFrameBuffer->showMessage("OpenGL mode failed, fallback to software",
 
453
                                 kMiddleCenter, true);
359
454
    }
 
455
    return ret;
360
456
  }
361
 
 
362
 
  return true;
363
 
}
364
 
 
365
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
366
 
void OSystem::toggleFrameBuffer()
367
 
{
368
 
#ifdef DISPLAY_OPENGL
369
 
  // First figure out which mode to switch to
370
 
  string video = mySettings->getString("video");
371
 
  if(video == "soft")
372
 
    video = "gl";
373
 
  else if(video == "gl")
374
 
    video = "soft";
375
 
  else   // a driver that doesn't exist was requested, so use software mode
376
 
    video = "soft";
377
 
 
378
 
  // Update the settings and create the framebuffer
379
 
  mySettings->setString("video", video);
380
 
  createFrameBuffer(true);  // show onscreen message, re-initialize framebuffer
381
 
 
382
 
  // The palette and phosphor info for the framebuffer will be lost
383
 
  // when a new framebuffer is created; we must restore it
384
 
  if(myConsole)
385
 
    myConsole->initializeVideo(false);
386
 
#endif
 
457
  else
 
458
    return false;
387
459
}
388
460
 
389
461
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
399
471
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
400
472
bool OSystem::createConsole(const string& romfile, const string& md5sum)
401
473
{
 
474
  ostringstream buf;
 
475
 
402
476
  // Do a little error checking; it shouldn't be necessary
403
477
  if(myConsole) deleteConsole();
404
478
 
410
484
    showmessage = true;  // we show a message if a ROM is being reloaded
411
485
    if(myRomFile == "")
412
486
    {
413
 
      cerr << "ERROR: Rom file not specified ..." << endl;
 
487
      logMessage("ERROR: Rom file not specified ...\n", 0);
414
488
      return false;
415
489
    }
416
490
  }
417
491
  else
 
492
  {
418
493
    myRomFile = romfile;
419
 
 
420
 
  // Open the cartridge image and read it in
421
 
  uInt8* image;
422
 
  int size = -1;
423
 
  string md5 = md5sum;
424
 
  if(openROM(myRomFile, md5, &image, &size))
 
494
    myRomMD5  = md5sum;
 
495
 
 
496
    // Each time a new console is loaded, we simulate a cart removal
 
497
    // Some carts need knowledge of this, as they behave differently
 
498
    // based on how many power-cycles they've been through since plugged in
 
499
    mySettings->setInt("romloadcount", 0);
 
500
  }
 
501
 
 
502
  // Create an instance of the 2600 game console
 
503
  string type, id;
 
504
  myConsole = openConsole(myRomFile, myRomMD5, type, id);
 
505
  if(myConsole)
425
506
  {
426
 
    // Get all required info for creating a valid console
427
 
    Cartridge* cart = (Cartridge*) NULL;
428
 
    Properties props;
429
 
    if(queryConsoleInfo(image, size, md5, &cart, props))
 
507
  #ifdef CHEATCODE_SUPPORT
 
508
    myCheatManager->loadCheats(myRomMD5);
 
509
  #endif
 
510
    bool audiofirst = mySettings->getBool("audiofirst");
 
511
    //////////////////////////////////////////////////////////////////////////
 
512
    // For some reason, ATI video drivers for OpenGL in Win32 cause problems
 
513
    // if the sound isn't initialized before the video
 
514
    // According to the SDL documentation, it shouldn't matter what order the
 
515
    // systems are initialized, but apparently it *does* matter
 
516
    // For now, I'll just reverse the ordering, as suggested by 'zagon' at
 
517
    // http://www.atariage.com/forums/index.php?showtopic=126090&view=findpost&p=1648693
 
518
    // Hopefully it won't break anything else
 
519
    //////////////////////////////////////////////////////////////////////////
 
520
    if(audiofirst)  myConsole->initializeAudio();
 
521
    myEventHandler->reset(EventHandler::S_EMULATE);
 
522
    if(!createFrameBuffer())  // Takes care of initializeVideo()
430
523
    {
431
 
      // Create an instance of the 2600 game console
432
 
      myConsole = new Console(this, cart, props);
433
 
    #ifdef CHEATCODE_SUPPORT
434
 
      myCheatManager->loadCheats(md5);
435
 
    #endif
436
 
      myEventHandler->reset(EventHandler::S_EMULATE);
437
 
      createFrameBuffer(false);  // Takes care of initializeVideo()
438
 
      myConsole->initializeAudio();
439
 
    #ifdef DEBUGGER_SUPPORT
440
 
      myDebugger->setConsole(myConsole);
441
 
      myDebugger->initialize();
442
 
    #endif
 
524
      logMessage("ERROR: Couldn't create framebuffer for console\n", 0);
 
525
      myEventHandler->reset(EventHandler::S_LAUNCHER);
 
526
      return false;
 
527
    }
 
528
    if(!audiofirst)  myConsole->initializeAudio();
443
529
 
444
 
      if(showmessage)
 
530
    if(showmessage)
 
531
    {
 
532
      if(id == "")
445
533
        myFrameBuffer->showMessage("New console created");
446
 
      if(mySettings->getBool("showinfo"))
447
 
        cout << "Game console created:" << endl
448
 
             << "  ROM file: " << myRomFile << endl << endl
449
 
             << myConsole->about() << endl;
450
 
 
451
 
      // Update the timing info for a new console run
452
 
      resetLoopTiming();
453
 
 
454
 
      myFrameBuffer->setCursorState();
455
 
      retval = true;
456
 
    }
457
 
    else
458
 
    {
459
 
      cerr << "ERROR: Couldn't create console for " << myRomFile << " ..." << endl;
460
 
      retval = false;
461
 
    }
 
534
      else
 
535
        myFrameBuffer->showMessage("Multicart " + type + ", loading ROM" + id);
 
536
    }
 
537
    buf << "Game console created:" << endl
 
538
        << "  ROM file: " << myRomFile << endl << endl
 
539
        << getROMInfo(myConsole) << endl;
 
540
    logMessage(buf.str(), 1);
 
541
 
 
542
    // Update the timing info for a new console run
 
543
    resetLoopTiming();
 
544
 
 
545
    myFrameBuffer->setCursorState();
 
546
    retval = true;
462
547
  }
463
548
  else
464
549
  {
465
 
    cerr << "ERROR: Couldn't open " << myRomFile << " ..." << endl;
 
550
    buf << "ERROR: Couldn't create console for " << myRomFile << endl;
 
551
    logMessage(buf.str(), 0);
466
552
    retval = false;
467
553
  }
468
554
 
469
 
  // Free the image since we don't need it any longer
470
 
  if(size != -1)
471
 
    delete[] image;
 
555
  // Also check if certain virtual buttons should be held down
 
556
  // These must be checked each time a new console is being created
 
557
  if(mySettings->getBool("holdreset"))
 
558
    myEventHandler->handleEvent(Event::ConsoleReset, 1);
 
559
  if(mySettings->getBool("holdselect"))
 
560
    myEventHandler->handleEvent(Event::ConsoleSelect, 1);
 
561
  if(mySettings->getBool("holdbutton0"))
 
562
    myEventHandler->handleEvent(Event::JoystickZeroFire1, 1);
472
563
 
473
564
  return retval;
474
565
}
482
573
  #ifdef CHEATCODE_SUPPORT
483
574
    myCheatManager->saveCheats(myConsole->properties().get(Cartridge_MD5));
484
575
  #endif
485
 
    if(mySettings->getBool("showinfo"))
486
 
    {
487
 
      double executionTime   = (double) myTimingInfo.totalTime / 1000000.0;
488
 
      double framesPerSecond = (double) myTimingInfo.totalFrames / executionTime;
489
 
      cout << "Game console stats:" << endl
490
 
           << "  Total frames drawn: " << myTimingInfo.totalFrames << endl
491
 
           << "  Total time (sec):   " << executionTime << endl
492
 
           << "  Frames per second:  " << framesPerSecond << endl
493
 
           << endl;
494
 
    }
 
576
    ostringstream buf;
 
577
    double executionTime   = (double) myTimingInfo.totalTime / 1000000.0;
 
578
    double framesPerSecond = (double) myTimingInfo.totalFrames / executionTime;
 
579
    buf << "Game console stats:" << endl
 
580
        << "  Total frames drawn: " << myTimingInfo.totalFrames << endl
 
581
        << "  Total time (sec):   " << executionTime << endl
 
582
        << "  Frames per second:  " << framesPerSecond << endl
 
583
        << endl;
 
584
    logMessage(buf.str(), 1);
 
585
 
495
586
    delete myConsole;  myConsole = NULL;
496
587
  }
497
588
}
498
589
 
499
590
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
500
 
void OSystem::createLauncher()
 
591
bool OSystem::createLauncher()
501
592
{
502
593
  myEventHandler->reset(EventHandler::S_LAUNCHER);
503
 
  createFrameBuffer(false);
 
594
  if(!createFrameBuffer())
 
595
  {
 
596
    logMessage("ERROR: Couldn't create launcher\n", 0);
 
597
    return false;
 
598
  }
504
599
  myLauncher->reStack();
505
600
  myFrameBuffer->setCursorState();
506
 
  myEventHandler->refreshDisplay();
 
601
  myFrameBuffer->refresh();
507
602
 
508
603
  setFramerate(60);
509
604
  resetLoopTiming();
510
 
}
511
 
 
512
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
513
 
bool OSystem::openROM(const string& rom, string& md5, uInt8** image, int* size)
514
 
{
 
605
 
 
606
  return true;
 
607
}
 
608
 
 
609
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
610
string OSystem::getROMInfo(const string& romfile)
 
611
{
 
612
  string md5, type, id, result = "";
 
613
  Console* console = openConsole(romfile, md5, type, id);
 
614
  if(console)
 
615
  {
 
616
    result = getROMInfo(console);
 
617
    delete console;
 
618
  }
 
619
  else
 
620
    result = "ERROR: Couldn't get ROM info for " + romfile + " ...";
 
621
 
 
622
  return result;
 
623
}
 
624
 
 
625
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
626
string OSystem::MD5FromFile(const string& filename)
 
627
{
 
628
  string md5 = "";
 
629
 
 
630
  uInt8* image = 0;
 
631
  uInt32 size  = 0;
 
632
  if((image = openROM(filename, md5, size)) != 0)
 
633
    if(image != 0 && size > 0)
 
634
      delete[] image;
 
635
 
 
636
  return md5;
 
637
}
 
638
 
 
639
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
640
void OSystem::logMessage(const string& message, uInt8 level)
 
641
{
 
642
  if(level == 0)
 
643
    cerr << message;
 
644
  else if(level <= (uInt8)mySettings->getInt("showinfo"))
 
645
    cout << message;
 
646
}
 
647
 
 
648
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
649
Console* OSystem::openConsole(const string& romfile, string& md5,
 
650
                              string& type, string& id)
 
651
{
 
652
#define CMDLINE_PROPS_UPDATE(cl_name, prop_name) \
 
653
  s = mySettings->getString(cl_name);            \
 
654
  if(s != "") props.set(prop_name, s);
 
655
 
 
656
  Console* console = (Console*) NULL;
 
657
 
 
658
  // Open the cartridge image and read it in
 
659
  uInt8* image = 0;
 
660
  uInt32 size  = 0;
 
661
  if((image = openROM(romfile, md5, size)) != 0)
 
662
  {
 
663
    // Get a valid set of properties, including any entered on the commandline
 
664
    // For initial creation of the Cart, we're only concerned with the BS type
 
665
    Properties props;
 
666
    myPropSet->getMD5(md5, props);
 
667
    string s = "";
 
668
    CMDLINE_PROPS_UPDATE("bs", Cartridge_Type);
 
669
    CMDLINE_PROPS_UPDATE("type", Cartridge_Type);
 
670
 
 
671
    // Now create the cartridge
 
672
    string cartmd5 = md5;
 
673
    type = props.get(Cartridge_Type);
 
674
    Cartridge* cart =
 
675
      Cartridge::create(image, size, cartmd5, type, id, *mySettings);
 
676
 
 
677
    // It's possible that the cart created was from a piece of the image,
 
678
    // and that the md5 (and hence the cart) has changed
 
679
    if(props.get(Cartridge_MD5) != cartmd5)
 
680
    {
 
681
      string name = props.get(Cartridge_Name);
 
682
      if(!myPropSet->getMD5(cartmd5, props))
 
683
      {
 
684
        // Cart md5 wasn't found, so we create a new props for it
 
685
        props.set(Cartridge_MD5, cartmd5);
 
686
        props.set(Cartridge_Name, name+id);
 
687
        myPropSet->insert(props, false);
 
688
      }
 
689
    }
 
690
 
 
691
    CMDLINE_PROPS_UPDATE("channels", Cartridge_Sound);
 
692
    CMDLINE_PROPS_UPDATE("ld", Console_LeftDifficulty);
 
693
    CMDLINE_PROPS_UPDATE("rd", Console_RightDifficulty);
 
694
    CMDLINE_PROPS_UPDATE("tv", Console_TelevisionType);
 
695
    CMDLINE_PROPS_UPDATE("sp", Console_SwapPorts);
 
696
    CMDLINE_PROPS_UPDATE("lc", Controller_Left);
 
697
    CMDLINE_PROPS_UPDATE("rc", Controller_Right);
 
698
    s = mySettings->getString("bc");
 
699
    if(s != "") { props.set(Controller_Left, s); props.set(Controller_Right, s); }
 
700
    CMDLINE_PROPS_UPDATE("cp", Controller_SwapPaddles);
 
701
    CMDLINE_PROPS_UPDATE("format", Display_Format);
 
702
    CMDLINE_PROPS_UPDATE("ystart", Display_YStart);
 
703
    CMDLINE_PROPS_UPDATE("height", Display_Height);
 
704
    CMDLINE_PROPS_UPDATE("pp", Display_Phosphor);
 
705
    CMDLINE_PROPS_UPDATE("ppblend", Display_PPBlend);
 
706
 
 
707
    // Finally, create the cart with the correct properties
 
708
    if(cart)
 
709
      console = new Console(this, cart, props);
 
710
  }
 
711
  else
 
712
  {
 
713
    ostringstream buf;
 
714
    buf << "ERROR: Couldn't open \'" << romfile << "\'" << endl;
 
715
    logMessage(buf.str(), 0);
 
716
  }
 
717
 
 
718
  // Free the image since we don't need it any longer
 
719
  if(image != 0 && size > 0)
 
720
    delete[] image;
 
721
 
 
722
  return console;
 
723
}
 
724
 
 
725
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
726
uInt8* OSystem::openROM(string file, string& md5, uInt32& size)
 
727
{
 
728
  // This method has a documented side-effect:
 
729
  // It not only loads a ROM and creates an array with its contents,
 
730
  // but also adds a properties entry if the one for the ROM doesn't
 
731
  // contain a valid name
 
732
 
 
733
  uInt8* image = 0;
 
734
 
515
735
  // Try to open the file as a zipped archive
516
736
  // If that fails, we assume it's just a gzipped or normal data file
517
737
  unzFile tz;
518
 
  if((tz = unzOpen(rom.c_str())) != NULL)
 
738
  if((tz = unzOpen(file.c_str())) != NULL)
519
739
  {
520
740
    if(unzGoToFirstFile(tz) == UNZ_OK)
521
741
    {
535
755
          // Grab 3-character extension
536
756
          char* ext = filename + strlen(filename) - 4;
537
757
 
538
 
          if(!BSPF_strcasecmp(ext, ".bin") || !BSPF_strcasecmp(ext, ".a26"))
 
758
          if(!BSPF_strcasecmp(ext, ".a26") || !BSPF_strcasecmp(ext, ".bin") ||
 
759
             !BSPF_strcasecmp(ext, ".rom"))
 
760
          {
 
761
            file = filename;
539
762
            break;
 
763
          }
540
764
        }
541
765
 
542
766
        // Scan the next file in the zip
548
772
      if(ufo.uncompressed_size <= 0)
549
773
      {
550
774
        unzClose(tz);
551
 
        return false;
 
775
        return image;
552
776
      }
553
 
      *size  = ufo.uncompressed_size;
554
 
      *image = new uInt8[*size];
 
777
      size  = ufo.uncompressed_size;
 
778
      image = new uInt8[size];
555
779
 
556
780
      // We don't have to check for any return errors from these functions,
557
781
      // since if there are, 'image' will not contain a valid ROM and the
558
782
      // calling method can take of it
559
783
      unzOpenCurrentFile(tz);
560
 
      unzReadCurrentFile(tz, *image, *size);
 
784
      unzReadCurrentFile(tz, image, size);
561
785
      unzCloseCurrentFile(tz);
562
786
      unzClose(tz);
563
787
    }
564
788
    else
565
789
    {
566
790
      unzClose(tz);
567
 
      return false;
 
791
      return image;
568
792
    }
569
793
  }
570
794
  else
571
795
  {
572
796
    // Assume the file is either gzip'ed or not compressed at all
573
 
    gzFile f = gzopen(rom.c_str(), "rb");
 
797
    gzFile f = gzopen(file.c_str(), "rb");
574
798
    if(!f)
575
 
      return false;
 
799
      return image;
576
800
 
577
 
    *image = new uInt8[MAX_ROM_SIZE];
578
 
    *size = gzread(f, *image, MAX_ROM_SIZE);
 
801
    image = new uInt8[MAX_ROM_SIZE];
 
802
    size = gzread(f, image, MAX_ROM_SIZE);
579
803
    gzclose(f);
580
804
  }
581
805
 
583
807
  // Now we make sure that the file has a valid properties entry
584
808
  // To save time, only generate an MD5 if we really need one
585
809
  if(md5 == "")
586
 
    md5 = MD5(*image, *size);
 
810
    md5 = MD5(image, size);
587
811
 
588
812
  // Some games may not have a name, since there may not
589
813
  // be an entry in stella.pro.  In that case, we use the rom name
590
814
  // and reinsert the properties object
591
815
  Properties props;
592
 
  myPropSet->getMD5(md5, props);
593
 
 
594
 
  string name = props.get(Cartridge_Name);
595
 
  if(name == "Untitled")
 
816
  if(!myPropSet->getMD5(md5, props))
596
817
  {
597
818
    // Get the filename from the rom pathname
598
 
    string::size_type pos = rom.find_last_of(BSPF_PATH_SEPARATOR);
599
 
    if(pos+1 != string::npos)
600
 
    {
601
 
      name = rom.substr(pos+1);
602
 
      props.set(Cartridge_MD5, md5);
603
 
      props.set(Cartridge_Name, name);
604
 
      myPropSet->insert(props, false);
605
 
    }
606
 
  }
607
 
 
608
 
  return true;
609
 
}
610
 
 
611
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
612
 
bool OSystem::isValidRomName(const string& filename, string& extension)
613
 
{
614
 
  string::size_type idx = filename.find_last_of('.');
615
 
  if(idx != string::npos)
616
 
  {
617
 
    extension = filename.substr(idx+1);
618
 
    return BSPF_strncasecmp(extension.c_str(), "bin", 3) == 0 ||
619
 
           BSPF_strncasecmp(extension.c_str(), "a26", 3) == 0 ||
620
 
           BSPF_strncasecmp(extension.c_str(), "zip", 3) == 0 ||
621
 
           BSPF_strncasecmp(extension.c_str(), "rom", 3) == 0 ||
622
 
           BSPF_strncasecmp(extension.c_str(), "gz", 2)  == 0 ;
623
 
  }
624
 
  return false;
625
 
}
626
 
 
627
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
628
 
string OSystem::MD5FromFile(const string& filename)
629
 
{
630
 
  uInt8* image;
631
 
  int size = -1;
632
 
  string md5 = "";
633
 
 
634
 
  if(openROM(filename, md5, &image, &size))
635
 
    if(size != -1)
636
 
      delete[] image;
637
 
 
638
 
  return md5;
639
 
}
640
 
 
641
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
642
 
string OSystem::getROMInfo(const string& romfile)
643
 
{
 
819
    string::size_type pos = file.find_last_of("/\\");
 
820
    if(pos != string::npos)  file = file.substr(pos+1);
 
821
 
 
822
    props.set(Cartridge_MD5, md5);
 
823
    props.set(Cartridge_Name, file);
 
824
    myPropSet->insert(props, false);
 
825
  }
 
826
 
 
827
  return image;
 
828
}
 
829
 
 
830
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
831
string OSystem::getROMInfo(const Console* console)
 
832
{
 
833
  const ConsoleInfo& info = console->about();
644
834
  ostringstream buf;
645
835
 
646
 
  // Open the cartridge image and read it in
647
 
  uInt8* image;
648
 
  int size = -1;
649
 
  string md5;
650
 
  if(openROM(romfile, md5, &image, &size))
651
 
  {
652
 
    // Get all required info for creating a temporary console
653
 
    Cartridge* cart = (Cartridge*) NULL;
654
 
    Properties props;
655
 
    if(queryConsoleInfo(image, size, md5, &cart, props))
656
 
    {
657
 
      Console* console = new Console(this, cart, props);
658
 
      if(console)
659
 
        buf << console->about();
660
 
      else
661
 
        buf << "ERROR: Couldn't get ROM info for " << romfile << " ..." << endl;
662
 
 
663
 
      delete console;
664
 
    }
665
 
    else
666
 
      buf << "ERROR: Couldn't open " << romfile << " ..." << endl;
667
 
  }
668
 
  // Free the image and console since we don't need it any longer
669
 
  if(size != -1)
670
 
    delete[] image;
 
836
  buf << "  Cart Name:       " << info.CartName << endl
 
837
      << "  Cart MD5:        " << info.CartMD5 << endl
 
838
      << "  Controller 0:    " << info.Control0 << endl
 
839
      << "  Controller 1:    " << info.Control1 << endl
 
840
      << "  Display Format:  " << info.DisplayFormat << endl
 
841
      << "  Bankswitch Type: " << info.BankSwitch << endl;
671
842
 
672
843
  return buf.str();
673
844
}
674
845
 
675
846
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
676
 
bool OSystem::queryConsoleInfo(const uInt8* image, uInt32 size,
677
 
                               const string& md5,
678
 
                               Cartridge** cart, Properties& props)
679
 
{
680
 
  // Get a valid set of properties, including any entered on the commandline
681
 
  string s;
682
 
  myPropSet->getMD5(md5, props);
683
 
 
684
 
  s = mySettings->getString("bs");
685
 
  if(s != "") props.set(Cartridge_Type, s);
686
 
  s = mySettings->getString("type");
687
 
  if(s != "") props.set(Cartridge_Type, s);
688
 
  s = mySettings->getString("channels");
689
 
  if(s != "") props.set(Cartridge_Sound, s);
690
 
  s = mySettings->getString("ld");
691
 
  if(s != "") props.set(Console_LeftDifficulty, s);
692
 
  s = mySettings->getString("rd");
693
 
  if(s != "") props.set(Console_RightDifficulty, s);
694
 
  s = mySettings->getString("tv");
695
 
  if(s != "") props.set(Console_TelevisionType, s);
696
 
  s = mySettings->getString("sp");
697
 
  if(s != "") props.set(Console_SwapPorts, s);
698
 
  s = mySettings->getString("lc");
699
 
  if(s != "") props.set(Controller_Left, s);
700
 
  s = mySettings->getString("rc");
701
 
  if(s != "") props.set(Controller_Right, s);
702
 
  s = mySettings->getString("bc");
703
 
  if(s != "") { props.set(Controller_Left, s); props.set(Controller_Right, s); }
704
 
  s = mySettings->getString("cp");
705
 
  if(s != "") props.set(Controller_SwapPaddles, s);
706
 
  s = mySettings->getString("format");
707
 
  if(s != "") props.set(Display_Format, s);
708
 
  s = mySettings->getString("ystart");
709
 
  if(s != "") props.set(Display_YStart, s);
710
 
  s = mySettings->getString("height");
711
 
  if(s != "") props.set(Display_Height, s);
712
 
  s = mySettings->getString("pp");
713
 
  if(s != "") props.set(Display_Phosphor, s);
714
 
  s = mySettings->getString("ppblend");
715
 
  if(s != "") props.set(Display_PPBlend, s);
716
 
  s = mySettings->getString("hmove");
717
 
  if(s != "") props.set(Emulation_HmoveBlanks, s);
718
 
 
719
 
  *cart = Cartridge::create(image, size, props, *mySettings);
720
 
  if(!*cart)
721
 
    return false;
722
 
 
723
 
  return true;
724
 
}
725
 
 
726
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
727
847
void OSystem::resetLoopTiming()
728
848
{
729
 
  memset(&myTimingInfo, 0, sizeof(TimingInfo));
730
 
  myTimingInfo.start = getTicks();
731
 
  myTimingInfo.virt = getTicks();
 
849
  myTimingInfo.start = myTimingInfo.virt = getTicks();
 
850
  myTimingInfo.current = 0;
 
851
  myTimingInfo.totalTime = 0;
 
852
  myTimingInfo.totalFrames = 0;
732
853
}
733
854
 
734
855
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
794
915
}
795
916
 
796
917
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
918
uInt64 OSystem::getTicks() const
 
919
{
 
920
#ifdef HAVE_GETTIMEOFDAY
 
921
  timeval now;
 
922
  gettimeofday(&now, 0);
 
923
 
 
924
  return uInt64(now.tv_sec) * 1000000 + now.tv_usec;
 
925
#else
 
926
  return uInt64(SDL_GetTicks()) * 1000;
 
927
#endif
 
928
}
 
929
 
 
930
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
797
931
void OSystem::mainLoop()
798
932
{
799
933
  if(mySettings->getString("timing") == "sleep")
808
942
      myTimingInfo.current = getTicks();
809
943
      myTimingInfo.virt += myTimePerFrame;
810
944
 
 
945
      // Timestamps may periodically go out of sync, particularly on systems
 
946
      // that can have 'negative time' (ie, when the time seems to go backwards)
 
947
      // This normally results in having a very large delay time, so we check
 
948
      // for that and reset the timers when appropriate
 
949
      if((myTimingInfo.virt - myTimingInfo.current) > (myTimePerFrame << 1))
 
950
      {
 
951
        myTimingInfo.start = myTimingInfo.current = myTimingInfo.virt = getTicks();
 
952
      }
 
953
 
811
954
      if(myTimingInfo.current < myTimingInfo.virt)
812
955
        SDL_Delay((myTimingInfo.virt - myTimingInfo.current) / 1000);
813
956
 
836
979
}
837
980
 
838
981
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
839
 
void OSystem::queryVideoHardware()
 
982
bool OSystem::queryVideoHardware()
840
983
{
841
 
  if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
842
 
    return;
 
984
  // Go ahead and open the video hardware; we're going to need it eventually
 
985
  if(SDL_WasInit(SDL_INIT_VIDEO) == 0)
 
986
    if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
 
987
      return false;
843
988
 
844
989
  // First get the maximum windowed desktop resolution
845
 
  const SDL_VideoInfo* info = SDL_GetVideoInfo();
846
 
  myDesktopWidth  = info->current_w;
847
 
  myDesktopHeight = info->current_h;
 
990
  // Check the 'maxres' setting, which is an undocumented developer feature
 
991
  // that specifies the desktop size
 
992
  // Normally, this wouldn't be set, and we ask SDL directly
 
993
  int w, h;
 
994
  mySettings->getSize("maxres", w, h);
 
995
  if(w == 0 || h == 0)
 
996
  {
 
997
    const SDL_VideoInfo* info = SDL_GetVideoInfo();
 
998
    myDesktopWidth  = info->current_w;
 
999
    myDesktopHeight = info->current_h;
 
1000
  }
 
1001
  else
 
1002
  {
 
1003
    myDesktopWidth  = BSPF_max(w, 320);
 
1004
    myDesktopHeight = BSPF_max(h, 240);
 
1005
  }
 
1006
 
 
1007
  // Various parts of the codebase assume a minimum screen size of 320x240
 
1008
  assert(myDesktopWidth >= 320 && myDesktopHeight >= 240);
848
1009
 
849
1010
  // Then get the valid fullscreen modes
850
1011
  // If there are any errors, just use the desktop resolution
872
1033
      myResolutions.insert_at(0, r);  // insert in opposite (of descending) order
873
1034
    }
874
1035
  }
 
1036
 
 
1037
  return true;
875
1038
}
876
1039
 
877
1040
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
878
1041
/*
879
1042
  Palette is defined as follows:
880
1043
    // Base colors
881
 
    kColor         TODO
882
 
    kBGColor       TODO
 
1044
    kColor            Normal foreground color (non-text)
 
1045
    kBGColor          Normal background color (non-text)
883
1046
    kShadowColor      Item is disabled
884
1047
    kTextColor        Normal text color
885
1048
    kTextColorHi      Highlighted text color
886
 
    kTextColorEm   TODO
 
1049
    kTextColorEm      Emphasized text color
887
1050
 
888
1051
    // UI elements (dialog and widgets)
889
1052
    kDlgColor         Dialog background
939
1102
OSystem& OSystem::operator = (const OSystem&)
940
1103
{
941
1104
  assert(false);
942
 
 
943
1105
  return *this;
944
1106
}