#include "Effect.hpp"
#include <SFML/Graphics.hpp>
#include <vector>
#include <cmath>
const
sf::Font* Effect::s_font = NULL;
class
Pixelate :
public
Effect
{
public
:
Pixelate() :
Effect(
"pixelate"
)
{
}
bool
onLoad()
{
if
(!m_texture.loadFromFile(
"resources/background.jpg"
))
return
false
;
m_sprite.setTexture(m_texture);
if
(!m_shader.loadFromFile(
"resources/pixelate.frag"
, sf::Shader::Fragment))
return
false
;
m_shader.setParameter(
"texture"
, sf::Shader::CurrentTexture);
return
true
;
}
void
onUpdate(
float
,
float
x,
float
y)
{
m_shader.setParameter(
"pixel_threshold"
, (x + y) / 30);
}
void
onDraw(sf::RenderTarget& target, sf::RenderStates states)
const
{
states.shader = &m_shader;
target.draw(m_sprite, states);
}
private
:
sf::Texture m_texture;
sf::Sprite m_sprite;
sf::Shader m_shader;
};
class
WaveBlur :
public
Effect
{
public
:
WaveBlur() :
Effect(
"wave + blur"
)
{
}
bool
onLoad()
{
m_text.setString(
"Praesent suscipit augue in velit pulvinar hendrerit varius purus aliquam.\n"
"Mauris mi odio, bibendum quis fringilla a, laoreet vel orci. Proin vitae vulputate tortor.\n"
"Praesent cursus ultrices justo, ut feugiat ante vehicula quis.\n"
"Donec fringilla scelerisque mauris et viverra.\n"
"Maecenas adipiscing ornare scelerisque. Nullam at libero elit.\n"
"Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas.\n"
"Nullam leo urna, tincidunt id semper eget, ultricies sed mi.\n"
"Morbi mauris massa, commodo id dignissim vel, lobortis et elit.\n"
"Fusce vel libero sed neque scelerisque venenatis.\n"
"Integer mattis tincidunt quam vitae iaculis.\n"
"Vivamus fringilla sem non velit venenatis fermentum.\n"
"Vivamus varius tincidunt nisi id vehicula.\n"
"Integer ullamcorper, enim vitae euismod rutrum, massa nisl semper ipsum,\n"
"vestibulum sodales sem ante in massa.\n"
"Vestibulum in augue non felis convallis viverra.\n"
"Mauris ultricies dolor sed massa convallis sed aliquet augue fringilla.\n"
"Duis erat eros, porta in accumsan in, blandit quis sem.\n"
"In hac habitasse platea dictumst. Etiam fringilla est id odio dapibus sit amet semper dui laoreet.\n"
);
m_text.setFont(getFont());
m_text.setCharacterSize(22);
m_text.setPosition(30, 20);
if
(!m_shader.loadFromFile(
"resources/wave.vert"
,
"resources/blur.frag"
))
return
false
;
return
true
;
}
void
onUpdate(
float
time
,
float
x,
float
y)
{
m_shader.setParameter(
"wave_phase"
,
time
);
m_shader.setParameter(
"wave_amplitude"
, x * 40, y * 40);
m_shader.setParameter(
"blur_radius"
, (x + y) * 0.008f);
}
void
onDraw(sf::RenderTarget& target, sf::RenderStates states)
const
{
states.shader = &m_shader;
target.draw(m_text, states);
}
private
:
sf::Text m_text;
sf::Shader m_shader;
};
class
StormBlink :
public
Effect
{
public
:
StormBlink() :
Effect(
"storm + blink"
)
{
}
bool
onLoad()
{
m_points.setPrimitiveType(sf::Points);
for
(
int
i = 0; i < 40000; ++i)
{
float
x =
static_cast
<
float
>(std::
rand
() % 800);
float
y =
static_cast
<
float
>(std::
rand
() % 600);
sf::Uint8 r = std::
rand
() % 255;
sf::Uint8 g = std::
rand
() % 255;
sf::Uint8 b = std::
rand
() % 255;
m_points.append(sf::Vertex(sf::Vector2f(x, y), sf::Color(r, g, b)));
}
if
(!m_shader.loadFromFile(
"resources/storm.vert"
,
"resources/blink.frag"
))
return
false
;
return
true
;
}
void
onUpdate(
float
time
,
float
x,
float
y)
{
float
radius = 200 + std::
cos
(
time
) * 150;
m_shader.setParameter(
"storm_position"
, x * 800, y * 600);
m_shader.setParameter(
"storm_inner_radius"
, radius / 3);
m_shader.setParameter(
"storm_total_radius"
, radius);
m_shader.setParameter(
"blink_alpha"
, 0.5f + std::
cos
(
time
* 3) * 0.25f);
}
void
onDraw(sf::RenderTarget& target, sf::RenderStates states)
const
{
states.shader = &m_shader;
target.draw(m_points, states);
}
private
:
sf::VertexArray m_points;
sf::Shader m_shader;
};
class
Edge :
public
Effect
{
public
:
Edge() :
Effect(
"edge post-effect"
)
{
}
bool
onLoad()
{
if
(!m_surface.create(800, 600))
return
false
;
m_surface.setSmooth(
true
);
if
(!m_backgroundTexture.loadFromFile(
"resources/sfml.png"
))
return
false
;
m_backgroundTexture.setSmooth(
true
);
if
(!m_entityTexture.loadFromFile(
"resources/devices.png"
))
return
false
;
m_entityTexture.setSmooth(
true
);
m_backgroundSprite.setTexture(m_backgroundTexture);
m_backgroundSprite.setPosition(135, 100);
for
(
int
i = 0; i < 6; ++i)
{
sf::Sprite entity(m_entityTexture, sf::IntRect(96 * i, 0, 96, 96));
m_entities.push_back(entity);
}
if
(!m_shader.loadFromFile(
"resources/edge.frag"
, sf::Shader::Fragment))
return
false
;
m_shader.setParameter(
"texture"
, sf::Shader::CurrentTexture);
return
true
;
}
void
onUpdate(
float
time
,
float
x,
float
y)
{
m_shader.setParameter(
"edge_threshold"
, 1 - (x + y) / 2);
for
(std::
size_t
i = 0; i < m_entities.size(); ++i)
{
sf::Vector2f position;
position.x = std::
cos
(0.25f * (
time
* i + (m_entities.size() - i))) * 300 + 350;
position.y = std::
sin
(0.25f * (
time
* (m_entities.size() - i) + i)) * 200 + 250;
m_entities[i].setPosition(position);
}
m_surface.clear(sf::Color::White);
m_surface.draw(m_backgroundSprite);
for
(std::
size_t
i = 0; i < m_entities.size(); ++i)
m_surface.draw(m_entities[i]);
m_surface.display();
}
void
onDraw(sf::RenderTarget& target, sf::RenderStates states)
const
{
states.shader = &m_shader;
target.draw(sf::Sprite(m_surface.getTexture()), states);
}
private
:
sf::RenderTexture m_surface;
sf::Texture m_backgroundTexture;
sf::Texture m_entityTexture;
sf::Sprite m_backgroundSprite;
std::vector<sf::Sprite> m_entities;
sf::Shader m_shader;
};
int
main()
{
sf::RenderWindow window(sf::VideoMode(800, 600),
"SFML Shader"
);
window.setVerticalSyncEnabled(
true
);
sf::Font font;
if
(!font.loadFromFile(
"resources/sansation.ttf"
))
return
EXIT_FAILURE;
Effect::setFont(font);
std::vector<Effect*> effects;
effects.push_back(
new
Pixelate);
effects.push_back(
new
WaveBlur);
effects.push_back(
new
StormBlink);
effects.push_back(
new
Edge);
std::
size_t
current = 0;
for
(std::
size_t
i = 0; i < effects.size(); ++i)
effects[i]->load();
sf::Texture textBackgroundTexture;
if
(!textBackgroundTexture.loadFromFile(
"resources/text-background.png"
))
return
EXIT_FAILURE;
sf::Sprite textBackground(textBackgroundTexture);
textBackground.setPosition(0, 520);
textBackground.setColor(sf::Color(255, 255, 255, 200));
sf::Text description(
"Current effect: "
+ effects[current]->getName(), font, 20);
description.setPosition(10, 530);
description.setColor(sf::Color(80, 80, 80));
sf::Text instructions(
"Press left and right arrows to change the current shader"
, font, 20);
instructions.setPosition(280, 555);
instructions.setColor(sf::Color(80, 80, 80));
sf::Clock
clock
;
while
(window.isOpen())
{
sf::Event event;
while
(window.pollEvent(event))
{
if
(event.type == sf::Event::Closed)
window.close();
if
(event.type == sf::Event::KeyPressed)
{
switch
(event.key.code)
{
case
sf::Keyboard::Escape:
window.close();
break
;
case
sf::Keyboard::Left:
if
(current == 0)
current = effects.size() - 1;
else
current--;
description.setString(
"Current effect: "
+ effects[current]->getName());
break
;
case
sf::Keyboard::Right:
if
(current == effects.size() - 1)
current = 0;
else
current++;
description.setString(
"Current effect: "
+ effects[current]->getName());
break
;
default
:
break
;
}
}
}
float
x =
static_cast
<
float
>(sf::Mouse::getPosition(window).x) / window.getSize().x;
float
y =
static_cast
<
float
>(sf::Mouse::getPosition(window).y) / window.getSize().y;
effects[current]->update(
clock
.getElapsedTime().asSeconds(), x, y);
window.clear(sf::Color(255, 128, 0));
window.draw(*effects[current]);
window.draw(textBackground);
window.draw(instructions);
window.draw(description);
window.display();
}
for
(std::
size_t
i = 0; i < effects.size(); ++i)
delete
effects[i];
return
EXIT_SUCCESS;
}