41
43
FrameBuffer::FrameBuffer(OSystem* osystem)
42
44
: myOSystem(osystem),
44
theRedrawTIAIndicator(true),
46
myRedrawEntireFrame(true),
45
47
myUsePhosphor(false),
46
48
myPhosphorBlend(77),
47
49
myInitializedCount(0),
49
myFrameStatsEnabled(false)
52
myMsg.surface = myStatsMsg.surface = NULL;
53
myMsg.surfaceID = myStatsMsg.surfaceID = -1;
54
myMsg.enabled = myStatsMsg.enabled = false;
53
57
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
54
58
FrameBuffer::~FrameBuffer(void)
60
// Free all allocated surfaces
61
while(!mySurfaceList.empty())
63
delete (*mySurfaceList.begin()).second;
64
mySurfaceList.erase(mySurfaceList.begin());
58
68
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
59
void FrameBuffer::initialize(const string& title, uInt32 width, uInt32 height)
69
bool FrameBuffer::initialize(const string& title, uInt32 width, uInt32 height)
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)
64
77
if(SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
79
buf << "ERROR: Couldn't initialize SDL: " << SDL_GetError() << endl;
80
myOSystem->logMessage(buf.str(), 0);
67
84
myInitializedCount++;
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)
73
// Set fullscreen flag
74
#ifdef WINDOWED_SUPPORT
75
mySDLFlags = myOSystem->settings().getBool("fullscreen") ? SDL_FULLSCREEN : 0;
94
// Initialize SDL flags and set fullscreen flag
95
// This must be done before any modes are initialized
97
#ifdef WINDOWED_SUPPORT
98
if(myOSystem->settings().getString("fullscreen") == "1") mySDLFlags = SDL_FULLSCREEN;
80
101
// Set the available video modes for this framebuffer
81
setAvailableVidModes();
83
// Set window title and icon
84
setWindowTitle(title);
85
if(myInitializedCount == 1) setWindowIcon();
87
// Initialize video subsystem
102
setAvailableVidModes(width, height);
104
// Initialize video subsystem (make sure we get a valid mode)
88
105
VideoMode mode = getSavedVidMode();
91
// And refresh the display
92
myOSystem->eventHandler().refreshDisplay();
106
if(width <= mode.screen_w && height <= mode.screen_h)
108
// Set window title and icon
109
setWindowTitle(title);
110
if(myInitializedCount == 1) setWindowIcon();
112
if(!initSubsystem(mode))
114
myOSystem->logMessage("ERROR: Couldn't initialize video subsystem\n", 0);
119
myImageRect.setWidth(mode.image_w);
120
myImageRect.setHeight(mode.image_h);
121
myImageRect.moveTo(mode.image_x, mode.image_y);
123
myScreenRect.setWidth(mode.screen_w);
124
myScreenRect.setHeight(mode.screen_h);
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");
94
136
// Enable unicode so we can see translated key events
95
137
// (lowercase vs. uppercase characters)
96
138
SDL_EnableUNICODE(1);
98
140
// Erase any messages from a previous run
99
myMessage.counter = 0;
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;
148
if(myStatsMsg.surface == NULL)
150
myStatsMsg.surfaceID = allocateSurface(myStatsMsg.w, myStatsMsg.h);
151
myStatsMsg.surface = surface(myStatsMsg.surfaceID);
153
if(myMsg.surface == NULL)
155
myMsg.surfaceID = allocateSurface(500, myOSystem->font().getFontHeight()+10);
156
myMsg.surface = surface(myMsg.surfaceID);
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);
107
167
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
108
168
void FrameBuffer::update()
110
// Do any pre-frame stuff
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:
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;
122
184
if(myOSystem->eventHandler().frying())
123
185
myOSystem->console().fry();
125
187
// And update the screen
188
drawTIA(myRedrawEntireFrame);
128
190
// Show frame statistics
129
if(myFrameStatsEnabled)
191
if(myStatsMsg.enabled)
131
// FIXME - sizes hardcoded for now; fix during UI refactoring
193
const ConsoleInfo& info = myOSystem->console().about();
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();
140
207
break; // S_EMULATE
143
210
case EventHandler::S_PAUSE:
145
212
// Only update the screen if it's been invalidated
146
if(theRedrawTIAIndicator)
213
if(myRedrawEntireFrame)
149
216
// Show a pause message every 5 seconds
150
217
if(myPausedCount++ >= 7*myOSystem->frameRate())
197
264
// Draw any pending messages
198
if(myMessage.counter > 0)
201
268
// Do any post-frame stuff
202
269
postFrameUpdate();
204
271
// The frame doesn't need to be completely redrawn anymore
205
theRedrawTIAIndicator = false;
272
myRedrawEntireFrame = false;
208
275
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
209
276
void FrameBuffer::showMessage(const string& message, MessagePosition position,
277
bool force, uInt32 color)
279
// Only show messages if they've been enabled
280
if(!(force || myOSystem->settings().getBool("uimessages")))
212
283
// Erase old messages on the screen
213
if(myMessage.counter > 0)
284
if(myMsg.counter > 0)
215
theRedrawTIAIndicator = true;
216
myOSystem->eventHandler().refreshDisplay();
286
myRedrawEntireFrame = true;
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;
224
myMessage.w = myOSystem->font().getStringWidth(myMessage.text) + 10;
225
myMessage.h = myOSystem->font().getFontHeight() + 8;
291
myMsg.text = message;
292
myMsg.counter = uInt32(myOSystem->frameRate()) << 1; // Show message for 2 seconds
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;
303
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
304
void FrameBuffer::toggleFrameStats()
306
showFrameStats(!myOSystem->settings().getBool("stats"));
309
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
310
void FrameBuffer::showFrameStats(bool enable)
312
myOSystem->settings().setBool("stats", enable);
313
myStatsMsg.enabled = enable;
317
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
318
void FrameBuffer::enableMessages(bool enable)
322
// Only re-enable frame stats if they were already enabled before
323
myStatsMsg.enabled = myOSystem->settings().getBool("stats");
327
// Temporarily disable frame stats
328
myStatsMsg.enabled = false;
330
// Erase old messages on the screen
331
myMsg.enabled = false;
338
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
339
inline void FrameBuffer::drawMessage()
341
// Draw the bounded box and text
342
switch(myMsg.position)
235
myMessage.x = (myBaseDim.w >> 1) - (myMessage.w >> 1);
350
myMsg.x = (myImageRect.width() - myMsg.w) >> 1;
240
myMessage.x = myBaseDim.w - myMessage.w - 5;
355
myMsg.x = myImageRect.width() - myMsg.w - 5;
244
359
case kMiddleLeft:
246
myMessage.y = (myBaseDim.h >> 1) - (myMessage.h >> 1);
361
myMsg.y = (myImageRect.height() - myMsg.h) >> 1;
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;
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;
259
374
case kBottomLeft:
260
myMessage.x = 5;//(myMessage.w >> 1);
261
myMessage.y = myBaseDim.h - myMessage.h - 5;
376
myMsg.y = myImageRect.height() - myMsg.h - 5;
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;
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;
276
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
277
void FrameBuffer::toggleFrameStats()
279
showFrameStats(!myOSystem->settings().getBool("stats"));
282
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
283
void FrameBuffer::showFrameStats(bool enable)
285
myOSystem->settings().setBool("stats", enable);
286
myFrameStatsEnabled = enable;
287
myOSystem->eventHandler().refreshDisplay();
290
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
291
void FrameBuffer::enableMessages(bool enable)
295
// Only re-anable frame stats if they were already enabled before
296
myFrameStatsEnabled = myOSystem->settings().getBool("stats");
300
// Temporarily disable frame stats
301
myFrameStatsEnabled = false;
303
// Erase old messages on the screen
304
myMessage.counter = 0;
306
myOSystem->eventHandler().refreshDisplay(true); // Do this twice for
307
myOSystem->eventHandler().refreshDisplay(true); // double-buffered modes
311
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
312
inline void FrameBuffer::drawMessage()
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);
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);
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
401
myMsg.enabled = false;
326
addDirtyRect(myMessage.x, myMessage.y, myMessage.w, myMessage.h);
406
myMsg.surface->addDirtyRect(0, 0, 0, 0);
407
myMsg.surface->update();
329
411
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
330
412
void FrameBuffer::refresh()
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
420
// This method is in essence a FULL refresh, putting all rendering
421
// buffers in a known, fully redrawn state
424
bool doubleBuffered = (type() == kGLBuffer);
425
switch(myOSystem->eventHandler().state())
427
case EventHandler::S_EMULATE:
428
case EventHandler::S_PAUSE:
434
case EventHandler::S_MENU:
436
myOSystem->menu().draw(true);
441
myOSystem->menu().draw(true);
445
case EventHandler::S_CMDMENU:
447
myOSystem->commandMenu().draw(true);
452
myOSystem->commandMenu().draw(true);
456
case EventHandler::S_LAUNCHER:
457
myOSystem->launcher().draw(true);
461
myOSystem->launcher().draw(true);
465
#ifdef DEBUGGER_SUPPORT
466
case EventHandler::S_DEBUGGER:
467
myOSystem->debugger().draw(true);
471
myOSystem->debugger().draw(true);
481
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
482
int FrameBuffer::allocateSurface(int w, int h, bool useBase)
484
// Create a new surface
485
FBSurface* surface = createSurface(w, h, useBase);
487
// Add it to the list
488
mySurfaceList.insert(make_pair(int(mySurfaceList.size()), surface));
490
// Return a reference to it
491
return mySurfaceList.size() - 1;
494
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
495
FBSurface* FrameBuffer::surface(int id) const
497
map<int,FBSurface*>::const_iterator iter = mySurfaceList.find(id);
498
return iter != mySurfaceList.end() ? iter->second : NULL;
501
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
502
void FrameBuffer::resetSurfaces()
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
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();
517
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
518
uInt32 FrameBuffer::tiaPixel(uInt32 idx, uInt8 shift) const
520
uInt8 c = *(myOSystem->console().tia().currentFrameBuffer() + idx) | shift;
521
uInt8 p = *(myOSystem->console().tia().previousFrameBuffer() + idx) | shift;
523
return (!myUsePhosphor ? myDefPalette[c] : myAvgPalette[c][p]);
335
526
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
413
638
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
414
639
bool FrameBuffer::changeVidMode(int direction)
416
bool saveModeChange = true;
418
VideoMode oldmode = myCurrentModeList->current();
641
EventHandler::State state = myOSystem->eventHandler().state();
642
bool inUIMode = (state == EventHandler::S_DEBUGGER ||
643
state == EventHandler::S_LAUNCHER);
645
// Ignore any attempts to change video size while in UI mode
646
if(inUIMode && direction != 0)
649
// Only save mode changes in TIA mode with a valid selector
650
bool saveModeChange = !inUIMode && (direction == -1 || direction == +1);
419
652
if(direction == +1)
420
653
myCurrentModeList->next();
421
654
else if(direction == -1)
422
655
myCurrentModeList->previous();
657
VideoMode vidmode = myCurrentModeList->current(myOSystem->settings(), fullScreen());
658
if(setVidMode(vidmode))
660
myImageRect.setWidth(vidmode.image_w);
661
myImageRect.setHeight(vidmode.image_h);
662
myImageRect.moveTo(vidmode.image_x, vidmode.image_y);
664
myScreenRect.setWidth(vidmode.screen_w);
665
myScreenRect.setHeight(vidmode.screen_h);
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");
675
if(direction != 0) // only show message when mode actually changes
676
showMessage(vidmode.gfxmode.description);
679
myOSystem->settings().setString("tia_filter", vidmode.gfxmode.name);
424
saveModeChange = false; // no resolution or zoom level actually changed
426
VideoMode newmode = myCurrentModeList->current();
427
if(!setVidMode(newmode))
430
myOSystem->eventHandler().handleResizeEvent();
431
myOSystem->eventHandler().refreshDisplay(true);
433
showMessage(newmode.name);
437
// Determine which mode we're in, and save to the appropriate setting
440
myOSystem->settings().setSize("fullres", newmode.screen_w, newmode.screen_h);
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);
451
myOSystem->settings().setInt("zoom_tia", newmode.zoom);
453
myOSystem->settings().setInt("zoom_ui", newmode.zoom);
458
688
cerr << "New mode:" << endl
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)
816
return ((c1 - c2) * myPhosphorBlend)/100 + c2;
819
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
820
const StringMap& FrameBuffer::supportedTIAFilters(const string& type)
822
uInt32 max_zoom = maxWindowSizeForScreen(320, 210,
823
myOSystem->desktopWidth(), myOSystem->desktopHeight());
824
uInt8 mask = (type == "soft" ? 0x1 : 0x2);
826
uInt32 firstmode = 1;
827
if(myOSystem->desktopWidth() < 640 || myOSystem->desktopHeight() < 480)
830
myTIAFilters.clear();
831
for(uInt32 i = firstmode; i < GFX_NumModes; ++i)
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)
837
myTIAFilters.push_back(ourGraphicsModes[i].description,
838
ourGraphicsModes[i].name);
844
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
845
uInt32 FrameBuffer::maxWindowSizeForScreen(uInt32 baseWidth, uInt32 baseHeight,
846
uInt32 screenWidth, uInt32 screenHeight)
848
uInt32 multiplier = 1;
851
// Figure out the zoomed size of the window
852
uInt32 width = baseWidth * multiplier;
853
uInt32 height = baseHeight * multiplier;
855
if((width > screenWidth) || (height > screenHeight))
860
return multiplier > 1 ? multiplier - 1 : 1;
863
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
864
void FrameBuffer::setAvailableVidModes(uInt32 baseWidth, uInt32 baseHeight)
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);
871
myWindowedModeList.clear();
872
myFullscreenModeList.clear();
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
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
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());
894
// Figure our the smallest zoom level we can use
895
uInt32 firstmode = 1;
896
if(myOSystem->desktopWidth() < 640 || myOSystem->desktopHeight() < 480)
899
for(uInt32 i = firstmode; i < GFX_NumModes; ++i)
901
uInt32 zoom = ourGraphicsModes[i].zoom;
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];
916
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
917
void FrameBuffer::addVidMode(VideoMode& mode)
919
// The are minimum size requirements on a screen, no matter is in fullscreen
921
// Various part of the UI system depend on having at least 320x240 pixels
922
// available, so we must enforce it here
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);
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)
939
if(mode.screen_w <= res[i].width && mode.screen_h <= res[i].height)
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;
950
myFullscreenModeList.add(mode);
953
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
954
FrameBuffer::VideoMode FrameBuffer::getSavedVidMode()
956
EventHandler::State state = myOSystem->eventHandler().state();
959
myCurrentModeList = &myFullscreenModeList;
961
myCurrentModeList = &myWindowedModeList;
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)
968
myCurrentModeList->setByGfxMode(GFX_Zoom1x);
972
const string& name = myOSystem->settings().getString("tia_filter");
973
myCurrentModeList->setByGfxMode(name);
976
return myCurrentModeList->current(myOSystem->settings(), fullScreen());
979
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
980
FrameBuffer::VideoModeList::VideoModeList()
985
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
986
FrameBuffer::VideoModeList::~VideoModeList()
991
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
992
void FrameBuffer::VideoModeList::add(VideoMode mode)
994
myModeList.push_back(mode);
997
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
998
void FrameBuffer::VideoModeList::clear()
1003
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1004
bool FrameBuffer::VideoModeList::isEmpty() const
1006
return myModeList.isEmpty();
1009
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1010
uInt32 FrameBuffer::VideoModeList::size() const
1012
return myModeList.size();
1015
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1016
void FrameBuffer::VideoModeList::previous()
1019
if(myIdx < 0) myIdx = myModeList.size() - 1;
1022
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1023
const FrameBuffer::VideoMode FrameBuffer::
1024
VideoModeList::current(const Settings& settings, bool isFullscreen) const
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")
1032
// Only use 'fullres' if it's *bigger* than the requested mode
1034
settings.getSize("fullres", w, h);
1036
if(w != -1 && h != -1 && (uInt32)w >= myModeList[myIdx].screen_w &&
1037
(uInt32)h >= myModeList[myIdx].screen_h)
1039
VideoMode mode = myModeList[myIdx];
1042
mode.image_x = (mode.screen_w - mode.image_w) >> 1;
1043
mode.image_y = (mode.screen_h - mode.image_h) >> 1;
1049
// Otherwise, we just use the mode has it was defined in ::addVidMode()
1050
return myModeList[myIdx];
1053
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1054
void FrameBuffer::VideoModeList::next()
1056
myIdx = (myIdx + 1) % myModeList.size();
1059
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1060
void FrameBuffer::VideoModeList::setByGfxMode(GfxID id)
1062
// First we determine which graphics mode is being requested
1064
GraphicsMode gfxmode;
1065
for(uInt32 i = 0; i < GFX_NumModes; ++i)
1067
if(ourGraphicsModes[i].type == id)
1069
gfxmode = ourGraphicsModes[i];
1074
if(!found) gfxmode = ourGraphicsModes[0];
1076
// Now we scan the list for the applicable video mode
1080
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1081
void FrameBuffer::VideoModeList::setByGfxMode(const string& name)
1083
// First we determine which graphics mode is being requested
1085
GraphicsMode gfxmode;
1086
for(uInt32 i = 0; i < GFX_NumModes; ++i)
1088
if(ourGraphicsModes[i].name == BSPF_tolower(name) ||
1089
ourGraphicsModes[i].description == BSPF_tolower(name))
1091
gfxmode = ourGraphicsModes[i];
1096
if(!found) gfxmode = ourGraphicsModes[0];
1098
// Now we scan the list for the applicable video mode
1102
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1103
void FrameBuffer::VideoModeList::set(const GraphicsMode& gfxmode)
1105
// Attempt to point the current mode to the one given
1108
// First search for the given gfx id
1109
for(unsigned int i = 0; i < myModeList.size(); ++i)
1111
if(myModeList[i].gfxmode.type == gfxmode.type)
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)
1123
myIdx = myModeList.size()-1;
1128
for(unsigned int i = 0; i < myModeList.size(); ++i)
1130
if(myModeList[i].gfxmode.zoom == gfxmode.zoom)
1138
// Finally, just pick the lowest video mode
1142
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1143
void FrameBuffer::VideoModeList::print()
1145
cerr << "VideoModeList: " << endl << endl;
1146
for(Common::Array<VideoMode>::const_iterator i = myModeList.begin();
1147
i != myModeList.end(); ++i)
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
1164
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
1165
void FBSurface::box(uInt32 x, uInt32 y, uInt32 w, uInt32 h,
1166
uInt32 colorA, uInt32 colorB)
585
1168
hLine(x + 1, y, x + w - 2, colorA);
586
1169
hLine(x, y + 1, x + w - 1, colorA);
708
1291
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
709
uInt8 FrameBuffer::getPhosphor(uInt8 c1, uInt8 c2)
714
return ((c1 - c2) * myPhosphorBlend)/100 + c2;
717
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
718
uInt32 FrameBuffer::maxWindowSizeForScreen(uInt32 screenWidth, uInt32 screenHeight)
720
uInt32 multiplier = 1;
723
// Figure out the zoomed size of the window
724
uInt32 width = myBaseDim.w * multiplier;
725
uInt32 height = myBaseDim.h * multiplier;
727
if((width > screenWidth) || (height > screenHeight))
732
return multiplier > 1 ? multiplier - 1 : 1;
735
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
736
void FrameBuffer::setAvailableVidModes()
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)
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;
752
buf << "Zoom " << i << "x";
755
myWindowedModeList.add(m);
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)
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;
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;
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
792
myFullscreenModeList.add(m);
796
// - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
797
VideoMode FrameBuffer::getSavedVidMode()
799
EventHandler::State state = myOSystem->eventHandler().state();
801
if(myOSystem->settings().getBool("fullscreen"))
803
// Point the modelist to fullscreen modes, and set the iterator to
804
// the mode closest to the given resolution
806
myOSystem->settings().getSize("fullres", w, h);
809
w = myOSystem->desktopWidth();
810
h = myOSystem->desktopHeight();
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)
819
myOSystem->settings().getSize("launcherres", lw, lh);
823
#ifdef DEBUGGER_SUPPORT
824
else if(state == EventHandler::S_DEBUGGER)
827
myOSystem->settings().getSize("debuggerres", lw, lh);
833
myCurrentModeList = &myFullscreenModeList;
834
myCurrentModeList->setByResolution(w, h);
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") );
847
myCurrentModeList = &myWindowedModeList;
848
myCurrentModeList->setByZoom(zoom);
851
return myCurrentModeList->current();
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 }