Skip to content

Instantly share code, notes, and snippets.

@rubenwardy rubenwardy/DropShadow.cpp
Last active May 12, 2020

Embed
What would you like to do?
uniform sampler2D source;
uniform vec4 mask;
uniform vec2 direction;
void main() {
vec2 textureCoordinates = gl_TexCoord[0].xy;
vec4 color = vec4(0.0);
color += texture2D(source, textureCoordinates - 4.0 * direction) * 0.0162162162;
color += texture2D(source, textureCoordinates - 3.0 * direction) * 0.0540540541;
color += texture2D(source, textureCoordinates - 2.0 * direction) * 0.1216216216;
color += texture2D(source, textureCoordinates - direction) * 0.1945945946;
color += texture2D(source, textureCoordinates) * 0.2270270270;
color += texture2D(source, textureCoordinates + direction) * 0.1945945946;
color += texture2D(source, textureCoordinates + 2.0 * direction) * 0.1216216216;
color += texture2D(source, textureCoordinates + 3.0 * direction) * 0.0540540541;
color += texture2D(source, textureCoordinates + 4.0 * direction) * 0.0162162162;
color = mask * vec4(100.0, 100.0, 100.0, color[3]) / 100.0;
gl_FragColor = color;
}
#include "DropShadow.hpp"
#include <cassert>
#include <cmath>
#include <memory>
using namespace sfext;
namespace {
std::unique_ptr<sf::Shader> shadowShader;
sf::Glsl::Vec4 convert255to100(const sf::Color &color) {
return sf::Glsl::Vec4((float)color.r * 100.f / 255.f,
(float)color.g * 100.f / 255.f, (float)color.b * 100.f / 255.f,
(float)color.a * 100.f / 255.f);
}
} // namespace
bool DropShadow::load(const std::string &shadowPath) {
shadowShader = std::make_unique<sf::Shader>();
return shadowShader->loadFromFile(shadowPath, sf::Shader::Fragment);
}
void DropShadow::draw(
sf::RenderTarget &target, sf::RenderStates baseStates) const {
auto transformable = dynamic_cast<const sf::Transformable *>(&drawable);
// Draw shadow
{
sf::Vector2f pos = transformable->getPosition() -
transformable->getOrigin() + offset -
sf::Vector2f(10, 10);
pos = {std::round(pos.x), std::round(pos.y)};
sf::RenderStates states = baseStates;
sf::Sprite sprite(texture.getTexture());
shadowShader->setUniform("mask", convert255to100(color));
shadowShader->setUniform("direction", sf::Vector2f(0.f, pixelSize.y));
states.shader = shadowShader.get();
states.transform.translate(pos);
target.draw(sprite, states);
}
// Draw drawable
{
sf::Vector2f pos =
transformable->getPosition() - transformable->getOrigin();
pos = {std::round(pos.x), std::round(pos.y)};
target.draw(drawable, baseStates);
}
}
void DropShadow::regenerate() {
auto transformable = dynamic_cast<const sf::Transformable *>(&drawable);
SanityCheck(transformable);
sf::Vector2i textureSize = {size.x + 20, size.y + 20};
pixelSize = {1.f / float(textureSize.x), 1.f / float(textureSize.y)};
// Render font to a single texture
sf::RenderTexture tmpTexture;
{
SanityCheck(tmpTexture.create(textureSize.x, textureSize.y));
tmpTexture.clear(sf::Color::Transparent);
sf::RenderStates states = sf::RenderStates::Default;
states.transform = transformable->getInverseTransform();
states.transform.translate({10, 10});
tmpTexture.draw(drawable, states);
tmpTexture.display();
}
// Render horizontal blur
{
SanityCheck(texture.create(textureSize.x, textureSize.y));
texture.clear(sf::Color::Transparent);
sf::Sprite sprite(tmpTexture.getTexture());
sf::RenderStates states = sf::RenderStates::Default;
shadowShader->setUniform("mask", sf::Glsl::Vec4(100, 100, 100, 100));
shadowShader->setUniform("direction", sf::Vector2f(pixelSize.x, 0.f));
states.shader = shadowShader.get();
texture.draw(sprite, states);
texture.display();
}
}
#include <SFML/Graphics.hpp>
#include <string>
namespace sfext {
class DropShadow : public sf::Drawable {
const sf::Drawable &drawable;
const sf::Vector2f size;
const sf::Vector2f offset;
const sf::Color color;
sf::RenderTexture texture;
sf::Vector2f pixelSize;
public:
DropShadow(const sf::Drawable &drawable, sf::Vector2f size,
sf::Vector2f offset, sf::Color color)
: drawable(drawable), size(size), offset(offset), color(color) {
regenerate();
}
[[nodiscard]] static bool load(const std::string &shadowPath);
private:
virtual void draw(
sf::RenderTarget &target, sf::RenderStates states) const override;
void regenerate();
};
} // namespace sfext
sf::Text rawlabel = sf::Text("RVWP", font, 17);
rawlabel.setFillColor(sf::Color::White);
sfext::DropShadow label(static_cast<const sf::Drawable&>(rawlabel),
rawlabel.getLocalBounds(), sf::Vector2f(1.f, 2.f), sf::Color(0x0000007f));
const auto size = rwindow->getSize();
label.setPosition(sf::Vector2f(size.x / 2, size.y * 0.1f));
sf::FloatRect textRect = rawlabel.getLocalBounds();
label.setOrigin(textRect.left + textRect.width / 2.0f,
textRect.top + textRect.height / 2.0f);
rwindow->draw(label);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.