mirror of https://github.com/auygun/kaliber.git
Compare commits
No commits in common. "c90d039944e553e41bee4a1d547067c6d576f0f6" and "daa3a8c06f375d5002159e7cbf343b71982fce27" have entirely different histories.
c90d039944
...
daa3a8c06f
Binary file not shown.
After Width: | Height: | Size: 8.0 KiB |
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
|
@ -62,8 +62,8 @@ add_library(kaliber SHARED
|
||||||
../../../src/demo/sky_quad.cc
|
../../../src/demo/sky_quad.cc
|
||||||
../../../src/engine/animatable.cc
|
../../../src/engine/animatable.cc
|
||||||
../../../src/engine/animator.cc
|
../../../src/engine/animator.cc
|
||||||
../../../src/engine/audio/audio_driver_oboe.cc
|
../../../src/engine/audio/audio_base.cc
|
||||||
../../../src/engine/audio/audio_mixer.cc
|
../../../src/engine/audio/audio_oboe.cc
|
||||||
../../../src/engine/drawable.cc
|
../../../src/engine/drawable.cc
|
||||||
../../../src/engine/engine.cc
|
../../../src/engine/engine.cc
|
||||||
../../../src/engine/font.cc
|
../../../src/engine/font.cc
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:versionCode="18"
|
android:versionCode="17"
|
||||||
android:versionName="1.0.2">
|
android:versionName="1.0.2">
|
||||||
|
|
||||||
<application
|
<application
|
||||||
|
|
|
@ -95,8 +95,8 @@ $(BASE_LIB): $(BASE_OBJS)
|
||||||
ENGINE_SRC := \
|
ENGINE_SRC := \
|
||||||
$(SRC_ROOT)/engine/animatable.cc \
|
$(SRC_ROOT)/engine/animatable.cc \
|
||||||
$(SRC_ROOT)/engine/animator.cc \
|
$(SRC_ROOT)/engine/animator.cc \
|
||||||
$(SRC_ROOT)/engine/audio/audio_driver_alsa.cc \
|
$(SRC_ROOT)/engine/audio/audio_alsa.cc \
|
||||||
$(SRC_ROOT)/engine/audio/audio_mixer.cc \
|
$(SRC_ROOT)/engine/audio/audio_base.cc \
|
||||||
$(SRC_ROOT)/engine/drawable.cc \
|
$(SRC_ROOT)/engine/drawable.cc \
|
||||||
$(SRC_ROOT)/engine/engine.cc \
|
$(SRC_ROOT)/engine/engine.cc \
|
||||||
$(SRC_ROOT)/engine/font.cc \
|
$(SRC_ROOT)/engine/font.cc \
|
||||||
|
|
|
@ -50,10 +50,6 @@ Demo::~Demo() {
|
||||||
bool Demo::Initialize() {
|
bool Demo::Initialize() {
|
||||||
saved_data_.Load(kSaveFileName);
|
saved_data_.Load(kSaveFileName);
|
||||||
|
|
||||||
Engine::Get().LoadCustomShader("sky_without_nebula",
|
|
||||||
"sky_without_nebula.glsl");
|
|
||||||
Engine::Get().LoadCustomShader("sky", "sky.glsl");
|
|
||||||
|
|
||||||
if (!font_.Load("PixelCaps!.ttf"))
|
if (!font_.Load("PixelCaps!.ttf"))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
@ -166,6 +162,11 @@ void Demo::Update(float delta_time) {
|
||||||
UpdateGameState(delta_time);
|
UpdateGameState(delta_time);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Demo::ContextLost() {
|
||||||
|
sky_.ContextLost();
|
||||||
|
enemy_.ContextLost();
|
||||||
|
}
|
||||||
|
|
||||||
void Demo::LostFocus() {}
|
void Demo::LostFocus() {}
|
||||||
|
|
||||||
void Demo::GainedFocus(bool from_interstitial_ad) {
|
void Demo::GainedFocus(bool from_interstitial_ad) {
|
||||||
|
|
|
@ -27,7 +27,7 @@ class Demo final : public eng::Game {
|
||||||
|
|
||||||
void Update(float delta_time) final;
|
void Update(float delta_time) final;
|
||||||
|
|
||||||
void ContextLost() final {}
|
void ContextLost() final;
|
||||||
|
|
||||||
void LostFocus() final;
|
void LostFocus() final;
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
#include "engine/font.h"
|
#include "engine/font.h"
|
||||||
#include "engine/image.h"
|
#include "engine/image.h"
|
||||||
#include "engine/renderer/geometry.h"
|
#include "engine/renderer/geometry.h"
|
||||||
|
#include "engine/renderer/shader.h"
|
||||||
|
#include "engine/shader_source.h"
|
||||||
#include "engine/sound.h"
|
#include "engine/sound.h"
|
||||||
|
|
||||||
#include "demo/demo.h"
|
#include "demo/demo.h"
|
||||||
|
@ -74,7 +76,8 @@ float SnapSpawnPosX(int col) {
|
||||||
|
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
Enemy::Enemy() = default;
|
Enemy::Enemy()
|
||||||
|
: chromatic_aberration_(Engine::Get().CreateRenderResource<Shader>()) {}
|
||||||
|
|
||||||
Enemy::~Enemy() = default;
|
Enemy::~Enemy() = default;
|
||||||
|
|
||||||
|
@ -202,6 +205,10 @@ void Enemy::Pause(bool pause) {
|
||||||
boss_animator_.PauseOrResumeAll(pause);
|
boss_animator_.PauseOrResumeAll(pause);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Enemy::ContextLost() {
|
||||||
|
CreateShaders();
|
||||||
|
}
|
||||||
|
|
||||||
bool Enemy::HasTarget(DamageType damage_type) {
|
bool Enemy::HasTarget(DamageType damage_type) {
|
||||||
DCHECK(damage_type > kDamageType_Invalid && damage_type < kDamageType_Any);
|
DCHECK(damage_type > kDamageType_Invalid && damage_type < kDamageType_Any);
|
||||||
|
|
||||||
|
@ -416,7 +423,7 @@ void Enemy::StopAllEnemyUnits(bool chromatic_aberration_effect) {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
if (chromatic_aberration_effect) {
|
if (chromatic_aberration_effect) {
|
||||||
e.sprite.SetCustomShader("chromatic_aberration");
|
e.sprite.SetCustomShader(chromatic_aberration_.get());
|
||||||
e.chromatic_aberration_active_ = true;
|
e.chromatic_aberration_active_ = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1186,6 +1193,9 @@ std::unique_ptr<Image> Enemy::GetScoreImage(EnemyType enemy_type) {
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Enemy::CreateRenderResources() {
|
bool Enemy::CreateRenderResources() {
|
||||||
|
if (!CreateShaders())
|
||||||
|
return false;
|
||||||
|
|
||||||
Engine::Get().SetImageSource("skull_tex", "enemy_anims_01_frames_ok.png",
|
Engine::Get().SetImageSource("skull_tex", "enemy_anims_01_frames_ok.png",
|
||||||
true);
|
true);
|
||||||
Engine::Get().SetImageSource("bug_tex", "enemy_anims_02_frames_ok.png", true);
|
Engine::Get().SetImageSource("bug_tex", "enemy_anims_02_frames_ok.png", true);
|
||||||
|
@ -1203,9 +1213,16 @@ bool Enemy::CreateRenderResources() {
|
||||||
"score_tex"s + std::to_string(i),
|
"score_tex"s + std::to_string(i),
|
||||||
std::bind(&Enemy::GetScoreImage, this, (EnemyType)i), true);
|
std::bind(&Enemy::GetScoreImage, this, (EnemyType)i), true);
|
||||||
|
|
||||||
Engine::Get().LoadCustomShader("chromatic_aberration",
|
return true;
|
||||||
"chromatic_aberration.glsl");
|
}
|
||||||
|
|
||||||
|
bool Enemy::CreateShaders() {
|
||||||
|
auto source = std::make_unique<ShaderSource>();
|
||||||
|
if (!source->Load("chromatic_aberration.glsl"))
|
||||||
|
return false;
|
||||||
|
chromatic_aberration_->Create(std::move(source),
|
||||||
|
Engine::Get().GetQuad()->vertex_description(),
|
||||||
|
Engine::Get().GetQuad()->primitive(), false);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
class Image;
|
class Image;
|
||||||
|
class Shader;
|
||||||
class Sound;
|
class Sound;
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
||||||
|
@ -29,6 +30,8 @@ class Enemy {
|
||||||
|
|
||||||
void Pause(bool pause);
|
void Pause(bool pause);
|
||||||
|
|
||||||
|
void ContextLost();
|
||||||
|
|
||||||
bool HasTarget(DamageType damage_type);
|
bool HasTarget(DamageType damage_type);
|
||||||
base::Vector2f GetTargetPos(DamageType damage_type);
|
base::Vector2f GetTargetPos(DamageType damage_type);
|
||||||
|
|
||||||
|
@ -103,6 +106,7 @@ class Enemy {
|
||||||
eng::SoundPlayer hit;
|
eng::SoundPlayer hit;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
std::unique_ptr<eng::Shader> chromatic_aberration_;
|
||||||
float chromatic_aberration_offset_ = 0;
|
float chromatic_aberration_offset_ = 0;
|
||||||
|
|
||||||
eng::ImageQuad boss_;
|
eng::ImageQuad boss_;
|
||||||
|
@ -165,6 +169,7 @@ class Enemy {
|
||||||
std::unique_ptr<eng::Image> GetScoreImage(EnemyType enemy_type);
|
std::unique_ptr<eng::Image> GetScoreImage(EnemyType enemy_type);
|
||||||
|
|
||||||
bool CreateRenderResources();
|
bool CreateRenderResources();
|
||||||
|
bool CreateShaders();
|
||||||
|
|
||||||
void TranslateEnemyUnit(EnemyUnit& e, const base::Vector2f& delta);
|
void TranslateEnemyUnit(EnemyUnit& e, const base::Vector2f& delta);
|
||||||
};
|
};
|
||||||
|
|
|
@ -6,12 +6,14 @@
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
#include "engine/renderer/geometry.h"
|
#include "engine/renderer/geometry.h"
|
||||||
#include "engine/renderer/shader.h"
|
#include "engine/renderer/shader.h"
|
||||||
|
#include "engine/shader_source.h"
|
||||||
|
|
||||||
using namespace base;
|
using namespace base;
|
||||||
using namespace eng;
|
using namespace eng;
|
||||||
|
|
||||||
SkyQuad::SkyQuad()
|
SkyQuad::SkyQuad()
|
||||||
: sky_offset_{
|
: shader_(Engine::Get().CreateRenderResource<Shader>()),
|
||||||
|
sky_offset_{
|
||||||
0, Lerp(0.0f, 10.0f, Engine::Get().GetRandomGenerator().Rand())} {
|
0, Lerp(0.0f, 10.0f, Engine::Get().GetRandomGenerator().Rand())} {
|
||||||
last_sky_offset_ = sky_offset_;
|
last_sky_offset_ = sky_offset_;
|
||||||
}
|
}
|
||||||
|
@ -20,9 +22,10 @@ SkyQuad::~SkyQuad() = default;
|
||||||
|
|
||||||
bool SkyQuad::Create(bool without_nebula) {
|
bool SkyQuad::Create(bool without_nebula) {
|
||||||
without_nebula_ = without_nebula;
|
without_nebula_ = without_nebula;
|
||||||
|
if (!CreateShaders())
|
||||||
|
return false;
|
||||||
|
|
||||||
scale_ = Engine::Get().GetScreenSize();
|
scale_ = Engine::Get().GetScreenSize();
|
||||||
shader_ = Engine::Get().GetCustomShader(
|
|
||||||
without_nebula ? "sky_without_nebula" : "sky");
|
|
||||||
|
|
||||||
color_animator_.Attach(this);
|
color_animator_.Attach(this);
|
||||||
|
|
||||||
|
@ -51,6 +54,10 @@ void SkyQuad::Draw(float frame_frac) {
|
||||||
Engine::Get().GetQuad()->Draw();
|
Engine::Get().GetQuad()->Draw();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkyQuad::ContextLost() {
|
||||||
|
CreateShaders();
|
||||||
|
}
|
||||||
|
|
||||||
void SkyQuad::SwitchColor(const Vector4f& color) {
|
void SkyQuad::SwitchColor(const Vector4f& color) {
|
||||||
color_animator_.Pause(Animator::kBlending);
|
color_animator_.Pause(Animator::kBlending);
|
||||||
color_animator_.SetTime(Animator::kBlending, 0);
|
color_animator_.SetTime(Animator::kBlending, 0);
|
||||||
|
@ -59,6 +66,17 @@ void SkyQuad::SwitchColor(const Vector4f& color) {
|
||||||
color_animator_.Play(Animator::kBlending, false);
|
color_animator_.Play(Animator::kBlending, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SkyQuad::CreateShaders() {
|
||||||
|
Engine& engine = Engine::Get();
|
||||||
|
|
||||||
|
auto source = std::make_unique<ShaderSource>();
|
||||||
|
if (!source->Load(without_nebula_ ? "sky_without_nebula.glsl" : "sky.glsl"))
|
||||||
|
return false;
|
||||||
|
shader_->Create(std::move(source), engine.GetQuad()->vertex_description(),
|
||||||
|
Engine::Get().GetQuad()->primitive(), false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void SkyQuad::SetSpeed(float speed) {
|
void SkyQuad::SetSpeed(float speed) {
|
||||||
speed_ = speed;
|
speed_ = speed;
|
||||||
}
|
}
|
|
@ -36,6 +36,8 @@ class SkyQuad : public eng::Animatable {
|
||||||
// Drawable interface.
|
// Drawable interface.
|
||||||
void Draw(float frame_frac) final;
|
void Draw(float frame_frac) final;
|
||||||
|
|
||||||
|
void ContextLost();
|
||||||
|
|
||||||
void SwitchColor(const base::Vector4f& color);
|
void SwitchColor(const base::Vector4f& color);
|
||||||
|
|
||||||
void SetSpeed(float speed);
|
void SetSpeed(float speed);
|
||||||
|
@ -43,7 +45,7 @@ class SkyQuad : public eng::Animatable {
|
||||||
const base::Vector4f& nebula_color() { return nebula_color_; }
|
const base::Vector4f& nebula_color() { return nebula_color_; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
eng::Shader* shader_;
|
std::unique_ptr<eng::Shader> shader_;
|
||||||
|
|
||||||
base::Vector2f sky_offset_ = {0, 0};
|
base::Vector2f sky_offset_ = {0, 0};
|
||||||
base::Vector2f last_sky_offset_ = {0, 0};
|
base::Vector2f last_sky_offset_ = {0, 0};
|
||||||
|
@ -55,6 +57,8 @@ class SkyQuad : public eng::Animatable {
|
||||||
float speed_ = 0;
|
float speed_ = 0;
|
||||||
|
|
||||||
bool without_nebula_ = false;
|
bool without_nebula_ = false;
|
||||||
|
|
||||||
|
bool CreateShaders();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // DEMO_SKY_QUAD_H
|
#endif // DEMO_SKY_QUAD_H
|
||||||
|
|
|
@ -126,10 +126,10 @@ void Animator::SetMovement(Vector2f direction,
|
||||||
a.movement_last_pos = {0, 0};
|
a.movement_last_pos = {0, 0};
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animator::SetRotation(float target,
|
void Animator::SetRotation(float trget,
|
||||||
float duration,
|
float duration,
|
||||||
Interpolator interpolator) {
|
Interpolator interpolator) {
|
||||||
rotation_target_ = target;
|
rotation_target_ = trget;
|
||||||
rotation_speed_ = 1.0f / duration;
|
rotation_speed_ = 1.0f / duration;
|
||||||
rotation_interpolator_ = std::move(interpolator);
|
rotation_interpolator_ = std::move(interpolator);
|
||||||
|
|
||||||
|
@ -153,7 +153,7 @@ void Animator::SetFrames(int count,
|
||||||
frame_count_ = count;
|
frame_count_ = count;
|
||||||
frame_speed_ = (float)frames_per_second / (float)count;
|
frame_speed_ = (float)frames_per_second / (float)count;
|
||||||
for (auto& a : elements_)
|
for (auto& a : elements_)
|
||||||
a.frame_start = a.animatable->GetFrame();
|
a.frame_start_ = a.animatable->GetFrame();
|
||||||
frame_interpolator_ = std::move(interpolator);
|
frame_interpolator_ = std::move(interpolator);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -180,43 +180,66 @@ void Animator::Update(float delta_time) {
|
||||||
UpdateAnimTime(delta_time, kFrames, frame_speed_, frame_time_, frame_cb_);
|
UpdateAnimTime(delta_time, kFrames, frame_speed_, frame_time_, frame_cb_);
|
||||||
if (play_flags_ & kTimer)
|
if (play_flags_ & kTimer)
|
||||||
UpdateAnimTime(delta_time, kTimer, timer_speed_, timer_time_, timer_cb_);
|
UpdateAnimTime(delta_time, kTimer, timer_speed_, timer_time_, timer_cb_);
|
||||||
|
|
||||||
|
did_evaluate_ = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animator::Evaluate(float frame_frac) {
|
void Animator::Evaluate(float frame_frac_time) {
|
||||||
if (play_flags_ & kMovement)
|
did_evaluate_ = true;
|
||||||
EvaluateAnimation<Vector2f, true>(
|
|
||||||
frame_frac, movement_speed_, movement_time_, movement_interpolator_,
|
|
||||||
movement_direction_, [](Element& a, Vector2f pos) {
|
|
||||||
a.animatable->Translate(pos - a.movement_last_pos);
|
|
||||||
a.movement_last_pos = pos;
|
|
||||||
});
|
|
||||||
|
|
||||||
if (play_flags_ & kRotation)
|
Vector2f pos = {0, 0};
|
||||||
EvaluateAnimation<float, true>(
|
if (play_flags_ & kMovement) {
|
||||||
frame_frac, rotation_speed_, rotation_time_, rotation_interpolator_,
|
float time = movement_time_ + movement_speed_ * frame_frac_time;
|
||||||
rotation_target_, [](Element& a, float theta) {
|
float interpolated_time =
|
||||||
a.animatable->Rotate(theta - a.rotation_last_theta);
|
movement_interpolator_ ? movement_interpolator_(time) : time;
|
||||||
a.rotation_last_theta = theta;
|
pos = base::Lerp({0, 0}, movement_direction_, interpolated_time);
|
||||||
});
|
}
|
||||||
|
|
||||||
if (play_flags_ & kBlending)
|
float theta = 0;
|
||||||
EvaluateAnimation<float, false>(
|
if (play_flags_ & kRotation) {
|
||||||
frame_frac, blending_speed_, blending_time_, blending_interpolator_, {},
|
float time = rotation_time_ + rotation_speed_ * frame_frac_time;
|
||||||
[&](Element& a, float interpolated_time) {
|
float interpolated_time =
|
||||||
Vector4f blending =
|
rotation_interpolator_ ? rotation_interpolator_(time) : time;
|
||||||
base::Lerp(a.blending_start, blending_target_, interpolated_time);
|
theta = base::Lerp(0.0f, rotation_target_, interpolated_time);
|
||||||
a.animatable->SetColor(blending);
|
}
|
||||||
});
|
|
||||||
|
|
||||||
if (play_flags_ & kFrames)
|
float blending_itime = 0;
|
||||||
EvaluateAnimation<float, false>(
|
if (play_flags_ & kBlending) {
|
||||||
frame_frac, frame_speed_, frame_time_, frame_interpolator_, {},
|
float time = blending_time_ + blending_speed_ * frame_frac_time;
|
||||||
[&](Element& a, float interpolated_time) {
|
blending_itime =
|
||||||
int target = a.frame_start + frame_count_;
|
blending_interpolator_ ? blending_interpolator_(time) : time;
|
||||||
int frame = base::Lerp(a.frame_start, target, interpolated_time);
|
}
|
||||||
if (frame < target)
|
|
||||||
a.animatable->SetFrame(frame);
|
float frame_itime = 0;
|
||||||
});
|
if (play_flags_ & kFrames) {
|
||||||
|
float time = frame_time_ + frame_speed_ * frame_frac_time;
|
||||||
|
frame_itime = frame_interpolator_ ? frame_interpolator_(time) : time;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto& a : elements_) {
|
||||||
|
if (play_flags_ & kMovement) {
|
||||||
|
a.animatable->Translate(pos - a.movement_last_pos);
|
||||||
|
a.movement_last_pos = pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (play_flags_ & kRotation) {
|
||||||
|
a.animatable->Rotate(theta - a.rotation_last_theta);
|
||||||
|
a.rotation_last_theta = theta;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (play_flags_ & kBlending) {
|
||||||
|
Vector4f blending =
|
||||||
|
base::Lerp(a.blending_start, blending_target_, blending_itime);
|
||||||
|
a.animatable->SetColor(blending);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (play_flags_ & kFrames) {
|
||||||
|
int target = a.frame_start_ + frame_count_;
|
||||||
|
int frame = base::Lerp(a.frame_start_, target, frame_itime);
|
||||||
|
if (frame < target)
|
||||||
|
a.animatable->SetFrame(frame);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Animator::UpdateAnimTime(float delta_time,
|
void Animator::UpdateAnimTime(float delta_time,
|
||||||
|
@ -229,8 +252,8 @@ void Animator::UpdateAnimTime(float delta_time,
|
||||||
if (loop_flags_ & anim) {
|
if (loop_flags_ & anim) {
|
||||||
anim_time = fmod(anim_time, 1.0f);
|
anim_time = fmod(anim_time, 1.0f);
|
||||||
} else {
|
} else {
|
||||||
anim_time = 1.0f;
|
if (!did_evaluate_)
|
||||||
Evaluate(0);
|
Evaluate(0);
|
||||||
anim_time = 0;
|
anim_time = 0;
|
||||||
play_flags_ &= ~anim;
|
play_flags_ &= ~anim;
|
||||||
if (cb) {
|
if (cb) {
|
||||||
|
@ -246,24 +269,4 @@ void Animator::UpdateAnimTime(float delta_time,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename T, bool relative>
|
|
||||||
void Animator::EvaluateAnimation(float frame_frac,
|
|
||||||
float anim_speed,
|
|
||||||
float anim_time,
|
|
||||||
Interpolator& interpolator,
|
|
||||||
T target,
|
|
||||||
ResultSetter<T> set_result) {
|
|
||||||
float time = anim_time + anim_speed * frame_frac;
|
|
||||||
float interpolated_time = interpolator ? interpolator(time) : time;
|
|
||||||
|
|
||||||
if constexpr (relative) {
|
|
||||||
T result = base::Lerp(T{0}, target, interpolated_time);
|
|
||||||
for (auto& a : elements_)
|
|
||||||
set_result(a, result);
|
|
||||||
} else {
|
|
||||||
for (auto& a : elements_)
|
|
||||||
set_result(a, interpolated_time);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
|
@ -40,7 +40,7 @@ class Animator {
|
||||||
float GetTime(int animation);
|
float GetTime(int animation);
|
||||||
void SetTime(int animation, float time, bool force_update = false);
|
void SetTime(int animation, float time, bool force_update = false);
|
||||||
|
|
||||||
// Set callback to be called once animation ends.
|
// Set callback ro be called once animation ends.
|
||||||
void SetEndCallback(int animation, base::Closure cb);
|
void SetEndCallback(int animation, base::Closure cb);
|
||||||
|
|
||||||
// Distance is the magnitude of direction vector. Duration is in seconds.
|
// Distance is the magnitude of direction vector. Duration is in seconds.
|
||||||
|
@ -69,7 +69,7 @@ class Animator {
|
||||||
void SetVisible(bool visible);
|
void SetVisible(bool visible);
|
||||||
|
|
||||||
void Update(float delta_time);
|
void Update(float delta_time);
|
||||||
void Evaluate(float frame_frac);
|
void Evaluate(float frame_frac_time);
|
||||||
|
|
||||||
bool IsPlaying(int animation) const { return play_flags_ & animation; }
|
bool IsPlaying(int animation) const { return play_flags_ & animation; }
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ class Animator {
|
||||||
base::Vector2f movement_last_pos = {0, 0};
|
base::Vector2f movement_last_pos = {0, 0};
|
||||||
float rotation_last_theta = 0;
|
float rotation_last_theta = 0;
|
||||||
base::Vector4f blending_start = {0, 0, 0, 0};
|
base::Vector4f blending_start = {0, 0, 0, 0};
|
||||||
int frame_start = 0;
|
int frame_start_ = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
unsigned int play_flags_ = 0;
|
unsigned int play_flags_ = 0;
|
||||||
|
@ -120,22 +120,13 @@ class Animator {
|
||||||
base::Closure pending_cb_;
|
base::Closure pending_cb_;
|
||||||
Flags inside_cb_ = kNone;
|
Flags inside_cb_ = kNone;
|
||||||
|
|
||||||
|
bool did_evaluate_ = false;
|
||||||
|
|
||||||
void UpdateAnimTime(float delta_time,
|
void UpdateAnimTime(float delta_time,
|
||||||
int anim,
|
int anim,
|
||||||
float anim_speed,
|
float anim_speed,
|
||||||
float& anim_time,
|
float& anim_time,
|
||||||
base::Closure& cb);
|
base::Closure& cb);
|
||||||
|
|
||||||
template <typename T>
|
|
||||||
using ResultSetter = std::function<void(Element&, T)>;
|
|
||||||
|
|
||||||
template <typename T, bool relative>
|
|
||||||
void EvaluateAnimation(float frame_frac,
|
|
||||||
float anim_speed,
|
|
||||||
float anim_time,
|
|
||||||
Interpolator& interpolator,
|
|
||||||
T target,
|
|
||||||
ResultSetter<T> set_result);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
#ifndef ENGINE_AUDIO_AUDIO_H
|
||||||
|
#define ENGINE_AUDIO_AUDIO_H
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
#include "engine/audio/audio_oboe.h"
|
||||||
|
#elif defined(__linux__)
|
||||||
|
#include "engine/audio/audio_alsa.h"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace eng {
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
using Audio = AudioOboe;
|
||||||
|
#elif defined(__linux__)
|
||||||
|
using Audio = AudioAlsa;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace eng
|
||||||
|
|
||||||
|
#endif // ENGINE_AUDIO_AUDIO_H
|
|
@ -1,26 +1,20 @@
|
||||||
#include "engine/audio/audio_driver_alsa.h"
|
#include "engine/audio/audio_alsa.h"
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include <alsa/asoundlib.h>
|
#include <alsa/asoundlib.h>
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
#include "engine/audio/audio_driver_delegate.h"
|
|
||||||
|
|
||||||
using namespace base;
|
using namespace base;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
AudioDriverAlsa::AudioDriverAlsa() = default;
|
AudioAlsa::AudioAlsa() = default;
|
||||||
|
|
||||||
AudioDriverAlsa::~AudioDriverAlsa() = default;
|
AudioAlsa::~AudioAlsa() = default;
|
||||||
|
|
||||||
void AudioDriverAlsa::SetDelegate(AudioDriverDelegate* delegate) {
|
bool AudioAlsa::Initialize() {
|
||||||
delegate_ = delegate;
|
|
||||||
Resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AudioDriverAlsa::Initialize() {
|
|
||||||
LOG << "Initializing audio system.";
|
LOG << "Initializing audio system.";
|
||||||
|
|
||||||
int err;
|
int err;
|
||||||
|
@ -142,43 +136,51 @@ bool AudioDriverAlsa::Initialize() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverAlsa::Shutdown() {
|
void AudioAlsa::Shutdown() {
|
||||||
LOG << "Shutting down audio system.";
|
LOG << "Shutting down audio system.";
|
||||||
|
|
||||||
TerminateAudioThread();
|
TerminateAudioThread();
|
||||||
snd_pcm_drop(device_);
|
snd_pcm_drop(device_);
|
||||||
snd_pcm_close(device_);
|
snd_pcm_close(device_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverAlsa::Suspend() {
|
void AudioAlsa::Suspend() {
|
||||||
|
DCHECK(!terminate_audio_thread_.load(std::memory_order_relaxed));
|
||||||
|
|
||||||
suspend_audio_thread_.store(true, std::memory_order_relaxed);
|
suspend_audio_thread_.store(true, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverAlsa::Resume() {
|
void AudioAlsa::Resume() {
|
||||||
|
DCHECK(!terminate_audio_thread_.load(std::memory_order_relaxed));
|
||||||
|
|
||||||
suspend_audio_thread_.store(false, std::memory_order_relaxed);
|
suspend_audio_thread_.store(false, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
int AudioDriverAlsa::GetHardwareSampleRate() {
|
int AudioAlsa::GetHardwareSampleRate() {
|
||||||
return sample_rate_;
|
return sample_rate_;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverAlsa::StartAudioThread() {
|
void AudioAlsa::StartAudioThread() {
|
||||||
LOG << "Starting audio thread.";
|
LOG << "Starting audio thread.";
|
||||||
terminate_audio_thread_.store(false, std::memory_order_relaxed);
|
|
||||||
suspend_audio_thread_.store(true, std::memory_order_relaxed);
|
DCHECK(!terminate_audio_thread_.load(std::memory_order_relaxed));
|
||||||
audio_thread_ = std::thread(&AudioDriverAlsa::AudioThreadMain, this);
|
|
||||||
|
audio_thread_ = std::thread(&AudioAlsa::AudioThreadMain, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverAlsa::TerminateAudioThread() {
|
void AudioAlsa::TerminateAudioThread() {
|
||||||
if (terminate_audio_thread_.load(std::memory_order_relaxed))
|
if (terminate_audio_thread_.load(std::memory_order_relaxed))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LOG << "Terminating audio thread";
|
LOG << "Terminating audio thread";
|
||||||
|
|
||||||
|
// Notify worker thread and wait for it to terminate.
|
||||||
terminate_audio_thread_.store(true, std::memory_order_relaxed);
|
terminate_audio_thread_.store(true, std::memory_order_relaxed);
|
||||||
suspend_audio_thread_.store(true, std::memory_order_relaxed);
|
suspend_audio_thread_.store(true, std::memory_order_relaxed);
|
||||||
audio_thread_.join();
|
audio_thread_.join();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverAlsa::AudioThreadMain() {
|
void AudioAlsa::AudioThreadMain() {
|
||||||
size_t num_frames = period_size_ / (num_channels_ * sizeof(float));
|
size_t num_frames = period_size_ / (num_channels_ * sizeof(float));
|
||||||
auto buffer = std::make_unique<float[]>(num_frames * 2);
|
auto buffer = std::make_unique<float[]>(num_frames * 2);
|
||||||
|
|
||||||
|
@ -190,11 +192,11 @@ void AudioDriverAlsa::AudioThreadMain() {
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
std::this_thread::sleep_for(std::chrono::milliseconds(1));
|
||||||
}
|
}
|
||||||
|
|
||||||
delegate_->RenderAudio(buffer.get(), num_frames);
|
RenderAudio(buffer.get(), num_frames);
|
||||||
|
|
||||||
while (snd_pcm_writei(device_, buffer.get(), num_frames) < 0) {
|
while (snd_pcm_writei(device_, buffer.get(), num_frames) < 0) {
|
||||||
snd_pcm_prepare(device_);
|
snd_pcm_prepare(device_);
|
||||||
DLOG << "Alsa buffer underrun!";
|
DLOG << "Audio buffer underrun!";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
#ifndef ENGINE_AUDIO_AUDIO_ALSA_H
|
||||||
|
#define ENGINE_AUDIO_AUDIO_ALSA_H
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include "engine/audio/audio_base.h"
|
||||||
|
|
||||||
|
typedef struct _snd_pcm snd_pcm_t;
|
||||||
|
|
||||||
|
namespace eng {
|
||||||
|
|
||||||
|
class AudioAlsa : public AudioBase {
|
||||||
|
public:
|
||||||
|
AudioAlsa();
|
||||||
|
~AudioAlsa();
|
||||||
|
|
||||||
|
bool Initialize();
|
||||||
|
|
||||||
|
void Shutdown();
|
||||||
|
|
||||||
|
void Suspend();
|
||||||
|
void Resume();
|
||||||
|
|
||||||
|
int GetHardwareSampleRate();
|
||||||
|
|
||||||
|
private:
|
||||||
|
// Handle for the PCM device.
|
||||||
|
snd_pcm_t* device_;
|
||||||
|
|
||||||
|
std::thread audio_thread_;
|
||||||
|
std::atomic<bool> terminate_audio_thread_{false};
|
||||||
|
std::atomic<bool> suspend_audio_thread_{false};
|
||||||
|
|
||||||
|
size_t num_channels_ = 0;
|
||||||
|
int sample_rate_ = 0;
|
||||||
|
size_t period_size_ = 0;
|
||||||
|
|
||||||
|
void StartAudioThread();
|
||||||
|
void TerminateAudioThread();
|
||||||
|
|
||||||
|
void AudioThreadMain();
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace eng
|
||||||
|
|
||||||
|
#endif // ENGINE_AUDIO_AUDIO_ALSA_H
|
|
@ -1,4 +1,4 @@
|
||||||
#include "engine/audio/audio_mixer.h"
|
#include "engine/audio/audio.h"
|
||||||
|
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
@ -11,33 +11,30 @@ using namespace base;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
AudioMixer::AudioMixer()
|
AudioBase::AudioBase()
|
||||||
: main_thread_task_runner_(TaskRunner::GetThreadLocalTaskRunner()) {}
|
: main_thread_task_runner_(TaskRunner::GetThreadLocalTaskRunner()) {}
|
||||||
|
|
||||||
AudioMixer::~AudioMixer() = default;
|
AudioBase::~AudioBase() = default;
|
||||||
|
|
||||||
uint64_t AudioMixer::CreateResource() {
|
uint64_t AudioBase::CreateResource() {
|
||||||
uint64_t resource_id = ++last_resource_id_;
|
uint64_t resource_id = ++last_resource_id_;
|
||||||
resources_[resource_id] = std::make_shared<Resource>();
|
resources_[resource_id] = std::make_shared<Resource>();
|
||||||
return resource_id;
|
return resource_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixer::DestroyResource(uint64_t resource_id) {
|
void AudioBase::DestroyResource(uint64_t resource_id) {
|
||||||
auto it = resources_.find(resource_id);
|
auto it = resources_.find(resource_id);
|
||||||
if (it == resources_.end())
|
if (it == resources_.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (it->second->active) {
|
it->second->flags.fetch_or(kStopped, std::memory_order_relaxed);
|
||||||
it->second->restart_cb = nullptr;
|
|
||||||
it->second->flags.fetch_or(kStopped, std::memory_order_relaxed);
|
|
||||||
}
|
|
||||||
resources_.erase(it);
|
resources_.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixer::Play(uint64_t resource_id,
|
void AudioBase::Play(uint64_t resource_id,
|
||||||
std::shared_ptr<Sound> sound,
|
std::shared_ptr<Sound> sound,
|
||||||
float amplitude,
|
float amplitude,
|
||||||
bool reset_pos) {
|
bool reset_pos) {
|
||||||
if (!audio_enabled_)
|
if (!audio_enabled_)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -49,11 +46,15 @@ void AudioMixer::Play(uint64_t resource_id,
|
||||||
if (reset_pos)
|
if (reset_pos)
|
||||||
it->second->flags.fetch_or(kStopped, std::memory_order_relaxed);
|
it->second->flags.fetch_or(kStopped, std::memory_order_relaxed);
|
||||||
|
|
||||||
if (it->second->flags.load(std::memory_order_relaxed) & kStopped)
|
if (it->second->flags.load(std::memory_order_relaxed) & kStopped) {
|
||||||
it->second->restart_cb = [&, resource_id, sound, amplitude,
|
Closure ocb = std::move(it->second->end_cb);
|
||||||
reset_pos]() -> void {
|
SetEndCallback(
|
||||||
Play(resource_id, sound, amplitude, reset_pos);
|
resource_id,
|
||||||
};
|
[&, resource_id, sound, amplitude, reset_pos, ocb]() -> void {
|
||||||
|
Play(resource_id, sound, amplitude, reset_pos);
|
||||||
|
SetEndCallback(resource_id, std::move(ocb));
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -74,18 +75,16 @@ void AudioMixer::Play(uint64_t resource_id,
|
||||||
play_list_[0].push_back(it->second);
|
play_list_[0].push_back(it->second);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixer::Stop(uint64_t resource_id) {
|
void AudioBase::Stop(uint64_t resource_id) {
|
||||||
auto it = resources_.find(resource_id);
|
auto it = resources_.find(resource_id);
|
||||||
if (it == resources_.end())
|
if (it == resources_.end())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (it->second->active) {
|
if (it->second->active)
|
||||||
it->second->restart_cb = nullptr;
|
|
||||||
it->second->flags.fetch_or(kStopped, std::memory_order_relaxed);
|
it->second->flags.fetch_or(kStopped, std::memory_order_relaxed);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixer::SetLoop(uint64_t resource_id, bool loop) {
|
void AudioBase::SetLoop(uint64_t resource_id, bool loop) {
|
||||||
auto it = resources_.find(resource_id);
|
auto it = resources_.find(resource_id);
|
||||||
if (it == resources_.end())
|
if (it == resources_.end())
|
||||||
return;
|
return;
|
||||||
|
@ -96,7 +95,7 @@ void AudioMixer::SetLoop(uint64_t resource_id, bool loop) {
|
||||||
it->second->flags.fetch_and(~kLoop, std::memory_order_relaxed);
|
it->second->flags.fetch_and(~kLoop, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixer::SetSimulateStereo(uint64_t resource_id, bool simulate) {
|
void AudioBase::SetSimulateStereo(uint64_t resource_id, bool simulate) {
|
||||||
auto it = resources_.find(resource_id);
|
auto it = resources_.find(resource_id);
|
||||||
if (it == resources_.end())
|
if (it == resources_.end())
|
||||||
return;
|
return;
|
||||||
|
@ -107,7 +106,7 @@ void AudioMixer::SetSimulateStereo(uint64_t resource_id, bool simulate) {
|
||||||
it->second->flags.fetch_and(~kSimulateStereo, std::memory_order_relaxed);
|
it->second->flags.fetch_and(~kSimulateStereo, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixer::SetResampleStep(uint64_t resource_id, size_t step) {
|
void AudioBase::SetResampleStep(uint64_t resource_id, size_t step) {
|
||||||
auto it = resources_.find(resource_id);
|
auto it = resources_.find(resource_id);
|
||||||
if (it == resources_.end())
|
if (it == resources_.end())
|
||||||
return;
|
return;
|
||||||
|
@ -115,7 +114,7 @@ void AudioMixer::SetResampleStep(uint64_t resource_id, size_t step) {
|
||||||
it->second->step.store(step + 100, std::memory_order_relaxed);
|
it->second->step.store(step + 100, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixer::SetMaxAmplitude(uint64_t resource_id, float max_amplitude) {
|
void AudioBase::SetMaxAmplitude(uint64_t resource_id, float max_amplitude) {
|
||||||
auto it = resources_.find(resource_id);
|
auto it = resources_.find(resource_id);
|
||||||
if (it == resources_.end())
|
if (it == resources_.end())
|
||||||
return;
|
return;
|
||||||
|
@ -123,7 +122,7 @@ void AudioMixer::SetMaxAmplitude(uint64_t resource_id, float max_amplitude) {
|
||||||
it->second->max_amplitude.store(max_amplitude, std::memory_order_relaxed);
|
it->second->max_amplitude.store(max_amplitude, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixer::SetAmplitudeInc(uint64_t resource_id, float amplitude_inc) {
|
void AudioBase::SetAmplitudeInc(uint64_t resource_id, float amplitude_inc) {
|
||||||
auto it = resources_.find(resource_id);
|
auto it = resources_.find(resource_id);
|
||||||
if (it == resources_.end())
|
if (it == resources_.end())
|
||||||
return;
|
return;
|
||||||
|
@ -131,7 +130,7 @@ void AudioMixer::SetAmplitudeInc(uint64_t resource_id, float amplitude_inc) {
|
||||||
it->second->amplitude_inc.store(amplitude_inc, std::memory_order_relaxed);
|
it->second->amplitude_inc.store(amplitude_inc, std::memory_order_relaxed);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixer::SetEndCallback(uint64_t resource_id, base::Closure cb) {
|
void AudioBase::SetEndCallback(uint64_t resource_id, base::Closure cb) {
|
||||||
auto it = resources_.find(resource_id);
|
auto it = resources_.find(resource_id);
|
||||||
if (it == resources_.end())
|
if (it == resources_.end())
|
||||||
return;
|
return;
|
||||||
|
@ -139,7 +138,7 @@ void AudioMixer::SetEndCallback(uint64_t resource_id, base::Closure cb) {
|
||||||
it->second->end_cb = std::move(cb);
|
it->second->end_cb = std::move(cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) {
|
void AudioBase::RenderAudio(float* output_buffer, size_t num_frames) {
|
||||||
{
|
{
|
||||||
std::unique_lock<std::mutex> scoped_lock(lock_, std::try_to_lock);
|
std::unique_lock<std::mutex> scoped_lock(lock_, std::try_to_lock);
|
||||||
if (scoped_lock)
|
if (scoped_lock)
|
||||||
|
@ -208,18 +207,20 @@ void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) {
|
||||||
|
|
||||||
// Remove, loop or stream if the source data is consumed
|
// Remove, loop or stream if the source data is consumed
|
||||||
if (src_index >= num_samples) {
|
if (src_index >= num_samples) {
|
||||||
if (num_samples)
|
if (!sound->is_streaming_sound()) {
|
||||||
src_index %= num_samples;
|
src_index %= num_samples;
|
||||||
|
|
||||||
if (!sound->is_streaming_sound()) {
|
|
||||||
if (!(flags & kLoop)) {
|
if (!(flags & kLoop)) {
|
||||||
marked_for_removal = true;
|
marked_for_removal = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
} else if (!it->get()->streaming_in_progress.load(
|
} else if (!it->get()->streaming_in_progress.load(
|
||||||
std::memory_order_acquire)) {
|
std::memory_order_acquire)) {
|
||||||
|
if (num_samples)
|
||||||
|
src_index %= num_samples;
|
||||||
|
|
||||||
|
// Looping streaming sounds never return eof.
|
||||||
if (sound->eof()) {
|
if (sound->eof()) {
|
||||||
DCHECK((flags & kLoop) == 0);
|
|
||||||
marked_for_removal = true;
|
marked_for_removal = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -237,9 +238,10 @@ void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) {
|
||||||
|
|
||||||
ThreadPool::Get().PostTask(
|
ThreadPool::Get().PostTask(
|
||||||
HERE,
|
HERE,
|
||||||
std::bind(&AudioMixer::DoStream, this, *it, flags & kLoop));
|
std::bind(&AudioBase::DoStream, this, *it, flags & kLoop));
|
||||||
} else if (num_samples) {
|
} else if (num_samples) {
|
||||||
DLOG << "Mixer buffer underrun!";
|
DLOG << "Buffer underrun!";
|
||||||
|
src_index %= num_samples;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -261,7 +263,7 @@ void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) {
|
||||||
if ((!it->get()->sound->is_streaming_sound() ||
|
if ((!it->get()->sound->is_streaming_sound() ||
|
||||||
!it->get()->streaming_in_progress.load(std::memory_order_relaxed))) {
|
!it->get()->streaming_in_progress.load(std::memory_order_relaxed))) {
|
||||||
main_thread_task_runner_->PostTask(
|
main_thread_task_runner_->PostTask(
|
||||||
HERE, std::bind(&AudioMixer::EndCallback, this, *it));
|
HERE, std::bind(&AudioBase::EndCallback, this, *it));
|
||||||
it = end_list_.erase(it);
|
it = end_list_.erase(it);
|
||||||
} else {
|
} else {
|
||||||
++it;
|
++it;
|
||||||
|
@ -269,20 +271,19 @@ void AudioMixer::RenderAudio(float* output_buffer, size_t num_frames) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixer::DoStream(std::shared_ptr<Resource> resource, bool loop) {
|
void AudioBase::DoStream(std::shared_ptr<Resource> resource, bool loop) {
|
||||||
resource->sound->Stream(loop);
|
resource->sound->Stream(loop);
|
||||||
|
|
||||||
|
// Memory barrier to ensure all memory writes become visible to the audio
|
||||||
|
// thread.
|
||||||
resource->streaming_in_progress.store(false, std::memory_order_release);
|
resource->streaming_in_progress.store(false, std::memory_order_release);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioMixer::EndCallback(std::shared_ptr<Resource> resource) {
|
void AudioBase::EndCallback(std::shared_ptr<Resource> resource) {
|
||||||
resource->active = false;
|
resource->active = false;
|
||||||
|
|
||||||
if (resource->end_cb)
|
if (resource->end_cb)
|
||||||
resource->end_cb();
|
resource->end_cb();
|
||||||
if (resource->restart_cb) {
|
|
||||||
resource->restart_cb();
|
|
||||||
resource->restart_cb = nullptr;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
|
@ -1,14 +1,12 @@
|
||||||
#ifndef ENGINE_AUDIO_AUDIO_MIXER_H
|
#ifndef ENGINE_AUDIO_AUDIO_BASE_H
|
||||||
#define ENGINE_AUDIO_AUDIO_MIXER_H
|
#define ENGINE_AUDIO_AUDIO_BASE_H
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include "base/closure.h"
|
#include "base/closure.h"
|
||||||
#include "engine/audio/audio_driver_delegate.h"
|
|
||||||
|
|
||||||
namespace base {
|
namespace base {
|
||||||
class TaskRunner;
|
class TaskRunner;
|
||||||
|
@ -18,14 +16,11 @@ namespace eng {
|
||||||
|
|
||||||
class Sound;
|
class Sound;
|
||||||
|
|
||||||
// Mix and render audio with low overhead. A platform specific AudioDriver
|
// Class representing the end-point for rendered audio. A platform specific
|
||||||
// implementation is expected to periodically call Render() in a background
|
// implementation is expected to periodically call RenderAudio() in a background
|
||||||
// thread.
|
// thread.
|
||||||
class AudioMixer : public AudioDriverDelegate {
|
class AudioBase {
|
||||||
public:
|
public:
|
||||||
AudioMixer();
|
|
||||||
~AudioMixer();
|
|
||||||
|
|
||||||
uint64_t CreateResource();
|
uint64_t CreateResource();
|
||||||
void DestroyResource(uint64_t resource_id);
|
void DestroyResource(uint64_t resource_id);
|
||||||
|
|
||||||
|
@ -44,15 +39,21 @@ class AudioMixer : public AudioDriverDelegate {
|
||||||
|
|
||||||
void SetEnableAudio(bool enable) { audio_enabled_ = enable; }
|
void SetEnableAudio(bool enable) { audio_enabled_ = enable; }
|
||||||
|
|
||||||
|
protected:
|
||||||
|
static constexpr int kChannelCount = 2;
|
||||||
|
|
||||||
|
AudioBase();
|
||||||
|
~AudioBase();
|
||||||
|
|
||||||
|
void RenderAudio(float* output_buffer, size_t num_frames);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
enum SampleFlags { kLoop = 1, kStopped = 2, kSimulateStereo = 4 };
|
enum SampleFlags { kLoop = 1, kStopped = 2, kSimulateStereo = 4 };
|
||||||
static constexpr int kChannelCount = 2;
|
|
||||||
|
|
||||||
struct Resource {
|
struct Resource {
|
||||||
// Accessed by main thread only.
|
// Accessed by main thread only.
|
||||||
bool active = false;
|
bool active = false;
|
||||||
base::Closure end_cb;
|
base::Closure end_cb;
|
||||||
base::Closure restart_cb;
|
|
||||||
|
|
||||||
// Initialized by main thread, used by audio thread.
|
// Initialized by main thread, used by audio thread.
|
||||||
std::shared_ptr<Sound> sound;
|
std::shared_ptr<Sound> sound;
|
||||||
|
@ -82,17 +83,14 @@ class AudioMixer : public AudioDriverDelegate {
|
||||||
|
|
||||||
bool audio_enabled_ = true;
|
bool audio_enabled_ = true;
|
||||||
|
|
||||||
// AudioDriverDelegate implementation
|
|
||||||
void RenderAudio(float* output_buffer, size_t num_frames) final;
|
|
||||||
|
|
||||||
void DoStream(std::shared_ptr<Resource> sample, bool loop);
|
void DoStream(std::shared_ptr<Resource> sample, bool loop);
|
||||||
|
|
||||||
void EndCallback(std::shared_ptr<Resource> sample);
|
void EndCallback(std::shared_ptr<Resource> sample);
|
||||||
|
|
||||||
AudioMixer(const AudioMixer&) = delete;
|
AudioBase(const AudioBase&) = delete;
|
||||||
AudioMixer& operator=(const AudioMixer&) = delete;
|
AudioBase& operator=(const AudioBase&) = delete;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
||||||
#endif // ENGINE_AUDIO_AUDIO_MIXER_H
|
#endif // ENGINE_AUDIO_AUDIO_BASE_H
|
|
@ -1,35 +0,0 @@
|
||||||
#ifndef ENGINE_AUDIO_AUDIO_DRIVER_H
|
|
||||||
#define ENGINE_AUDIO_AUDIO_DRIVER_H
|
|
||||||
|
|
||||||
#include "engine/audio/audio_driver.h"
|
|
||||||
|
|
||||||
namespace eng {
|
|
||||||
|
|
||||||
class AudioDriverDelegate;
|
|
||||||
|
|
||||||
// Models an audio sink sending mixed audio to the audio driver. Audio data from
|
|
||||||
// the mixer source is delivered on a pull model using AudioDriverDelegate.
|
|
||||||
class AudioDriver {
|
|
||||||
public:
|
|
||||||
AudioDriver() = default;
|
|
||||||
virtual ~AudioDriver() = default;
|
|
||||||
|
|
||||||
virtual void SetDelegate(AudioDriverDelegate* delegate) = 0;
|
|
||||||
|
|
||||||
virtual bool Initialize() = 0;
|
|
||||||
|
|
||||||
virtual void Shutdown() = 0;
|
|
||||||
|
|
||||||
virtual void Suspend() = 0;
|
|
||||||
virtual void Resume() = 0;
|
|
||||||
|
|
||||||
virtual int GetHardwareSampleRate() = 0;
|
|
||||||
|
|
||||||
private:
|
|
||||||
AudioDriver(const AudioDriver&) = delete;
|
|
||||||
AudioDriver& operator=(const AudioDriver&) = delete;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace eng
|
|
||||||
|
|
||||||
#endif // ENGINE_AUDIO_AUDIO_DRIVER_H
|
|
|
@ -1,51 +0,0 @@
|
||||||
#ifndef ENGINE_AUDIO_AUDIO_DRIVER_ALSA_H
|
|
||||||
#define ENGINE_AUDIO_AUDIO_DRIVER_ALSA_H
|
|
||||||
|
|
||||||
#include <atomic>
|
|
||||||
#include <thread>
|
|
||||||
|
|
||||||
#include "engine/audio/audio_driver.h"
|
|
||||||
|
|
||||||
typedef struct _snd_pcm snd_pcm_t;
|
|
||||||
|
|
||||||
namespace eng {
|
|
||||||
|
|
||||||
class AudioDriverAlsa final : public AudioDriver {
|
|
||||||
public:
|
|
||||||
AudioDriverAlsa();
|
|
||||||
~AudioDriverAlsa() final;
|
|
||||||
|
|
||||||
void SetDelegate(AudioDriverDelegate* delegate) final;
|
|
||||||
|
|
||||||
bool Initialize() final;
|
|
||||||
|
|
||||||
void Shutdown() final;
|
|
||||||
|
|
||||||
void Suspend() final;
|
|
||||||
void Resume() final;
|
|
||||||
|
|
||||||
int GetHardwareSampleRate() final;
|
|
||||||
|
|
||||||
private:
|
|
||||||
// Handle for the PCM device.
|
|
||||||
snd_pcm_t* device_;
|
|
||||||
|
|
||||||
std::thread audio_thread_;
|
|
||||||
std::atomic<bool> terminate_audio_thread_{false};
|
|
||||||
std::atomic<bool> suspend_audio_thread_{false};
|
|
||||||
|
|
||||||
size_t num_channels_ = 0;
|
|
||||||
int sample_rate_ = 0;
|
|
||||||
size_t period_size_ = 0;
|
|
||||||
|
|
||||||
AudioDriverDelegate* delegate_ = nullptr;
|
|
||||||
|
|
||||||
void StartAudioThread();
|
|
||||||
void TerminateAudioThread();
|
|
||||||
|
|
||||||
void AudioThreadMain();
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace eng
|
|
||||||
|
|
||||||
#endif // ENGINE_AUDIO_AUDIO_DRIVER_ALSA_H
|
|
|
@ -1,18 +0,0 @@
|
||||||
#ifndef ENGINE_AUDIO_AUDIO_DRIVER_DELEGATE_H
|
|
||||||
#define ENGINE_AUDIO_AUDIO_DRIVER_DELEGATE_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
namespace eng {
|
|
||||||
|
|
||||||
class AudioDriverDelegate {
|
|
||||||
public:
|
|
||||||
AudioDriverDelegate() = default;
|
|
||||||
virtual ~AudioDriverDelegate() = default;
|
|
||||||
|
|
||||||
virtual void RenderAudio(float* output_buffer, size_t num_frames) = 0;
|
|
||||||
};
|
|
||||||
|
|
||||||
} // namespace eng
|
|
||||||
|
|
||||||
#endif // ENGINE_AUDIO_AUDIO_DRIVER_DELEGATE_H
|
|
|
@ -0,0 +1,16 @@
|
||||||
|
#ifndef ENGINE_AUDIO_AUDIO_FORWARD_H
|
||||||
|
#define ENGINE_AUDIO_AUDIO_FORWARD_H
|
||||||
|
|
||||||
|
namespace eng {
|
||||||
|
|
||||||
|
#if defined(__ANDROID__)
|
||||||
|
class AudioOboe;
|
||||||
|
using Audio = AudioOboe;
|
||||||
|
#elif defined(__linux__)
|
||||||
|
class AudioAlsa;
|
||||||
|
using Audio = AudioAlsa;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} // namespace eng
|
||||||
|
|
||||||
|
#endif // ENGINE_AUDIO_AUDIO_FORWARD_H
|
|
@ -1,70 +1,62 @@
|
||||||
#include "engine/audio/audio_driver_oboe.h"
|
#include "engine/audio/audio_oboe.h"
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
#include "engine/audio/audio_driver_delegate.h"
|
|
||||||
#include "third_party/oboe/include/oboe/Oboe.h"
|
#include "third_party/oboe/include/oboe/Oboe.h"
|
||||||
|
|
||||||
using namespace base;
|
using namespace base;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
AudioDriverOboe::AudioDriverOboe()
|
AudioOboe::AudioOboe() : callback_(std::make_unique<StreamCallback>(this)) {}
|
||||||
: callback_(std::make_unique<StreamCallback>(this)) {}
|
|
||||||
|
|
||||||
AudioDriverOboe::~AudioDriverOboe() = default;
|
AudioOboe::~AudioOboe() = default;
|
||||||
|
|
||||||
void AudioDriverOboe::SetDelegate(AudioDriverDelegate* delegate) {
|
bool AudioOboe::Initialize() {
|
||||||
delegate_ = delegate;
|
|
||||||
Resume();
|
|
||||||
}
|
|
||||||
|
|
||||||
bool AudioDriverOboe::Initialize() {
|
|
||||||
LOG << "Initializing audio system.";
|
LOG << "Initializing audio system.";
|
||||||
|
|
||||||
return RestartStream(true);
|
return RestartStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverOboe::Shutdown() {
|
void AudioOboe::Shutdown() {
|
||||||
LOG << "Shutting down audio system.";
|
LOG << "Shutting down audio system.";
|
||||||
|
|
||||||
stream_->stop();
|
stream_->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverOboe::Suspend() {
|
void AudioOboe::Suspend() {
|
||||||
stream_->stop();
|
stream_->stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverOboe::Resume() {
|
void AudioOboe::Resume() {
|
||||||
RestartStream();
|
RestartStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
int AudioDriverOboe::GetHardwareSampleRate() {
|
int AudioOboe::GetHardwareSampleRate() {
|
||||||
return stream_->getSampleRate();
|
return stream_->getSampleRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
AudioDriverOboe::StreamCallback::StreamCallback(AudioDriverOboe* driver)
|
AudioOboe::StreamCallback::StreamCallback(AudioOboe* audio) : audio_(audio) {}
|
||||||
: driver_(driver) {}
|
|
||||||
|
|
||||||
AudioDriverOboe::StreamCallback::~StreamCallback() = default;
|
AudioOboe::StreamCallback::~StreamCallback() = default;
|
||||||
|
|
||||||
oboe::DataCallbackResult AudioDriverOboe::StreamCallback::onAudioReady(
|
oboe::DataCallbackResult AudioOboe::StreamCallback::onAudioReady(
|
||||||
oboe::AudioStream* oboe_stream,
|
oboe::AudioStream* oboe_stream,
|
||||||
void* audio_data,
|
void* audio_data,
|
||||||
int32_t num_frames) {
|
int32_t num_frames) {
|
||||||
float* output_buffer = static_cast<float*>(audio_data);
|
float* output_buffer = static_cast<float*>(audio_data);
|
||||||
driver_->delegate_->RenderAudio(output_buffer, num_frames);
|
audio_->RenderAudio(output_buffer, num_frames);
|
||||||
return oboe::DataCallbackResult::Continue;
|
return oboe::DataCallbackResult::Continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
void AudioDriverOboe::StreamCallback::onErrorAfterClose(
|
void AudioOboe::StreamCallback::onErrorAfterClose(
|
||||||
oboe::AudioStream* oboe_stream,
|
oboe::AudioStream* oboe_stream,
|
||||||
oboe::Result error) {
|
oboe::Result error) {
|
||||||
LOG << "Error after close. Error: " << oboe::convertToText(error);
|
LOG << "Error after close. Error: " << oboe::convertToText(error);
|
||||||
|
|
||||||
driver_->RestartStream();
|
audio_->RestartStream();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool AudioDriverOboe::RestartStream(bool suspended) {
|
bool AudioOboe::RestartStream() {
|
||||||
oboe::AudioStreamBuilder builder;
|
oboe::AudioStreamBuilder builder;
|
||||||
oboe::Result result =
|
oboe::Result result =
|
||||||
builder.setSharingMode(oboe::SharingMode::Exclusive)
|
builder.setSharingMode(oboe::SharingMode::Exclusive)
|
||||||
|
@ -88,8 +80,7 @@ bool AudioDriverOboe::RestartStream(bool suspended) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!suspended)
|
stream_->start();
|
||||||
stream_->start();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,37 +1,33 @@
|
||||||
#ifndef ENGINE_AUDIO_AUDIO_DRIVER_OBOE_H
|
#ifndef ENGINE_AUDIO_AUDIO_OBOE_H
|
||||||
#define ENGINE_AUDIO_AUDIO_DRIVER_OBOE_H
|
#define ENGINE_AUDIO_AUDIO_OBOE_H
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "third_party/oboe/include/oboe/AudioStream.h"
|
#include "third_party/oboe/include/oboe/AudioStream.h"
|
||||||
#include "third_party/oboe/include/oboe/AudioStreamCallback.h"
|
#include "third_party/oboe/include/oboe/AudioStreamCallback.h"
|
||||||
|
|
||||||
#include "engine/audio/audio_driver.h"
|
#include "engine/audio/audio_base.h"
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
class AudioDriverOboe final : public AudioDriver {
|
class AudioOboe : public AudioBase {
|
||||||
public:
|
public:
|
||||||
AudioDriverOboe();
|
AudioOboe();
|
||||||
~AudioDriverOboe() final;
|
~AudioOboe();
|
||||||
|
|
||||||
void SetDelegate(AudioDriverDelegate* delegate) final;
|
bool Initialize();
|
||||||
|
|
||||||
bool Initialize() final;
|
void Shutdown();
|
||||||
|
|
||||||
void Shutdown() final;
|
void Suspend();
|
||||||
|
void Resume();
|
||||||
|
|
||||||
void Suspend() final;
|
int GetHardwareSampleRate();
|
||||||
void Resume() final;
|
|
||||||
|
|
||||||
int GetHardwareSampleRate() final;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr int kChannelCount = 2;
|
|
||||||
|
|
||||||
class StreamCallback final : public oboe::AudioStreamCallback {
|
class StreamCallback final : public oboe::AudioStreamCallback {
|
||||||
public:
|
public:
|
||||||
StreamCallback(AudioDriverOboe* audio);
|
StreamCallback(AudioOboe* audio);
|
||||||
~StreamCallback() final;
|
~StreamCallback() final;
|
||||||
|
|
||||||
oboe::DataCallbackResult onAudioReady(oboe::AudioStream* oboe_stream,
|
oboe::DataCallbackResult onAudioReady(oboe::AudioStream* oboe_stream,
|
||||||
|
@ -42,17 +38,15 @@ class AudioDriverOboe final : public AudioDriver {
|
||||||
oboe::Result error) final;
|
oboe::Result error) final;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
AudioDriverOboe* driver_;
|
AudioOboe* audio_;
|
||||||
};
|
};
|
||||||
|
|
||||||
oboe::ManagedStream stream_;
|
oboe::ManagedStream stream_;
|
||||||
std::unique_ptr<StreamCallback> callback_;
|
std::unique_ptr<StreamCallback> callback_;
|
||||||
|
|
||||||
AudioDriverDelegate* delegate_ = nullptr;
|
bool RestartStream();
|
||||||
|
|
||||||
bool RestartStream(bool suspended = false);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
||||||
#endif // ENGINE_AUDIO_AUDIO_DRIVER_OBOE_H
|
#endif // ENGINE_AUDIO_AUDIO_OBOE_H
|
|
@ -2,8 +2,7 @@
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
#include "engine/animator.h"
|
#include "engine/animator.h"
|
||||||
#include "engine/audio/audio_driver.h"
|
#include "engine/audio/audio.h"
|
||||||
#include "engine/audio/audio_mixer.h"
|
|
||||||
#include "engine/drawable.h"
|
#include "engine/drawable.h"
|
||||||
#include "engine/font.h"
|
#include "engine/font.h"
|
||||||
#include "engine/game.h"
|
#include "engine/game.h"
|
||||||
|
@ -26,17 +25,11 @@ namespace eng {
|
||||||
|
|
||||||
Engine* Engine::singleton = nullptr;
|
Engine* Engine::singleton = nullptr;
|
||||||
|
|
||||||
Engine::Engine(Platform* platform,
|
Engine::Engine(Platform* platform, Renderer* renderer, Audio* audio)
|
||||||
Renderer* renderer,
|
: platform_(platform), renderer_(renderer), audio_(audio) {
|
||||||
AudioDriver* audio_driver)
|
|
||||||
: platform_(platform),
|
|
||||||
renderer_(renderer),
|
|
||||||
audio_driver_(audio_driver),
|
|
||||||
audio_mixer_{std::make_unique<AudioMixer>()} {
|
|
||||||
DCHECK(!singleton);
|
DCHECK(!singleton);
|
||||||
singleton = this;
|
singleton = this;
|
||||||
|
|
||||||
audio_driver_->SetDelegate(audio_mixer_.get());
|
|
||||||
renderer_->SetContextLostCB(std::bind(&Engine::ContextLost, this));
|
renderer_->SetContextLostCB(std::bind(&Engine::ContextLost, this));
|
||||||
|
|
||||||
quad_ = CreateRenderResource<Geometry>();
|
quad_ = CreateRenderResource<Geometry>();
|
||||||
|
@ -116,7 +109,6 @@ void Engine::Shutdown() {
|
||||||
game_.reset();
|
game_.reset();
|
||||||
stats_->Destory();
|
stats_->Destory();
|
||||||
textures_.clear();
|
textures_.clear();
|
||||||
shaders_.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::Update(float delta_time) {
|
void Engine::Update(float delta_time) {
|
||||||
|
@ -158,14 +150,14 @@ void Engine::Draw(float frame_frac) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::LostFocus() {
|
void Engine::LostFocus() {
|
||||||
audio_driver_->Suspend();
|
audio_->Suspend();
|
||||||
|
|
||||||
if (game_)
|
if (game_)
|
||||||
game_->LostFocus();
|
game_->LostFocus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::GainedFocus(bool from_interstitial_ad) {
|
void Engine::GainedFocus(bool from_interstitial_ad) {
|
||||||
audio_driver_->Resume();
|
audio_->Resume();
|
||||||
|
|
||||||
if (game_)
|
if (game_)
|
||||||
game_->GainedFocus(from_interstitial_ad);
|
game_->GainedFocus(from_interstitial_ad);
|
||||||
|
@ -285,42 +277,6 @@ void Engine::ReleaseTexture(const std::string& asset_name) {
|
||||||
it->second.texture->Destroy();
|
it->second.texture->Destroy();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::LoadCustomShader(const std::string& asset_name,
|
|
||||||
const std::string& file_name) {
|
|
||||||
if (shaders_.contains(asset_name)) {
|
|
||||||
DLOG << "Shader already exists: " << asset_name;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto& s = shaders_[asset_name] = {CreateRenderResource<Shader>(), file_name};
|
|
||||||
|
|
||||||
auto source = std::make_unique<ShaderSource>();
|
|
||||||
if (!source->Load(file_name))
|
|
||||||
return;
|
|
||||||
s.shader->Create(std::move(source), quad_->vertex_description(),
|
|
||||||
quad_->primitive(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
Shader* Engine::GetCustomShader(const std::string& asset_name) {
|
|
||||||
auto it = shaders_.find(asset_name);
|
|
||||||
if (it == shaders_.end()) {
|
|
||||||
DLOG << "Shader not found: " << asset_name;
|
|
||||||
return nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
return it->second.shader.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
void Engine::RemoveCustomShader(const std::string& asset_name) {
|
|
||||||
auto it = shaders_.find(asset_name);
|
|
||||||
if (it == shaders_.end()) {
|
|
||||||
DLOG << "Shader not found: " << asset_name;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
shaders_.erase(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Engine::AddInputEvent(std::unique_ptr<InputEvent> event) {
|
void Engine::AddInputEvent(std::unique_ptr<InputEvent> event) {
|
||||||
if (replaying_)
|
if (replaying_)
|
||||||
return;
|
return;
|
||||||
|
@ -443,7 +399,7 @@ void Engine::SetKeepScreenOn(bool keep_screen_on) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Engine::SetEnableAudio(bool enable) {
|
void Engine::SetEnableAudio(bool enable) {
|
||||||
audio_mixer_->SetEnableAudio(enable);
|
audio_->SetEnableAudio(enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
TextureCompressor* Engine::GetTextureCompressor(bool opacity) {
|
TextureCompressor* Engine::GetTextureCompressor(bool opacity) {
|
||||||
|
@ -481,7 +437,7 @@ const std::string& Engine::GetSharedDataPath() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
int Engine::GetAudioHardwareSampleRate() {
|
int Engine::GetAudioHardwareSampleRate() {
|
||||||
return audio_driver_->GetHardwareSampleRate();
|
return audio_->GetHardwareSampleRate();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Engine::IsMobile() const {
|
bool Engine::IsMobile() const {
|
||||||
|
@ -496,13 +452,6 @@ void Engine::ContextLost() {
|
||||||
RefreshImage(t.first);
|
RefreshImage(t.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& s : shaders_) {
|
|
||||||
auto source = std::make_unique<ShaderSource>();
|
|
||||||
if (source->Load(s.second.file_name))
|
|
||||||
s.second.shader->Create(std::move(source), quad_->vertex_description(),
|
|
||||||
quad_->primitive(), false);
|
|
||||||
}
|
|
||||||
|
|
||||||
game_->ContextLost();
|
game_->ContextLost();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
|
|
||||||
#include "base/random.h"
|
#include "base/random.h"
|
||||||
#include "base/vecmath.h"
|
#include "base/vecmath.h"
|
||||||
|
#include "engine/audio/audio_forward.h"
|
||||||
#include "engine/persistent_data.h"
|
#include "engine/persistent_data.h"
|
||||||
|
|
||||||
class TextureCompressor;
|
class TextureCompressor;
|
||||||
|
@ -16,8 +17,6 @@ class TextureCompressor;
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
class Animator;
|
class Animator;
|
||||||
class AudioDriver;
|
|
||||||
class AudioMixer;
|
|
||||||
class Font;
|
class Font;
|
||||||
class Game;
|
class Game;
|
||||||
class Drawable;
|
class Drawable;
|
||||||
|
@ -34,7 +33,7 @@ class Engine {
|
||||||
public:
|
public:
|
||||||
using CreateImageCB = std::function<std::unique_ptr<Image>()>;
|
using CreateImageCB = std::function<std::unique_ptr<Image>()>;
|
||||||
|
|
||||||
Engine(Platform* platform, Renderer* renderer, AudioDriver* audio_driver);
|
Engine(Platform* platform, Renderer* renderer, Audio* audio);
|
||||||
~Engine();
|
~Engine();
|
||||||
|
|
||||||
static Engine& Get();
|
static Engine& Get();
|
||||||
|
@ -80,11 +79,6 @@ class Engine {
|
||||||
Texture* AcquireTexture(const std::string& asset_name);
|
Texture* AcquireTexture(const std::string& asset_name);
|
||||||
void ReleaseTexture(const std::string& asset_name);
|
void ReleaseTexture(const std::string& asset_name);
|
||||||
|
|
||||||
void LoadCustomShader(const std::string& asset_name,
|
|
||||||
const std::string& file_name);
|
|
||||||
Shader* GetCustomShader(const std::string& asset_name);
|
|
||||||
void RemoveCustomShader(const std::string& asset_name);
|
|
||||||
|
|
||||||
void AddInputEvent(std::unique_ptr<InputEvent> event);
|
void AddInputEvent(std::unique_ptr<InputEvent> event);
|
||||||
std::unique_ptr<InputEvent> GetNextInputEvent();
|
std::unique_ptr<InputEvent> GetNextInputEvent();
|
||||||
|
|
||||||
|
@ -108,7 +102,7 @@ class Engine {
|
||||||
|
|
||||||
void SetEnableVibration(bool enable) { vibration_enabled_ = enable; }
|
void SetEnableVibration(bool enable) { vibration_enabled_ = enable; }
|
||||||
|
|
||||||
AudioMixer* GetAudioMixer() { return audio_mixer_.get(); }
|
Audio* GetAudio() { return audio_; }
|
||||||
|
|
||||||
// Access to the render resources.
|
// Access to the render resources.
|
||||||
Geometry* GetQuad() { return quad_.get(); }
|
Geometry* GetQuad() { return quad_.get(); }
|
||||||
|
@ -164,19 +158,14 @@ class Engine {
|
||||||
size_t use_count = 0;
|
size_t use_count = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
// Class holding information about shader resources managed by engine.
|
|
||||||
struct ShaderResource {
|
|
||||||
std::unique_ptr<Shader> shader;
|
|
||||||
std::string file_name;
|
|
||||||
};
|
|
||||||
|
|
||||||
static Engine* singleton;
|
static Engine* singleton;
|
||||||
|
|
||||||
Platform* platform_ = nullptr;
|
Platform* platform_ = nullptr;
|
||||||
Renderer* renderer_ = nullptr;
|
|
||||||
AudioDriver* audio_driver_ = nullptr;
|
|
||||||
|
|
||||||
std::unique_ptr<AudioMixer> audio_mixer_;
|
Renderer* renderer_ = nullptr;
|
||||||
|
|
||||||
|
Audio* audio_ = nullptr;
|
||||||
|
|
||||||
std::unique_ptr<Game> game_;
|
std::unique_ptr<Game> game_;
|
||||||
|
|
||||||
std::unique_ptr<Geometry> quad_;
|
std::unique_ptr<Geometry> quad_;
|
||||||
|
@ -195,9 +184,8 @@ class Engine {
|
||||||
|
|
||||||
std::list<Animator*> animators_;
|
std::list<Animator*> animators_;
|
||||||
|
|
||||||
// Managed render resources mapped by asset name.
|
// Textures mapped by asset name.
|
||||||
std::unordered_map<std::string, TextureResource> textures_;
|
std::unordered_map<std::string, TextureResource> textures_;
|
||||||
std::unordered_map<std::string, ShaderResource> shaders_;
|
|
||||||
|
|
||||||
std::unique_ptr<ImageQuad> stats_;
|
std::unique_ptr<ImageQuad> stats_;
|
||||||
|
|
||||||
|
|
|
@ -49,8 +49,8 @@ void ImageQuad::AutoScale() {
|
||||||
SetSize(size);
|
SetSize(size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImageQuad::SetCustomShader(const std::string& asset_name) {
|
void ImageQuad::SetCustomShader(Shader* shader) {
|
||||||
custom_shader_ = Engine::Get().GetCustomShader(asset_name);
|
custom_shader_ = shader;
|
||||||
custom_uniforms_.clear();
|
custom_uniforms_.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,7 +28,7 @@ class ImageQuad final : public Animatable {
|
||||||
|
|
||||||
void AutoScale();
|
void AutoScale();
|
||||||
|
|
||||||
void SetCustomShader(const std::string& asset_name);
|
void SetCustomShader(Shader* shader);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void SetCustomUniform(const std::string& name, T value) {
|
void SetCustomUniform(const std::string& name, T value) {
|
||||||
|
|
|
@ -2,16 +2,11 @@
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
#include "base/task_runner.h"
|
#include "base/task_runner.h"
|
||||||
|
#include "engine/audio/audio.h"
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
#include "engine/renderer/opengl/renderer_opengl.h"
|
#include "engine/renderer/opengl/renderer_opengl.h"
|
||||||
#include "engine/renderer/vulkan/renderer_vulkan.h"
|
#include "engine/renderer/vulkan/renderer_vulkan.h"
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
|
||||||
#include "engine/audio/audio_driver_oboe.h"
|
|
||||||
#elif defined(__linux__)
|
|
||||||
#include "engine/audio/audio_driver_alsa.h"
|
|
||||||
#endif
|
|
||||||
|
|
||||||
using namespace base;
|
using namespace base;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
@ -28,13 +23,9 @@ void Platform::InitializeCommon() {
|
||||||
thread_pool_.Initialize();
|
thread_pool_.Initialize();
|
||||||
TaskRunner::CreateThreadLocalTaskRunner();
|
TaskRunner::CreateThreadLocalTaskRunner();
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
audio_ = std::make_unique<Audio>();
|
||||||
audio_driver_ = std::make_unique<AudioDriverOboe>();
|
if (!audio_->Initialize()) {
|
||||||
#elif defined(__linux__)
|
LOG << "Failed to initialize audio system.";
|
||||||
audio_driver_ = std::make_unique<AudioDriverAlsa>();
|
|
||||||
#endif
|
|
||||||
if (!audio_driver_->Initialize()) {
|
|
||||||
LOG << "Failed to initialize audio driver.";
|
|
||||||
throw internal_error;
|
throw internal_error;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -50,13 +41,12 @@ void Platform::InitializeCommon() {
|
||||||
void Platform::ShutdownCommon() {
|
void Platform::ShutdownCommon() {
|
||||||
LOG << "Shutting down platform.";
|
LOG << "Shutting down platform.";
|
||||||
|
|
||||||
audio_driver_->Shutdown();
|
audio_->Shutdown();
|
||||||
renderer_->Shutdown();
|
renderer_->Shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Platform::RunMainLoop() {
|
void Platform::RunMainLoop() {
|
||||||
engine_ =
|
engine_ = std::make_unique<Engine>(this, renderer_.get(), audio_.get());
|
||||||
std::make_unique<Engine>(this, renderer_.get(), audio_driver_.get());
|
|
||||||
if (!engine_->Initialize()) {
|
if (!engine_->Initialize()) {
|
||||||
LOG << "Failed to initialize the engine.";
|
LOG << "Failed to initialize the engine.";
|
||||||
throw internal_error;
|
throw internal_error;
|
||||||
|
|
|
@ -7,6 +7,7 @@
|
||||||
|
|
||||||
#include "base/thread_pool.h"
|
#include "base/thread_pool.h"
|
||||||
#include "base/timer.h"
|
#include "base/timer.h"
|
||||||
|
#include "engine/audio/audio_forward.h"
|
||||||
|
|
||||||
#if defined(__ANDROID__)
|
#if defined(__ANDROID__)
|
||||||
|
|
||||||
|
@ -24,7 +25,6 @@ struct AInputEvent;
|
||||||
|
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
class AudioDriver;
|
|
||||||
class Renderer;
|
class Renderer;
|
||||||
class Engine;
|
class Engine;
|
||||||
|
|
||||||
|
@ -80,7 +80,7 @@ class Platform {
|
||||||
bool has_focus_ = false;
|
bool has_focus_ = false;
|
||||||
bool should_exit_ = false;
|
bool should_exit_ = false;
|
||||||
|
|
||||||
std::unique_ptr<AudioDriver> audio_driver_;
|
std::unique_ptr<Audio> audio_;
|
||||||
std::unique_ptr<Renderer> renderer_;
|
std::unique_ptr<Renderer> renderer_;
|
||||||
std::unique_ptr<Engine> engine_;
|
std::unique_ptr<Engine> engine_;
|
||||||
|
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
#include "base/task_runner.h"
|
#include "base/task_runner.h"
|
||||||
|
#include "engine/audio/audio.h"
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
#include "engine/input_event.h"
|
#include "engine/input_event.h"
|
||||||
#include "engine/renderer/renderer.h"
|
#include "engine/renderer/renderer.h"
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
#include "base/task_runner.h"
|
#include "base/task_runner.h"
|
||||||
#include "base/vecmath.h"
|
#include "base/vecmath.h"
|
||||||
|
#include "engine/audio/audio.h"
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
#include "engine/input_event.h"
|
#include "engine/input_event.h"
|
||||||
#include "engine/renderer/renderer.h"
|
#include "engine/renderer/renderer.h"
|
||||||
|
|
|
@ -2,7 +2,7 @@
|
||||||
|
|
||||||
#include "base/interpolation.h"
|
#include "base/interpolation.h"
|
||||||
#include "base/log.h"
|
#include "base/log.h"
|
||||||
#include "engine/audio/audio_mixer.h"
|
#include "engine/audio/audio.h"
|
||||||
#include "engine/engine.h"
|
#include "engine/engine.h"
|
||||||
#include "engine/sound.h"
|
#include "engine/sound.h"
|
||||||
|
|
||||||
|
@ -11,10 +11,10 @@ using namespace base;
|
||||||
namespace eng {
|
namespace eng {
|
||||||
|
|
||||||
SoundPlayer::SoundPlayer()
|
SoundPlayer::SoundPlayer()
|
||||||
: resource_id_(Engine::Get().GetAudioMixer()->CreateResource()) {}
|
: resource_id_(Engine::Get().GetAudio()->CreateResource()) {}
|
||||||
|
|
||||||
SoundPlayer::~SoundPlayer() {
|
SoundPlayer::~SoundPlayer() {
|
||||||
Engine::Get().GetAudioMixer()->DestroyResource(resource_id_);
|
Engine::Get().GetAudio()->DestroyResource(resource_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundPlayer::SetSound(std::shared_ptr<Sound> sound) {
|
void SoundPlayer::SetSound(std::shared_ptr<Sound> sound) {
|
||||||
|
@ -32,14 +32,14 @@ void SoundPlayer::Play(bool loop, float fade_in_duration) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
int step = variate_ ? Engine::Get().GetRandomGenerator().Roll(3) - 2 : 0;
|
int step = variate_ ? Engine::Get().GetRandomGenerator().Roll(3) - 2 : 0;
|
||||||
Engine::Get().GetAudioMixer()->SetResampleStep(resource_id_, step * 12);
|
Engine::Get().GetAudio()->SetResampleStep(resource_id_, step * 12);
|
||||||
Engine::Get().GetAudioMixer()->SetLoop(resource_id_, loop);
|
Engine::Get().GetAudio()->SetLoop(resource_id_, loop);
|
||||||
if (fade_in_duration > 0)
|
if (fade_in_duration > 0)
|
||||||
Engine::Get().GetAudioMixer()->SetAmplitudeInc(
|
Engine::Get().GetAudio()->SetAmplitudeInc(
|
||||||
resource_id_, 1.0f / (sound_->sample_rate() * fade_in_duration));
|
resource_id_, 1.0f / (sound_->sample_rate() * fade_in_duration));
|
||||||
else
|
else
|
||||||
Engine::Get().GetAudioMixer()->SetAmplitudeInc(resource_id_, 0);
|
Engine::Get().GetAudio()->SetAmplitudeInc(resource_id_, 0);
|
||||||
Engine::Get().GetAudioMixer()->Play(
|
Engine::Get().GetAudio()->Play(
|
||||||
resource_id_, sound_, fade_in_duration > 0 ? 0 : max_amplitude_, true);
|
resource_id_, sound_, fade_in_duration > 0 ? 0 : max_amplitude_, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,10 +48,10 @@ void SoundPlayer::Resume(float fade_in_duration) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (fade_in_duration > 0)
|
if (fade_in_duration > 0)
|
||||||
Engine::Get().GetAudioMixer()->SetAmplitudeInc(
|
Engine::Get().GetAudio()->SetAmplitudeInc(
|
||||||
resource_id_, 1.0f / (sound_->sample_rate() * fade_in_duration));
|
resource_id_, 1.0f / (sound_->sample_rate() * fade_in_duration));
|
||||||
Engine::Get().GetAudioMixer()->Play(resource_id_, sound_,
|
Engine::Get().GetAudio()->Play(resource_id_, sound_,
|
||||||
fade_in_duration > 0 ? 0 : -1, false);
|
fade_in_duration > 0 ? 0 : -1, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundPlayer::Stop(float fade_out_duration) {
|
void SoundPlayer::Stop(float fade_out_duration) {
|
||||||
|
@ -59,10 +59,10 @@ void SoundPlayer::Stop(float fade_out_duration) {
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (fade_out_duration > 0)
|
if (fade_out_duration > 0)
|
||||||
Engine::Get().GetAudioMixer()->SetAmplitudeInc(
|
Engine::Get().GetAudio()->SetAmplitudeInc(
|
||||||
resource_id_, -1.0f / (sound_->sample_rate() * fade_out_duration));
|
resource_id_, -1.0f / (sound_->sample_rate() * fade_out_duration));
|
||||||
else
|
else
|
||||||
Engine::Get().GetAudioMixer()->Stop(resource_id_);
|
Engine::Get().GetAudio()->Stop(resource_id_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundPlayer::SetVariate(bool variate) {
|
void SoundPlayer::SetVariate(bool variate) {
|
||||||
|
@ -70,16 +70,16 @@ void SoundPlayer::SetVariate(bool variate) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundPlayer::SetSimulateStereo(bool simulate) {
|
void SoundPlayer::SetSimulateStereo(bool simulate) {
|
||||||
Engine::Get().GetAudioMixer()->SetSimulateStereo(resource_id_, simulate);
|
Engine::Get().GetAudio()->SetSimulateStereo(resource_id_, simulate);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundPlayer::SetMaxAplitude(float max_amplitude) {
|
void SoundPlayer::SetMaxAplitude(float max_amplitude) {
|
||||||
max_amplitude_ = max_amplitude;
|
max_amplitude_ = max_amplitude;
|
||||||
Engine::Get().GetAudioMixer()->SetMaxAmplitude(resource_id_, max_amplitude);
|
Engine::Get().GetAudio()->SetMaxAmplitude(resource_id_, max_amplitude);
|
||||||
}
|
}
|
||||||
|
|
||||||
void SoundPlayer::SetEndCallback(base::Closure cb) {
|
void SoundPlayer::SetEndCallback(base::Closure cb) {
|
||||||
Engine::Get().GetAudioMixer()->SetEndCallback(resource_id_, cb);
|
Engine::Get().GetAudio()->SetEndCallback(resource_id_, cb);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace eng
|
} // namespace eng
|
||||||
|
|
Loading…
Reference in New Issue