Manage custom shaders in Engine

This commit is contained in:
Attila Uygun 2023-05-17 11:03:04 +02:00
parent 7dd7d7bfd7
commit cda1d750f8
10 changed files with 73 additions and 62 deletions

View File

@ -50,6 +50,10 @@ 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;
@ -162,11 +166,6 @@ 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) {

View File

@ -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;

View File

@ -13,8 +13,6 @@
#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"
@ -76,8 +74,7 @@ float SnapSpawnPosX(int col) {
} // namespace } // namespace
Enemy::Enemy() Enemy::Enemy() = default;
: chromatic_aberration_(Engine::Get().CreateRenderResource<Shader>()) {}
Enemy::~Enemy() = default; Enemy::~Enemy() = default;
@ -205,10 +202,6 @@ 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);
@ -423,7 +416,7 @@ void Enemy::StopAllEnemyUnits(bool chromatic_aberration_effect) {
continue; continue;
if (chromatic_aberration_effect) { if (chromatic_aberration_effect) {
e.sprite.SetCustomShader(chromatic_aberration_.get()); e.sprite.SetCustomShader("chromatic_aberration");
e.chromatic_aberration_active_ = true; e.chromatic_aberration_active_ = true;
} }
@ -1193,9 +1186,6 @@ 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);
@ -1213,16 +1203,9 @@ 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);
return true; Engine::Get().LoadCustomShader("chromatic_aberration",
} "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;
} }

View File

@ -15,7 +15,6 @@
namespace eng { namespace eng {
class Image; class Image;
class Shader;
class Sound; class Sound;
} // namespace eng } // namespace eng
@ -30,8 +29,6 @@ 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);
@ -106,7 +103,6 @@ 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_;
@ -169,7 +165,6 @@ 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);
}; };

View File

@ -6,14 +6,12 @@
#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()
: shader_(Engine::Get().CreateRenderResource<Shader>()), : sky_offset_{
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_;
} }
@ -22,10 +20,9 @@ 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);
@ -54,10 +51,6 @@ 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);
@ -66,17 +59,6 @@ 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;
} }

View File

@ -36,8 +36,6 @@ 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);
@ -45,7 +43,7 @@ class SkyQuad : public eng::Animatable {
const base::Vector4f& nebula_color() { return nebula_color_; } const base::Vector4f& nebula_color() { return nebula_color_; }
private: private:
std::unique_ptr<eng::Shader> shader_; 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};
@ -57,8 +55,6 @@ 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

View File

@ -109,6 +109,7 @@ 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) {
@ -277,6 +278,42 @@ 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;
@ -452,6 +489,13 @@ 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();
} }

View File

@ -79,6 +79,11 @@ 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();
@ -158,6 +163,12 @@ 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;
@ -184,8 +195,9 @@ class Engine {
std::list<Animator*> animators_; std::list<Animator*> animators_;
// Textures mapped by asset name. // Managed render resources 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_;

View File

@ -49,8 +49,8 @@ void ImageQuad::AutoScale() {
SetSize(size); SetSize(size);
} }
void ImageQuad::SetCustomShader(Shader* shader) { void ImageQuad::SetCustomShader(const std::string& asset_name) {
custom_shader_ = shader; custom_shader_ = Engine::Get().GetCustomShader(asset_name);
custom_uniforms_.clear(); custom_uniforms_.clear();
} }

View File

@ -28,7 +28,7 @@ class ImageQuad final : public Animatable {
void AutoScale(); void AutoScale();
void SetCustomShader(Shader* shader); void SetCustomShader(const std::string& asset_name);
template <typename T> template <typename T>
void SetCustomUniform(const std::string& name, T value) { void SetCustomUniform(const std::string& name, T value) {