From bc859c4c597f106d40f07380bf255f180d565577 Mon Sep 17 00:00:00 2001 From: Piotr Dziwinski Date: Sun, 10 Mar 2013 15:44:21 +0100 Subject: VBO override option; argv parsing using getopt * added -vbo option to override autodetection of OpenGL VBO extension * refactored argument parsing to use getopt() * fixed failing UTs --- src/app/app.cpp | 246 +++++++++++++++++----------- src/app/app.h | 1 + src/common/logger.cpp | 82 ++++++++-- src/common/logger.h | 131 ++++++++------- src/graphics/opengl/gldevice.cpp | 25 ++- src/graphics/opengl/gldevice.h | 14 ++ test/unit/graphics/engine/lightman_test.cpp | 4 +- 7 files changed, 327 insertions(+), 176 deletions(-) diff --git a/src/app/app.cpp b/src/app/app.cpp index ae5ac88..cb1ac34 100644 --- a/src/app/app.cpp +++ b/src/app/app.cpp @@ -39,6 +39,7 @@ #include #include #include +#include #ifdef OPENAL_SOUND @@ -195,102 +196,131 @@ CEventQueue* CApplication::GetEventQueue() CSoundInterface* CApplication::GetSound() { return m_sound; + + for (int i = 0; i < PCNT_MAX; ++i) + { + DestroyTimeStamp(m_performanceCounters[i][0]); + DestroyTimeStamp(m_performanceCounters[i][1]); + } } ParseArgsStatus CApplication::ParseArguments(int argc, char *argv[]) { - bool waitDataDir = false; - bool waitLogLevel = false; - bool waitLanguage = false; - - for (int i = 1; i < argc; ++i) + enum OptionType { - std::string arg = argv[i]; - - if (waitDataDir) - { - waitDataDir = false; - m_dataPath = arg; - GetLogger()->Info("Using custom data dir: '%s'\n", m_dataPath.c_str()); - continue; - } - - if (waitLogLevel) + OPT_HELP = 1, + OPT_DEBUG, + OPT_DATADIR, + OPT_LOGLEVEL, + OPT_LANGUAGE, + OPT_VBO + }; + + option options[] = + { + { "help", no_argument, nullptr, OPT_HELP }, + { "debug", no_argument, nullptr, OPT_DEBUG }, + { "datadir", required_argument, nullptr, OPT_DATADIR }, + { "loglevel", required_argument, nullptr, OPT_LOGLEVEL }, + { "language", required_argument, nullptr, OPT_LANGUAGE }, + { "vbo", required_argument, nullptr, OPT_VBO } + }; + + opterr = 0; + + int c = 0; + int index = -1; + while ((c = getopt_long_only(argc, argv, "", options, &index)) != -1) + { + if (c == '?') { - waitLogLevel = false; - if (arg == "trace") - GetLogger()->SetLogLevel(LOG_TRACE); - else if (arg == "debug") - GetLogger()->SetLogLevel(LOG_DEBUG); - else if (arg == "info") - GetLogger()->SetLogLevel(LOG_INFO); - else if (arg == "warn") - GetLogger()->SetLogLevel(LOG_WARN); - else if (arg == "error") - GetLogger()->SetLogLevel(LOG_ERROR); - else if (arg == "none") - GetLogger()->SetLogLevel(LOG_NONE); + if (optopt == 0) + GetLogger()->Error("Invalid argument: %s\n", argv[optind-1]); else - return PARSE_ARGS_FAIL; - continue; - } + GetLogger()->Error("Expected argument for option: %s\n", argv[optind-1]); - if (waitLanguage) - { - waitLanguage = false; - if (arg == "en") - m_language = LANGUAGE_ENGLISH; - else if (arg == "de") - m_language = LANGUAGE_GERMAN; - else if (arg == "fr") - m_language = LANGUAGE_FRENCH; - else if (arg == "pl") - m_language = LANGUAGE_POLISH; - else - return PARSE_ARGS_FAIL; - continue; + m_exitCode = 1; + return PARSE_ARGS_FAIL; } - if (arg == "-debug") - { - SetDebugMode(true); - } - else if (arg == "-loglevel") - { - waitLogLevel = true; - } - else if (arg == "-datadir") - { - waitDataDir = true; - } - else if (arg == "-language") - { - waitLanguage = true; - } - else if (arg == "-help") - { - GetLogger()->Message("\n"); - GetLogger()->Message("Colobot %s (%s)\n",COLOBOT_CODENAME,COLOBOT_VERSION); - GetLogger()->Message("\n"); - GetLogger()->Message("List of available options:\n"); - GetLogger()->Message(" -help this help\n"); - GetLogger()->Message(" -datadir path set custom data directory path\n"); - GetLogger()->Message(" -debug enable debug mode (more info printed in logs)\n"); - GetLogger()->Message(" -loglevel level set log level to level (one of: trace, debug, info, warn, error, none)\n"); - GetLogger()->Message(" -language lang set language (one of: en, de, fr, pl)\n"); - return PARSE_ARGS_HELP; - } - else + index = -1; + + switch (c) { - m_exitCode = 1; - return PARSE_ARGS_FAIL; + case OPT_HELP: + { + GetLogger()->Message("\n"); + GetLogger()->Message("Colobot %s (%s)\n", COLOBOT_CODENAME, COLOBOT_VERSION); + GetLogger()->Message("\n"); + GetLogger()->Message("List of available options:\n"); + GetLogger()->Message(" -help this help\n"); + GetLogger()->Message(" -debug enable debug mode (more info printed in logs)\n"); + GetLogger()->Message(" -datadir path set custom data directory path\n"); + GetLogger()->Message(" -loglevel level set log level to level (one of: trace, debug, info, warn, error, none)\n"); + GetLogger()->Message(" -language lang set language (one of: en, de, fr, pl)\n"); + GetLogger()->Message(" -vbo mode set OpenGL VBO mode (one of: auto, enable, disable)\n"); + return PARSE_ARGS_HELP; + } + case OPT_DEBUG: + { + SetDebugMode(true); + break; + } + case OPT_DATADIR: + { + m_dataPath = optarg; + GetLogger()->Info("Using custom data dir: '%s'\n", m_dataPath.c_str()); + break; + } + case OPT_LOGLEVEL: + { + LogLevel logLevel; + if (! CLogger::ParseLogLevel(optarg, logLevel)) + { + GetLogger()->Error("Invalid log level: \"%s\"\n", optarg); + return PARSE_ARGS_FAIL; + } + + GetLogger()->Message("[*****] Log level changed to %s\n", optarg); + GetLogger()->SetLogLevel(logLevel); + break; + } + case OPT_LANGUAGE: + { + Language language; + if (! ParseLanguage(optarg, language)) + { + GetLogger()->Error("Invalid language: \"%s\"\n", optarg); + return PARSE_ARGS_FAIL; + } + + GetLogger()->Info("Using language %s\n", optarg); + m_language = language; + break; + } + case OPT_VBO: + { + std::string vbo; + vbo = optarg; + if (vbo == "auto") + m_deviceConfig.vboMode = Gfx::VBO_MODE_AUTO; + else if (vbo == "enable") + m_deviceConfig.vboMode = Gfx::VBO_MODE_ENABLE; + else if (vbo == "disable") + m_deviceConfig.vboMode = Gfx::VBO_MODE_DISABLE; + else + { + GetLogger()->Error("Invalid vbo mode: \"%s\"\n", optarg); + return PARSE_ARGS_FAIL; + } + + break; + } + default: + assert(false); // should never get here } } - // Args not given? - if (waitDataDir || waitLogLevel || waitLanguage) - return PARSE_ARGS_FAIL; - return PARSE_ARGS_OK; } @@ -336,7 +366,7 @@ bool CApplication::Create() } else { m_sound->CacheAll(GetDataSubdirPath(DIR_SOUND)); } - + if (GetProfile().GetLocalProfileString("Resources", "Music", path)) { m_sound->AddMusicFiles(path); } else { @@ -376,20 +406,22 @@ bool CApplication::Create() m_exitCode = 3; return false; } - + // load settings from profile int iValue; - if ( GetProfile().GetLocalProfileInt("Setup", "Resolution", iValue) ) { - std::vector modes; - GetVideoResolutionList(modes, true, true); - if (static_cast(iValue) < modes.size()) - m_deviceConfig.size = modes.at(iValue); + if ( GetProfile().GetLocalProfileInt("Setup", "Resolution", iValue) ) + { + std::vector modes; + GetVideoResolutionList(modes, true, true); + if (static_cast(iValue) < modes.size()) + m_deviceConfig.size = modes.at(iValue); } - - if ( GetProfile().GetLocalProfileInt("Setup", "Fullscreen", iValue) ) { - m_deviceConfig.fullScreen = (iValue == 1); + + if ( GetProfile().GetLocalProfileInt("Setup", "Fullscreen", iValue) ) + { + m_deviceConfig.fullScreen = (iValue == 1); } - + if (! CreateVideoSurface()) return false; // dialog is in function @@ -409,7 +441,7 @@ bool CApplication::Create() // Don't generate joystick events SDL_JoystickEventState(SDL_IGNORE); - + // The video is ready, we can create and initalize the graphics device m_device = new Gfx::CGLDevice(m_deviceConfig); if (! m_device->Create() ) @@ -1503,6 +1535,32 @@ char CApplication::GetLanguageChar() return langChar; } +bool CApplication::ParseLanguage(const std::string& str, Language& language) +{ + if (str == "en") + { + language = LANGUAGE_ENGLISH; + return true; + } + else if (str == "de") + { + language = LANGUAGE_GERMAN; + return true; + } + else if (str == "fr") + { + language = LANGUAGE_FRENCH; + return true; + } + else if (str == "pl") + { + language = LANGUAGE_POLISH; + return true; + } + + return false; +} + void CApplication::SetLanguage(Language language) { m_language = language; diff --git a/src/app/app.h b/src/app/app.h index f3f5601..71a3527 100644 --- a/src/app/app.h +++ b/src/app/app.h @@ -327,6 +327,7 @@ public: Language GetLanguage(); char GetLanguageChar(); void SetLanguage(Language language); + static bool ParseLanguage(const std::string& str, Language& language); //@} //! Management of sleep in main loop (lowers CPU usage) diff --git a/src/common/logger.cpp b/src/common/logger.cpp index 3ec9746..8bc4cef 100644 --- a/src/common/logger.cpp +++ b/src/common/logger.cpp @@ -36,25 +36,37 @@ CLogger::~CLogger() } -void CLogger::Log(LogType type, const char *str, va_list args) +void CLogger::Log(LogLevel type, const char* str, va_list args) { if (type < mLogLevel) return; - switch (type) { - case LOG_TRACE: fprintf(IsOpened() ? mFile : stderr, "[TRACE]: "); break; - case LOG_DEBUG: fprintf(IsOpened() ? mFile : stderr, "[DEBUG]: "); break; - case LOG_WARN: fprintf(IsOpened() ? mFile : stderr, "[WARN]: "); break; - case LOG_INFO: fprintf(IsOpened() ? mFile : stderr, "[INFO]: "); break; - case LOG_ERROR: fprintf(IsOpened() ? mFile : stderr, "[ERROR]: "); break; - default: break; + switch (type) + { + case LOG_TRACE: + fprintf(IsOpened() ? mFile : stderr, "[TRACE]: "); + break; + case LOG_DEBUG: + fprintf(IsOpened() ? mFile : stderr, "[DEBUG]: "); + break; + case LOG_WARN: + fprintf(IsOpened() ? mFile : stderr, "[WARN]: "); + break; + case LOG_INFO: + fprintf(IsOpened() ? mFile : stderr, "[INFO]: "); + break; + case LOG_ERROR: + fprintf(IsOpened() ? mFile : stderr, "[ERROR]: "); + break; + default: + break; } vfprintf(IsOpened() ? mFile : stderr, str, args); } -void CLogger::Trace(const char *str, ...) +void CLogger::Trace(const char* str, ...) { va_list args; va_start(args, str); @@ -63,7 +75,7 @@ void CLogger::Trace(const char *str, ...) } -void CLogger::Debug(const char *str, ...) +void CLogger::Debug(const char* str, ...) { va_list args; va_start(args, str); @@ -72,7 +84,7 @@ void CLogger::Debug(const char *str, ...) } -void CLogger::Info(const char *str, ...) +void CLogger::Info(const char* str, ...) { va_list args; va_start(args, str); @@ -81,7 +93,7 @@ void CLogger::Info(const char *str, ...) } -void CLogger::Warn(const char *str, ...) +void CLogger::Warn(const char* str, ...) { va_list args; va_start(args, str); @@ -90,7 +102,7 @@ void CLogger::Warn(const char *str, ...) } -void CLogger::Error(const char *str, ...) +void CLogger::Error(const char* str, ...) { va_list args; va_start(args, str); @@ -99,7 +111,7 @@ void CLogger::Error(const char *str, ...) } -void CLogger::Message(const char *str, ...) +void CLogger::Message(const char* str, ...) { va_list args; va_start(args, str); @@ -118,6 +130,7 @@ void CLogger::SetOutputFile(std::string filename) void CLogger::Open() { mFile = fopen(mFilename.c_str(), "w"); + if (mFile == NULL) fprintf(stderr, "Could not create file %s\n", mFilename.c_str()); } @@ -136,6 +149,45 @@ bool CLogger::IsOpened() } -void CLogger::SetLogLevel(LogType type) { +void CLogger::SetLogLevel(LogLevel type) +{ mLogLevel = type; } + + +bool CLogger::ParseLogLevel(const std::string& str, LogLevel& logLevel) +{ + if (str == "trace") + { + logLevel = LOG_TRACE; + return true; + } + else if (str == "debug") + { + logLevel = LOG_DEBUG; + return true; + } + else if (str == "info") + { + logLevel = LOG_INFO; + return true; + } + else if (str == "warn") + { + logLevel = LOG_WARN; + return true; + } + else if (str == "error") + { + logLevel = LOG_ERROR; + return true; + } + else if (str == "none") + { + logLevel = LOG_NONE; + return true; + } + + return false; +} + diff --git a/src/common/logger.h b/src/common/logger.h index 198e5e5..769f548 100644 --- a/src/common/logger.h +++ b/src/common/logger.h @@ -31,10 +31,10 @@ /** * \public - * \enum LogType common/logger.h + * \enum LogLevel common/logger.h * \brief Enum representing log level **/ -enum LogType +enum LogLevel { LOG_TRACE = 1, /*!< lowest level, execution tracing */ LOG_DEBUG = 2, /*!< debugging messages */ @@ -53,65 +53,74 @@ enum LogType */ class CLogger : public CSingleton { - public: - CLogger(); - ~CLogger(); - - /** Write message to console or file - * \param str - message to write - * \param ... - additional arguments - */ - void Message(const char *str, ...); - - /** Write message to console or file with LOG_TRACE level - * \param str - message to write - * \param ... - additional arguments - */ - void Trace(const char *str, ...); - - /** Write message to console or file with LOG_DEBUG level - * \param str - message to write - * \param ... - additional arguments - */ - void Debug(const char *str, ...); - - /** Write message to console or file with LOG_INFO level - * \param str - message to write - * \param ... - additional arguments - */ - void Info(const char *str, ...); - - /** Write message to console or file with LOG_WARN level - * \param str - message to write - * \param ... - additional arguments - */ - void Warn(const char *str, ...); - - /** Write message to console or file with LOG_ERROR level - * \param str - message to write - * \param ... - additional arguments - */ - void Error(const char *str, ...); - - /** Set output file to write logs to - * \param filename - output file to write to - */ - void SetOutputFile(std::string filename); - - /** Set log level. Logs with level below will not be shown - * \param level - minimum log level to write - */ - void SetLogLevel(LogType level); - - private: - std::string mFilename; - FILE *mFile; - LogType mLogLevel; - - void Open(); - void Close(); - bool IsOpened(); - void Log(LogType type, const char* str, va_list args); +public: + CLogger(); + ~CLogger(); + + /** Write message to console or file + * \param str - message to write + * \param ... - additional arguments + */ + void Message(const char *str, ...); + + /** Write message to console or file with LOG_TRACE level + * \param str - message to write + * \param ... - additional arguments + */ + void Trace(const char *str, ...); + + /** Write message to console or file with LOG_DEBUG level + * \param str - message to write + * \param ... - additional arguments + */ + void Debug(const char *str, ...); + + /** Write message to console or file with LOG_INFO level + * \param str - message to write + * \param ... - additional arguments + */ + void Info(const char *str, ...); + + /** Write message to console or file with LOG_WARN level + * \param str - message to write + * \param ... - additional arguments + */ + void Warn(const char *str, ...); + + /** Write message to console or file with LOG_ERROR level + * \param str - message to write + * \param ... - additional arguments + */ + void Error(const char *str, ...); + + /** Set output file to write logs to + * \param filename - output file to write to + */ + void SetOutputFile(std::string filename); + + /** Set log level. Logs with level below will not be shown + * \param level - minimum log level to write + */ + void SetLogLevel(LogLevel level); + + /** Parses string as a log level + * \param str string to parse + * \param logLevel result log level + * + * Valid values are "trace", "debug", "info", "warn", "error" and "none". + * On invalid value, returns \c false. + */ + static bool ParseLogLevel(const std::string& str, LogLevel& logLevel); + +private: + std::string mFilename; + FILE *mFile; + LogLevel mLogLevel; + + void Open(); + void Close(); + bool IsOpened(); + void Log(LogLevel type, const char* str, va_list args); }; diff --git a/src/graphics/opengl/gldevice.cpp b/src/graphics/opengl/gldevice.cpp index 80fa9a1..beeb85e 100644 --- a/src/graphics/opengl/gldevice.cpp +++ b/src/graphics/opengl/gldevice.cpp @@ -51,6 +51,8 @@ void GLDeviceConfig::LoadDefault() greenSize = 8; alphaSize = 8; depthSize = 24; + + vboMode = VBO_MODE_AUTO; } @@ -99,11 +101,26 @@ bool CGLDevice::Create() if (!m_multitextureAvailable) GetLogger()->Warn("GLEW reports multitexturing not supported - graphics quality will be degraded!\n"); - m_vboAvailable = glewIsSupported("GL_ARB_vertex_buffer_object"); - if (m_vboAvailable) - GetLogger()->Info("Detected ARB_vertex_buffer_object extension - using VBOs\n"); + if (m_config.vboMode == VBO_MODE_ENABLE) + { + GetLogger()->Info("VBO enabled by override - using VBOs\n"); + m_vboAvailable = true; + } + else if (m_config.vboMode == VBO_MODE_DISABLE) + { + GetLogger()->Info("VBO disabled by override - using display lists\n"); + m_vboAvailable = false; + } else - GetLogger()->Info("No ARB_vertex_buffer_object extension present - using display lists\n"); + { + GetLogger()->Info("Auto-detecting VBO support\n"); + m_vboAvailable = glewIsSupported("GL_ARB_vertex_buffer_object"); + + if (m_vboAvailable) + GetLogger()->Info("Detected ARB_vertex_buffer_object extension - using VBOs\n"); + else + GetLogger()->Info("No ARB_vertex_buffer_object extension present - using display lists\n"); + } } // This is mostly done in all modern hardware by default diff --git a/src/graphics/opengl/gldevice.h b/src/graphics/opengl/gldevice.h index 7137671..fe3f2a1 100644 --- a/src/graphics/opengl/gldevice.h +++ b/src/graphics/opengl/gldevice.h @@ -33,6 +33,17 @@ // Graphics module namespace namespace Gfx { +/** + \enum VBOMode + \brief VBO autodetect/override + */ +enum VBOMode +{ + VBO_MODE_ENABLE, //! < override: enable + VBO_MODE_DISABLE, //! < override: disable + VBO_MODE_AUTO //! < autodetect +}; + /** \struct GLDeviceConfig \brief Additional config with OpenGL-specific settings */ @@ -52,6 +63,9 @@ struct GLDeviceConfig : public DeviceConfig //! Force hardware acceleration (video mode set will fail on lack of hw accel) bool hardwareAccel; + //! VBO override/autodetect + VBOMode vboMode; + //! Constructor calls LoadDefaults() GLDeviceConfig(); diff --git a/test/unit/graphics/engine/lightman_test.cpp b/test/unit/graphics/engine/lightman_test.cpp index b20b058..c955f0a 100644 --- a/test/unit/graphics/engine/lightman_test.cpp +++ b/test/unit/graphics/engine/lightman_test.cpp @@ -110,7 +110,7 @@ TEST_F(LightManagerUT, LightSorting_IncludeTypesAreIncluded) AddLight(2, LIGHT_PRI_LOW, true, true, Math::Vector(0.0f, 0.0f, 0.0f), ENG_OBJTYPE_TERRAIN, ENG_OBJTYPE_NULL); AddLight(3, LIGHT_PRI_LOW, true, true, Math::Vector(0.0f, 0.0f, 0.0f), ENG_OBJTYPE_QUARTZ, ENG_OBJTYPE_NULL); - std::vector expectedLights = { 2, 1 }; + std::vector expectedLights = { 1, 2 }; CheckLightSorting(ENG_OBJTYPE_TERRAIN, expectedLights); } @@ -124,7 +124,7 @@ TEST_F(LightManagerUT, LightSorting_ExcludeTypesAreExcluded) AddLight(2, LIGHT_PRI_LOW, true, true, Math::Vector(0.0f, 0.0f, 0.0f), ENG_OBJTYPE_NULL, ENG_OBJTYPE_TERRAIN); AddLight(3, LIGHT_PRI_LOW, true, true, Math::Vector(0.0f, 0.0f, 0.0f), ENG_OBJTYPE_NULL, ENG_OBJTYPE_QUARTZ); - std::vector expectedLights = { 3, 1 }; + std::vector expectedLights = { 1, 3 }; CheckLightSorting(ENG_OBJTYPE_TERRAIN, expectedLights); } -- cgit v1.2.3-1-g7c22