audio, sfx and bgm classes; filesystem path added as type to json lib
This commit is contained in:
parent
be360b8a47
commit
013f8279d4
|
@ -13,11 +13,15 @@
|
||||||
screen resolution, debug display, loading wheel animation, shadowed sprite,
|
screen resolution, debug display, loading wheel animation, shadowed sprite,
|
||||||
separate update and draw, sprite movement cage, multiple windows, multiple
|
separate update and draw, sprite movement cage, multiple windows, multiple
|
||||||
renderers, node children list, node animations list, copy constructor for all
|
renderers, node children list, node animations list, copy constructor for all
|
||||||
base classes, private and public class members, pixel class iterator, sprite
|
base classes (esp. sprite, audio), private and public class members, pixel
|
||||||
movement history, input history, use seconds instead of milliseconds, store
|
class iterator, sprite movement history, input history, use seconds instead of
|
||||||
a node's animations in list, frame object for sprite class, inline short
|
milliseconds, store a node's animations in list, frame object for sprite
|
||||||
functions, add box2d to library, load in separate thread and display progress,
|
class, inline short functions, add box2d to library, load in separate thread
|
||||||
add anchor to box class
|
and display progress, add anchor to box class, add comments to code, generate
|
||||||
|
documentation from comments, get resource function, automatically update
|
||||||
|
animations, add arguments list to animation call, queue multiple calls to
|
||||||
|
animation, print list of chunk and music decoders available, allow nodes that
|
||||||
|
aren't connected to root
|
||||||
|
|
||||||
:) SWEATY HANDS :) OILY SNACKS :) AND BAD HYGIENE :)
|
:) SWEATY HANDS :) OILY SNACKS :) AND BAD HYGIENE :)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,140 @@
|
||||||
|
#include "SDL.h"
|
||||||
|
|
||||||
|
#include "Box.hpp"
|
||||||
|
#include "Configuration.hpp"
|
||||||
|
#include "Display.hpp"
|
||||||
|
#include "Audio.hpp"
|
||||||
|
|
||||||
|
BGM::BGM(Node* parent) : Node(parent) {}
|
||||||
|
|
||||||
|
BGM::BGM() : BGM(nullptr) {}
|
||||||
|
|
||||||
|
BGM::BGM(Node* parent, const fs::path& path) : BGM(parent)
|
||||||
|
{
|
||||||
|
load_music(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
BGM::BGM(const fs::path& path) : BGM(nullptr, path) {}
|
||||||
|
|
||||||
|
void BGM::load_music(const fs::path& path)
|
||||||
|
{
|
||||||
|
music = Mix_LoadMUS(path.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void BGM::set_volume(float v)
|
||||||
|
{
|
||||||
|
volume = v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void BGM::play(int loops)
|
||||||
|
{
|
||||||
|
Mix_VolumeMusic(std::round(volume * 127));
|
||||||
|
Mix_PlayMusic(music, loops);
|
||||||
|
}
|
||||||
|
|
||||||
|
BGM::~BGM()
|
||||||
|
{
|
||||||
|
Mix_FreeMusic(music);
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundEffect::SoundEffect(Node* parent) : Node(parent) {}
|
||||||
|
|
||||||
|
SoundEffect::SoundEffect() : SoundEffect(nullptr) {}
|
||||||
|
|
||||||
|
SoundEffect::SoundEffect(Node* parent, const fs::path& path) : SoundEffect(parent)
|
||||||
|
{
|
||||||
|
load_chunk(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundEffect::SoundEffect(const fs::path& path) : SoundEffect(nullptr, path) {}
|
||||||
|
|
||||||
|
void SoundEffect::load_chunk(const fs::path& path)
|
||||||
|
{
|
||||||
|
chunk = Mix_LoadWAV(path.c_str());
|
||||||
|
Mix_VolumeChunk(chunk, std::round(volume * 127));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundEffect::play(float location)
|
||||||
|
{
|
||||||
|
play();
|
||||||
|
Box window_box = get_window_box();
|
||||||
|
location = std::clamp(location, window_box.get_left(), window_box.get_right());
|
||||||
|
float location_relative = (location - window_box.get_left()) / window_box.get_w();
|
||||||
|
int angle = 270 - location_relative * 180;
|
||||||
|
Mix_SetPosition(channel, angle, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundEffect::play()
|
||||||
|
{
|
||||||
|
channel = Mix_PlayChannel(-1, chunk, loops);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundEffect::play_after(float delay)
|
||||||
|
{
|
||||||
|
play_animation.play_once(delay);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundEffect::set_volume(float v)
|
||||||
|
{
|
||||||
|
volume = v;
|
||||||
|
Mix_VolumeChunk(chunk, std::round(volume * 127));
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundEffect::set_loop_count(int count)
|
||||||
|
{
|
||||||
|
loops = count;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundEffect::set_loop_forever()
|
||||||
|
{
|
||||||
|
loops = -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SoundEffect::is_playing(bool include_delay)
|
||||||
|
{
|
||||||
|
if (include_delay)
|
||||||
|
{
|
||||||
|
if (play_animation.is_playing())
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int channel_ii = 0; channel_ii < Mix_GroupAvailable(-1); channel_ii++)
|
||||||
|
{
|
||||||
|
if (Mix_GetChunk(channel_ii) == chunk)
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SoundEffect::update()
|
||||||
|
{
|
||||||
|
play_animation.update();
|
||||||
|
}
|
||||||
|
|
||||||
|
SoundEffect::~SoundEffect()
|
||||||
|
{
|
||||||
|
Mix_FreeChunk(chunk);
|
||||||
|
}
|
||||||
|
|
||||||
|
Audio::Audio(Node* parent) : Node(parent) {}
|
||||||
|
|
||||||
|
void Audio::load_sfx()
|
||||||
|
{
|
||||||
|
load_directory(get_configuration()["audio"]["default-sfx-root"], sfx, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::load_bgm()
|
||||||
|
{
|
||||||
|
load_directory(get_configuration()["audio"]["default-bgm-root"], bgm, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Audio::update()
|
||||||
|
{
|
||||||
|
for (auto& [name, sound_effect] : sfx)
|
||||||
|
{
|
||||||
|
sound_effect.update();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,89 @@
|
||||||
|
#ifndef Audio_h_
|
||||||
|
#define Audio_h_
|
||||||
|
|
||||||
|
#include <regex>
|
||||||
|
#include <map>
|
||||||
|
|
||||||
|
#include "SDL_mixer.h"
|
||||||
|
#include "filesystem.hpp"
|
||||||
|
#include "Node.hpp"
|
||||||
|
#include "Animation.hpp"
|
||||||
|
#include "extension.hpp"
|
||||||
|
|
||||||
|
struct BGM : Node
|
||||||
|
{
|
||||||
|
|
||||||
|
Mix_Music* music;
|
||||||
|
float volume = 1.0f;
|
||||||
|
|
||||||
|
BGM();
|
||||||
|
BGM(Node*);
|
||||||
|
BGM(Node*, const fs::path&);
|
||||||
|
BGM(const fs::path&);
|
||||||
|
void load_music(const fs::path&);
|
||||||
|
void set_volume(float);
|
||||||
|
void play(int = -1);
|
||||||
|
~BGM();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct SoundEffect : Node
|
||||||
|
{
|
||||||
|
|
||||||
|
Mix_Chunk* chunk = nullptr;
|
||||||
|
int channel, loops = 0;
|
||||||
|
float volume = 1.0f;
|
||||||
|
Animation play_animation = Animation(&SoundEffect::play, this);
|
||||||
|
|
||||||
|
SoundEffect(Node*);
|
||||||
|
SoundEffect();
|
||||||
|
SoundEffect(Node*, const fs::path&);
|
||||||
|
SoundEffect(const fs::path&);
|
||||||
|
void load_chunk(const fs::path&);
|
||||||
|
void play(float);
|
||||||
|
void play();
|
||||||
|
void play_after(float);
|
||||||
|
void set_volume(float);
|
||||||
|
void set_loop_count(int);
|
||||||
|
void set_loop_forever();
|
||||||
|
bool is_playing(bool = false);
|
||||||
|
void update();
|
||||||
|
~SoundEffect();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Audio : Node
|
||||||
|
{
|
||||||
|
|
||||||
|
std::map<std::string, SoundEffect> sfx;
|
||||||
|
std::map<std::string, BGM> bgm;
|
||||||
|
|
||||||
|
Audio(Node*);
|
||||||
|
void load_sfx();
|
||||||
|
void load_bgm();
|
||||||
|
void update();
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void load_directory(const fs::path& root, std::map<std::string, T>& storage, Node* parent = nullptr)
|
||||||
|
{
|
||||||
|
SDL_Log("looking for audio files in %s", root.c_str());
|
||||||
|
if (fs::exists(root))
|
||||||
|
{
|
||||||
|
for (const fs::path& path : sfw::glob(root / ".*"))
|
||||||
|
{
|
||||||
|
std::regex pattern("([^.]+).*$");
|
||||||
|
std::smatch match;
|
||||||
|
std::string basename = path.filename();
|
||||||
|
if (std::regex_match(basename, match, pattern))
|
||||||
|
{
|
||||||
|
std::string key = match[1].str();
|
||||||
|
SDL_Log("loading %s as %s", path.c_str(), key.c_str());
|
||||||
|
storage.try_emplace(key, parent, path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -51,6 +51,10 @@ void Configuration::set_defaults()
|
||||||
{"render-test-spacing", 2},
|
{"render-test-spacing", 2},
|
||||||
{"render driver", "opengl"}
|
{"render driver", "opengl"}
|
||||||
};
|
};
|
||||||
|
sys_config["audio"] = {
|
||||||
|
{"default-sfx-root", "resource/sfx"},
|
||||||
|
{"default-bgm-root", "resource/bgm"}
|
||||||
|
};
|
||||||
sys_config["recording"] = {
|
sys_config["recording"] = {
|
||||||
{"enabled", false},
|
{"enabled", false},
|
||||||
{"screenshot-prefix", "screenshot-"},
|
{"screenshot-prefix", "screenshot-"},
|
||||||
|
|
|
@ -24,4 +24,39 @@ struct Configuration : Node
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
namespace glm
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
void to_json(nlohmann::json& j, const vec<2, T, defaultp>& v)
|
||||||
|
{
|
||||||
|
j = nlohmann::json{v.x, v.y};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void from_json(const nlohmann::json& j, vec<2, T, defaultp>& v)
|
||||||
|
{
|
||||||
|
j.at(0).get_to(v.x);
|
||||||
|
j.at(1).get_to(v.y);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(__MINGW32__)
|
||||||
|
namespace std::experimental::filesystem
|
||||||
|
#else
|
||||||
|
namespace std::filesystem
|
||||||
|
#endif
|
||||||
|
{
|
||||||
|
template <typename T>
|
||||||
|
void to_json(nlohmann::json& j, const path& p)
|
||||||
|
{
|
||||||
|
j = nlohmann::json{p};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void from_json(const nlohmann::json& j, path& p)
|
||||||
|
{
|
||||||
|
j.at(0).get_to(p);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
10
src/Game.cpp
10
src/Game.cpp
|
@ -145,6 +145,8 @@ Game::Game()
|
||||||
SDL_Log("Found audio capture device %i: %s", ii,
|
SDL_Log("Found audio capture device %i: %s", ii,
|
||||||
SDL_GetAudioDeviceName(ii, SDL_TRUE));
|
SDL_GetAudioDeviceName(ii, SDL_TRUE));
|
||||||
}
|
}
|
||||||
|
audio.load_sfx();
|
||||||
|
audio.load_bgm();
|
||||||
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
#if SDL_BYTEORDER == SDL_BIG_ENDIAN
|
||||||
SDL_Log("big endian");
|
SDL_Log("big endian");
|
||||||
#else
|
#else
|
||||||
|
@ -511,6 +513,11 @@ Input& Game::get_input()
|
||||||
return input;
|
return input;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Audio& Game::get_audio()
|
||||||
|
{
|
||||||
|
return audio;
|
||||||
|
}
|
||||||
|
|
||||||
glm::vec2 Game::weight(glm::vec2 motion)
|
glm::vec2 Game::weight(glm::vec2 motion)
|
||||||
{
|
{
|
||||||
return {weight(motion.x), weight(motion.y)};
|
return {weight(motion.x), weight(motion.y)};
|
||||||
|
@ -556,7 +563,8 @@ void Game::frame(float ticks)
|
||||||
recorder.update();
|
recorder.update();
|
||||||
}
|
}
|
||||||
delegate.dispatch();
|
delegate.dispatch();
|
||||||
get_root()->input.unsuppress_animation.update();
|
audio.update();
|
||||||
|
input.unsuppress_animation.update();
|
||||||
update();
|
update();
|
||||||
framerate_indicator.update();
|
framerate_indicator.update();
|
||||||
if (!is_gl_context)
|
if (!is_gl_context)
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "Recorder.hpp"
|
#include "Recorder.hpp"
|
||||||
#include "extension.hpp"
|
#include "extension.hpp"
|
||||||
#include "Sprite.hpp"
|
#include "Sprite.hpp"
|
||||||
|
#include "Audio.hpp"
|
||||||
|
|
||||||
struct FramerateIndicator : Sprite
|
struct FramerateIndicator : Sprite
|
||||||
{
|
{
|
||||||
|
@ -60,6 +61,7 @@ struct Game : Node
|
||||||
Display display = Display(this);
|
Display display = Display(this);
|
||||||
Recorder recorder = Recorder(this);
|
Recorder recorder = Recorder(this);
|
||||||
Input input = Input(this);
|
Input input = Input(this);
|
||||||
|
Audio audio = Audio(this);
|
||||||
std::vector<float> frame_length_history;
|
std::vector<float> frame_length_history;
|
||||||
TTF_Font* bp_mono_font = NULL;
|
TTF_Font* bp_mono_font = NULL;
|
||||||
FramerateIndicator framerate_indicator = FramerateIndicator(this);
|
FramerateIndicator framerate_indicator = FramerateIndicator(this);
|
||||||
|
@ -84,6 +86,7 @@ struct Game : Node
|
||||||
SDL_Renderer* get_renderer();
|
SDL_Renderer* get_renderer();
|
||||||
const Input& get_input() const;
|
const Input& get_input() const;
|
||||||
Input& get_input();
|
Input& get_input();
|
||||||
|
Audio& get_audio();
|
||||||
glm::vec2 weight(glm::vec2);
|
glm::vec2 weight(glm::vec2);
|
||||||
void run();
|
void run();
|
||||||
void frame(float);
|
void frame(float);
|
||||||
|
|
12
src/Node.cpp
12
src/Node.cpp
|
@ -4,9 +4,10 @@
|
||||||
#include "Input.hpp"
|
#include "Input.hpp"
|
||||||
#include "Box.hpp"
|
#include "Box.hpp"
|
||||||
#include "Game.hpp"
|
#include "Game.hpp"
|
||||||
|
#include "Audio.hpp"
|
||||||
#include "Node.hpp"
|
#include "Node.hpp"
|
||||||
|
|
||||||
Node::Node() : Node(NULL) {}
|
Node::Node() : Node(nullptr) {}
|
||||||
|
|
||||||
Node::Node(Node* parent) : parent(parent)
|
Node::Node(Node* parent) : parent(parent)
|
||||||
{
|
{
|
||||||
|
@ -79,6 +80,11 @@ Input& Node::get_input()
|
||||||
return get_root()->get_input();
|
return get_root()->get_input();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Audio& Node::get_audio()
|
||||||
|
{
|
||||||
|
return get_root()->get_audio();
|
||||||
|
}
|
||||||
|
|
||||||
const Game* Node::get_root() const
|
const Game* Node::get_root() const
|
||||||
{
|
{
|
||||||
const Node* r = this;
|
const Node* r = this;
|
||||||
|
@ -117,10 +123,10 @@ void Node::unsuppress_input()
|
||||||
void Node::print_branch()
|
void Node::print_branch()
|
||||||
{
|
{
|
||||||
Node* current = this;
|
Node* current = this;
|
||||||
while (current != NULL)
|
while (current != nullptr)
|
||||||
{
|
{
|
||||||
std::cout << current->get_class_name() << " @ " << current;
|
std::cout << current->get_class_name() << " @ " << current;
|
||||||
if (current->parent != NULL)
|
if (current->parent != nullptr)
|
||||||
{
|
{
|
||||||
std::cout << " -> ";
|
std::cout << " -> ";
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@ struct Delegate;
|
||||||
struct Display;
|
struct Display;
|
||||||
struct Input;
|
struct Input;
|
||||||
struct Box;
|
struct Box;
|
||||||
|
struct Audio;
|
||||||
|
|
||||||
struct Node
|
struct Node
|
||||||
{
|
{
|
||||||
|
@ -41,6 +42,7 @@ struct Node
|
||||||
SDL_Window* get_window();
|
SDL_Window* get_window();
|
||||||
const Input& get_input() const;
|
const Input& get_input() const;
|
||||||
Input& get_input();
|
Input& get_input();
|
||||||
|
Audio& get_audio();
|
||||||
const Game* get_root() const;
|
const Game* get_root() const;
|
||||||
Box get_window_box();
|
Box get_window_box();
|
||||||
void suppress_input();
|
void suppress_input();
|
||||||
|
|
|
@ -269,11 +269,11 @@ void Sprite::toggle_hidden()
|
||||||
{
|
{
|
||||||
if (is_hidden())
|
if (is_hidden())
|
||||||
{
|
{
|
||||||
hide();
|
unhide();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
unhide();
|
hide();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -168,22 +168,6 @@ namespace sfw
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace glm
|
|
||||||
{
|
|
||||||
template <typename T>
|
|
||||||
void to_json(nlohmann::json& j, const vec<2, T, defaultp>& v)
|
|
||||||
{
|
|
||||||
j = nlohmann::json{{"x", v.x}, {"y", v.y}};
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
void from_json(const nlohmann::json& j, vec<2, T, defaultp>& v)
|
|
||||||
{
|
|
||||||
j.at(0).get_to(v.x);
|
|
||||||
j.at(1).get_to(v.y);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int SDL_SetRenderDrawColor(SDL_Renderer*, const Color&);
|
int SDL_SetRenderDrawColor(SDL_Renderer*, const Color&);
|
||||||
int SDL_RenderFillRect(SDL_Renderer*, const Box&);
|
int SDL_RenderFillRect(SDL_Renderer*, const Box&);
|
||||||
int lineColor(SDL_Renderer*, const Segment&, const Color&, std::uint8_t = 1);
|
int lineColor(SDL_Renderer*, const Segment&, const Color&, std::uint8_t = 1);
|
||||||
|
|
Loading…
Reference in New Issue