1 //=============================================================================
2 //
3 // Adventure Game Studio (AGS)
4 //
5 // Copyright (C) 1999-2011 Chris Jones and 2011-20xx others
6 // The full list of copyright holders can be found in the Copyright.txt
7 // file, which is part of this source code distribution.
8 //
9 // The AGS source code is provided under the Artistic License 2.0.
10 // A copy of this license can be found in the file License.txt and at
11 // http://www.opensource.org/licenses/artistic-license-2.0.php
12 //
13 //=============================================================================
14
15 //
16 // Graphics initialization
17 //
18
19 #include <algorithm>
20 #include "ac/draw.h"
21 #include "debug/debugger.h"
22 #include "debug/out.h"
23 #include "gfx/ali3dexception.h"
24 #include "gfx/bitmap.h"
25 #include "gfx/gfxdriverfactory.h"
26 #include "gfx/gfxfilter.h"
27 #include "gfx/graphicsdriver.h"
28 #include "main/config.h"
29 #include "main/engine_setup.h"
30 #include "main/graphics_mode.h"
31 #include "main/main_allegro.h"
32 #include "platform/base/agsplatformdriver.h"
33
34 // Don't try to figure out the window size on the mac because the port resizes itself.
35 #if defined(MAC_VERSION) || defined(ALLEGRO_SDL2) || defined(IOS_VERSION) || defined(PSP_VERSION) || defined(ANDROID_VERSION)
36 #define USE_SIMPLE_GFX_INIT
37 #endif
38
39 using namespace AGS::Common;
40 using namespace AGS::Engine;
41
42 extern int proper_exit;
43 extern AGSPlatformDriver *platform;
44 extern IGraphicsDriver *gfxDriver;
45 extern volatile int timerloop;
46
47
48 IGfxDriverFactory *GfxFactory = NULL;
49
50 // Last saved fullscreen and windowed configs; they are used when switching
51 // between between fullscreen and windowed modes at runtime.
52 // If particular mode is modified, e.g. by script command, related config should be overwritten.
53 ActiveDisplaySetting SavedFullscreenSetting;
54 ActiveDisplaySetting SavedWindowedSetting;
55 // Current frame scaling setup
56 GameFrameSetup CurFrameSetup;
57 // The game-to-screen transformation
58 PlaneScaling GameScaling;
59
60
GameFrameSetup()61 GameFrameSetup::GameFrameSetup()
62 : ScaleDef(kFrame_IntScale)
63 , ScaleFactor(1)
64 {
65 }
66
GameFrameSetup(FrameScaleDefinition def,int factor)67 GameFrameSetup::GameFrameSetup(FrameScaleDefinition def, int factor)
68 : ScaleDef(def)
69 , ScaleFactor(factor)
70 {
71 }
72
IsValid() const73 bool GameFrameSetup::IsValid() const
74 {
75 return ScaleDef != kFrame_IntScale || ScaleFactor > 0;
76 }
77
DisplayModeSetup()78 DisplayModeSetup::DisplayModeSetup()
79 : RefreshRate(0)
80 , VSync(false)
81 , Windowed(false)
82 {
83 }
84
85
get_desktop_size()86 Size get_desktop_size()
87 {
88 Size sz;
89 get_desktop_resolution(&sz.Width, &sz.Height);
90 return sz;
91 }
92
get_max_display_size(bool windowed)93 Size get_max_display_size(bool windowed)
94 {
95 Size device_size = get_desktop_size();
96 if (windowed)
97 platform->ValidateWindowSize(device_size.Width, device_size.Height, false);
98 return device_size;
99 }
100
create_gfx_driver(const String & gfx_driver_id)101 bool create_gfx_driver(const String &gfx_driver_id)
102 {
103 GfxFactory = GetGfxDriverFactory(gfx_driver_id);
104 if (!GfxFactory)
105 {
106 Debug::Printf(kDbgMsg_Error, "Failed to initialize %s graphics factory. Error: %s", gfx_driver_id.GetCStr(), get_allegro_error());
107 return false;
108 }
109 Debug::Printf("Using graphics factory: %s", gfx_driver_id.GetCStr());
110 gfxDriver = GfxFactory->GetDriver();
111 if (!gfxDriver)
112 {
113 Debug::Printf(kDbgMsg_Error, "Failed to create graphics driver. Error: %s", get_allegro_error());
114 return false;
115 }
116 Debug::Printf("Created graphics driver: %s", gfxDriver->GetDriverName());
117 return true;
118 }
119
120 // Set requested graphics filter, or default filter if the requested one failed
graphics_mode_set_filter_any(const GfxFilterSetup & setup)121 bool graphics_mode_set_filter_any(const GfxFilterSetup &setup)
122 {
123 Debug::Printf("Requested gfx filter: %s", setup.UserRequest.GetCStr());
124 if (!graphics_mode_set_filter(setup.ID))
125 {
126 String def_filter = GfxFactory->GetDefaultFilterID();
127 if (def_filter.CompareNoCase(setup.ID) == 0)
128 return false;
129 Debug::Printf(kDbgMsg_Error, "Failed to apply gfx filter: %s; will try to use factory default filter '%s' instead",
130 setup.UserRequest.GetCStr(), def_filter.GetCStr());
131 if (!graphics_mode_set_filter(def_filter))
132 return false;
133 }
134 Debug::Printf("Using gfx filter: %s", GfxFactory->GetDriver()->GetGraphicsFilter()->GetInfo().Id.GetCStr());
135 return true;
136 }
137
find_nearest_supported_mode(const IGfxModeList & modes,const Size & wanted_size,const int color_depth,const Size * ratio_reference,const Size * upper_bound,DisplayMode & dm,int * mode_index)138 bool find_nearest_supported_mode(const IGfxModeList &modes, const Size &wanted_size, const int color_depth,
139 const Size *ratio_reference, const Size *upper_bound, DisplayMode &dm, int *mode_index)
140 {
141 uint32_t wanted_ratio = 0;
142 if (ratio_reference && !ratio_reference->IsNull())
143 {
144 wanted_ratio = (ratio_reference->Height << kShift) / ratio_reference->Width;
145 }
146
147 int nearest_width = 0;
148 int nearest_height = 0;
149 int nearest_width_diff = 0;
150 int nearest_height_diff = 0;
151 int nearest_mode_index = -1;
152 int mode_count = modes.GetModeCount();
153 DisplayMode mode;
154 for (int i = 0; i < mode_count; ++i)
155 {
156 if (!modes.GetMode(i, mode))
157 {
158 continue;
159 }
160 if (mode.ColorDepth != color_depth)
161 {
162 continue;
163 }
164 if (wanted_ratio > 0)
165 {
166 uint32_t mode_ratio = (mode.Height << kShift) / mode.Width;
167 if (mode_ratio != wanted_ratio)
168 {
169 continue;
170 }
171 }
172 if (upper_bound && (mode.Width > upper_bound->Width || mode.Height > upper_bound->Height))
173 continue;
174 if (mode.Width == wanted_size.Width && mode.Height == wanted_size.Height)
175 {
176 nearest_width = mode.Width;
177 nearest_height = mode.Height;
178 nearest_mode_index = i;
179 break;
180 }
181
182 int diff_w = abs(wanted_size.Width - mode.Width);
183 int diff_h = abs(wanted_size.Height - mode.Height);
184 bool same_diff_w_higher = (diff_w == nearest_width_diff && nearest_width < wanted_size.Width);
185 bool same_diff_h_higher = (diff_h == nearest_height_diff && nearest_height < wanted_size.Height);
186
187 if (nearest_width == 0 ||
188 (diff_w < nearest_width_diff || same_diff_w_higher) && diff_h <= nearest_height_diff ||
189 (diff_h < nearest_height_diff || same_diff_h_higher) && diff_w <= nearest_width_diff)
190 {
191 nearest_width = mode.Width;
192 nearest_width_diff = diff_w;
193 nearest_height = mode.Height;
194 nearest_height_diff = diff_h;
195 nearest_mode_index = i;
196 }
197 }
198
199 if (nearest_width > 0 && nearest_height > 0)
200 {
201 dm = mode;
202 if (mode_index)
203 *mode_index = nearest_mode_index;
204 return true;
205 }
206 return false;
207 }
208
set_game_frame_after_screen_size(const Size & game_size,const Size screen_size,const GameFrameSetup & setup)209 Size set_game_frame_after_screen_size(const Size &game_size, const Size screen_size, const GameFrameSetup &setup)
210 {
211 // Set game frame as native game resolution scaled by particular method
212 Size frame_size;
213 if (setup.ScaleDef == kFrame_MaxStretch)
214 {
215 frame_size = screen_size;
216 }
217 else if (setup.ScaleDef == kFrame_MaxProportional)
218 {
219 frame_size = ProportionalStretch(screen_size, game_size);
220 }
221 else
222 {
223 int scale;
224 if (setup.ScaleDef == kFrame_MaxRound)
225 scale = Math::Min((screen_size.Width / game_size.Width) << kShift,
226 (screen_size.Height / game_size.Height) << kShift);
227 else
228 scale = convert_scaling_to_fp(setup.ScaleFactor);
229
230 // Ensure scaling factors are sane
231 if (scale <= 0)
232 scale = kUnit;
233
234 frame_size = Size((game_size.Width * scale) >> kShift, (game_size.Height * scale) >> kShift);
235 // If the scaled game size appear larger than the screen,
236 // use "proportional stretch" method instead
237 if (frame_size.ExceedsByAny(screen_size))
238 frame_size = ProportionalStretch(screen_size, game_size);
239 }
240 return frame_size;
241 }
242
precalc_screen_size(const Size & game_size,const DisplayModeSetup & dm_setup,const GameFrameSetup & frame_setup)243 Size precalc_screen_size(const Size &game_size, const DisplayModeSetup &dm_setup, const GameFrameSetup &frame_setup)
244 {
245 Size screen_size, frame_size;
246 Size device_size = get_max_display_size(dm_setup.Windowed);
247
248 // Set requested screen (window) size, depending on screen definition option
249 ScreenSizeSetup scsz = dm_setup.ScreenSize;
250 switch (scsz.SizeDef)
251 {
252 case kScreenDef_Explicit:
253 // Use resolution from user config
254 screen_size = scsz.Size;
255 if (screen_size.IsNull())
256 {
257 // If the configuration did not define proper screen size,
258 // use the scaled game size instead
259 frame_size = set_game_frame_after_screen_size(game_size, device_size, frame_setup);
260 if (screen_size.Width <= 0)
261 screen_size.Width = frame_size.Width;
262 if (screen_size.Height <= 0)
263 screen_size.Height = frame_size.Height;
264 }
265 break;
266 case kScreenDef_ByGameScaling:
267 // Use game frame (scaled game) size
268 frame_size = set_game_frame_after_screen_size(game_size, device_size, frame_setup);
269 screen_size = frame_size;
270 break;
271 case kScreenDef_MaxDisplay:
272 // Set as big as current device size
273 screen_size = device_size;
274 break;
275 }
276 return screen_size;
277 }
278
279 // Find closest possible compatible display mode and initialize it
try_init_compatible_mode(const DisplayMode & dm,const bool match_device_ratio)280 bool try_init_compatible_mode(const DisplayMode &dm, const bool match_device_ratio)
281 {
282 const Size &screen_size = Size(dm.Width, dm.Height);
283 // Find nearest compatible mode and init that
284 Debug::Printf("Attempting to find nearest supported resolution for screen size %d x %d (%d-bit) %s",
285 dm.Width, dm.Height, dm.ColorDepth, dm.Windowed ? "windowed" : "fullscreen");
286 const Size device_size = get_max_display_size(dm.Windowed);
287 if (dm.Windowed)
288 Debug::Printf("Maximal allowed window size: %d x %d", device_size.Width, device_size.Height);
289 DisplayMode dm_compat = dm;
290
291 std::auto_ptr<IGfxModeList> modes(gfxDriver->GetSupportedModeList(dm.ColorDepth)); // TODO: use unique_ptr when available
292
293 // Windowed mode
294 if (dm.Windowed)
295 {
296 // If windowed mode, make the resolution stay in the generally supported limits
297 if (Size(dm.Width, dm.Height).ExceedsByAny(device_size))
298 {
299 dm_compat.Width = device_size.Width;
300 dm_compat.Height = device_size.Height;
301 }
302 }
303 // Fullscreen mode
304 else
305 {
306 // If told to find mode with aspect ratio matching current desktop resolution, then first
307 // try find matching one, and if failed then try any compatible one
308 bool mode_found = false;
309 if (modes.get())
310 {
311 if (match_device_ratio)
312 mode_found = find_nearest_supported_mode(*modes.get(), screen_size, dm.ColorDepth, &device_size, NULL, dm_compat);
313 if (!mode_found)
314 mode_found = find_nearest_supported_mode(*modes.get(), screen_size, dm.ColorDepth, NULL, NULL, dm_compat);
315 }
316 if (!mode_found)
317 Debug::Printf("Could not find compatible fullscreen mode. Will try to force-set mode requested by user and fallback to windowed mode if that fails.");
318 dm_compat.Vsync = dm.Vsync;
319 dm_compat.Windowed = false;
320 }
321
322 bool result = graphics_mode_set_dm(dm_compat);
323 if (!result && dm.Windowed)
324 {
325 // When initializing windowed mode we could start with any random window size;
326 // if that did not work, try to find nearest supported mode, as with fullscreen mode,
327 // except refering to max window size as an upper bound
328 if (find_nearest_supported_mode(*modes.get(), screen_size, dm.ColorDepth, NULL, &device_size, dm_compat))
329 {
330 dm_compat.Vsync = dm.Vsync;
331 dm_compat.Windowed = true;
332 result = graphics_mode_set_dm(dm_compat);
333 }
334 }
335 return result;
336 }
337
338 // Try to find and initialize compatible display mode as close to given setup as possible
try_init_mode_using_setup(const Size & game_size,const DisplayModeSetup & dm_setup,const int col_depth,const GameFrameSetup & frame_setup,const GfxFilterSetup & filter_setup)339 bool try_init_mode_using_setup(const Size &game_size, const DisplayModeSetup &dm_setup,
340 const int col_depth, const GameFrameSetup &frame_setup,
341 const GfxFilterSetup &filter_setup)
342 {
343 // We determine the requested size of the screen using setup options
344 const Size screen_size = precalc_screen_size(game_size, dm_setup, frame_setup);
345 DisplayMode dm(GraphicResolution(screen_size.Width, screen_size.Height, col_depth),
346 dm_setup.Windowed, dm_setup.RefreshRate, dm_setup.VSync);
347 if (!try_init_compatible_mode(dm, dm_setup.ScreenSize.SizeDef == kScreenDef_Explicit ? false : dm_setup.ScreenSize.MatchDeviceRatio))
348 return false;
349
350 // Set up native size and render frame
351 if (!graphics_mode_set_native_size(game_size) || !graphics_mode_set_render_frame(frame_setup))
352 return false;
353
354 // Set up graphics filter
355 if (!graphics_mode_set_filter_any(filter_setup))
356 return false;
357 return true;
358 }
359
log_out_driver_modes(const int color_depth)360 void log_out_driver_modes(const int color_depth)
361 {
362 IGfxModeList *modes = gfxDriver->GetSupportedModeList(color_depth);
363 if (!modes)
364 {
365 Debug::Printf(kDbgMsg_Error, "Couldn't get a list of supported resolutions for color depth = %d", color_depth);
366 return;
367 }
368 const int mode_count = modes->GetModeCount();
369 DisplayMode mode;
370 String mode_str;
371 for (int i = 0, in_str = 0; i < mode_count; ++i)
372 {
373 if (!modes->GetMode(i, mode) || mode.ColorDepth != color_depth)
374 continue;
375 mode_str.Append(String::FromFormat("%dx%d;", mode.Width, mode.Height));
376 if (++in_str % 8 == 0)
377 mode_str.Append("\n\t");
378 }
379 delete modes;
380
381 String out_str = String::FromFormat("Supported gfx modes (%d-bit): ", color_depth);
382 if (!mode_str.IsEmpty())
383 {
384 out_str.Append("\n\t");
385 out_str.Append(mode_str);
386 }
387 else
388 out_str.Append("none");
389 Debug::Printf(out_str);
390 }
391
392 // Create requested graphics driver and try to find and initialize compatible display mode as close to user setup as possible;
393 // if the given setup fails, gets default setup for the opposite type of mode (fullscreen/windowed) and tries that instead.
create_gfx_driver_and_init_mode_any(const String & gfx_driver_id,const Size & game_size,const DisplayModeSetup & dm_setup,const ColorDepthOption & color_depth,const GameFrameSetup & frame_setup,const GfxFilterSetup & filter_setup)394 bool create_gfx_driver_and_init_mode_any(const String &gfx_driver_id, const Size &game_size, const DisplayModeSetup &dm_setup,
395 const ColorDepthOption &color_depth, const GameFrameSetup &frame_setup, const GfxFilterSetup &filter_setup)
396 {
397 if (!graphics_mode_create_renderer(gfx_driver_id))
398 return false;
399
400 const int use_col_depth =
401 color_depth.Forced ? color_depth.Bits : gfxDriver->GetDisplayDepthForNativeDepth(color_depth.Bits);
402 // Log out supported driver modes
403 log_out_driver_modes(use_col_depth);
404
405 bool result = try_init_mode_using_setup(game_size, dm_setup, use_col_depth, frame_setup, filter_setup);
406 // Try windowed mode if fullscreen failed, and vice versa
407 if (!result && editor_debugging_enabled == 0)
408 {
409 // we need to clone from initial config, because not every parameter is set by graphics_mode_get_defaults()
410 DisplayModeSetup dm_setup_alt = dm_setup;
411 dm_setup_alt.Windowed = !dm_setup.Windowed;
412 GameFrameSetup frame_setup_alt;
413 graphics_mode_get_defaults(dm_setup_alt.Windowed, dm_setup_alt.ScreenSize, frame_setup_alt);
414 result = try_init_mode_using_setup(game_size, dm_setup_alt, use_col_depth, frame_setup_alt, filter_setup);
415 }
416 return result;
417 }
418
simple_create_gfx_driver_and_init_mode(const String & gfx_driver_id,const Size & game_size,const DisplayModeSetup & dm_setup,const ColorDepthOption & color_depth,const GameFrameSetup & frame_setup,const GfxFilterSetup & filter_setup)419 bool simple_create_gfx_driver_and_init_mode(const String &gfx_driver_id,
420 const Size &game_size,
421 const DisplayModeSetup &dm_setup,
422 const ColorDepthOption &color_depth,
423 const GameFrameSetup &frame_setup,
424 const GfxFilterSetup &filter_setup)
425 {
426 if (!graphics_mode_create_renderer(gfx_driver_id)) { return false; }
427
428 const int col_depth = gfxDriver->GetDisplayDepthForNativeDepth(color_depth.Bits);
429
430 DisplayMode dm(GraphicResolution(game_size.Width, game_size.Height, col_depth),
431 dm_setup.Windowed, dm_setup.RefreshRate, dm_setup.VSync);
432
433 if (!graphics_mode_set_dm(dm)) { return false; }
434 if (!graphics_mode_set_native_size(game_size)) { return false; }
435 if (!graphics_mode_set_render_frame(frame_setup)) { return false; }
436 if (!graphics_mode_set_filter_any(filter_setup)) { return false; }
437
438 return true;
439 }
440
441
display_gfx_mode_error(const Size & game_size,const ScreenSetup & setup,const int color_depth)442 void display_gfx_mode_error(const Size &game_size, const ScreenSetup &setup, const int color_depth)
443 {
444 proper_exit=1;
445 platform->FinishedUsingGraphicsMode();
446
447 String main_error;
448 ScreenSizeSetup scsz = setup.DisplayMode.ScreenSize;
449 PGfxFilter filter = gfxDriver ? gfxDriver->GetGraphicsFilter() : PGfxFilter();
450 Size wanted_screen;
451 if (scsz.SizeDef == kScreenDef_Explicit)
452 main_error.Format("There was a problem initializing graphics mode %d x %d (%d-bit), or finding nearest compatible mode, with game size %d x %d and filter '%s'.",
453 scsz.Size.Width, scsz.Size.Height, color_depth, game_size.Width, game_size.Height, filter ? filter->GetInfo().Id.GetCStr() : "Undefined");
454 else
455 main_error.Format("There was a problem finding and/or creating valid graphics mode for game size %d x %d (%d-bit) and requested filter '%s'.",
456 game_size.Width, game_size.Height, color_depth, setup.Filter.UserRequest.IsEmpty() ? "Undefined" : setup.Filter.UserRequest.GetCStr());
457
458 platform->DisplayAlert("%s\n"
459 "(Problem: '%s')\n"
460 "Try to correct the problem, or seek help from the AGS homepage."
461 "%s",
462 main_error.GetCStr(), get_allegro_error(), platform->GetGraphicsTroubleshootingText());
463 }
464
graphics_mode_init_any(const Size game_size,const ScreenSetup & setup,const ColorDepthOption & color_depth)465 bool graphics_mode_init_any(const Size game_size, const ScreenSetup &setup, const ColorDepthOption &color_depth)
466 {
467 // Log out display information
468 Size device_size;
469 if (get_desktop_resolution(&device_size.Width, &device_size.Height) == 0)
470 Debug::Printf("Device display resolution: %d x %d", device_size.Width, device_size.Height);
471 else
472 Debug::Printf(kDbgMsg_Error, "Unable to obtain device resolution");
473
474 const char *screen_sz_def_options[kNumScreenDef] = { "explicit", "scaling", "max" };
475 ScreenSizeSetup scsz = setup.DisplayMode.ScreenSize;
476 const bool ignore_device_ratio = setup.DisplayMode.Windowed || scsz.SizeDef == kScreenDef_Explicit;
477 GameFrameSetup gameframe = setup.DisplayMode.Windowed ? setup.WinGameFrame : setup.FsGameFrame;
478 const String scale_option = make_scaling_option(gameframe);
479 Debug::Printf(kDbgMsg_Init, "Graphic settings: driver: %s, windowed: %s, screen def: %s, screen size: %d x %d, match device ratio: %s, game scale: %s",
480 setup.DriverID.GetCStr(),
481 setup.DisplayMode.Windowed ? "yes" : "no", screen_sz_def_options[scsz.SizeDef],
482 scsz.Size.Width, scsz.Size.Height,
483 ignore_device_ratio ? "ignore" : (scsz.MatchDeviceRatio ? "yes" : "no"), scale_option.GetCStr());
484
485 // Prepare the list of available gfx factories, having the one requested by user at first place
486 // TODO: make factory & driver IDs case-insensitive!
487 StringV ids;
488 GetGfxDriverFactoryNames(ids);
489 StringV::iterator it = ids.begin();
490 for (; it != ids.end(); ++it)
491 {
492 if (it->CompareNoCase(setup.DriverID) == 0) break;
493 }
494 if (it != ids.end())
495 std::rotate(ids.begin(), it, ids.end());
496 else
497 Debug::Printf(kDbgMsg_Error, "Requested graphics driver '%s' not found, will try existing drivers instead", setup.DriverID.GetCStr());
498
499 // Try to create renderer and init gfx mode, choosing one factory at a time
500 bool result = false;
501 for (StringV::const_iterator it = ids.begin(); it != ids.end(); ++it)
502 {
503 result =
504 #ifdef USE_SIMPLE_GFX_INIT
505 simple_create_gfx_driver_and_init_mode
506 #else
507 create_gfx_driver_and_init_mode_any
508 #endif
509 (*it, game_size, setup.DisplayMode, color_depth, gameframe, setup.Filter);
510
511 if (result)
512 break;
513 graphics_mode_shutdown();
514 }
515 // If all possibilities failed, display error message and quit
516 if (!result)
517 {
518 display_gfx_mode_error(game_size, setup, color_depth.Bits);
519 return false;
520 }
521 return true;
522 }
523
graphics_mode_get_last_setting(bool windowed)524 ActiveDisplaySetting graphics_mode_get_last_setting(bool windowed)
525 {
526 return windowed ? SavedWindowedSetting : SavedFullscreenSetting;
527 }
528
529 bool graphics_mode_update_render_frame();
GfxDriverOnSurfaceUpdate()530 void GfxDriverOnSurfaceUpdate()
531 {
532 // Resize render frame using current scaling settings
533 graphics_mode_update_render_frame();
534 on_coordinates_scaling_changed();
535 }
536
graphics_mode_create_renderer(const String & driver_id)537 bool graphics_mode_create_renderer(const String &driver_id)
538 {
539 if (!create_gfx_driver(driver_id))
540 return false;
541
542 gfxDriver->SetCallbackOnInit(GfxDriverOnInitCallback);
543 gfxDriver->SetCallbackOnSurfaceUpdate(GfxDriverOnSurfaceUpdate);
544 // TODO: this is remains of the old code; find out if this is really
545 // the best time and place to set the tint method
546 gfxDriver->SetTintMethod(TintReColourise);
547 return true;
548 }
549
graphics_mode_set_dm_any(const Size & game_size,const DisplayModeSetup & dm_setup,const ColorDepthOption & color_depth,const GameFrameSetup & frame_setup)550 bool graphics_mode_set_dm_any(const Size &game_size, const DisplayModeSetup &dm_setup,
551 const ColorDepthOption &color_depth, const GameFrameSetup &frame_setup)
552 {
553 // We determine the requested size of the screen using setup options
554 const Size screen_size = precalc_screen_size(game_size, dm_setup, frame_setup);
555 DisplayMode dm(GraphicResolution(screen_size.Width, screen_size.Height, color_depth.Bits),
556 dm_setup.Windowed, dm_setup.RefreshRate, dm_setup.VSync);
557 return try_init_compatible_mode(dm, dm_setup.ScreenSize.MatchDeviceRatio);
558 }
559
graphics_mode_set_dm(const DisplayMode & dm)560 bool graphics_mode_set_dm(const DisplayMode &dm)
561 {
562 Debug::Printf("Attempt to switch gfx mode to %d x %d (%d-bit) %s",
563 dm.Width, dm.Height, dm.ColorDepth, dm.Windowed ? "windowed" : "fullscreen");
564
565 // Tell Allegro new default bitmap color depth (must be done before set_gfx_mode)
566 // TODO: this is also done inside ALSoftwareGraphicsDriver implementation; can remove one?
567 set_color_depth(dm.ColorDepth);
568 // TODO: this is remains of the old code; find out what it means and do we
569 // need this if we are not using allegro software driver?
570 if (dm.RefreshRate >= 50)
571 request_refresh_rate(dm.RefreshRate);
572
573 if (!gfxDriver->SetDisplayMode(dm, &timerloop))
574 {
575 Debug::Printf(kDbgMsg_Error, "Failed to init gfx mode. Error: %s", get_allegro_error());
576 return false;
577 }
578
579 DisplayMode rdm = gfxDriver->GetDisplayMode();
580 if (rdm.Windowed)
581 SavedWindowedSetting.Dm = rdm;
582 else
583 SavedFullscreenSetting.Dm = rdm;
584 Debug::Printf("Succeeded. Using gfx mode %d x %d (%d-bit) %s",
585 rdm.Width, rdm.Height, rdm.ColorDepth, rdm.Windowed ? "windowed" : "fullscreen");
586 return true;
587 }
588
graphics_mode_update_render_frame()589 bool graphics_mode_update_render_frame()
590 {
591 if (!gfxDriver || !gfxDriver->IsModeSet() || !gfxDriver->IsNativeSizeValid())
592 return false;
593
594 DisplayMode dm = gfxDriver->GetDisplayMode();
595 Size screen_size = Size(dm.Width, dm.Height);
596 Size native_size = gfxDriver->GetNativeSize();
597 Size frame_size = set_game_frame_after_screen_size(native_size, screen_size, CurFrameSetup);
598 Rect render_frame = CenterInRect(RectWH(screen_size), RectWH(frame_size));
599
600 if (!gfxDriver->SetRenderFrame(render_frame))
601 {
602 Debug::Printf(kDbgMsg_Error, "Failed to set render frame (%d, %d, %d, %d : %d x %d). Error: %s",
603 render_frame.Left, render_frame.Top, render_frame.Right, render_frame.Bottom,
604 render_frame.GetWidth(), render_frame.GetHeight(), get_allegro_error());
605 return false;
606 }
607
608 Rect dst_rect = gfxDriver->GetRenderDestination();
609 Debug::Printf("Render frame set, render dest (%d, %d, %d, %d : %d x %d)",
610 dst_rect.Left, dst_rect.Top, dst_rect.Right, dst_rect.Bottom, dst_rect.GetWidth(), dst_rect.GetHeight());
611 // init game scaling transformation
612 GameScaling.Init(native_size, gfxDriver->GetRenderDestination());
613 return true;
614 }
615
graphics_mode_set_native_size(const Size & native_size)616 bool graphics_mode_set_native_size(const Size &native_size)
617 {
618 if (!gfxDriver || native_size.IsNull())
619 return false;
620 if (!gfxDriver->SetNativeSize(native_size))
621 return false;
622 // if render frame translation was already set, then update it with new native size
623 if (gfxDriver->IsRenderFrameValid())
624 graphics_mode_update_render_frame();
625 return true;
626 }
627
graphics_mode_get_render_frame()628 GameFrameSetup graphics_mode_get_render_frame()
629 {
630 return CurFrameSetup;
631 }
632
graphics_mode_set_render_frame(const GameFrameSetup & frame_setup)633 bool graphics_mode_set_render_frame(const GameFrameSetup &frame_setup)
634 {
635 if (!frame_setup.IsValid())
636 return false;
637 CurFrameSetup = frame_setup;
638 if (gfxDriver->GetDisplayMode().Windowed)
639 SavedWindowedSetting.FrameSetup = frame_setup;
640 else
641 SavedFullscreenSetting.FrameSetup = frame_setup;
642 graphics_mode_update_render_frame();
643 return true;
644 }
645
graphics_mode_set_filter(const String & filter_id)646 bool graphics_mode_set_filter(const String &filter_id)
647 {
648 if (!GfxFactory)
649 return false;
650
651 String filter_error;
652 PGfxFilter filter = GfxFactory->SetFilter(filter_id, filter_error);
653 if (!filter)
654 {
655 Debug::Printf(kDbgMsg_Error, "Unable to set graphics filter '%s'. Error: %s", filter_id.GetCStr(), filter_error.GetCStr());
656 return false;
657 }
658 Rect filter_rect = filter->GetDestination();
659 Debug::Printf("Graphics filter set: '%s', filter dest (%d, %d, %d, %d : %d x %d)", filter->GetInfo().Id.GetCStr(),
660 filter_rect.Left, filter_rect.Top, filter_rect.Right, filter_rect.Bottom, filter_rect.GetWidth(), filter_rect.GetHeight());
661 return true;
662 }
663
graphics_mode_shutdown()664 void graphics_mode_shutdown()
665 {
666 if (GfxFactory)
667 GfxFactory->Shutdown();
668 GfxFactory = NULL;
669 gfxDriver = NULL;
670
671 // Tell Allegro that we are no longer in graphics mode
672 set_gfx_mode(GFX_TEXT, 0, 0, 0, 0);
673 }
674