Skip to content

Commit afa9380

Browse files
committed
Overlay: read/write overlay settings to .overlay.ini
course editor should also be written, haven't tested it that much yet though merged letterboxing & overlay hooks into a single hook, since letterboxing is technically an overlay after all
1 parent 5688a91 commit afa9380

File tree

11 files changed

+315
-260
lines changed

11 files changed

+315
-260
lines changed

OutRun2006Tweaks.ini

Lines changed: 1 addition & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -265,23 +265,6 @@ DemonwareServerOverride = clarissa.port0.org
265265
# Enables OR2006Tweaks overlay
266266
Enabled = true
267267

268-
# Font scale to use for overlay
269-
FontScale = 1.5
270-
271-
# How many seconds notifications should show on-screen before being hidden
272-
# 0 will disable notifications
273-
NotifyDisplayTime = 7
274-
275-
# Allows checking online services & notifying when new lobbies are created
276-
NotifyOnlineEnable = true
277-
278-
# How often to check for new lobbies, in seconds
279-
NotifyOnlineUpdateTime = 20
280-
281-
# Hides notifications during gameplay, either during online races only, or during any race
282-
# 0 = never hide, 1 = hide during online races, 2 = hide during any race
283-
NotifyHideMode = 1
284-
285268
[Bugfixes]
286269
# Fixes looping clop sound effect remaining active through the session.
287270
FixPegasusClopping = true
@@ -354,4 +337,4 @@ HideOnlineSigninText = false
354337
25_Shiny_World_prototype.ogg = Shiny World (Prototype)
355338
26_Night_Flight_prototype.ogg = Night Flight (Prototype)
356339
27_Life_was_a_Bore_Instrumental.ogg = Life was a Bore (Instrumental)
357-
28_Night_Flight_Instrumental.ogg = Night Flight (Instrumental)
340+
28_Night_Flight_Instrumental.ogg = Night Flight (Instrumental)

external/ini-cpp/ini/ini.h

Lines changed: 28 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,9 @@ class INIReader {
206206
// about the parsing.
207207
INIReader(std::string filename);
208208

209+
// Construct INIReader and parse given filepath, unicode paths supported
210+
INIReader(const std::filesystem::path& filepath);
211+
209212
// Construct INIReader and parse given file. See ini.h for more info
210213
// about the parsing.
211214
INIReader(FILE* file);
@@ -240,20 +243,12 @@ class INIReader {
240243
const std::vector<T>& default_v) const;
241244

242245
template <typename T = std::string>
243-
void InsertEntry(const std::string& section, const std::string& name,
244-
const T& v);
245-
246-
template <typename T = std::string>
247-
void InsertEntry(const std::string& section, const std::string& name,
248-
const std::vector<T>& vs);
249-
250-
template <typename T = std::string>
251-
void UpdateEntry(const std::string& section, const std::string& name,
252-
const T& v);
246+
void Set(const std::string& section, const std::string& name,
247+
const T& v);
253248

254249
template <typename T = std::string>
255-
void UpdateEntry(const std::string& section, const std::string& name,
256-
const std::vector<T>& vs);
250+
void Set(const std::string& section, const std::string& name,
251+
const std::vector<T>& vs);
257252

258253
protected:
259254
int _error;
@@ -290,6 +285,20 @@ inline INIReader::INIReader(std::string filename) {
290285
ParseError();
291286
}
292287

288+
/**
289+
* @brief Construct an INIReader object from a file path
290+
* @param filepath The path of the INI file to parse
291+
* @throws std::runtime_error if there is an error parsing the INI file
292+
*/
293+
inline INIReader::INIReader(const std::filesystem::path& filepath) {
294+
const std::wstring path_str = filepath.wstring();
295+
FILE* iniFile;
296+
errno_t result = _wfopen_s(&iniFile, path_str.c_str(), L"r");
297+
_error = ini_parse_file(iniFile, ValueHandler, this);
298+
ParseError();
299+
fclose(iniFile);
300+
}
301+
293302
/**
294303
* @brief Construct an INIReader object from a file pointer
295304
* @param file A pointer to the INI file to parse
@@ -461,41 +470,6 @@ inline std::vector<T> INIReader::GetVector(
461470
};
462471
}
463472

464-
/**
465-
* @brief Insert a key-value pair into the INI file
466-
* @param section The section name
467-
* @param name The key name
468-
* @param v The value to insert
469-
* @throws std::runtime_error if the key already exists in the section
470-
*/
471-
template <typename T>
472-
inline void INIReader::InsertEntry(const std::string& section,
473-
const std::string& name, const T& v) {
474-
if (_values[section][name].size() > 0) {
475-
throw std::runtime_error("duplicate key '" + std::string(name) +
476-
"' in section '" + section + "'.");
477-
}
478-
_values[section][name] = V2String(v);
479-
}
480-
481-
/**
482-
* @brief Insert a vector of values into the INI file
483-
* @param section The section name
484-
* @param name The key name
485-
* @param vs The vector of values to insert
486-
* @throws std::runtime_error if the key already exists in the section
487-
*/
488-
template <typename T>
489-
inline void INIReader::InsertEntry(const std::string& section,
490-
const std::string& name,
491-
const std::vector<T>& vs) {
492-
if (_values[section][name].size() > 0) {
493-
throw std::runtime_error("duplicate key '" + std::string(name) +
494-
"' in section '" + section + "'.");
495-
}
496-
_values[section][name] = Vec2String(vs);
497-
}
498-
499473
/**
500474
* @brief Update a key-value pair in the INI file
501475
* @param section The section name
@@ -504,12 +478,8 @@ inline void INIReader::InsertEntry(const std::string& section,
504478
* @throws std::runtime_error if the key does not exist in the section
505479
*/
506480
template <typename T>
507-
inline void INIReader::UpdateEntry(const std::string& section,
508-
const std::string& name, const T& v) {
509-
if (!_values[section][name].size()) {
510-
throw std::runtime_error("key '" + std::string(name) +
511-
"' not exist in section '" + section + "'.");
512-
}
481+
inline void INIReader::Set(const std::string& section,
482+
const std::string& name, const T& v) {
513483
_values[section][name] = V2String(v);
514484
}
515485

@@ -521,9 +491,9 @@ inline void INIReader::UpdateEntry(const std::string& section,
521491
* @throws std::runtime_error if the key does not exist in the section
522492
*/
523493
template <typename T>
524-
inline void INIReader::UpdateEntry(const std::string& section,
525-
const std::string& name,
526-
const std::vector<T>& vs) {
494+
inline void INIReader::Set(const std::string& section,
495+
const std::string& name,
496+
const std::vector<T>& vs) {
527497
if (!_values[section][name].size()) {
528498
throw std::runtime_error("key '" + std::string(name) +
529499
"' not exist in section '" + section + "'.");
@@ -604,15 +574,12 @@ class INIWriter {
604574
* @throws std::runtime_error if the output file already exists or cannot be
605575
* opened
606576
*/
607-
inline static void write(const std::string& filepath,
577+
inline static void write(const std::filesystem::path& filepath,
608578
const INIReader& reader) {
609-
if (struct stat buf; stat(filepath.c_str(), &buf) == 0) {
610-
throw std::runtime_error("file: " + filepath + " already exist.");
611-
}
612579
std::ofstream out;
613580
out.open(filepath);
614581
if (!out.is_open()) {
615-
throw std::runtime_error("cannot open output file: " + filepath);
582+
throw std::runtime_error("cannot open output file: " + filepath.string());
616583
}
617584
for (const auto& section : reader.Sections()) {
618585
out << "[" << section << "]\n";

src/dllmain.cpp

Lines changed: 2 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ namespace Module
1717
constexpr std::string_view IniFileName = "OutRun2006Tweaks.ini";
1818
constexpr std::string_view UserIniFileName = "OutRun2006Tweaks.user.ini";
1919
constexpr std::string_view LodIniFileName = "OutRun2006Tweaks.lods.ini";
20+
constexpr std::string_view OverlayIniFileName = "OutRun2006Tweaks.overlay.ini";
2021
constexpr std::string_view LogFileName = "OutRun2006Tweaks.log";
2122

2223
void init()
@@ -36,6 +37,7 @@ namespace Module
3637
IniPath = dllParent / IniFileName;
3738
UserIniPath = dllParent / UserIniFileName;
3839
LodIniPath = dllParent / LodIniFileName;
40+
OverlayIniPath = dllParent / OverlayIniFileName;
3941

4042
Game::init();
4143
}
@@ -128,11 +130,6 @@ namespace Settings
128130
spdlog::info(" - DemonwareServerOverride: {}", DemonwareServerOverride);
129131

130132
spdlog::info(" - OverlayEnabled: {}", OverlayEnabled);
131-
spdlog::info(" - OverlayFontScale: {}", OverlayFontScale);
132-
spdlog::info(" - OverlayNotifyDisplayTime: {}", OverlayNotifyDisplayTime);
133-
spdlog::info(" - OverlayNotifyOnlineEnable: {}", OverlayNotifyOnlineEnable);
134-
spdlog::info(" - OverlayNotifyOnlineUpdateTime: {}", OverlayNotifyOnlineUpdateTime);
135-
spdlog::info(" - OverlayNotifyHideMode: {}", OverlayNotifyHideMode);
136133

137134
spdlog::info(" - FixPegasusClopping: {}", FixPegasusClopping);
138135
spdlog::info(" - FixRightSideBunkiAnimations: {}", FixRightSideBunkiAnimations);
@@ -260,11 +257,6 @@ namespace Settings
260257
DemonwareServerOverride = ini.Get("Misc", "DemonwareServerOverride", DemonwareServerOverride);
261258

262259
OverlayEnabled = ini.Get("Overlay", "Enabled", OverlayEnabled);
263-
OverlayFontScale = ini.Get("Overlay", "FontScale", OverlayFontScale);
264-
OverlayNotifyDisplayTime = ini.Get("Overlay", "NotifyDisplayTime", OverlayNotifyDisplayTime);
265-
OverlayNotifyOnlineEnable = ini.Get("Overlay", "NotifyOnlineEnable", OverlayNotifyOnlineEnable);
266-
OverlayNotifyOnlineUpdateTime = ini.Get("Overlay", "NotifyOnlineUpdateTime", OverlayNotifyOnlineUpdateTime);
267-
OverlayNotifyHideMode = ini.Get("Overlay", "NotifyHideMode", OverlayNotifyHideMode);
268260

269261
FixPegasusClopping = ini.Get("Bugfixes", "FixPegasusClopping", FixPegasusClopping);
270262
FixRightSideBunkiAnimations = ini.Get("Bugfixes", "FixRightSideBunkiAnimations", FixRightSideBunkiAnimations);

src/hooks_uiscaling.cpp

Lines changed: 0 additions & 114 deletions
Original file line numberDiff line numberDiff line change
@@ -635,117 +635,3 @@ class UIScaling : public Hook
635635
static UIScaling instance;
636636
};
637637
UIScaling UIScaling::instance;
638-
639-
struct CUSTOMVERTEX
640-
{
641-
FLOAT x, y, z, rhw;
642-
D3DCOLOR color;
643-
};
644-
#define CUSTOMFVF (D3DFVF_XYZRHW | D3DFVF_DIFFUSE)
645-
646-
class UILetterboxing : public Hook
647-
{
648-
const static int D3DEndSceneCaller_Addr = 0x17D4E;
649-
650-
inline static IDirect3DVertexBuffer9* VertexBuf = nullptr;
651-
652-
inline static SafetyHookMid dest_hook = {};
653-
static void destination(SafetyHookContext& ctx)
654-
{
655-
IDirect3DDevice9* d3ddev = Game::D3DDevice();
656-
657-
if (!VertexBuf)
658-
{
659-
float screenWidth = float(Game::screen_resolution->x);
660-
float screenHeight = float(Game::screen_resolution->y);
661-
float contentWidth = screenHeight / (3.f / 4.f);
662-
float borderWidth = ((screenWidth - contentWidth) / 2) + 0.5f;
663-
664-
// Add half-pixel offset so there's no white border...
665-
screenHeight = screenHeight + 0.5f;
666-
screenWidth = screenWidth + 0.5f;
667-
668-
CUSTOMVERTEX vertices[] =
669-
{
670-
// Left border
671-
{ -0.5f, -0.5f, 0.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 0) },
672-
{ borderWidth, -0.5f, 0.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 0) },
673-
{ -0.5f, screenHeight, 0.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 0) },
674-
{ borderWidth, screenHeight, 0.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 0) },
675-
676-
// Right border
677-
{ (screenWidth - borderWidth), -0.5f, 0.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 0) },
678-
{ screenWidth, -0.5f, 0.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 0) },
679-
{ (screenWidth - borderWidth), screenHeight, 0.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 0) },
680-
{ screenWidth, screenHeight, 0.0f, 1.0f, D3DCOLOR_XRGB(0, 0, 0) }
681-
};
682-
683-
d3ddev->CreateVertexBuffer(8 * sizeof(CUSTOMVERTEX),
684-
0,
685-
CUSTOMFVF,
686-
D3DPOOL_MANAGED,
687-
&VertexBuf,
688-
NULL);
689-
690-
void* pVoid;
691-
VertexBuf->Lock(0, 0, &pVoid, 0);
692-
memcpy(pVoid, vertices, sizeof(vertices));
693-
VertexBuf->Unlock();
694-
}
695-
696-
if (Settings::UILetterboxing == 1 && Game::is_in_game())
697-
return; // disable letterboxing while in-game
698-
699-
// Backup existing cullmode and set to none, otherwise we won't get drawn
700-
DWORD prevCullMode = D3DCULL_NONE;
701-
d3ddev->GetRenderState(D3DRS_CULLMODE, &prevCullMode);
702-
d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE);
703-
704-
// TODO: not sure if we might need these in future, if game overrides some state during gameplay it may affect letterbox
705-
#if 0
706-
// Set render states
707-
d3ddev->SetRenderState(D3DRS_ALPHABLENDENABLE, FALSE);
708-
d3ddev->SetRenderState(D3DRS_ZENABLE, D3DZB_FALSE);
709-
d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE);
710-
711-
// Set texture stage states to avoid any texture influence
712-
d3ddev->SetTexture(0, NULL);
713-
d3ddev->SetTextureStageState(0, D3DTSS_COLOROP, D3DTOP_DISABLE);
714-
d3ddev->SetTextureStageState(0, D3DTSS_ALPHAOP, D3DTOP_DISABLE);
715-
#endif
716-
717-
// Set FVF and stream source
718-
d3ddev->SetFVF(CUSTOMFVF);
719-
d3ddev->SetStreamSource(0, VertexBuf, 0, sizeof(CUSTOMVERTEX));
720-
721-
// Draw left border
722-
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
723-
724-
// Draw right border
725-
d3ddev->DrawPrimitive(D3DPT_TRIANGLESTRIP, 4, 2);
726-
727-
// Restore original cullmode
728-
d3ddev->SetRenderState(D3DRS_CULLMODE, prevCullMode);
729-
}
730-
731-
public:
732-
std::string_view description() override
733-
{
734-
return "UILetterboxing";
735-
}
736-
737-
bool validate() override
738-
{
739-
return Settings::UILetterboxing > 0 && Settings::UIScalingMode > 0;
740-
}
741-
742-
bool apply() override
743-
{
744-
dest_hook = safetyhook::create_mid(Module::exe_ptr(D3DEndSceneCaller_Addr), destination);
745-
746-
return true;
747-
}
748-
749-
static UILetterboxing instance;
750-
};
751-
UILetterboxing UILetterboxing::instance;

0 commit comments

Comments
 (0)