Skip to content

Instantly share code, notes, and snippets.

@falrnd
Last active January 23, 2020 06:38
Show Gist options
  • Save falrnd/96b95e5d31488fc0b2b7fe597063edf1 to your computer and use it in GitHub Desktop.
Save falrnd/96b95e5d31488fc0b2b7fe597063edf1 to your computer and use it in GitHub Desktop.
#pragma once
#include <Siv3D.hpp>
// https://siv3d.github.io/ja-jp/sample/visual/#2d
class LightBloom2D
{
protected:
Size sceneSize;
RenderTexture gaussianA1, gaussianB1;
RenderTexture gaussianA4, gaussianB4;
RenderTexture gaussianA8, gaussianB8;
public:
explicit LightBloom2D(const Size& sceneSize)
: sceneSize(sceneSize),
gaussianA1(sceneSize), gaussianB1(sceneSize),
gaussianA4(sceneSize / 4), gaussianB4(sceneSize / 4),
gaussianA8(sceneSize / 8), gaussianB8(sceneSize / 8)
{
init();
}
void init()
{
gaussianA1.clear(ColorF(0.0));
}
void clear()
{
gaussianA1.clear(ColorF(0.0));
gaussianA4.clear(ColorF(0.0));
gaussianA8.clear(ColorF(0.0));
}
void draw(double a8 = 1, double a4 = 1, double a1 = 1)
{
// オリジナルサイズのガウスぼかし (A1)
// A1 を 1/4 サイズにしてガウスぼかし (A4)
// A4 を 1/2 サイズにしてガウスぼかし (A8)
Shader::GaussianBlur(gaussianA1, gaussianB1, gaussianA1);
Shader::Downsample(gaussianA1, gaussianA4);
Shader::GaussianBlur(gaussianA4, gaussianB4, gaussianA4);
Shader::Downsample(gaussianA4, gaussianA8);
Shader::GaussianBlur(gaussianA8, gaussianB8, gaussianA8);
ScopedRenderStates2D blend(BlendState::Additive);
if (a1)
gaussianA1.resized(sceneSize).draw(ColorF(a1));
if (a4)
gaussianA4.resized(sceneSize).draw(ColorF(a4));
if (a8)
gaussianA8.resized(sceneSize).draw(ColorF(a8));
}
using RenderScope = std::pair<ScopedRenderTarget2D, ScopedRenderStates2D>;
[[nodiscard]] RenderScope makeRenderScope() const
{
return std::make_pair(ScopedRenderTarget2D(gaussianA1), ScopedRenderStates2D(BlendState::Additive));
}
private:
class ScopedLightBloom : Uncopyable
{
private:
friend class LightBloom2D;
Optional<RenderScope> rs;
std::reference_wrapper<LightBloom2D> _this;
double a8, a4, a1;
ScopedLightBloom(Optional<RenderScope>&& rs, LightBloom2D& _this, double a8, double a4, double a1)
: rs(std::move(rs)), _this(_this),
a8(a8), a4(a4), a1(a1)
{
_this.init();
}
public:
~ScopedLightBloom()
{
rs.reset();
_this.get().draw(a8, a4, a1);
}
};
public:
[[nodiscard]] auto makeLightBloomScope(double a8 = 1, double a4 = 1, double a1 = 1)
{
return ScopedLightBloom(makeRenderScope(), *this, a8, a4, a1);
}
};
void DrawScene()
{
Circle(680, 40, 20).draw();
Rect(Arg::center(680, 110), 30).draw();
Triangle(680, 180, 40).draw();
Circle(740, 40, 20).draw(HSV(0));
Rect(Arg::center(740, 110), 30).draw(HSV(120));
Triangle(740, 180, 40).draw(HSV(240));
Circle(50, 200, 300).drawFrame(4);
Circle(550, 450, 200).drawFrame(4);
for (auto i : step(12))
{
const double angle = i * 30_deg + Scene::Time() * 5_deg;
const Vec2 pos = OffsetCircular(Scene::Center(), 200, angle);
Circle(pos, 8).draw(HSV(i * 30));
}
}
void GUI(const Vec2& pos, double& a8, double& a4, double& a1) {
SimpleGUI::Slider(U"a8: {:.1f}"_fmt(a8), a8, 0.0, 4.0, pos);
SimpleGUI::Slider(U"a4: {:.1f}"_fmt(a4), a4, 0.0, 4.0, pos.movedBy(0, 40));
SimpleGUI::Slider(U"a1: {:.1f}"_fmt(a1), a1, 0.0, 4.0, pos.movedBy(0, 80));
if (SimpleGUI::Button(U"0, 0, 0", pos.movedBy(0, 120))) {
a8 = a4 = a1 = 0.0;
}
if (SimpleGUI::Button(U"1, 0, 0", pos.movedBy(0, 160))) {
a8 = 1.0;
a4 = a1 = 0.0;
}
if (SimpleGUI::Button(U"1, 1, 0", pos.movedBy(0, 200))) {
a8 = a4 = 1.0;
a1 = 0.0;
}
if (SimpleGUI::Button(U"1, 1, 1", pos.movedBy(0, 240))) {
a8 = a4 = a1 = 1.0;
}
}
void Main()
{
constexpr Size sceneSize(800, 600);
LightBloom2D lightbloom(sceneSize);
double a8 = 1, a4 = 1, a1 = 1;
while (System::Update())
{
DrawScene();
//*
lightbloom.init();
{
auto rs = lightbloom.makeRenderScope();
DrawScene();
}
lightbloom.draw(a8, a4, a1);
//*/
/*
{
auto rs = lightbloom.makeLightBloomScope(a8, a4, a1);
DrawScene();
}
//*/
GUI({ 20,20 }, a8, a4, a1);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment