stk-code_catmod/src/graphics/graphics_restrictions.cpp

322 lines
11 KiB
C++

//
// SuperTuxKart - a fun racing game with go-kart
// Copyright (C) 2014 Joerg Henrichs
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 3
// of the License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
#include "graphics/graphics_restrictions.hpp"
#include "io/file_manager.hpp"
#include "io/xml_node.hpp"
#include "utils/log.hpp"
#include "utils/no_copy.hpp"
#include "utils/string_utils.hpp"
#include "utils/types.hpp"
#include <algorithm>
namespace GraphicsRestrictions
{
class Rule;
namespace Private
{
std::vector<Rule*> m_all_rules;
} // namespace Private
using namespace Private;
// ============================================================================
/** A small utility class to manage and compare version tuples.
*/
class Version
{
private:
/** The array containing the version number. */
std::vector<uint32_t> m_version;
// ----------------------------------------------------------------------------
/** Searches for the first number in the string, then converts the rest of the
* string into a tuple. E.g. "Build 12.34.56" --> [12,34,56].
*/
void convertVersionString(const std::string &version)
{
std::string s = version;
std::string::iterator p = s.begin();
while(p !=s.end() && (*p<'0') || (*p>'9') )
p++;
s.erase(s.begin(), p);
m_version = StringUtils::splitToUInt(s, '.');
} // convertVersionString
public:
// ------------------------------------------------------------------------
/** Dummy default constructor. */
Version() {}
// ------------------------------------------------------------------------
/** Simple constructor which takes a string with "." separated numbers.
*/
Version(const std::string &version)
{
convertVersionString(version);
} // Version(std::string)
// ------------------------------------------------------------------------
/** Create a version instance from the driver and car name. For example for
* an Intel HD3000 card the string is "3.1.0 - Build 9.17.10.3517" it would
* create [9,17,10,3517] - i.e. it takes the vendor info into account.
* \param driver_version The GL_VERSION string (i.e. opengl and version
* number).
* \param card_name The GL_RENDERER string (i.e. graphics card).
*/
Version(const std::string &driver_version, const std::string &card_name)
{
m_version.clear();
// Intel card: driver version = "3.1.0 - Build 9.17.10.3517"
// ---------------------------------------------------------
if (StringUtils::startsWith(card_name, "Intel"))
{
std::vector<std::string> s = StringUtils::split(driver_version, '-');
if (s.size() == 2)
{
convertVersionString(s[1]);
return;
}
}
// Nvidia: driver_version = "4.3.0 NVIDIA 340.58"
// ----------------------------------------------
if (driver_version.find("NVIDIA") != std::string::npos)
{
std::vector<std::string> s = StringUtils::split(driver_version, ' ');
if (s.size() == 3)
{
convertVersionString(s[2]);
return;
}
}
Log::warn("Graphics", "Can not find version for '%s' '%s' - ignored.",
driver_version.c_str(), card_name.c_str());
} // Version
// ------------------------------------------------------------------------
/** Compares two version numbers. Equal returns true if the elements are
* identical up to the minimum number of elements, e.g.: [1.2.3] = [1.2].
* This allows so e.g. disable a feature for all minor versions by just
* specifying the major version.
*/
bool operator== (const Version &other) const
{
unsigned int min_n = std::min(m_version.size(), other.m_version.size());
for(unsigned int i=0; i<min_n; i++)
if(other.m_version[i]!=m_version[i]) return false;
return true;
} // operator ==
// ------------------------------------------------------------------------
bool operator< (const Version &other) const
{
unsigned int min_n = std::min(m_version.size(), other.m_version.size());
for(unsigned int i=0; i<min_n; i++)
if(other.m_version[i]>=m_version[i]) return false;
return true;
} // operator>
}; // class Version
// ============================================================================
class Rule : public NoCopy
{
private:
/** Operators to test for a card. */
enum {CARD_IS, CARD_CONTAINS} m_card_test;
/** Name of the card for which this rule applies. */
std::string m_card_name;
/** Operators to test version numbers with. */
enum {VERSION_IGNORE, VERSION_EQUAL, VERSION_LESS,
VERSION_LESS_EQUAL} m_version_test;
/** Driver version for which this rule applies. */
Version m_driver_version;
/** For which OS this rule applies. */
std::string m_os;
/** Which options to disable. */
std::vector<std::string> m_disable_options;
public:
Rule(const XMLNode *rule)
{
m_version_test = VERSION_IGNORE;
if(rule->get("is", &m_card_name))
{
m_card_test = CARD_IS;
}
else if(rule->get("contains", &m_card_name))
{
m_card_test = CARD_CONTAINS;
}
rule->get("os", &m_os);
std::string s;
if(rule->get("version", &s) && s.size()>1)
{
if(s.substr(0, 2)=="<=")
{
m_version_test = VERSION_LESS_EQUAL;
s = s.substr(2, s.size());
}
else if(s[0]=='<')
{
m_version_test = VERSION_LESS;
s.erase(s.begin());
}
else if(s[0]=='=')
{
m_version_test = VERSION_EQUAL;
s.erase(s.begin());
}
else
{
Log::warn("Graphics", "Invalid verison '%s' found - ignored.",
s.c_str());
}
m_driver_version = Version(s);
} // has version
if(rule->get("disable", &s))
m_disable_options = StringUtils::split(s, ' ');
} // Rule
// ------------------------------------------------------------------------
bool applies(const std::string &card, const Version &version) const
{
// Test for OS
// -----------
if(m_os.size()>0)
{
#ifdef __linux__
if(m_os!="linux") return false;
#endif
#ifdef WIN32
if(m_os!="windows") return false;
#endif
#ifdef __APPLE__
if(m_os!="osx") return false;
#endif
#ifdef BSD
if(m_os!="bsd") return false;
#endif
} // m_os.size()>0
// Test for card
// -------------
switch(m_card_test)
{
case CARD_IS:
if(card!=m_card_name) return false;
break;
case CARD_CONTAINS:
if(card.find(m_card_name)==std::string::npos)
return false;
break;
} // switch m_card_test
// Test for driver version
// -----------------------
switch(m_version_test)
{
case VERSION_IGNORE: break; // always true
case VERSION_EQUAL: if(!(version==m_driver_version)) return false;
break;
case VERSION_LESS_EQUAL:
if(m_driver_version < version) return false;
} // switch m_version_test
return true;
// -----------------------------------------------
}
// ------------------------------------------------------------------------
/** Returns a list of options to disable. */
const std::vector<std::string>& getRestrictions() const
{
return m_disable_options;
} // getRestrictions
// ------------------------------------------------------------------------
}; // class Rule
// ============================================================================
void init()
{
std::string filename =
file_manager->getUserConfigFile("graphical_restrictions.xml");
if(!file_manager->fileExists(filename))
filename = file_manager->getAsset("graphical_restrictions.xml");
const XMLNode *rules = file_manager->createXMLTree(filename);
if(!rules)
{
Log::warn("Graphics", "Could not find graphical_restrictions.xm");
return;
}
if(rules->getName()!="graphical-restrictions")
{
delete rules;
Log::warn("Graphics", "'%s' did not contain graphical-restrictions tag",
filename.c_str());
return;
}
for(unsigned int i=0; i<rules->getNumNodes(); i++)
{
const XMLNode *rule = rules->getNode(i);
if(rule->getName()!="card")
{
Log::warn("Graphics", "Incorrect node '%s' found in '%s' - ignored.",
rule->getName().c_str(), filename.c_str());
continue;
}
m_all_rules.push_back(new Rule(rule));
}
} // init
// ----------------------------------------------------------------------------
/** Returns a list of graphical features that need to be disabled for the
* specified driver and graphics card (and OS).
* \paaram driver_version The GL_VERSION string (i.e. opengl and version
* number).
* \param card_name The GL_RENDERER string (i.e. graphics card).
*/
std::vector<std::string> getRestrictions(const std::string &driver_version,
const std::string &card_name)
{
std::vector<std::string> restrictions;
Version version(driver_version, card_name);
for(unsigned int i=0; i<m_all_rules.size(); i++)
{
if(m_all_rules[i]->applies(card_name, version))
{
std::vector<std::string> r = m_all_rules[i]->getRestrictions();
restrictions.insert(restrictions.end(), r.begin(), r.end());
}
}
return restrictions;
} // getRestrictions
} // namespace HardwareStats