allow changing the collision zone + save zoom

This commit is contained in:
Stepland 2022-11-20 00:02:14 +01:00
parent 019e9be178
commit 3fe5985900
11 changed files with 109 additions and 30 deletions

View File

@ -75,7 +75,7 @@ namespace better {
};
bool Notes::is_colliding(const better::Note& note, const better::Timing& timing) const {
bool Notes::is_colliding(const better::Note& note, const better::Timing& timing, const sf::Time& collision_zone) const {
const auto [start_beat, end_beat] = note.get_time_bounds();
/*
@ -92,11 +92,9 @@ namespace better {
Reverse-engineering of the jubeat plus iOS app suggest the "official"
note collision zone size is 1030 ms, so actually I wasn't that far off
with 1000 ms !
TODO: Make the collision zone customizable
*/
const auto collision_start = timing.beats_at(timing.time_at(start_beat) - sf::seconds(1));
const auto collision_end = timing.beats_at(timing.time_at(end_beat) + sf::seconds(1));
const auto collision_start = timing.beats_at(timing.time_at(start_beat) - collision_zone);
const auto collision_end = timing.beats_at(timing.time_at(end_beat) + collision_zone);
bool found_collision = false;
in(

View File

@ -39,7 +39,7 @@ namespace better {
is colliding with ANOTHER note. This means notes exactly equal to the
one passed as an argument are NOT taken into account.
*/
bool is_colliding(const better::Note& note, const better::Timing& timing) const;
bool is_colliding(const better::Note& note, const better::Timing& timing, const sf::Time& collision_zone) const;
Notes between(const Interval<Fraction>& bounds);
std::size_t count_between(const Interval<Fraction>& bounds);

View File

@ -14,12 +14,14 @@ ChartState::ChartState(
better::Chart& c,
const std::string& name,
History& history,
std::filesystem::path assets
std::filesystem::path assets,
const config::Config& config_
) :
chart(c),
difficulty_name(name),
config(config_),
history(history),
density_graph(assets)
density_graph(assets, config_)
{}
void ChartState::cut(

View File

@ -8,6 +8,7 @@
#include "better_note.hpp"
#include "better_notes.hpp"
#include "better_song.hpp"
#include "config.hpp"
#include "generic_interval.hpp"
#include "history.hpp"
#include "long_note_dummy.hpp"
@ -20,10 +21,13 @@ struct ChartState {
better::Chart& c,
const std::string& name,
History& history,
std::filesystem::path assets
std::filesystem::path assets,
const config::Config& config
);
better::Chart& chart;
const std::string& difficulty_name;
const config::Config& config;
void cut(
NotificationsQueue& nq,

View File

@ -1,6 +1,7 @@
#include "config.hpp"
#include <SFML/Config.hpp>
#include <SFML/System/Time.hpp>
#include <filesystem>
#include <fmt/format.h>
#include <toml++/toml.h>
@ -219,11 +220,13 @@ void config::LinearView::load_from_v1_0_0_table(const toml::table& tbl) {
if (not tbl["linear_view"].is_table()) {
return;
}
const auto linear_view_table = tbl["linear_view"].ref<toml::table>();
colors = load_linear_view_colors_from_v1_0_0_table(linear_view_table);
sizes = load_linear_view_sizes_from_v1_0_0_table(linear_view_table);
lane_order = load_linear_view_lane_order_from_v1_0_0_table(linear_view_table);
if (linear_view_table["zoom"].is_integer()) {
zoom = *linear_view_table["zoom"].value<int>();
}
}
void config::LinearView::dump_as_v1_0_0(toml::table& tbl) {
@ -231,10 +234,29 @@ void config::LinearView::dump_as_v1_0_0(toml::table& tbl) {
dump_linear_view_colors_as_v1_0_0(colors, linear_view);
dump_linear_view_sizes_as_v1_0_0(sizes, linear_view);
dump_linear_view_lane_order_as_v1_0_0(lane_order, linear_view);
linear_view.insert_or_assign("zoom", zoom);
tbl.insert_or_assign("linear_view", linear_view);
}
void config::Editor::load_from_v1_0_0_table(const toml::table& tbl) {
if (not tbl["editor"].is_table()) {
return;
}
const auto editor_table = tbl["editor"].ref<toml::table>();
if (editor_table["collision_zone"].is_integer()) {
const auto ms = editor_table["collision_zone"].value<int>();
collision_zone = sf::milliseconds(std::clamp(*ms, 100, 2000));
}
}
void config::Editor::dump_as_v1_0_0(toml::table& tbl) {
tbl.insert_or_assign("editor", toml::table{{
"collision_zone", collision_zone.asMilliseconds()
}});
}
config::Config::Config(const std::filesystem::path& settings) :
config_path(settings / "config.toml")
@ -271,6 +293,7 @@ toml::table config::Config::dump_as_v1_0_0() {
};
marker.dump_as_v1_0_0(tbl);
linear_view.dump_as_v1_0_0(tbl);
editor.dump_as_v1_0_0(tbl);
return tbl;
}
@ -284,4 +307,5 @@ config::Config::~Config() {
void config::Config::load_from_v1_0_0_table(const toml::table& tbl) {
marker.load_from_v1_0_0_table(tbl);
linear_view.load_from_v1_0_0_table(tbl);
editor.load_from_v1_0_0_table(tbl);
}

View File

@ -1,5 +1,6 @@
#pragma once
#include <SFML/System/Time.hpp>
#include <filesystem>
#include <toml++/toml.h>
@ -38,6 +39,14 @@ namespace config {
linear_view::Colors colors;
linear_view::Sizes sizes;
linear_view::LaneOrder lane_order;
int zoom = 0;
void load_from_v1_0_0_table(const toml::table& tbl);
void dump_as_v1_0_0(toml::table& tbl);
};
struct Editor {
sf::Time collision_zone = sf::seconds(1);
void load_from_v1_0_0_table(const toml::table& tbl);
void dump_as_v1_0_0(toml::table& tbl);
@ -54,6 +63,7 @@ namespace config {
Marker marker;
LinearView linear_view;
Editor editor;
private:
void load_from_v1_0_0_table(const toml::table& tbl);

View File

@ -7,6 +7,7 @@
#include <algorithm>
#include <cmath>
#include <cstddef>
#include <cstdint>
#include <filesystem>
#include <fmt/core.h>
@ -46,7 +47,7 @@ EditorState::EditorState(const std::filesystem::path& assets_, config::Config& c
chord_claps(std::make_shared<ChordClaps>(nullptr, nullptr, assets_, 1.f)),
beat_ticks(std::make_shared<BeatTicks>(nullptr, assets_, 1.f)),
playfield(assets_),
linear_view(assets_, config_.linear_view),
linear_view(assets_, config_),
applicable_timing(song.timing),
assets(assets_)
{
@ -67,7 +68,7 @@ EditorState::EditorState(
chord_claps(std::make_shared<ChordClaps>(nullptr, nullptr, assets_, 1.f)),
beat_ticks(std::make_shared<BeatTicks>(nullptr, assets_, 1.f)),
playfield(assets_),
linear_view(assets_, config_.linear_view),
linear_view(assets_, config_),
applicable_timing(song.timing),
assets(assets_)
{
@ -518,7 +519,7 @@ void EditorState::display_playfield(Marker& marker, Judgement markerEndingState)
// Check for collisions then display them
std::array<bool, 16> collisions = {};
for (const auto& [_, note] : chart_state->visible_notes) {
if (chart_state->chart.notes->is_colliding(note, *applicable_timing)) {
if (chart_state->chart.notes->is_colliding(note, *applicable_timing, config.editor.collision_zone)) {
collisions[note.get_position().index()] = true;
}
}
@ -1043,7 +1044,7 @@ void EditorState::display_sound_settings() {
void EditorState::display_editor_settings() {
if (ImGui::Begin("Editor Settings", &show_editor_settings)) {
static const std::uint64_t step = 1;
if (ImGui::InputScalar("Snap", ImGuiDataType_U64, &snap, &step, nullptr, "%d")) {
if (ImGui::InputScalar("Snap##Editor Settings", ImGuiDataType_U64, &snap, &step, nullptr, "%d")) {
snap = std::clamp(snap, 1UL, 1000UL);
};
ImGui::SameLine();
@ -1053,6 +1054,37 @@ void EditorState::display_editor_settings() {
"This changes the underlying value that's multiplied "
"by 4 before being shown in the status bar"
);
int collision_zone_ms = config.editor.collision_zone.asMilliseconds();
if (ImGui::SliderInt("Collision Zone##Editor Settings", &collision_zone_ms, 100, 2000, "%d ms")) {
collision_zone_ms = std::clamp(collision_zone_ms, 100, 2000);
config.editor.collision_zone = sf::milliseconds(collision_zone_ms);
if (chart_state) {
chart_state->density_graph.should_recompute = true;
}
}
ImGui::SameLine();
feis::HelpMarker(
"Change the underlying snap value, this allows setting snap "
"values that aren't a divisor of 240. "
"This changes the underlying value that's multiplied "
"by 4 before being shown in the status bar"
);
const std::array<std::pair<const char*, sf::Time>, 3> presets{{
{"F.E.I.S default", sf::seconds(1)},
{"Safe", sf::milliseconds(1066)},
{"jubeat plus", sf::milliseconds(1030)}
}};
if (ImGui::BeginCombo("Collision Zone Presets", presets[0].first)) {
for (const auto& [name, value] : presets) {
if (ImGui::Selectable(name, false)) {
config.editor.collision_zone = value;
if (chart_state) {
chart_state->density_graph.should_recompute = true;
}
}
}
ImGui::EndCombo();
}
}
ImGui::End();
}
@ -1275,7 +1307,7 @@ void EditorState::erase_chart_and_push_history(const std::string& name) {
void EditorState::open_chart(const std::string& name) {
auto& [name_ref, chart] = *song.charts.find(name);
chart_state.emplace(chart, name_ref, history, assets);
chart_state.emplace(chart, name_ref, history, assets, config);
reload_editable_range();
reload_applicable_timing();
reload_all_sounds();

View File

@ -4,8 +4,9 @@
const std::string texture_file = "textures/edit_textures/game_front_edit_tex_1.tex.png";
DensityGraph::DensityGraph(std::filesystem::path assets) :
texture_path(assets / texture_file)
DensityGraph::DensityGraph(std::filesystem::path assets, const config::Config& config) :
texture_path(assets / texture_file),
collision_zone(config.editor.collision_zone)
{
if (!base_texture.loadFromFile(texture_path)) {
std::cerr << "Unable to load texture " << texture_path;
@ -60,7 +61,7 @@ void DensityGraph::compute_densities(
densities.at(section).density += 1;
if (not densities.at(section).has_collisions) {
densities.at(section).has_collisions =
chart.notes->is_colliding(note, timing);
chart.notes->is_colliding(note, timing, collision_zone);
}
}
}

View File

@ -6,6 +6,7 @@
#include <filesystem>
#include "../better_song.hpp"
#include "../config.hpp"
class DensityGraph {
public:
@ -14,7 +15,7 @@ public:
bool has_collisions;
};
DensityGraph(std::filesystem::path assets);
DensityGraph(std::filesystem::path assets, const config::Config& config);
sf::Texture base_texture;
sf::Sprite normal_square;
sf::Sprite collision_square;
@ -38,6 +39,7 @@ public:
private:
const std::filesystem::path texture_path;
const sf::Time& collision_zone;
void compute_densities(
unsigned int height,

View File

@ -40,12 +40,16 @@ void SelectionRectangle::reset() {
end = {-1, -1};
}
LinearView::LinearView(std::filesystem::path assets, config::LinearView& config_) :
colors(config_.colors),
sizes(config_.sizes),
LinearView::LinearView(std::filesystem::path assets, config::Config& config_) :
colors(config_.linear_view.colors),
sizes(config_.linear_view.sizes),
collision_zone(config_.editor.collision_zone),
beats_to_pixels_proportional(0, 1, 0, 100),
lane_order(config_.lane_order)
{}
zoom(config_.linear_view.zoom),
lane_order(config_.linear_view.lane_order)
{
set_zoom(config_.linear_view.zoom);
}
void LinearView::draw(
ImDrawList* draw_list,
@ -167,7 +171,7 @@ void LinearView::draw(
};
auto collision_zone_color = colors.normal_collision_zone;
auto tap_note_color = colors.normal_tap_note;
if (chart_state.chart.notes->is_colliding(tap_note, timing)) {
if (chart_state.chart.notes->is_colliding(tap_note, timing, collision_zone)) {
collision_zone_color = colors.conflicting_collision_zone;
tap_note_color = colors.conflicting_tap_note;
}
@ -222,7 +226,7 @@ void LinearView::draw(
auto collision_zone_color = colors.normal_collision_zone;
auto tap_note_color = colors.normal_tap_note;
auto long_note_color = colors.normal_long_note;
if (chart_state.chart.notes->is_colliding(long_note, timing)) {
if (chart_state.chart.notes->is_colliding(long_note, timing, collision_zone)) {
collision_zone_color = colors.conflicting_collision_zone;
tap_note_color = colors.conflicting_tap_note;
long_note_color = colors.conflicting_long_note;
@ -391,6 +395,9 @@ void LinearView::set_zoom(int newZoom) {
void LinearView::display_settings() {
if (ImGui::Begin("Linear View Settings", &shouldDisplaySettings)) {
if (ImGui::SliderInt("Zoom##Linear View Settings", &zoom, -10, 10, "%d")) {
set_zoom(zoom);
}
if (ImGui::CollapsingHeader("Lanes##Linear View Settings")) {
if (ImGui::BeginCombo("Order", lane_order_name().c_str())) {
if (ImGui::Selectable(

View File

@ -25,7 +25,7 @@ struct SelectionRectangle {
class LinearView {
public:
LinearView(std::filesystem::path assets, config::LinearView& config);
LinearView(std::filesystem::path assets, config::Config& config);
void draw(
ImDrawList* draw_list,
@ -47,17 +47,16 @@ public:
void display_settings();
private:
linear_view::Colors& colors;
linear_view::Sizes& sizes;
const sf::Time& collision_zone;
AffineTransform<Fraction> beats_to_pixels_proportional;
void reload_transforms();
int zoom = 0;
int& zoom;
SelectionRectangle selection_rectangle;
bool started_selection_inside_window = false;