Skip to content

Commit

Permalink
GroupR1 image generation fix (cars in category GroupR1 uses now R1 sp…
Browse files Browse the repository at this point in the history
…ecific rpl template file). UTF8 fixes in car spec data reading. Added some basic info log printouts to the release build.
  • Loading branch information
mika-n committed May 24, 2020
1 parent 2ae35b9 commit 4665bee
Show file tree
Hide file tree
Showing 8 changed files with 254 additions and 72 deletions.
11 changes: 7 additions & 4 deletions src/CreateReleaseZip.cmd
Original file line number Diff line number Diff line change
Expand Up @@ -40,19 +40,22 @@ pause


mkdir "%RELEASE_FOLDER%\"
mkdir "%RELEASE_FOLDER%\Replays\"
rem mkdir "%RELEASE_FOLDER%\Replays\"
mkdir "%RELEASE_FOLDER%\Plugins\"
mkdir "%RELEASE_FOLDER%\Plugins\%APPNAME%\"
mkdir "%RELEASE_FOLDER%\Plugins\%APPNAME%\Replays"
mkdir "%RELEASE_FOLDER%\Plugins\%APPNAME%\preview\1920x1080\"
mkdir "%RELEASE_FOLDER%\Plugins\%APPNAME%\preview\1366x768\"

rem Dummy files because 7Zip tool would ignore empty folders
type NUL > "%RELEASE_FOLDER%\Plugins\%APPNAME%\preview\1920x1080\carImages.txt"
type NUL > "%RELEASE_FOLDER%\Plugins\%APPNAME%\preview\1366x768\carImages.txt"
echo Use Options-Plugins-NGPCarMenu-CreateCarImages menu command in RBR game to update car preview images> "%RELEASE_FOLDER%\Plugins\%APPNAME%\preview\1920x1080\carImages.txt"
copy "%RELEASE_FOLDER%\Plugins\%APPNAME%\preview\1920x1080\carImages.txt" "%RELEASE_FOLDER%\Plugins\%APPNAME%\preview\1366x768\"

copy "Release\%APPNAME%.dll" "%RELEASE_FOLDER%\Plugins\"

copy "%APPNAME%.ini" "%RELEASE_FOLDER%\Plugins\%APPNAME%.ini.sample"
copy "%APPNAME%.rpl" "%RELEASE_FOLDER%\Replays\"
copy "%APPNAME%*.rpl" "%RELEASE_FOLDER%\Plugins\%APPNAME%\Replays\"

copy "CustomCarSpecs.ini" "%RELEASE_FOLDER%\Plugins\%APPNAME%\"
copy "..\LicenseText.txt" "%RELEASE_FOLDER%\Plugins\%APPNAME%\"
copy "..\LicenseText_3rdPartyTools.txt" "%RELEASE_FOLDER%\Plugins\%APPNAME%\"
Expand Down
144 changes: 116 additions & 28 deletions src/D3D9Helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@
#include <filesystem> // fs::exists
#include <fstream> // std::ifstream and ofstream

#include <locale> // UTF8 locales
#include <codecvt>

#include <wincodec.h> // IWICxx image funcs
#include <shlwapi.h> // PathRemoveFileSpec

Expand All @@ -51,7 +54,7 @@
namespace fs = std::filesystem;

//
// Case-insensitive str comparison functions.
// Case-insensitive str comparison functions (starts with, ends with).
// s1 and s2 - Strings to compare (case-insensitive)
// s2AlreadyInLowercase - If true then s2 is already in lowercase letters, so "optimize" the comparison by converting only s1 to lowercase
// Return TRUE=Equal, FALSE=NotEqual
Expand All @@ -63,6 +66,33 @@ inline bool _iStarts_With(std::wstring s1, std::wstring s2, bool s2AlreadyInLowe
return s1._Starts_with(s2);
}

inline bool _iStarts_With(std::string s1, std::string s2, bool s2AlreadyInLowercase)
{
transform(s1.begin(), s1.end(), s1.begin(), ::tolower);
if (!s2AlreadyInLowercase) transform(s2.begin(), s2.end(), s2.begin(), ::tolower);
return s1._Starts_with(s2);
}

inline bool _iEnds_With(std::wstring s1, std::wstring s2, bool s2AlreadyInLowercase)
{
transform(s1.begin(), s1.end(), s1.begin(), ::tolower);
if (!s2AlreadyInLowercase) transform(s2.begin(), s2.end(), s2.begin(), ::tolower);
if (s1.length() >= s2.length())
return (s1.compare(s1.length() - s2.length(), s2.length(), s2) == 0);
else
return false;
}

inline bool _iEnds_With(std::string s1, std::string s2, bool s2AlreadyInLowercase)
{
transform(s1.begin(), s1.end(), s1.begin(), ::tolower);
if (!s2AlreadyInLowercase) transform(s2.begin(), s2.end(), s2.begin(), ::tolower);
if (s1.length() >= s2.length())
return (s1.compare(s1.length() - s2.length(), s2.length(), s2) == 0);
else
return false;
}

/*
inline bool _iEqual_wchar(wchar_t c1, wchar_t c2)
{
Expand Down Expand Up @@ -91,17 +121,33 @@ inline void _LTrim(std::wstring& s)
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](WCHAR c) { return !std::isspace(c); }));
}

inline void _LTrim(std::string& s)
{
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](char c) { return !std::isspace(c); }));
}

inline void _RTrim(std::wstring& s)
{
s.erase(std::find_if(s.rbegin(), s.rend(), [](WCHAR c) { return !std::isspace(c); }).base(), s.end());
}

inline void _RTrim(std::string& s)
{
s.erase(std::find_if(s.rbegin(), s.rend(), [](char c) { return !std::isspace(c); }).base(), s.end());
}

inline void _Trim(std::wstring& s)
{
_LTrim(s);
_RTrim(s);
}

inline void _Trim(std::string& s)
{
_LTrim(s);
_RTrim(s);
}

/*
inline std::wstring _LTrimCopy(std::wstring s)
{
Expand All @@ -123,7 +169,7 @@ inline std::wstring _TrimCopy(std::wstring s)
*/

//
// Convert ASCII char string to Unicode WCHAR string object or vice-versa
// Convert ASCII char string to WCHAR string object or vice-versa
//
inline std::wstring _ToWString(const std::string& s)
{
Expand All @@ -140,6 +186,40 @@ inline std::string _ToString(const std::wstring& s)
return std::string{ buf.get() };
}

std::string _ToUTF8String(const wchar_t* wszTextBuf, int iLen)
{
std::string sResult;
int iChars = ::WideCharToMultiByte(CP_UTF8, 0, wszTextBuf, iLen, nullptr, 0, nullptr, nullptr);
if (iChars > 0)
{
sResult.resize(iChars);
::WideCharToMultiByte(CP_UTF8, 0, wszTextBuf, iLen, const_cast<char*>(sResult.c_str()), iChars, nullptr, nullptr);
}
return sResult;
}

std::string _ToUTF8String(const std::wstring& s)
{
return ::_ToUTF8String(s.c_str(), (int)s.size());
}

std::wstring _ToUTF8WString(const char* szTextBuf, int iLen)
{
std::wstring sResult;
int iChars = ::MultiByteToWideChar(CP_UTF8, 0, szTextBuf, -1, nullptr, 0);
if (iChars > 0)
{
sResult.resize(iChars);
::MultiByteToWideChar(CP_UTF8, 0, szTextBuf, -1, const_cast<WCHAR*>(sResult.c_str()), iChars);
}
return sResult;
}

std::wstring _ToUTF8WString(const std::string& s)
{
return ::_ToUTF8WString(s.c_str(), (int)s.size());
}


inline void _ToLowerCase(std::string& s)
{
Expand Down Expand Up @@ -230,17 +310,17 @@ bool _StringToPoint(const std::wstring& s, POINT* outPoint, const wchar_t separa


// Return the version tag of a file as string, for example "1.0.4.0"
std::string GetFileVersionInformationAsString(const std::string& fileName)
std::string GetFileVersionInformationAsString(const std::wstring& fileName)
{
std::string sResult;

DWORD dwHandle = 0;
DWORD dwSize = GetFileVersionInfoSize(fileName.c_str(), &dwHandle);
DWORD dwSize = GetFileVersionInfoSizeW(fileName.c_str(), &dwHandle);

if (dwSize > 0)
{
LPBYTE pVerData = new BYTE[dwSize];
if (GetFileVersionInfo(fileName.c_str(), dwHandle, dwSize, pVerData))
if (GetFileVersionInfoW(fileName.c_str(), dwHandle, dwSize, pVerData))
{
LPBYTE pQryBuffer = nullptr;
UINT iLen = 0;
Expand Down Expand Up @@ -274,8 +354,8 @@ std::string GetFileVersionInformationAsString(const std::string& fileName)
//

unsigned long g_iLogMsgCount = 0; // Safety precaution in debug logger to avoid flooding the logfile. One process running prints out only max N debug lines (more than that then the plugin is probably in some infinite loop lock)
std::string g_sLogFileName;
FILE* g_fpLogFile = nullptr;
std::wstring g_sLogFileName;
std::ofstream* g_fpLogFile = nullptr;

void DebugOpenFile(bool bOverwriteFile = false)
{
Expand All @@ -285,12 +365,12 @@ void DebugOpenFile(bool bOverwriteFile = false)
{
if (g_sLogFileName.empty())
{
char szModulePath[_MAX_PATH];
::GetModuleFileName(NULL, szModulePath, sizeof(szModulePath));
::PathRemoveFileSpec(szModulePath);
wchar_t szModulePath[_MAX_PATH];
::GetModuleFileNameW(NULL, szModulePath, sizeof(szModulePath));
::PathRemoveFileSpecW(szModulePath);

g_sLogFileName = szModulePath;
g_sLogFileName = g_sLogFileName + "\\Plugins\\NGPCarMenu\\NGPCarMenu.log";
g_sLogFileName = g_sLogFileName + L"\\Plugins\\NGPCarMenu\\NGPCarMenu.log";

#ifndef USE_DEBUG
// Release build creates always a new empty logfile when the logfile is opened for the first time during a process run
Expand All @@ -299,7 +379,8 @@ void DebugOpenFile(bool bOverwriteFile = false)
}

// Overwrite or append the logfile
fopen_s(&g_fpLogFile, g_sLogFileName.c_str(), (bOverwriteFile ? "w+t" : "a+t"));
//_wfopen_s(&g_fpLogFile, g_sLogFileName.c_str(), (bOverwriteFile ? L"w+t,ccs=UTF-8" : L"a+t,ccs=UTF-8"));
g_fpLogFile = new std::ofstream(g_sLogFileName, (bOverwriteFile ? std::ios::out | std::ios::trunc : std::ios::out | std::ios::app) );
}
}
catch (...)
Expand All @@ -310,13 +391,17 @@ void DebugOpenFile(bool bOverwriteFile = false)

void DebugCloseFile()
{
FILE* fpLogFile = g_fpLogFile;
std::ofstream* fpLogFile = g_fpLogFile;
g_fpLogFile = nullptr;
if (fpLogFile != nullptr) fclose(fpLogFile);
if (fpLogFile != nullptr)
{
fpLogFile->close();
delete fpLogFile;
}
}

// Print out CHAR or WCHAR log msg
void DebugPrintFunc_CHAR_or_WCHAR(LPCSTR szTxtBuf, LPCWSTR wszTxtBuf)
void DebugPrintFunc_CHAR_or_WCHAR(LPCSTR szTxtBuf, LPCWSTR wszTxtBuf, int iMaxCharsInBuf)
{
SYSTEMTIME t;
char szTxtTimeStampBuf[32];
Expand All @@ -327,7 +412,7 @@ void DebugPrintFunc_CHAR_or_WCHAR(LPCSTR szTxtBuf, LPCWSTR wszTxtBuf)
g_iLogMsgCount++;

GetLocalTime(&t);
if (GetTimeFormat(LOCALE_USER_DEFAULT, 0, &t, "hh:mm:ss ", (LPSTR)szTxtTimeStampBuf, sizeof(szTxtTimeStampBuf) - 1) <= 0)
if (GetTimeFormat(LOCALE_USER_DEFAULT, 0, &t, "HH:mm:ss ", (LPSTR)szTxtTimeStampBuf, COUNT_OF_ITEMS(szTxtTimeStampBuf) - 1) <= 0)
szTxtTimeStampBuf[0] = '\0';

if (g_fpLogFile == nullptr)
Expand All @@ -337,16 +422,16 @@ void DebugPrintFunc_CHAR_or_WCHAR(LPCSTR szTxtBuf, LPCWSTR wszTxtBuf)
{
if (bFirstMessage)
{
std::string sVersionTag = "NGPCarMenu.dll version " + GetFileVersionInformationAsString(g_sLogFileName + "\\..\\..\\NGPCarMenu.dll");
fprintf(g_fpLogFile, sVersionTag.c_str());
fprintf(g_fpLogFile, "\n");
// Mark the output debug logfile as UTF8 file (just in case some debug msg contains utf8 chars)
*g_fpLogFile << ::_ToUTF8String(std::wstring(L"NGPCarMenu.dll "));
*g_fpLogFile << (GetFileVersionInformationAsString(g_sLogFileName + L"\\..\\..\\NGPCarMenu.dll")).c_str() << std::endl;
}

fprintf(g_fpLogFile, szTxtTimeStampBuf);
if (szTxtBuf != nullptr) fprintf(g_fpLogFile, szTxtBuf);
if (wszTxtBuf != nullptr) fwprintf(g_fpLogFile, wszTxtBuf);
fprintf(g_fpLogFile, "\n");
DebugCloseFile();
*g_fpLogFile << szTxtTimeStampBuf;
if (szTxtBuf != nullptr) *g_fpLogFile << szTxtBuf;
if (wszTxtBuf != nullptr) *g_fpLogFile << ::_ToUTF8String(wszTxtBuf, iMaxCharsInBuf).c_str();
*g_fpLogFile << std::endl;
//DebugCloseFile();
}
}
catch (...)
Expand All @@ -368,7 +453,7 @@ void DebugPrintFunc(LPCSTR lpszFormat, ...)
if (_vsnprintf_s(szTxtBuf, COUNT_OF_ITEMS(szTxtBuf) - 1, lpszFormat, args) <= 0)
szTxtBuf[0] = '\0';

DebugPrintFunc_CHAR_or_WCHAR(szTxtBuf, nullptr);
DebugPrintFunc_CHAR_or_WCHAR(szTxtBuf, nullptr, COUNT_OF_ITEMS(szTxtBuf)-1);

va_end(args);
}
Expand All @@ -386,7 +471,7 @@ void DebugPrintFunc(LPCWSTR lpszFormat, ...)
if (_vsnwprintf_s(wszTxtBuf, COUNT_OF_ITEMS(wszTxtBuf) - 1, lpszFormat, args) <= 0)
wszTxtBuf[0] = L'\0';

DebugPrintFunc_CHAR_or_WCHAR(nullptr, wszTxtBuf);
DebugPrintFunc_CHAR_or_WCHAR(nullptr, wszTxtBuf, COUNT_OF_ITEMS(wszTxtBuf)-1);

va_end(args);
}
Expand Down Expand Up @@ -480,6 +565,9 @@ HRESULT D3D9SavePixelsToFileGDI(const HWND hAppWnd, RECT wndCaptureRect, const s

try
{
// Reading bitmap via DirectX frame buffers
LogPrint(L"Using GDI image buffer to create %s", outputFileName.c_str());

hdcAppWnd = GetDC(hAppWnd);
if (hdcAppWnd) hdcMemory = CreateCompatibleDC(hdcAppWnd);

Expand Down Expand Up @@ -691,7 +779,7 @@ HRESULT D3D9SaveScreenToFile(const LPDIRECT3DDEVICE9 pD3Device, const HWND hAppW
return D3D9SavePixelsToFileGDI(hAppWnd, wndCaptureRect, outputFileName, cf);

// Reading bitmap via DirectX frame buffers
DebugPrint("D3D9SaveScreenToFile DirectX buffer");
LogPrint(L"Using DirectX image buffer to create %s", outputFileName.c_str());

//d3d = Direct3DCreate9(D3D_SDK_VERSION);
//d3d->GetAdapterDisplayMode(adapter, &mode)
Expand Down
18 changes: 14 additions & 4 deletions src/D3D9Helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,18 +60,28 @@ extern void DebugPrintFunc(LPCWSTR lpszFormat, ...);
#define SAFE_DELETE( p ) if( p ){ delete p; p = nullptr; }
#endif

extern bool _iStarts_With(std::wstring s1, std::wstring s2, bool s2AlreadyInLowercase = FALSE); // Case-insensitive starts_with string comparison
extern bool _iStarts_With(std::wstring s1, std::wstring s2, bool s2AlreadyInLowercase = FALSE); // Case-insensitive starts_with string comparison
extern bool _iEnds_With(std::wstring s1, std::wstring s2, bool s2AlreadyInLowercase = FALSE); // Case-insensitive ends_with string comparison

extern bool _iStarts_With(std::string s1, std::string s2, bool s2AlreadyInLowercase = FALSE); // Case-insensitive starts_with string comparison
extern bool _iEnds_With(std::string s1, std::string s2, bool s2AlreadyInLowercase = FALSE); // Case-insensitive ends_with string comparison

//extern bool _iEqual(std::wstring const& s1, std::wstring const& s2, bool s2AlreadyInLowercase = FALSE); // Case-insensitive string comparison

extern void _Trim(std::wstring & s); // Trim wstring (in-place, modify the s)
extern void _Trim(std::string & s); // Trim string (in-place, modify the s)
//extern std::wstring _TrimCopy(std::wstring s); // Trim wstring (return new string, the s unmodified)

extern std::wstring _ToWString(const std::string & s); // Convert std::string to std::wstring
extern std::string _ToString(const std::wstring & s); // Convert std::wstring to std:string
extern std::wstring _ToWString(const std::string & s); // Convert std::string to std::wstring
extern std::string _ToString(const std::wstring & s); // Convert std::wstring to std:string

extern std::string _ToUTF8String(const std::wstring & s); // Convert widchar std::wstring(UTF8) to multibyte string value (WinOS specific implementation)
extern std::wstring _ToUTF8WString(const std::string & s); // Convert multibyte std::string(UTF8) to widechar UTF8 string value (WinOS specific implementation)

extern inline void _ToLowerCase(std::string & s); // Convert string to lowercase letters (in-place, so the original str in the parameter is converted)
extern inline void _ToLowerCase(std::wstring & s); // Convert wstring to lowercase letters (in-place)

extern std::string GetFileVersionInformationAsString(const std::string & fileName);
extern std::string GetFileVersionInformationAsString(const std::wstring & fileName);

extern bool _StringToRect(const std::wstring & s, RECT * outRect, const wchar_t separatorChar = L' '); // String in "0 50 200 400" format is converted as RECT struct value
extern bool _StringToPoint(const std::wstring & s, POINT * outPoint, const wchar_t separatorChar = L' '); // String in "0 50" format is converted as POINT struct value
Expand Down
Loading

0 comments on commit 4665bee

Please sign in to comment.