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

« back to all changes in this revision

Viewing changes to src/emucore/FrameBuffer.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: FrameBuffer.cxx,v 1.131 2008/05/21 21:01:40 stephena Exp $
 
17
// $Id: FrameBuffer.cxx 2029 2010-04-29 12:46:07Z stephena $
17
18
//============================================================================
18
19
 
 
20
#include <algorithm>
19
21
#include <sstream>
20
22
 
21
23
#include "bspf.hxx"
26
28
#include "Event.hxx"
27
29
#include "Font.hxx"
28
30
#include "Launcher.hxx"
29
 
#include "MediaSrc.hxx"
30
31
#include "Menu.hxx"
31
32
#include "OSystem.hxx"
32
33
#include "Settings.hxx"
 
34
#include "TIA.hxx"
33
35
 
34
36
#include "FrameBuffer.hxx"
35
37
 
41
43
FrameBuffer::FrameBuffer(OSystem* osystem)
42
44
  : myOSystem(osystem),
43
45
    myScreen(0),
44
 
    theRedrawTIAIndicator(true),
 
46
    myRedrawEntireFrame(true),
45
47
    myUsePhosphor(false),
46
48
    myPhosphorBlend(77),
47
49
    myInitializedCount(0),
48
 
    myPausedCount(0),
49
 
    myFrameStatsEnabled(false)
 
50
    myPausedCount(0)
50
51
{
 
52
  myMsg.surface   = myStatsMsg.surface = NULL;
 
53
  myMsg.surfaceID = myStatsMsg.surfaceID = -1;
 
54
  myMsg.enabled   = myStatsMsg.enabled = false;
51
55
}
52
56
 
53
57
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
54
58
FrameBuffer::~FrameBuffer(void)
55
59
{
 
60
  // Free all allocated surfaces
 
61
  while(!mySurfaceList.empty())
 
62
  {
 
63
    delete (*mySurfaceList.begin()).second;
 
64
    mySurfaceList.erase(mySurfaceList.begin());
 
65
  }
56
66
}
57
67
 
58
68
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
59
 
void FrameBuffer::initialize(const string& title, uInt32 width, uInt32 height)
 
69
bool FrameBuffer::initialize(const string& title, uInt32 width, uInt32 height)
60
70
{
 
71
  ostringstream buf;
 
72
 
61
73
  // Now (re)initialize the SDL video system
62
74
  // These things only have to be done one per FrameBuffer creation
63
75
  if(SDL_WasInit(SDL_INIT_VIDEO) == 0)
 
76
  {
64
77
    if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
65
 
      return;
66
 
 
 
78
    {
 
79
      buf << "ERROR: Couldn't initialize SDL: " << SDL_GetError() << endl;
 
80
      myOSystem->logMessage(buf.str(), 0);
 
81
      return false;
 
82
    }
 
83
  }
67
84
  myInitializedCount++;
68
85
 
69
 
  myBaseDim.x = myBaseDim.y = 0;
70
 
  myBaseDim.w = (uInt16) width;
71
 
  myBaseDim.h = (uInt16) height;
 
86
  // Make sure this mode is even possible
 
87
  // We only really need to worry about it in non-windowed environments,
 
88
  // where requesting a window that's too large will probably cause a crash
 
89
#ifndef WINDOWED_SUPPORT
 
90
  if(myOSystem->desktopWidth() < width || myOSystem->desktopHeight() < height)
 
91
    return false;
 
92
#endif
72
93
 
73
 
  // Set fullscreen flag
74
 
#ifdef WINDOWED_SUPPORT
75
 
  mySDLFlags = myOSystem->settings().getBool("fullscreen") ? SDL_FULLSCREEN : 0;
76
 
#else
 
94
  // Initialize SDL flags and set fullscreen flag
 
95
  // This must be done before any modes are initialized
77
96
  mySDLFlags = 0;
 
97
#ifdef WINDOWED_SUPPORT
 
98
  if(myOSystem->settings().getString("fullscreen") == "1") mySDLFlags = SDL_FULLSCREEN;
78
99
#endif
79
100
 
80
101
  // Set the available video modes for this framebuffer
81
 
  setAvailableVidModes();
82
 
 
83
 
  // Set window title and icon
84
 
  setWindowTitle(title);
85
 
  if(myInitializedCount == 1) setWindowIcon();
86
 
 
87
 
  // Initialize video subsystem
 
102
  setAvailableVidModes(width, height);
 
103
 
 
104
  // Initialize video subsystem (make sure we get a valid mode)
88
105
  VideoMode mode = getSavedVidMode();
89
 
  initSubsystem(mode);
90
 
 
91
 
  // And refresh the display
92
 
  myOSystem->eventHandler().refreshDisplay();
 
106
  if(width <= mode.screen_w && height <= mode.screen_h)
 
107
  {
 
108
    // Set window title and icon
 
109
    setWindowTitle(title);
 
110
    if(myInitializedCount == 1) setWindowIcon();
 
111
 
 
112
    if(!initSubsystem(mode))
 
113
    {
 
114
      myOSystem->logMessage("ERROR: Couldn't initialize video subsystem\n", 0);
 
115
      return false;
 
116
    }
 
117
    else
 
118
    {
 
119
      myImageRect.setWidth(mode.image_w);
 
120
      myImageRect.setHeight(mode.image_h);
 
121
      myImageRect.moveTo(mode.image_x, mode.image_y);
 
122
 
 
123
      myScreenRect.setWidth(mode.screen_w);
 
124
      myScreenRect.setHeight(mode.screen_h);
 
125
 
 
126
      // Did we get the requested fullscreen state?
 
127
      const string& fullscreen = myOSystem->settings().getString("fullscreen");
 
128
      if(fullscreen != "-1")
 
129
        myOSystem->settings().setString("fullscreen", fullScreen() ? "1" : "0");
 
130
      setCursorState();
 
131
    }
 
132
  }
 
133
  else
 
134
    return false;
93
135
 
94
136
  // Enable unicode so we can see translated key events
95
137
  // (lowercase vs. uppercase characters)
96
138
  SDL_EnableUNICODE(1);
97
139
 
98
140
  // Erase any messages from a previous run
99
 
  myMessage.counter = 0;
 
141
  myMsg.counter = 0;
 
142
 
 
143
  // Create surfaces for TIA statistics and general messages
 
144
  myStatsMsg.color = kBtnTextColor;
 
145
  myStatsMsg.w = myOSystem->consoleFont().getMaxCharWidth() * 23 + 2;
 
146
  myStatsMsg.h = (myOSystem->consoleFont().getFontHeight() + 2) * 2;
 
147
 
 
148
 if(myStatsMsg.surface == NULL)
 
149
  {
 
150
    myStatsMsg.surfaceID = allocateSurface(myStatsMsg.w, myStatsMsg.h);
 
151
    myStatsMsg.surface   = surface(myStatsMsg.surfaceID);
 
152
  }
 
153
  if(myMsg.surface == NULL)
 
154
  {
 
155
    myMsg.surfaceID = allocateSurface(500, myOSystem->font().getFontHeight()+10);
 
156
    myMsg.surface   = surface(myMsg.surfaceID);
 
157
  }
100
158
 
101
159
  // Finally, show some information about the framebuffer,
102
160
  // but only on the first initialization
103
 
  if(myInitializedCount == 1 && myOSystem->settings().getBool("showinfo"))
104
 
    cout << about() << endl;
 
161
  if(myInitializedCount == 1)
 
162
    myOSystem->logMessage(about() + "\n", 1);
 
163
 
 
164
  return true;
105
165
}
106
166
 
107
167
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
108
168
void FrameBuffer::update()
109
169
{
110
 
  // Do any pre-frame stuff
111
 
  preFrameUpdate();
112
 
 
113
170
  // Determine which mode we are in (from the EventHandler)
114
171
  // Take care of S_EMULATE mode here, otherwise let the GUI
115
172
  // figure out what to draw
118
175
    case EventHandler::S_EMULATE:
119
176
    {
120
177
      // Run the console for one frame
121
 
      myOSystem->console().mediaSource().update();
 
178
      // Note that the debugger can cause a breakpoint to occur, which changes
 
179
      // the EventHandler state 'behind our back' - we need to check for that
 
180
      myOSystem->console().tia().update();
 
181
  #ifdef DEBUGGER_SUPPORT
 
182
      if(myOSystem->eventHandler().state() != EventHandler::S_EMULATE) break;
 
183
  #endif
122
184
      if(myOSystem->eventHandler().frying())
123
185
        myOSystem->console().fry();
124
186
 
125
187
      // And update the screen
126
 
      drawMediaSource();
 
188
      drawTIA(myRedrawEntireFrame);
127
189
 
128
190
      // Show frame statistics
129
 
      if(myFrameStatsEnabled)
 
191
      if(myStatsMsg.enabled)
130
192
      {
131
 
        // FIXME - sizes hardcoded for now; fix during UI refactoring
 
193
        const ConsoleInfo& info = myOSystem->console().about();
132
194
        char msg[30];
133
 
        sprintf(msg, "%u LINES  %2.2f FPS",
134
 
                myOSystem->console().mediaSource().scanlines(),
135
 
                myOSystem->console().getFramerate());
136
 
        fillRect(3, 3, 95, 9, kBGColor);
137
 
        drawString(&myOSystem->font(), msg, 3, 3, 95, kBtnTextColor, kTextAlignCenter);
 
195
        sprintf(msg, "%u @ %2.2ffps => %s",
 
196
                myOSystem->console().tia().scanlines(),
 
197
                myOSystem->console().getFramerate(), info.DisplayFormat.c_str());
 
198
        myStatsMsg.surface->fillRect(0, 0, myStatsMsg.w, myStatsMsg.h, kBGColor);
 
199
        myStatsMsg.surface->drawString(&myOSystem->consoleFont(),
 
200
          msg, 1, 1, myStatsMsg.w, myStatsMsg.color, kTextAlignLeft);
 
201
        myStatsMsg.surface->drawString(&myOSystem->consoleFont(),
 
202
          info.BankSwitch, 1, 15, myStatsMsg.w, myStatsMsg.color, kTextAlignLeft);
 
203
        myStatsMsg.surface->addDirtyRect(0, 0, 0, 0);  // force a full draw
 
204
        myStatsMsg.surface->setPos(myImageRect.x() + 1, myImageRect.y() + 1);
 
205
        myStatsMsg.surface->update();
138
206
      }
139
 
 
140
207
      break;  // S_EMULATE
141
208
    }
142
209
 
143
210
    case EventHandler::S_PAUSE:
144
211
    {
145
212
      // Only update the screen if it's been invalidated
146
 
      if(theRedrawTIAIndicator)
147
 
        drawMediaSource();
 
213
      if(myRedrawEntireFrame)
 
214
        drawTIA(true);
148
215
 
149
216
      // Show a pause message every 5 seconds
150
217
      if(myPausedCount++ >= 7*myOSystem->frameRate())
157
224
 
158
225
    case EventHandler::S_MENU:
159
226
    {
160
 
      // Only update the screen if it's been invalidated
161
 
      if(theRedrawTIAIndicator)
162
 
        drawMediaSource();
163
 
 
164
 
      myOSystem->menu().draw();
 
227
      // When onscreen messages are enabled in double-buffer mode,
 
228
      // a full redraw is required
 
229
      myOSystem->menu().draw(myMsg.enabled && type() == kGLBuffer);
165
230
      break;  // S_MENU
166
231
    }
167
232
 
168
233
    case EventHandler::S_CMDMENU:
169
234
    {
170
 
      // Only update the screen if it's been invalidated
171
 
      if(theRedrawTIAIndicator)
172
 
        drawMediaSource();
173
 
 
174
 
      myOSystem->commandMenu().draw();
 
235
      // When onscreen messages are enabled in double-buffer mode,
 
236
      // a full redraw is required
 
237
      myOSystem->commandMenu().draw(myMsg.enabled && type() == kGLBuffer);
175
238
      break;  // S_CMDMENU
176
239
    }
177
240
 
178
241
    case EventHandler::S_LAUNCHER:
179
242
    {
180
 
      myOSystem->launcher().draw();
 
243
      // When onscreen messages are enabled in double-buffer mode,
 
244
      // a full redraw is required
 
245
      myOSystem->launcher().draw(myMsg.enabled && type() == kGLBuffer);
181
246
      break;  // S_LAUNCHER
182
247
    }
183
248
 
184
249
#ifdef DEBUGGER_SUPPORT
185
250
    case EventHandler::S_DEBUGGER:
186
251
    {
187
 
      myOSystem->debugger().draw();
 
252
      // When onscreen messages are enabled in double-buffer mode,
 
253
      // a full redraw is required
 
254
      myOSystem->debugger().draw(myMsg.enabled && type() == kGLBuffer);
188
255
      break;  // S_DEBUGGER
189
256
    }
190
257
#endif
195
262
  }
196
263
 
197
264
  // Draw any pending messages
198
 
  if(myMessage.counter > 0)
 
265
  if(myMsg.enabled)
199
266
    drawMessage();
200
267
 
201
268
  // Do any post-frame stuff
202
269
  postFrameUpdate();
203
270
 
204
271
  // The frame doesn't need to be completely redrawn anymore
205
 
  theRedrawTIAIndicator = false;
 
272
  myRedrawEntireFrame = false;
206
273
}
207
274
 
208
275
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
209
276
void FrameBuffer::showMessage(const string& message, MessagePosition position,
210
 
                              int color)
 
277
                              bool force, uInt32 color)
211
278
{
 
279
  // Only show messages if they've been enabled
 
280
  if(!(force || myOSystem->settings().getBool("uimessages")))
 
281
    return;
 
282
 
212
283
  // Erase old messages on the screen
213
 
  if(myMessage.counter > 0)
 
284
  if(myMsg.counter > 0)
214
285
  {
215
 
    theRedrawTIAIndicator = true;
216
 
    myOSystem->eventHandler().refreshDisplay();
 
286
    myRedrawEntireFrame = true;
 
287
    refresh();
217
288
  }
218
289
 
219
290
  // Precompute the message coordinates
220
 
  myMessage.text    = message;
221
 
  myMessage.counter = uInt32(myOSystem->frameRate()) << 1; // Show message for 2 seconds
222
 
  myMessage.color   = color;
223
 
 
224
 
  myMessage.w = myOSystem->font().getStringWidth(myMessage.text) + 10;
225
 
  myMessage.h = myOSystem->font().getFontHeight() + 8;
226
 
 
227
 
  switch(position)
 
291
  myMsg.text    = message;
 
292
  myMsg.counter = uInt32(myOSystem->frameRate()) << 1; // Show message for 2 seconds
 
293
  myMsg.color   = color;
 
294
 
 
295
  myMsg.w = myOSystem->font().getStringWidth(myMsg.text) + 10;
 
296
  myMsg.h = myOSystem->font().getFontHeight() + 8;
 
297
  myMsg.surface->setWidth(myMsg.w);
 
298
  myMsg.surface->setHeight(myMsg.h);
 
299
  myMsg.position = position;
 
300
  myMsg.enabled = true;
 
301
}
 
302
 
 
303
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
304
void FrameBuffer::toggleFrameStats()
 
305
{
 
306
  showFrameStats(!myOSystem->settings().getBool("stats"));
 
307
}
 
308
 
 
309
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
310
void FrameBuffer::showFrameStats(bool enable)
 
311
{
 
312
  myOSystem->settings().setBool("stats", enable);
 
313
  myStatsMsg.enabled = enable;
 
314
  refresh();
 
315
}
 
316
 
 
317
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
318
void FrameBuffer::enableMessages(bool enable)
 
319
{
 
320
  if(enable)
 
321
  {
 
322
    // Only re-enable frame stats if they were already enabled before
 
323
    myStatsMsg.enabled = myOSystem->settings().getBool("stats");
 
324
  }
 
325
  else
 
326
  {
 
327
    // Temporarily disable frame stats
 
328
    myStatsMsg.enabled = false;
 
329
 
 
330
    // Erase old messages on the screen
 
331
    myMsg.enabled = false;
 
332
    myMsg.counter = 0;
 
333
 
 
334
    refresh();
 
335
  }
 
336
}
 
337
 
 
338
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
339
inline void FrameBuffer::drawMessage()
 
340
{
 
341
  // Draw the bounded box and text
 
342
  switch(myMsg.position)
228
343
  {
229
344
    case kTopLeft:
230
 
      myMessage.x = 5;
231
 
      myMessage.y = 5;
 
345
      myMsg.x = 5;
 
346
      myMsg.y = 5;
232
347
      break;
233
348
 
234
349
    case kTopCenter:
235
 
      myMessage.x = (myBaseDim.w >> 1) - (myMessage.w >> 1);
236
 
      myMessage.y = 5;
 
350
      myMsg.x = (myImageRect.width() - myMsg.w) >> 1;
 
351
      myMsg.y = 5;
237
352
      break;
238
353
 
239
354
    case kTopRight:
240
 
      myMessage.x = myBaseDim.w - myMessage.w - 5;
241
 
      myMessage.y = 5;
 
355
      myMsg.x = myImageRect.width() - myMsg.w - 5;
 
356
      myMsg.y = 5;
242
357
      break;
243
358
 
244
359
    case kMiddleLeft:
245
 
      myMessage.x = 5;
246
 
      myMessage.y = (myBaseDim.h >> 1) - (myMessage.h >> 1);
 
360
      myMsg.x = 5;
 
361
      myMsg.y = (myImageRect.height() - myMsg.h) >> 1;
247
362
      break;
248
363
 
249
364
    case kMiddleCenter:
250
 
      myMessage.x = (myBaseDim.w >> 1) - (myMessage.w >> 1);
251
 
      myMessage.y = (myBaseDim.h >> 1) - (myMessage.h >> 1);
 
365
      myMsg.x = (myImageRect.width() - myMsg.w) >> 1;
 
366
      myMsg.y = (myImageRect.height() - myMsg.h) >> 1;
252
367
      break;
253
368
 
254
369
    case kMiddleRight:
255
 
      myMessage.x = myBaseDim.w - myMessage.w - 5;
256
 
      myMessage.y = (myBaseDim.h >> 1) - (myMessage.h >> 1);
 
370
      myMsg.x = myImageRect.width() - myMsg.w - 5;
 
371
      myMsg.y = (myImageRect.height() - myMsg.h) >> 1;
257
372
      break;
258
373
 
259
374
    case kBottomLeft:
260
 
      myMessage.x = 5;//(myMessage.w >> 1);
261
 
      myMessage.y = myBaseDim.h - myMessage.h - 5;
 
375
      myMsg.x = 5;
 
376
      myMsg.y = myImageRect.height() - myMsg.h - 5;
262
377
      break;
263
378
 
264
379
    case kBottomCenter:
265
 
      myMessage.x = (myBaseDim.w >> 1) - (myMessage.w >> 1);
266
 
      myMessage.y = myBaseDim.h - myMessage.h - 5;
 
380
      myMsg.x = (myImageRect.width() - myMsg.w) >> 1;
 
381
      myMsg.y = myImageRect.height() - myMsg.h - 5;
267
382
      break;
268
383
 
269
384
    case kBottomRight:
270
 
      myMessage.x = myBaseDim.w - myMessage.w - 5;
271
 
      myMessage.y = myBaseDim.h - myMessage.h - 5;
 
385
      myMsg.x = myImageRect.width() - myMsg.w - 5;
 
386
      myMsg.y = myImageRect.height() - myMsg.h - 5;
272
387
      break;
273
388
  }
274
 
}
275
 
 
276
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
277
 
void FrameBuffer::toggleFrameStats()
278
 
{
279
 
  showFrameStats(!myOSystem->settings().getBool("stats"));
280
 
}
281
 
 
282
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
283
 
void FrameBuffer::showFrameStats(bool enable)
284
 
{
285
 
  myOSystem->settings().setBool("stats", enable);
286
 
  myFrameStatsEnabled = enable;
287
 
  myOSystem->eventHandler().refreshDisplay();
288
 
}
289
 
 
290
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
291
 
void FrameBuffer::enableMessages(bool enable)
292
 
{
293
 
  if(enable)
294
 
  {
295
 
    // Only re-anable frame stats if they were already enabled before
296
 
    myFrameStatsEnabled = myOSystem->settings().getBool("stats");
297
 
  }
298
 
  else
299
 
  {
300
 
    // Temporarily disable frame stats
301
 
    myFrameStatsEnabled = false;
302
 
 
303
 
    // Erase old messages on the screen
304
 
    myMessage.counter = 0;
305
 
 
306
 
    myOSystem->eventHandler().refreshDisplay(true);  // Do this twice for
307
 
    myOSystem->eventHandler().refreshDisplay(true);  // double-buffered modes
308
 
  }
309
 
}
310
 
 
311
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
312
 
inline void FrameBuffer::drawMessage()
313
 
{
314
 
  // Draw the bounded box and text
315
 
  fillRect(myMessage.x+1, myMessage.y+2, myMessage.w-2, myMessage.h-4, kBGColor);
316
 
  box(myMessage.x, myMessage.y+1, myMessage.w, myMessage.h-2, kColor, kShadowColor);
317
 
  drawString(&myOSystem->font(), myMessage.text, myMessage.x+1, myMessage.y+4,
318
 
             myMessage.w, myMessage.color, kTextAlignCenter);
319
 
  myMessage.counter--;
 
389
 
 
390
  myMsg.surface->setPos(myMsg.x + myImageRect.x(), myMsg.y + myImageRect.y());
 
391
  myMsg.surface->fillRect(0, 0, myMsg.w-2, myMsg.h-4, kBGColor);
 
392
  myMsg.surface->box(0, 0, myMsg.w, myMsg.h-2, kColor, kShadowColor);
 
393
  myMsg.surface->drawString(&myOSystem->font(), myMsg.text, 4, 4,
 
394
                               myMsg.w, myMsg.color, kTextAlignLeft);
 
395
  myMsg.counter--;
320
396
 
321
397
  // Either erase the entire message (when time is reached),
322
398
  // or show again this frame
323
 
  if(myMessage.counter == 0)  // Force an immediate update
324
 
    myOSystem->eventHandler().refreshDisplay(true);
 
399
  if(myMsg.counter == 0)  // Force an immediate update
 
400
  {
 
401
    myMsg.enabled = false;
 
402
    refresh();
 
403
  }
325
404
  else
326
 
    addDirtyRect(myMessage.x, myMessage.y, myMessage.w, myMessage.h);
 
405
  {
 
406
    myMsg.surface->addDirtyRect(0, 0, 0, 0);
 
407
    myMsg.surface->update();
 
408
  }
327
409
}
328
410
 
329
411
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
330
412
void FrameBuffer::refresh()
331
413
{
332
 
  theRedrawTIAIndicator = true;
 
414
  // This method partly duplicates the behaviour in ::update()
 
415
  // Here, however, make sure to redraw *all* surfaces applicable to the
 
416
  // current EventHandler state
 
417
  // We also check for double-buffered modes, and when present
 
418
  // update both buffers accordingly
 
419
  //
 
420
  // This method is in essence a FULL refresh, putting all rendering
 
421
  // buffers in a known, fully redrawn state
 
422
 
 
423
  invalidate();
 
424
  bool doubleBuffered = (type() == kGLBuffer);
 
425
  switch(myOSystem->eventHandler().state())
 
426
  {
 
427
    case EventHandler::S_EMULATE:
 
428
    case EventHandler::S_PAUSE:
 
429
      drawTIA(true);
 
430
      if(doubleBuffered)
 
431
        drawTIA(true);
 
432
      break;
 
433
 
 
434
    case EventHandler::S_MENU:
 
435
      drawTIA(true);
 
436
      myOSystem->menu().draw(true);
 
437
      if(doubleBuffered)
 
438
      {
 
439
        postFrameUpdate();
 
440
        drawTIA(true);
 
441
        myOSystem->menu().draw(true);
 
442
      }
 
443
      break;
 
444
 
 
445
    case EventHandler::S_CMDMENU:
 
446
      drawTIA(true);
 
447
      myOSystem->commandMenu().draw(true);
 
448
      if(doubleBuffered)
 
449
      {
 
450
        postFrameUpdate();
 
451
        drawTIA(true);
 
452
        myOSystem->commandMenu().draw(true);
 
453
      }
 
454
      break;
 
455
 
 
456
    case EventHandler::S_LAUNCHER:
 
457
      myOSystem->launcher().draw(true);
 
458
      if(doubleBuffered)
 
459
      {
 
460
        postFrameUpdate();
 
461
        myOSystem->launcher().draw(true);
 
462
      }
 
463
      break;
 
464
 
 
465
  #ifdef DEBUGGER_SUPPORT
 
466
    case EventHandler::S_DEBUGGER:
 
467
      myOSystem->debugger().draw(true);
 
468
      if(doubleBuffered)
 
469
      {
 
470
        postFrameUpdate();
 
471
        myOSystem->debugger().draw(true);
 
472
      }
 
473
      break;
 
474
  #endif
 
475
 
 
476
    default:
 
477
      break;
 
478
  }
 
479
}
 
480
 
 
481
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
482
int FrameBuffer::allocateSurface(int w, int h, bool useBase)
 
483
{
 
484
  // Create a new surface
 
485
  FBSurface* surface = createSurface(w, h, useBase);
 
486
 
 
487
  // Add it to the list
 
488
  mySurfaceList.insert(make_pair(int(mySurfaceList.size()), surface));
 
489
 
 
490
  // Return a reference to it
 
491
  return mySurfaceList.size() - 1;
 
492
}
 
493
 
 
494
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
495
FBSurface* FrameBuffer::surface(int id) const
 
496
{
 
497
  map<int,FBSurface*>::const_iterator iter = mySurfaceList.find(id);
 
498
  return iter != mySurfaceList.end() ? iter->second : NULL;
 
499
}
 
500
 
 
501
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
502
void FrameBuffer::resetSurfaces()
 
503
{
 
504
  // Free all resources for each surface, then reload them
 
505
  // Due to possible timing and/or synchronization issues, all free()'s
 
506
  // are done first, then all reload()'s
 
507
  // Any derived FrameBuffer classes that call this method should be
 
508
  // aware of these restrictions, and act accordingly
 
509
 
 
510
  map<int,FBSurface*>::iterator iter;
 
511
  for(iter = mySurfaceList.begin(); iter != mySurfaceList.end(); ++iter)
 
512
    iter->second->free();
 
513
  for(iter = mySurfaceList.begin(); iter != mySurfaceList.end(); ++iter)
 
514
    iter->second->reload();
 
515
}
 
516
 
 
517
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
518
uInt32 FrameBuffer::tiaPixel(uInt32 idx, uInt8 shift) const
 
519
{
 
520
  uInt8 c = *(myOSystem->console().tia().currentFrameBuffer() + idx) | shift;
 
521
  uInt8 p = *(myOSystem->console().tia().previousFrameBuffer() + idx) | shift;
 
522
 
 
523
  return (!myUsePhosphor ? myDefPalette[c] : myAvgPalette[c][p]);
333
524
}
334
525
 
335
526
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
345
536
    Uint8 b = palette[i] & 0xff;
346
537
 
347
538
    myDefPalette[i] = mapRGB(r, g, b);
 
539
    if(SDL_BYTEORDER == SDL_LIL_ENDIAN)
 
540
    {
 
541
      myDefPalette24[i][0] = b;
 
542
      myDefPalette24[i][1] = g;
 
543
      myDefPalette24[i][2] = r;
 
544
    }
 
545
    else
 
546
    {
 
547
      myDefPalette24[i][0] = r;
 
548
      myDefPalette24[i][1] = g;
 
549
      myDefPalette24[i][2] = b;
 
550
    }
348
551
  }
349
552
 
350
553
  // Set palette for phosphor effect
367
570
    }
368
571
  }
369
572
 
370
 
  theRedrawTIAIndicator = true;
 
573
  myRedrawEntireFrame = true;
371
574
}
372
575
 
373
576
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
374
577
void FrameBuffer::setUIPalette(const uInt32* palette)
375
578
{
376
579
  // Set palette for GUI
377
 
  for(int i = 0; i < kNumColors-256; ++i)
 
580
  for(int i = 0, j = 256; i < kNumColors-256; ++i, ++j)
378
581
  {
379
582
    Uint8 r = (palette[i] >> 16) & 0xff;
380
583
    Uint8 g = (palette[i] >> 8) & 0xff;
381
584
    Uint8 b = palette[i] & 0xff;
382
 
    myDefPalette[i+256] = mapRGB(r, g, b);
 
585
 
 
586
    myDefPalette[j] = mapRGB(r, g, b);
 
587
    if(SDL_BYTEORDER == SDL_LIL_ENDIAN)
 
588
    {
 
589
      myDefPalette24[j][0] = b;
 
590
      myDefPalette24[j][1] = g;
 
591
      myDefPalette24[j][2] = r;
 
592
    }
 
593
    else
 
594
    {
 
595
      myDefPalette24[j][0] = r;
 
596
      myDefPalette24[j][1] = g;
 
597
      myDefPalette24[j][2] = b;
 
598
    }
383
599
  }
384
600
}
385
601
 
386
602
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
603
void FrameBuffer::stateChanged(EventHandler::State state)
 
604
{
 
605
  // Make sure any onscreen messages are removed
 
606
  myMsg.enabled = false;
 
607
  myMsg.counter = 0;
 
608
 
 
609
  myRedrawEntireFrame = true;
 
610
}
 
611
 
 
612
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
387
613
void FrameBuffer::toggleFullscreen()
388
614
{
389
 
  setFullscreen(!myOSystem->settings().getBool("fullscreen"));
 
615
  setFullscreen(!fullScreen());
390
616
}
391
617
 
392
618
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
393
619
void FrameBuffer::setFullscreen(bool enable)
394
620
{
395
621
#ifdef WINDOWED_SUPPORT
396
 
  // Update the settings
397
 
  myOSystem->settings().setBool("fullscreen", enable);
398
 
  if(enable)
 
622
  // '-1' means fullscreen mode is completely disabled
 
623
  if(enable && myOSystem->settings().getString("fullscreen") != "-1" )
399
624
    mySDLFlags |= SDL_FULLSCREEN;
400
625
  else
401
626
    mySDLFlags &= ~SDL_FULLSCREEN;
413
638
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
414
639
bool FrameBuffer::changeVidMode(int direction)
415
640
{
416
 
  bool saveModeChange = true;
417
 
 
418
 
  VideoMode oldmode = myCurrentModeList->current();
 
641
  EventHandler::State state = myOSystem->eventHandler().state();
 
642
  bool inUIMode = (state == EventHandler::S_DEBUGGER ||
 
643
                   state == EventHandler::S_LAUNCHER);
 
644
 
 
645
  // Ignore any attempts to change video size while in UI mode
 
646
  if(inUIMode && direction != 0)
 
647
    return false;
 
648
 
 
649
  // Only save mode changes in TIA mode with a valid selector
 
650
  bool saveModeChange = !inUIMode && (direction == -1 || direction == +1);
 
651
 
419
652
  if(direction == +1)
420
653
    myCurrentModeList->next();
421
654
  else if(direction == -1)
422
655
    myCurrentModeList->previous();
 
656
 
 
657
  VideoMode vidmode = myCurrentModeList->current(myOSystem->settings(), fullScreen());
 
658
  if(setVidMode(vidmode))
 
659
  {
 
660
    myImageRect.setWidth(vidmode.image_w);
 
661
    myImageRect.setHeight(vidmode.image_h);
 
662
    myImageRect.moveTo(vidmode.image_x, vidmode.image_y);
 
663
 
 
664
    myScreenRect.setWidth(vidmode.screen_w);
 
665
    myScreenRect.setHeight(vidmode.screen_h);
 
666
 
 
667
    // Did we get the requested fullscreen state?
 
668
    const string& fullscreen = myOSystem->settings().getString("fullscreen");
 
669
    if(fullscreen != "-1")
 
670
      myOSystem->settings().setString("fullscreen", fullScreen() ? "1" : "0");
 
671
    setCursorState();
 
672
 
 
673
    if(!inUIMode)
 
674
    {
 
675
      if(direction != 0)  // only show message when mode actually changes
 
676
        showMessage(vidmode.gfxmode.description);
 
677
    }
 
678
    if(saveModeChange)
 
679
      myOSystem->settings().setString("tia_filter", vidmode.gfxmode.name);
 
680
 
 
681
    refresh();
 
682
  }
423
683
  else
424
 
    saveModeChange = false;  // no resolution or zoom level actually changed
425
 
 
426
 
  VideoMode newmode = myCurrentModeList->current();
427
 
  if(!setVidMode(newmode))
428
684
    return false;
429
685
 
430
 
  myOSystem->eventHandler().handleResizeEvent();
431
 
  myOSystem->eventHandler().refreshDisplay(true);
432
 
  setCursorState();
433
 
  showMessage(newmode.name);
434
 
 
435
 
  if(saveModeChange)
436
 
  {
437
 
    // Determine which mode we're in, and save to the appropriate setting
438
 
    if(fullScreen())
439
 
    {
440
 
      myOSystem->settings().setSize("fullres", newmode.screen_w, newmode.screen_h);
441
 
    }
442
 
    else
443
 
    {
444
 
      EventHandler::State state = myOSystem->eventHandler().state();
445
 
      bool inTIAMode = (state == EventHandler::S_EMULATE ||
446
 
                        state == EventHandler::S_PAUSE   ||
447
 
                        state == EventHandler::S_MENU    ||
448
 
                        state == EventHandler::S_CMDMENU);
449
 
 
450
 
      if(inTIAMode)
451
 
        myOSystem->settings().setInt("zoom_tia", newmode.zoom);
452
 
      else
453
 
        myOSystem->settings().setInt("zoom_ui", newmode.zoom);
454
 
    }
455
 
  }
456
686
  return true;
457
687
/*
458
688
cerr << "New mode:" << endl
471
701
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
472
702
void FrameBuffer::setCursorState()
473
703
{
474
 
  bool isFullscreen = myOSystem->settings().getBool("fullscreen");
475
 
 
476
 
  if(isFullscreen)
 
704
  if(fullScreen())
477
705
    grabMouse(true);
478
706
  else
479
707
    grabMouse(myOSystem->settings().getBool("grabmouse"));
486
714
      break;
487
715
    default:
488
716
      showCursor(true);
 
717
      break;
489
718
  }
490
719
}
491
720
 
505
734
bool FrameBuffer::fullScreen() const
506
735
{
507
736
#ifdef WINDOWED_SUPPORT
508
 
    return myOSystem->settings().getBool("fullscreen");
 
737
  return mySDLFlags & SDL_FULLSCREEN;
509
738
#else
510
 
    return true;
 
739
  return true;
511
740
#endif
512
741
}
513
742
 
528
757
  uInt32 rgba[256], icon[32 * 32];
529
758
  uInt8  mask[32][4];
530
759
 
531
 
  sscanf(stella_icon[0], "%d %d %d %d", &w, &h, &ncols, &nbytes);
 
760
  sscanf(stella_icon[0], "%u %u %u %u", &w, &h, &ncols, &nbytes);
532
761
  if((w != 32) || (h != 32) || (ncols > 255) || (nbytes > 1))
533
762
  {
534
 
    cerr << "ERROR: Couldn't load the icon.\n";
 
763
    myOSystem->logMessage("ERROR: Couldn't load the application icon.\n", 0);
535
764
    return;
536
765
  }
537
766
 
553
782
    }
554
783
    else
555
784
    {
556
 
      cerr << "ERROR: Couldn't load the icon.\n";
 
785
      myOSystem->logMessage("ERROR: Couldn't load the application icon.\n", 0);
557
786
      return;
558
787
    }
559
788
    rgba[code] = col;
579
808
}
580
809
 
581
810
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
582
 
void FrameBuffer::box(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
583
 
                      int colorA, int colorB)
 
811
uInt8 FrameBuffer::getPhosphor(uInt8 c1, uInt8 c2)
 
812
{
 
813
  if(c2 > c1)
 
814
    BSPF_swap(c1, c2);
 
815
 
 
816
  return ((c1 - c2) * myPhosphorBlend)/100 + c2;
 
817
}
 
818
 
 
819
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
820
const StringMap& FrameBuffer::supportedTIAFilters(const string& type)
 
821
{
 
822
  uInt32 max_zoom = maxWindowSizeForScreen(320, 210,
 
823
                    myOSystem->desktopWidth(), myOSystem->desktopHeight());
 
824
  uInt8 mask = (type == "soft" ? 0x1 : 0x2);
 
825
 
 
826
  uInt32 firstmode = 1;
 
827
  if(myOSystem->desktopWidth() < 640 || myOSystem->desktopHeight() < 480)
 
828
    firstmode = 0;
 
829
 
 
830
  myTIAFilters.clear();
 
831
  for(uInt32 i = firstmode; i < GFX_NumModes; ++i)
 
832
  {
 
833
    // For now, just include all filters
 
834
    // This will change once OpenGL-only filters are added
 
835
    if((ourGraphicsModes[i].avail & mask) && ourGraphicsModes[i].zoom <= max_zoom)
 
836
    {
 
837
      myTIAFilters.push_back(ourGraphicsModes[i].description,
 
838
                             ourGraphicsModes[i].name);
 
839
    }
 
840
  }
 
841
  return myTIAFilters;
 
842
}
 
843
 
 
844
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
845
uInt32 FrameBuffer::maxWindowSizeForScreen(uInt32 baseWidth, uInt32 baseHeight,
 
846
                    uInt32 screenWidth, uInt32 screenHeight)
 
847
{
 
848
  uInt32 multiplier = 1;
 
849
  for(;;)
 
850
  {
 
851
    // Figure out the zoomed size of the window
 
852
    uInt32 width  = baseWidth * multiplier;
 
853
    uInt32 height = baseHeight * multiplier;
 
854
 
 
855
    if((width > screenWidth) || (height > screenHeight))
 
856
      break;
 
857
 
 
858
    ++multiplier;
 
859
  }
 
860
  return multiplier > 1 ? multiplier - 1 : 1;
 
861
}
 
862
 
 
863
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
864
void FrameBuffer::setAvailableVidModes(uInt32 baseWidth, uInt32 baseHeight)
 
865
{
 
866
  // Modelists are different depending on what state we're in
 
867
  EventHandler::State state = myOSystem->eventHandler().state();
 
868
  bool inUIMode = (state == EventHandler::S_DEBUGGER ||
 
869
                   state == EventHandler::S_LAUNCHER);
 
870
 
 
871
  myWindowedModeList.clear();
 
872
  myFullscreenModeList.clear();
 
873
 
 
874
  // In UI/windowed mode, there's only one valid video mode we can use
 
875
  // We don't use maxWindowSizeForScreen here, since UI mode has to open its
 
876
  // window at the requested size
 
877
  if(inUIMode)
 
878
  {
 
879
    VideoMode m;
 
880
    m.image_x = m.image_y = 0;
 
881
    m.image_w = m.screen_w = baseWidth;
 
882
    m.image_h = m.screen_h = baseHeight;
 
883
    m.gfxmode = ourGraphicsModes[0];  // this should be zoom1x
 
884
 
 
885
    addVidMode(m);
 
886
  }
 
887
  else
 
888
  {
 
889
    // Scan list of filters, adding only those which are appropriate
 
890
    // for the given dimensions
 
891
    uInt32 max_zoom = maxWindowSizeForScreen(baseWidth, baseHeight,
 
892
                      myOSystem->desktopWidth(), myOSystem->desktopHeight());
 
893
 
 
894
    // Figure our the smallest zoom level we can use
 
895
    uInt32 firstmode = 1;
 
896
    if(myOSystem->desktopWidth() < 640 || myOSystem->desktopHeight() < 480)
 
897
      firstmode = 0;
 
898
 
 
899
    for(uInt32 i = firstmode; i < GFX_NumModes; ++i)
 
900
    {
 
901
      uInt32 zoom = ourGraphicsModes[i].zoom;
 
902
      if(zoom <= max_zoom)
 
903
      {
 
904
        VideoMode m;
 
905
        m.image_x = m.image_y = 0;
 
906
        m.image_w = m.screen_w = baseWidth * zoom;
 
907
        m.image_h = m.screen_h = baseHeight * zoom;
 
908
        m.gfxmode = ourGraphicsModes[i];
 
909
 
 
910
        addVidMode(m);
 
911
      }
 
912
    }
 
913
  }
 
914
}
 
915
 
 
916
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
917
void FrameBuffer::addVidMode(VideoMode& mode)
 
918
{
 
919
  // The are minimum size requirements on a screen, no matter is in fullscreen
 
920
  // or windowed mode
 
921
  // Various part of the UI system depend on having at least 320x240 pixels
 
922
  // available, so we must enforce it here
 
923
 
 
924
  // Windowed modes can be sized exactly as required, since there's normally
 
925
  // no restriction on window size (between the minimum and maximum size)
 
926
  mode.screen_w = BSPF_max(mode.screen_w, 320u);
 
927
  mode.screen_h = BSPF_max(mode.screen_h, 240u);
 
928
  mode.image_x = (mode.screen_w - mode.image_w) >> 1;
 
929
  mode.image_y = (mode.screen_h - mode.image_h) >> 1;
 
930
  myWindowedModeList.add(mode);
 
931
 
 
932
  // There are often stricter requirements on fullscreen modes, and they're
 
933
  // normally different depending on the OSystem in use
 
934
  // As well, we usually can't get fullscreen modes in the exact size
 
935
  // we want, so we need to calculate image offsets
 
936
  const ResolutionList& res = myOSystem->supportedResolutions();
 
937
  for(uInt32 i = 0; i < res.size(); ++i)
 
938
  {
 
939
    if(mode.screen_w <= res[i].width && mode.screen_h <= res[i].height)
 
940
    {
 
941
      // Auto-calculate 'smart' centering; platform-specific framebuffers are
 
942
      // free to ignore or augment it
 
943
      mode.screen_w = BSPF_max(res[i].width, 320u);
 
944
      mode.screen_h = BSPF_max(res[i].height, 240u);
 
945
      mode.image_x = (mode.screen_w - mode.image_w) >> 1;
 
946
      mode.image_y = (mode.screen_h - mode.image_h) >> 1;
 
947
      break;
 
948
    }
 
949
  }
 
950
  myFullscreenModeList.add(mode);
 
951
}
 
952
 
 
953
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
954
FrameBuffer::VideoMode FrameBuffer::getSavedVidMode()
 
955
{
 
956
  EventHandler::State state = myOSystem->eventHandler().state();
 
957
 
 
958
  if(fullScreen())
 
959
    myCurrentModeList = &myFullscreenModeList;
 
960
  else
 
961
    myCurrentModeList = &myWindowedModeList;
 
962
 
 
963
  // Now select the best resolution depending on the state
 
964
  // UI modes (launcher and debugger) have only one supported resolution
 
965
  // so the 'current' one is the only valid one
 
966
  if(state == EventHandler::S_DEBUGGER || state == EventHandler::S_LAUNCHER)
 
967
  {
 
968
    myCurrentModeList->setByGfxMode(GFX_Zoom1x);
 
969
  }
 
970
  else
 
971
  {
 
972
    const string& name = myOSystem->settings().getString("tia_filter");
 
973
    myCurrentModeList->setByGfxMode(name);
 
974
  }
 
975
 
 
976
  return myCurrentModeList->current(myOSystem->settings(), fullScreen());
 
977
}
 
978
 
 
979
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
980
FrameBuffer::VideoModeList::VideoModeList()
 
981
  : myIdx(-1)
 
982
{
 
983
}
 
984
 
 
985
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
986
FrameBuffer::VideoModeList::~VideoModeList()
 
987
{
 
988
  clear();
 
989
}
 
990
 
 
991
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
992
void FrameBuffer::VideoModeList::add(VideoMode mode)
 
993
{
 
994
  myModeList.push_back(mode);
 
995
}
 
996
 
 
997
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
998
void FrameBuffer::VideoModeList::clear()
 
999
{
 
1000
  myModeList.clear();
 
1001
}
 
1002
 
 
1003
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1004
bool FrameBuffer::VideoModeList::isEmpty() const
 
1005
{
 
1006
  return myModeList.isEmpty();
 
1007
}
 
1008
 
 
1009
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1010
uInt32 FrameBuffer::VideoModeList::size() const
 
1011
{
 
1012
  return myModeList.size();
 
1013
}
 
1014
 
 
1015
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1016
void FrameBuffer::VideoModeList::previous()
 
1017
{
 
1018
  --myIdx;
 
1019
  if(myIdx < 0) myIdx = myModeList.size() - 1;
 
1020
}
 
1021
 
 
1022
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1023
const FrameBuffer::VideoMode FrameBuffer::
 
1024
  VideoModeList::current(const Settings& settings, bool isFullscreen) const
 
1025
{
 
1026
  // Fullscreen modes are related to the 'fullres' setting
 
1027
  //   If it's 'auto', we just use the mode as already previously defined
 
1028
  //   If it's not 'auto', attempt to fit the mode into the resolution
 
1029
  //   specified by 'fullres' (if possible)
 
1030
  if(isFullscreen && BSPF_tolower(settings.getString("fullres")) != "auto")
 
1031
  {
 
1032
    // Only use 'fullres' if it's *bigger* than the requested mode
 
1033
    int w, h;
 
1034
    settings.getSize("fullres", w, h);
 
1035
 
 
1036
    if(w != -1 && h != -1 && (uInt32)w >= myModeList[myIdx].screen_w &&
 
1037
      (uInt32)h >= myModeList[myIdx].screen_h)
 
1038
    {
 
1039
      VideoMode mode = myModeList[myIdx];
 
1040
      mode.screen_w = w;
 
1041
      mode.screen_h = h;
 
1042
      mode.image_x = (mode.screen_w - mode.image_w) >> 1;
 
1043
      mode.image_y = (mode.screen_h - mode.image_h) >> 1;
 
1044
 
 
1045
      return mode;
 
1046
    }
 
1047
  }
 
1048
 
 
1049
  // Otherwise, we just use the mode has it was defined in ::addVidMode()
 
1050
  return myModeList[myIdx];
 
1051
}
 
1052
 
 
1053
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1054
void FrameBuffer::VideoModeList::next()
 
1055
{
 
1056
  myIdx = (myIdx + 1) % myModeList.size();
 
1057
}
 
1058
 
 
1059
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1060
void FrameBuffer::VideoModeList::setByGfxMode(GfxID id)
 
1061
{
 
1062
  // First we determine which graphics mode is being requested
 
1063
  bool found = false;
 
1064
  GraphicsMode gfxmode;
 
1065
  for(uInt32 i = 0; i < GFX_NumModes; ++i)
 
1066
  {
 
1067
    if(ourGraphicsModes[i].type == id)
 
1068
    {
 
1069
      gfxmode = ourGraphicsModes[i];
 
1070
      found = true;
 
1071
      break;
 
1072
    }
 
1073
  }
 
1074
  if(!found) gfxmode = ourGraphicsModes[0];
 
1075
 
 
1076
  // Now we scan the list for the applicable video mode
 
1077
  set(gfxmode);
 
1078
}
 
1079
 
 
1080
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1081
void FrameBuffer::VideoModeList::setByGfxMode(const string& name)
 
1082
{
 
1083
  // First we determine which graphics mode is being requested
 
1084
  bool found = false;
 
1085
  GraphicsMode gfxmode;
 
1086
  for(uInt32 i = 0; i < GFX_NumModes; ++i)
 
1087
  {
 
1088
    if(ourGraphicsModes[i].name == BSPF_tolower(name) ||
 
1089
       ourGraphicsModes[i].description == BSPF_tolower(name))
 
1090
    {
 
1091
      gfxmode = ourGraphicsModes[i];
 
1092
      found = true;
 
1093
      break;
 
1094
    }
 
1095
  }
 
1096
  if(!found) gfxmode = ourGraphicsModes[0];
 
1097
 
 
1098
  // Now we scan the list for the applicable video mode
 
1099
  set(gfxmode);
 
1100
}
 
1101
 
 
1102
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1103
void FrameBuffer::VideoModeList::set(const GraphicsMode& gfxmode)
 
1104
{
 
1105
  // Attempt to point the current mode to the one given
 
1106
  myIdx = -1;
 
1107
 
 
1108
  // First search for the given gfx id
 
1109
  for(unsigned int i = 0; i < myModeList.size(); ++i)
 
1110
  {
 
1111
    if(myModeList[i].gfxmode.type == gfxmode.type)
 
1112
    {
 
1113
      myIdx = i;
 
1114
      return;
 
1115
    }
 
1116
  }
 
1117
 
 
1118
  // If we get here, then the gfx type couldn't be found, so we search
 
1119
  // for the first mode with the same zoomlevel (making sure that the
 
1120
  // requested mode can fit inside the current screen)
 
1121
  if(gfxmode.zoom > myModeList[myModeList.size()-1].gfxmode.zoom)
 
1122
  {
 
1123
    myIdx = myModeList.size()-1;
 
1124
    return;
 
1125
  }
 
1126
  else
 
1127
  {
 
1128
    for(unsigned int i = 0; i < myModeList.size(); ++i)
 
1129
    {
 
1130
      if(myModeList[i].gfxmode.zoom == gfxmode.zoom)
 
1131
      {
 
1132
        myIdx = i;
 
1133
        return;
 
1134
      }
 
1135
    }
 
1136
  }
 
1137
 
 
1138
  // Finally, just pick the lowest video mode
 
1139
  myIdx = 0;
 
1140
}
 
1141
 
 
1142
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1143
void FrameBuffer::VideoModeList::print()
 
1144
{
 
1145
  cerr << "VideoModeList: " << endl << endl;
 
1146
  for(Common::Array<VideoMode>::const_iterator i = myModeList.begin();
 
1147
      i != myModeList.end(); ++i)
 
1148
  {
 
1149
    cerr << "  Mode " << i << endl
 
1150
         << "    screen w = " << i->screen_w << endl
 
1151
         << "    screen h = " << i->screen_h << endl
 
1152
         << "    image x  = " << i->image_x << endl
 
1153
         << "    image y  = " << i->image_y << endl
 
1154
         << "    image w  = " << i->image_w << endl
 
1155
         << "    image h  = " << i->image_h << endl
 
1156
         << "    gfx id   = " << i->gfxmode.type << endl
 
1157
         << "    gfx name = " << i->gfxmode.name << endl
 
1158
         << "    gfx desc = " << i->gfxmode.description << endl
 
1159
         << "    gfx zoom = " << i->gfxmode.zoom << endl
 
1160
         << endl;
 
1161
  }
 
1162
}
 
1163
 
 
1164
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
 
1165
void FBSurface::box(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
 
1166
                    uInt32 colorA, uInt32 colorB)
584
1167
{
585
1168
  hLine(x + 1, y,     x + w - 2, colorA);
586
1169
  hLine(x,     y + 1, x + w - 1, colorA);
594
1177
}
595
1178
 
596
1179
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
597
 
void FrameBuffer::frameRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
598
 
                            int color, FrameStyle style)
 
1180
void FBSurface::frameRect(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
 
1181
                          uInt32 color, FrameStyle style)
599
1182
{
600
1183
  switch(style)
601
1184
  {
630
1213
}
631
1214
 
632
1215
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
633
 
void FrameBuffer::drawString(const GUI::Font* font, const string& s,
634
 
                             int x, int y, int w,
635
 
                             int color, TextAlignment align,
636
 
                             int deltax, bool useEllipsis)
 
1216
void FBSurface::drawString(const GUI::Font* font, const string& s,
 
1217
                           int x, int y, int w,
 
1218
                           uInt32 color, TextAlignment align,
 
1219
                           int deltax, bool useEllipsis)
637
1220
{
638
1221
  const int leftX = x, rightX = x + w;
639
1222
  unsigned int i;
706
1289
}
707
1290
 
708
1291
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
709
 
uInt8 FrameBuffer::getPhosphor(uInt8 c1, uInt8 c2)
710
 
{
711
 
  if(c2 > c1)
712
 
    BSPF_swap(c1, c2);
713
 
 
714
 
  return ((c1 - c2) * myPhosphorBlend)/100 + c2;
715
 
}
716
 
 
717
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
718
 
uInt32 FrameBuffer::maxWindowSizeForScreen(uInt32 screenWidth, uInt32 screenHeight)
719
 
{
720
 
  uInt32 multiplier = 1;
721
 
  for(;;)
722
 
  {
723
 
    // Figure out the zoomed size of the window
724
 
    uInt32 width  = myBaseDim.w * multiplier;
725
 
    uInt32 height = myBaseDim.h * multiplier;
726
 
 
727
 
    if((width > screenWidth) || (height > screenHeight))
728
 
      break;
729
 
 
730
 
    ++multiplier;
731
 
  }
732
 
  return multiplier > 1 ? multiplier - 1 : 1;
733
 
}
734
 
 
735
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
736
 
void FrameBuffer::setAvailableVidModes()
737
 
{
738
 
  // First we look at windowed modes
739
 
  // These can be sized exactly as required, since there's normally no
740
 
  // restriction on window size (up the maximum size)
741
 
  myWindowedModeList.clear();
742
 
  int max_zoom = maxWindowSizeForScreen(myOSystem->desktopWidth(),
743
 
                                        myOSystem->desktopHeight());
744
 
  for(int i = 1; i <= max_zoom; ++i)
745
 
  {
746
 
    VideoMode m;
747
 
    m.image_x = m.image_y = 0;
748
 
    m.image_w = m.screen_w = myBaseDim.w * i;
749
 
    m.image_h = m.screen_h = myBaseDim.h * i;
750
 
    m.zoom = i;
751
 
    ostringstream buf;
752
 
    buf << "Zoom " << i << "x";
753
 
    m.name = buf.str();
754
 
 
755
 
    myWindowedModeList.add(m);
756
 
  }
757
 
 
758
 
  // Now consider the fullscreen modes
759
 
  // There are often stricter requirements on these, and they're normally
760
 
  // different depending on the OSystem in use
761
 
  // As well, we usually can't get fullscreen modes in the exact size
762
 
  // we want, so we need to calculate image offsets
763
 
  myFullscreenModeList.clear();
764
 
  const ResolutionList& res = myOSystem->supportedResolutions();
765
 
  for(unsigned int i = 0; i < res.size(); ++i)
766
 
  {
767
 
    VideoMode m;
768
 
    m.screen_w = res[i].width;
769
 
    m.screen_h = res[i].height;
770
 
    m.zoom = maxWindowSizeForScreen(m.screen_w, m.screen_h);
771
 
    m.name = res[i].name;
772
 
 
773
 
    // Auto-calculate 'smart' centering; platform-specific framebuffers are
774
 
    // free to ignore or augment it
775
 
    m.image_w = myBaseDim.w * m.zoom;
776
 
    m.image_h = myBaseDim.h * m.zoom;
777
 
    m.image_x = (m.screen_w - m.image_w) / 2;
778
 
    m.image_y = (m.screen_h - m.image_h) / 2;
779
 
 
780
 
/*
781
 
cerr << "Fullscreen modes:" << endl
782
 
        << "  Mode " << i << endl
783
 
        << "    screen w = " << m.screen_w << endl
784
 
        << "    screen h = " << m.screen_h << endl
785
 
        << "    image x  = " << m.image_x << endl
786
 
        << "    image y  = " << m.image_y << endl
787
 
        << "    image w  = " << m.image_w << endl
788
 
        << "    image h  = " << m.image_h << endl
789
 
        << "    zoom     = " << m.zoom << endl
790
 
        << endl;
791
 
*/
792
 
    myFullscreenModeList.add(m);
793
 
  }
794
 
}
795
 
 
796
 
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
797
 
VideoMode FrameBuffer::getSavedVidMode()
798
 
{
799
 
  EventHandler::State state = myOSystem->eventHandler().state();
800
 
 
801
 
  if(myOSystem->settings().getBool("fullscreen"))
802
 
  {
803
 
    // Point the modelist to fullscreen modes, and set the iterator to
804
 
    // the mode closest to the given resolution
805
 
    int w = -1, h = -1;
806
 
    myOSystem->settings().getSize("fullres", w, h);
807
 
    if(w < 0 || h < 0)
808
 
    {
809
 
      w = myOSystem->desktopWidth();
810
 
      h = myOSystem->desktopHeight();
811
 
    }
812
 
 
813
 
    // The launcher and debugger modes are different, in that their size is
814
 
    // set at program launch and can't be changed
815
 
    // In these cases, the resolution must accommodate their size
816
 
    if(state == EventHandler::S_LAUNCHER)
817
 
    {
818
 
      int lw, lh;
819
 
      myOSystem->settings().getSize("launcherres", lw, lh);
820
 
      w = BSPF_max(w, lw);
821
 
      h = BSPF_max(h, lh);
822
 
    }
823
 
#ifdef DEBUGGER_SUPPORT
824
 
    else if(state == EventHandler::S_DEBUGGER)
825
 
    {
826
 
      int lw, lh;
827
 
      myOSystem->settings().getSize("debuggerres", lw, lh);
828
 
      w = BSPF_max(w, lw);
829
 
      h = BSPF_max(h, lh);
830
 
    }
831
 
#endif
832
 
 
833
 
    myCurrentModeList = &myFullscreenModeList;
834
 
    myCurrentModeList->setByResolution(w, h);
835
 
  }
836
 
  else
837
 
  {
838
 
    // Point the modelist to windowed modes, and set the iterator to
839
 
    // the mode closest to the given zoom level
840
 
    bool inTIAMode = (state == EventHandler::S_EMULATE ||
841
 
                      state == EventHandler::S_PAUSE   ||
842
 
                      state == EventHandler::S_MENU    ||
843
 
                      state == EventHandler::S_CMDMENU);
844
 
    int zoom = (inTIAMode ? myOSystem->settings().getInt("zoom_tia") :
845
 
                            myOSystem->settings().getInt("zoom_ui") );
846
 
 
847
 
    myCurrentModeList = &myWindowedModeList;
848
 
    myCurrentModeList->setByZoom(zoom);
849
 
  }
850
 
 
851
 
  return myCurrentModeList->current();
852
 
}
 
1292
FrameBuffer::GraphicsMode FrameBuffer::ourGraphicsModes[GFX_NumModes] = {
 
1293
  { GFX_Zoom1x,  "zoom1x",  "Zoom 1x",  1,  0x3 },
 
1294
  { GFX_Zoom2x,  "zoom2x",  "Zoom 2x",  2,  0x3 },
 
1295
  { GFX_Zoom3x,  "zoom3x",  "Zoom 3x",  3,  0x3 },
 
1296
  { GFX_Zoom4x,  "zoom4x",  "Zoom 4x",  4,  0x3 },
 
1297
  { GFX_Zoom5x,  "zoom5x",  "Zoom 5x",  5,  0x3 },
 
1298
  { GFX_Zoom6x,  "zoom6x",  "Zoom 6x",  6,  0x3 },
 
1299
  { GFX_Zoom7x,  "zoom7x",  "Zoom 7x",  7,  0x3 },
 
1300
  { GFX_Zoom8x,  "zoom8x",  "Zoom 8x",  8,  0x3 },
 
1301
  { GFX_Zoom9x,  "zoom9x",  "Zoom 9x",  9,  0x3 },
 
1302
  { GFX_Zoom10x, "zoom10x", "Zoom 10x", 10, 0x3 }
 
1303
};