int StrUtil::StringToInt(const String &s, int def_val)
{
    if (!s.GetCStr())
        return def_val;
    char *stop_ptr;
    int val = strtol(s.GetCStr(), &stop_ptr, 0);
    return (stop_ptr == s.GetCStr() + s.GetLength()) ? val : def_val;
}
StrUtil::ConversionError StrUtil::StringToInt(const String &s, int &val, int def_val)
{
    val = def_val;
    if (!s.GetCStr())
        return StrUtil::kFailed;
    char *stop_ptr;
    errno = 0;
    long lval = strtol(s.GetCStr(), &stop_ptr, 0);
    if (stop_ptr != s.GetCStr() + s.GetLength())
        return StrUtil::kFailed;
    if (lval > INT_MAX || lval < INT_MIN || errno == ERANGE)
        return StrUtil::kOutOfRange;
    val = (int)lval;
    return StrUtil::kNoError;
}
void StrUtil::WriteString(const String &s, Stream *out)
{
    size_t len = s.GetLength();
    out->WriteInt32(len);
    if (len > 0)
        out->Write(s.GetCStr(), len);
}
Beispiel #4
0
char *INIreaditem(const char *sectn, const char *entry) {
    Stream *fin = Common::File::OpenFileRead(filetouse);
    if (fin == NULL)
        return NULL;
    TextStreamReader reader(fin);

    //char templine[200];
    char wantsect[100];
    sprintf (wantsect, "[%s]", sectn);

    // NOTE: the string is used as a raw buffer down there;
    // FIXME that as soon as string class is optimized for common use
    String line;

    while (!reader.EOS()) {
        //fgets (templine, 199, fin);
        line = reader.ReadLine();

        // find the section
        if (strnicmp (wantsect, line.GetCStr(), strlen(wantsect)) == 0) {
            while (!reader.EOS()) {
                // we're in the right section, find the entry
                //fgets (templine, 199, fin);
                line = reader.ReadLine();
                if (line.IsEmpty())
                    continue;
                if (line[0] == '[')
                    break;
                // Have we found the entry?
                if (strnicmp (line.GetCStr(), entry, strlen(entry)) == 0) {
                    const char *pptr = &line.GetCStr()[strlen(entry)];
                    while ((pptr[0] == ' ') || (pptr[0] == '\t'))
                        pptr++;
                    if (pptr[0] == '=') {
                        pptr++;
                        while ((pptr[0] == ' ') || (pptr[0] == '\t'))
                            pptr++;
                        char *toret = (char*)malloc (strlen(pptr) + 5);
                        strcpy (toret, pptr);
                        return toret;
                    }
                }
            }
        }
    }
    return NULL;
}
Beispiel #5
0
bool engine_init_gfx_filters(Size &game_size, Size &screen_size, const int color_depth)
{
    Out::FPrint("Initializing gfx filters");
    if (force_gfxfilter[0])
        GfxFilterRequest = force_gfxfilter;
    else
        GfxFilterRequest = usetup.gfxFilterID;
    Out::FPrint("Requested gfx filter: %s", GfxFilterRequest.GetCStr());

    // Try to initialize gfx filter of requested name
    if (GfxFilterRequest.CompareNoCase("max") != 0 &&
        initialize_graphics_filter(GfxFilterRequest, color_depth))
    {
        // Filter found, but we must also try if the engine will be able to set
        // screen resolution
        if (!try_find_nearest_supported_mode(game_size, filter->GetScalingFactor(), screen_size, color_depth,
                usetup.windowed, usetup.prefer_sideborders, usetup.prefer_letterbox))
        {
            delete filter;
            filter = NULL;
        }
    }
    
    // If the filter was not set for any reason, try to choose standard scaling filter
    // of maximal possible scaling factor
    if (!filter)
    {
        String filter_name;
        int scaling_factor;
#if defined (WINDOWS_VERSION) || defined (LINUX_VERSION)
        scaling_factor = try_find_max_supported_uniform_scaling(game_size, screen_size, color_depth,
                            usetup.windowed, usetup.prefer_sideborders, usetup.prefer_letterbox);
        if (scaling_factor == 0)
#endif
        {
            screen_size = game_size;
            scaling_factor = 1;
        }
        filter_name.Format(scaling_factor > 1 ? "StdScale%d" : "None", scaling_factor);
        initialize_graphics_filter(filter_name, color_depth);
    }

    // If not suitable filter still found then return with error message
    if (!filter)
    {
        set_allegro_error("Failed to find acceptable graphics filter");
        return false;
    }

    // On success apply filter and define game frame
    Out::FPrint("Applying graphics filter: %s", filter->GetFilterID());
    gfxDriver->SetGraphicsFilter(filter);    
    game_size.Width = screen_size.Width / filter->GetScalingFactor();
    game_size.Height = screen_size.Height / filter->GetScalingFactor();
    Out::FPrint("Chosen gfx resolution: %d x %d (%d bit), game frame: %d x %d",
        screen_size.Width, screen_size.Height, color_depth, game_size.Width, game_size.Height);
    return true;
}
Beispiel #6
0
bool pre_create_gfx_driver(const String &gfx_driver_id)
{
    GfxFactory = GetGfxDriverFactory(gfx_driver_id);
    if (!GfxFactory)
    {
        Out::FPrint("Failed to initialize %s graphics factory: %s", gfx_driver_id.GetCStr(), get_allegro_error());
        return false;
    }
    Out::FPrint("Using graphics factory: %s", gfx_driver_id.GetCStr());
    gfxDriver = GfxFactory->GetDriver();
    if (!gfxDriver)
    {
        Out::FPrint("Failed to create graphics driver. %s", get_allegro_error());
        return false;
    }
    Out::FPrint("Created graphics driver: %s", gfxDriver->GetDriverName());
    return true;
}
Beispiel #7
0
int engine_init_gfx_filters(Size &game_size, Size &screen_size, const int color_depth)
{
    Out::FPrint("Initializing gfx filters");
    if (force_gfxfilter[0])
        GfxFilterRequest = force_gfxfilter;
    else
        GfxFilterRequest = usetup.gfxFilterID;
    Out::FPrint("Requested gfx filter: %s", GfxFilterRequest.GetCStr());

    String gfxfilter;
    if (GfxFilterRequest.CompareNoCase("max") != 0)
        gfxfilter = GfxFilterRequest;
    
    const Size base_size = game_size;
    const bool windowed = usetup.windowed != 0;
    const bool enable_sideborders = usetup.enable_side_borders != 0;
    const bool force_letterbox = game.options[OPT_LETTERBOX] != 0;

    int scaling_factor = 0;
    if (!gfxfilter.IsEmpty())
    {
        scaling_factor = get_scaling_from_filter_name(gfxfilter);
        Size found_screen_size;
        if (try_find_nearest_supported_mode(base_size, scaling_factor, found_screen_size, color_depth,
                windowed, enable_sideborders, force_letterbox))
            screen_size = found_screen_size;
    }

#if defined (WINDOWS_VERSION) || defined (LINUX_VERSION)
    if (screen_size.IsNull())
    {
        Size found_screen_size;
        scaling_factor = try_find_max_supported_uniform_scaling(base_size, found_screen_size, color_depth,
                            windowed, enable_sideborders, force_letterbox);
        if (scaling_factor > 0)
        {
            screen_size = found_screen_size;
            gfxfilter.Format(scaling_factor > 1 ? "StdScale%d" : "None", scaling_factor);
        }
    }
#endif

    if (gfxfilter.IsEmpty())
    {
        set_allegro_error("Failed to find acceptable graphics filter");
        return EXIT_NORMAL;
    }
    game_size.Width = screen_size.Width / scaling_factor;
    game_size.Height = screen_size.Height / scaling_factor;
    Out::FPrint("Chosen gfx resolution: %d x %d (%d bit), game frame: %d x %d",
        screen_size.Width, screen_size.Height, color_depth, game_size.Width, game_size.Height);
    if (initialize_graphics_filter(gfxfilter, base_size.Width, base_size.Height, color_depth))
    {
        return EXIT_NORMAL;
    }
    return RETURN_CONTINUE;
}
Beispiel #8
0
bool create_gfx_driver(const String &gfx_driver_id)
{
    Out::FPrint("Init gfx driver: %s", gfx_driver_id.GetCStr());
    if (!pre_create_gfx_driver(gfx_driver_id))
        return false;

    usetup.gfxDriverID = gfxDriver->GetDriverID();
    gfxDriver->SetCallbackOnInit(GfxDriverOnInitCallback);
    gfxDriver->SetTintMethod(TintReColourise);
    return true;
}
Beispiel #9
0
String find_game_data_in_directory(const String &path)
{
    al_ffblk ff;
    String test_file;
    String first_nonstd_fn;
    String pattern = path;
    pattern.Append("/*");

    if (al_findfirst(pattern, &ff, FA_ALL & ~(FA_DIREC)) != 0)
        return "";
    // Select first found data file; files with standart names (*.ags) have
    // higher priority over files with custom names.
    do
    {
        test_file = ff.name;
        // Add a bit of sanity and do not parse contents of the 10k-files-large
        // digital sound libraries.
        // NOTE: we could certainly benefit from any kind of flag in file lib
        // that would tell us this is the main lib without extra parsing.
        if (test_file.CompareRightNoCase(".vox") == 0)
            continue;

        // *.ags is a standart cross-platform file pattern for AGS games,
        // ac2game.dat is a legacy file name for very old games,
        // *.exe is a MS Win executable; it is included to this case because
        // users often run AGS ports with Windows versions of games.
        bool is_std_name = test_file.CompareRightNoCase(".ags") == 0 ||
            test_file.CompareNoCase("ac2game.dat") == 0 ||
            test_file.CompareRightNoCase(".exe") == 0;
        if (is_std_name || first_nonstd_fn.IsEmpty())
        {
            test_file.Format("%s/%s", path.GetCStr(), ff.name);
            if (is_main_game_file(test_file))
            {
                if (is_std_name)
                {
                    al_findclose(&ff);
                    return test_file;
                }
                else
                    first_nonstd_fn = test_file;
            }
        }
    }
    while(al_findnext(&ff) == 0);
    al_findclose(&ff);
    return first_nonstd_fn;
}
Beispiel #10
0
bool initialize_graphics_filter(const String filter_id, const int color_depth)
{
    filter = GfxFactory->SetFilter(filter_id);
    if (!filter)
    {
        Out::FPrint("Unable to create filter: %s", filter_id.GetCStr());
        return false;
    }

    String filter_error;
    if (!filter->Initialize(color_depth, filter_error))
    {
        Out::FPrint("Unable to initialize the graphics filter. Error: %s.", filter_error.GetCStr());
        return false;
    }
    return true;
}
Beispiel #11
0
// Prepends message text with current room number and running script info, then logs result
void debug_script_print(const String &msg, MessageType mt)
{
    String script_ref;
    ccInstance *curinst = ccInstance::GetCurrentInstance();
    if (curinst != NULL) {
        String scriptname;
        if (curinst->instanceof == gamescript)
            scriptname = "G ";
        else if (curinst->instanceof == thisroom.compiled_script)
            scriptname = "R ";
        else if (curinst->instanceof == dialogScriptsScript)
            scriptname = "D ";
        else
            scriptname = "? ";
        script_ref.Format("[%s%d]", scriptname.GetCStr(), currentline);
    }

    Debug::Printf(kDbgGroup_Script, mt, "(room:%d)%s %s", displayed_room, script_ref.GetCStr(), msg.GetCStr());
}
Beispiel #12
0
String find_user_global_cfg_file()
{
    String parent_dir = PathOrCurDir(platform->GetUserGlobalConfigDirectory());
    return String::FromFormat("%s/%s", parent_dir.GetCStr(), DefaultConfigFileName.GetCStr());
}
Beispiel #13
0
String find_user_cfg_file()
{
    String parent_dir = MakeSpecialSubDir(PathOrCurDir(platform->GetUserConfigDirectory()));
    return String::FromFormat("%s/%s", parent_dir.GetCStr(), DefaultConfigFileName.GetCStr());
}
Beispiel #14
0
void MessageBuffer::Send(const String &out_id)
{
    if (_buffer.empty())
        return;
    if (_msgLost > 0)
    {
        DebugGroup gr = DbgMgr.GetGroup(kDbgGroup_Main);
        DbgMgr.SendMessage(out_id, DebugMessage(String::FromFormat("WARNING: output %s lost exceeding buffer: %u debug messages\n", out_id.GetCStr(), (unsigned)_msgLost),
            gr.UID.ID, gr.OutputName, kDbgMsgSet_All));
    }
    for (std::vector<DebugMessage>::const_iterator it = _buffer.begin(); it != _buffer.end(); ++it)
    {
        DbgMgr.SendMessage(out_id, *it);
    }
}
Beispiel #15
0
String find_default_cfg_file(const char *alt_cfg_file)
{
    // Try current directory for config first; else try exe dir
    String filename = String::FromFormat("%s/%s", Directory::GetCurrentDirectory().GetCStr(), DefaultConfigFileName.GetCStr());
    if (!Common::File::TestReadFile(filename))
    {
        char conffilebuf[512];
        strcpy(conffilebuf, alt_cfg_file);
        fix_filename_case(conffilebuf);
        fix_filename_slashes(conffilebuf);
        INIgetdirec(conffilebuf, DefaultConfigFileName);
        filename = conffilebuf;
    }
    return filename;
}
Beispiel #16
0
const char* System_GetRuntimeInfo()
{
    String runtimeInfo = GetRuntimeInfo();

    return CreateNewScriptString(runtimeInfo.GetCStr());
}
Beispiel #17
0
void display_gfx_mode_error(const Size &game_size, const Size &screen_size)
{
    proper_exit=1;
    platform->FinishedUsingGraphicsMode();

    String main_error;
    if (screen_size.IsNull())
        main_error.Format("There was a problem finding appropriate graphics mode for game size %d x %d (%d-bit) and requested filter '%s'.",
            game_size.Width, game_size.Height, firstDepth, GfxFilterRequest.IsEmpty() ? "Undefined" : GfxFilterRequest.GetCStr());
    else
        main_error.Format("There was a problem initializing graphics mode %d x %d (%d-bit) with game size %d x %d and filter '%s'.",
            screen_size.Width, screen_size.Height, firstDepth, game_size.Width, game_size.Height, filter ? filter->GetFilterID() : "Undefined");

    platform->DisplayAlert("%s\n"
            "(Problem: '%s')\n"
            "Try to correct the problem, or seek help from the AGS homepage.\n"
            "\nPossible causes:\n* your graphics card drivers do not support this resolution. "
            "Run the game setup program and try the other resolution.\n"
            "* the graphics driver you have selected does not work. Try switching between Direct3D and DirectDraw.\n"
            "* the graphics filter you have selected does not work. Try another filter.",
            main_error.GetCStr(), get_allegro_error());
}
Beispiel #18
0
void preparesavegamelist(int ctrllist)
{
  numsaves = 0;
  toomanygames = 0;
  al_ffblk ffb;
  int bufix = 0;
  char curdir[255];
  _getcwd(curdir, 255);

  char searchPath[260];
  sprintf(searchPath, "%s""agssave.*%s", saveGameDirectory, saveGameSuffix);

  int don = al_findfirst(searchPath, &ffb, -1);
  while (!don) {
    bufix = 0;
    if (numsaves >= MAXSAVEGAMES) {
      toomanygames = 1;
      break;
    }

    // only list games .000 to .099 (to allow higher slots for other purposes)
    if (strstr(ffb.name, ".0") == NULL) {
      don = al_findnext(&ffb);
      continue;
    }

    const char *numberExtension = strstr(ffb.name, ".0") + 1;
    int sgNumber = atoi(numberExtension);

    String thisGamePath = get_save_game_path(sgNumber);

    // get description
    String description;
    read_savedgame_description(thisGamePath, description);

    CSCISendControlMessage(ctrllist, CLB_ADDITEM, 0, (long)description.GetCStr());
    // Select the first item
    CSCISendControlMessage(ctrllist, CLB_SETCURSEL, 0, 0);
    filenumbers[numsaves] = sgNumber;
    filedates[numsaves] = (long int)ffb.time;
    numsaves++;
    don = al_findnext(&ffb);
  }

  al_findclose(&ffb);
  if (numsaves >= MAXSAVEGAMES)
    toomanygames = 1;

  for (int nn = 0; nn < numsaves - 1; nn++) {
    for (int kk = 0; kk < numsaves - 1; kk++) { // Date order the games
      if (filedates[kk] < filedates[kk + 1]) {  // swap them round
        CSCISendControlMessage(ctrllist, CLB_GETTEXT, kk, (long)&buff[0]);
        CSCISendControlMessage(ctrllist, CLB_GETTEXT, kk + 1, (long)&buffer2[0]);
        CSCISendControlMessage(ctrllist, CLB_SETTEXT, kk + 1, (long)&buff[0]);
        CSCISendControlMessage(ctrllist, CLB_SETTEXT, kk, (long)&buffer2[0]);
        int numtem = filenumbers[kk];
        filenumbers[kk] = filenumbers[kk + 1];
        filenumbers[kk + 1] = numtem;
        long numted = filedates[kk];
        filedates[kk] = filedates[kk + 1];
        filedates[kk + 1] = numted;
      }
    }
  }
}
Beispiel #19
0
String find_game_data_in_directory(const String &path)
{
    String test_file;
    String found_data_file;
    // TODO: find a way to make this platform-agnostic way
    // using find-file interface or something
#if defined (LINUX_VERSION) || defined (MAC_VERSION)
    DIR* fd = NULL;
    struct dirent* entry = NULL;
    version_info_t version_info;

    if ((fd = opendir(path)))
    {
        while ((entry = readdir(fd)))
        {
            // Filename must be >= 4 chars long
            int length = strlen(entry->d_name);
            if (length < 4)
            {
                continue;
            }

            // Exclude the setup program
            if (stricmp(entry->d_name, "winsetup.exe") == 0)
            {
                continue;
            }

            if (stricmp(&(entry->d_name[length - 4]), ".exe") == 0)
            {
                if (!getVersionInformation(entry->d_name, &version_info))
                    continue;
                if (strcmp(version_info.internal_name, "acwin") == 0)
                {
                    test_file.Format("%s/%s", path.GetCStr(), entry->d_name);
                    if (AGS::Common::AssetManager::IsDataFile(test_file))
                    {
                        found_data_file = test_file;
                        break;
                    }
                }
            }
            else if (stricmp(&(entry->d_name[length - 4]), ".ags") == 0 ||
                stricmp(entry->d_name, "ac2game.dat") == 0)
            {
                test_file.Format("%s/%s", path.GetCStr(), entry->d_name);
                if (AGS::Common::AssetManager::IsDataFile(test_file))
                {
                    found_data_file = test_file;
                    break;
                }
            }
        }
        closedir(fd);
    }
#elif defined (WINDOWS_VERSION)
    String path_mask = path;
    path_mask.Append("/*");
    WIN32_FIND_DATAA file_data;
    HANDLE find_handle = FindFirstFileA(path_mask, &file_data);
    if (find_handle != INVALID_HANDLE_VALUE)
    {
        do
        {
            // Filename must be >= 4 chars long
            int length = strlen(file_data.cFileName);
            if (length < 4)
            {
                continue;
            }

            // Exclude the setup program
            if (strcmp(file_data.cFileName, "winsetup.exe") == 0)
            {
                continue;
            }

            if (strcmp(&(file_data.cFileName[length - 4]), ".exe") == 0 ||
                strcmp(&(file_data.cFileName[length - 4]), ".ags") == 0 ||
                strcmp(file_data.cFileName, "ac2game.dat") == 0)
            {
                test_file.Format("%s/%s", path.GetCStr(), file_data.cFileName);
                if (AGS::Common::AssetManager::IsDataFile(test_file))
                {
                    found_data_file = test_file;
                    break;
                }
            }
        }
        while (FindNextFileA(find_handle, &file_data) != FALSE);
        FindClose(find_handle);
    }
#else
    // TODO ??? (PSP, ANDROID)
#endif
    return found_data_file;
}
Beispiel #20
0
void display_gfx_mode_error(const Size &game_size, const Size &screen_size)
{
    proper_exit=1;
    platform->FinishedUsingGraphicsMode();

    String main_error;
    if (screen_size.IsNull())
        main_error.Format("There was a problem finding appropriate graphics mode for game size %d x %d (%d-bit) and requested filter '%s'.",
            game_size.Width, game_size.Height, firstDepth, GfxFilterRequest.IsEmpty() ? "Undefined" : GfxFilterRequest.GetCStr());
    else
        main_error.Format("There was a problem initializing graphics mode %d x %d (%d-bit) with game size %d x %d and filter '%s'.",
            screen_size.Width, screen_size.Height, firstDepth, game_size.Width, game_size.Height, filter ? filter->GetFilterID() : "Undefined");

    platform->DisplayAlert("%s\n"
            "(Problem: '%s')\n"
            "Try to correct the problem, or seek help from the AGS homepage."
            "%s",
            main_error.GetCStr(), get_allegro_error(), platform->GetGraphicsTroubleshootingText());
}
Beispiel #21
0
HSaveError OpenSavegameBase(const String &filename, SavegameSource *src, SavegameDescription *desc, SavegameDescElem elems)
{
    UStream in(File::OpenFileRead(filename));
    if (!in.get())
        return new SavegameError(kSvgErr_FileOpenFailed, String::FromFormat("Requested filename: %s.", filename.GetCStr()));

    // Skip MS Windows Vista rich media header
    RICH_GAME_MEDIA_HEADER rich_media_header;
    rich_media_header.ReadFromFile(in.get());

    // Check saved game signature
    bool is_new_save = false;
    size_t pre_sig_pos = in->GetPosition();
    String svg_sig = String::FromStreamCount(in.get(), SavegameSource::Signature.GetLength());
    if (svg_sig.Compare(SavegameSource::Signature) == 0)
    {
        is_new_save = true;
    }
    else
    {
        in->Seek(pre_sig_pos, kSeekBegin);
        svg_sig = String::FromStreamCount(in.get(), SavegameSource::LegacySignature.GetLength());
        if (svg_sig.Compare(SavegameSource::LegacySignature) != 0)
            return new SavegameError(kSvgErr_SignatureFailed);
    }

    SavegameVersion svg_ver;
    SavegameDescription temp_desc;
    HSaveError err;
    if (is_new_save)
        err = ReadDescription(in.get(), svg_ver, temp_desc, desc ? elems : kSvgDesc_None);
    else
        err = ReadDescription_v321(in.get(), svg_ver, temp_desc, desc ? elems : kSvgDesc_None);
    if (!err)
        return err;

    if (src)
    {
        src->Filename = filename;
        src->Version = svg_ver;
        src->InputStream.reset(in.release()); // give the stream away to the caller
    }
    if (desc)
    {
        if (elems & kSvgDesc_EnvInfo)
        {
            desc->EngineName = temp_desc.EngineName;
            desc->EngineVersion = temp_desc.EngineVersion;
            desc->GameGuid = temp_desc.GameGuid;
            desc->GameTitle = temp_desc.GameTitle;
            desc->MainDataFilename = temp_desc.MainDataFilename;
            desc->MainDataVersion = temp_desc.MainDataVersion;
            desc->ColorDepth = temp_desc.ColorDepth;
        }
        if (elems & kSvgDesc_UserText)
            desc->UserText = temp_desc.UserText;
        if (elems & kSvgDesc_UserImage)
            desc->UserImage.reset(temp_desc.UserImage.release());
    }
    return err;
}
Beispiel #22
0
String GetPathInASCII(const String &path)
{
    char ascii_buffer[MAX_PATH];
    if (GetShortPathNameA(path, ascii_buffer, MAX_PATH) == 0)
    {
        Debug::Printf(kDbgMsg_Error, "Unable to determine path: GetShortPathNameA failed.\nArg: %s", path.GetCStr());
        return "";
    }
    return Path::MakeAbsolutePath(ascii_buffer);
}
Beispiel #23
0
bool graphics_mode_init(const ScreenSetup &setup, const ColorDepthOption &color_depths)
{
    // Log out display information
    Size device_size;
    if (get_desktop_resolution(&device_size.Width, &device_size.Height) == 0)
        Out::FPrint("Device display resolution: %d x %d", device_size.Width, device_size.Height);
    else
        Out::FPrint("Unable to obtain device resolution");

    const char *screen_sz_def_options[kNumScreenDef] = { "explicit", "scaling", "max" };
    const bool ignore_device_ratio = setup.Windowed || setup.SizeDef == kScreenDef_Explicit;
    const String scale_option = make_scaling_option(setup.GameFrame.ScaleDef, convert_fp_to_scaling(setup.GameFrame.ScaleFactor));
    Out::FPrint("Game settings: windowed = %s, screen def: %s, screen size: %d x %d, match device ratio: %s, game scale: %s",
        setup.Windowed ? "yes" : "no", screen_sz_def_options[setup.SizeDef], setup.Size.Width, setup.Size.Height,
        ignore_device_ratio ? "ignore" : (setup.MatchDeviceRatio ? "yes" : "no"), scale_option.GetCStr());

    // Game size is used when defining resolution base and proper scaling;
    // Box size specifies minimal wanted screen size for the game (unscaled),
    // it is supposed to be be equal or greater than game_size
    GameSizeDef game_size;
    game_size.Game = game.size;
    game_size.Box = game.size;

    // Prepare the list of available gfx factories, having the one requested by user at first place
    StringV ids;
    GetGfxDriverFactoryNames(ids);
    StringV::iterator it = std::find(ids.begin(), ids.end(), setup.DriverID);
    if (it != ids.end())
        std::rotate(ids.begin(), it, ids.end());
    else
        Out::FPrint("Requested graphics driver '%s' not found, will try existing drivers instead", setup.DriverID.GetCStr());

    // Try to create renderer and init gfx mode, choosing one factory at a time
    bool result = false;
    for (StringV::const_iterator it = ids.begin(); it != ids.end(); ++it)
    {
        result = create_gfx_driver_and_init_mode(*it, game_size, setup, color_depths, setup.Windowed);
        if (result)
            break;
        graphics_mode_shutdown();
    }
    // If all possibilities failed, display error message and quit
    if (!result)
    {
        display_gfx_mode_error(game_size.Box, setup.Filter, color_depths.Prime);
        return false;
    }

    // On success: log out new mode params and continue initialization
    DisplayMode dm   = gfxDriver->GetDisplayMode();
    ScreenResolution = dm;

    Rect dst_rect    = gfxDriver->GetRenderDestination();
    Rect filter_rect = filter->GetDestination();
    Out::FPrint("Succeeded. Using gfx mode %d x %d (%d-bit) %s\n\t"
                "filter dest (%d, %d, %d, %d : %d x %d), render dest (%d, %d, %d, %d : %d x %d)",
        dm.Width, dm.Height, dm.ColorDepth, dm.Windowed ? "windowed" : "fullscreen",
        filter_rect.Left, filter_rect.Top, filter_rect.Right, filter_rect.Bottom, filter_rect.GetWidth(), filter_rect.GetHeight(),
        dst_rect.Left, dst_rect.Top, dst_rect.Right, dst_rect.Bottom, dst_rect.GetWidth(), dst_rect.GetHeight());

    return true;
}
void StrUtil::WriteCStr(const String &s, Stream *out)
{
    out->Write(s.GetCStr(), s.GetLength() + 1);
}