HostInterface: Better configuration of custom crosshair/software cursor

This commit is contained in:
Connor McLaughlin 2020-07-01 00:35:13 +10:00
parent f0c1dfefe7
commit e374853cf5
8 changed files with 110 additions and 62 deletions

View file

@ -41,6 +41,11 @@ float Controller::GetVibrationMotorStrength(u32 motor)
void Controller::LoadSettings(HostInterface* host_interface, const char* section) {} void Controller::LoadSettings(HostInterface* host_interface, const char* section) {}
bool Controller::GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale)
{
return false;
}
std::unique_ptr<Controller> Controller::Create(System* system, ControllerType type, u32 index) std::unique_ptr<Controller> Controller::Create(System* system, ControllerType type, u32 index)
{ {
switch (type) switch (type)
@ -208,6 +213,9 @@ Controller::SettingList Controller::GetSettings(ControllerType type)
case ControllerType::AnalogController: case ControllerType::AnalogController:
return AnalogController::StaticGetSettings(); return AnalogController::StaticGetSettings();
case ControllerType::NamcoGunCon:
return NamcoGunCon::StaticGetSettings();
default: default:
return {}; return {};
} }

View file

@ -1,4 +1,5 @@
#pragma once #pragma once
#include "common/image.h"
#include "settings.h" #include "settings.h"
#include "types.h" #include "types.h"
#include <memory> #include <memory>
@ -54,6 +55,9 @@ public:
/// Loads/refreshes any per-controller settings. /// Loads/refreshes any per-controller settings.
virtual void LoadSettings(HostInterface* host_interface, const char* section); virtual void LoadSettings(HostInterface* host_interface, const char* section);
/// Returns the software cursor to use for this controller, if any.
virtual bool GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale);
/// Creates a new controller of the specified type. /// Creates a new controller of the specified type.
static std::unique_ptr<Controller> Create(System* system, ControllerType type, u32 index); static std::unique_ptr<Controller> Create(System* system, ControllerType type, u32 index);

View file

@ -4,8 +4,10 @@
#include "common/audio_stream.h" #include "common/audio_stream.h"
#include "common/byte_stream.h" #include "common/byte_stream.h"
#include "common/file_system.h" #include "common/file_system.h"
#include "common/image.h"
#include "common/log.h" #include "common/log.h"
#include "common/string_util.h" #include "common/string_util.h"
#include "controller.h"
#include "dma.h" #include "dma.h"
#include "gpu.h" #include "gpu.h"
#include "host_display.h" #include "host_display.h"
@ -89,6 +91,7 @@ bool HostInterface::BootSystem(const SystemBootParameters& parameters)
return false; return false;
} }
UpdateSoftwareCursor();
OnSystemCreated(); OnSystemCreated();
m_audio_stream->PauseOutput(false); m_audio_stream->PauseOutput(false);
@ -117,6 +120,7 @@ void HostInterface::DestroySystem()
m_system.reset(); m_system.reset();
m_audio_stream.reset(); m_audio_stream.reset();
UpdateSoftwareCursor();
ReleaseHostDisplay(); ReleaseHostDisplay();
OnSystemDestroyed(); OnSystemDestroyed();
OnRunningGameChanged(); OnRunningGameChanged();
@ -352,8 +356,6 @@ void HostInterface::SetDefaultSettings(SettingsInterface& si)
si.SetBoolValue("Display", "ShowSpeed", false); si.SetBoolValue("Display", "ShowSpeed", false);
si.SetBoolValue("Display", "Fullscreen", false); si.SetBoolValue("Display", "Fullscreen", false);
si.SetBoolValue("Display", "VSync", true); si.SetBoolValue("Display", "VSync", true);
si.SetStringValue("Display", "SoftwareCursorPath", "");
si.SetFloatValue("Display", "SoftwareCursorScale", 1.0f);
si.SetBoolValue("CDROM", "ReadThread", true); si.SetBoolValue("CDROM", "ReadThread", true);
si.SetBoolValue("CDROM", "RegionCheck", true); si.SetBoolValue("CDROM", "RegionCheck", true);
@ -476,6 +478,7 @@ void HostInterface::CheckForSettingsChanges(const Settings& old_settings)
if (m_system && !controllers_updated) if (m_system && !controllers_updated)
{ {
m_system->UpdateControllers(); m_system->UpdateControllers();
UpdateSoftwareCursor();
controllers_updated = true; controllers_updated = true;
} }
@ -483,7 +486,10 @@ void HostInterface::CheckForSettingsChanges(const Settings& old_settings)
} }
if (m_system && !controllers_updated) if (m_system && !controllers_updated)
{
m_system->UpdateControllerSettings(); m_system->UpdateControllerSettings();
UpdateSoftwareCursor();
}
} }
if (m_display && m_settings.display_linear_filtering != old_settings.display_linear_filtering) if (m_display && m_settings.display_linear_filtering != old_settings.display_linear_filtering)
@ -491,21 +497,6 @@ void HostInterface::CheckForSettingsChanges(const Settings& old_settings)
if (m_display && m_settings.display_integer_scaling != old_settings.display_integer_scaling) if (m_display && m_settings.display_integer_scaling != old_settings.display_integer_scaling)
m_display->SetDisplayIntegerScaling(m_settings.display_integer_scaling); m_display->SetDisplayIntegerScaling(m_settings.display_integer_scaling);
if (m_software_cursor_use_count > 0 && m_display &&
(m_settings.display_software_cursor_path != old_settings.display_software_cursor_path ||
m_settings.display_software_cursor_scale != old_settings.display_software_cursor_scale))
{
if (m_settings.display_software_cursor_path.empty())
{
m_display->ClearSoftwareCursor();
}
else
{
m_display->SetSoftwareCursor(m_settings.display_software_cursor_path.c_str(),
m_settings.display_software_cursor_scale);
}
}
} }
void HostInterface::SetUserDirectoryToProgramDirectory() void HostInterface::SetUserDirectoryToProgramDirectory()
@ -580,7 +571,7 @@ bool HostInterface::GetBooleanSettingValue(const char* section, const char* key,
return bool_value.value_or(default_value); return bool_value.value_or(default_value);
} }
bool HostInterface::GetIntegerSettingValue(const char* section, const char* key, s32 default_value /*= 0*/) s32 HostInterface::GetIntegerSettingValue(const char* section, const char* key, s32 default_value /*= 0*/)
{ {
std::string value = GetSettingValue(section, key, ""); std::string value = GetSettingValue(section, key, "");
if (value.empty()) if (value.empty())
@ -590,7 +581,7 @@ bool HostInterface::GetIntegerSettingValue(const char* section, const char* key,
return int_value.value_or(default_value); return int_value.value_or(default_value);
} }
bool HostInterface::GetFloatSettingValue(const char* section, const char* key, float default_value /*= 0.0f*/) float HostInterface::GetFloatSettingValue(const char* section, const char* key, float default_value /*= 0.0f*/)
{ {
std::string value = GetSettingValue(section, key, ""); std::string value = GetSettingValue(section, key, "");
if (value.empty()) if (value.empty())
@ -628,6 +619,35 @@ void HostInterface::ModifyResolutionScale(s32 increment)
m_system->GetGPU()->UpdateSettings(); m_system->GetGPU()->UpdateSettings();
} }
void HostInterface::UpdateSoftwareCursor()
{
if (!m_system)
{
m_display->ClearSoftwareCursor();
return;
}
const Common::RGBA8Image* image = nullptr;
float image_scale = 1.0f;
for (u32 i = 0; i < NUM_CONTROLLER_AND_CARD_PORTS; i++)
{
Controller* controller = m_system->GetController(i);
if (controller && controller->GetSoftwareCursor(&image, &image_scale))
break;
}
if (image && image->IsValid())
{
m_display->SetSoftwareCursor(image->GetPixels(), image->GetWidth(), image->GetHeight(), image->GetByteStride(),
image_scale);
}
else
{
m_display->ClearSoftwareCursor();
}
}
void HostInterface::RecreateSystem() void HostInterface::RecreateSystem()
{ {
std::unique_ptr<ByteStream> stream = ByteStream_CreateGrowableMemoryStream(nullptr, 8 * 1024); std::unique_ptr<ByteStream> stream = ByteStream_CreateGrowableMemoryStream(nullptr, 8 * 1024);
@ -657,22 +677,4 @@ void HostInterface::DisplayLoadingScreen(const char* message, int progress_min /
Log_InfoPrintf("Loading: %s %d of %d-%d", message, progress_value, progress_min, progress_max); Log_InfoPrintf("Loading: %s %d of %d-%d", message, progress_value, progress_min, progress_max);
} }
void HostInterface::EnableSoftwareCursor()
{
if (m_software_cursor_use_count++ > 0 || m_settings.display_software_cursor_path.empty())
return;
m_display->SetSoftwareCursor(m_settings.display_software_cursor_path.c_str(),
m_settings.display_software_cursor_scale);
}
void HostInterface::DisableSoftwareCursor()
{
DebugAssert(m_software_cursor_use_count > 0);
if (--m_software_cursor_use_count > 0)
return;
m_display->ClearSoftwareCursor();
}
void HostInterface::GetGameInfo(const char* path, CDImage* image, std::string* code, std::string* title) {} void HostInterface::GetGameInfo(const char* path, CDImage* image, std::string* code, std::string* title) {}

View file

@ -110,17 +110,10 @@ public:
bool GetBooleanSettingValue(const char* section, const char* key, bool default_value = false); bool GetBooleanSettingValue(const char* section, const char* key, bool default_value = false);
/// Returns an integer setting from the configuration. /// Returns an integer setting from the configuration.
bool GetIntegerSettingValue(const char* section, const char* key, s32 default_value = 0); s32 GetIntegerSettingValue(const char* section, const char* key, s32 default_value = 0);
/// Returns a float setting from the configuration. /// Returns a float setting from the configuration.
bool GetFloatSettingValue(const char* section, const char* key, float default_value = 0.0f); float GetFloatSettingValue(const char* section, const char* key, float default_value = 0.0f);
/// Enables the software cursor. Can be called multiple times, but must be matched by a call to
/// DisableSoftwareCursor().
void EnableSoftwareCursor();
/// Disables the software cursor, preventing it from being renderered.
void DisableSoftwareCursor();
protected: protected:
virtual bool AcquireHostDisplay() = 0; virtual bool AcquireHostDisplay() = 0;
@ -164,6 +157,9 @@ protected:
/// Adjusts the internal (render) resolution of the hardware backends. /// Adjusts the internal (render) resolution of the hardware backends.
void ModifyResolutionScale(s32 increment); void ModifyResolutionScale(s32 increment);
/// Updates software cursor state, based on controllers.
void UpdateSoftwareCursor();
bool SaveState(const char* filename); bool SaveState(const char* filename);
void CreateAudioStream(); void CreateAudioStream();
@ -173,6 +169,4 @@ protected:
Settings m_settings; Settings m_settings;
std::string m_program_directory; std::string m_program_directory;
std::string m_user_directory; std::string m_user_directory;
u32 m_software_cursor_use_count = 0;
}; };

View file

@ -5,19 +5,14 @@
#include "gpu.h" #include "gpu.h"
#include "host_display.h" #include "host_display.h"
#include "host_interface.h" #include "host_interface.h"
#include "resources.h"
#include "system.h" #include "system.h"
#include <array> #include <array>
Log_SetChannel(NamcoGunCon); Log_SetChannel(NamcoGunCon);
NamcoGunCon::NamcoGunCon(System* system) : m_system(system) NamcoGunCon::NamcoGunCon(System* system) : m_system(system) {}
{
m_system->GetHostInterface()->EnableSoftwareCursor();
}
NamcoGunCon::~NamcoGunCon() NamcoGunCon::~NamcoGunCon() = default;
{
m_system->GetHostInterface()->DisableSoftwareCursor();
}
ControllerType NamcoGunCon::GetType() const ControllerType NamcoGunCon::GetType() const
{ {
@ -226,3 +221,48 @@ u32 NamcoGunCon::StaticGetVibrationMotorCount()
{ {
return 0; return 0;
} }
Controller::SettingList NamcoGunCon::StaticGetSettings()
{
static constexpr std::array<SettingInfo, 2> settings = {
{{SettingInfo::Type::Path, "CrosshairImagePath", "Crosshair Image Path",
"Path to an image to use as a crosshair/cursor."},
{SettingInfo::Type::Float, "CrosshairScale", "Crosshair Image Scale", "Scale of crosshair image on screen.", "1.0",
"0.0001", "100.0"}}};
return SettingList(settings.begin(), settings.end());
}
void NamcoGunCon::LoadSettings(HostInterface* host_interface, const char* section)
{
Controller::LoadSettings(host_interface, section);
std::string path = host_interface->GetSettingValue(section, "CrosshairImagePath");
if (path != m_crosshair_image_path)
{
m_crosshair_image_path = std::move(path);
if (m_crosshair_image_path.empty() ||
!Common::LoadImageFromFile(&m_crosshair_image, m_crosshair_image_path.c_str()))
{
m_crosshair_image.Invalidate();
}
}
if (!m_crosshair_image.IsValid())
{
m_crosshair_image.SetPixels(Resources::CROSSHAIR_IMAGE_WIDTH, Resources::CROSSHAIR_IMAGE_HEIGHT,
Resources::CROSSHAIR_IMAGE_DATA.data());
}
m_crosshair_image_scale = host_interface->GetFloatSettingValue(section, "CrosshairScale", 1.0f);
}
bool NamcoGunCon::GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale)
{
if (!m_crosshair_image.IsValid())
return false;
*image = &m_crosshair_image;
*image_scale = m_crosshair_image_scale;
return true;
}

View file

@ -24,6 +24,7 @@ public:
static AxisList StaticGetAxisNames(); static AxisList StaticGetAxisNames();
static ButtonList StaticGetButtonNames(); static ButtonList StaticGetButtonNames();
static u32 StaticGetVibrationMotorCount(); static u32 StaticGetVibrationMotorCount();
static SettingList StaticGetSettings();
ControllerType GetType() const override; ControllerType GetType() const override;
std::optional<s32> GetAxisCodeByName(std::string_view axis_name) const override; std::optional<s32> GetAxisCodeByName(std::string_view axis_name) const override;
@ -31,6 +32,8 @@ public:
void Reset() override; void Reset() override;
bool DoState(StateWrapper& sw) override; bool DoState(StateWrapper& sw) override;
void LoadSettings(HostInterface* host_interface, const char* section) override;
bool GetSoftwareCursor(const Common::RGBA8Image** image, float* image_scale) override;
void SetAxisState(s32 axis_code, float value) override; void SetAxisState(s32 axis_code, float value) override;
void SetButtonState(s32 button_code, bool pressed) override; void SetButtonState(s32 button_code, bool pressed) override;
@ -56,6 +59,9 @@ private:
}; };
System* m_system; System* m_system;
Common::RGBA8Image m_crosshair_image;
std::string m_crosshair_image_path;
float m_crosshair_image_scale = 1.0f;
// buttons are active low // buttons are active low
u16 m_button_state = UINT16_C(0xFFFF); u16 m_button_state = UINT16_C(0xFFFF);

View file

@ -113,8 +113,6 @@ void Settings::Load(SettingsInterface& si)
display_show_vps = si.GetBoolValue("Display", "ShowVPS", false); display_show_vps = si.GetBoolValue("Display", "ShowVPS", false);
display_show_speed = si.GetBoolValue("Display", "ShowSpeed", false); display_show_speed = si.GetBoolValue("Display", "ShowSpeed", false);
video_sync_enabled = si.GetBoolValue("Display", "VSync", true); video_sync_enabled = si.GetBoolValue("Display", "VSync", true);
display_software_cursor_path = si.GetStringValue("Display", "SoftwareCursorPath", "");
display_software_cursor_scale = si.GetFloatValue("Display", "SoftwareCursorScale", 1.0f);
cdrom_read_thread = si.GetBoolValue("CDROM", "ReadThread", true); cdrom_read_thread = si.GetBoolValue("CDROM", "ReadThread", true);
cdrom_region_check = si.GetBoolValue("CDROM", "RegionCheck", true); cdrom_region_check = si.GetBoolValue("CDROM", "RegionCheck", true);
@ -211,8 +209,6 @@ void Settings::Save(SettingsInterface& si) const
si.SetBoolValue("Display", "ShowVPS", display_show_vps); si.SetBoolValue("Display", "ShowVPS", display_show_vps);
si.SetBoolValue("Display", "ShowSpeed", display_show_speed); si.SetBoolValue("Display", "ShowSpeed", display_show_speed);
si.SetBoolValue("Display", "VSync", video_sync_enabled); si.SetBoolValue("Display", "VSync", video_sync_enabled);
si.SetStringValue("Display", "SoftwareCursorPath", display_software_cursor_path.c_str());
si.SetFloatValue("Display", "SoftwareCursorScale", display_software_cursor_scale);
si.SetBoolValue("CDROM", "ReadThread", cdrom_read_thread); si.SetBoolValue("CDROM", "ReadThread", cdrom_read_thread);
si.SetBoolValue("CDROM", "RegionCheck", cdrom_region_check); si.SetBoolValue("CDROM", "RegionCheck", cdrom_region_check);

View file

@ -97,8 +97,6 @@ struct Settings
bool display_show_vps = false; bool display_show_vps = false;
bool display_show_speed = false; bool display_show_speed = false;
bool video_sync_enabled = true; bool video_sync_enabled = true;
std::string display_software_cursor_path;
float display_software_cursor_scale = 1.0f;
bool cdrom_read_thread = true; bool cdrom_read_thread = true;
bool cdrom_region_check = true; bool cdrom_region_check = true;