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
dev-ui
Piotr Dziwinski 2013-03-10 15:44:21 +01:00
parent 1f565fdf38
commit bc859c4c59
7 changed files with 316 additions and 165 deletions

View File

@ -39,6 +39,7 @@
#include <stdlib.h> #include <stdlib.h>
#include <libintl.h> #include <libintl.h>
#include <unistd.h> #include <unistd.h>
#include <getopt.h>
#ifdef OPENAL_SOUND #ifdef OPENAL_SOUND
@ -195,101 +196,130 @@ CEventQueue* CApplication::GetEventQueue()
CSoundInterface* CApplication::GetSound() CSoundInterface* CApplication::GetSound()
{ {
return m_sound; 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[]) ParseArgsStatus CApplication::ParseArguments(int argc, char *argv[])
{ {
bool waitDataDir = false; enum OptionType
bool waitLogLevel = false;
bool waitLanguage = false;
for (int i = 1; i < argc; ++i)
{ {
std::string arg = argv[i]; OPT_HELP = 1,
OPT_DEBUG,
OPT_DATADIR,
OPT_LOGLEVEL,
OPT_LANGUAGE,
OPT_VBO
};
if (waitDataDir) option options[] =
{ {
waitDataDir = false; { "help", no_argument, nullptr, OPT_HELP },
m_dataPath = arg; { "debug", no_argument, nullptr, OPT_DEBUG },
GetLogger()->Info("Using custom data dir: '%s'\n", m_dataPath.c_str()); { "datadir", required_argument, nullptr, OPT_DATADIR },
continue; { "loglevel", required_argument, nullptr, OPT_LOGLEVEL },
} { "language", required_argument, nullptr, OPT_LANGUAGE },
{ "vbo", required_argument, nullptr, OPT_VBO }
};
if (waitLogLevel) opterr = 0;
int c = 0;
int index = -1;
while ((c = getopt_long_only(argc, argv, "", options, &index)) != -1)
{
if (c == '?')
{ {
waitLogLevel = false; if (optopt == 0)
if (arg == "trace") GetLogger()->Error("Invalid argument: %s\n", argv[optind-1]);
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);
else else
return PARSE_ARGS_FAIL; GetLogger()->Error("Expected argument for option: %s\n", argv[optind-1]);
continue;
}
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;
}
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
{
m_exitCode = 1; m_exitCode = 1;
return PARSE_ARGS_FAIL; return PARSE_ARGS_FAIL;
} }
}
// Args not given? index = -1;
if (waitDataDir || waitLogLevel || waitLanguage)
return PARSE_ARGS_FAIL; switch (c)
{
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
}
}
return PARSE_ARGS_OK; return PARSE_ARGS_OK;
} }
@ -336,7 +366,7 @@ bool CApplication::Create()
} else { } else {
m_sound->CacheAll(GetDataSubdirPath(DIR_SOUND)); m_sound->CacheAll(GetDataSubdirPath(DIR_SOUND));
} }
if (GetProfile().GetLocalProfileString("Resources", "Music", path)) { if (GetProfile().GetLocalProfileString("Resources", "Music", path)) {
m_sound->AddMusicFiles(path); m_sound->AddMusicFiles(path);
} else { } else {
@ -376,20 +406,22 @@ bool CApplication::Create()
m_exitCode = 3; m_exitCode = 3;
return false; return false;
} }
// load settings from profile // load settings from profile
int iValue; int iValue;
if ( GetProfile().GetLocalProfileInt("Setup", "Resolution", iValue) ) { if ( GetProfile().GetLocalProfileInt("Setup", "Resolution", iValue) )
std::vector<Math::IntPoint> modes; {
GetVideoResolutionList(modes, true, true); std::vector<Math::IntPoint> modes;
if (static_cast<unsigned int>(iValue) < modes.size()) GetVideoResolutionList(modes, true, true);
m_deviceConfig.size = modes.at(iValue); if (static_cast<unsigned int>(iValue) < modes.size())
m_deviceConfig.size = modes.at(iValue);
} }
if ( GetProfile().GetLocalProfileInt("Setup", "Fullscreen", iValue) ) { if ( GetProfile().GetLocalProfileInt("Setup", "Fullscreen", iValue) )
m_deviceConfig.fullScreen = (iValue == 1); {
m_deviceConfig.fullScreen = (iValue == 1);
} }
if (! CreateVideoSurface()) if (! CreateVideoSurface())
return false; // dialog is in function return false; // dialog is in function
@ -409,7 +441,7 @@ bool CApplication::Create()
// Don't generate joystick events // Don't generate joystick events
SDL_JoystickEventState(SDL_IGNORE); SDL_JoystickEventState(SDL_IGNORE);
// The video is ready, we can create and initalize the graphics device // The video is ready, we can create and initalize the graphics device
m_device = new Gfx::CGLDevice(m_deviceConfig); m_device = new Gfx::CGLDevice(m_deviceConfig);
if (! m_device->Create() ) if (! m_device->Create() )
@ -1503,6 +1535,32 @@ char CApplication::GetLanguageChar()
return langChar; 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) void CApplication::SetLanguage(Language language)
{ {
m_language = language; m_language = language;

View File

@ -327,6 +327,7 @@ public:
Language GetLanguage(); Language GetLanguage();
char GetLanguageChar(); char GetLanguageChar();
void SetLanguage(Language language); void SetLanguage(Language language);
static bool ParseLanguage(const std::string& str, Language& language);
//@} //@}
//! Management of sleep in main loop (lowers CPU usage) //! Management of sleep in main loop (lowers CPU usage)

View File

@ -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) if (type < mLogLevel)
return; return;
switch (type) { switch (type)
case LOG_TRACE: fprintf(IsOpened() ? mFile : stderr, "[TRACE]: "); break; {
case LOG_DEBUG: fprintf(IsOpened() ? mFile : stderr, "[DEBUG]: "); break; case LOG_TRACE:
case LOG_WARN: fprintf(IsOpened() ? mFile : stderr, "[WARN]: "); break; fprintf(IsOpened() ? mFile : stderr, "[TRACE]: ");
case LOG_INFO: fprintf(IsOpened() ? mFile : stderr, "[INFO]: "); break; break;
case LOG_ERROR: fprintf(IsOpened() ? mFile : stderr, "[ERROR]: "); break; case LOG_DEBUG:
default: break; 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); vfprintf(IsOpened() ? mFile : stderr, str, args);
} }
void CLogger::Trace(const char *str, ...) void CLogger::Trace(const char* str, ...)
{ {
va_list args; va_list args;
va_start(args, str); 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_list args;
va_start(args, str); 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_list args;
va_start(args, str); 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_list args;
va_start(args, str); 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_list args;
va_start(args, str); 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_list args;
va_start(args, str); va_start(args, str);
@ -118,6 +130,7 @@ void CLogger::SetOutputFile(std::string filename)
void CLogger::Open() void CLogger::Open()
{ {
mFile = fopen(mFilename.c_str(), "w"); mFile = fopen(mFilename.c_str(), "w");
if (mFile == NULL) if (mFile == NULL)
fprintf(stderr, "Could not create file %s\n", mFilename.c_str()); 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; 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;
}

View File

@ -31,10 +31,10 @@
/** /**
* \public * \public
* \enum LogType common/logger.h * \enum LogLevel common/logger.h
* \brief Enum representing log level * \brief Enum representing log level
**/ **/
enum LogType enum LogLevel
{ {
LOG_TRACE = 1, /*!< lowest level, execution tracing */ LOG_TRACE = 1, /*!< lowest level, execution tracing */
LOG_DEBUG = 2, /*!< debugging messages */ LOG_DEBUG = 2, /*!< debugging messages */
@ -53,65 +53,74 @@ enum LogType
*/ */
class CLogger : public CSingleton<CLogger> class CLogger : public CSingleton<CLogger>
{ {
public: public:
CLogger(); CLogger();
~CLogger(); ~CLogger();
/** Write message to console or file /** Write message to console or file
* \param str - message to write * \param str - message to write
* \param ... - additional arguments * \param ... - additional arguments
*/ */
void Message(const char *str, ...); void Message(const char *str, ...);
/** Write message to console or file with LOG_TRACE level /** Write message to console or file with LOG_TRACE level
* \param str - message to write * \param str - message to write
* \param ... - additional arguments * \param ... - additional arguments
*/ */
void Trace(const char *str, ...); void Trace(const char *str, ...);
/** Write message to console or file with LOG_DEBUG level /** Write message to console or file with LOG_DEBUG level
* \param str - message to write * \param str - message to write
* \param ... - additional arguments * \param ... - additional arguments
*/ */
void Debug(const char *str, ...); void Debug(const char *str, ...);
/** Write message to console or file with LOG_INFO level /** Write message to console or file with LOG_INFO level
* \param str - message to write * \param str - message to write
* \param ... - additional arguments * \param ... - additional arguments
*/ */
void Info(const char *str, ...); void Info(const char *str, ...);
/** Write message to console or file with LOG_WARN level /** Write message to console or file with LOG_WARN level
* \param str - message to write * \param str - message to write
* \param ... - additional arguments * \param ... - additional arguments
*/ */
void Warn(const char *str, ...); void Warn(const char *str, ...);
/** Write message to console or file with LOG_ERROR level /** Write message to console or file with LOG_ERROR level
* \param str - message to write * \param str - message to write
* \param ... - additional arguments * \param ... - additional arguments
*/ */
void Error(const char *str, ...); void Error(const char *str, ...);
/** Set output file to write logs to /** Set output file to write logs to
* \param filename - output file to write to * \param filename - output file to write to
*/ */
void SetOutputFile(std::string filename); void SetOutputFile(std::string filename);
/** Set log level. Logs with level below will not be shown /** Set log level. Logs with level below will not be shown
* \param level - minimum log level to write * \param level - minimum log level to write
*/ */
void SetLogLevel(LogType level); void SetLogLevel(LogLevel level);
private: /** Parses string as a log level
std::string mFilename; * \param str string to parse
FILE *mFile; * \param logLevel result log level
LogType mLogLevel; *
* 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);
void Open(); private:
void Close(); std::string mFilename;
bool IsOpened(); FILE *mFile;
void Log(LogType type, const char* str, va_list args); LogLevel mLogLevel;
void Open();
void Close();
bool IsOpened();
void Log(LogLevel type, const char* str, va_list args);
}; };

View File

@ -51,6 +51,8 @@ void GLDeviceConfig::LoadDefault()
greenSize = 8; greenSize = 8;
alphaSize = 8; alphaSize = 8;
depthSize = 24; depthSize = 24;
vboMode = VBO_MODE_AUTO;
} }
@ -99,11 +101,26 @@ bool CGLDevice::Create()
if (!m_multitextureAvailable) if (!m_multitextureAvailable)
GetLogger()->Warn("GLEW reports multitexturing not supported - graphics quality will be degraded!\n"); GetLogger()->Warn("GLEW reports multitexturing not supported - graphics quality will be degraded!\n");
m_vboAvailable = glewIsSupported("GL_ARB_vertex_buffer_object"); if (m_config.vboMode == VBO_MODE_ENABLE)
if (m_vboAvailable) {
GetLogger()->Info("Detected ARB_vertex_buffer_object extension - using VBOs\n"); 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 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 // This is mostly done in all modern hardware by default

View File

@ -33,6 +33,17 @@
// Graphics module namespace // Graphics module namespace
namespace Gfx { 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 \struct GLDeviceConfig
\brief Additional config with OpenGL-specific settings */ \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) //! Force hardware acceleration (video mode set will fail on lack of hw accel)
bool hardwareAccel; bool hardwareAccel;
//! VBO override/autodetect
VBOMode vboMode;
//! Constructor calls LoadDefaults() //! Constructor calls LoadDefaults()
GLDeviceConfig(); GLDeviceConfig();

View File

@ -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(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); AddLight(3, LIGHT_PRI_LOW, true, true, Math::Vector(0.0f, 0.0f, 0.0f), ENG_OBJTYPE_QUARTZ, ENG_OBJTYPE_NULL);
std::vector<int> expectedLights = { 2, 1 }; std::vector<int> expectedLights = { 1, 2 };
CheckLightSorting(ENG_OBJTYPE_TERRAIN, expectedLights); 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(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); AddLight(3, LIGHT_PRI_LOW, true, true, Math::Vector(0.0f, 0.0f, 0.0f), ENG_OBJTYPE_NULL, ENG_OBJTYPE_QUARTZ);
std::vector<int> expectedLights = { 3, 1 }; std::vector<int> expectedLights = { 1, 3 };
CheckLightSorting(ENG_OBJTYPE_TERRAIN, expectedLights); CheckLightSorting(ENG_OBJTYPE_TERRAIN, expectedLights);
} }