Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/launcher_main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2971,14 +2971,14 @@ struct Launcher {
if (kinect_v2_chosen && settings.kinect_v2_view == "ideal") kinect_v2_tuning_rows(row_width, scale);
const float slider_width = kinect_chosen ? row_width : 220 * scale;
setting_row(tr(MenuSteady), tr(MenuSteadyHint), slider_width, scale, [&] {
int radius = int((std::min)(settings.menu_steady_radius, 30u));
int radius = int((std::min)(menu_steady_for(settings), 30u));
char shown[32];
if (radius) std::snprintf(shown, sizeof shown, "%d mm", radius);
else std::snprintf(shown, sizeof shown, "%s", tr(MenuSteadyOff));
ImGui::SetNextItemWidth(slider_width);
bool moved = ImGui::SliderInt("##menu_steady", &radius, 0, 30, shown);
moved |= slider_steps(&radius, 0, 30, 1);
if (moved) settings.menu_steady_radius = uint32_t(std::clamp(radius, 0, 30));
if (moved) menu_steady_for(settings) = uint32_t(std::clamp(radius, 0, 30));
});
// For a bug report: numbers in game.log (motion_trace.h).
setting_row(tr(MotionTrace), tr(MotionTraceHint), ImGui::GetFrameHeight() * 1.9f, scale,
Expand Down
28 changes: 22 additions & 6 deletions src/launcher_settings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,13 +138,15 @@ LauncherSettings parse_launcher_settings(const std::string& text) {
else if (key == "touch_controls") read_flag(value, settings.touch_controls);
else if (key == "touch_labels") read_flag(value, settings.touch_labels);
else if (key == "tilt") read_flag(value, settings.tilt);
else if (key == "camera" && (value == "off" || value == "picture" || value == "motion" || value == "kinect" || value == "kinect_v2")) settings.camera = value;
// "picture" is no longer offered: it reads as the default, off.
else if (key == "camera" && (value == "off" || value == "motion" || value == "kinect" || value == "kinect_v2")) settings.camera = value;
else if (key == "camera_device" && value.size() <= 128) settings.camera_device = value;
else if (key == "camera_mirror") read_flag(value, settings.camera_mirror);
// kinect_smooth (the v2's smoothing switch) is gone: the game smooths
// a real Kinect's skeletons once, as the title asks. An old file's
// key is ignored like any unknown one and not written again.
else if (key == "menu_steady_radius") read_number(value, 0, 30, settings.menu_steady_radius);
else if (key == "menu_steady_radius_v2") read_number(value, 0, 30, settings.menu_steady_radius_v2);
else if (key == "kinect_v2_view" && (value == "fit" || value == "sensor" || value == "ideal"))
settings.kinect_v2_view = value;
else if (key == "kinect_v2_distance") read_number(value, 100, 400, settings.kinect_v2_distance);
Expand Down Expand Up @@ -234,6 +236,7 @@ std::string format_launcher_settings(const LauncherSettings& s) {
<< "camera_device=" << s.camera_device << '\n'
<< "camera_mirror=" << s.camera_mirror << '\n'
<< "menu_steady_radius=" << (std::min)(s.menu_steady_radius, 30u) << '\n'
<< "menu_steady_radius_v2=" << (std::min)(s.menu_steady_radius_v2, 30u) << '\n'
<< "kinect_v2_view=" << s.kinect_v2_view << '\n'
<< "kinect_v2_distance=" << s.kinect_v2_distance << '\n'
<< "kinect_v2_height=" << s.kinect_v2_height << '\n'
Expand Down Expand Up @@ -318,8 +321,20 @@ bool has_game_save(const std::filesystem::path& saves) {
return false;
}

uint32_t& menu_steady_for(LauncherSettings& settings) {
return settings.camera == "kinect_v2" ? settings.menu_steady_radius_v2 : settings.menu_steady_radius;
}
uint32_t menu_steady_for(const LauncherSettings& settings) {
return settings.camera == "kinect_v2" ? settings.menu_steady_radius_v2 : settings.menu_steady_radius;
}

namespace {
bool v2_recompiled(const LauncherSettings& s) { return s.camera == "kinect_v2" && s.kinect_v2_view == "ideal"; }
// A Kinect v2 may be what the game opens: chosen, or standing in when the
// Xbox 360 choice finds no v1 (kinect_sensor.cpp, open_selected). Its view
// is sent for both, so an old camera=kinect with a v2 gets the default view
// (Recompiled) too, not the game's own fallback (Simulated).
bool v2_possible(const LauncherSettings& s) { return s.camera == "kinect_v2" || s.camera == "kinect"; }
bool v2_recompiled(const LauncherSettings& s) { return v2_possible(s) && s.kinect_v2_view == "ideal"; }
// A hundredths value as the decimal text the game reads (250 -> "2.50").
std::string centi(uint32_t value) {
char text[32];
Expand Down Expand Up @@ -407,8 +422,9 @@ std::vector<std::pair<std::string, std::string>> game_environment(const Launcher
{"SFR_CAMERA", s.camera == "off" ? "" : s.camera == "kinect_v2" ? "kinect" : s.camera},
{"SFR_KINECT_MODEL", s.camera == "kinect_v2" ? "2" : s.camera == "kinect" ? "1" : ""},
// A Kinect v2's depth view and Recompiled's tuning (kinect_v2_depth.h);
// only for the v2 choice, so an inherited value is cleared otherwise.
{"SFR_KINECT_V2_DEPTH_VIEW", s.camera == "kinect_v2" ? s.kinect_v2_view : ""},
// only when a v2 may open (v2_possible), so an inherited value is
// cleared otherwise.
{"SFR_KINECT_V2_DEPTH_VIEW", v2_possible(s) ? s.kinect_v2_view : ""},
{"SFR_KINECT_V2_DEPTH_DISTANCE", v2_recompiled(s) ? centi(s.kinect_v2_distance) : ""},
{"SFR_KINECT_V2_DEPTH_HEIGHT", v2_recompiled(s) ? centi(s.kinect_v2_height) : ""},
{"SFR_KINECT_V2_DEPTH_FOLLOW", v2_recompiled(s) ? centi(s.kinect_v2_follow * 10) : ""},
Expand All @@ -417,8 +433,8 @@ std::vector<std::pair<std::string, std::string>> game_environment(const Launcher
{"SFR_KINECT_V2_SKELETON_DISTANCE", ""},
{"SFR_CAMERA_DEVICE", s.camera_device},
{"SFR_CAMERA_MIRROR", s.camera_mirror ? "1" : "0"},
{"SFR_MENU_HAND_STEADY", s.menu_steady_radius ? "1" : "0"},
{"SFR_MENU_STEADY_RADIUS", s.menu_steady_radius ? std::to_string((std::min)(s.menu_steady_radius, 30u)) : ""},
{"SFR_MENU_HAND_STEADY", menu_steady_for(s) ? "1" : "0"},
{"SFR_MENU_STEADY_RADIUS", menu_steady_for(s) ? std::to_string((std::min)(menu_steady_for(s), 30u)) : ""},
{"SFR_VOICE", s.voice ? "1" : ""},
{"SFR_CAMERA_RACE_TRACE", s.motion_trace && (s.camera == "kinect" || s.camera == "motion") ? "1" : ""},
{"SFR_AVATAR", s.avatar_model.empty() ? "0" : "1"},
Expand Down
17 changes: 13 additions & 4 deletions src/launcher_settings.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,12 @@ namespace sfr {
// What the launcher asks of the player before the game starts, kept in
// settings.ini next to the launcher. The game reads all of it at startup
// (environment variables and arguments), so it is fixed for a run.
struct LauncherSettings;
// The menu cursor steadying the chosen camera uses (menu_steady_radius or
// menu_steady_radius_v2).
uint32_t& menu_steady_for(LauncherSettings& settings);
uint32_t menu_steady_for(const LauncherSettings& settings);

struct LauncherSettings {
// 0 = not chosen yet: the launcher fills in the desktop size
// (apply_default_window_size); the game falls back to 1280x720 without it.
Expand Down Expand Up @@ -71,11 +77,12 @@ struct LauncherSettings {
// picture the title shows is a real one. "pad" is the emulated player the
// gamepad drives; "camera" tracks a real body with a webcam, which cannot
// share the pad's sticks, so the two are one choice. "picture" keeps the
// pad in charge and only gives the title a camera image.
// pad in charge and only gives the title a camera image; the launcher no
// longer offers it, and a saved "picture" reads as "off".
// "kinect" is a real Xbox 360 Kinect tracking the players, as on the
// console (a Kinect v2 stands in when no v1 opens); "kinect_v2" is a
// Kinect v2 for Xbox One only.
std::string camera = "off"; // "off", "picture", "motion", "kinect" or "kinect_v2"
std::string camera = "off"; // "off", "motion", "kinect" or "kinect_v2"
// Which of the host's cameras, by the name it lists (SFR_CAMERA_DEVICE).
// A name and not a number, because the list changes: a phone camera or a
// capture card comes and goes, and the number then means another camera.
Expand All @@ -91,8 +98,10 @@ struct LauncherSettings {
// The menu cursor's steadying (pose_stability.h), webcam and Kinect: the
// circle a hand held still may wander in without moving the cursor, in
// millimetres; 0 turns it off. SFR_MENU_STEADY_RADIUS and
// SFR_MENU_HAND_STEADY.
uint32_t menu_steady_radius = 0;
// SFR_MENU_HAND_STEADY. Each choice keeps its own: the webcam and the
// Xbox 360 Kinect start at 8 mm, a Kinect v2 (steadier) starts off.
uint32_t menu_steady_radius = 8; // webcam, Kinect (Xbox 360)
uint32_t menu_steady_radius_v2 = 0; // Kinect v2
// How a Kinect v2's depth becomes the v1's (SFR_KINECT_V2_DEPTH_VIEW):
// "ideal" (Recompiled, the launcher's default: a virtual level v1 that
// follows the players), "fit" (Simulated, the v2's whole view fitted into
Expand Down
36 changes: 27 additions & 9 deletions tests/launcher_settings_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -564,19 +564,30 @@ void save_directory_settings() {

void menu_steady_settings() {
const sfr::LauncherSettings defaults;
require(sfr::format_launcher_settings(defaults).find("menu_steady_radius=0\n") != std::string::npos,
"the menu cursor steadying defaults to off");
require(value_of(defaults, "SFR_MENU_HAND_STEADY") == "0" && value_of(defaults, "SFR_MENU_STEADY_RADIUS").empty(),
"the default (off) reaches the game");
const auto wide = sfr::parse_launcher_settings("menu_steady_radius=15\n");
require(sfr::format_launcher_settings(defaults).find("menu_steady_radius=8\n") != std::string::npos &&
sfr::format_launcher_settings(defaults).find("menu_steady_radius_v2=0\n") != std::string::npos,
"the steadying starts at 8 mm for the webcam and Xbox 360 Kinect, off for a Kinect v2");
for (const char* camera : {"motion", "kinect"}) {
const auto chosen = sfr::parse_launcher_settings(std::string("camera=") + camera + "\n");
require(value_of(chosen, "SFR_MENU_HAND_STEADY") == "1" && value_of(chosen, "SFR_MENU_STEADY_RADIUS") == "8",
"8 mm reaches the game with the webcam and the Xbox 360 Kinect");
}
const auto v2 = sfr::parse_launcher_settings("camera=kinect_v2\nmenu_steady_radius=8\n");
require(value_of(v2, "SFR_MENU_HAND_STEADY") == "0" && value_of(v2, "SFR_MENU_STEADY_RADIUS").empty(),
"a Kinect v2 starts off, whatever the webcam's circle is");
const auto v2_set = sfr::parse_launcher_settings("camera=kinect_v2\nmenu_steady_radius_v2=5\n");
require(value_of(v2_set, "SFR_MENU_STEADY_RADIUS") == "5" && sfr::menu_steady_for(v2_set) == 5 &&
v2_set.menu_steady_radius == 8,
"a Kinect v2's own circle reaches the game and leaves the webcam's alone");
const auto wide = sfr::parse_launcher_settings("camera=motion\nmenu_steady_radius=15\n");
require(wide.menu_steady_radius == 15 && value_of(wide, "SFR_MENU_STEADY_RADIUS") == "15" &&
sfr::format_launcher_settings(wide).find("menu_steady_radius=15\n") != std::string::npos,
"a chosen circle survives a save and reaches the game");
const auto off = sfr::parse_launcher_settings("menu_steady_radius=0\n");
const auto off = sfr::parse_launcher_settings("camera=motion\nmenu_steady_radius=0\n");
require(value_of(off, "SFR_MENU_HAND_STEADY") == "0" && value_of(off, "SFR_MENU_STEADY_RADIUS").empty(),
"0 starts the steadying off");
for (const char* bad : {"31", "-1", "big"})
require(sfr::parse_launcher_settings(std::string("menu_steady_radius=") + bad + "\n").menu_steady_radius == 0,
require(sfr::parse_launcher_settings(std::string("menu_steady_radius=") + bad + "\n").menu_steady_radius == 8,
"an out-of-range circle keeps the default");
}

Expand Down Expand Up @@ -612,8 +623,15 @@ void kinect_v2_view_settings() {
require(saved.find("kinect_v2_view=ideal\n") != std::string::npos &&
saved.find("kinect_v2_skeleton_distance") == std::string::npos,
"the view and its tuning survive a save");
require(value_of(sfr::parse_launcher_settings("camera=kinect\nkinect_v2_view=ideal\n"), "SFR_KINECT_V2_DEPTH_VIEW").empty(),
"the Xbox 360 choice sends no v2 view");
const auto old_kinect = sfr::parse_launcher_settings("camera=kinect\n");
require(value_of(old_kinect, "SFR_KINECT_V2_DEPTH_VIEW") == "ideal" &&
value_of(old_kinect, "SFR_KINECT_V2_DEPTH_DISTANCE") == "2.50",
"the Xbox 360 choice sends the v2 view too, for a v2 standing in (an old camera=kinect)");
require(value_of(sfr::parse_launcher_settings("camera=motion\n"), "SFR_KINECT_V2_DEPTH_VIEW").empty(),
"the webcam sends no v2 view");
const auto picture = sfr::parse_launcher_settings("camera=picture\n");
require(picture.camera == "off" && value_of(picture, "SFR_CAMERA").empty(),
"a saved Picture mode, no longer offered, reads as off");
require(sfr::parse_launcher_settings("kinect_v2_view=player\n").kinect_v2_view == "ideal",
"an unknown view keeps the default");
require(sfr::parse_launcher_settings("kinect_v2_distance=9000\n").kinect_v2_distance == 250,
Expand Down
Loading