Compare commits

..

No commits in common. "b92bffb43e03a2fac08a294c0f4effe627497015" and "319e27e1eb4677c9652d4ddfe09df806b539a583" have entirely different histories.

132 changed files with 0 additions and 6028 deletions

10
.gitignore vendored
View File

@ -1,10 +0,0 @@
# This file is used to ignore files which are generated
# ----------------------------------------------------------------------------
build
SFML-*
*.user
*CMakeFiles*
*Makefile
*.cmake*
*.cbp

View File

@ -1,43 +0,0 @@
cmake_minimum_required(VERSION 3.13)
project(project-kyoku LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall -Werror -Wextra -Wpedantic -g")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/build)
set(CMAKE_RESOURCE_DIRECTORY ${CMAKE_SOURCE_DIR}/resources)
set(CMAKE_THREAD_LIBS_INIT "-lpthread")
SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread")
set(CMAKE_HAVE_THREADS_LIBRARY 1)
set(CMAKE_USE_WIN32_THREADS_INIT 0)
set(CMAKE_USE_PTHREADS_INIT 1)
set(THREADS_PREFER_PTHREAD_FLAG ON)
include_directories(${CMAKE_SOURCE_DIR}/include)
file(GLOB_RECURSE SOURCES "src/main.cpp" "include/*.h")
add_executable(project-kyoku ${SOURCES})
SET(CMAKE_INSTALL_PREFIX /)
# When new game modes appear, aggregate them into a ONE subdirectory
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/modes/classicmode/CMakeLists.txt")
add_subdirectory(src/modes/classicmode)
target_link_libraries(project-kyoku classicmode)
endif()
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/tools/CMakeLists.txt")
add_subdirectory(src/tools)
target_link_libraries(project-kyoku tools)
endif()
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/application/CMakeLists.txt")
add_subdirectory(src/application)
target_link_libraries(project-kyoku application)
endif()
if (EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/src/impl/CMakeLists.txt")
add_subdirectory(src/impl)
target_link_libraries(project-kyoku impl)
endif()
file(COPY "${CMAKE_RESOURCE_DIRECTORY}" DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})

View File

@ -1,7 +0,0 @@
Boost Software License - Version 1.0 - August 17th, 2003
Permission is hereby granted, free of charge, to any person or organization obtaining a copy of the software and accompanying documentation covered by this license (the "Software") to use, reproduce, display, distribute, execute, and transmit the Software, and to prepare derivative works of the Software, and to permit third-parties to whom the Software is furnished to do so, all subject to the following:
The copyright notices in the Software and this entire statement, including the above license grant, this restriction and the following disclaimer, must be included in all copies of the Software, in whole or in part, and all derivative works of the Software, unless such copies or derivative works are solely in the form of machine-executable object code generated by a source language processor.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@ -1,37 +0,0 @@
#pragma once
#include <type_traits>
#include "core/point.h"
#include "core/vector.h"
namespace kku
{
template <typename T, typename = std::enable_if_t<std::is_arithmetic_v<T>>>
struct Area
{
T left = 0;
T top = 0;
T width = 0;
T height = 0;
inline kku::Point position() const noexcept
{
return kku::Point{static_cast<float>(left),
static_cast<float>(top) };
}
inline void moveBy(const kku::Vector2<T>& vector)
{
top += vector.second;
left += vector.first;
}
inline bool contains(const kku::Point& point) const
{
return point.x >= left ; // debug it when on computer
}
};
}

View File

@ -1,24 +0,0 @@
#pragma once
#include "core/time.h"
namespace kku
{
struct BPMSection
{
unsigned int bpm = 120; // Hi, osu
unsigned int fraction = 2;
microsec offset_start = 0;
microsec interval = 0;
};
struct BPMSectionComparator
{
bool operator()(const BPMSection& lhs, const BPMSection& rhs) const noexcept
{
return lhs.offset_start < rhs.offset_start;
}
};
}

View File

@ -1,14 +0,0 @@
#pragma once
namespace kku
{
struct Color
{
unsigned char red = 0;
unsigned char green = 0;
unsigned char blue = 0;
unsigned char alpha = 0;
};
}

View File

@ -1,28 +0,0 @@
#pragma once
#include <memory>
#include "core/music.h"
#include "core/text.h"
#include "core/resourceholder.h"
#include "core/rectangle.h"
#include "core/vector.h"
#include "core/line.h"
#include "core/sprite.h"
namespace kku
{
class CoreFactory
{
public:
virtual ~CoreFactory() = default;
virtual std::shared_ptr<kku::Music> getMusic() const = 0;
virtual std::shared_ptr<kku::Text> getText(kku::Font::Id id) const = 0;
virtual std::shared_ptr<kku::Rectangle> getRectangle() const = 0;
virtual std::shared_ptr<kku::Line> getLine() const = 0;
virtual std::shared_ptr<kku::Sprite> getSprite(kku::GUISprite::Id id) const = 0;
virtual kku::Vector2<std::size_t> getRenderSize() const = 0;
};
}

View File

@ -1,88 +0,0 @@
#pragma once
#include <set>
#include <algorithm>
#include "core/gameevent.h"
#include "core/updatedata.h"
#include "core/bpmsection.h"
namespace kku
{
class Editor
{
public:
virtual ~Editor() = default;
virtual void input(GameEvent&& input) = 0;
virtual void update(UpdateData&& updatedata) = 0;
virtual void display() const = 0;
virtual void recalculate(const microsec& timestamp) = 0;
void setBPMSections(const std::set<BPMSection, BPMSectionComparator>& sections) noexcept
{
_bpm_sections = sections;
}
void setBPMSections(std::set<BPMSection, BPMSectionComparator>&& sections) noexcept
{
_bpm_sections = std::move(sections);
}
bool insertBPMSection(const BPMSection& section)
{
return _bpm_sections.insert(section).second;
}
bool insertBPMSection(BPMSection&& section)
{
return _bpm_sections.insert(section).second;
}
bool removeBPMSectionAt(const microsec& offset)
{
auto section_it = std::find_if(_bpm_sections.rbegin(), _bpm_sections.rend(),
[offset](const auto& section)
{
return section.offset_start < offset;
});
if (section_it != _bpm_sections.rend())
{
++section_it;
_bpm_sections.erase(section_it.base());
return true;
}
return false;
}
BPMSection getBPMSectionAt(const microsec& offset) const
{
auto section_it = std::find_if(_bpm_sections.rbegin(), _bpm_sections.rend(),
[offset](const auto& section)
{
return section.offset_start < offset;
});
if (section_it != _bpm_sections.rend())
{
++section_it;
return *section_it.base();
}
return BPMSection();
}
void clearBPMSections() noexcept
{
_bpm_sections.clear();
}
protected:
std::set<BPMSection, BPMSectionComparator> _bpm_sections;
};
}

View File

@ -1,26 +0,0 @@
#pragma once
#include "core/systemevent.h"
#include <string>
namespace kku
{
class EditorCallback
{
public:
virtual ~EditorCallback() = default;
struct Metadata
{
const std::string group_title;
const std::string title;
};
virtual bool isEnabled() const = 0;
virtual void run() const = 0;
virtual Metadata getMetadata() const = 0;
};
}

View File

@ -1,11 +0,0 @@
#pragma once
#include <functional>
namespace kku
{
using lambda = std::function<void(void)>;
using predicate = std::function<bool(void)>;
}

View File

@ -1,20 +0,0 @@
#pragma once
#include "core/gameevent.h"
#include "core/updatedata.h"
namespace kku
{
class Game
{
public:
virtual ~Game() = default;
virtual void run() = 0;
virtual void input(GameEvent&& inputdata) = 0;
virtual void update(UpdateData&& updatedata) = 0;
virtual void display() const = 0;
};
}

View File

@ -1,15 +0,0 @@
#pragma once
#include "core/systemevent.h"
#include "core/time.h"
namespace kku
{
struct GameEvent
{
const microsec timestamp = 0;
const SystemEvent event;
};
}

View File

@ -1,18 +0,0 @@
#pragma once
#include "core/point.h"
#include "core/color.h"
namespace kku
{
class Line
{
public:
virtual ~Line() = default;
virtual void setPosition(const kku::Point& p1, const kku::Point& p2) = 0;
virtual void setColor(const kku::Color& c1, const kku::Color& c2) = 0;
virtual void display() = 0;
};
}

View File

@ -1,32 +0,0 @@
#pragma once
#include <string>
#include "core/time.h"
namespace kku
{
class Music
{
public:
virtual ~Music() = default;
virtual bool open(const std::string& filepath) = 0;
virtual void play() = 0;
virtual void pause() = 0;
virtual void stop() = 0;
virtual bool isPlaying() const = 0;
virtual void setVolume(float volume) = 0;
virtual void setOffset(const kku::microsec& offset) = 0;
virtual void moveOffset(const kku::microsec& delta) = 0;
virtual kku::microsec fetchOffset() = 0;
virtual kku::microsec getDuration() const = 0;
};
}

View File

@ -1,55 +0,0 @@
#pragma once
#include "core/time.h"
#include "core/gameevent.h"
namespace kku
{
class Note
{
public:
explicit Note(microsec perfect_offset) :
_perfect_offset(perfect_offset) {}
virtual ~Note() = default;
virtual bool isActive(const microsec& offset) const = 0;
virtual void update(const microsec& music_offset) = 0;
virtual void input(kku::GameEvent&& input) = 0;
inline const microsec& getPerfectOffset() const noexcept
{
return _perfect_offset;
}
bool operator<(const Note& note) const
{
return _perfect_offset < note._perfect_offset;
}
bool operator==(const Note& note) const
{
return _perfect_offset == note._perfect_offset;
}
bool operator>(const Note& note) const
{
return _perfect_offset > note._perfect_offset;
}
protected:
microsec _perfect_offset;
};
struct NotePtrComparator
{
bool operator()(const Note* lhs, const Note* rhs) const noexcept
{
return lhs->getPerfectOffset() < rhs->getPerfectOffset();
}
};
}

View File

@ -1,46 +0,0 @@
#pragma once
namespace kku
{
struct Point
{
float x;
float y;
constexpr inline explicit Point() noexcept :
x(0.), y(0.)
{}
constexpr inline explicit Point(int x, int y) noexcept :
x(x), y(y)
{}
constexpr inline explicit Point(float x, float y) noexcept :
x(x), y(y)
{}
constexpr inline Point operator+(const Point& right) const noexcept
{
return Point{right.x + x, right.y + y};
}
constexpr inline Point operator-(const Point& right) const noexcept
{
return Point{right.x - x, right.y - y};
}
inline void moveBy(float x, float y) noexcept
{
this->x += x;
this->y += y;
}
inline void scaleBy(float factor) noexcept
{
x *= factor;
y *= factor;
}
};
}

View File

@ -1,69 +0,0 @@
#pragma once
#include <numeric>
#include <type_traits>
#include <vector>
#include <cmath>
#include <iostream>
#include "core/time.h"
namespace kku
{
template<typename Grade, typename = std::enable_if_t<std::is_enum<Grade>::value>>
class PrecisionEvaluator
{
public:
PrecisionEvaluator(const std::vector<microsec>& intervals, microsec offset) :
_offset(offset),
_intervals(intervals)
{
_start_handling_offset = _offset - intervals.back();
_end_handling_offset = _offset + intervals.back();
}
inline microsec offset() const noexcept
{
return _offset;
}
inline bool isActive(microsec music_play_offset) const noexcept
{
return music_play_offset > _start_handling_offset
&& music_play_offset < _end_handling_offset;
}
Grade calculatePrecision(microsec odds) const
{
microsec shift_from_perfect = std::abs(odds - offset());
std::cout << "Shift " << ((odds > _offset) ? "late: " : "early: ")
<< shift_from_perfect << "\n";
std::size_t raw_grade;
for (raw_grade = 0; raw_grade < _intervals.size(); ++raw_grade)
{
if (shift_from_perfect <= _intervals.at(raw_grade))
break;
}
return static_cast<Grade>(raw_grade);
}
private:
microsec _offset;
microsec _start_handling_offset;
microsec _end_handling_offset;
/* Amount of values in enum instanced as GradeS
* represents capacity of _intervals.
* So, for each V value in GradeS enum, _intervals[V]
* should return time shift from V - 1.
* V0 is PERFECT SCORE and the last V represents the worst
* grades which is death of note by expiration */
const std::vector<microsec> _intervals;
};
}

View File

@ -1,27 +0,0 @@
#pragma once
#include "core/area.h"
#include "core/color.h"
namespace kku
{
class Rectangle
{
public:
virtual ~Rectangle() = default;
virtual void setRect(const Area<float>& rect) = 0;
virtual Area<float> getRect() const = 0;
virtual void setPosition(const Point& position) = 0;
virtual Point getPosition() const = 0;
virtual void move(const kku::Vector2<float>& delta) = 0;
virtual void setColor(const Color& color) = 0;
virtual kku::Color getColor() const = 0;
virtual bool contains(const kku::Point& position) const = 0;
virtual void display() = 0;
};
}

View File

@ -1,52 +0,0 @@
#pragma once
#include <memory>
#include <map>
namespace kku
{
template <typename Resource, typename Id>
class ResourceHolder
{
public:
inline void load(Id id, std::unique_ptr<Resource>&& resource) noexcept
{
_resources[id] = std::move(resource);
}
inline std::shared_ptr<Resource> get(Id id) const
{
return _resources.find(id)->second;
}
private:
std::map<Id, std::shared_ptr<Resource>> _resources;
};
namespace Font
{
enum class Id
{
GUI
};
}
namespace Texture
{
enum class Id
{
GUI
};
}
namespace GUISprite
{
enum class Id
{
SFML_LOGO,
CRYPTOPP_LOGO
};
}
}

View File

@ -1,20 +0,0 @@
#pragma once
#include "core/area.h"
namespace kku
{
class Sprite
{
public:
virtual ~Sprite() = default;
virtual void setPosition(const Point& position) = 0;
virtual Point getPosition() const = 0;
virtual void move(const kku::Vector2<float>& delta) = 0;
virtual void display() const = 0;
};
}

View File

@ -1,61 +0,0 @@
#pragma once
#include <memory>
#include <stack>
#include <map>
namespace kku
{
template<typename Type, class SpriteFactory, class Sprite,
typename = std::enable_if_t<std::is_enum<Type>::value>>
class SpriteContainer
{
public:
explicit SpriteContainer(std::initializer_list<Type>&& types,
const std::shared_ptr<SpriteFactory>& factory,
std::size_t reserve_size = 20) :
_sprite_factory(factory),
_poll_reserve_size(reserve_size)
{
for (const Type& type : types)
reallocatePoll(type);
}
inline std::shared_ptr<Sprite> getSprite(Type type)
{
SpritePoll& poll = _sprite_dispatcher.at(type);
if (poll.empty())
reallocatePoll(type);
std::shared_ptr<Sprite> sprite = poll.top();
poll.pop();
return sprite;
}
inline void resetSprite(const std::shared_ptr<Sprite> &sprite, Type action) noexcept
{
_sprite_dispatcher[action].push(sprite);
}
~SpriteContainer() = default;
private:
inline void reallocatePoll(Type sprite_type)
{
SpritePoll &poll = _sprite_dispatcher[sprite_type];
for (std::size_t i = 0; i < _poll_reserve_size; ++i)
{
poll.push(_sprite_factory->createSprite(sprite_type));
}
}
using SpritePoll = std::stack<std::shared_ptr<Sprite>>;
std::map<Type, SpritePoll> _sprite_dispatcher;
const std::shared_ptr<SpriteFactory> _sprite_factory;
std::size_t _poll_reserve_size;
};
}

View File

@ -1,171 +0,0 @@
#pragma once
#include <variant>
#include "core/point.h"
namespace kku
{
struct SystemEvent
{
enum class Type
{
None = 0,
Resize = 1,
KeyPress = 2,
KeyRelease = 3,
MouseWheelScroll = 4,
MouseMove = 5,
MousePress = 6,
MouseRelease = 7
};
struct Size
{
std::size_t width = 0;
std::size_t height = 0;
};
struct Key
{
enum class Code
{
Unknown = -1,
A = 0,
B,
C,
D,
E,
F,
G,
H,
I,
J,
K,
L,
M,
N,
O,
P,
Q,
R,
S,
T,
U,
V,
W,
X,
Y,
Z,
Num0,
Num1,
Num2,
Num3,
Num4,
Num5,
Num6,
Num7,
Num8,
Num9,
Escape,
LControl,
LShift,
LAlt,
LSystem,
RControl,
RShift,
RAlt,
RSystem,
Menu,
LBracket,
RBracket,
Semicolon,
Comma,
Period,
Quote,
Slash,
Backslash,
Tilde,
Equal,
Hyphen,
Space,
Enter,
Backspace,
Tab,
PageUp,
PageDown,
End,
Home,
Insert,
Delete,
Add,
Subtract,
Multiply,
Divide,
Left,
Right,
Up,
Down,
Numpad0,
Numpad1,
Numpad2,
Numpad3,
Numpad4,
Numpad5,
Numpad6,
Numpad7,
Numpad8,
Numpad9,
F1,
F2,
F3,
F4,
F5,
F6,
F7,
F8,
F9,
F10,
F11,
F12,
F13,
F14,
F15,
Pause
};
Code view = Code::Unknown;
bool alt = false;
bool control = false;
bool shift = false;
};
struct Mouse
{
Point position;
bool scrolled_up = false;
enum class Button
{
None = 0,
Wheel = 1,
Left = 2,
Right = 3
};
Button button = Button::Left;
};
struct None
{};
Type type = Type::None;
std::variant<Size, Key, Mouse, None> data;
};
}

View File

@ -1,24 +0,0 @@
#pragma once
#include <string>
#include "core/color.h"
#include "core/point.h"
#include "core/vector.h"
namespace kku
{
class Text
{
public:
virtual ~Text() = default;
virtual void setString(const std::string& string) = 0;
virtual void setCharacterSize(std::size_t pixels) = 0;
virtual void setPosition(const Point& point) = 0;
virtual void move(const kku::Vector2<float>& delta) = 0;
virtual void setColor(const Color& color) = 0;
virtual void display() = 0;
};
}

View File

@ -1,22 +0,0 @@
#pragma once
namespace kku
{
using microsec = long long;
struct TimeRange
{
const microsec begin = 0;
const microsec end = 0;
constexpr inline explicit TimeRange() noexcept :
begin(0), end(0)
{}
constexpr inline explicit TimeRange(microsec x, microsec y) noexcept :
begin(x), end(y)
{}
};
}

View File

@ -1,171 +0,0 @@
#pragma once
#include <set>
#include <memory>
#include <algorithm>
#include "core/time.h"
#include "core/note.h"
namespace kku
{
template <class TNote, class = std::enable_if_t<std::is_base_of<Note, TNote>::value>>
class Timeline
{
public:
explicit Timeline() :
_current_offset(0)
{}
typedef typename std::set<TNote*>::const_iterator Iterator;
void recalculate(const microsec& offset)
{
_current_offset = offset;
expire(_top_note);
if (!_timeline.empty())
{
Iterator head_iterator = _timeline.begin();
while (!isExpired(head_iterator))
{
if ((*head_iterator)->getPerfectOffset() >= offset)
{
Iterator pre_head = head_iterator;
--pre_head;
_top_note = !isExpired(pre_head) && (*pre_head)->isActive(offset)
? pre_head
: head_iterator;
break;
}
++head_iterator;
}
if (isExpired(_top_note))
_top_note = _timeline.begin();
}
}
void setNotes(const std::set<TNote*, NotePtrComparator>& notes)
{
_timeline = std::move(notes);
recalculate(_current_offset);
if (isExpired(_top_note))
return;
}
void insertNote(TNote* note)
{
_top_note = _timeline.insert(note).first;
recalculate(_current_offset);
update(_current_offset);
}
void insertNotes(const std::set<TNote*, NotePtrComparator>& notes)
{
_timeline.insert(notes.begin(), notes.end());
recalculate(_current_offset);
update(_current_offset);
}
inline void clear()
{
for (auto& note : _timeline)
delete note;
_timeline.clear();
}
void update(const microsec& offset)
{
_current_offset = offset;
updateTopNote(_current_offset);
}
Iterator getActiveNote(const microsec& music_offset) noexcept
{
Iterator return_note = _timeline.end();
auto note_iterator = _top_note;
while (!isExpired(note_iterator))
{
const auto& note = *note_iterator;
if (note->isActive(music_offset))
{
return_note = note_iterator;
break;
}
else if (note->getPerfectOffset() > music_offset)
break;
++note_iterator;
}
return return_note;
}
inline Iterator getNoteBy(const microsec& music_offset) noexcept
{
return std::find_if(_timeline.begin(), _timeline.end(),
[music_offset](const auto& note)
{
return note->getPerfectOffset() == music_offset;
});
}
inline bool isExpired(const Iterator& iterator) const noexcept
{
return iterator == _timeline.end();
}
inline void expire(Iterator& iterator) noexcept
{
iterator = _timeline.end();
}
inline Iterator getTopNote() const noexcept
{
return _top_note;
}
inline Iterator begin() const noexcept
{
return _timeline.begin();
}
inline Iterator end() const noexcept
{
return _timeline.end();
}
private:
std::set<TNote*, NotePtrComparator> _timeline;
microsec _current_offset;
inline void updateTopNote(const microsec& music_offset) noexcept
{
if (isExpired(_top_note))
return;
const auto& top_note = *_top_note;
bool already_played = top_note->getPerfectOffset() < music_offset
&& !top_note->isActive(music_offset);
if (already_played)
++_top_note;
}
Iterator _top_note;
};
}

View File

@ -1,16 +0,0 @@
#pragma once
#include "core/time.h"
namespace kku
{
struct UpdateData
{
const microsec timestamp;
const microsec dt;
};
}

View File

@ -1,22 +0,0 @@
#pragma once
#include <utility>
namespace kku
{
/* Meaning an element of a vector space in math.
* Don't mistake for std::vector<T>
* For now we don't need it as a special class,
* so let it be a wrapper. */
template <typename T>
using Vector2 = std::pair<T, T>;
template <typename T>
inline constexpr auto makeVector(T&& l, T&& r) -> Vector2<T>
{
return std::make_pair(std::forward<T>(l), std::forward<T>(r));
}
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 24 KiB

View File

@ -1,18 +0,0 @@
cmake_minimum_required(VERSION 3.13)
project(application)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/shared)
file(GLOB_RECURSE HEADERS "shared/*.h" "include/*.h")
file(GLOB_RECURSE SOURCES "src/*.cpp")
add_library(application STATIC ${SOURCES} ${HEADERS})
target_link_libraries(application tools classicmode)
target_include_directories(application PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_include_directories(application PRIVATE ${CMAKE_SOURCE_DIR}/src/modes/classicmode/shared)
target_include_directories(application PRIVATE ${CMAKE_SOURCE_DIR}/src/tools/shared)
target_include_directories(project-kyoku PRIVATE ${CMAKE_SOURCE_DIR}/src/application/shared)

View File

@ -1,39 +0,0 @@
#pragma once
#include "application/state.h"
#include "core/corefactory.h"
#include "core/functional.h"
class Group;
class PushButton;
namespace kku { class Sprite; class Text; }
class About : public GUIState
{
public:
struct Callbacks
{
kku::lambda onLeaveAboutState;
};
explicit About(const std::shared_ptr<kku::CoreFactory>& factory, Callbacks&& callbacks);
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void enter() override;
virtual void leave() override;
private:
const Callbacks _callbacks;
const std::shared_ptr<kku::CoreFactory> _core_factory;
const std::shared_ptr<kku::Sprite> _sfml_logo;
const std::shared_ptr<kku::Sprite> _cryptopp_logo;
const std::shared_ptr<kku::Text> _powered_by_text;
std::shared_ptr<Group> _buttons;
std::shared_ptr<PushButton> _exit_button;
};

View File

@ -1,41 +0,0 @@
#pragma once
#include "application/state.h"
#include "core/corefactory.h"
#include "core/music.h"
#include "core/functional.h"
class BPMCalculator;
class Group;
namespace kku { class Editor; }
class EditorState : public GUIState
{
public:
struct Callbacks
{
kku::lambda onLeaveEditorState;
};
explicit EditorState(const std::shared_ptr<kku::CoreFactory>& core_factory, std::unique_ptr<kku::Editor>&& editor, Callbacks&& callbacks);
virtual ~EditorState() override;
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void enter() override;
virtual void leave() override;
private:
const Callbacks _callbacks;
const std::shared_ptr<kku::CoreFactory> _core_factory;
std::shared_ptr<kku::Music> _music;
std::shared_ptr<BPMCalculator> _bpm_calculator;
std::shared_ptr<Group> _group;
std::unique_ptr<kku::Editor> _editor;
};

View File

@ -1,38 +0,0 @@
#pragma once
#include "state.h"
#include "core/music.h"
#include "core/game.h"
#include "core/corefactory.h"
#include "core/functional.h"
class Group;
class GameState : public GUIState
{
public:
struct Callbacks
{
kku::lambda onLeaveGame;
};
explicit GameState(const std::shared_ptr<kku::CoreFactory>& core_factory, const std::shared_ptr<kku::Game>& game, Callbacks&& callbacks);
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void enter() override;
virtual void leave() override;
private:
const std::shared_ptr<kku::CoreFactory> _core_factory;
std::shared_ptr<kku::Music> _music;
std::shared_ptr<kku::Game> _game;
kku::lambda _onEnterGameCallback;
kku::lambda _onLeaveGameCallback;
};

View File

@ -1,34 +0,0 @@
#pragma once
#include "application/state.h"
#include "core/corefactory.h"
#include "core/functional.h"
class Group;
class MainMenu : public GUIState
{
public:
struct Callbacks
{
kku::lambda onAppendGameState;
kku::lambda onAppendEditorState;
kku::lambda onAppendAboutState;
};
explicit MainMenu(const std::shared_ptr<kku::CoreFactory>& factory, Callbacks&& callbacks);
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void enter() override;
virtual void leave() override;
private:
const Callbacks _callbacks;
const std::shared_ptr<kku::CoreFactory> _core_factory;
std::shared_ptr<Group> _buttons;
};

View File

@ -1,35 +0,0 @@
#pragma once
#include <stack>
#include <memory>
#include "core/systemevent.h"
#include "core/vector.h"
#include "core/time.h"
class GUIState
{
public:
enum Tag {
SPLASH_SCREEN,
MAIN_MENU,
GAME_PICKER,
GAME,
EDITOR_PICKER,
EDITOR,
SETTINGS,
ABOUT,
AMOUNT
};
virtual ~GUIState() = default;
virtual void input(const kku::SystemEvent& event) = 0;
virtual void update(const kku::microsec& dt) = 0;
virtual void display() const = 0;
virtual void enter() = 0;
virtual void leave() = 0;
};

View File

@ -1,29 +0,0 @@
#pragma once
#include <vector>
#include <memory>
#include <array>
#include "../../include/application/state.h" // HOW? WHY DOESN'T "application/state.h" LINK ON BY ITSELF
#include "core/corefactory.h"
class Application
{
public:
virtual ~Application() = default;
virtual bool init();
virtual void display() = 0;
virtual void run() = 0;
void input(const kku::SystemEvent& input);
void update(const kku::microsec& dt);
protected:
std::shared_ptr<kku::CoreFactory> _core_factory;
std::array<std::shared_ptr<GUIState>, GUIState::Tag::AMOUNT> _states;
std::vector<std::shared_ptr<GUIState>> _state_stack;
void pushState(GUIState::Tag new_state);
void popState();
};

View File

@ -1,59 +0,0 @@
#include "application/about.h"
#include "widgets/pushbutton.h"
#include "widgets/group.h"
About::About(const std::shared_ptr<kku::CoreFactory>& factory, About::Callbacks&& callbacks) :
_callbacks(std::move(callbacks)),
_core_factory(factory),
_sfml_logo(factory->getSprite(kku::GUISprite::Id::SFML_LOGO)),
_cryptopp_logo(factory->getSprite(kku::GUISprite::Id::CRYPTOPP_LOGO)),
_powered_by_text(factory->getText(kku::Font::Id::GUI)),
_buttons(std::make_shared<Group>())
{
_powered_by_text->setString("Powered by: ");
_powered_by_text->move(kku::Vector2<float>{0., 60});
_sfml_logo->move(kku::Vector2<float>{230., 60});
_cryptopp_logo->move(kku::Vector2<float>{250., 180});
}
void About::input(const kku::SystemEvent& event)
{
_buttons->input(event);
}
void About::update(const kku::microsec& dt)
{
_buttons->update(dt);
}
void About::display() const
{
_buttons->display();
_sfml_logo->display();
_cryptopp_logo->display();
_powered_by_text->display();
}
void About::enter()
{
const auto render_size = _core_factory->getRenderSize();
const float window_width = render_size.first;
const float window_height = render_size.second;
if (!_exit_button)
{
_exit_button = std::make_shared<PushButton>("Return", _core_factory, 48);
_exit_button->setCallback(_callbacks.onLeaveAboutState);
_buttons->addChild(_exit_button);
}
_exit_button->setRect(kku::Area<float>{window_width / 3.f, window_height / 7.f * 4,
window_width / 3.f, window_height / 7.f});
_buttons->setVisibility();
}
void About::leave()
{
_buttons->setVisibility(false);
}

View File

@ -1,66 +0,0 @@
#include "application/application.h"
#include "core/gameevent.h"
#include "core/editor.h"
#include "application/mainmenu.h"
#include "application/gamestate.h"
#include "application/editorstate.h"
#include "application/about.h"
#include "classicmode/classicfactory.h"
bool Application::init()
{
if (!_core_factory)
return false;
MainMenu::Callbacks callbacks =
{
[&](){ pushState(GUIState::Tag::GAME); },
[&](){ pushState(GUIState::Tag::EDITOR); },
[&](){ pushState(GUIState::Tag::ABOUT); },
};
EditorState::Callbacks editor_callbacks = {[&](){ popState(); }};
About::Callbacks about_callbacks = {[&](){ popState(); }};
const auto main_menu = std::make_shared<MainMenu>(_core_factory, std::move(callbacks));
const auto game_state = std::make_shared<GameState>(_core_factory, classic::getGame(_core_factory), GameState::Callbacks());
const auto editor = std::make_shared<EditorState>(_core_factory, classic::getEditor(_core_factory), std::move(editor_callbacks));
const auto about = std::make_shared<About>(_core_factory, std::move(about_callbacks));
_states[GUIState::Tag::MAIN_MENU] = main_menu;
_states[GUIState::Tag::GAME] = game_state;
_states[GUIState::Tag::EDITOR] = editor;
_states[GUIState::Tag::ABOUT] = about;
pushState(GUIState::Tag::MAIN_MENU);
return true;
}
void Application::input(const kku::SystemEvent& event)
{
_state_stack.back()->input(event);
}
void Application::update(const kku::microsec& dt)
{
_state_stack.back()->update(dt);
}
void Application::pushState(GUIState::Tag new_state)
{
if (!_state_stack.empty())
_state_stack.back()->leave();
_state_stack.emplace_back(_states.at(new_state));
_state_stack.back()->enter();
}
void Application::popState()
{
_state_stack.back()->leave();
_state_stack.pop_back();
_state_stack.back()->enter();
}

View File

@ -1,190 +0,0 @@
#include "application/editorstate.h"
#include "widgets/button.h"
#include "widgets/group.h"
#include "widgets/menubar.h"
#include "widgets/window.h"
#include "widgets/editorwidget.h"
#include "widgets/bpmcalculatorwidget.h"
#include "tools/bpmcalculator.h"
#include "core/editor.h"
EditorState::EditorState(const std::shared_ptr<kku::CoreFactory>& core_factory,
std::unique_ptr<kku::Editor>&& editor,
Callbacks&& callbacks) :
_callbacks(std::move(callbacks)),
_core_factory(core_factory),
_editor(std::move(editor))
{}
EditorState::~EditorState()
{}
void EditorState::input(const kku::SystemEvent& event)
{
_group->input(event);
}
void EditorState::update(const kku::microsec& dt)
{
_group->update(dt);
}
void EditorState::display() const
{
_group->display();
}
void EditorState::enter()
{
_music = _core_factory->getMusic();
_music->open("sources/METEOR.flac");
_music->setVolume(5.f);
auto& group = _group;
auto& music = _music;
auto& editor = _editor;
_bpm_calculator = std::make_shared<BPMCalculator>();
auto& bpm_calculator = _bpm_calculator;
std::shared_ptr<BPMCalculatorWidget> bpm_widget = std::make_shared<BPMCalculatorWidget>(_bpm_calculator, _core_factory);
auto button_start = std::make_shared<PushButton>("Start", _core_factory);
auto button_stop = std::make_shared<PushButton>("Stop", _core_factory);
auto button_apply = std::make_shared<PushButton>("Apply", _core_factory);
button_start->setCallback([bpm_calculator, button_start, button_stop, &music]()
{
music->play();
bpm_calculator->start();
button_start->setVisibility(false);
button_stop->setVisibility(true);
});
button_stop->setCallback([bpm_calculator, button_start, button_stop, &music]()
{
music->stop();
bpm_calculator->stop();
button_start->setVisibility(true);
button_stop->setVisibility(false);
});
button_apply->setCallback([&editor, bpm_calculator]()
{
kku::BPMSection section;
const auto& info = bpm_calculator->fetchApproximatedInfo();
section.bpm = info.BPM;
section.interval = info.interval;
section.fraction = 2;
section.offset_start = bpm_calculator->getStartingOffset();
editor->insertBPMSection(std::move(section));
});
BPMCalculatorWidget::Init bpm_widget_init;
bpm_widget_init.stop = button_stop;
bpm_widget_init.apply = button_apply;
bpm_widget_init.start = button_start;
bpm_widget_init.current_time = [&music]() -> kku::microsec { return music->fetchOffset(); };
bpm_widget->init(std::move(bpm_widget_init));
const auto bpm_widget_callback = [&group, bpm_widget=bpm_widget, &music]()
{
music->stop();
bpm_widget->setVisibility(false);
group->unblock();
};
const auto render_size = _core_factory->getRenderSize();
const float window_width = render_size.first;
auto menu_bar = std::make_shared<MenuBar>(_core_factory);
auto bpm_button = std::make_shared<PushButton>("Calculate BPM", _core_factory);
bpm_button->setCallback([&group, bpm_widget=bpm_widget]()
{
group->blockBy(bpm_widget);
bpm_widget->setVisibility(true);
});
bpm_widget->setRect(kku::Area<float>{render_size.first / 3.f, render_size.second / 3.f,
render_size.first / 3.f, render_size.second / 3.f});
bpm_widget->addBarButton("X", bpm_widget_callback);
bpm_widget->setVisibility(false);
auto test_menu_2 = std::make_shared<MenuDrop>(_core_factory);
test_menu_2->setRect(kku::Area<float>{0., 0., 200., 27. * 5.});
auto test_menu_3 = std::make_shared<MenuDrop>(_core_factory);
test_menu_3->setRect(kku::Area<float>{0., 0., 200., 27. * 5.});
auto test_cascade_button = std::make_shared<CascadeMenuButton>("Show submenu", _core_factory);
auto test_cascade_button_2 = std::make_shared<CascadeMenuButton>("Show submenu 2", _core_factory);
auto quit_button = std::make_shared<PushButton>("Quit", _core_factory);
quit_button->setCallback(_callbacks.onLeaveEditorState);
auto test_menu = std::make_shared<MenuDrop>(_core_factory);
test_menu->setRect(kku::Area<float>{0., 0., 200., 27. * 3.});
menu_bar->setRect(kku::Area<float>{0., 0., window_width, 27.});
menu_bar->addRootSubMenu("test", test_menu);
menu_bar->addDependentSubmenu(test_menu_2);
menu_bar->addDependentSubmenu(test_menu_3);
test_cascade_button->setSubmenu(test_menu_2);
test_menu->addPushButton(bpm_button);
test_menu->addCascadeButton(test_cascade_button);
test_menu->addPushButton(quit_button);
test_cascade_button->resetRect();
test_cascade_button_2->setSubmenu(test_menu_3);
test_menu_2->addCascadeButton(test_cascade_button_2);
test_cascade_button_2->resetRect();
menu_bar->setVisibility(true);
EditorWidget::Callbacks callbacks;
callbacks.onDisplay = [&editor]()
{
editor->display();
};
callbacks.onInput = [&editor, &music](const kku::SystemEvent& event)
{
if (event.type == kku::SystemEvent::Type::KeyRelease
&& std::get<kku::SystemEvent::Key>(event.data).view == kku::SystemEvent::Key::Code::Space)
music->isPlaying() ? music->pause() : music->play();
else if (event.type == kku::SystemEvent::Type::MouseWheelScroll)
{
const auto& up = std::get<kku::SystemEvent::Mouse>(event.data).scrolled_up;
music->moveOffset(up ? 500000 : -500000);
editor->recalculate(music->fetchOffset());
}
else
editor->input(kku::GameEvent{music->fetchOffset(), event});
};
callbacks.onUpdate = [&editor, &music](const kku::microsec& dt)
{
editor->update(kku::UpdateData{music->fetchOffset(), dt});
};
auto editor_widget = std::make_shared<EditorWidget>(std::move(callbacks));
_group = std::make_shared<Group>();
_group->addChild(editor_widget);
_group->addChild(menu_bar);
_group->addChild(bpm_widget);
}
void EditorState::leave()
{
_group.reset();
_bpm_calculator.reset();
}

View File

@ -1,52 +0,0 @@
#include "application/gamestate.h"
#include "widgets/button.h"
#include "widgets/group.h"
#include "core/game.h"
GameState::GameState(const std::shared_ptr<kku::CoreFactory>& core_factory, const std::shared_ptr<kku::Game>& game, Callbacks&& callbacks) :
_core_factory(core_factory),
_game(game),
_onLeaveGameCallback(callbacks.onLeaveGame)
{
_music = _core_factory->getMusic();
}
void GameState::input(const kku::SystemEvent& event)
{
switch (event.type)
{
default:
break;
case kku::SystemEvent::Type::KeyRelease:
if (std::get<kku::SystemEvent::Key>(event.data).view == kku::SystemEvent::Key::Code::Space)
_music->isPlaying() ? _music->pause() : _music->play();
}
_game->input(kku::GameEvent{_music->fetchOffset(), event});
}
void GameState::update(const kku::microsec& dt)
{
_game->update(kku::UpdateData{_music->fetchOffset(), dt});
}
void GameState::display() const
{
_game->display();
}
void GameState::enter()
{
_game->run();
_music->open("sources/METEOR.flac");
_music->setVolume(10);
_music->play();
}
void GameState::leave()
{
_onLeaveGameCallback();
}

View File

@ -1,59 +0,0 @@
#include "application/mainmenu.h"
#include "widgets/pushbutton.h"
#include "widgets/group.h"
MainMenu::MainMenu(const std::shared_ptr<kku::CoreFactory>& factory, MainMenu::Callbacks&& callbacks) :
_callbacks(std::move(callbacks)),
_core_factory(factory),
_buttons(std::make_shared<Group>())
{
}
void MainMenu::input(const kku::SystemEvent& event)
{
_buttons->input(event);
}
void MainMenu::update(const kku::microsec& dt)
{
_buttons->update(dt);
}
void MainMenu::display() const
{
_buttons->display();
}
void MainMenu::enter()
{
const auto render_size = _core_factory->getRenderSize();
const float window_width = render_size.first;
const float window_height = render_size.second;
auto button_start = std::make_shared<PushButton>("Start", _core_factory, 48);
button_start->setRect(kku::Area<float>{window_width / 3.f, window_height / 7.f,
window_width / 3.f, window_height / 7.f});
button_start->setCallback(_callbacks.onAppendGameState);
auto button_editor = std::make_shared<PushButton>("Editor", _core_factory, 48);
button_editor->setRect(kku::Area<float>{window_width / 3.f, window_height / 7.f * 3,
window_width / 3.f, window_height / 7.f});
button_editor->setCallback(_callbacks.onAppendEditorState);
auto button_about = std::make_shared<PushButton>("About", _core_factory, 48);
button_about->setRect(kku::Area<float>{window_width / 3.f, window_height / 7.f * 5,
window_width / 3.f, window_height / 7.f});
button_about->setCallback(_callbacks.onAppendAboutState);
_buttons->addChild(button_start);
_buttons->addChild(button_editor);
_buttons->addChild(button_about);
_buttons->setVisibility();
}
void MainMenu::leave()
{
_buttons->setVisibility(false);
}

View File

@ -1,140 +0,0 @@
#include "bpmcalculatorwidget.h"
#include "tools/bpmcalculator.h"
#include "core/editor.h"
#include <iostream>
BPMCalculatorWidget::BPMCalculatorWidget(const std::shared_ptr<BPMCalculator>& bpm_calculator, const std::shared_ptr<kku::CoreFactory>& factory) :
Window(factory, "BPM Calculation"),
_bpm_calculator(bpm_calculator),
_slider(std::make_shared<BPMSlider>(factory)),
_core_factory(factory),
_ticked(false)
{
_bpm_value = _core_factory->getText(kku::Font::Id::GUI);
_bpm_value->setCharacterSize(40);
_bpm_value->setColor(kku::Color{0, 0, 0, 255});
_bpm_value->setString("--");
/*_slap_buffer.loadFromFile("Tick.ogg");
_slap.setBuffer(_slap_buffer);
_slap.setVolume(30.);*/
}
void BPMCalculatorWidget::input(const kku::SystemEvent& event)
{
switch (event.type)
{
default:
break;
case kku::SystemEvent::Type::KeyPress:
{
if (std::get<kku::SystemEvent::Key>(event.data).view == kku::SystemEvent::Key::Code::Space)
{
_bpm_calculator->click(_current_time());
}
break;
}
}
Window::input(event);
}
void BPMCalculatorWidget::update(const kku::microsec& dt)
{
Window::update(dt);
const auto beat_info = _bpm_calculator->fetchApproximatedInfo();
if (beat_info.BPM != 0)
{
_bpm_value->setString(std::to_string(static_cast<int>(beat_info.BPM)));
const kku::microsec until_beat = _bpm_calculator->fetchTimeUntilNextBeat(_current_time());
const auto time_relation = static_cast<long double>(beat_info.interval) / static_cast<long double>(until_beat);
const auto slider_path_left = _slider->getRect().width / time_relation;
if (slider_path_left < 50)
{
//if (!_ticked)
//_slap.play();
_ticked = true;
}
else
_ticked = false;
_slider->setTickPosition(slider_path_left);
}
}
void BPMCalculatorWidget::display() const
{
Window::display();
if (_is_visible)
{
_slider->display();
_button_start->display();
_button_stop->display();
_button_apply->display();
_bpm_value->display();
}
}
void BPMCalculatorWidget::setRect(const kku::Area<float>& rect)
{
Window::setRect(rect);
_slider->setRect(kku::Area<float>{0, 0, rect.width / 8 * 6, 100});
_slider->setPosition(kku::Point{_window_content->getRect().left + rect.width / 8,
_window_content->getRect().top + rect.height / 8 * 3});
_button_start->setRect(kku::Area<float>{0, 0, rect.width / 10 * 3, 30});
_button_start->setPosition(kku::Point{_window_content->getRect().left + rect.width / 7,
_window_content->getRect().top + _window_content->getRect().height - 40});
_button_stop->setRect(kku::Area<float>{0, 0, rect.width / 10 * 3, 30});
_button_stop->setPosition(kku::Point{_window_content->getRect().left + rect.width / 7,
_window_content->getRect().top + _window_content->getRect().height - 40});
_button_apply->setRect(kku::Area<float>{0, 0, rect.width / 10 * 3, 30});
_button_apply->setPosition(kku::Point{_window_content->getRect().left + 50 + (2 * (rect.width / 7)),
_window_content->getRect().top + _window_content->getRect().height - 40});
_bpm_value->setPosition(kku::Point{_window_content->getRect().left + rect.width / 8,
_window_content->getRect().top + rect.height / 8 });
}
void BPMCalculatorWidget::move(const kku::Vector2<float>& delta)
{
Window::move(delta);
_slider->move(delta);
_bpm_value->move(delta);
}
void BPMCalculatorWidget::setPosition(const kku::Point& position)
{
Window::setPosition(position);
}
void BPMCalculatorWidget::init(Init &&init)
{
_button_start = init.start;
_button_stop = init.stop;
_button_apply = init.apply;
_current_time = init.current_time;
addChild(_button_start);
addChild(_button_stop);
addChild(_button_apply);
_button_stop->setVisibility(false);
}
void BPMCalculatorWidget::setVisibility(bool is_visible)
{
Window::setVisibility(is_visible);
bool can_stop = _bpm_calculator->calculating();
_button_stop->setVisibility(can_stop && is_visible);
_button_start->setVisibility(!can_stop && is_visible);
}

View File

@ -1,54 +0,0 @@
#pragma once
#include "core/time.h"
#include "core/text.h"
#include "window.h"
#include "bpmslider.h"
#include "pushbutton.h"
#include <functional>
class BPMCalculator;
class Editor;
class BPMCalculatorWidget : public Window
{
public:
struct Init
{
std::shared_ptr<PushButton> start;
std::shared_ptr<PushButton> stop;
std::shared_ptr<PushButton> apply;
std::function<kku::microsec(void)> current_time;
};
explicit BPMCalculatorWidget(const std::shared_ptr<BPMCalculator>& bpm_calculator, const std::shared_ptr<kku::CoreFactory>& factory);
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual void setRect(const kku::Area<float>& rect) override;
virtual void setPosition(const kku::Point& position) override;
virtual void setVisibility(bool is_visible = true) override;
void init(Init&& init);
private:
std::shared_ptr<PushButton> _button_start;
std::shared_ptr<PushButton> _button_stop;
std::shared_ptr<PushButton> _button_apply;
std::shared_ptr<BPMCalculator> _bpm_calculator;
std::shared_ptr<BPMSlider> _slider;
const std::shared_ptr<kku::CoreFactory> _core_factory;
bool _ticked;
std::shared_ptr<kku::Text> _bpm_value;
std::function<kku::microsec(void)> _current_time;
};

View File

@ -1,69 +0,0 @@
#include "bpmslider.h"
BPMSlider::BPMSlider(const std::shared_ptr<kku::CoreFactory> &factory)
{
_slider_background = factory->getRectangle();
_slider_tick = factory->getRectangle();
_slider_background->setColor(kku::Color{0, 0, 0, 255});
_slider_tick->setColor(kku::Color{255, 0, 0, 255});
}
void BPMSlider::input(const kku::SystemEvent& event)
{
Widget::input(event);
}
void BPMSlider::update(const kku::microsec& dt)
{
Widget::update(dt);
}
void BPMSlider::display() const
{
_slider_background->display();
_slider_tick->display();
Widget::display();
}
void BPMSlider::setRect(const kku::Area<float>& rect)
{
_slider_background->setRect(rect);
_slider_tick->setRect(kku::Area<float>{rect.left,
rect.top,
rect.width / 30.f,
rect.height});
}
void BPMSlider::setPosition(const kku::Point& position)
{
_slider_background->setPosition(position);
_slider_tick->setPosition(position);
}
void BPMSlider::move(const kku::Vector2<float>& delta)
{
_slider_background->move(delta);
_slider_tick->move(delta);
}
bool BPMSlider::isUnderMouse(const kku::Point& position) const
{
return _slider_background->contains(position);
}
kku::Area<float> BPMSlider::getRect() const
{
return _slider_background->getRect();
}
kku::Point BPMSlider::getPosition() const
{
return _slider_background->getPosition();
}
void BPMSlider::setTickPosition(float x_position)
{
_slider_tick->setPosition(kku::Point{_slider_background->getPosition().x + x_position,
_slider_tick->getPosition().y});
}

View File

@ -1,31 +0,0 @@
#pragma once
#include "widget.h"
#include "core/rectangle.h"
#include "core/corefactory.h"
class BPMSlider : public Widget
{
public:
explicit BPMSlider(const std::shared_ptr<kku::CoreFactory>& factory);
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual bool isUnderMouse(const kku::Point& position) const override;
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
void setTickPosition(float x_position);
private:
std::shared_ptr<kku::Rectangle> _slider_background;
std::shared_ptr<kku::Rectangle> _slider_tick;
};

View File

@ -1,70 +0,0 @@
#include "button.h"
#include <iostream>
Button::Button(const std::string &text, const std::shared_ptr<kku::CoreFactory>& factory, unsigned int font_size) :
_core_factory(factory)
{
_button_text = _core_factory->getText(kku::Font::Id::GUI);
_button_text->setString(text);
_button_text->setColor(kku::Color{0, 0, 0, 255});
_button_text->setCharacterSize(font_size);
}
void Button::update(const kku::microsec& dt)
{
Widget::update(dt);
}
void Button::display() const
{
if (_is_visible)
{
_button_content->display();
_button_text->display();
}
Widget::display();
}
void Button::setRect(const kku::Area<float>& rect)
{
_button_content->setRect(rect);
_button_text->setPosition(kku::Point{rect.left + 5,
rect.top + 5});
}
void Button::setPosition(const kku::Point& position)
{
_button_content->setPosition(position);
auto new_point = position;
new_point.moveBy(5.f, 5.f);
_button_text->setPosition(new_point);
}
void Button::move(const kku::Vector2<float>& delta)
{
_button_content->move(delta);
_button_text->move(delta);
Widget::move(delta);
}
bool Button::isUnderMouse(const kku::Point& position) const
{
return _is_visible && _button_content->contains(position);
}
void Button::setText(const std::string& text)
{
_button_text->setString(text);
}
kku::Area<float> Button::getRect() const
{
return _button_content->getRect();
}
kku::Point Button::getPosition() const
{
return _button_content->getPosition();
}

View File

@ -1,31 +0,0 @@
#pragma once
#include "widget.h"
#include "core/corefactory.h"
class Button : public Widget
{
public:
explicit Button(const std::string& text, const std::shared_ptr<kku::CoreFactory>& factory, unsigned int font_size);
virtual void input(const kku::SystemEvent& event) override = 0;
virtual void update(const kku::microsec& dt) override final;
virtual void display() const override final;
virtual void move(const kku::Vector2<float>& delta) override final;
virtual bool isUnderMouse(const kku::Point& position) const override final;
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
virtual void setText(const std::string& text);
protected:
std::shared_ptr<kku::Rectangle> _button_content;
std::shared_ptr<kku::Text> _button_text;
const std::shared_ptr<kku::CoreFactory> _core_factory;
};

View File

@ -1,77 +0,0 @@
#include "cascademenubutton.h"
#include "menudrop.h"
CascadeMenuButton::CascadeMenuButton(const std::string& text, const std::shared_ptr<kku::CoreFactory>& factory, unsigned int font_size) :
Button(text, factory, font_size)
{
_color_idle = kku::Color{230, 230, 230, 255};
_color_hover = kku::Color{84, 158, 253, 255};
_button_content = factory->getRectangle();
_button_content->setColor(_color_idle);
}
void CascadeMenuButton::input(const kku::SystemEvent& event)
{
if (!_submenu)
return;
switch (event.type)
{
default:
break;
case kku::SystemEvent::Type::MouseMove:
{
const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
if (isUnderMouse(position))
{
_button_content->setColor(_color_hover);
_submenu->lock();
_submenu->setVisibility(true);
}
else
{
_submenu->unlock();
if (!_submenu->isVisible())
{
_button_content->setColor(_color_idle);
}
}
break;
}
}
}
void CascadeMenuButton::setRect(const kku::Area<float>& rect)
{
Button::setRect(rect);
resetRect();
}
void CascadeMenuButton::setSubmenu(const std::shared_ptr<MenuDrop>& submenu)
{
_submenu = submenu;
resetRect();
}
const std::shared_ptr<MenuDrop> CascadeMenuButton::submenu() const
{
return _submenu;
}
void CascadeMenuButton::resetRect()
{
if (_submenu)
{
_submenu->setPosition(kku::Point{_button_content->getPosition().x + _button_content->getRect().width,
_button_content->getPosition().y});
}
}
void CascadeMenuButton::setFillColors(kku::Color&& idle_color, kku::Color&& hover_color)
{
_color_idle = idle_color;
_color_hover = hover_color;
}

View File

@ -1,25 +0,0 @@
#pragma once
#include "button.h"
class MenuDrop;
class CascadeMenuButton : public Button
{
public:
explicit CascadeMenuButton(const std::string& text, const std::shared_ptr<kku::CoreFactory>& factory, unsigned int font_size = 12);
virtual void input(const kku::SystemEvent& event) override final;
virtual void setRect(const kku::Area<float>& rect) override final;
void setSubmenu(const std::shared_ptr<MenuDrop>& submenu);
const std::shared_ptr<MenuDrop> submenu() const;
void resetRect();
void setFillColors(kku::Color&& idle_color, kku::Color&& hover_color);
private:
std::shared_ptr<MenuDrop> _submenu;
kku::Color _color_idle;
kku::Color _color_hover;
};

View File

@ -1,55 +0,0 @@
#include "editorwidget.h"
#include "core/editor.h"
EditorWidget::EditorWidget(Callbacks&& callbacks) :
_input(std::move(callbacks.onInput)),
_update(std::move(callbacks.onUpdate)),
_draw(std::move(callbacks.onDisplay))
{}
void EditorWidget::input(const kku::SystemEvent& event)
{
_input(event);
}
void EditorWidget::update(const kku::microsec& dt)
{
_update(dt);
}
void EditorWidget::display() const
{
_draw();
}
void EditorWidget::move(const kku::Vector2<float>& delta)
{
(void)delta;
// delegate to children
}
bool EditorWidget::isUnderMouse(const kku::Point& position) const
{
return _parent->isUnderMouse(position);
}
void EditorWidget::setRect(const kku::Area<float>& rect)
{
(void)rect;
// basically useless beacuse editor widget fills the entire screen
}
kku::Area<float> EditorWidget::getRect() const
{
return {};
}
void EditorWidget::setPosition(const kku::Point& position)
{
(void)position;
}
kku::Point EditorWidget::getPosition() const
{
return kku::Point{};
}

View File

@ -1,36 +0,0 @@
#pragma once
#include "widget.h"
#include <functional>
class EditorWidget : public Widget
{
public:
struct Callbacks
{
std::function<void(const kku::SystemEvent& event)> onInput;
std::function<void(const kku::microsec& dt)> onUpdate;
std::function<void(void)> onDisplay;
};
explicit EditorWidget(Callbacks&& callbacks);
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual bool isUnderMouse(const kku::Point& position) const override;
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
private:
std::function<void(const kku::SystemEvent& event)> _input;
std::function<void(const kku::microsec& dt)> _update;
std::function<void(void)> _draw;
};

View File

@ -1,55 +0,0 @@
#include "group.h"
void Group::input(const kku::SystemEvent& event)
{
Widget::input(event);
}
void Group::update(const kku::microsec& dt)
{
Widget::update(dt);
}
void Group::display() const
{
Widget::display();
}
void Group::setRect(const kku::Area<float>& rect)
{
_rect = rect;
}
void Group::setPosition(const kku::Point& position)
{
_rect.top = position.y;
_rect.left = position.x;
}
void Group::move(const kku::Vector2<float>& delta)
{
_rect.top += delta.first;
_rect.left += delta.second;
Widget::move(delta);
}
bool Group::isUnderMouse(const kku::Point& position) const
{
return _rect.contains(position);
}
kku::Area<float> Group::getRect() const
{
return _rect;
}
kku::Point Group::getPosition() const
{
return kku::Point
{
_rect.top,
_rect.left
};
}

View File

@ -1,23 +0,0 @@
#pragma once
#include "widget.h"
class Group : public Widget
{
public:
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual bool isUnderMouse(const kku::Point& position) const override;
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
private:
kku::Area<float> _rect;
};

View File

@ -1,131 +0,0 @@
#include "menubar.h"
MenuBar::MenuBar(const std::shared_ptr<kku::CoreFactory>& factory) :
_core_factory(factory),
_bar_rect(factory->getRectangle()),
_amount_buttons(0),
_button_width(170)
{
_bar_rect->setColor(kku::Color{88, 57, 107, 255});
}
void MenuBar::input(const kku::SystemEvent &event)
{
switch (event.type)
{
default:
break;
case kku::SystemEvent::Type::MouseRelease:
{
const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
if (!isUnderMouse(position))
{
for (auto& submenu : _submenus)
submenu->unlock();
}
break;
}
}
Widget::input(event);
}
void MenuBar::update(const kku::microsec& dt)
{
Widget::update(dt);
}
void MenuBar::display() const
{
if (_is_visible)
_bar_rect->display();
Widget::display();
}
void MenuBar::setRect(const kku::Area<float>& rect)
{
_bar_rect->setRect(rect);
// Buttons will not resize
}
void MenuBar::setPosition(const kku::Point& position)
{
_bar_rect->setPosition(position);
}
void MenuBar::move(const kku::Vector2<float>& delta)
{
_bar_rect->move(delta);
Widget::move(delta);
for (auto& menu : _submenus)
menu->move(delta);
}
bool MenuBar::isUnderMouse(const kku::Point& position) const
{
bool bar_under_mouse = _bar_rect->contains(position);
bool submenus_under_mouse = std::any_of(_children.begin(), _children.end(),
[p=position](const auto& child)
{
return child->isUnderMouse(p);
});
return bar_under_mouse || submenus_under_mouse;
}
void MenuBar::addRootSubMenu(std::string name, const std::shared_ptr<MenuDrop>& submenu)
{
const auto new_button = std::make_shared<PushButton>(name, _core_factory);
std::size_t current_index = _amount_buttons;
new_button->setRect(kku::Area<float>{static_cast<float>(current_index * _button_width),
0.f,
static_cast<float>(_button_width),
_bar_rect->getRect().height});
new_button->setCallback([submenu=submenu]()
{
submenu->setVisibility(true);
submenu->lock();
});
submenu->setPosition(kku::Point{static_cast<float>(current_index * _button_width),
_bar_rect->getRect().height});
new_button->setColors(kku::Color{171, 141, 189, 255},
kku::Color{48, 27, 57, 255});
addChild(new_button);
addChild(submenu);
_submenus.emplace_back(submenu);
++_amount_buttons;
}
void MenuBar::addDependentSubmenu(const std::shared_ptr<MenuDrop> &submenu)
{
_submenus.emplace_back(submenu);
}
void MenuBar::setVisibility(bool is_visible)
{
Widget::setVisibility(is_visible);
for (auto& submenu : _submenus)
submenu->setVisibility(false);
}
kku::Area<float> MenuBar::getRect() const
{
return _bar_rect->getRect();
}
kku::Point MenuBar::getPosition() const
{
return _bar_rect->getPosition();
}

View File

@ -1,35 +0,0 @@
#pragma once
#include "widget.h"
#include "menudrop.h"
#include "button.h"
class MenuBar : public Widget
{
public:
explicit MenuBar(const std::shared_ptr<kku::CoreFactory>& factory);
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual bool isUnderMouse(const kku::Point& position) const override;
virtual void setVisibility(bool is_visible = true) override;
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
void addRootSubMenu(std::string name, const std::shared_ptr<MenuDrop>& submenu);
void addDependentSubmenu(const std::shared_ptr<MenuDrop>& submenu);
private:
const std::shared_ptr<kku::CoreFactory> _core_factory;
const std::shared_ptr<kku::Rectangle> _bar_rect;
std::size_t _amount_buttons;
std::size_t _button_width;
std::vector<std::shared_ptr<MenuDrop>> _submenus;
};

View File

@ -1,164 +0,0 @@
#include "menudrop.h"
#include "core/corefactory.h"
MenuDrop::MenuDrop(const std::shared_ptr<kku::CoreFactory>& factory) :
_is_locked(false),
_button_height(27),
_button_index(0)
{
_is_visible = false;
_content_rect = factory->getRectangle();
_content_rect->setColor(kku::Color{200, 200, 200, 255});
}
void MenuDrop::input(const kku::SystemEvent& event)
{
if (!_is_visible)
return;
Widget::input(event);
switch (event.type)
{
default:
break;
case kku::SystemEvent::Type::MouseRelease:
{
const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
if (isUnderMouse(position))
{
setVisibility(false);
for (auto& submenu : _submenus)
{
submenu->unlock();
submenu->setVisibility(false);
}
}
break;
}
case kku::SystemEvent::Type::MouseMove:
{
const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
if (!isUnderMouse(position))
{
if (!isLocked() && !hasActiveSubmenus())
setVisibility(false);
}
break;
}
}
}
bool MenuDrop::hasActiveSubmenus() const
{
return std::any_of(_submenus.begin(), _submenus.end(),
[](const auto& submenu) -> bool
{
return submenu->_is_visible;
});
}
void MenuDrop::update(const kku::microsec& dt)
{
Widget::update(dt);
}
void MenuDrop::display() const
{
if (_is_visible)
_content_rect->display();
Widget::display();
}
void MenuDrop::setRect(const kku::Area<float>& rect)
{
_content_rect->setRect(rect);
}
void MenuDrop::setPosition(const kku::Point& position)
{
_content_rect->setPosition(position);
}
void MenuDrop::move(const kku::Vector2<float>& delta)
{
_content_rect->move(delta);
Widget::move(delta);
for (auto& submenu : _submenus)
submenu->move(delta);
}
bool MenuDrop::isUnderMouse(const kku::Point& position) const
{
return _is_visible && _content_rect->contains(position);
}
void MenuDrop::setVisibility(bool is_visible)
{
Widget::setVisibility(is_visible);
if (!is_visible)
_is_locked = false;
}
void MenuDrop::addPushButton(const std::shared_ptr<PushButton>& button)
{
add(button);
}
void MenuDrop::addCascadeButton(const std::shared_ptr<CascadeMenuButton>& button)
{
auto& submenu = button->submenu();
_submenus.emplace_back(submenu);
add(button);
submenu->setParent(_parent);
}
void MenuDrop::addSeparator(const std::shared_ptr<MenuSeparator>& separator)
{
add(separator);
}
void MenuDrop::add(const std::shared_ptr<Widget> &widget)
{
const auto& parent_rect = _content_rect->getRect();
widget->setRect(kku::Area<float>{parent_rect.left,
parent_rect.top + (parent_rect.height * _button_index),
parent_rect.width,
static_cast<float>(_button_height)});
addChild(widget);
++_button_index;
}
void MenuDrop::lock()
{
_is_locked = true;
}
void MenuDrop::unlock()
{
_is_locked = false;
}
bool MenuDrop::isLocked() const
{
return _is_locked;
}
kku::Area<float> MenuDrop::getRect() const
{
return _content_rect->getRect();
}
kku::Point MenuDrop::getPosition() const
{
return _content_rect->getPosition();
}

View File

@ -1,46 +0,0 @@
#pragma once
#include "widget.h"
#include "pushbutton.h"
#include "cascademenubutton.h"
#include "menuseparator.h"
#include "core/rectangle.h"
class MenuDrop : public Widget
{
public:
explicit MenuDrop(const std::shared_ptr<kku::CoreFactory>& factory);
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual bool isUnderMouse(const kku::Point& position) const override;
virtual void setVisibility(bool is_visible = true) override;
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
void addPushButton(const std::shared_ptr<PushButton>& button);
void addCascadeButton(const std::shared_ptr<CascadeMenuButton>& button);
void addSeparator(const std::shared_ptr<MenuSeparator>& separator);
void lock();
void unlock();
bool isLocked() const;
private:
std::shared_ptr<kku::Rectangle> _content_rect;
bool _is_locked;
std::size_t _button_height;
std::size_t _button_index;
std::vector<std::shared_ptr<MenuDrop>> _submenus;
void add(const std::shared_ptr<Widget>& widget);
bool hasActiveSubmenus() const;
};

View File

@ -1,48 +0,0 @@
#include "menuseparator.h"
void MenuSeparator::input(const kku::SystemEvent& event)
{
Widget::input(event);
}
void MenuSeparator::update(const kku::microsec& dt)
{
Widget::update(dt);
}
void MenuSeparator::display() const
{
_line->display();
}
void MenuSeparator::setRect(const kku::Area<float>& rect)
{
_rect = rect;
//_line
}
void MenuSeparator::setPosition(const kku::Point& position)
{
(void)position;
}
void MenuSeparator::move(const kku::Vector2<float>& delta)
{
(void)delta;
}
bool MenuSeparator::isUnderMouse(const kku::Point& position) const
{
return _is_visible && _rect.contains(position);
}
kku::Area<float> MenuSeparator::getRect() const
{
return {};
}
kku::Point MenuSeparator::getPosition() const
{
return kku::Point{};
}

View File

@ -1,25 +0,0 @@
#pragma once
#include "widget.h"
#include "core/line.h"
class MenuSeparator : public Widget
{
public:
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual bool isUnderMouse(const kku::Point& position) const override;
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
private:
std::shared_ptr<kku::Line> _line;
kku::Area<float> _rect;
};

View File

@ -1,57 +0,0 @@
#include "pushbutton.h"
PushButton::PushButton(const std::string& text, const std::shared_ptr<kku::CoreFactory>& factory, unsigned int font_size) :
Button(text, factory, font_size),
_pressed(false)
{
_color_idle = kku::Color{230, 230, 230, 255};
_color_pressed = kku::Color{200, 200, 200, 255};
_button_content = _core_factory->getRectangle();
_button_content->setColor(_color_idle);
}
void PushButton::input(const kku::SystemEvent& event)
{
switch (event.type)
{
default:
break;
case kku::SystemEvent::Type::MousePress:
{
const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
if (isUnderMouse(position))
{
_pressed = true;
_button_content->setColor(_color_pressed);
}
break;
}
case kku::SystemEvent::Type::MouseRelease:
{
if (_pressed)
{
const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
_button_content->setColor(_color_idle);
_pressed = false;
if (isUnderMouse(position))
_on_click_callback();
}
break;
}
}
}
void PushButton::setCallback(kku::lambda callback)
{
_on_click_callback = callback;
}
void PushButton::setColors(kku::Color&& idle_color, kku::Color&& pressed_color)
{
_color_idle = idle_color;
_color_pressed = pressed_color;
_button_content->setColor(_pressed ? pressed_color : idle_color);
}

View File

@ -1,22 +0,0 @@
#pragma once
#include "button.h"
#include "core/functional.h"
class PushButton : public Button
{
public:
explicit PushButton(const std::string& text, const std::shared_ptr<kku::CoreFactory>& factory, unsigned int font_size = 12);
virtual void input(const kku::SystemEvent& event) override final;
void setCallback(kku::lambda callback);
void setColors(kku::Color&& idle_color, kku::Color&& pressed_color);
private:
kku::Color _color_idle;
kku::Color _color_pressed;
bool _pressed;
kku::lambda _on_click_callback;
};

View File

@ -1,71 +0,0 @@
#include "widget.h"
#include <algorithm>
void Widget::input(const kku::SystemEvent &event)
{
if (_blocker)
_blocker->input(event);
else
{
for (auto& child : _children)
child->input(event);
}
}
void Widget::update(const kku::microsec& dt)
{
for (auto& child : _children)
child->update(dt);
}
void Widget::display() const
{
for (const auto& child : _children)
child->display();
}
void Widget::move(const kku::Vector2<float>& delta)
{
for (auto& child : _children)
child->move(delta);
}
void Widget::setVisibility(bool is_visible)
{
_is_visible = is_visible;
for (auto& child : _children)
child->setVisibility(_is_visible);
}
bool Widget::isVisible() const
{
return _is_visible;
}
void Widget::addChild(const std::shared_ptr<Widget>& child)
{
child->setParent(shared_from_this());
const auto iterator = std::find(_children.begin(), _children.end(), child);
if (iterator == _children.end())
_children.emplace_back(child);
}
void Widget::setParent(const std::shared_ptr<Widget>& parent)
{
if (_parent != parent)
{
_parent = parent;
_parent->addChild(shared_from_this());
}
}
void Widget::blockBy(const std::shared_ptr<Widget>& blocker)
{
_blocker = blocker;
}
void Widget::unblock()
{
_blocker = nullptr;
}

View File

@ -1,42 +0,0 @@
#pragma once
#include <vector>
#include <memory>
#include "core/systemevent.h"
#include "core/rectangle.h"
#include "core/time.h"
class Widget : public std::enable_shared_from_this<Widget>
{
public:
virtual ~Widget() = default;
virtual void input(const kku::SystemEvent& event) = 0;
virtual void update(const kku::microsec& dt) = 0;
virtual void display() const = 0;
virtual void move(const kku::Vector2<float>& delta) = 0;
virtual bool isUnderMouse(const kku::Point& position) const = 0;
virtual void setRect(const kku::Area<float>& rect) = 0;
virtual kku::Area<float> getRect() const = 0;
virtual void setPosition(const kku::Point& position) = 0;
virtual kku::Point getPosition() const = 0;
virtual void setVisibility(bool is_visible = true);
bool isVisible() const;
void addChild(const std::shared_ptr<Widget>& child);
void setParent(const std::shared_ptr<Widget>& parent);
void blockBy(const std::shared_ptr<Widget>& blocker);
void unblock();
protected:
std::vector<std::shared_ptr<Widget>> _children;
std::shared_ptr<Widget> _parent;
std::shared_ptr<Widget> _blocker;
bool _is_visible = true;
};

View File

@ -1,131 +0,0 @@
#include "window.h"
Window::Window(const std::shared_ptr<kku::CoreFactory>& factory, const std::string& title) :
_core_factory(factory),
_is_dragging(false)
{
_bar_title = _core_factory->getText(kku::Font::Id::GUI);
_bar_title->setString(title);
_bar_title->setCharacterSize(12);
_bar_title->setColor(kku::Color{188, 157, 207, 255});
_bar = _core_factory->getRectangle();
_bar->setColor(kku::Color{88, 57, 107, 255});
_window_content = _core_factory->getRectangle();
_window_content->setColor(kku::Color{188, 157, 207, 255});
}
void Window::input(const kku::SystemEvent& event)
{
Widget::input(event);
switch (event.type)
{
default:
break;
case kku::SystemEvent::Type::MousePress:
{
const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
if (_bar->contains(position))
{
_is_dragging = true;
_previous_click_position = position;
}
break;
}
case kku::SystemEvent::Type::MouseRelease:
_is_dragging = false;
break;
case kku::SystemEvent::Type::MouseMove:
{
const auto position = std::get<kku::SystemEvent::Mouse>(event.data).position;
if (_is_dragging)
{
float x_mouse_diff = position.x - _previous_click_position.x;
float y_mouse_diff = position.y - _previous_click_position.y;
_previous_click_position = position;
move(kku::Vector2<float>{x_mouse_diff, y_mouse_diff});
}
break;
}
}
}
void Window::update(const kku::microsec& dt)
{
Widget::update(dt);
}
void Window::display() const
{
if (_is_visible)
{
_window_content->display();
_bar->display();
_bar_title->display();
Widget::display();
}
}
void Window::setRect(const kku::Area<float>& rect)
{
_window_content->setRect(rect);
kku::Area<float> bar_rect = {rect.left, rect.top, rect.width, 30};
_bar->setRect(bar_rect);
_bar_title->setPosition(kku::Point{rect.left + 5,
rect.top + 5});
}
void Window::setPosition(const kku::Point& position)
{
_window_content->setPosition(position);
_bar->setPosition(position);
auto new_position = position;
new_position.moveBy(5.f, 5.f);
_bar_title->setPosition(new_position);
}
void Window::move(const kku::Vector2<float>& delta)
{
_window_content->move(delta);
_bar->move(delta);
_bar_title->move(delta);
Widget::move(delta);
}
bool Window::isUnderMouse(const kku::Point& position) const
{
return _is_visible && _window_content->contains(position);
}
void Window::addBarButton(const std::string &text, kku::lambda callback)
{
const auto area = _window_content->getRect();
auto b = std::make_shared<PushButton>(text, _core_factory, 20);
b->setCallback(callback);
b->setRect({area.left + area.width - 35,
area.top, 30, 30});
Widget::addChild(b);
}
kku::Area<float> Window::getRect() const
{
return _window_content->getRect();
}
kku::Point Window::getPosition() const
{
return _window_content->getPosition();
}

View File

@ -1,40 +0,0 @@
#pragma once
#include "widget.h"
#include "pushbutton.h"
#include "core/corefactory.h"
#include "core/rectangle.h"
#include "core/vector.h"
#include "core/text.h"
class Window : public Widget
{
public:
explicit Window(const std::shared_ptr<kku::CoreFactory>& factory, const std::string& title);
virtual void input(const kku::SystemEvent& event) override;
virtual void update(const kku::microsec& dt) override;
virtual void display() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual bool isUnderMouse(const kku::Point& position) const override final;
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
void addBarButton(const std::string& text, kku::lambda callback);
protected:
std::shared_ptr<kku::Rectangle> _bar;
std::shared_ptr<kku::Rectangle> _window_content;
std::shared_ptr<kku::Text> _bar_title;
const std::shared_ptr<kku::CoreFactory> _core_factory;
private:
bool _is_dragging;
kku::Point _previous_click_position;
};

View File

@ -1,22 +0,0 @@
cmake_minimum_required(VERSION 3.13)
project(impl)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/shared)
# check SFML by some compilation flag or idk
file(GLOB_RECURSE SOURCES "sfml/*.cpp" "sfml/*.h")
find_package(SFML REQUIRED graphics window system audio)
include_directories(${SFML_INCL_DIR} ${CMAKE_SOURCE_DIR}/include)
target_link_libraries(project-kyoku sfml-system sfml-audio sfml-graphics sfml-network)
######
add_library(impl STATIC ${SOURCES})
target_link_libraries(impl tools classicmode application)
target_include_directories(impl PRIVATE ${CMAKE_SOURCE_DIR}/src/modes/classicmode)
target_include_directories(impl PRIVATE ${CMAKE_SOURCE_DIR}/src/tools/shared)
target_include_directories(impl PRIVATE ${CMAKE_SOURCE_DIR}/src/application/shared)
target_include_directories(project-kyoku PRIVATE ${CMAKE_SOURCE_DIR}/src/impl/sfml)

View File

@ -1,19 +0,0 @@
SFML (Simple and Fast Multimedia Library) - Copyright (c) Laurent Gomila
This software is provided 'as-is', without any express or implied warranty.
In no event will the authors be held liable for any damages arising from
the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not claim
that you wrote the original software. If you use this software in a product,
an acknowledgment in the product documentation would be appreciated but is
not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.

View File

@ -1,62 +0,0 @@
#include "applicationsfml.h"
#include "sfml/corefactorysfml.h"
#include "sfml/application/inputconvertersfml.h"
#include <SFML/System/Clock.hpp>
const sf::Time TIME_PER_FRAME = sf::seconds(1.f / 90.f);
ApplicationSFML::ApplicationSFML(sf::RenderWindow * const render_window) :
_render_window(render_window)
{
_render_window->setFramerateLimit(60);
_render_window->setKeyRepeatEnabled(false);
_render_window->setMouseCursorGrabbed(false);
_render_window->setVerticalSyncEnabled(true);
_core_factory = std::make_shared<CoreFactorySFML>(_render_window);
}
void ApplicationSFML::display()
{
_render_window->clear();
for (const auto& state : _state_stack)
state->display();
_render_window->display();
}
void ApplicationSFML::run()
{
sf::Clock timer;
sf::Time time_since_last_update = sf::Time::Zero;
while (_render_window->isOpen())
{
time_since_last_update += timer.restart();
sf::Event event;
while (_render_window->pollEvent(event))
{
switch(event.type)
{
case sf::Event::Closed:
_render_window->close();
break;
default:
Application::input(kku::convert(event));
break;
}
}
bool isOneFramePassed = time_since_last_update >= TIME_PER_FRAME;
if (isOneFramePassed)
{
time_since_last_update -= TIME_PER_FRAME;
update(time_since_last_update.asMicroseconds());
display();
}
}
}

View File

@ -1,17 +0,0 @@
#pragma once
#include <SFML/Graphics/RenderWindow.hpp>
#include <SFML/Window/Event.hpp>
#include "application/application.h"
class ApplicationSFML : public Application
{
public:
explicit ApplicationSFML(sf::RenderWindow * const _render_window);
virtual void display() override;
virtual void run() override;
private:
sf::RenderWindow * const _render_window;
};

View File

@ -1,138 +0,0 @@
#pragma once
#include "core/systemevent.h"
#include <SFML/Window/Event.hpp>
namespace kku
{
constexpr kku::SystemEvent::Key::Code convert(sf::Keyboard::Key key) noexcept
{
return kku::SystemEvent::Key::Code{int(key)};
}
constexpr kku::SystemEvent convert(const sf::Event& event) noexcept
{
switch (event.type)
{
default:
break;
case sf::Event::Resized:
return kku::SystemEvent
{
kku::SystemEvent::Type::Resize,
kku::SystemEvent::Size
{
event.size.width,
event.size.height
}
};
case sf::Event::KeyPressed:
return kku::SystemEvent
{
kku::SystemEvent::Type::KeyPress,
kku::SystemEvent::Key
{
kku::convert(event.key.code),
event.key.alt,
event.key.control,
event.key.shift
}
};
case sf::Event::KeyReleased:
return kku::SystemEvent
{
kku::SystemEvent::Type::KeyRelease,
kku::SystemEvent::Key
{
kku::convert(event.key.code),
event.key.alt,
event.key.control,
event.key.shift
}
};
case sf::Event::MouseWheelScrolled:
return kku::SystemEvent
{
kku::SystemEvent::Type::MouseWheelScroll,
kku::SystemEvent::Mouse
{
kku::Point
{
event.mouseWheelScroll.x,
event.mouseWheelScroll.y
},
(event.mouseWheelScroll.delta > 0),
kku::SystemEvent::Mouse::Button::Wheel
}
};
case sf::Event::MouseMoved:
return kku::SystemEvent
{
kku::SystemEvent::Type::MouseMove,
kku::SystemEvent::Mouse
{
kku::Point
{
event.mouseMove.x,
event.mouseMove.y
},
false,
kku::SystemEvent::Mouse::Button::None
}
};
case sf::Event::MouseButtonPressed:
return kku::SystemEvent
{
kku::SystemEvent::Type::MousePress,
kku::SystemEvent::Mouse
{
kku::Point
{
event.mouseButton.x,
event.mouseButton.y
},
false,
((event.mouseButton.button == sf::Mouse::Button::Left)
? kku::SystemEvent::Mouse::Button::Left
: kku::SystemEvent::Mouse::Button::Right)
}
};
case sf::Event::MouseButtonReleased:
return kku::SystemEvent
{
kku::SystemEvent::Type::MouseRelease,
kku::SystemEvent::Mouse
{
kku::Point
{
event.mouseButton.x,
event.mouseButton.y
},
false,
((event.mouseButton.button == sf::Mouse::Button::Left)
? kku::SystemEvent::Mouse::Button::Left
: kku::SystemEvent::Mouse::Button::Right)
}
};
}
return kku::SystemEvent
{
kku::SystemEvent::Type::None,
kku::SystemEvent::None{}
};
}
}

View File

@ -1,66 +0,0 @@
#include "corefactorysfml.h"
#include "rectanglesfml.h"
#include "musicsfml.h"
#include "textsfml.h"
#include "linesfml.h"
#include "spritesfml.h"
CoreFactorySFML::CoreFactorySFML(sf::RenderTarget * const render_target) :
_render_target(render_target)
{
auto gui_font = std::make_unique<sf::Font>();
gui_font->loadFromFile("resources/SourceCodePro-Regular.ttf");
_font_holder.load(kku::Font::Id::GUI, std::move(gui_font));
auto menu_texture = std::make_unique<sf::Texture>();
menu_texture->loadFromFile("resources/gui-texture.png");
_texture_holder.load(kku::Texture::Id::GUI, std::move(menu_texture));
}
std::shared_ptr<kku::Music> CoreFactorySFML::getMusic() const
{
return std::make_unique<MusicSFML>();
}
std::shared_ptr<kku::Text> CoreFactorySFML::getText(kku::Font::Id id) const
{
return std::make_unique<TextSFML>(_render_target, _font_holder.get(id));
}
std::shared_ptr<kku::Rectangle> CoreFactorySFML::getRectangle() const
{
return std::make_unique<RectangleSFML>(_render_target);
}
std::shared_ptr<kku::Line> CoreFactorySFML::getLine() const
{
return std::make_unique<LineSFML>(_render_target);
}
std::shared_ptr<kku::Sprite> CoreFactorySFML::getSprite(kku::GUISprite::Id id) const
{
const auto texture = _texture_holder.get(kku::Texture::Id::GUI);
switch (id)
{
default:
return nullptr;
break;
case kku::GUISprite::Id::SFML_LOGO:
return std::make_unique<SpriteSFML>(_render_target, _texture_holder.get(kku::Texture::Id::GUI),
kku::Area<unsigned int>{0, 0, 252, 81});
break;
case kku::GUISprite::Id::CRYPTOPP_LOGO:
return std::make_unique<SpriteSFML>(_render_target, _texture_holder.get(kku::Texture::Id::GUI),
kku::Area<unsigned int>{252, 0, 135, 36});
break;
}
}
kku::Vector2<std::size_t> CoreFactorySFML::getRenderSize() const
{
const sf::Vector2u size = _render_target->getSize();
return kku::makeVector(size.x, size.y);
}

View File

@ -1,26 +0,0 @@
#pragma once
#include <SFML/Graphics/RectangleShape.hpp>
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/Font.hpp>
#include <SFML/Graphics/Sprite.hpp>
#include <SFML/Graphics/Texture.hpp>
#include "core/corefactory.h"
class CoreFactorySFML : public kku::CoreFactory
{
public:
explicit CoreFactorySFML(sf::RenderTarget * const render_target);
virtual std::shared_ptr<kku::Music> getMusic() const override;
virtual std::shared_ptr<kku::Text> getText(kku::Font::Id id) const override;
virtual std::shared_ptr<kku::Rectangle> getRectangle() const override;
virtual std::shared_ptr<kku::Line> getLine() const override;
virtual std::shared_ptr<kku::Sprite> getSprite(kku::GUISprite::Id id) const override;
virtual kku::Vector2<std::size_t> getRenderSize() const override;
private:
sf::RenderTarget * const _render_target;
kku::ResourceHolder<sf::Font, kku::Font::Id> _font_holder;
kku::ResourceHolder<sf::Texture, kku::Texture::Id> _texture_holder;
};

View File

@ -1,24 +0,0 @@
#include "linesfml.h"
LineSFML::LineSFML(sf::RenderTarget * const render_target) :
_render_target(render_target)
{
_vertex = sf::VertexArray(sf::LinesStrip, 2);
}
void LineSFML::setPosition(const kku::Point& p1, const kku::Point& p2)
{
_vertex[0].position = {p1.x, p1.y};
_vertex[1].position = {p2.x, p2.y};
}
void LineSFML::setColor(const kku::Color& c1, const kku::Color& c2)
{
_vertex[0].color = sf::Color{c1.red, c1.green, c1.blue, c1.alpha};
_vertex[1].color = sf::Color{c2.red, c2.green, c2.blue, c2.alpha};
}
void LineSFML::display()
{
_render_target->draw(_vertex);
}

View File

@ -1,20 +0,0 @@
#pragma once
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/VertexArray.hpp>
#include <memory>
#include "core/line.h"
class LineSFML : public kku::Line
{
public:
explicit LineSFML(sf::RenderTarget * const render_target);
virtual void setPosition(const kku::Point& p1, const kku::Point& p2) override;
virtual void setColor(const kku::Color& c1, const kku::Color& c2) override;
virtual void display() override;
private:
sf::RenderTarget * const _render_target;
sf::VertexArray _vertex;
};

View File

@ -1,89 +0,0 @@
#include "musicsfml.h"
MusicSFML::MusicSFML() :
_sfml_music_offset(0),
_previous_frame_offset(0),
_absolute_offset(0)
{}
bool MusicSFML::open(const std::string& filepath)
{
return _music.openFromFile(filepath);
}
void MusicSFML::play()
{
_music.play();
_sfml_music_offset = _offset_interpolator.restart().asMicroseconds();
}
void MusicSFML::pause()
{
_music.pause();
}
void MusicSFML::stop()
{
_music.stop();
}
bool MusicSFML::isPlaying() const
{
return _music.getStatus() == sf::Music::Playing;
}
void MusicSFML::setVolume(float volume)
{
_music.setVolume(volume);
}
void MusicSFML::setOffset(const kku::microsec& offset)
{
//_previous_frame_offset += (offset - _absolute_offset);
_music.setPlayingOffset(sf::microseconds(offset));
}
kku::microsec MusicSFML::fetchOffset()
{
if (_music.getStatus() != sf::Music::Status::Playing)
return _absolute_offset;
const auto interpolator_timestamp = _offset_interpolator.getElapsedTime().asMicroseconds();
const auto sfml_new_offset = _music.getPlayingOffset().asMicroseconds();
_absolute_offset += (interpolator_timestamp - _previous_frame_offset);
_previous_frame_offset = interpolator_timestamp;
if (sfml_new_offset != _sfml_music_offset)
{
_absolute_offset = ((_absolute_offset + sfml_new_offset) / 2);
_sfml_music_offset = sfml_new_offset;
}
return _absolute_offset;
}
void MusicSFML::moveOffset(const kku::microsec& delta)
{
const auto offset = fetchOffset();
const auto result = offset + delta;
if (result < 0)
{
setOffset(0);
}
else if (result > getDuration())
{
setOffset(_music.getDuration().asMicroseconds());
pause();
}
else
{
setOffset(result);
}
}
kku::microsec MusicSFML::getDuration() const
{
return _music.getDuration().asMicroseconds();
}

View File

@ -1,35 +0,0 @@
#pragma once
#include "core/music.h"
#include <SFML/Audio/Music.hpp>
#include <SFML/System/Clock.hpp>
class MusicSFML : public kku::Music
{
public:
explicit MusicSFML();
virtual bool open(const std::string& filepath) override;
virtual void play() override;
virtual void pause() override;
virtual void stop() override;
virtual bool isPlaying() const override;
virtual void setVolume(float volume) override;
virtual void setOffset(const kku::microsec& offset) override;
virtual void moveOffset(const kku::microsec& delta) override;
virtual kku::microsec fetchOffset() override;
virtual kku::microsec getDuration() const override;
private:
sf::Music _music;
sf::Clock _offset_interpolator;
kku::microsec _sfml_music_offset;
kku::microsec _previous_frame_offset;
kku::microsec _absolute_offset;
};

View File

@ -1,57 +0,0 @@
#include "rectanglesfml.h"
RectangleSFML::RectangleSFML(sf::RenderTarget * const render_target) :
_render_target(render_target)
{}
void RectangleSFML::setRect(const kku::Area<float>& rect)
{
_rectangle.setPosition(rect.left, rect.top);
_rectangle.setSize({rect.width, rect.height});
}
kku::Area<float> RectangleSFML::getRect() const
{
const auto position = _rectangle.getPosition();
const auto size = _rectangle.getSize();
return kku::Area<float>{position.x, position.y, size.x, size.y};
}
void RectangleSFML::move(const kku::Vector2<float>& delta)
{
_rectangle.move({delta.first, delta.second});
}
void RectangleSFML::setPosition(const kku::Point& position)
{
_rectangle.setPosition({position.x, position.y});
}
kku::Point RectangleSFML::getPosition() const
{
const auto position = _rectangle.getPosition();
return kku::Point{position.x, position.y};
}
void RectangleSFML::setColor(const kku::Color& color)
{
_rectangle.setFillColor(sf::Color{color.red, color.green,
color.blue, color.alpha});
}
kku::Color RectangleSFML::getColor() const
{
const auto color = _rectangle.getFillColor();
return kku::Color{color.r, color.g, color.b, color.a};
}
bool RectangleSFML::contains(const kku::Point& position) const
{
return _rectangle.getGlobalBounds().contains(position.x, position.y);
}
void RectangleSFML::display()
{
_render_target->draw(_rectangle);
}

View File

@ -1,29 +0,0 @@
#pragma once
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/RectangleShape.hpp>
#include <memory>
#include "core/rectangle.h"
class RectangleSFML : public kku::Rectangle
{
public:
explicit RectangleSFML(sf::RenderTarget * const render_target);
virtual void setRect(const kku::Area<float>& rect) override;
virtual kku::Area<float> getRect() const override;
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual void setColor(const kku::Color& color) override;
virtual kku::Color getColor() const override;
virtual bool contains(const kku::Point& position) const override;
virtual void display() override;
private:
sf::RenderTarget * const _render_target;
sf::RectangleShape _rectangle;
};

View File

@ -1,33 +0,0 @@
#include "spritesfml.h"
SpriteSFML::SpriteSFML(sf::RenderTarget * const render_target,
const std::shared_ptr<sf::Texture>& texture,
const kku::Area<unsigned int> &cropping) :
_render_target(render_target),
_sprite(*texture, sf::IntRect(cropping.left, cropping.top, cropping.width, cropping.height))
{}
void SpriteSFML::setPosition(const kku::Point& position)
{
_sprite.setPosition(position.x, position.y);
}
kku::Point SpriteSFML::getPosition() const
{
const auto& position = _sprite.getPosition();
return kku::Point
{
position.x,
position.y
};
}
void SpriteSFML::move(const kku::Vector2<float>& delta)
{
_sprite.move({delta.first, delta.second});
}
void SpriteSFML::display() const
{
_render_target->draw(_sprite);
}

View File

@ -1,25 +0,0 @@
#pragma once
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/Sprite.hpp>
#include <memory>
#include "core/sprite.h"
class SpriteSFML : public kku::Sprite
{
public:
explicit SpriteSFML(sf::RenderTarget * const render_target,
const std::shared_ptr<sf::Texture> &texture,
const kku::Area<unsigned int>& cropping);
virtual void setPosition(const kku::Point& position) override;
virtual kku::Point getPosition() const override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual void display() const override;
protected:
sf::RenderTarget * const _render_target;
sf::Sprite _sprite;
};

View File

@ -1,38 +0,0 @@
#include "textsfml.h"
TextSFML::TextSFML(sf::RenderTarget * const render_target,
const std::shared_ptr<const sf::Font>& font) :
_render_target(render_target)
{
_text.setFont(*font);
}
void TextSFML::setString(const std::string& string)
{
_text.setString(string);
}
void TextSFML::setCharacterSize(std::size_t pixels)
{
_text.setCharacterSize(pixels);
}
void TextSFML::setPosition(const kku::Point& point)
{
_text.setPosition(point.x, point.y);
}
void TextSFML::move(const kku::Vector2<float>& delta)
{
_text.move({delta.first, delta.second});
}
void TextSFML::setColor(const kku::Color& color)
{
_text.setFillColor(sf::Color{color.red, color.green, color.blue, color.alpha});
}
void TextSFML::display()
{
_render_target->draw(_text);
}

View File

@ -1,27 +0,0 @@
#pragma once
#include <SFML/Graphics/RenderTarget.hpp>
#include <SFML/Graphics/Text.hpp>
#include <SFML/Graphics/Font.hpp>
#include <memory>
#include "core/text.h"
class TextSFML : public kku::Text
{
public:
explicit TextSFML(sf::RenderTarget * const render_target,
const std::shared_ptr<const sf::Font>& font);
virtual void setString(const std::string& string) override;
virtual void setCharacterSize(std::size_t pixels) override;
virtual void setPosition(const kku::Point& point) override;
virtual void move(const kku::Vector2<float>& delta) override;
virtual void setColor(const kku::Color& color) override;
virtual void display() override;
protected:
sf::RenderTarget * const _render_target;
sf::Text _text;
};

View File

@ -1,9 +0,0 @@
#include "application/applicationsfml.h"
int main()
{
sf::RenderWindow window(sf::VideoMode{1280, 720}, "Project Kyoku", sf::Style::Default);
ApplicationSFML app(&window);
if (app.init())
app.run();
}

View File

@ -1,20 +0,0 @@
cmake_minimum_required(VERSION 3.13)
project(classicmode)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
include_directories(${CMAKE_SOURCE_DIR}/include)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/shared)
file(GLOB_RECURSE SOURCES "editor/*.h" "editor/*.cpp"
"graphics/*.h" "graphics/*.cpp"
"game/*.h" "game/*.cpp"
"shared/*.h" "*.cpp"
"include/*.h")
add_library(classicmode STATIC ${SOURCES} ${HEADERS})
target_include_directories(classicmode PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_link_libraries(classicmode tools)
target_include_directories(project-kyoku PRIVATE ${CMAKE_SOURCE_DIR}/src/modes/classicmode/shared)

View File

@ -1,36 +0,0 @@
#include "classicmode/classicfactory.h"
#include "graphics/classicscenegraphicsmanager.h"
#include "graphics/classicgraphicsfactory.h"
#include "core/timeline.h"
#include "game/classicgame.h"
#include "editor/classiceditor.h"
#include "editor/selectionmanager.h"
std::unique_ptr<kku::Game> classic::getGame(const std::shared_ptr<kku::CoreFactory>& core_factory)
{
// read offset from beatmap metadata
const kku::microsec visibility_offset = 1648648;
const auto factory = std::make_shared<ClassicGraphicsFactory>(core_factory);
const auto timeline = std::make_shared<kku::Timeline<ClassicNote>>();
const auto selection_manager = std::make_shared<SelectionManager>();
const auto graphics_manager = std::make_shared<ClassicSceneGraphicsManager<ClassicNote>>(timeline, factory, visibility_offset);
return std::make_unique<ClassicGame>(timeline, graphics_manager);
}
std::unique_ptr<kku::Editor> classic::getEditor(const std::shared_ptr<kku::CoreFactory>& core_factory)
{
// read offset from beatmap metadata
const kku::microsec visibility_offset = 1648648;
const auto factory = std::make_shared<ClassicGraphicsFactory>(core_factory);
const auto timeline = std::make_shared<kku::Timeline<ClassicMockNote>>();
const auto selection_manager = std::make_shared<SelectionManager>();
const auto graphics_manager = std::make_shared<ClassicSceneGraphicsManager<ClassicMockNote>>(timeline, factory, visibility_offset);
return std::make_unique<ClassicEditor>(timeline, graphics_manager, selection_manager);
}

View File

@ -1,16 +0,0 @@
#include "classicmode/classicnote.h"
ClassicNote::ClassicNote(NoteInitializer &&init) :
Note(init.perfect_offset),
_state(State::NONE)
{}
void ClassicNote::setState(ClassicNote::State state) noexcept
{
_state = state;
}
auto ClassicNote::getState() const noexcept -> State
{
return _state;
}

View File

@ -1,22 +0,0 @@
#include "callbacksimple.h"
CallbackSimple::CallbackSimple(Init&& init, Metadata&& metadata) :
_run(std::move(init.run)),
_is_enabled(std::move(init.is_enabled)),
_metadata(std::move(metadata))
{}
bool CallbackSimple::isEnabled() const
{
return _is_enabled();
}
void CallbackSimple::run() const
{
_run();
}
auto CallbackSimple::getMetadata() const -> EditorCallback::Metadata
{
return _metadata;
}

View File

@ -1,27 +0,0 @@
#pragma once
#include "core/editorcallback.h"
#include "core/functional.h"
class CallbackSimple : public kku::EditorCallback
{
public:
struct Init
{
kku::lambda run;
kku::predicate is_enabled;
};
explicit CallbackSimple(Init&& init, Metadata&& metadata);
virtual bool isEnabled() const override;
virtual void run() const override;
virtual Metadata getMetadata() const override;
private:
const kku::lambda _run;
const kku::predicate _is_enabled;
const Metadata _metadata;
};

View File

@ -1,179 +0,0 @@
#include "classiceditor.h"
#include "classicmocknote.h"
#include "graphics/classicgraphicsmanager.h"
#include "editor/selectionmanager.h"
// Replace with interface by dependency injection
#include "graphics/animations/classicflyinganimationscenario.h"
#include "graphics/animations/classicdyinganimationscenario.h"
//
#include "callbacks/callbacksimple.h"
ClassicEditor::ClassicEditor(const std::shared_ptr<kku::Timeline<ClassicMockNote>>& timeline,
const std::shared_ptr<ClassicGraphicsManager>& graphics_manager,
const std::shared_ptr<SelectionManager>& selection_manager) :
_timeline(timeline),
_graphics_manager(graphics_manager),
_selection_manager(selection_manager),
_selected_type(Type::UP),
_current_time(0),
_scroll_step(500000)
{
kku::microsec starting_beat_offset = 402162;
int amount_of_beats = 209;
kku::microsec interval = 1412162;
kku::microsec tempo_interval = interval / 4;
kku::microsec note_input_offset = 412162 / 2;
//microsec note_input_offset_fast = 412162 / 6;
kku::microsec bpm_iterator = starting_beat_offset;
kku::microsec bpm_end = starting_beat_offset + (interval * amount_of_beats);
std::vector<kku::microsec> input_intervals = {note_input_offset / 3, note_input_offset / 3 * 2, note_input_offset};
std::set<ClassicMockNote*, kku::NotePtrComparator> notes;
input_intervals.shrink_to_fit();
bpm_iterator += tempo_interval;
float x = 90.;
int counter = 3;
while (bpm_iterator < bpm_end)
{
ArrowNoteInitializer init;
ArrowElementInitializer element;
init.initializer.intervals = input_intervals;
init.initializer.perfect_offset = bpm_iterator;
init.hold = false;
element.element.position = kku::Point(x, 390.f);
element.element.falling_curve_interpolation = {};
element.keys = {kku::SystemEvent::Key::Code::W,
kku::SystemEvent::Key::Code::Up};
element.element.type = Type::UP;
if (counter == 0)
{
init.hold = true;
element.keys = {kku::SystemEvent::Key::Code::D,
kku::SystemEvent::Key::Code::Right};
element.element.type = Type::RIGHT;
}
--counter;
init.elements = {element};
notes.insert(new ClassicMockNote(std::move(init), _selection_manager));
bpm_iterator += tempo_interval;
x += 70;
if (x >= 1200)
x = 90.;
}
_timeline->setNotes(notes);
}
kku::microsec ClassicEditor::adjustOffset(kku::microsec offset) const noexcept
{
const auto& section = getBPMSectionAt(offset);
const kku::microsec actual_offset = offset - section.offset_start;
return actual_offset + (actual_offset % section.interval);
}
void ClassicEditor::input(kku::GameEvent&& input)
{
_current_time = input.timestamp;
const auto& event = input.event;
switch (input.event.type)
{
default:
break;
case kku::SystemEvent::Type::KeyPress:
{
const auto key_data = std::get<kku::SystemEvent::Key>(input.event.data);
if (key_data.view == kku::SystemEvent::Key::Code::LControl)
{
_selection_manager->enableMultiselection(true);
}
break;
}
case kku::SystemEvent::Type::KeyRelease:
{
const auto key_data = std::get<kku::SystemEvent::Key>(input.event.data);
if (key_data.view == kku::SystemEvent::Key::Code::LControl)
{
_selection_manager->enableMultiselection(false);
}
break;
}
case kku::SystemEvent::Type::MousePress:
{
const auto note = _timeline->getNoteBy(_current_time);
if (_timeline->isExpired(note) && !_bpm_sections.empty() && _current_time >= (*_bpm_sections.begin()).offset_start)
{
ArrowNoteInitializer init;
ArrowElementInitializer element;
init.initializer.intervals = {};
init.initializer.perfect_offset = input.timestamp;
init.hold = false;
element.element.position = std::get<kku::SystemEvent::Mouse>(event.data).position;
element.element.falling_curve_interpolation = {};
element.keys = {kku::SystemEvent::Key::Code::W,
kku::SystemEvent::Key::Code::Up};
element.element.type = Type::UP;
init.elements = { element };
_timeline->insertNote(new ClassicMockNote(std::move(init), _selection_manager));
}
if (!_selection_manager->isMultiselectionEnabled())
_selection_manager->discard();
_graphics_manager->input(std::move(input));
break;
}
}
}
void ClassicEditor::update(kku::UpdateData&& updatedata)
{
_timeline->update(updatedata.timestamp);
_graphics_manager->update(updatedata.timestamp);
}
void ClassicEditor::display() const
{
_graphics_manager->display();
_selection_manager->display();
}
void ClassicEditor::recalculate(const kku::microsec& timestamp)
{
_timeline->recalculate(timestamp);
}
void ClassicEditor::selectNoteType(Type type) noexcept
{
_selected_type = type;
}

View File

@ -1,38 +0,0 @@
#pragma once
#include <memory>
#include "core/editor.h"
#include "core/timeline.h"
#include "classicmocknote.h"
#include "classicmode/classicactions.h"
class ClassicGraphicsManager;
class SelectionManager;
class ClassicEditor : public kku::Editor
{
public:
explicit ClassicEditor(const std::shared_ptr<kku::Timeline<ClassicMockNote>>& timeline,
const std::shared_ptr<ClassicGraphicsManager>& graphics_manager,
const std::shared_ptr<SelectionManager>& selection_manager);
virtual void input(kku::GameEvent&& input) override;
virtual void update(kku::UpdateData&& updatedata) override;
virtual void display() const override;
virtual void recalculate(const kku::microsec& timestamp) override;
void selectNoteType(Type type) noexcept;
private:
inline kku::microsec adjustOffset(kku::microsec offset) const noexcept;
const std::shared_ptr<kku::Timeline<ClassicMockNote>> _timeline;
const std::shared_ptr<ClassicGraphicsManager> _graphics_manager;
const std::shared_ptr<SelectionManager> _selection_manager;
Type _selected_type;
kku::microsec _current_time;
kku::microsec _scroll_step;
};

View File

@ -1,95 +0,0 @@
#include "classicmocknote.h"
#include "graphics/classicscenegraphicsmanager.h"
#include "graphics/animations/classicanimationscenario.h"
#include "editor/selectionmanager.h"
ClassicMockNote::ClassicMockNote(ArrowNoteInitializer&& init, const std::shared_ptr<SelectionManager>& selection_manager) :
ClassicNote(std::move(init.initializer)),
_selection_manager(selection_manager)
{
_elements.resize(init.elements.size());
for (std::size_t i = 0; i < _elements.size(); ++i)
{
_elements[i].position = init.elements[i].element.position;
_elements[i].type = init.elements[i].element.type;
}
}
bool ClassicMockNote::isActive(const kku::microsec &offset) const
{
(void)offset;
return _state != State::DEAD
&& _state != State::NONE;
}
void ClassicMockNote::input(kku::GameEvent&& input)
{
switch (input.event.type)
{
default:
break;
case kku::SystemEvent::Type::MousePress:
{
bool selection_changed = false;
std::size_t amount_selected = 0;
const auto position = std::get<kku::SystemEvent::Mouse>(input.event.data).position;
for (auto& element : _elements)
{
if (element.sprite->getRectangle()->contains(position))
{
element.selected = !element.selected;
selection_changed = true;
if (element.selected)
++amount_selected;
}
}
if (selection_changed)
{
if (amount_selected > 0)
_selection_manager->fetch(this);
else
_selection_manager->remove(this);
}
break;
}
}
}
void ClassicMockNote::update(const kku::microsec& music_offset)
{
switch (_state)
{
default: return;
break;
case State::FLYING:
if (music_offset >= getPerfectOffset())
{
_state = State::DYING;
for (auto& element : _elements)
element.animations[_state]->launch(element.sprite, music_offset, getPerfectOffset());
}
break;
case State::DYING:
if (_elements[0].animations[_state]->isDone())
_state = State::DEAD;
break;
}
for (auto& element : _elements)
if (element.animations[_state])
element.animations[_state]->update(music_offset);
}
std::vector<MockElement>& ClassicMockNote::getElements()
{
return _elements;
}

View File

@ -1,27 +0,0 @@
#pragma once
#include "classicmode/classicnote.h"
#include "mockelement.h"
#include "classicmode/arrownoteinitializer.h"
class SelectionManager;
class ClassicMockNote : public ClassicNote
{
public:
explicit ClassicMockNote(ArrowNoteInitializer&& init, const std::shared_ptr<SelectionManager>& selection_manager);
virtual ~ClassicMockNote() = default;
virtual bool isActive(const kku::microsec& offset) const override;
virtual void update(const kku::microsec &music_offset) override;
virtual void input(kku::GameEvent&& input) override;
std::vector<MockElement>& getElements();
private:
const std::shared_ptr<SelectionManager> _selection_manager;
std::vector<MockElement> _elements;
};
using MockElements = std::vector<MockElement>;

View File

@ -1,10 +0,0 @@
#pragma once
#include "classicmode/noteinitializer.h"
#include "classicmode/elementinitializer.h"
struct MockArrowNoteInitializer
{
NoteInitializer initializer;
std::vector<ElementInitializer> elements;
};

View File

@ -1,32 +0,0 @@
#pragma once
#include "classicmode/classicactions.h"
#include "core/gameevent.h"
#include "core/point.h"
#include <memory>
#include <vector>
#include <array>
class ClassicAnimationScenario;
class ClassicNoteGraphics;
class ClassicSelectionGraphics;
struct MockElement
{
std::shared_ptr<ClassicNoteGraphics> sprite;
std::shared_ptr<ClassicSelectionGraphics> selection;
bool selected;
std::array<std::shared_ptr<ClassicAnimationScenario>, 5> animations;
kku::Point position;
std::vector<kku::Point> falling_curve_interpolation;
Type type = Type::NONE;
// Each note may consist of several buttons.
// For example, ↑ → or ↓ → ←
// Note Element represents this idea.
};

View File

@ -1,63 +0,0 @@
#include "selectionmanager.h"
#include "classicmocknote.h"
#include "mockelement.h"
#include "graphics/classicselectiongraphics.h"
#include <algorithm>
SelectionManager::SelectionManager() :
_multiselection_enabled(false)
{}
void SelectionManager::discard()
{
for (const auto& note : _selected_notes)
for (auto& element : note->getElements())
element.selected = false;
_selected_notes.clear();
}
void SelectionManager::fetch(ClassicMockNote * const note)
{
bool already_there = std::any_of(_selected_notes.begin(), _selected_notes.end(),
[&note](const auto& selected_note)
{
return note == selected_note;
});
if (!already_there)
_selected_notes.emplace_back(note);
}
void SelectionManager::remove(ClassicMockNote * const note)
{
for (std::size_t i = 0; i < _selected_notes.size(); ++i)
{
if (note == _selected_notes.at(i))
{
_selected_notes[i] = std::move(_selected_notes.back());
_selected_notes.pop_back();
break;
}
}
}
void SelectionManager::enableMultiselection(bool enable)
{
_multiselection_enabled = enable;
}
bool SelectionManager::isMultiselectionEnabled() const
{
return _multiselection_enabled;
}
void SelectionManager::display() const
{
for (const auto& note : _selected_notes)
for (const auto& element : note->getElements())
if (element.selected)
{
element.selection->display();
}
}

View File

@ -1,27 +0,0 @@
#pragma once
#include "classicmocknote.h"
#include <memory>
#include <vector>
class SelectionManager
{
public:
explicit SelectionManager();
// Remove whole selection completely
void discard();
void fetch(ClassicMockNote * const note);
void remove(ClassicMockNote * const note);
void enableMultiselection(bool enable = true);
bool isMultiselectionEnabled() const;
void display() const;
private:
std::vector<ClassicMockNote*> _selected_notes;
bool _multiselection_enabled;
};

View File

@ -1,31 +0,0 @@
#pragma once
#include "classicmode/classicactions.h"
#include "core/gameevent.h"
#include "core/point.h"
#include <memory>
#include <vector>
#include <array>
class ClassicNoteGraphics;
class ClassicAnimationScenario;
struct ArrowElement
{
std::shared_ptr<ClassicNoteGraphics> sprite;
std::array<std::shared_ptr<ClassicAnimationScenario>, 5> animations;
kku::SystemEvent::Key::Code pressed_as = kku::SystemEvent::Key::Code::Unknown;
kku::Point position;
std::vector<kku::Point> falling_curve_interpolation;
std::array<kku::SystemEvent::Key::Code, 2> keys;
Type type = Type::NONE;
bool pressed = false;
// Each note may consist of several buttons.
// For example, ↑ → or ↓ → ←
// Note Element represents this idea.
};

View File

@ -1,123 +0,0 @@
#include "classicarrownote.h"
#include "graphics/classicscenegraphicsmanager.h"
#include "graphics/animations/classicanimationscenario.h"
#include "holdmanager.h"
ClassicArrowNote::ClassicArrowNote(ArrowNoteInitializer&& init, const std::shared_ptr<HoldManager>& hold_manager) :
ClassicNote(std::move(init.initializer)),
_evaluator(init.initializer.intervals, _perfect_offset),
_hold_manager(hold_manager),
_is_hold(init.hold)
{
_elements.resize(init.elements.size());
for (std::size_t i = 0; i < _elements.size(); ++i)
{
_elements[i].keys = init.elements[i].keys;
_elements[i].position = init.elements[i].element.position;
_elements[i].type = init.elements[i].element.type;
}
}
bool ClassicArrowNote::isActive(const kku::microsec& offset) const
{
return _evaluator.isActive(offset)
&& _state != State::DYING;
}
void ClassicArrowNote::input(kku::GameEvent&& input)
{
auto grade = Grade::BAD;
bool input_valid = std::any_of(_elements.begin(), _elements.end(),
[input=input](auto& element)
{
if (element.pressed)
return false;
const auto code = std::get<kku::SystemEvent::Key>(input.event.data).view;
auto key_iterator = std::find(element.keys.begin(), element.keys.end(), code);
bool found_key = key_iterator != element.keys.end();
if (found_key)
{
element.pressed = true;
element.pressed_as = code;
}
return found_key;
});
bool all_pressed = allElementsPressed();
if (all_pressed)
{
grade = _evaluator.calculatePrecision(input.timestamp);
if (isHold())
_hold_manager->emplace(this);
}
if (all_pressed || !input_valid)
{
_state = State::DYING;
for (auto& element : _elements)
element.animations[_state]->launch(element.sprite, input.timestamp, getPerfectOffset());
}
std::cout << "User input: " << static_cast<int>(grade) << "\n";
}
void ClassicArrowNote::update(const kku::microsec& music_offset)
{
switch (_state)
{
default: return;
break;
case State::FLYING:
if (!_evaluator.isActive(music_offset) && music_offset > getPerfectOffset())
{
_state = State::DYING;
for (auto& element : _elements)
element.animations[_state]->launch(element.sprite, music_offset, getPerfectOffset());
}
break;
case State::DYING:
if (_elements[0].animations[_state]->isDone())
_state = State::DEAD;
break;
}
for (auto& element : _elements)
if (element.animations[_state])
element.animations[_state]->update(music_offset);
}
bool ClassicArrowNote::allElementsPressed() const
{
return std::all_of(_elements.begin(), _elements.end(),
[](const auto& element)
{
return element.pressed;
});
}
bool ClassicArrowNote::isPressedAs(kku::SystemEvent::Key::Code key) const
{
return std::any_of(_elements.begin(), _elements.end(),
[key](const auto& element)
{
return key == element.pressed_as;
});
}
bool ClassicArrowNote::isHold() const
{
return _is_hold;
}
std::vector<ArrowElement>& ClassicArrowNote::getElements()
{
return _elements;
}

Some files were not shown because too many files have changed in this diff Show More