Compare commits

..

3 Commits

Author SHA1 Message Date
Attila Uygun e376b1bc17 Add option to switch between renderers 2023-06-04 12:54:40 +02:00
Attila Uygun 76fb19ab3a Move AudioSinkDelegate into AudioSink 2023-06-04 11:31:37 +02:00
Attila Uygun a39efa5d3c Add comments 2023-06-04 11:13:22 +02:00
17 changed files with 121 additions and 75 deletions

BIN
assets/renderer_logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -11,6 +11,7 @@
#include "engine/font.h" #include "engine/font.h"
#include "engine/image.h" #include "engine/image.h"
#include "engine/input_event.h" #include "engine/input_event.h"
#include "engine/renderer/renderer.h"
#include "engine/sound.h" #include "engine/sound.h"
#include "demo/demo.h" #include "demo/demo.h"
@ -33,9 +34,10 @@ const Vector4f kColorNormal = {1, 1, 1, 1};
const Vector4f kColorHighlight = {20, 20, 20, 1}; const Vector4f kColorHighlight = {20, 20, 20, 1};
constexpr float kBlendingSpeed = 0.12f; constexpr float kBlendingSpeed = 0.12f;
const Vector4f kColorSwitch[2] = {{0.003f, 0.91f, 0.99f, 1}, const std::array<Vector4f, 2> kColorSwitch = {Vector4f{0.003f, 0.91f, 0.99f, 1},
{0.33f, 0.47, 0.51f, 1}}; Vector4f{0.33f, 0.47, 0.51f, 1}};
const Vector4f kColorFadeIn = {1, 1, 1, 1};
const Vector4f kColorFadeOut = {1, 1, 1, 0}; const Vector4f kColorFadeOut = {1, 1, 1, 0};
constexpr float kFadeSpeed = 0.2f; constexpr float kFadeSpeed = 0.2f;
@ -150,7 +152,8 @@ bool Menu::Initialize() {
} }
game->saved_data().root()["audio"] = toggle_audio_.enabled(); game->saved_data().root()["audio"] = toggle_audio_.enabled();
}, },
true, game->saved_data().root().get("audio", Json::Value(true)).asBool()); true, game->saved_data().root().get("audio", Json::Value(true)).asBool(),
kColorFadeOut, kColorSwitch);
toggle_audio_.image().SetPosition(Engine::Get().GetScreenSize() * toggle_audio_.image().SetPosition(Engine::Get().GetScreenSize() *
Vector2f(0, -0.25f)); Vector2f(0, -0.25f));
toggle_audio_.image().Scale(0.7f); toggle_audio_.image().Scale(0.7f);
@ -162,7 +165,8 @@ bool Menu::Initialize() {
game->SetEnableMusic(toggle_music_.enabled()); game->SetEnableMusic(toggle_music_.enabled());
game->saved_data().root()["music"] = toggle_music_.enabled(); game->saved_data().root()["music"] = toggle_music_.enabled();
}, },
true, game->saved_data().root().get("music", Json::Value(true)).asBool()); true, game->saved_data().root().get("music", Json::Value(true)).asBool(),
kColorFadeOut, kColorSwitch);
toggle_music_.image().SetPosition(Engine::Get().GetScreenSize() * toggle_music_.image().SetPosition(Engine::Get().GetScreenSize() *
Vector2f(0, -0.25f)); Vector2f(0, -0.25f));
toggle_music_.image().Scale(0.7f); toggle_music_.image().Scale(0.7f);
@ -177,7 +181,8 @@ bool Menu::Initialize() {
game->saved_data().root()["vibration"] = toggle_vibration_.enabled(); game->saved_data().root()["vibration"] = toggle_vibration_.enabled();
}, },
true, true,
game->saved_data().root().get("vibration", Json::Value(true)).asBool()); game->saved_data().root().get("vibration", Json::Value(true)).asBool(),
kColorFadeOut, kColorSwitch);
toggle_vibration_.image().SetPosition(Engine::Get().GetScreenSize() * toggle_vibration_.image().SetPosition(Engine::Get().GetScreenSize() *
Vector2f(0, -0.25f)); Vector2f(0, -0.25f));
toggle_vibration_.image().Scale(0.7f); toggle_vibration_.image().Scale(0.7f);
@ -188,6 +193,21 @@ bool Menu::Initialize() {
toggle_vibration_.image().Translate( toggle_vibration_.image().Translate(
{toggle_music_.image().GetSize().x / 2, 0}); {toggle_music_.image().GetSize().x / 2, 0});
renderer_type_.Create(
"renderer_logo", {2, 1}, 0, 1,
[&] {
Engine::Get().CreateRenderer(renderer_type_.enabled()
? RendererType::kVulkan
: RendererType::kOpenGL);
renderer_type_.SetEnabled(
(Engine::Get().GetRendererType() == RendererType::kVulkan));
},
true, Engine::Get().GetRendererType() == RendererType::kVulkan,
kColorFadeOut, {Vector4f{1, 1, 1, 1}, Vector4f{1, 1, 1, 1}});
renderer_type_.image().PlaceToBottomOf(toggle_music_.image());
renderer_type_.image().Translate(toggle_music_.image().GetPosition() *
Vector2f(0, 1.1f));
high_score_value_ = game->GetHighScore(); high_score_value_ = game->GetHighScore();
high_score_.Create("high_score_tex"); high_score_.Create("high_score_tex");
@ -226,7 +246,7 @@ bool Menu::Initialize() {
starting_wave_.image().SetFrame(start_from_wave_ / 3); starting_wave_.image().SetFrame(start_from_wave_ / 3);
click_.Play(false); click_.Play(false);
}, },
false, true); false, true, kColorFadeOut, kColorSwitch);
wave_up_.image().Scale(1.5f); wave_up_.image().Scale(1.5f);
return true; return true;
@ -236,6 +256,7 @@ void Menu::OnInputEvent(std::unique_ptr<InputEvent> event) {
if (toggle_audio_.OnInputEvent(event.get()) || if (toggle_audio_.OnInputEvent(event.get()) ||
toggle_music_.OnInputEvent(event.get()) || toggle_music_.OnInputEvent(event.get()) ||
toggle_vibration_.OnInputEvent(event.get()) || toggle_vibration_.OnInputEvent(event.get()) ||
renderer_type_.OnInputEvent(event.get()) ||
(wave_up_.image().IsVisible() && wave_up_.OnInputEvent(event.get()))) (wave_up_.image().IsVisible() && wave_up_.OnInputEvent(event.get())))
return; return;
@ -350,6 +371,7 @@ void Menu::Show() {
toggle_audio_.Show(); toggle_audio_.Show();
toggle_music_.Show(); toggle_music_.Show();
toggle_vibration_.Show(); toggle_vibration_.Show();
renderer_type_.Show();
Demo* game = static_cast<Demo*>(Engine::Get().GetGame()); Demo* game = static_cast<Demo*>(Engine::Get().GetGame());
@ -410,6 +432,7 @@ void Menu::Hide(Closure cb) {
toggle_audio_.Hide(); toggle_audio_.Hide();
toggle_music_.Hide(); toggle_music_.Hide();
toggle_vibration_.Hide(); toggle_vibration_.Hide();
renderer_type_.Hide();
if (starting_wave_.image().IsVisible()) { if (starting_wave_.image().IsVisible()) {
starting_wave_.Hide(); starting_wave_.Hide();
@ -425,6 +448,7 @@ bool Menu::CreateRenderResources() {
Engine::Get().SetImageSource("buttons_tex", "menu_icons.png"); Engine::Get().SetImageSource("buttons_tex", "menu_icons.png");
Engine::Get().SetImageSource("high_score_tex", Engine::Get().SetImageSource("high_score_tex",
std::bind(&Menu::CreateHighScoreImage, this)); std::bind(&Menu::CreateHighScoreImage, this));
Engine::Get().SetImageSource("renderer_logo", "renderer_logo.png");
Engine::Get().SetImageSource("wave_up_tex", []() -> std::unique_ptr<Image> { Engine::Get().SetImageSource("wave_up_tex", []() -> std::unique_ptr<Image> {
const Font& font = static_cast<Demo*>(Engine::Get().GetGame())->GetFont(); const Font& font = static_cast<Demo*>(Engine::Get().GetGame())->GetFont();
@ -520,16 +544,20 @@ void Menu::Button::Create(const std::string& asset_name,
int frame2, int frame2,
Closure pressed_cb, Closure pressed_cb,
bool switch_control, bool switch_control,
bool enabled) { bool enabled,
const Vector4f& fade_out_color,
const std::array<Vector4f, 2>& switch_color) {
frame1_ = frame1; frame1_ = frame1;
frame2_ = frame2; frame2_ = frame2;
pressed_cb_ = std::move(pressed_cb); pressed_cb_ = std::move(pressed_cb);
switch_control_ = switch_control; switch_control_ = switch_control;
enabled_ = enabled; enabled_ = enabled;
fade_out_color_ = fade_out_color;
switch_color_ = switch_color;
image_.Create(asset_name, num_frames); image_.Create(asset_name, num_frames);
image_.SetFrame(enabled ? frame1 : frame2); image_.SetFrame(enabled ? frame1 : frame2);
image_.SetColor(kColorFadeOut); image_.SetColor(fade_out_color_);
image_.SetZOrder(41); image_.SetZOrder(41);
image_.SetVisible(false); image_.SetVisible(false);
@ -562,14 +590,14 @@ bool Menu::Button::OnInputEvent(eng::InputEvent* event) {
void Menu::Button::Show() { void Menu::Button::Show() {
animator_.SetVisible(true); animator_.SetVisible(true);
animator_.SetBlending(enabled_ ? kColorSwitch[0] : kColorSwitch[1], animator_.SetBlending(enabled_ ? switch_color_[0] : switch_color_[1],
kBlendingSpeed); kBlendingSpeed);
animator_.Play(Animator::kBlending, false); animator_.Play(Animator::kBlending, false);
animator_.SetEndCallback(Animator::kBlending, nullptr); animator_.SetEndCallback(Animator::kBlending, nullptr);
} }
void Menu::Button::Hide() { void Menu::Button::Hide() {
animator_.SetBlending(kColorFadeOut, kBlendingSpeed); animator_.SetBlending(fade_out_color_, kBlendingSpeed);
animator_.Play(Animator::kBlending, false); animator_.Play(Animator::kBlending, false);
animator_.SetEndCallback(Animator::kBlending, animator_.SetEndCallback(Animator::kBlending,
[&]() -> void { animator_.SetVisible(false); }); [&]() -> void { animator_.SetVisible(false); });
@ -579,7 +607,7 @@ void Menu::Button::SetEnabled(bool enable) {
if (switch_control_) { if (switch_control_) {
enabled_ = enable; enabled_ = enable;
image_.SetFrame(enabled_ ? frame1_ : frame2_); image_.SetFrame(enabled_ ? frame1_ : frame2_);
image_.SetColor(enabled_ ? kColorSwitch[0] : kColorSwitch[1]); image_.SetColor(enabled_ ? switch_color_[0] : switch_color_[1]);
} }
} }

View File

@ -55,13 +55,17 @@ class Menu {
int frame2, int frame2,
base::Closure pressed_cb, base::Closure pressed_cb,
bool switch_control, bool switch_control,
bool enabled); bool enabled,
const base::Vector4f& fade_out_color,
const std::array<base::Vector4f, 2>& switch_color);
bool OnInputEvent(eng::InputEvent* event); bool OnInputEvent(eng::InputEvent* event);
void Show(); void Show();
void Hide(); void Hide();
void SetEnabled(bool enable);
eng::ImageQuad& image() { return image_; }; eng::ImageQuad& image() { return image_; };
bool enabled() const { return enabled_; } bool enabled() const { return enabled_; }
@ -77,7 +81,8 @@ class Menu {
bool enabled_ = false; bool enabled_ = false;
base::Vector2f tap_pos_[2] = {{0, 0}, {0, 0}}; base::Vector2f tap_pos_[2] = {{0, 0}, {0, 0}};
void SetEnabled(bool enable); base::Vector4f fade_out_color_;
std::array<base::Vector4f, 2> switch_color_;
}; };
class Radio { class Radio {
@ -126,6 +131,7 @@ class Menu {
Button toggle_audio_; Button toggle_audio_;
Button toggle_music_; Button toggle_music_;
Button toggle_vibration_; Button toggle_vibration_;
Button renderer_type_;
size_t high_score_value_ = 0; size_t high_score_value_ = 0;

View File

@ -11,28 +11,28 @@ namespace eng {
namespace { namespace {
template <typename T> template <typename T>
std::array<std::unique_ptr<T[]>, 2> Deinterleave(size_t num_channels, std::array<std::unique_ptr<T[]>, 2> Deinterleave(
size_t num_samples, size_t num_channels,
float* input_buffer) { size_t num_samples,
std::unique_ptr<float[]> source_buffer) {
std::array<std::unique_ptr<T[]>, 2> channels; std::array<std::unique_ptr<T[]>, 2> channels;
if (num_channels == 1) { if (num_channels == 1) {
// Single channel.
if constexpr (std::is_same<float, T>::value) { if constexpr (std::is_same<float, T>::value) {
channels[0] = std::make_unique<T[]>(num_samples); // Passthrough
memcpy(channels[0].get(), input_buffer, num_samples * sizeof(float)); channels[0] = std::move(source_buffer);
} else { } else {
channels[0] = std::make_unique<T[]>(num_samples); channels[0] = std::make_unique<T[]>(num_samples);
for (int i = 0; i < num_samples; ++i) for (int i = 0; i < num_samples; ++i)
channels[0].get()[i] = static_cast<T>(input_buffer[i]); channels[0].get()[i] = static_cast<T>(source_buffer.get()[i]);
} }
} else { } else {
// Deinterleave into separate channels. // Deinterleave into separate channels.
channels[0] = std::make_unique<T[]>(num_samples); channels[0] = std::make_unique<T[]>(num_samples);
channels[1] = std::make_unique<T[]>(num_samples); channels[1] = std::make_unique<T[]>(num_samples);
for (size_t i = 0, j = 0; i < num_samples * 2; i += 2) { for (size_t i = 0, j = 0; i < num_samples * 2; i += 2) {
channels[0].get()[j] = static_cast<T>(input_buffer[i]); channels[0].get()[j] = static_cast<T>(source_buffer.get()[i]);
channels[1].get()[j++] = static_cast<T>(input_buffer[i + 1]); channels[1].get()[j++] = static_cast<T>(source_buffer.get()[i + 1]);
} }
} }
@ -59,15 +59,15 @@ void AudioBus::SetAudioConfig(size_t num_channels, size_t sample_rate) {
sample_rate_ = sample_rate; sample_rate_ = sample_rate;
} }
void AudioBus::FromInterleaved(std::unique_ptr<float[]> input_buffer, void AudioBus::FromInterleaved(std::unique_ptr<float[]> source_buffer,
size_t samples_per_channel) { size_t samples_per_channel) {
auto channels = Deinterleave<float>(num_channels_, samples_per_channel, auto channels = Deinterleave<float>(num_channels_, samples_per_channel,
input_buffer.get()); std::move(source_buffer));
size_t hw_sample_rate = Engine::Get().GetAudioHardwareSampleRate(); size_t hw_sample_rate = Engine::Get().GetAudioHardwareSampleRate();
if (hw_sample_rate == sample_rate_) { if (hw_sample_rate == sample_rate_) {
// No need for resmapling. // Passthrough
channel_data_[0] = std::move(channels[0]); channel_data_[0] = std::move(channels[0]);
if (num_channels_ == 2) if (num_channels_ == 2)
channel_data_[1] = std::move(channels[1]); channel_data_[1] = std::move(channels[1]);

View File

@ -7,6 +7,10 @@ namespace eng {
class SincResampler; class SincResampler;
// Represents a sequence of audio samples for each channels. The data layout is
// planar as opposed to interleaved. The memory for the data is allocated and
// owned by the AudioBus. Max two channels are supported. An AudioBus with one
// channel is mono, with two channels is stereo.
class AudioBus { class AudioBus {
public: public:
AudioBus(); AudioBus();
@ -28,7 +32,11 @@ class AudioBus {
protected: protected:
void SetAudioConfig(size_t num_channels, size_t sample_rate); void SetAudioConfig(size_t num_channels, size_t sample_rate);
void FromInterleaved(std::unique_ptr<float[]> input_buffer, // Overwrites the sample values stored in this AudioBus instance with values
// from a given interleaved source_buffer. The expected layout of the
// source_buffer is [ch0, ch1, ch0, ch1, ...]. A sample-rate conversion to the
// system sample-rate will be made if it doesn't match.
void FromInterleaved(std::unique_ptr<float[]> source_buffer,
size_t samples_per_channel); size_t samples_per_channel);
private: private:

View File

@ -8,7 +8,7 @@
#include <unordered_map> #include <unordered_map>
#include "base/closure.h" #include "base/closure.h"
#include "engine/audio/audio_sink_delegate.h" #include "engine/audio/audio_sink.h"
namespace base { namespace base {
class TaskRunner; class TaskRunner;
@ -22,7 +22,7 @@ class AudioBus;
// Mix and render audio with low overhead. A platform specific AudioSink // Mix and render audio with low overhead. A platform specific AudioSink
// implementation is expected to periodically call RenderAudio() in a background // implementation is expected to periodically call RenderAudio() in a background
// thread. // thread.
class AudioMixer : public AudioSinkDelegate { class AudioMixer : public AudioSink::Delegate {
public: public:
AudioMixer(); AudioMixer();
~AudioMixer(); ~AudioMixer();
@ -91,7 +91,7 @@ class AudioMixer : public AudioSinkDelegate {
bool audio_enabled_ = true; bool audio_enabled_ = true;
// AudioSinkDelegate implementation // AudioSink::Delegate implementation
int GetChannelCount() final { return kChannelCount; } int GetChannelCount() final { return kChannelCount; }
void RenderAudio(float* output_buffer, size_t num_frames) final; void RenderAudio(float* output_buffer, size_t num_frames) final;

View File

@ -4,9 +4,19 @@
namespace eng { namespace eng {
// Models an audio sink sending mixed audio to the audio driver. Audio data from // Models an audio sink sending mixed audio to the audio driver. Audio data from
// the mixer source is delivered on a pull model using AudioSinkDelegate. // the mixer source is delivered on a pull model using Delegate.
class AudioSink { class AudioSink {
public: public:
class Delegate {
public:
Delegate() = default;
virtual ~Delegate() = default;
virtual int GetChannelCount() = 0;
virtual void RenderAudio(float* output_buffer, size_t num_frames) = 0;
};
AudioSink() = default; AudioSink() = default;
virtual ~AudioSink() = default; virtual ~AudioSink() = default;

View File

@ -5,13 +5,12 @@
#include <alsa/asoundlib.h> #include <alsa/asoundlib.h>
#include "base/log.h" #include "base/log.h"
#include "engine/audio/audio_sink_delegate.h"
using namespace base; using namespace base;
namespace eng { namespace eng {
AudioSinkAlsa::AudioSinkAlsa(AudioSinkDelegate* delegate) AudioSinkAlsa::AudioSinkAlsa(AudioSink::Delegate* delegate)
: delegate_(delegate) {} : delegate_(delegate) {}
AudioSinkAlsa::~AudioSinkAlsa() { AudioSinkAlsa::~AudioSinkAlsa() {

View File

@ -10,11 +10,9 @@ typedef struct _snd_pcm snd_pcm_t;
namespace eng { namespace eng {
class AudioSinkDelegate;
class AudioSinkAlsa final : public AudioSink { class AudioSinkAlsa final : public AudioSink {
public: public:
AudioSinkAlsa(AudioSinkDelegate* delegate); AudioSinkAlsa(AudioSink::Delegate* delegate);
~AudioSinkAlsa() final; ~AudioSinkAlsa() final;
bool Initialize() final; bool Initialize() final;
@ -36,7 +34,7 @@ class AudioSinkAlsa final : public AudioSink {
size_t sample_rate_ = 0; size_t sample_rate_ = 0;
size_t period_size_ = 0; size_t period_size_ = 0;
AudioSinkDelegate* delegate_ = nullptr; AudioSink::Delegate* delegate_ = nullptr;
void StartAudioThread(); void StartAudioThread();
void TerminateAudioThread(); void TerminateAudioThread();

View File

@ -1,20 +0,0 @@
#ifndef ENGINE_AUDIO_AUDIO_SINK_DELEGATE_H
#define ENGINE_AUDIO_AUDIO_SINK_DELEGATE_H
#include <stddef.h>
namespace eng {
class AudioSinkDelegate {
public:
AudioSinkDelegate() = default;
virtual ~AudioSinkDelegate() = default;
virtual int GetChannelCount() = 0;
virtual void RenderAudio(float* output_buffer, size_t num_frames) = 0;
};
} // namespace eng
#endif // ENGINE_AUDIO_AUDIO_SINK_DELEGATE_H

View File

@ -1,14 +1,13 @@
#include "engine/audio/audio_sink_oboe.h" #include "engine/audio/audio_sink_oboe.h"
#include "base/log.h" #include "base/log.h"
#include "engine/audio/audio_sink_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 {
AudioSinkOboe::AudioSinkOboe(AudioSinkDelegate* delegate) AudioSinkOboe::AudioSinkOboe(AudioSink::Delegate* delegate)
: callback_(std::make_unique<StreamCallback>(this)), delegate_(delegate) {} : callback_(std::make_unique<StreamCallback>(this)), delegate_(delegate) {}
AudioSinkOboe::~AudioSinkOboe() { AudioSinkOboe::~AudioSinkOboe() {

View File

@ -10,11 +10,9 @@
namespace eng { namespace eng {
class AudioSinkDelegate;
class AudioSinkOboe final : public AudioSink { class AudioSinkOboe final : public AudioSink {
public: public:
AudioSinkOboe(AudioSinkDelegate* delegate); AudioSinkOboe(AudioSink::Delegate* delegate);
~AudioSinkOboe() final; ~AudioSinkOboe() final;
bool Initialize() final; bool Initialize() final;
@ -44,7 +42,7 @@ class AudioSinkOboe final : public AudioSink {
oboe::ManagedStream stream_; oboe::ManagedStream stream_;
std::unique_ptr<StreamCallback> callback_; std::unique_ptr<StreamCallback> callback_;
AudioSinkDelegate* delegate_ = nullptr; AudioSink::Delegate* delegate_ = nullptr;
bool RestartStream(); bool RestartStream();
}; };

View File

@ -106,7 +106,7 @@ void Engine::Initialize() {
thread_pool_.Initialize(); thread_pool_.Initialize();
CreateRenderer(true); CreateRenderer(RendererType::kVulkan);
// Normalize viewport. // Normalize viewport.
if (GetScreenWidth() > GetScreenHeight()) { if (GetScreenWidth() > GetScreenHeight()) {
@ -201,23 +201,27 @@ void Engine::RemoveAnimator(Animator* animator) {
} }
} }
void Engine::CreateRenderer(bool vulkan) { void Engine::CreateRenderer(RendererType type) {
if ((dynamic_cast<RendererVulkan*>(renderer_.get()) && vulkan) || if ((dynamic_cast<RendererVulkan*>(renderer_.get()) &&
(dynamic_cast<RendererOpenGL*>(renderer_.get()) && !vulkan)) type == RendererType::kVulkan) ||
(dynamic_cast<RendererOpenGL*>(renderer_.get()) &&
type == RendererType::kOpenGL))
return; return;
if (vulkan) if (type == RendererType::kVulkan)
renderer_ = renderer_ =
std::make_unique<RendererVulkan>(std::bind(&Engine::ContextLost, this)); std::make_unique<RendererVulkan>(std::bind(&Engine::ContextLost, this));
else else if (type == RendererType::kOpenGL)
renderer_ = renderer_ =
std::make_unique<RendererOpenGL>(std::bind(&Engine::ContextLost, this)); std::make_unique<RendererOpenGL>(std::bind(&Engine::ContextLost, this));
else
NOTREACHED;
bool result = renderer_->Initialize(platform_); bool result = renderer_->Initialize(platform_);
if (!result && vulkan) { if (!result && type == RendererType::kVulkan) {
LOG << "Failed to initialize " << renderer_->GetDebugName() << " renderer."; LOG << "Failed to initialize " << renderer_->GetDebugName() << " renderer.";
LOG << "Fallback to OpenGL renderer."; LOG << "Fallback to OpenGL renderer.";
CreateRenderer(false); CreateRenderer(RendererType::kOpenGL);
return; return;
} }
CHECK(result) << "Failed to initialize " << renderer_->GetDebugName() CHECK(result) << "Failed to initialize " << renderer_->GetDebugName()
@ -227,6 +231,12 @@ void Engine::CreateRenderer(bool vulkan) {
ContextLost(); ContextLost();
} }
RendererType Engine::GetRendererType() {
if (renderer_)
return renderer_->GetRendererType();
return RendererType::kUnknown;
}
void Engine::Exit() { void Engine::Exit() {
platform_->Exit(); platform_->Exit();
} }

View File

@ -20,17 +20,18 @@ namespace eng {
class Animator; class Animator;
class AudioMixer; class AudioMixer;
class Drawable;
class Font; class Font;
class Game; class Game;
class Drawable; class Geometry;
class InputEvent;
class Image; class Image;
class ImageQuad; class ImageQuad;
class InputEvent;
class Platform;
class Renderer; class Renderer;
class Geometry;
class Shader; class Shader;
class Texture; class Texture;
class Platform; enum class RendererType;
class Engine : public PlatformObserver { class Engine : public PlatformObserver {
public: public:
@ -49,7 +50,8 @@ class Engine : public PlatformObserver {
void AddAnimator(Animator* animator); void AddAnimator(Animator* animator);
void RemoveAnimator(Animator* animator); void RemoveAnimator(Animator* animator);
void CreateRenderer(bool vulkan); void CreateRenderer(RendererType type);
RendererType GetRendererType();
void Exit(); void Exit();

View File

@ -86,6 +86,8 @@ class RendererOpenGL final : public Renderer {
const char* GetDebugName() final { return "OpenGL"; } const char* GetDebugName() final { return "OpenGL"; }
RendererType GetRendererType() final { return RendererType::kOpenGL; }
private: private:
struct GeometryOpenGL { struct GeometryOpenGL {
struct Element { struct Element {

View File

@ -15,6 +15,8 @@ class ShaderSource;
class Mesh; class Mesh;
class Platform; class Platform;
enum class RendererType { kUnknown, kVulkan, kOpenGL };
class Renderer { class Renderer {
public: public:
const unsigned kInvalidId = 0; const unsigned kInvalidId = 0;
@ -82,6 +84,8 @@ class Renderer {
virtual const char* GetDebugName() = 0; virtual const char* GetDebugName() = 0;
virtual RendererType GetRendererType() { return RendererType::kUnknown; }
protected: protected:
struct TextureCompression { struct TextureCompression {
unsigned etc1 : 1; unsigned etc1 : 1;

View File

@ -69,6 +69,8 @@ class RendererVulkan final : public Renderer {
const char* GetDebugName() final { return "Vulkan"; } const char* GetDebugName() final { return "Vulkan"; }
RendererType GetRendererType() final { return RendererType::kVulkan; }
private: private:
// VkBuffer or VkImage with allocator. // VkBuffer or VkImage with allocator.
template <typename T> template <typename T>