diff --git a/data/graphical_restrictions.xml b/data/graphical_restrictions.xml new file mode 100644 index 000000000..5771f722b --- /dev/null +++ b/data/graphical_restrictions.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/sources.cmake b/sources.cmake index 5b3d0c21e..0837c5629 100644 --- a/sources.cmake +++ b/sources.cmake @@ -1,5 +1,5 @@ # Modify this file to change the last-modified date when you add/remove a file. -# This will then trigger a new cmake run automatically. +# This will then trigger a new cmake run automatically. file(GLOB_RECURSE STK_HEADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.hpp") file(GLOB_RECURSE STK_SOURCES RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "src/*.cpp") file(GLOB_RECURSE STK_SHADERS RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "data/shaders/*") diff --git a/src/graphics/graphics_restrictions.cpp b/src/graphics/graphics_restrictions.cpp new file mode 100644 index 000000000..4e49e3e15 --- /dev/null +++ b/src/graphics/graphics_restrictions.cpp @@ -0,0 +1,308 @@ +// +// 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 + +namespace GraphicsRestrictions +{ + + class Rule; + namespace Private + { + std::vector 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 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 s = StringUtils::split(driver_version, '-'); + if (s.size() == 2) + { + convertVersionString(s[1]); + 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 + { + int min_n = std::min(m_version.size(), other.m_version.size()); + for(unsigned int i=0; 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 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& 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; igetNumNodes(); 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 getRestrictions(const std::string &driver_version, + const std::string &card_name) +{ + init(); + + std::vector restrictions; + + Version version(driver_version, card_name); + for(unsigned int i=0; iapplies(card_name, version)) + { + std::vector r = m_all_rules[i]->getRestrictions(); + restrictions.insert(restrictions.end(), r.begin(), r.end()); + } + } + return restrictions; +} // getRestrictions + +} // namespace HardwareStats diff --git a/src/graphics/graphics_restrictions.hpp b/src/graphics/graphics_restrictions.hpp new file mode 100644 index 000000000..681314a82 --- /dev/null +++ b/src/graphics/graphics_restrictions.hpp @@ -0,0 +1,35 @@ +// +// 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. + +#ifndef HEADER_GRAPHICS_RESTrICTIONS_HPP +#define HEADER_GRAPHICS_RESTrICTIONS_HPP + +/** + * \defgroup graphics + */ + +#include +#include + +namespace GraphicsRestrictions +{ + std::vector getRestrictions(const std::string &driver_version, + const std::string &card_name); +}; // HardwareStats + +#endif diff --git a/src/graphics/irr_driver.cpp b/src/graphics/irr_driver.cpp index 401c9a98e..04e5bd36b 100644 --- a/src/graphics/irr_driver.cpp +++ b/src/graphics/irr_driver.cpp @@ -23,6 +23,7 @@ #include "graphics/camera.hpp" #include "graphics/glwrap.hpp" #include "graphics/2dutils.hpp" +#include "graphics/graphics_restrictions.hpp" #include "graphics/hardware_skinning.hpp" #include "graphics/lens_flare.hpp" #include "graphics/light.hpp" @@ -475,6 +476,13 @@ void IrrDriver::initDevice() m_gl_minor_version = 1; // Call to glGetIntegerv should not be made if --no-graphics is used if(!ProfileWorld::isNoGraphics()) + { + std::string driver((char*)(glGetString(GL_VERSION))); + std::string card ((char*)(glGetString(GL_RENDERER))); + std::vector restrictions = + GraphicsRestrictions::getRestrictions(driver, card); + } + if(!ProfileWorld::isNoGraphics()) { glGetIntegerv(GL_MAJOR_VERSION, &m_gl_major_version); glGetIntegerv(GL_MINOR_VERSION, &m_gl_minor_version);