diff options
author | Didier Raboud <odyx@debian.org> | 2013-03-22 10:13:08 +0100 |
---|---|---|
committer | Didier Raboud <odyx@debian.org> | 2013-03-22 10:13:28 +0100 |
commit | 79029d635c9d024f2086b8b15bb6f8e7ae860d88 (patch) | |
tree | 7198d0ab39d0c3ab3f08995b8eaeacd5563c1531 | |
parent | d9eedf77a11745dbf3c2463236744ca9d7b4f361 (diff) | |
parent | 1406464f0ce0b804298e2ee034bdd8bc7856e0dc (diff) | |
download | colobot-79029d635c9d024f2086b8b15bb6f8e7ae860d88.tar.gz colobot-79029d635c9d024f2086b8b15bb6f8e7ae860d88.tar.bz2 colobot-79029d635c9d024f2086b8b15bb6f8e7ae860d88.zip |
Merge branch 'dev' into debian
46 files changed, 1590 insertions, 891 deletions
diff --git a/debian/changelog b/debian/changelog index 1a0910e..75ca998 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,4 +1,4 @@ -colobot (0.1.0~pre-alpha-git-dev~r3a594dc-1~OdyX0) UNRELEASED; urgency=low +colobot (0.1.0~pre-alpha-git-dev~r1406464-1~OdyX0) UNRELEASED; urgency=low * Initial release. (Closes: #695829) diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index e6b3acd..cc181f2 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -55,11 +55,21 @@ if (${OPENAL_SOUND}) ) endif() +# Platform-dependent implementation of system.h +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(SYSTEM_CPP_MODULE "system_windows.cpp") +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(SYSTEM_CPP_MODULE "system_linux.cpp") +else() + set(SYSTEM_CPP_MODULE "system_other.cpp") +endif() + # Source files set(SOURCES app/app.cpp app/main.cpp app/system.cpp +app/${SYSTEM_CPP_MODULE} common/event.cpp common/image.cpp common/iman.cpp 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 <stdlib.h> #include <libintl.h> #include <unistd.h> +#include <getopt.h> #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<Math::IntPoint> modes; - GetVideoResolutionList(modes, true, true); - if (static_cast<unsigned int>(iValue) < modes.size()) - m_deviceConfig.size = modes.at(iValue); + if ( GetProfile().GetLocalProfileInt("Setup", "Resolution", iValue) ) + { + std::vector<Math::IntPoint> modes; + GetVideoResolutionList(modes, true, true); + if (static_cast<unsigned int>(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/app/system_linux.cpp b/src/app/system_linux.cpp new file mode 100644 index 0000000..cd785f8 --- /dev/null +++ b/src/app/system_linux.cpp @@ -0,0 +1,79 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * 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, see http://www.gnu.org/licenses/. + +#include "app/system_linux.h" + +#include <stdlib.h> + + +SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string& title, const std::string& message) +{ + std::string options = ""; + switch (type) + { + case SDT_INFO: + default: + options = "--info"; + break; + case SDT_WARNING: + options = "--warning"; + break; + case SDT_ERROR: + options = "--error"; + break; + case SDT_YES_NO: + options = "--question --ok-label=\"Yes\" --cancel-label=\"No\""; + break; + case SDT_OK_CANCEL: + options = "--question --ok-label=\"OK\" --cancel-label=\"Cancel\""; + break; + } + + std::string command = "zenity " + options + " --text=\"" + message + "\" --title=\"" + title + "\""; + int code = system(command.c_str()); + + SystemDialogResult result = SDR_OK; + switch (type) + { + case SDT_YES_NO: + result = code ? SDR_NO : SDR_YES; + break; + case SDT_OK_CANCEL: + result = code ? SDR_CANCEL : SDR_OK; + break; + default: + break; + } + + return result; +} + +void GetCurrentTimeStamp_Linux(SystemTimeStamp *stamp) +{ + clock_gettime(CLOCK_MONOTONIC_RAW, &stamp->clockTime); +} + +long long GetTimeStampExactResolution_Linux() +{ + return 1ll; +} + +long long TimeStampExactDiff_Linux(SystemTimeStamp *before, SystemTimeStamp *after) +{ + return (after->clockTime.tv_nsec - before->clockTime.tv_nsec) + + (after->clockTime.tv_sec - before->clockTime.tv_sec) * 1000000000ll; +} diff --git a/src/app/system_linux.h b/src/app/system_linux.h index 69893de..bc07c31 100644 --- a/src/app/system_linux.h +++ b/src/app/system_linux.h @@ -20,20 +20,11 @@ * \brief Linux-specific implementation of system functions */ -/* NOTE: code is contained in this header; - * there is no separate .cpp module for simplicity */ +#include "app/system.h" #include <sys/time.h> -#include <time.h> -#include <stdlib.h> -SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string& title, const std::string& message); - -void GetCurrentTimeStamp_Linux(SystemTimeStamp *stamp); -long long GetTimeStampExactResolution_Linux(); -long long TimeStampExactDiff_Linux(SystemTimeStamp *before, SystemTimeStamp *after); - struct SystemTimeStamp { timespec clockTime; @@ -45,60 +36,8 @@ struct SystemTimeStamp }; -SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string& title, const std::string& message) -{ - std::string options = ""; - switch (type) - { - case SDT_INFO: - default: - options = "--info"; - break; - case SDT_WARNING: - options = "--warning"; - break; - case SDT_ERROR: - options = "--error"; - break; - case SDT_YES_NO: - options = "--question --ok-label=\"Yes\" --cancel-label=\"No\""; - break; - case SDT_OK_CANCEL: - options = "--question --ok-label=\"OK\" --cancel-label=\"Cancel\""; - break; - } - - std::string command = "zenity " + options + " --text=\"" + message + "\" --title=\"" + title + "\""; - int code = system(command.c_str()); - - SystemDialogResult result = SDR_OK; - switch (type) - { - case SDT_YES_NO: - result = code ? SDR_NO : SDR_YES; - break; - case SDT_OK_CANCEL: - result = code ? SDR_CANCEL : SDR_OK; - break; - default: - break; - } - - return result; -} - -void GetCurrentTimeStamp_Linux(SystemTimeStamp *stamp) -{ - clock_gettime(CLOCK_MONOTONIC, &stamp->clockTime); -} - -long long GetTimeStampExactResolution_Linux() -{ - return 1ll; -} +SystemDialogResult SystemDialog_Linux(SystemDialogType type, const std::string& title, const std::string& message); -long long TimeStampExactDiff_Linux(SystemTimeStamp *before, SystemTimeStamp *after) -{ - return (after->clockTime.tv_nsec - before->clockTime.tv_nsec) + - (after->clockTime.tv_sec - before->clockTime.tv_sec) * 1000000000ll; -} +void GetCurrentTimeStamp_Linux(SystemTimeStamp *stamp); +long long GetTimeStampExactResolution_Linux(); +long long TimeStampExactDiff_Linux(SystemTimeStamp *before, SystemTimeStamp *after); diff --git a/src/app/system_other.cpp b/src/app/system_other.cpp new file mode 100644 index 0000000..006bf6d --- /dev/null +++ b/src/app/system_other.cpp @@ -0,0 +1,122 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * 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, see http://www.gnu.org/licenses/. + +#include "app/system_other.h" + + +SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string& title, const std::string& message) +{ + switch (type) + { + case SDT_INFO: + std::cout << "INFO: "; + break; + case SDT_WARNING: + std::cout << "WARNING:"; + break; + case SDT_ERROR: + std::cout << "ERROR: "; + break; + case SDT_YES_NO: + case SDT_OK_CANCEL: + std::cout << "QUESTION: "; + break; + } + + std::cout << message << std::endl; + + std::string line; + + SystemDialogResult result = SDR_OK; + + bool done = false; + while (!done) + { + switch (type) + { + case SDT_INFO: + case SDT_WARNING: + case SDT_ERROR: + std::cout << "Press ENTER to continue"; + break; + + case SDT_YES_NO: + std::cout << "Type 'Y' for Yes or 'N' for No"; + break; + + case SDT_OK_CANCEL: + std::cout << "Type 'O' for OK or 'C' for Cancel"; + break; + } + + std::getline(std::cin, line); + + switch (type) + { + case SDT_INFO: + case SDT_WARNING: + case SDT_ERROR: + done = true; + break; + + case SDT_YES_NO: + if (line == "Y" || line == "y") + { + result = SDR_YES; + done = true; + } + else if (line == "N" || line == "n") + { + result = SDR_NO; + done = true; + } + break; + + case SDT_OK_CANCEL: + if (line == "O" || line == "o") + { + done = true; + result = SDR_OK; + } + else if (line == "C" || line == "c") + { + done = true; + result = SDR_CANCEL; + } + break; + } + } + + return result; +} + + + +void GetCurrentTimeStamp_Other(SystemTimeStamp *stamp) +{ + stamp->sdlTicks = SDL_GetTicks(); +} + +long long GetTimeStampExactResolution_Other() +{ + return 1000000ll; +} + +long long TimeStampExactDiff_Other(SystemTimeStamp *before, SystemTimeStamp *after) +{ + return (after->sdlTicks - before->sdlTicks) * 1000000ll; +} diff --git a/src/app/system_other.h b/src/app/system_other.h index eff0c8a..6fb4b86 100644 --- a/src/app/system_other.h +++ b/src/app/system_other.h @@ -20,20 +20,13 @@ * \brief Fallback code for other systems */ -/* NOTE: code is contained in this header; - * there is no separate .cpp module for simplicity */ +#include "app/system.h" #include <SDL/SDL.h> #include <iostream> -SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string& title, const std::string& message); - -void GetCurrentTimeStamp_Other(SystemTimeStamp *stamp); -long long GetTimeStampExactResolution_Other(); -long long TimeStampExactDiff_Other(SystemTimeStamp *before, SystemTimeStamp *after); - struct SystemTimeStamp { Uint32 sdlTicks; @@ -45,105 +38,8 @@ struct SystemTimeStamp }; -SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string& title, const std::string& message) -{ - switch (type) - { - case SDT_INFO: - std::cout << "INFO: "; - break; - case SDT_WARNING: - std::cout << "WARNING:"; - break; - case SDT_ERROR: - std::cout << "ERROR: "; - break; - case SDT_YES_NO: - case SDT_OK_CANCEL: - std::cout << "QUESTION: "; - break; - } - - std::cout << message << std::endl; - - std::string line; - - SystemDialogResult result = SDR_OK; - - bool done = false; - while (!done) - { - switch (type) - { - case SDT_INFO: - case SDT_WARNING: - case SDT_ERROR: - std::cout << "Press ENTER to continue"; - break; - - case SDT_YES_NO: - std::cout << "Type 'Y' for Yes or 'N' for No"; - break; - - case SDT_OK_CANCEL: - std::cout << "Type 'O' for OK or 'C' for Cancel"; - break; - } - - std::getline(std::cin, line); - - switch (type) - { - case SDT_INFO: - case SDT_WARNING: - case SDT_ERROR: - done = true; - break; - - case SDT_YES_NO: - if (line == "Y" || line == "y") - { - result = SDR_YES; - done = true; - } - else if (line == "N" || line == "n") - { - result = SDR_NO; - done = true; - } - break; - - case SDT_OK_CANCEL: - if (line == "O" || line == "o") - { - done = true; - result = SDR_OK; - } - else if (line == "C" || line == "c") - { - done = true; - result = SDR_CANCEL; - } - break; - } - } - - return result; -} - - - -void GetCurrentTimeStamp_Other(SystemTimeStamp *stamp) -{ - stamp->sdlTicks = SDL_GetTicks(); -} - -long long GetTimeStampExactResolution_Other() -{ - return 1000000ll; -} +SystemDialogResult SystemDialog_Other(SystemDialogType type, const std::string& title, const std::string& message); -long long TimeStampExactDiff_Other(SystemTimeStamp *before, SystemTimeStamp *after) -{ - return (after->sdlTicks - before->sdlTicks) * 1000000ll; -} +void GetCurrentTimeStamp_Other(SystemTimeStamp *stamp); +long long GetTimeStampExactResolution_Other(); +long long TimeStampExactDiff_Other(SystemTimeStamp *before, SystemTimeStamp *after); diff --git a/src/app/system_windows.cpp b/src/app/system_windows.cpp new file mode 100644 index 0000000..34fa57e --- /dev/null +++ b/src/app/system_windows.cpp @@ -0,0 +1,98 @@ +// * This file is part of the COLOBOT source code +// * Copyright (C) 2001-2008, Daniel ROUX & EPSITEC SA, www.epsitec.ch +// * Copyright (C) 2012, Polish Portal of Colobot (PPC) +// * +// * 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, see http://www.gnu.org/licenses/. + +#include "app/system_windows.h" + + +// Convert a wide Unicode string to an UTF8 string +std::string UTF8_Encode_Windows(const std::wstring &wstr) +{ + int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], static_cast<int>(wstr.size()), NULL, 0, NULL, NULL); + std::string strTo(size_needed, 0); + WideCharToMultiByte(CP_UTF8, 0, &wstr[0], static_cast<int>(wstr.size()), &strTo[0], size_needed, NULL, NULL); + return strTo; +} + +// Convert an UTF8 string to a wide Unicode String +std::wstring UTF8_Decode_Windows(const std::string &str) +{ + int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], static_cast<int>(str.size()), NULL, 0); + std::wstring wstrTo(size_needed, 0); + MultiByteToWideChar(CP_UTF8, 0, &str[0], static_cast<int>(str.size()), &wstrTo[0], size_needed); + return wstrTo; +} + +SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string& title, const std::string& message) +{ + unsigned int windowsType = 0; + std::wstring windowsMessage = UTF8_Decode_Windows(message); + std::wstring windowsTitle = UTF8_Decode_Windows(title); + + switch (type) + { + case SDT_INFO: + default: + windowsType = MB_ICONINFORMATION|MB_OK; + break; + case SDT_WARNING: + windowsType = MB_ICONWARNING|MB_OK; + break; + case SDT_ERROR: + windowsType = MB_ICONERROR|MB_OK; + break; + case SDT_YES_NO: + windowsType = MB_ICONQUESTION|MB_YESNO; + break; + case SDT_OK_CANCEL: + windowsType = MB_ICONWARNING|MB_OKCANCEL; + break; + } + + switch (MessageBoxW(NULL, windowsMessage.c_str(), windowsTitle.c_str(), windowsType)) + { + case IDOK: + return SDR_OK; + case IDCANCEL: + return SDR_CANCEL; + case IDYES: + return SDR_YES; + case IDNO: + return SDR_NO; + default: + break; + } + + return SDR_OK; +} + + +void GetCurrentTimeStamp_Windows(SystemTimeStamp *stamp) +{ + GetSystemTimeAsFileTime(&stamp->fileTime); +} + +long long GetTimeStampExactResolution_Windows() +{ + return 100ll; +} + +long long TimeStampExactDiff_Windows(SystemTimeStamp *before, SystemTimeStamp *after) +{ + long long tH = (1ll << 32) * (after->fileTime.dwHighDateTime - before->fileTime.dwHighDateTime); + long long tL = after->fileTime.dwLowDateTime - before->fileTime.dwLowDateTime; + return (tH + tL) * 100ll; +} diff --git a/src/app/system_windows.h b/src/app/system_windows.h index c9743e6..804d064 100644 --- a/src/app/system_windows.h +++ b/src/app/system_windows.h @@ -20,20 +20,11 @@ * \brief Windows-specific implementation of system functions */ -/* NOTE: code is contained in this header; - * there is no separate .cpp module for simplicity */ +#include "app/system.h" #include <windows.h> -std::string UTF8_Encode_Windows(const std::wstring &wstr); -std::wstring UTF8_Decode_Windows(const std::string &str); -SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string& title, const std::string& message); - -void GetCurrentTimeStamp_Windows(SystemTimeStamp *stamp); -long long GetTimeStampExactResolution_Windows(); -long long TimeStampExactDiff_Windows(SystemTimeStamp *before, SystemTimeStamp *after); - struct SystemTimeStamp { FILETIME fileTime; @@ -44,82 +35,10 @@ struct SystemTimeStamp } }; +std::string UTF8_Encode_Windows(const std::wstring &wstr); +std::wstring UTF8_Decode_Windows(const std::string &str); +SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string& title, const std::string& message); -// Convert a wide Unicode string to an UTF8 string -std::string UTF8_Encode_Windows(const std::wstring &wstr) -{ - int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], static_cast<int>(wstr.size()), NULL, 0, NULL, NULL); - std::string strTo(size_needed, 0); - WideCharToMultiByte(CP_UTF8, 0, &wstr[0], static_cast<int>(wstr.size()), &strTo[0], size_needed, NULL, NULL); - return strTo; -} - -// Convert an UTF8 string to a wide Unicode String -std::wstring UTF8_Decode_Windows(const std::string &str) -{ - int size_needed = MultiByteToWideChar(CP_UTF8, 0, &str[0], static_cast<int>(str.size()), NULL, 0); - std::wstring wstrTo(size_needed, 0); - MultiByteToWideChar(CP_UTF8, 0, &str[0], static_cast<int>(str.size()), &wstrTo[0], size_needed); - return wstrTo; -} - -SystemDialogResult SystemDialog_Windows(SystemDialogType type, const std::string& title, const std::string& message) -{ - unsigned int windowsType = 0; - std::wstring windowsMessage = UTF8_Decode_Windows(message); - std::wstring windowsTitle = UTF8_Decode_Windows(title); - - switch (type) - { - case SDT_INFO: - default: - windowsType = MB_ICONINFORMATION|MB_OK; - break; - case SDT_WARNING: - windowsType = MB_ICONWARNING|MB_OK; - break; - case SDT_ERROR: - windowsType = MB_ICONERROR|MB_OK; - break; - case SDT_YES_NO: - windowsType = MB_ICONQUESTION|MB_YESNO; - break; - case SDT_OK_CANCEL: - windowsType = MB_ICONWARNING|MB_OKCANCEL; - break; - } - - switch (MessageBoxW(NULL, windowsMessage.c_str(), windowsTitle.c_str(), windowsType)) - { - case IDOK: - return SDR_OK; - case IDCANCEL: - return SDR_CANCEL; - case IDYES: - return SDR_YES; - case IDNO: - return SDR_NO; - default: - break; - } - - return SDR_OK; -} - - -void GetCurrentTimeStamp_Windows(SystemTimeStamp *stamp) -{ - GetSystemTimeAsFileTime(&stamp->fileTime); -} - -long long GetTimeStampExactResolution_Windows() -{ - return 100ll; -} - -long long TimeStampExactDiff_Windows(SystemTimeStamp *before, SystemTimeStamp *after) -{ - long long tH = (1ll << 32) * (after->fileTime.dwHighDateTime - before->fileTime.dwHighDateTime); - long long tL = after->fileTime.dwLowDateTime - before->fileTime.dwLowDateTime; - return (tH + tL) * 100ll; -} +void GetCurrentTimeStamp_Windows(SystemTimeStamp *stamp); +long long GetTimeStampExactResolution_Windows(); +long long TimeStampExactDiff_Windows(SystemTimeStamp *before, SystemTimeStamp *after); 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<CLogger> { - 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/common/misc.cpp b/src/common/misc.cpp index 2bce3b8..b96abca 100644 --- a/src/common/misc.cpp +++ b/src/common/misc.cpp @@ -25,10 +25,6 @@ #include <time.h> -static bool g_bUserDir = false; -static char g_userDir[100] = ""; - - // Returns a non-accented letter. char GetNoAccent(char letter) @@ -234,72 +230,11 @@ void TimeToAscii(time_t time, char *buffer) #endif*/ } - -// Makes a copy of a file. - -bool Xfer(char* src, char* dst) -{ - FILE *fs, *fd; - char *buffer; - int len; - - fs = fopen(src, "rb"); - if ( fs == 0 ) - { - return false; - } - - fd = fopen(dst, "wb"); - if ( fd == 0 ) - { - fclose(fs); - return false; - } - - buffer = static_cast<char*>(malloc(10000)); - - while ( true ) - { - len = fread(buffer, 1, 10000, fs); - if ( len == 0 ) break; - fwrite(buffer, 1, len, fd); - } - - free(buffer); - fclose(fs); - fclose(fd); - return true; -} - -// Copy a file into the temporary folder. - -bool CopyFileToTemp(char* filename) -{ - char src[100]; - char dst[100]; - char save[100]; - - UserDir(src, filename, "textures"); - - strcpy(save, g_userDir); - strcpy(g_userDir, "temp"); - UserDir(dst, filename, "textures"); - strcpy(g_userDir, save); - - //_mkdir("temp"); - system("mkdir temp"); - - if ( !Xfer(src, dst) ) return false; - - strcpy(filename, dst); - return true; -} - // Copy a list of numbered files into the temporary folder. bool CopyFileListToTemp(char* filename, int* list, int total) { - char name[100]; + /*char name[100]; char ext[10]; char file[100]; char save[100]; @@ -329,8 +264,8 @@ bool CopyFileListToTemp(char* filename, int* list, int total) UserDir(file, filename, "textures"); strcpy(filename, file); strcpy(g_userDir, save); - - return true; +*/ + return false; } @@ -342,56 +277,3 @@ void AddExt(char* filename, const char* ext) strcat(filename, ext); } - -// Specifies the user folder. - -void UserDir(bool bUser, const char* dir) -{ - g_bUserDir = bUser; - strcpy(g_userDir, dir); -} - -// Replaces the string %user% by the user folder. -// in: dir = "%user%toto.txt" -// def = "abc\" -// out: buffer = "abc\toto.txt" - -void UserDir(char* buffer, const char* dir, const char* def) -{ - char ddir[100]; - const char* add; - - if ( strstr(dir, "\\") == 0 && def[0] != 0 ) - { - sprintf(ddir, "%s\\%s", def, dir); - } - else - { - strcpy(ddir, dir); - } - dir = ddir; - - while ( *dir != 0 ) - { - if ( dir[0] == '%' && - dir[1] == 'u' && - dir[2] == 's' && - dir[3] == 'e' && - dir[4] == 'r' && - dir[5] == '%' ) // %user% ? - { - if ( g_bUserDir ) add = g_userDir; - else add = def; - - while ( *add != 0 ) - { - *buffer++ = *add++; - } - dir += 6; // jumps to %user% - continue; - } - - *buffer++ = *dir++; - } - *buffer = 0; -} diff --git a/src/common/misc.h b/src/common/misc.h index f210706..e2ddc44 100644 --- a/src/common/misc.h +++ b/src/common/misc.h @@ -29,8 +29,5 @@ extern char GetToLower(char letter); extern void TimeToAscii(time_t time, char *buffer); -extern bool CopyFileToTemp(char* filename); extern bool CopyFileListToTemp(char* filename, int* list, int total); extern void AddExt(char* filename, const char* ext); -extern void UserDir(bool bUser, const char* dir); -extern void UserDir(char* buffer, const char* dir, const char* def); diff --git a/src/common/profile.cpp b/src/common/profile.cpp index 18cc187..2d11217 100644 --- a/src/common/profile.cpp +++ b/src/common/profile.cpp @@ -182,3 +182,48 @@ std::vector< std::string > CProfile::GetLocalProfileSection(std::string section, return ret_list; } + + +void CProfile::SetUserDir(std::string dir) +{ + m_userDirectory = dir; +} + + +std::string CProfile::GetUserBasedPath(std::string dir, std::string default_dir) +{ + std::string path = dir; + boost::replace_all(path, "\\", "/"); + if (dir.find("/") == std::string::npos) { + path = default_dir + "/" + dir; + } + + if (m_userDirectory.length() > 0) { + boost::replace_all(path, "%user%", m_userDirectory); + } else { + boost::replace_all(path, "%user%", default_dir); + } + + return fs::path(path).make_preferred().string(); +} + + +bool CProfile::CopyFileToTemp(std::string filename) +{ + std::string src, dst; + std::string tmp_user_dir = m_userDirectory; + + src = GetUserBasedPath(filename, "textures"); + SetUserDir("temp"); + dst = GetUserBasedPath(filename, "textures"); + SetUserDir(tmp_user_dir); + + fs::create_directory(fs::path(dst).parent_path().make_preferred().string()); + fs::copy_file(src, dst, fs::copy_option::overwrite_if_exists); + if (fs::exists(dst)) { + return true; + } + + return false; +} + diff --git a/src/common/profile.h b/src/common/profile.h index 9bc6c37..bcd76c3 100644 --- a/src/common/profile.h +++ b/src/common/profile.h @@ -21,14 +21,20 @@ #pragma once - #include "common/singleton.h" +// this is just to fix problem with undefined reference when compiling with c++11 support +#define BOOST_NO_SCOPED_ENUMS + #include <boost/property_tree/ptree.hpp> +#include <boost/filesystem.hpp> +#include <boost/algorithm/string/replace.hpp> #include <string> #include <vector> +namespace fs = boost::filesystem; + /** * \class CProfile @@ -101,10 +107,30 @@ class CProfile : public CSingleton<CProfile> * \return vector of values */ std::vector< std::string > GetLocalProfileSection(std::string section, std::string key); + + /** Sets current user directory + * \param dir + */ + void SetUserDir(std::string dir); + + /** Returns path based on current user. Replaces %user% in path with current user dir or + * uses default_dir param if no user dir is specified + * \param dir + * \param default_dir + * \return path + */ + std::string GetUserBasedPath(std::string dir, std::string default_dir); + + /** opy a file into the temporary folder. + * \param filename + * \return true on success + */ + bool CopyFileToTemp(std::string filename); private: boost::property_tree::ptree m_propertyTree; bool m_profileNeedSave; + std::string m_userDirectory; }; //! Global function to get profile instance diff --git a/src/graphics/core/color.h b/src/graphics/core/color.h index 7cbd175..5d059e5 100644 --- a/src/graphics/core/color.h +++ b/src/graphics/core/color.h @@ -76,6 +76,16 @@ struct Color { return ! this->operator==(other); } + + inline Color operator*(float scale) const + { + Color c = *this; + c.r *= scale; + c.g *= scale; + c.b *= scale; + c.a *= scale; + return c; + } }; /** diff --git a/src/graphics/engine/engine.h b/src/graphics/engine/engine.h index 0647fbd..f9dfd45 100644 --- a/src/graphics/engine/engine.h +++ b/src/graphics/engine/engine.h @@ -729,7 +729,7 @@ public: //@{ //! Management of game pause mode void SetPause(bool pause); - bool GetPause(); + TEST_VIRTUAL bool GetPause(); //@} //@{ @@ -1170,9 +1170,9 @@ public: //! Returns the view matrix const Math::Matrix& GetMatView(); //! Returns the camera center point - Math::Vector GetEyePt(); + TEST_VIRTUAL Math::Vector GetEyePt(); //! Returns the camera target point - Math::Vector GetLookatPt(); + TEST_VIRTUAL Math::Vector GetLookatPt(); //! Returns the horizontal direction angle of view float GetEyeDirH(); //! Returns the vertical direction angle of view diff --git a/src/graphics/engine/lightman.cpp b/src/graphics/engine/lightman.cpp index 4a8fd60..16c84ea 100644 --- a/src/graphics/engine/lightman.cpp +++ b/src/graphics/engine/lightman.cpp @@ -26,6 +26,7 @@ #include <cmath> +#include <algorithm> // Graphics module namespace @@ -125,6 +126,7 @@ int CLightManager::CreateLight(LightPriority priority) m_dynLights[index].light.type = LIGHT_DIRECTIONAL; m_dynLights[index].light.diffuse = Color(0.5f, 0.5f, 0.5f); + m_dynLights[index].light.ambient = Color(0.0f, 0.0f, 0.0f); m_dynLights[index].light.position = Math::Vector(-100.0f, 100.0f, -100.0f); m_dynLights[index].light.direction = Math::Vector( 1.0f, -1.0f, 1.0f); @@ -386,68 +388,35 @@ void CLightManager::UpdateDeviceLights(EngineObjectType type) for (int i = 0; i < static_cast<int>( m_lightMap.size() ); ++i) m_lightMap[i] = -1; - // High priority - for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++) - { - if (! m_dynLights[i].used) - continue; - if (! m_dynLights[i].enabled) - continue; - if (Math::IsZero(m_dynLights[i].intensity.current)) - continue; - if (m_dynLights[i].priority == LIGHT_PRI_LOW) - continue; - - bool enabled = true; - if (m_dynLights[i].includeType != ENG_OBJTYPE_NULL) - enabled = (m_dynLights[i].includeType == type); - - if (m_dynLights[i].excludeType != ENG_OBJTYPE_NULL) - enabled = (m_dynLights[i].excludeType != type); - - if (enabled) - { - for (int j = 0; j < static_cast<int>( m_lightMap.size() ); ++j) - { - if (m_lightMap[j] == -1) - { - m_lightMap[j] = i; - break; - } - } - } - } + std::vector<DynamicLight> sortedLights = m_dynLights; + LightsComparator lightsComparator(m_engine->GetEyePt(), type); + std::sort(sortedLights.begin(), sortedLights.end(), lightsComparator); - // Low priority - for (int i = 0; i < static_cast<int>( m_dynLights.size() ); i++) + int lightMapIndex = 0; + for (int i = 0; i < static_cast<int>( sortedLights.size() ); i++) { - if (! m_dynLights[i].used) + if (! sortedLights[i].used) continue; - if (! m_dynLights[i].enabled) + if (! sortedLights[i].enabled) continue; - if (m_dynLights[i].intensity.current == 0.0f) - continue; - if (m_dynLights[i].priority == LIGHT_PRI_HIGH) + if (sortedLights[i].intensity.current == 0.0f) continue; bool enabled = true; - if (m_dynLights[i].includeType != ENG_OBJTYPE_NULL) - enabled = (m_dynLights[i].includeType == type); + if (sortedLights[i].includeType != ENG_OBJTYPE_NULL) + enabled = (sortedLights[i].includeType == type); - if (m_dynLights[i].excludeType != ENG_OBJTYPE_NULL) - enabled = (m_dynLights[i].excludeType != type); + if (sortedLights[i].excludeType != ENG_OBJTYPE_NULL) + enabled = (sortedLights[i].excludeType != type); if (enabled) { - for (int j = 0; j < static_cast<int>( m_lightMap.size() ); ++j) - { - if (m_lightMap[j] == -1) - { - m_lightMap[j] = i; - break; - } - } + m_lightMap[lightMapIndex] = i; + ++lightMapIndex; } + + if (lightMapIndex >= static_cast<int>( m_lightMap.size() )) + break; } for (int i = 0; i < static_cast<int>( m_lightMap.size() ); ++i) @@ -455,7 +424,8 @@ void CLightManager::UpdateDeviceLights(EngineObjectType type) int rank = m_lightMap[i]; if (rank != -1) { - m_device->SetLight(i, m_dynLights[rank].light); + sortedLights[rank].light.ambient = Gfx::Color(0.2f, 0.2f, 0.2f); + m_device->SetLight(i, sortedLights[rank].light); m_device->SetLightEnabled(i, true); } else @@ -465,5 +435,33 @@ void CLightManager::UpdateDeviceLights(EngineObjectType type) } } +// ----------- + +CLightManager::LightsComparator::LightsComparator(Math::Vector eyePos, EngineObjectType objectType) +{ + m_eyePos = eyePos; + m_objectType = objectType; +} + +float CLightManager::LightsComparator::GetLightWeight(const DynamicLight& dynLight) +{ + bool enabled = true; + if (!dynLight.used || !dynLight.enabled || dynLight.intensity.current == 0.0f) + enabled = false; + else if (dynLight.includeType != ENG_OBJTYPE_NULL) + enabled = dynLight.includeType == m_objectType; + else if (dynLight.excludeType != ENG_OBJTYPE_NULL) + enabled = dynLight.excludeType != m_objectType; + + return enabled ? ( (dynLight.light.position - m_eyePos).Length() * dynLight.priority ) : 10000.0f; +} + +bool CLightManager::LightsComparator::operator()(const DynamicLight& left, const DynamicLight& right) +{ + float leftWeight = GetLightWeight(left); + float rightWeight = GetLightWeight(right); + + return leftWeight < rightWeight; +} } // namespace Gfx diff --git a/src/graphics/engine/lightman.h b/src/graphics/engine/lightman.h index 07dfe6a..ab66524 100644 --- a/src/graphics/engine/lightman.h +++ b/src/graphics/engine/lightman.h @@ -71,8 +71,8 @@ struct LightProgression */ enum LightPriority { - LIGHT_PRI_HIGH, - LIGHT_PRI_LOW + LIGHT_PRI_HIGH = 1, + LIGHT_PRI_LOW = 2 }; /** @@ -189,6 +189,21 @@ public: void UpdateDeviceLights(EngineObjectType type); protected: + class LightsComparator + { + public: + LightsComparator(Math::Vector eyePos, EngineObjectType objectType); + + bool operator()(const DynamicLight& left, const DynamicLight& right); + + private: + float GetLightWeight(const DynamicLight& dynLight); + + Math::Vector m_eyePos; + EngineObjectType m_objectType; + }; + +protected: CEngine* m_engine; CDevice* m_device; @@ -196,7 +211,7 @@ protected: float m_time; //! List of dynamic lights std::vector<DynamicLight> m_dynLights; - //! Map of current light allotment: graphics light -> dynamic light + //! Map of current light allocation: graphics light -> dynamic light std::vector<int> m_lightMap; }; diff --git a/src/graphics/engine/pyro.cpp b/src/graphics/engine/pyro.cpp index 1d80fea..cab28b6 100644 --- a/src/graphics/engine/pyro.cpp +++ b/src/graphics/engine/pyro.cpp @@ -1318,12 +1318,9 @@ void CPyro::CreateLight(Math::Vector pos, float height) Gfx::Light light; light.type = LIGHT_SPOT; - light.position.x = pos.x; - light.position.y = pos.y+height; - light.position.z = pos.z; - light.direction.x = 0.0f; - light.direction.y = -1.0f; // against the bottom - light.direction.z = 0.0f; + light.ambient = Gfx::Color(0.0f, 0.0f, 0.0f); + light.position = Math::Vector(pos.x, pos.y+height, pos.z); + light.direction = Math::Vector(0.0f, -1.0f, 0.0f); // against the bottom light.spotIntensity = 1.0f; light.attenuation0 = 1.0f; light.attenuation1 = 0.0f; 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 @@ -34,6 +34,17 @@ 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 */ struct GLDeviceConfig : public DeviceConfig @@ -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/src/object/object.cpp b/src/object/object.cpp index 8f2a4cc..d6ac681 100644 --- a/src/object/object.cpp +++ b/src/object/object.cpp @@ -2248,15 +2248,10 @@ bool CObject::CreateShadowLight(float height, Gfx::Color color) Gfx::Light light; light.type = Gfx::LIGHT_SPOT; - light.diffuse.r = color.r; - light.diffuse.g = color.g; - light.diffuse.b = color.b; - light.position.x = pos.x; - light.position.y = pos.y+height; - light.position.z = pos.z; - light.direction.x = 0.0f; - light.direction.y = -1.0f; // against the bottom - light.direction.z = 0.0f; + light.diffuse = color; + light.ambient = color * 0.1f; + light.position = Math::Vector(pos.x, pos.y+height, pos.z); + light.direction = Math::Vector(0.0f, -1.0f, 0.0f); // against the bottom light.spotIntensity = 128; light.attenuation0 = 1.0f; light.attenuation1 = 0.0f; @@ -2291,15 +2286,9 @@ bool CObject::CreateEffectLight(float height, Gfx::Color color) Gfx::Light light; light.type = Gfx::LIGHT_SPOT; - light.diffuse.r = color.r; - light.diffuse.g = color.g; - light.diffuse.b = color.b; - light.position.x = 0.0f; - light.position.y = 0.0f+height; - light.position.z = 0.0f; - light.direction.x = 0.0f; - light.direction.y = -1.0f; // against the bottom - light.direction.z = 0.0f; + light.diffuse = color; + light.position = Math::Vector(0.0f, height, 0.0f); + light.direction = Math::Vector(0.0f, -1.0f, 0.0f); // against the bottom light.spotIntensity = 0.0f; light.attenuation0 = 1.0f; light.attenuation1 = 0.0f; diff --git a/src/object/robotmain.cpp b/src/object/robotmain.cpp index 6efd853..2554ce4 100644 --- a/src/object/robotmain.cpp +++ b/src/object/robotmain.cpp @@ -661,7 +661,11 @@ CRobotMain::CRobotMain(CApplication* app) m_showPos = false; m_selectInsect = false; m_showSoluce = false; + #ifdef NDEBUG + m_showAll = false; + #else m_showAll = true; // for development + #endif m_cheatRadar = false; m_fixScene = false; m_trainerPilot = false; @@ -1142,6 +1146,7 @@ void CRobotMain::ChangePhase(Phase phase) if (m_phase == PHASE_WIN) { + m_sound->StopAll(); if (m_endingWinRank == -1) { ChangePhase(PHASE_TERM); @@ -1181,20 +1186,20 @@ void CRobotMain::ChangePhase(Phase phase) pe->SetGenericMode(true); pe->SetFontType(Gfx::FONT_COLOBOT); pe->SetEditCap(false); - pe->SetHiliteCap(false); - pe->ReadText("help/win.txt"); + pe->SetHighlightCap(false); + pe->ReadText(std::string("help/win.txt")); } else { m_displayText->DisplayError(INFO_WIN, Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 1000.0f); } + StartMusic(); } - m_sound->StopAll(); - StartMusic(); } if (m_phase == PHASE_LOST) { + m_sound->StopAll(); if (m_endingLostRank == -1) { ChangePhase(PHASE_TERM); @@ -1211,9 +1216,9 @@ void CRobotMain::ChangePhase(Phase phase) ddim.x = dim.x*2; ddim.y = dim.y*2; m_interface->CreateButton(pos, ddim, 16, EVENT_BUTTON_OK); m_displayText->DisplayError(INFO_LOST, Math::Vector(0.0f,0.0f,0.0f), 15.0f, 60.0f, 1000.0f); + + StartMusic(); } - m_sound->StopAll(); - StartMusic(); } if (m_phase == PHASE_LOADING) @@ -3833,7 +3838,12 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) int rankObj = 0; int rankGadget = 0; CObject* sel = 0; + + std::string oldLocale; char *locale = setlocale(LC_NUMERIC, nullptr); + if (locale != nullptr) + oldLocale = locale; + setlocale(LC_NUMERIC, "C"); while (fgets(line, 500, file) != NULL) @@ -4084,8 +4094,9 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) { OpString(line, "image", name); AddExt(name, ".png"); - if (strstr(name, "%user%") != 0) - CopyFileToTemp(name); + if (strstr(name, "%user%") != 0) { + GetProfile().CopyFileToTemp(std::string(name)); + } m_terrain->AddMaterial(OpInt(line, "id", 0), name, @@ -4568,8 +4579,8 @@ void CRobotMain::CreateScene(bool soluce, bool fixScene, bool resetObject) } m_dialog->SetSceneRead(""); m_dialog->SetStackRead(""); - - setlocale(LC_NUMERIC, locale); + + setlocale(LC_NUMERIC, oldLocale.c_str()); } //! Creates an object of decoration mobile or stationary @@ -4917,6 +4928,7 @@ int CRobotMain::CreateLight(Math::Vector direction, Gfx::Color color) Gfx::Light light; light.type = Gfx::LIGHT_DIRECTIONAL; light.diffuse = color; + light.ambient = color * 0.1f; light.direction = direction; int obj = m_lightMan->CreateLight(Gfx::LIGHT_PRI_HIGH); m_lightMan->SetLight(obj, light); @@ -4934,6 +4946,7 @@ int CRobotMain::CreateSpot(Math::Vector pos, Gfx::Color color) Gfx::Light light; light.type = Gfx::LIGHT_SPOT; light.diffuse = color; + light.ambient = color * 0.1f; light.position = pos; light.direction = Math::Vector(0.0f, -1.0f, 0.0f); light.spotIntensity = 1.0f; diff --git a/src/object/task/taskbuild.cpp b/src/object/task/taskbuild.cpp index f209cd5..b9af475 100644 --- a/src/object/task/taskbuild.cpp +++ b/src/object/task/taskbuild.cpp @@ -114,7 +114,6 @@ bool CTaskBuild::CreateBuilding(Math::Vector pos, float angle) void CTaskBuild::CreateLight() { - Gfx::Light light; Gfx::Color color; Math::Vector center, pos, dir; Math::Point c, p; @@ -141,18 +140,12 @@ void CTaskBuild::CreateLight() pos.y = center.y+40.0f; dir = center-pos; - memset(&light, 0, sizeof(light)); + Gfx::Light light; light.type = Gfx::LIGHT_SPOT; - light.diffuse.r = 0.0f; - light.diffuse.g = 0.0f; - light.diffuse.b = 0.0f; // white (invisible) - light.position.x = pos.x; - light.position.y = pos.y; - light.position.z = pos.z; - light.direction.x = dir.x; - light.direction.y = dir.y; - light.direction.z = dir.z; - //TODO Is this value correct + light.ambient = Gfx::Color(0.0f, 0.0f, 0.0f); + light.diffuse = Gfx::Color(0.0f, 0.0f, 0.0f); // invisible + light.position = pos; + light.direction = dir; light.spotIntensity = 128; light.attenuation0 = 1.0f; light.attenuation1 = 0.0f; diff --git a/src/object/task/taskshield.cpp b/src/object/task/taskshield.cpp index 4b2fccd..929dd5c 100644 --- a/src/object/task/taskshield.cpp +++ b/src/object/task/taskshield.cpp @@ -488,15 +488,10 @@ bool CTaskShield::CreateLight(Math::Vector pos) memset(&light, 0, sizeof(light)); light.type = Gfx::LIGHT_SPOT; - light.diffuse.r = 0.0f; - light.diffuse.g = 1.0f; - light.diffuse.b = 2.0f; - light.position.x = pos.x; - light.position.y = pos.y; - light.position.z = pos.z; - light.direction.x = 0.0f; - light.direction.y = -1.0f; // against the bottom - light.direction.z = 0.0f; + light.ambient = Gfx::Color(0.0f, 0.0f, 0.0f); + light.diffuse = Gfx::Color(0.0f, 1.0f, 2.0f); + light.position = pos; + light.direction = Math::Vector(0.0f, -1.0f, 0.0f); // against the bottom light.spotIntensity = 128; light.attenuation0 = 1.0f; light.attenuation1 = 0.0f; diff --git a/src/script/script.cpp b/src/script/script.cpp index 977070f..a62866d 100644 --- a/src/script/script.cpp +++ b/src/script/script.cpp @@ -948,10 +948,8 @@ bool CScript::rDirection(CBotVar* var, CBotVar* result, int& exception, void* us } -// Compilation of the instruction "produce(pos, angle, type, scriptName, power)". -// or "produce(pos, angle, type, scriptName)" -// or "produce(pos, angle, type)" -// or "produce(type)" +// Compilation of the instruction "produce(pos, angle, type[, scriptName[, power]])" +// or "produce(type[, power])". CBotTypResult CScript::cProduce(CBotVar* &var, void* user) { @@ -961,6 +959,10 @@ CBotTypResult CScript::cProduce(CBotVar* &var, void* user) if ( var->GetType() <= CBotTypDouble ) { var = var->GetNext(); + if( var != 0 ) { + if ( var->GetType() > CBotTypDouble ) return CBotTypResult(CBotErrBadNum); + var = var->GetNext(); + } } else { ret = cPoint(var, user); if ( ret.GetType() != 0 ) return ret; @@ -989,10 +991,8 @@ CBotTypResult CScript::cProduce(CBotVar* &var, void* user) return CBotTypResult(CBotTypFloat); } -// Instruction "produce(pos, angle, type, scriptName, power)". -// or "produce(pos, angle, type, scriptName)" -// or "produce(pos, angle, type)" -// or "produce(type)" +// Instruction "produce(pos, angle, type[, scriptName[, power]])" +// or "produce(type[, power])". bool CScript::rProduce(CBotVar* var, CBotVar* result, int& exception, void* user) { @@ -1008,13 +1008,17 @@ bool CScript::rProduce(CBotVar* var, CBotVar* result, int& exception, void* user if ( var->GetType() <= CBotTypDouble ) { type = static_cast<ObjectType>(var->GetValInt()); + var = var->GetNext(); pos = me->GetPosition(0); Math::Vector rotation = me->GetAngle(0) + me->GetInclinaison(); angle = rotation.y; - power = -1.0f; + if( var != 0 ) + power = var->GetValFloat(); + else + power = -1.0f; name = ""; } else { @@ -2457,6 +2461,8 @@ bool CScript::rJet(CBotVar* var, CBotVar* result, int& exception, void* user) float value; value = var->GetValFloat(); + if( value > 1.0f ) value = 1.0f; + physics->SetMotorSpeedY(value); return true; @@ -3894,7 +3900,7 @@ bool CScript::WriteScript(const char* filename) edit->SetMaxChar(Ui::EDITSTUDIOMAX); edit->SetAutoIndent(m_engine->GetEditIndentMode()); edit->SetText(m_script); - edit->WriteText(name.c_str()); + edit->WriteText(name); m_interface->DeleteControl(EVENT_EDIT9); return true; } diff --git a/src/sound/oalsound/alsound.cpp b/src/sound/oalsound/alsound.cpp index 17a46fe..8c1cb81 100644 --- a/src/sound/oalsound/alsound.cpp +++ b/src/sound/oalsound/alsound.cpp @@ -136,7 +136,7 @@ void ALSound::SetMusicVolume(int volume) { mMusicVolume = MIN(static_cast<float>(volume) / MAXVOLUME, 1.0f); if (mCurrentMusic) { - mCurrentMusic->SetVolume(mMusicVolume); + mCurrentMusic->SetVolume(mMusicVolume * mAudioVolume); } } @@ -318,7 +318,7 @@ int ALSound::Play(Sound sound, Math::Vector pos, float amplitude, float frequenc Position(channel, pos); // setting initial values - mChannels[channel]->SetStartAmplitude(amplitude * mAudioVolume); + mChannels[channel]->SetStartAmplitude(amplitude); mChannels[channel]->SetStartFrequency(frequency); mChannels[channel]->SetChangeFrequency(1.0f); mChannels[channel]->ResetOper(); @@ -434,7 +434,7 @@ bool ALSound::MuteAll(bool bMute) volume = mAudioVolume; for (auto channel : mChannels) { - channel.second->SetVolume(volume); + channel.second->SetVolume(volume * mAudioVolume); } return true; @@ -468,7 +468,6 @@ void ALSound::FrameMove(float delta) // setting frequency frequency = progress * (oper.finalFrequency - it.second->GetStartFrequency()) * it.second->GetStartFrequency() * it.second->GetChangeFrequency() * it.second->GetInitFrequency(); it.second->AdjustFrequency(frequency); - GetLogger()->Error("%f\n", frequency); if (oper.totalTime <= oper.currentTime) { if (oper.nextOper == SOPER_LOOP) { @@ -509,7 +508,7 @@ bool ALSound::PlayMusic(int rank, bool bRepeat) GetLogger()->Debug("Music loaded from cache\n"); mCurrentMusic->SetBuffer(music); - mCurrentMusic->SetVolume(mMusicVolume); + mCurrentMusic->SetVolume(mMusicVolume * mAudioVolume); mCurrentMusic->SetLoop(bRepeat); mCurrentMusic->Play(); return true; @@ -534,7 +533,7 @@ bool ALSound::PlayMusic(int rank, bool bRepeat) mMusicCache[rank] = buffer; } - mCurrentMusic->SetVolume(mMusicVolume); + mCurrentMusic->SetVolume(mMusicVolume * mAudioVolume); mCurrentMusic->SetLoop(bRepeat); mCurrentMusic->Play(); diff --git a/src/sound/oalsound/channel.cpp b/src/sound/oalsound/channel.cpp index 0faecd0..19394c6 100644 --- a/src/sound/oalsound/channel.cpp +++ b/src/sound/oalsound/channel.cpp @@ -94,7 +94,7 @@ bool Channel::AdjustFrequency(float freq) if (!mReady || mBuffer == nullptr) return false; - return SetFrequency(mInitFrequency + freq); + return SetFrequency(mInitFrequency + fabs(freq)); } diff --git a/src/ui/displayinfo.cpp b/src/ui/displayinfo.cpp index a9e754f..974cd60 100644 --- a/src/ui/displayinfo.cpp +++ b/src/ui/displayinfo.cpp @@ -381,7 +381,7 @@ void CDisplayInfo::StartDisplayInfo(std::string filename, int index, bool bSoluc edit->ReadText(filename.c_str()); edit->HyperHome(filename.c_str()); edit->SetEditCap(false); // just to see! - edit->SetHiliteCap(false); + edit->SetHighlightCap(false); edit->SetFocus(true); ViewDisplayInfo(); @@ -455,6 +455,7 @@ void CDisplayInfo::StartDisplayInfo(std::string filename, int index, bool bSoluc } light.type = Gfx::LIGHT_DIRECTIONAL; + light.ambient = Gfx::Color(0.0f, 0.0f, 0.0f); light.diffuse = Gfx::Color(1.0f, 0.1f, 0.1f); light.direction = Math::Vector(1.0f, 0.0f, 1.0f); @@ -670,7 +671,7 @@ void CDisplayInfo::ChangeIndexButton(int index) { filename = m_main->GetDisplayInfoName(m_index); edit->ReadText(filename); - edit->HyperHome(filename); + edit->HyperHome(std::string(filename)); SetPosition(m_main->GetDisplayInfoPosition(m_index)); } @@ -784,7 +785,7 @@ void CDisplayInfo::UpdateIndexButton() if ( edit != 0 ) { //? edit->SetHiliteCap(m_index==SATCOM_LOADING); - edit->SetHiliteCap(true); + edit->SetHighlightCap(true); } UpdateCopyButton(); diff --git a/src/ui/edit.cpp b/src/ui/edit.cpp index c0b6446..e4bb3a3 100644 --- a/src/ui/edit.cpp +++ b/src/ui/edit.cpp @@ -560,7 +560,7 @@ bool CEdit::IsLinkPos(Math::Point pos) if ( i == -1 ) return false; if ( i >= m_len ) return false; - if ( m_format.size() > i && ((m_format[i] & Gfx::FONT_MASK_HIGHLIGHT) == Gfx::FONT_HIGHLIGHT_LINK)) return true; // TODO + if ( m_format.size() > static_cast<unsigned int>(i) && ((m_format[i] & Gfx::FONT_MASK_HIGHLIGHT) == Gfx::FONT_HIGHLIGHT_LINK)) return true; // TODO return false; } @@ -760,7 +760,7 @@ void CEdit::HyperFlush() // Indicates which is the home page. -void CEdit::HyperHome(const char *filename) +void CEdit::HyperHome(std::string filename) { HyperFlush(); HyperAdd(filename, 0); @@ -768,10 +768,10 @@ void CEdit::HyperHome(const char *filename) // Performs a hyper jump through a link. -void CEdit::HyperJump(const char *name, const char *marker) +void CEdit::HyperJump(std::string name, std::string marker) { - char filename[100]; - char sMarker[100]; + std::string filename; + std:: string sMarker; int i, line, pos; if ( m_historyCurrent >= 0 ) @@ -779,18 +779,16 @@ void CEdit::HyperJump(const char *name, const char *marker) m_history[m_historyCurrent].firstLine = m_lineFirst; } - strcpy(sMarker, marker); + sMarker = marker; //? sprintf(filename, "help\\%s.txt", name); - if ( name[0] == '%' ) - { - UserDir(filename, name, ""); - strcat(filename, ".txt"); - } - else - { - sprintf(filename, "help\\%s.txt", name); + + if ( name[0] == '%' ) { + filename = GetProfile().GetUserBasedPath(name, "") + ".txt"; + } else { + filename = "/help/" + name + ".txt"; } + if ( ReadText(filename) ) { Justif(); @@ -798,7 +796,7 @@ void CEdit::HyperJump(const char *name, const char *marker) line = 0; for ( i=0 ; i<m_markerTotal ; i++ ) { - if ( strcmp(sMarker, m_marker[i].name) == 0 ) + if (sMarker == m_marker[i].name) { pos = m_marker[i].pos; for ( i=0 ; i<m_lineTotal ; i++ ) @@ -819,12 +817,12 @@ void CEdit::HyperJump(const char *name, const char *marker) // Adds text to the history of visited. -bool CEdit::HyperAdd(const char *filename, int firstLine) +bool CEdit::HyperAdd(std::string filename, int firstLine) { if ( m_historyCurrent >= EDITHISTORYMAX-1 ) return false; m_historyCurrent ++; - strcpy(m_history[m_historyCurrent].filename, filename); + m_history[m_historyCurrent].filename = filename; m_history[m_historyCurrent].firstLine = firstLine; m_historyTotal = m_historyCurrent+1; @@ -1136,16 +1134,14 @@ void CEdit::Draw() // Draw an image part. -void CEdit::DrawImage(Math::Point pos, const char *name, float width, +void CEdit::DrawImage(Math::Point pos, std::string name, float width, float offset, float height, int nbLine) { - Math::Point uv1, uv2, dim; - float dp; - char filename[100]; + Math::Point uv1, uv2, dim; + float dp; + std::string filename; -//? sprintf(filename, "diagram\\%s.png", name); - UserDir(filename, name, "diagram"); - strcat(filename, ".png"); + filename = GetProfile().GetUserBasedPath(name, "diagram") + ".png"; m_engine->SetTexture(filename); m_engine->SetState(Gfx::ENG_RSTATE_NORMAL); @@ -1389,77 +1385,58 @@ int CEdit::GetTextLength() // Returns a name in a command. // \x nom1 nom2 nom3; -void GetNameParam(const char *cmd, int rank, char *buffer) +std::string GetNameParam(std::string cmd, int rank) { - int i; - - for ( i=0 ; i<rank ; i++ ) - { - while ( *cmd != ' ' && *cmd != ';' ) - { - cmd ++; - } - if ( *cmd != ';' ) cmd ++; + std::vector<std::string> results; + boost::split(results, cmd, boost::is_any_of(" ;")); + + if (results.size() > static_cast<unsigned int>(rank)) { + return results.at(rank); } - while ( *cmd != ' ' && *cmd != ';' ) - { - *buffer++ = *cmd++; - } - *buffer = 0; + return ""; } // Returns a number of a command. // \x nom n1 n2; -int GetValueParam(const char *cmd, int rank) +int GetValueParam(std::string cmd, int rank) { - int n, i; - - for ( i=0 ; i<rank ; i++ ) - { - while ( *cmd != ' ' && *cmd != ';' ) - { - cmd ++; - } - if ( *cmd != ';' ) cmd ++; + std::vector<std::string> results; + boost::split(results, cmd, boost::is_any_of(" ;")); + int return_value = 0; + + if (results.size() > static_cast<unsigned int>(rank)) { + return_value = atoi(results.at(rank).c_str()); } - sscanf(cmd, "%d", &n); - return n; + return return_value; } // Frees all images. void CEdit::FreeImage() { - char filename[100]; - int i; + std::string filename; - for ( i=0 ; i<m_imageTotal ; i++ ) - { -//? sprintf(filename, "diagram\\%s.png", m_image[i].name); - UserDir(filename, m_image[i].name, "diagram"); - strcat(filename, ".png"); + for (int i = 0 ; i < m_imageTotal; i++ ) { + filename = GetProfile().GetUserBasedPath(m_image[i].name, "diagram") + ".png"; m_engine->DeleteTexture(filename); } } // Reads the texture of an image. -void CEdit::LoadImage(const char *name) +void CEdit::LoadImage(std::string name) { - char filename[100]; - -//? sprintf(filename, "diagram\\%s.png", name); - UserDir(filename, name, "diagram"); - strcat(filename, ".png"); + std::string filename; + filename = GetProfile().GetUserBasedPath(name, "diagram") + ".png"; m_engine->LoadTexture(filename); } // Read from a text file. -bool CEdit::ReadText(const char *filename, int addSize) +bool CEdit::ReadText(std::string filename, int addSize) { FILE *file = NULL; char *buffer; @@ -1471,7 +1448,16 @@ bool CEdit::ReadText(const char *filename, int addSize) bool bInSoluce, bBOL; if ( filename[0] == 0 ) return false; - file = fopen(filename, "rb"); + boost::replace_all(filename, "\\", "/"); + + /* This is ugly but doesn't require many changes in code. If file doesn't + exists it's posible filename is absolute not full path */ + std::string path = filename; + if (!fs::exists(path)) { + path = CApplication::GetInstancePointer()->GetDataDirPath() + "/" + filename; + } + + file = fopen(fs::path(path).make_preferred().string().c_str(), "rb"); if ( file == NULL ) return false; fseek(file, 0, SEEK_END); @@ -1605,8 +1591,8 @@ bool CEdit::ReadText(const char *filename, int addSize) { if ( iLink < EDITLINKMAX ) { - GetNameParam(buffer+i+3, 0, m_link[iLink].name); - GetNameParam(buffer+i+3, 1, m_link[iLink].marker); + m_link[iLink].name = GetNameParam(buffer+i+3, 0); + m_link[iLink].marker = GetNameParam(buffer+i+3, 1); iLink ++; } font &= ~Gfx::FONT_MASK_HIGHLIGHT; @@ -1622,7 +1608,7 @@ bool CEdit::ReadText(const char *filename, int addSize) { if ( m_markerTotal < EDITLINKMAX ) { - GetNameParam(buffer+i+3, 0, m_marker[m_markerTotal].name); + m_marker[m_markerTotal].name = GetNameParam(buffer+i+3, 0); m_marker[m_markerTotal].pos = j; m_markerTotal ++; } @@ -1640,21 +1626,19 @@ bool CEdit::ReadText(const char *filename, int addSize) { if ( m_bSoluce || !bInSoluce ) { -#if _DEMO - strcpy(iName, "demo"); -#else - GetNameParam(buffer+i+7, 0, iName); -#endif + + strcpy(iName, GetNameParam(buffer+i+7, 0).c_str()); + //? iWidth = m_lineHeight*RetValueParam(buffer+i+7, 1); iWidth = static_cast<float>(GetValueParam(buffer+i+7, 1)); iWidth *= m_engine->GetText()->GetHeight(Gfx::FONT_COLOBOT, Gfx::FONT_SIZE_SMALL); iLines = GetValueParam(buffer+i+7, 2); - LoadImage(iName); + LoadImage(std::string(iName)); // A part of image per line of text. for ( iCount=0 ; iCount<iLines ; iCount++ ) { - strcpy(m_image[iIndex].name, iName); + m_image[iIndex].name = iName; m_image[iIndex].offset = static_cast<float>(iCount/iLines); m_image[iIndex].height = 1.0f/iLines; m_image[iIndex].width = iWidth*0.75f; @@ -1888,7 +1872,7 @@ bool CEdit::ReadText(const char *filename, int addSize) // Writes all the text in a file. -bool CEdit::WriteText(const char *filename) +bool CEdit::WriteText(std::string filename) { FILE* file; char buffer[1000+20]; @@ -1896,7 +1880,7 @@ bool CEdit::WriteText(const char *filename) float iDim; if ( filename[0] == 0 ) return false; - file = fopen(filename, "wb"); + file = fopen(filename.c_str(), "wb"); if ( file == NULL ) return false; if ( m_bAutoIndent ) @@ -1998,12 +1982,12 @@ bool CEdit::GetEditCap() // Mode management "hilitable" (that's the franch). -void CEdit::SetHiliteCap(bool bEnable) +void CEdit::SetHighlightCap(bool bEnable) { m_bHilite = bEnable; } -bool CEdit::GetHiliteCap() +bool CEdit::GetHighlightCap() { return m_bHilite; } diff --git a/src/ui/edit.h b/src/ui/edit.h index 8f46445..1cfec80 100644 --- a/src/ui/edit.h +++ b/src/ui/edit.h @@ -35,7 +35,13 @@ #include "common/restext.h" #include <set> +#include <string> +#include <cstdlib> +#include <boost/filesystem.hpp> +#include <boost/algorithm/string.hpp> + +namespace fs = boost::filesystem; namespace Ui { @@ -84,7 +90,7 @@ enum OperUndo struct ImageLine { //! name of the image (without diagram \) - char name[40]; + std::string name; //! vertical offset (v texture) float offset; //! height of the part (dv texture) @@ -96,15 +102,15 @@ struct ImageLine struct HyperLink { //! text file name (without help \) - char name[40]; + std::string name; //! name of the marker - char marker[20]; + std::string marker; }; struct HyperMarker { //! name of the marker - char name[20]; + std::string name; //! position in the text int pos; }; @@ -112,7 +118,7 @@ struct HyperMarker struct HyperHistory { //! full file name text - char filename[50]; + std::string filename; //! rank of the first displayed line int firstLine; }; @@ -140,8 +146,8 @@ public: char* GetText(); int GetTextLength(); - bool ReadText(const char *filename, int addSize=0); - bool WriteText(const char *filename); + bool ReadText(std::string filename, int addSize=0); + bool WriteText(std::string filename); void SetMaxChar(int max); int GetMaxChar(); @@ -149,8 +155,8 @@ public: void SetEditCap(bool bMode); bool GetEditCap(); - void SetHiliteCap(bool bEnable); - bool GetHiliteCap(); + void SetHighlightCap(bool bEnable); + bool GetHighlightCap(); void SetInsideScroll(bool bInside); bool GetInsideScroll(); @@ -183,7 +189,7 @@ public: bool Undo(); void HyperFlush(); - void HyperHome(const char *filename); + void HyperHome(std::string filename); bool HyperTest(EventType event); bool HyperGo(EventType event); @@ -202,15 +208,15 @@ protected: int MouseDetect(Math::Point mouse); void MoveAdjust(); - void HyperJump(const char *name, const char *marker); - bool HyperAdd(const char *filename, int firstLine); + void HyperJump(std::string name, std::string marker); + bool HyperAdd(std::string filename, int firstLine); - void DrawImage(Math::Point pos, const char *name, float width, float offset, float height, int nbLine); + void DrawImage(Math::Point pos, std::string name, float width, float offset, float height, int nbLine); void DrawBack(Math::Point pos, Math::Point dim); void DrawPart(Math::Point pos, Math::Point dim, int icon); void FreeImage(); - void LoadImage(const char *name); + void LoadImage(std::string name); void Scroll(int pos, bool bAdjustCursor); void Scroll(); void MoveChar(int move, bool bWord, bool bSelect); diff --git a/src/ui/maindialog.cpp b/src/ui/maindialog.cpp index fede0b7..8b97f4e 100644 --- a/src/ui/maindialog.cpp +++ b/src/ui/maindialog.cpp @@ -745,6 +745,10 @@ pb->SetState(STATE_SHADOW); m_phase == PHASE_USER || m_phase == PHASE_PROTO ) { + if (!m_sound->IsPlayingMusic()) { + m_sound->PlayMusic(11, true); + } + if ( m_phase == PHASE_TRAINER ) m_index = 0; if ( m_phase == PHASE_DEFI ) m_index = 1; if ( m_phase == PHASE_MISSION ) m_index = 2; @@ -887,7 +891,7 @@ pb->SetState(STATE_SHADOW); pe->SetState(STATE_SHADOW); pe->SetMaxChar(500); pe->SetEditCap(false); // just to see - pe->SetHiliteCap(false); + pe->SetHighlightCap(false); // Button displays the "soluce": if ( m_phase != PHASE_TRAINER && @@ -1811,7 +1815,7 @@ pos.y -= 0.048f; pe = pw->CreateEdit(pos, ddim, 0, EVENT_EDIT1); pe->SetGenericMode(true); pe->SetEditCap(false); - pe->SetHiliteCap(false); + pe->SetHighlightCap(false); pe->SetFontType(Gfx::FONT_COURIER); pe->SetFontSize(8.0f); pe->ReadText("help/authors.txt"); @@ -1823,7 +1827,7 @@ pos.y -= 0.048f; pe = pw->CreateEdit(pos, ddim, 0, EVENT_EDIT2); pe->SetGenericMode(true); pe->SetEditCap(false); - pe->SetHiliteCap(false); + pe->SetHighlightCap(false); pe->SetFontType(Gfx::FONT_COURIER); pe->SetFontSize(6.5f); pe->ReadText("help/licences.txt"); @@ -1843,7 +1847,7 @@ ddim.y = 150.0f/480.0f; pe = pw->CreateEdit(pos, ddim, 0, EVENT_EDIT1); pe->SetGenericMode(true); pe->SetEditCap(false); - pe->SetHiliteCap(false); + pe->SetHighlightCap(false); pe->SetFontType(Gfx::FONT_COURIER); pe->SetFontSize(8.0f); pe->ReadText("help/authors.txt"); @@ -1876,7 +1880,7 @@ ddim.y = 150.0f/480.0f; // TODO: #if !_DEMO pos.x = 40.0f/640.0f; - pos.y = 83.0f/480.0f; + pos.y = 65.0f/480.0f; ddim.x = 246.0f/640.0f; ddim.y = 16.0f/480.0f; GetResource(RES_TEXT, RT_GENERIC_DEV1, name); @@ -1884,14 +1888,14 @@ ddim.y = 150.0f/480.0f; pl->SetFontType(Gfx::FONT_COURIER); pl->SetFontSize(8.0f); - pos.y = 13.0f/480.0f; + pos.y = 0.0f/480.0f; GetResource(RES_TEXT, RT_GENERIC_DEV2, name); pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL2, name); pl->SetFontType(Gfx::FONT_COURIER); pl->SetFontSize(8.0f); pos.x = 355.0f/640.0f; - pos.y = 83.0f/480.0f; + pos.y = 65.0f/480.0f; ddim.x = 246.0f/640.0f; ddim.y = 16.0f/480.0f; GetResource(RES_TEXT, RT_GENERIC_EDIT1, name); @@ -1899,7 +1903,7 @@ ddim.y = 150.0f/480.0f; pl->SetFontType(Gfx::FONT_COURIER); pl->SetFontSize(8.0f); - pos.y = 13.0f/480.0f; + pos.y = 0.0f/480.0f; GetResource(RES_TEXT, RT_GENERIC_EDIT2, name); pl = pw->CreateLabel(pos, ddim, 0, EVENT_LABEL4, name); pl->SetFontType(Gfx::FONT_COURIER); @@ -3555,11 +3559,11 @@ void CMainDialog::SetUserDir(char *base, int rank) if ( strcmp(base, "user") == 0 && rank >= 100 ) { dir = m_userDir + "/" + m_userList.at(rank/100-1); - UserDir(true, dir.c_str()); + GetProfile().SetUserDir(dir); } else { - UserDir(false, ""); + GetProfile().SetUserDir(""); } } @@ -4254,7 +4258,6 @@ bool CMainDialog::IsIOReadScene() FILE* file; std::string filename; - //TODO: Change this to point user dir acocrding to operating system filename = m_savegameDir + "/" + m_main->GetGamerName() + "/" + "save" + m_sceneName[0] + "000/data.sav"; file = fopen(filename.c_str(), "r"); if ( file == NULL ) return false; @@ -4350,7 +4353,7 @@ void CMainDialog::IOReadList() filename = m_savegameDir + "/" + m_main->GetGamerName() + "/save" + m_sceneName[0] + rankStream.str()+ "/data.sav"; // sprintf(filename, "%s\\%s\\save%c%.3d\\data.sav", m_savegameDir, m_main->GetGamerName(), m_sceneName[0], j); - file = fopen(filename.c_str(), "r"); + file = fopen(fs::path(filename).make_preferred().string().c_str(), "r"); if ( file == NULL ) break; while ( fgets(line, 500, file) != NULL ) @@ -5042,8 +5045,8 @@ void CMainDialog::UpdateDisplayDevice() CWindow* pw; CList* pl; char bufDevices[1000]; - char bufModes[5000]; - int i, j, totalDevices, selectDevices, totalModes, selectModes; + //char bufModes[5000]; + int i, j; pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5)); if ( pw == 0 ) return; @@ -5051,7 +5054,7 @@ void CMainDialog::UpdateDisplayDevice() if ( pl == 0 ) return; pl->Flush(); - bufModes[0] = 0; + //bufModes[0] = 0; /* TODO: remove device choice m_engine->EnumDevices(bufDevices, 1000, bufModes, 5000, @@ -5066,10 +5069,10 @@ void CMainDialog::UpdateDisplayDevice() while ( bufDevices[i++] != 0 ); } - pl->SetSelect(selectDevices); + pl->SetSelect(0); pl->ShowSelect(false); - m_setupSelDevice = selectDevices; + m_setupSelDevice = 0; } // Updates the list of modes. @@ -5106,8 +5109,8 @@ void CMainDialog::ChangeDisplay() CWindow* pw; CList* pl; CCheck* pc; - char* device; - char* mode; + //char* device; + //char* mode; bool bFull; pw = static_cast<CWindow*>(m_interface->SearchControl(EVENT_WINDOW5)); @@ -5116,12 +5119,12 @@ void CMainDialog::ChangeDisplay() pl = static_cast<CList*>(pw->SearchControl(EVENT_LIST1)); if ( pl == 0 ) return; m_setupSelDevice = pl->GetSelect(); - device = pl->GetName(m_setupSelDevice); + //device = pl->GetName(m_setupSelDevice); pl = static_cast<CList*>(pw->SearchControl(EVENT_LIST2)); if ( pl == 0 ) return; m_setupSelMode = pl->GetSelect(); - mode = pl->GetName(m_setupSelMode); + //mode = pl->GetName(m_setupSelMode); pc = static_cast<CCheck*>(pw->SearchControl(EVENT_INTERFACE_FULL)); if ( pc == 0 ) return; diff --git a/src/ui/maindialog.h b/src/ui/maindialog.h index be61299..a79b95e 100644 --- a/src/ui/maindialog.h +++ b/src/ui/maindialog.h @@ -23,6 +23,12 @@ #include "object/robotmain.h" +#include <boost/filesystem.hpp> +#include <boost/algorithm/string.hpp> + +namespace fs = boost::filesystem; + + class CEventQueue; class CSoundInterface; diff --git a/src/ui/studio.cpp b/src/ui/studio.cpp index bf2ff33..da18d83 100644 --- a/src/ui/studio.cpp +++ b/src/ui/studio.cpp @@ -990,13 +990,13 @@ void CStudio::UpdateButtons() { edit->SetIcon(1); // red background edit->SetEditCap(false); // just to see - edit->SetHiliteCap(true); + edit->SetHighlightCap(true); } else { edit->SetIcon(0); // standard background edit->SetEditCap(true); - edit->SetHiliteCap(true); + edit->SetHighlightCap(true); } button = static_cast< CButton* >(pw->SearchControl(EVENT_STUDIO_COMPILE)); @@ -1477,8 +1477,7 @@ void CStudio::UpdateDialogPublic() CCheck* pc; CLabel* pl; char name[100]; - char dir[MAX_FNAME]; - char text[MAX_FNAME+100]; + //char text[MAX_FNAME+100]; pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW9)); if ( pw == nullptr ) return; @@ -1499,9 +1498,7 @@ void CStudio::UpdateDialogPublic() if ( pl != 0 ) { GetResource(RES_TEXT, RT_IO_LIST, name); - SearchDirectory(dir, false); - sprintf(text, name, dir); - pl->SetName(text, false); + pl->SetName(SearchDirectory(false).c_str(), false); } } @@ -1509,84 +1506,52 @@ void CStudio::UpdateDialogPublic() void CStudio::UpdateDialogList() { - // TODO rewrite to multiplatform - /*CWindow* pw; - CList* pl; - long hFile; - struct _finddata_t fileBuffer; - struct _finddata_t* listBuffer; - bool bDo; - char dir[MAX_FNAME]; - char temp[MAX_FNAME]; - int nbFilenames, i; - - pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW9); + CWindow* pw; + CList* pl; + fs::path path; + int i = 0; + char time[100]; + char temp[100]; + + pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW9)); if ( pw == nullptr ) return; - pl = static_cast< CList* >(pw->SearchControl(EVENT_DIALOG_LIST); - if ( pl == 0 ) return; + pl = static_cast< CList* >(pw->SearchControl(EVENT_DIALOG_LIST)); + if ( pl == nullptr ) return; pl->Flush(); - nbFilenames = 0; - listBuffer = (_finddata_t*)malloc(sizeof(_finddata_t)*1000); - - SearchDirectory(dir, false); - strcat(dir, "*"); // list all - hFile = _findfirst(dir, &fileBuffer); - if ( hFile != -1 ) - { - do - { - if ( (fileBuffer.attrib & _A_SUBDIR) == 0 ) - { - listBuffer[nbFilenames++] = fileBuffer; - } - } - while ( _findnext(hFile, &fileBuffer) == 0 && nbFilenames < 1000 ); - } - do // sorts all names: - { - bDo = false; - for ( i=0 ; i<nbFilenames-1 ; i++ ) - { - if ( strcmp(listBuffer[i].name, listBuffer[i+1].name) > 0 ) - { - fileBuffer = listBuffer[i]; // exchange i and i +1 - listBuffer[i] = listBuffer[i+1]; - listBuffer[i+1] = fileBuffer; - bDo = true; + path = fs::path(SearchDirectory(false)); + fs::directory_iterator end_iter; + if ( fs::exists(path) && fs::is_directory(path) ) { + for( fs::directory_iterator file(path); file != end_iter; file++) { + if (fs::is_regular_file(file->status()) ) { + TimeToAscii(fs::last_write_time(file->path()), time); + sprintf(temp, "%s\t%lu \t%s", file->path().filename().string().c_str(), fs::file_size(file->path()), time); + + pl->SetName(i++, temp); } } } - while ( bDo ); - - for ( i=0 ; i<nbFilenames ; i++ ) - { - TimeToAscii(listBuffer[i].time_write, dir); - sprintf(temp, "%s\t%d \t%s", listBuffer[i].name, listBuffer[i].size, dir); - pl->SetName(i, temp); - } - - free(listBuffer);*/ } // Constructs the name of the folder or open/save. // If the folder does not exist, it will be created. -void CStudio::SearchDirectory(char *dir, bool bCreate) +std::string CStudio::SearchDirectory(bool bCreate) { - if ( m_main->GetIOPublic() ) - { - sprintf(dir, "%s\\", m_main->GetPublicDir()); + char dir[MAX_FNAME]; + if ( m_main->GetIOPublic() ) { + sprintf(dir, "%s/", m_main->GetPublicDir()); + } else { + sprintf(dir, "%s/%s/Program/", m_main->GetSavegameDir(), m_main->GetGamerName()); } - else - { - sprintf(dir, "%s\\%s\\Program\\", m_main->GetSavegameDir(), m_main->GetGamerName()); + + fs::path path = fs::path(dir); + + if ( bCreate ) { + fs::create_directory(path); } - if ( bCreate ) - {// TODO -// mkdir(dir,0777); // if does not exist yet! - } + return path.make_preferred().string(); } // Reads a new program. @@ -1612,7 +1577,7 @@ bool CStudio::ReadProgram() { strcat(filename, ".txt"); } - SearchDirectory(dir, true); + strcpy(dir, SearchDirectory(true).c_str()); strcat(dir, filename); pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW3)); @@ -1650,7 +1615,7 @@ bool CStudio::WriteProgram() { strcat(filename, ".txt"); } - SearchDirectory(dir, true); + strcpy(dir, SearchDirectory(true).c_str()); strcat(dir, filename); pw = static_cast< CWindow* >(m_interface->SearchControl(EVENT_WINDOW3)); @@ -1658,7 +1623,7 @@ bool CStudio::WriteProgram() pe = static_cast< CEdit* >(pw->SearchControl(EVENT_STUDIO_EDIT)); if ( pe == nullptr ) return false; - if ( !pe->WriteText(dir) ) return false; + if ( !pe->WriteText(std::string(dir)) ) return false; m_script->SetFilename(filename); return true; diff --git a/src/ui/studio.h b/src/ui/studio.h index 7c2f652..1c14124 100644 --- a/src/ui/studio.h +++ b/src/ui/studio.h @@ -22,6 +22,9 @@ #include "graphics/engine/camera.h" +#include <boost/filesystem.hpp> + +namespace fs = boost::filesystem; #include <string> @@ -81,7 +84,7 @@ protected: void UpdateDialogAction(); void UpdateDialogPublic(); void UpdateDialogList(); - void SearchDirectory(char* dir, bool bCreate); + std::string SearchDirectory(bool bCreate); bool ReadProgram(); bool WriteProgram(); diff --git a/test/envs/opengl/CMakeLists.txt b/test/envs/opengl/CMakeLists.txt index 3de5466..d6c3a37 100644 --- a/test/envs/opengl/CMakeLists.txt +++ b/test/envs/opengl/CMakeLists.txt @@ -2,6 +2,14 @@ set(SRC_DIR ${colobot_SOURCE_DIR}/src) configure_file(${SRC_DIR}/common/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/common/config.h) +# Platform-dependent implementation of system.h +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(SYSTEM_CPP_MODULE "system_windows.cpp") +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(SYSTEM_CPP_MODULE "system_linux.cpp") +else() + set(SYSTEM_CPP_MODULE "system_other.cpp") +endif() set(TEXTURE_SOURCES ${SRC_DIR}/graphics/opengl/gldevice.cpp @@ -17,6 +25,7 @@ ${SRC_DIR}/common/logger.cpp ${SRC_DIR}/common/image.cpp ${SRC_DIR}/common/stringutils.cpp ${SRC_DIR}/app/system.cpp +${SRC_DIR}/app/${SYSTEM_CPP_MODULE} model_test.cpp ) @@ -25,6 +34,7 @@ ${SRC_DIR}/graphics/opengl/gldevice.cpp ${SRC_DIR}/common/logger.cpp ${SRC_DIR}/common/image.cpp ${SRC_DIR}/app/system.cpp +${SRC_DIR}/app/${SYSTEM_CPP_MODULE} transform_test.cpp ) @@ -33,6 +43,7 @@ ${SRC_DIR}/graphics/opengl/gldevice.cpp ${SRC_DIR}/common/logger.cpp ${SRC_DIR}/common/image.cpp ${SRC_DIR}/app/system.cpp +${SRC_DIR}/app/${SYSTEM_CPP_MODULE} light_test.cpp ) diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index f6a1d75..34027b8 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -1,21 +1,222 @@ set(SRC_DIR ${colobot_SOURCE_DIR}/src) -include_directories( -${SRC_DIR} -${GTEST_INCLUDE_DIR} -math -common +# Additional libraries per platform +if (${MXE}) # MXE requires special treatment + set(PLATFORM_LIBS ${MXE_LIBS}) +elseif (${PLATFORM_WINDOWS}) + # because it isn't included in standard linking libraries + set(PLATFORM_LIBS "-lintl") +elseif(${PLATFORM_LINUX}) + # for clock_gettime + set(PLATFORM_LIBS "-lrt") +endif() + + +# Configure file +configure_file(${SRC_DIR}/common/config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/common/config.h) + +# Platform-dependent implementation of system.h +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + set(SYSTEM_CPP_MODULE "system_windows.cpp") +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(SYSTEM_CPP_MODULE "system_linux.cpp") +else() + set(SYSTEM_CPP_MODULE "system_other.cpp") +endif() + +# Code sources +set(COLOBOT_SOURCES +${SRC_DIR}/app/app.cpp +${SRC_DIR}/app/system.cpp +${SRC_DIR}/app/${SYSTEM_CPP_MODULE} +${SRC_DIR}/common/event.cpp +${SRC_DIR}/common/image.cpp +${SRC_DIR}/common/iman.cpp +${SRC_DIR}/common/logger.cpp +${SRC_DIR}/common/misc.cpp +${SRC_DIR}/common/profile.cpp +${SRC_DIR}/common/restext.cpp +${SRC_DIR}/common/stringutils.cpp +${SRC_DIR}/graphics/core/color.cpp +${SRC_DIR}/graphics/engine/camera.cpp +${SRC_DIR}/graphics/engine/cloud.cpp +${SRC_DIR}/graphics/engine/engine.cpp +${SRC_DIR}/graphics/engine/lightman.cpp +${SRC_DIR}/graphics/engine/lightning.cpp +${SRC_DIR}/graphics/engine/modelfile.cpp +${SRC_DIR}/graphics/engine/modelmanager.cpp +${SRC_DIR}/graphics/engine/particle.cpp +${SRC_DIR}/graphics/engine/planet.cpp +${SRC_DIR}/graphics/engine/pyro.cpp +${SRC_DIR}/graphics/engine/terrain.cpp +${SRC_DIR}/graphics/engine/text.cpp +${SRC_DIR}/graphics/engine/water.cpp +${SRC_DIR}/graphics/opengl/gldevice.cpp +${SRC_DIR}/object/auto/auto.cpp +${SRC_DIR}/object/auto/autobase.cpp +${SRC_DIR}/object/auto/autoconvert.cpp +${SRC_DIR}/object/auto/autoderrick.cpp +${SRC_DIR}/object/auto/autodestroyer.cpp +${SRC_DIR}/object/auto/autoegg.cpp +${SRC_DIR}/object/auto/autoenergy.cpp +${SRC_DIR}/object/auto/autofactory.cpp +${SRC_DIR}/object/auto/autoflag.cpp +${SRC_DIR}/object/auto/autohuston.cpp +${SRC_DIR}/object/auto/autoinfo.cpp +${SRC_DIR}/object/auto/autojostle.cpp +${SRC_DIR}/object/auto/autokid.cpp +${SRC_DIR}/object/auto/autolabo.cpp +${SRC_DIR}/object/auto/automush.cpp +${SRC_DIR}/object/auto/autonest.cpp +${SRC_DIR}/object/auto/autonuclear.cpp +${SRC_DIR}/object/auto/autopara.cpp +${SRC_DIR}/object/auto/autoportico.cpp +${SRC_DIR}/object/auto/autoradar.cpp +${SRC_DIR}/object/auto/autorepair.cpp +${SRC_DIR}/object/auto/autoresearch.cpp +${SRC_DIR}/object/auto/autoroot.cpp +${SRC_DIR}/object/auto/autosafe.cpp +${SRC_DIR}/object/auto/autostation.cpp +${SRC_DIR}/object/auto/autotower.cpp +${SRC_DIR}/object/brain.cpp +${SRC_DIR}/object/mainmovie.cpp +${SRC_DIR}/object/motion/motion.cpp +${SRC_DIR}/object/motion/motionant.cpp +${SRC_DIR}/object/motion/motionbee.cpp +${SRC_DIR}/object/motion/motionhuman.cpp +${SRC_DIR}/object/motion/motionmother.cpp +${SRC_DIR}/object/motion/motionspider.cpp +${SRC_DIR}/object/motion/motiontoto.cpp +${SRC_DIR}/object/motion/motionvehicle.cpp +${SRC_DIR}/object/motion/motionworm.cpp +${SRC_DIR}/object/object.cpp +${SRC_DIR}/object/robotmain.cpp +${SRC_DIR}/object/task/task.cpp +${SRC_DIR}/object/task/taskadvance.cpp +${SRC_DIR}/object/task/taskbuild.cpp +${SRC_DIR}/object/task/taskfire.cpp +${SRC_DIR}/object/task/taskfireant.cpp +${SRC_DIR}/object/task/taskflag.cpp +${SRC_DIR}/object/task/taskgoto.cpp +${SRC_DIR}/object/task/taskgungoal.cpp +${SRC_DIR}/object/task/taskinfo.cpp +${SRC_DIR}/object/task/taskmanager.cpp +${SRC_DIR}/object/task/taskmanip.cpp +${SRC_DIR}/object/task/taskpen.cpp +${SRC_DIR}/object/task/taskrecover.cpp +${SRC_DIR}/object/task/taskreset.cpp +${SRC_DIR}/object/task/tasksearch.cpp +${SRC_DIR}/object/task/taskshield.cpp +${SRC_DIR}/object/task/taskspiderexplo.cpp +${SRC_DIR}/object/task/tasktake.cpp +${SRC_DIR}/object/task/taskterraform.cpp +${SRC_DIR}/object/task/taskturn.cpp +${SRC_DIR}/object/task/taskwait.cpp +${SRC_DIR}/physics/physics.cpp +${SRC_DIR}/script/cbottoken.cpp +${SRC_DIR}/script/cmdtoken.cpp +${SRC_DIR}/script/script.cpp +${SRC_DIR}/ui/button.cpp +${SRC_DIR}/ui/check.cpp +${SRC_DIR}/ui/color.cpp +${SRC_DIR}/ui/compass.cpp +${SRC_DIR}/ui/control.cpp +${SRC_DIR}/ui/displayinfo.cpp +${SRC_DIR}/ui/displaytext.cpp +${SRC_DIR}/ui/edit.cpp +${SRC_DIR}/ui/editvalue.cpp +${SRC_DIR}/ui/gauge.cpp +${SRC_DIR}/ui/group.cpp +${SRC_DIR}/ui/image.cpp +${SRC_DIR}/ui/interface.cpp +${SRC_DIR}/ui/key.cpp +${SRC_DIR}/ui/label.cpp +${SRC_DIR}/ui/list.cpp +${SRC_DIR}/ui/maindialog.cpp +${SRC_DIR}/ui/mainmap.cpp +${SRC_DIR}/ui/mainshort.cpp +${SRC_DIR}/ui/map.cpp +${SRC_DIR}/ui/scroll.cpp +${SRC_DIR}/ui/shortcut.cpp +${SRC_DIR}/ui/slider.cpp +${SRC_DIR}/ui/studio.cpp +${SRC_DIR}/ui/target.cpp +${SRC_DIR}/ui/window.cpp ) +set(OPENAL_SOURCES "") + +if (${OPENAL_SOUND}) + set(OPENAL_SOURCES + ${SRC_DIR}/sound/oalsound/alsound.cpp + ${SRC_DIR}/sound/oalsound/buffer.cpp + ${SRC_DIR}/sound/oalsound/channel.cpp + ) +endif() + +# Optional libraries +set(OPTIONAL_LIBS "") + +if (${OPENAL_SOUND}) + if (${PLATFORM_WINDOWS}) + set(OPTIONAL_LIBS + OpenAL32 + ) + else() + set(OPTIONAL_LIBS + openal + ) + endif() +endif() + + +# Platform-dependent tests +if (${CMAKE_SYSTEM_NAME} MATCHES "Windows") + #TODO: set(PLATFORM_TESTS app/system_windows_test.cpp) +elseif(${CMAKE_SYSTEM_NAME} MATCHES "Linux") + set(PLATFORM_TESTS app/system_linux_test.cpp) +else() + #TODO: set(PLATFORM_TESTS app/system_other_test.cpp) +endif() + +# Tests set(UT_SOURCES main.cpp +graphics/engine/lightman_test.cpp math/geometry_test.cpp math/matrix_test.cpp math/vector_test.cpp +${PLATFORM_TESTS} +) + +include_directories( +${CMAKE_CURRENT_BINARY_DIR} +${SRC_DIR} +${GTEST_INCLUDE_DIR} +${GMOCK_INCLUDE_DIR} +. +common +math +) + +set(LIBS +gtest +gmock +CBot +${SDL_LIBRARY} +${SDLIMAGE_LIBRARY} +${SDLTTF_LIBRARY} +${OPENGL_LIBRARY} +${PNG_LIBRARIES} +${GLEW_LIBRARY} +${Boost_LIBRARIES} +${OPTIONAL_LIBS} +${PLATFORM_LIBS} +${LIBSNDFILE_LIBRARY} ) -add_executable(colobot_ut ${UT_SOURCES}) -target_link_libraries(colobot_ut gtest) +add_executable(colobot_ut ${COLOBOT_SOURCES} ${UT_SOURCES} ${OPENAL_SOURCES}) +target_link_libraries(colobot_ut ${LIBS}) add_test(colobot_ut ./colobot_ut) diff --git a/test/unit/app/system_linux_test.cpp b/test/unit/app/system_linux_test.cpp new file mode 100644 index 0000000..fe89399 --- /dev/null +++ b/test/unit/app/system_linux_test.cpp @@ -0,0 +1,51 @@ +#include "app/system.h" +#include "app/system_linux.h" + +#include <gtest/gtest.h> + +TEST(SystemLinuxTest, TimeStampDiff) +{ + const long long SEC = 1000000000; + + SystemTimeStamp before, after; + + before.clockTime.tv_sec = 1; + before.clockTime.tv_nsec = 100; + + after.clockTime.tv_sec = 1; + after.clockTime.tv_nsec = 900; + + long long tDiff = TimeStampExactDiff_Linux(&before, &after); + EXPECT_EQ( 800, tDiff); + + tDiff = TimeStampExactDiff_Linux(&after, &before); + EXPECT_EQ(-800, tDiff); + + // ------- + + before.clockTime.tv_sec = 2; + before.clockTime.tv_nsec = 200; + + after.clockTime.tv_sec = 3; + after.clockTime.tv_nsec = 500; + + tDiff = TimeStampExactDiff_Linux(&before, &after); + EXPECT_EQ( SEC + 300, tDiff); + + tDiff = TimeStampExactDiff_Linux(&after, &before); + EXPECT_EQ(-SEC - 300, tDiff); + + // ------- + + before.clockTime.tv_sec = 3; + before.clockTime.tv_nsec = 200; + + after.clockTime.tv_sec = 4; + after.clockTime.tv_nsec = 100; + + tDiff = TimeStampExactDiff_Linux(&before, &after); + EXPECT_EQ( SEC - 100, tDiff); + + tDiff = TimeStampExactDiff_Linux(&after, &before); + EXPECT_EQ(-SEC + 100, tDiff); +} diff --git a/test/unit/graphics/core/device_mock.h b/test/unit/graphics/core/device_mock.h new file mode 100644 index 0000000..80e214f --- /dev/null +++ b/test/unit/graphics/core/device_mock.h @@ -0,0 +1,107 @@ +#pragma once + +#include "graphics/core/device.h" + +#include <gmock/gmock.h> + +class CDeviceMock : public Gfx::CDevice +{ +public: + CDeviceMock() {} + + MOCK_METHOD0(DebugHook, void()); + + MOCK_METHOD0(Create, bool()); + MOCK_METHOD0(Destroy, void()); + + MOCK_METHOD0(BeginScene, void()); + MOCK_METHOD0(EndScene, void()); + + MOCK_METHOD0(Clear, void()); + + MOCK_METHOD2(SetTransform, void(Gfx::TransformType type, const Math::Matrix &matrix)); + MOCK_METHOD1(GetTransform, const Math::Matrix& (Gfx::TransformType type)); + MOCK_METHOD2(MultiplyTransform, void(Gfx::TransformType type, const Math::Matrix &matrix)); + + MOCK_METHOD1(SetMaterial, void(const Gfx::Material &material)); + MOCK_METHOD0(GetMaterial, const Gfx::Material&()); + + MOCK_METHOD0(GetMaxLightCount, int()); + + MOCK_METHOD2(SetLight, void(int index, const Gfx::Light &light)); + MOCK_METHOD1(GetLight, const Gfx::Light&(int index)); + + MOCK_METHOD2(SetLightEnabled, void(int index, bool enabled)); + MOCK_METHOD1(GetLightEnabled, bool(int index)); + + MOCK_METHOD2(CreateTexture, Gfx::Texture(CImage *image, const Gfx::TextureCreateParams ¶ms)); + MOCK_METHOD2(CreateTexture, Gfx::Texture(ImageData *data, const Gfx::TextureCreateParams ¶ms)); + + MOCK_METHOD1(DestroyTexture, void(const Gfx::Texture &texture)); + MOCK_METHOD0(DestroyAllTextures, void()); + + MOCK_METHOD0(GetMaxTextureStageCount, int()); + + MOCK_METHOD2(SetTexture, void(int index, const Gfx::Texture &texture)); + MOCK_METHOD2(SetTexture, void(int index, unsigned int textureId)); + MOCK_METHOD1(GetTexture, Gfx::Texture(int index)); + + MOCK_METHOD2(SetTextureEnabled, void(int index, bool enabled)); + MOCK_METHOD1(GetTextureEnabled, bool(int index)); + + MOCK_METHOD2(SetTextureStageParams, void(int index, const Gfx::TextureStageParams ¶ms)); + MOCK_METHOD1(GetTextureStageParams, Gfx::TextureStageParams(int index)); + + MOCK_METHOD3(SetTextureStageWrap, void(int index, Gfx::TexWrapMode wrapS, Gfx::TexWrapMode wrapT)); + + MOCK_METHOD4(DrawPrimitive, void(Gfx::PrimitiveType type, const Gfx::Vertex *vertices, int vertexCount, Gfx::Color color)); + MOCK_METHOD4(DrawPrimitive, void(Gfx::PrimitiveType type, const Gfx::VertexTex2 *vertices, int vertexCount, Gfx::Color color)); + MOCK_METHOD3(DrawPrimitive, void(Gfx::PrimitiveType type, const Gfx::VertexCol *vertices, int vertexCount)); + + MOCK_METHOD3(CreateStaticBuffer, unsigned int(Gfx::PrimitiveType primitiveType, const Gfx::Vertex* vertices, int vertexCount)); + MOCK_METHOD3(CreateStaticBuffer, unsigned int(Gfx::PrimitiveType primitiveType, const Gfx::VertexTex2* vertices, int vertexCount)); + MOCK_METHOD3(CreateStaticBuffer, unsigned int(Gfx::PrimitiveType primitiveType, const Gfx::VertexCol* vertices, int vertexCount)); + + MOCK_METHOD4(UpdateStaticBuffer, void(unsigned int bufferId, Gfx::PrimitiveType primitiveType, const Gfx::Vertex* vertices, int vertexCount)); + MOCK_METHOD4(UpdateStaticBuffer, void(unsigned int bufferId, Gfx::PrimitiveType primitiveType, const Gfx::VertexTex2* vertices, int vertexCount)); + MOCK_METHOD4(UpdateStaticBuffer, void(unsigned int bufferId, Gfx::PrimitiveType primitiveType, const Gfx::VertexCol* vertices, int vertexCount)); + + MOCK_METHOD1(DrawStaticBuffer, void(unsigned int bufferId)); + + MOCK_METHOD1(DestroyStaticBuffer, void(unsigned int bufferId)); + + MOCK_METHOD2(ComputeSphereVisibility, int(const Math::Vector ¢er, float radius)); + + MOCK_METHOD2(SetRenderState, void(Gfx::RenderState state, bool enabled)); + MOCK_METHOD1(GetRenderState, bool(Gfx::RenderState state)); + + MOCK_METHOD1(SetDepthTestFunc, void(Gfx::CompFunc func)); + MOCK_METHOD0(GetDepthTestFunc, Gfx::CompFunc()); + + MOCK_METHOD1(SetDepthBias, void(float factor)); + MOCK_METHOD0(GetDepthBias, float()); + + MOCK_METHOD2(SetAlphaTestFunc, void(Gfx::CompFunc func, float refValue)); + MOCK_METHOD2(GetAlphaTestFunc, void(Gfx::CompFunc &func, float &refValue)); + + MOCK_METHOD2(SetBlendFunc, void(Gfx::BlendFunc srcBlend, Gfx::BlendFunc dstBlend)); + MOCK_METHOD2(GetBlendFunc, void(Gfx::BlendFunc &srcBlend, Gfx::BlendFunc &dstBlend)); + + MOCK_METHOD1(SetClearColor, void(const Gfx::Color &color)); + MOCK_METHOD0(GetClearColor, Gfx::Color()); + + MOCK_METHOD1(SetGlobalAmbient, void(const Gfx::Color &color)); + MOCK_METHOD0(GetGlobalAmbient, Gfx::Color()); + + MOCK_METHOD5(SetFogParams, void(Gfx::FogMode mode, const Gfx::Color &color, float start, float end, float density)); + MOCK_METHOD5(GetFogParams, void(Gfx::FogMode &mode, Gfx::Color &color, float &start, float &end, float &density)); + + MOCK_METHOD1(SetCullMode, void(Gfx::CullMode mode)); + MOCK_METHOD0(GetCullMode, Gfx::CullMode()); + + MOCK_METHOD1(SetShadeModel, void(Gfx::ShadeModel model)); + MOCK_METHOD0(GetShadeModel, Gfx::ShadeModel()); + + MOCK_METHOD1(SetFillMode, void(Gfx::FillMode mode)); + MOCK_METHOD0(GetFillMode, Gfx::FillMode()); +}; diff --git a/test/unit/graphics/engine/engine_mock.h b/test/unit/graphics/engine/engine_mock.h new file mode 100644 index 0000000..1a15eca --- /dev/null +++ b/test/unit/graphics/engine/engine_mock.h @@ -0,0 +1,14 @@ +#include "graphics/engine/engine.h" + +#include <gmock/gmock.h> + +class CEngineMock : public Gfx::CEngine +{ +public: + CEngineMock() : Gfx::CEngine(nullptr) {} + + MOCK_METHOD0(GetPause, bool()); + + MOCK_METHOD0(GetEyePt, Math::Vector()); + MOCK_METHOD0(GetLookatPt, Math::Vector()); +}; diff --git a/test/unit/graphics/engine/lightman_test.cpp b/test/unit/graphics/engine/lightman_test.cpp new file mode 100644 index 0000000..c955f0a --- /dev/null +++ b/test/unit/graphics/engine/lightman_test.cpp @@ -0,0 +1,146 @@ +#include "graphics/engine/lightman.h" + +#include "graphics/core/device_mock.h" +#include "graphics/engine/engine_mock.h" + +#include <gtest/gtest.h> + +using namespace Gfx; + +using testing::_; +using testing::Invoke; +using testing::Return; + +class LightManagerUT : public testing::Test +{ +protected: + LightManagerUT() + : lightManager(&engine) + {} + + void PrepareLightTesting(int maxLights, Math::Vector eyePos); + void CheckLightSorting(EngineObjectType objectType, const std::vector<int>& expectedLights); + void CheckLight(int index, const Light& light); + void AddLight(int type, LightPriority priority, bool used, bool enabled, + Math::Vector pos, EngineObjectType includeType, EngineObjectType excludeType); + + + CLightManager lightManager; + CEngineMock engine; + CDeviceMock device; + +private: + std::vector<DynamicLight> dynamicLights; + std::vector<int> expectedLightTypes; + int maxLightsCount; +}; + +void LightManagerUT::PrepareLightTesting(int maxLights, Math::Vector eyePos) +{ + maxLightsCount = maxLights; + + EXPECT_CALL(device, GetMaxLightCount()).WillOnce(Return(maxLights)); + lightManager.SetDevice(&device); + + ON_CALL(device, SetLight(_, _)).WillByDefault(Invoke(this, &LightManagerUT::CheckLight)); + + EXPECT_CALL(engine, GetEyePt()).WillRepeatedly(Return(eyePos)); +} + +void LightManagerUT::CheckLightSorting(EngineObjectType objectType, const std::vector<int>& expectedLights) +{ + expectedLightTypes = expectedLights; + + EXPECT_CALL(device, SetLight(_, _)).Times(expectedLights.size()); + + for (int i = 0; i < static_cast<int>( expectedLights.size() ); ++i) + EXPECT_CALL(device, SetLightEnabled(i, true)); + + for (int i = expectedLights.size(); i < maxLightsCount; ++i) + EXPECT_CALL(device, SetLightEnabled(i, false)); + + lightManager.UpdateDeviceLights(objectType); +} + +void LightManagerUT::CheckLight(int index, const Light& light) +{ + ASSERT_TRUE(index >= 0 && index < static_cast<int>( expectedLightTypes.size() )); + ASSERT_EQ(expectedLightTypes[index], light.type); +} + +void LightManagerUT::AddLight(int type, LightPriority priority, bool used, bool enabled, + Math::Vector pos, EngineObjectType includeType, EngineObjectType excludeType) +{ + int rank = lightManager.CreateLight(priority); + + Light light; + light.type = static_cast<LightType>(type); + light.position = pos; + lightManager.SetLight(rank, light); + + lightManager.SetLightEnabled(rank, enabled); + lightManager.SetLightIncludeType(rank, includeType); + lightManager.SetLightExcludeType(rank, excludeType); + + if (!used) + lightManager.DeleteLight(rank); +} + +TEST_F(LightManagerUT, LightSorting_UnusedOrDisabledAreSkipped) +{ + const int lightCount = 10; + const Math::Vector eyePos(0.0f, 0.0f, 0.0f); + PrepareLightTesting(lightCount, eyePos); + + AddLight(1, LIGHT_PRI_LOW, false, true, Math::Vector(0.0f, 0.0f, 0.0f), ENG_OBJTYPE_NULL, ENG_OBJTYPE_NULL); + AddLight(2, LIGHT_PRI_LOW, true, false, Math::Vector(0.0f, 0.0f, 0.0f), ENG_OBJTYPE_NULL, ENG_OBJTYPE_NULL); + AddLight(3, LIGHT_PRI_LOW, false, false, Math::Vector(0.0f, 0.0f, 0.0f), ENG_OBJTYPE_NULL, ENG_OBJTYPE_NULL); + + std::vector<int> expectedLights; + CheckLightSorting(ENG_OBJTYPE_TERRAIN, expectedLights); +} + +TEST_F(LightManagerUT, LightSorting_IncludeTypesAreIncluded) +{ + const int lightCount = 10; + const Math::Vector eyePos(0.0f, 0.0f, 0.0f); + PrepareLightTesting(lightCount, eyePos); + + AddLight(1, LIGHT_PRI_LOW, true, true, Math::Vector(0.0f, 0.0f, 0.0f), ENG_OBJTYPE_NULL, 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); + + std::vector<int> expectedLights = { 1, 2 }; + CheckLightSorting(ENG_OBJTYPE_TERRAIN, expectedLights); +} + +TEST_F(LightManagerUT, LightSorting_ExcludeTypesAreExcluded) +{ + const int lightCount = 10; + const Math::Vector eyePos(0.0f, 0.0f, 0.0f); + PrepareLightTesting(lightCount, eyePos); + + AddLight(1, LIGHT_PRI_LOW, true, true, Math::Vector(0.0f, 0.0f, 0.0f), ENG_OBJTYPE_NULL, ENG_OBJTYPE_NULL); + 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<int> expectedLights = { 1, 3 }; + CheckLightSorting(ENG_OBJTYPE_TERRAIN, expectedLights); +} + +TEST_F(LightManagerUT, LightSorting_SortingAccordingToDistance) +{ + const int lightCount = 3; + const Math::Vector eyePos(0.0f, 0.0f, 0.0f); + PrepareLightTesting(lightCount, eyePos); + + AddLight(1, LIGHT_PRI_HIGH, true, true, Math::Vector(10.0f, 0.0f, 0.0f), ENG_OBJTYPE_NULL, ENG_OBJTYPE_NULL); + AddLight(2, LIGHT_PRI_LOW, true, true, Math::Vector(4.0f, 0.0f, 0.0f), ENG_OBJTYPE_NULL, ENG_OBJTYPE_NULL); + AddLight(3, LIGHT_PRI_HIGH, true, true, Math::Vector(20.0f, 0.0f, 0.0f), ENG_OBJTYPE_NULL, ENG_OBJTYPE_NULL); + AddLight(4, LIGHT_PRI_LOW, true, true, Math::Vector(11.0f, 0.0f, 0.0f), ENG_OBJTYPE_NULL, ENG_OBJTYPE_NULL); + AddLight(5, LIGHT_PRI_LOW, true, true, Math::Vector(100.0f, 0.0f, 0.0f), ENG_OBJTYPE_NULL, ENG_OBJTYPE_NULL); + AddLight(6, LIGHT_PRI_HIGH, true, true, Math::Vector(21.0f, 0.0f, 0.0f), ENG_OBJTYPE_NULL, ENG_OBJTYPE_NULL); + + std::vector<int> expectedLights = { 2, 1, 3 }; + CheckLightSorting(ENG_OBJTYPE_TERRAIN, expectedLights); +} diff --git a/test/unit/ui/CMakeLists.txt b/test/unit/ui/CMakeLists.txt index 916a73b..f5945dc 100644 --- a/test/unit/ui/CMakeLists.txt +++ b/test/unit/ui/CMakeLists.txt @@ -11,6 +11,7 @@ add_executable(edit_test ${SRC_DIR}/common/event.cpp ${SRC_DIR}/common/logger.cpp ${SRC_DIR}/common/misc.cpp +${SRC_DIR}/common/profile.cpp ${SRC_DIR}/common/iman.cpp ${SRC_DIR}/common/stringutils.cpp ${SRC_DIR}/graphics/engine/text.cpp diff --git a/test/unit/ui/stubs/app_stub.cpp b/test/unit/ui/stubs/app_stub.cpp index 094806f..3df7d42 100644 --- a/test/unit/ui/stubs/app_stub.cpp +++ b/test/unit/ui/stubs/app_stub.cpp @@ -36,3 +36,7 @@ CEventQueue* CApplication::GetEventQueue() return nullptr; } +std::string CApplication::GetDataDirPath() +{ + return ""; +} diff --git a/test/unit/ui/stubs/engine_stub.cpp b/test/unit/ui/stubs/engine_stub.cpp index 40886da..0a2777c 100644 --- a/test/unit/ui/stubs/engine_stub.cpp +++ b/test/unit/ui/stubs/engine_stub.cpp @@ -77,11 +77,28 @@ int CEngine::GetEditIndentValue() void CEngine::DeleteTexture(const std::string& /* texName */) { } + Texture CEngine::LoadTexture(const std::string& /* name */) { Texture texture; return texture; } +Math::Vector CEngine::GetEyePt() +{ + return Math::Vector(); +} + +Math::Vector CEngine::GetLookatPt() +{ + return Math::Vector(); +} + +bool CEngine::GetPause() +{ + return false; +} + + } /* Gfx */ |