From 3dbfc2820cd31ae17dcc471961f1be157a3f0e6a Mon Sep 17 00:00:00 2001 From: Stepland Date: Mon, 14 Jan 2019 21:43:56 +0100 Subject: [PATCH] Non tested notes drawing code --- Chart.cpp | 6 +++- EditorState.cpp | 70 ++++++++++++++++++++++++++++++++++++++++++++- EditorState.h | 27 ++++++++++++++++-- Marker.cpp | 48 ++++++++++++++++++++++++++++--- Marker.h | 5 ++-- Widgets.cpp | 32 ++------------------- Widgets.h | 46 +++++++++++++++--------------- main.cpp | 75 ++++++++++++++++++++++++++++++++++--------------- 8 files changed, 222 insertions(+), 87 deletions(-) diff --git a/Chart.cpp b/Chart.cpp index fbd97bd..f171f3d 100644 --- a/Chart.cpp +++ b/Chart.cpp @@ -19,4 +19,8 @@ void Chart::setResolution(int resolution) { Chart::Chart(const std::string &dif, int level, int resolution) : dif_name(dif), level(level), resolution(resolution), - Notes() {} + Notes() { + if (resolution <= 0) { + throw std::invalid_argument("Can't set a resolution of "+std::to_string(resolution)); + } +} diff --git a/EditorState.cpp b/EditorState.cpp index ef4efb3..9afcc33 100644 --- a/EditorState.cpp +++ b/EditorState.cpp @@ -10,7 +10,7 @@ #include "tinyfiledialogs.h" #include "Toolbox.h" -EditorState::EditorState(Fumen &fumen) : fumen(fumen) { +EditorState::EditorState(Fumen &fumen) : fumen(fumen), markerEndingState(MISS) { reloadFromFumen(); } @@ -80,6 +80,42 @@ void EditorState::reloadJacket() { } void EditorState::displayPlayfield() { + + ImGui::SetNextWindowSize(ImVec2(400,400),ImGuiCond_FirstUseEver); + ImGui::SetNextWindowSizeConstraints(ImVec2(0,0),ImVec2(FLT_MAX,FLT_MAX),Toolbox::CustomConstraints::ContentSquare); + if (ImGui::Begin("Playfield",&showPlayfield,ImGuiWindowFlags_NoScrollbar)) { + float squareSize = ImGui::GetWindowSize().x / 4.f; + float TitlebarHeight = ImGui::GetWindowSize().y - ImGui::GetWindowSize().x; + if (selectedChart) { + int ImGuiIndex = 0; + for (auto note : getVisibleNotes()) { + std::optional t; + if ((t = playfield.marker.getSprite(playfield.markerEndingState,getSecondsAt(note.getTiming())))) { + int x = note.getPos()%4; + int y = note.getPos()/4; + ImGui::SetCursorPos({x*squareSize,TitlebarHeight + y*squareSize}); + ImGui::PushID(ImGuiIndex); + ImGui::Image(*t,{squareSize,squareSize}); + ImGui::PopID(); + } + ++ImGuiIndex; + } + } + for (int y = 0; y < 4; ++y) { + for (int x = 0; x < 4; ++x) { + ImGui::PushID(x+4*y); + ImGui::SetCursorPos({x*squareSize,TitlebarHeight + y*squareSize}); + ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(0,0,0,0)); + ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(0,0,1.f,0.1f)); + ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(0,0,1.f,0.5f)); + ImGui::ImageButton(playfield.button,{squareSize,squareSize},0); + ImGui::PopStyleColor(3); + ImGui::PopID(); + } + } + } + ImGui::End(); + } /* @@ -135,6 +171,8 @@ void EditorState::displayStatus() { ImGui::TextColored(ImVec4(1,0.42,0.41,1),"No jacket loaded"); } } + ImGui::Checkbox("Beat Tick",&playBeatTick); + ImGui::Checkbox("Note Tick",&playNoteTick); } ImGui::End(); } @@ -224,6 +262,36 @@ void EditorState::displayTimeline() { ImGui::PopStyleVar(3); } +std::vector EditorState::getVisibleNotes() { + if (selectedChart) { + + std::vector visibleNotes; + + float minPos; + if (this->markerEndingState == MISS) { + minPos = playbackPosition.asSeconds() - 8.f/30.f; + } else { + minPos = playbackPosition.asSeconds() - 16.f/30.f; + } + + float maxPos = playbackPosition.asSeconds() + 16.f/30.f; + + int min_exclusive = static_cast(getTicksAt(minPos)); + int max_exclusive = static_cast(getTicksAt(maxPos)); + + for (auto note : selectedChart->Notes) { + if (note.getTiming() > min_exclusive and note.getTiming() < max_exclusive) { + visibleNotes.push_back(note); + } + } + + return visibleNotes; + + } else { + return {}; + } +} + void ESHelper::save(EditorState& ed) { try { ed.fumen.autoSaveAsMemon(); diff --git a/EditorState.h b/EditorState.h index 45b495b..58620d4 100644 --- a/EditorState.h +++ b/EditorState.h @@ -10,12 +10,14 @@ #include #include "Fumen.h" #include "Marker.h" +#include "Widgets.h" class EditorState { public: Fumen fumen; - Marker marker; + Widgets::Playfield playfield; + MarkerEndingState markerEndingState; std::optional music; std::optional jacket; std::optional selectedChart; @@ -23,7 +25,23 @@ public: sf::Time playbackPosition; sf::Time chartRuntime; // Timing at which the playback stops bool playing; - float getBeats() {return ((playbackPosition.asSeconds()+fumen.offset)/60.f)* fumen.BPM;}; + float getBeats() {return getBeatsAt(playbackPosition.asSeconds());}; + float getBeatsAt(float seconds) {return ((seconds+fumen.offset)/60.f)* fumen.BPM;}; + float getTicks() {return getTicksAt(playbackPosition.asSeconds());}; + float getTicksAt(float seconds) { + if (selectedChart) { + return getBeatsAt(seconds)*selectedChart->getResolution(); + } else { + return getBeatsAt(seconds)*240.f; + } + } + float getSecondsAt(int tick) { + if (selectedChart) { + return (60.f * tick)/(fumen.BPM * selectedChart->getResolution()) - fumen.offset; + } else { + return (60.f * tick)/(fumen.BPM * 240.f) - fumen.offset; + } + } void reloadFromFumen(); void reloadMusic(); @@ -42,6 +60,11 @@ public: void displayPlaybackStatus(); void displayTimeline(); + bool playBeatTick; + bool playNoteTick; + + std::vector getVisibleNotes(); + explicit EditorState(Fumen& fumen); }; diff --git a/Marker.cpp b/Marker.cpp index 1502a91..d191ba4 100644 --- a/Marker.cpp +++ b/Marker.cpp @@ -2,6 +2,9 @@ // Created by Syméon on 17/08/2017. // +#include +#include +#include #include "Marker.h" Marker::Marker(std::string folder) { @@ -41,11 +44,48 @@ Marker::Marker(std::string folder) { } } -sf::Texture Marker::getSprite(Etat etat, int frame) { +std::optional Marker::getSprite(MarkerEndingState state, float seconds) { + std::ostringstream frameName; + int frame = static_cast((seconds*30.f+16.f)); + if (frame >= 0 and frame <= 15) { + frameName << "ma" << std::setfill('0') << std::setw(2) << frame; + return textures[frameName.str()]; + } else { + if (state == MISS) { + if (frame >= 16 and frame <= 23) { + frameName << "ma" << std::setfill('0') << std::setw(2) << frame; + return textures[frameName.str()]; + } + } else if (frame >= 16 and frame <= 32) { + switch (state) { + case EARLY: + frameName << "h1"; + break; + case GOOD: + frameName << "h2"; + break; + case GREAT: + frameName << "h3"; + break; + case PERFECT: + frameName << "h4"; + break; + default: + return {}; + } + frameName << std::setfill('0') << std::setw(2) << frame-16; + return textures[frameName.str()]; + } + } + return {}; +} + +/* +sf::Texture Marker::getSprite(MarkerEndingState state, int frame) { int lower; int upper; - switch(etat) { + switch(state) { case MISS: lower = 16; upper = 32; @@ -61,8 +101,7 @@ sf::Texture Marker::getSprite(Etat etat, int frame) { } std::string tex_key; - switch (etat) { - case APPROCHE: + switch (state) { case MISS: tex_key += "ma"; break; @@ -86,3 +125,4 @@ sf::Texture Marker::getSprite(Etat etat, int frame) { return textures[tex_key+std::to_string(frame)]; } + */ diff --git a/Marker.h b/Marker.h index f79e462..3971451 100644 --- a/Marker.h +++ b/Marker.h @@ -11,8 +11,7 @@ #include #include -enum Etat { - APPROCHE, +enum MarkerEndingState { MISS, EARLY, GOOD, @@ -25,7 +24,7 @@ class Marker { public: Marker(std::string folder = "mk0013"); - sf::Texture getSprite(Etat etat, int frame); + std::optional getSprite(MarkerEndingState state, float seconds); private: diff --git a/Widgets.cpp b/Widgets.cpp index 408ef10..b9f2626 100644 --- a/Widgets.cpp +++ b/Widgets.cpp @@ -5,7 +5,7 @@ #include "Widgets.h" #include "Toolbox.h" -Ecran_attente::Ecran_attente() : gris_de_fond(sf::Color(38,38,38)) { +Widgets::Ecran_attente::Ecran_attente() : gris_de_fond(sf::Color(38,38,38)) { if(!tex_FEIS_logo.loadFromFile("assets/textures/FEIS_logo.png")) { @@ -17,7 +17,7 @@ Ecran_attente::Ecran_attente() : gris_de_fond(sf::Color(38,38,38)) { } -void Ecran_attente::render(sf::RenderWindow& window) { +void Widgets::Ecran_attente::render(sf::RenderWindow& window) { // effacement de la fenêtre en noir window.clear(gris_de_fond); @@ -27,9 +27,7 @@ void Ecran_attente::render(sf::RenderWindow& window) { window.draw(FEIS_logo); } -Playfield::Playfield() { - - marker = Marker(); +Widgets::Playfield::Playfield() { if (!button.loadFromFile(button_path,{0,0,192,192})) { std::cerr << "Unable to load texture " << button_path; throw std::runtime_error("Unable to load texture " + button_path); @@ -39,27 +37,3 @@ Playfield::Playfield() { throw std::runtime_error("Unable to load texture " + button_path); } } - -void Playfield::render(sf::RenderWindow &window, EditorState& editorState) { - - ImGui::SetNextWindowSize(ImVec2(400,400),ImGuiCond_FirstUseEver); - ImGui::SetNextWindowSizeConstraints(ImVec2(0,0),ImVec2(FLT_MAX,FLT_MAX),Toolbox::CustomConstraints::ContentSquare); - ImGui::Begin("Playfield",&editorState.showPlayfield,ImGuiWindowFlags_NoScrollbar); - { - float squareSize = ImGui::GetWindowSize().x / 4.f; - float TitlebarHeight = ImGui::GetWindowSize().y - ImGui::GetWindowSize().x; - for (int y = 0; y < 4; ++y) { - for (int x = 0; x < 4; ++x) { - ImGui::PushID(x+4*y); - ImGui::SetCursorPos({x*squareSize,TitlebarHeight + y*squareSize}); - ImGui::PushStyleColor(ImGuiCol_Button, (ImVec4)ImColor::HSV(0,0,0,0)); - ImGui::PushStyleColor(ImGuiCol_ButtonHovered, (ImVec4)ImColor::HSV(0,0,1.f,0.1f)); - ImGui::PushStyleColor(ImGuiCol_ButtonActive, (ImVec4)ImColor::HSV(0,0,1.f,0.5f)); - ImGui::ImageButton(button,{squareSize,squareSize},0); - ImGui::PopStyleColor(3); - ImGui::PopID(); - } - } - } - ImGui::End(); -} diff --git a/Widgets.h b/Widgets.h index 16b028f..42cd219 100644 --- a/Widgets.h +++ b/Widgets.h @@ -2,43 +2,41 @@ // Created by Syméon on 17/08/2017. // -#ifndef FEIS_SCREEN_H -#define FEIS_SCREEN_H +#pragma once #include #include #include #include "Marker.h" -#include "EditorState.h" -class Ecran_attente { +namespace Widgets { + class Ecran_attente { -public: + public: - Ecran_attente(); - void render(sf::RenderWindow &window); + Ecran_attente(); + void render(sf::RenderWindow &window); -private: + private: - sf::Color gris_de_fond; - sf::Texture tex_FEIS_logo; - sf::Sprite FEIS_logo; + sf::Color gris_de_fond; + sf::Texture tex_FEIS_logo; + sf::Sprite FEIS_logo; -}; + }; -class Playfield { + class Playfield { -public: + public: - Playfield(); - void render(sf::RenderWindow &window, EditorState& editorState); + Playfield(); - Marker marker; - sf::Texture button; - sf::Texture button_pressed; + Marker marker; + MarkerEndingState markerEndingState; + sf::Texture button; + sf::Texture button_pressed; -private: - std::string button_path = "assets/textures/edit_textures/game_front_edit_tex_1.tex.png"; -}; - -#endif //FEIS_SCREEN_H + private: + std::string button_path = "assets/textures/edit_textures/game_front_edit_tex_1.tex.png"; + }; +} diff --git a/main.cpp b/main.cpp index cdb58e3..11fe6e7 100644 --- a/main.cpp +++ b/main.cpp @@ -22,9 +22,25 @@ int main(int argc, char** argv) { IO.Fonts->AddFontFromFileTTF("assets/fonts/NotoSans-Medium.ttf", 16.f); ImGui::SFML::UpdateFontTexture(); + std::string noteTickPath = "assets/sounds/sound note tick.wav"; + sf::SoundBuffer noteTick; + if (!noteTick.loadFromFile(noteTickPath)) { + std::cerr << "Unable to load sound " << noteTickPath; + throw std::runtime_error("Unable to load sound " + noteTickPath); + } + sf::Sound noteTickSound(noteTick); - Ecran_attente bg; - Playfield playfield; + bool beatTicked = false; + std::string beatTickPath = "assets/sounds/sound beat tick.wav"; + sf::SoundBuffer beatTick; + if (!beatTick.loadFromFile(beatTickPath)) { + std::cerr << "Unable to load sound " << beatTickPath; + throw std::runtime_error("Unable to load sound " + beatTickPath); + } + sf::Sound beatTickSound(beatTick); + + + Widgets::Ecran_attente bg; std::optional editorState; sf::Clock deltaClock; @@ -41,31 +57,33 @@ int main(int argc, char** argv) { window.setView(sf::View(sf::FloatRect(0, 0, event.size.width, event.size.height))); break; case sf::Event::KeyPressed: - if (event.key.code == sf::Keyboard::Space) { - if (not ImGui::GetIO().WantTextInput) { - if (editorState) { - editorState->playing = not editorState->playing; - } - /* - if (editorState and editorState->music) { - switch (editorState->music->getStatus()) { - case sf::Music::Stopped: - case sf::Music::Paused: - editorState->music->play(); - break; - case sf::Music::Playing: - editorState->music->pause(); - break; - } - } - */ - } - } + switch (event.key.code) { + case sf::Keyboard::F3: + if (editorState) { + editorState->playBeatTick = not editorState->playBeatTick; + } + break; + case sf::Keyboard::F4: + if (editorState) { + editorState->playNoteTick = not editorState->playNoteTick; + } + break; + case sf::Keyboard::Space: + if (not ImGui::GetIO().WantTextInput) { + if (editorState) { + editorState->playing = not editorState->playing; + } + } + break; + } break; } } + sf::Time delta = deltaClock.restart(); ImGui::SFML::Update(window, delta); + + // Gestion du playback if (editorState->playing) { editorState->playbackPosition += delta; if (editorState->music) { @@ -84,6 +102,16 @@ int main(int argc, char** argv) { break; } } + if (editorState->playBeatTick) { + if (fmodf(editorState->getBeats(),1.f) < 0.5) { + if (not beatTicked) { + beatTickSound.play(); + beatTicked = true; + } + } else { + beatTicked = false; + } + } if (editorState->playbackPosition >= editorState->chartRuntime) { editorState->playing = false; editorState->playbackPosition = editorState->chartRuntime; @@ -99,7 +127,7 @@ int main(int argc, char** argv) { // Dessin du fond if (editorState) { if (editorState->showPlayfield) { - playfield.render(window,*editorState); + editorState->displayPlayfield(); } if (editorState->showProperties) { editorState->displayProperties(); @@ -118,6 +146,7 @@ int main(int argc, char** argv) { bg.render(window); } + // TODO : Use events instead // Gestion des Raccourcis Clavier // Ctrl+S