Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for custom texture #29

Draft
wants to merge 5 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 47 additions & 1 deletion include/Candle/RadialLight.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,11 @@ namespace candle{
class RadialLight: public LightSource{
private:
static int s_instanceCount;
float m_beamAngle;
float m_beamAngle;
unsigned int m_localRadius;

sf::Texture* m_lightTextureFade;
sf::Texture* m_lightTexturePlain;

void draw(sf::RenderTarget& t, sf::RenderStates st) const override;
void resetColor() override;
Expand Down Expand Up @@ -66,6 +70,48 @@ namespace candle{
*/
float getBeamAngle() const;

/**
* @brief Set the light fade texture.
* @details The default texture is generated internally.
* @see getLightFadeTexture
*/
void setLightFadeTexture(sf::Texture& texture);

/**
* @brief Get the light fade texture.
* @returns The actual light fade texture.
* @see setLightFadeTexture
*/
sf::Texture* getLightFadeTexture();

/**
* @brief Set the light plain texture.
* @details The default texture is generated internally.
* @see getLightPlainTexture
*/
void setLightPlainTexture(sf::Texture& texture);

/**
* @brief Get the light plain texture.
* @returns The actual light plain texture.
* @see setLightPlainTexture
*/
sf::Texture* getLightPlainTexture();

/**
* @brief Get the default internally generated light fade texture.
* @returns The default light fade texture.
* @see getLightFadeTexture
*/
std::shared_ptr<sf::Texture> getDefaultLightFadeTexture() const;

/**
* @brief Get the default internally generated light plain texture.
* @returns The default light plain texture.
* @see getLightFadeTexture
*/
std::shared_ptr<sf::Texture> getDefaultLightPlainTexture() const;

/**
* @brief Get the local bounding rectangle of the light.
* @returns The local bounding rectangle in float.
Expand Down
169 changes: 114 additions & 55 deletions src/RadialLight.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,41 +13,51 @@

namespace candle{
int RadialLight::s_instanceCount = 0;
const float BASE_RADIUS = 400.0f;
const unsigned int BASE_RADIUS = 400;
bool l_texturesReady(false);
std::unique_ptr<sf::RenderTexture> l_lightTextureFade;
std::unique_ptr<sf::RenderTexture> l_lightTexturePlain;
std::shared_ptr<sf::Texture> l_lightTextureFade;
std::shared_ptr<sf::Texture> l_lightTexturePlain;

void initializeTextures(){
#ifdef CANDLE_DEBUG
std::cout << "RadialLight: InitializeTextures" << std::endl;
#endif
int points = 100;

l_lightTextureFade.reset(new sf::RenderTexture);
l_lightTexturePlain.reset(new sf::RenderTexture);
l_lightTextureFade->create(BASE_RADIUS*2 + 2, BASE_RADIUS*2 + 2);
l_lightTexturePlain->create(BASE_RADIUS*2 + 2, BASE_RADIUS*2 + 2);

sf::VertexArray lightShape(sf::TriangleFan, points+2);
float step = sfu::PI*2.f/points;
lightShape[0].position = {BASE_RADIUS + 1, BASE_RADIUS + 1};
for(int i = 1; i < points+2; i++){
lightShape[i].position = {
(std::sin(step*(i)) + 1) * BASE_RADIUS + 1,
(std::cos(step*(i)) + 1) * BASE_RADIUS + 1
};
lightShape[i].color.a = 0;
}
l_lightTextureFade->clear(sf::Color::Transparent);
l_lightTextureFade->draw(lightShape);
l_lightTextureFade->display();
l_lightTextureFade->setSmooth(true);

sfu::setColor(lightShape, sf::Color::White);
l_lightTexturePlain->clear(sf::Color::Transparent);
l_lightTexturePlain->draw(lightShape);
l_lightTexturePlain->display();

sf::Image lightImageFade;
sf::Image lightImagePlain;

//We create an image of the radius*2 + an 2 more pixels
lightImageFade.create(BASE_RADIUS*2+2, BASE_RADIUS*2+2, sf::Color(255,255,255,0));
lightImagePlain.create(BASE_RADIUS*2+2, BASE_RADIUS*2+2, sf::Color(255,255,255,0));

sf::Vector2f center = {BASE_RADIUS, BASE_RADIUS};

for (unsigned int y=1; y<BASE_RADIUS*2; ++y)
{
for (unsigned int x=1; x<BASE_RADIUS*2; ++x)
{
//Get distance of the pixel from the center, normalize it with the radius and inverse it
float distanceFromCenter = 1.0f - sfu::magnitude(sf::Vector2f(x,y) - center) / BASE_RADIUS;

if ( distanceFromCenter < 0.0f )
{//Too far from center, pixel will be fully transparent
lightImageFade.setPixel(x,y, sf::Color(255,255,255,0));
lightImagePlain.setPixel(x,y, sf::Color(255,255,255,0));
}
else
{
lightImageFade.setPixel(x,y, sf::Color(255,255,255, static_cast<unsigned int>(255.0f*distanceFromCenter)));
lightImagePlain.setPixel(x,y, sf::Color(255,255,255,255));
}
}
}

l_lightTextureFade.reset( new sf::Texture() );
l_lightTextureFade->loadFromImage(lightImageFade);
l_lightTextureFade->setSmooth(true);

l_lightTexturePlain.reset( new sf::Texture() );
l_lightTexturePlain->loadFromImage(lightImagePlain);
l_lightTexturePlain->setSmooth(true);
}

Expand All @@ -64,26 +74,17 @@ namespace candle{
// The first time we create a RadialLight, we must create the textures
initializeTextures();
l_texturesReady = true;
}
m_polygon.setPrimitiveType(sf::TriangleFan);
m_polygon.resize(6);
m_polygon[0].position =
m_polygon[0].texCoords = {BASE_RADIUS+1, BASE_RADIUS+1};
m_polygon[1].position =
m_polygon[5].position =
m_polygon[1].texCoords =
m_polygon[5].texCoords = {0.f, 0.f};
m_polygon[2].position =
m_polygon[2].texCoords = {BASE_RADIUS*2 + 2, 0.f};
m_polygon[3].position =
m_polygon[3].texCoords = {BASE_RADIUS*2 + 2, BASE_RADIUS*2 + 2};
m_polygon[4].position =
m_polygon[4].texCoords = {0.f, BASE_RADIUS*2 + 2};
Transformable::setOrigin(BASE_RADIUS, BASE_RADIUS);
}

setLightFadeTexture( *l_lightTextureFade.get() );
setLightPlainTexture( *l_lightTexturePlain.get() );

setRange(1.0f);
setBeamAngle(360.f);
// castLight();
s_instanceCount++;
s_instanceCount++;

setColor(sf::Color(255,255,255,255));
}

RadialLight::~RadialLight(){
Expand All @@ -105,9 +106,9 @@ namespace candle{

void RadialLight::draw(sf::RenderTarget& t, sf::RenderStates s) const{
sf::Transform trm = Transformable::getTransform();
trm.scale(m_range/BASE_RADIUS, m_range/BASE_RADIUS, BASE_RADIUS, BASE_RADIUS);
trm.scale(m_range/m_localRadius, m_range/m_localRadius, m_localRadius, m_localRadius);
s.transform *= trm;
s.texture = m_fade ? &l_lightTextureFade->getTexture() : &l_lightTexturePlain->getTexture();
s.texture = m_fade ? m_lightTextureFade : m_lightTexturePlain;
if(s.blendMode == sf::BlendAlpha){
s.blendMode = sf::BlendAdd;
}
Expand All @@ -130,21 +131,79 @@ namespace candle{
return m_beamAngle;
}

void RadialLight::setLightFadeTexture(sf::Texture& texture){
m_lightTextureFade = &texture;
m_localRadius = (texture.getSize().x > texture.getSize().y) ? texture.getSize().x/2+1 : texture.getSize().y/2+1;

m_polygon.setPrimitiveType(sf::TriangleFan);
m_polygon.resize(6);
m_polygon[0].position =
m_polygon[0].texCoords = {static_cast<float>(m_localRadius), static_cast<float>(m_localRadius)};
m_polygon[1].position =
m_polygon[5].position =
m_polygon[1].texCoords =
m_polygon[5].texCoords = {0.f, 0.f};
m_polygon[2].position =
m_polygon[2].texCoords = {static_cast<float>(m_localRadius)*2, 0.f};
m_polygon[3].position =
m_polygon[3].texCoords = {static_cast<float>(m_localRadius)*2, static_cast<float>(m_localRadius)*2};
m_polygon[4].position =
m_polygon[4].texCoords = {0.f, static_cast<float>(m_localRadius)*2};
Transformable::setOrigin(m_localRadius, m_localRadius);
}

sf::Texture* RadialLight::getLightFadeTexture(){
return m_lightTextureFade;
}

void RadialLight::setLightPlainTexture(sf::Texture& texture){
m_lightTexturePlain = &texture;
m_localRadius = (texture.getSize().x > texture.getSize().y) ? texture.getSize().x/2 : texture.getSize().y/2;

m_polygon.setPrimitiveType(sf::TriangleFan);
m_polygon.resize(6);
m_polygon[0].position =
m_polygon[0].texCoords = {static_cast<float>(m_localRadius), static_cast<float>(m_localRadius)};
m_polygon[1].position =
m_polygon[5].position =
m_polygon[1].texCoords =
m_polygon[5].texCoords = {0.f, 0.f};
m_polygon[2].position =
m_polygon[2].texCoords = {static_cast<float>(m_localRadius)*2, 0.f};
m_polygon[3].position =
m_polygon[3].texCoords = {static_cast<float>(m_localRadius)*2, static_cast<float>(m_localRadius)*2};
m_polygon[4].position =
m_polygon[4].texCoords = {0.f, static_cast<float>(m_localRadius)*2};
Transformable::setOrigin(m_localRadius, m_localRadius);
}

sf::Texture* RadialLight::getLightPlainTexture(){
return m_lightTexturePlain;
}

std::shared_ptr<sf::Texture> RadialLight::getDefaultLightFadeTexture() const{
return l_lightTextureFade;
}

std::shared_ptr<sf::Texture> RadialLight::getDefaultLightPlainTexture() const{
return l_lightTexturePlain;
}

sf::FloatRect RadialLight::getLocalBounds() const{
return sf::FloatRect(0.0f, 0.0f, BASE_RADIUS*2, BASE_RADIUS*2);
return sf::FloatRect(0.0f, 0.0f, m_localRadius*2, m_localRadius*2);
}

sf::FloatRect RadialLight::getGlobalBounds() const{
float scaledRange = m_range / BASE_RADIUS;
float scaledRange = m_range / m_localRadius;
sf::Transform trm = Transformable::getTransform();
trm.scale(scaledRange, scaledRange, BASE_RADIUS, BASE_RADIUS);
trm.scale(scaledRange, scaledRange, m_localRadius, m_localRadius);
return trm.transformRect( getLocalBounds() );
}

void RadialLight::castLight(const EdgeVector::iterator& begin, const EdgeVector::iterator& end){
float scaledRange = m_range / BASE_RADIUS;
float scaledRange = m_range / m_localRadius;
sf::Transform trm = Transformable::getTransform();
trm.scale(scaledRange, scaledRange, BASE_RADIUS, BASE_RADIUS);
trm.scale(scaledRange, scaledRange, m_localRadius, m_localRadius);
std::vector<sfu::Line> rays;

rays.reserve(2 + std::distance(begin, end) * 2 * 3); // 2: beam angle, 4: corners, 2: pnts/sgmnt, 3 rays/pnt
Expand All @@ -166,7 +225,7 @@ namespace candle{
if(beamAngleBigEnough || angleInBeam(a)){
rays.emplace_back(castPoint, a);
}
}
}

sf::FloatRect lightBounds = getGlobalBounds();
for(auto it = begin; it != end; it++){
Expand Down Expand Up @@ -223,7 +282,7 @@ namespace candle{
std::vector<sf::Vector2f> points;
points.reserve(rays.size());
for (auto& r: rays){
points.push_back(tr_i.transformPoint(castRay(begin, end, r, m_range*m_range)));
points.push_back(tr_i.transformPoint(castRay(begin, end, r, m_range*2)));
}
m_polygon.resize(points.size() + 1 + beamAngleBigEnough); // + center and last
m_polygon[0].color = m_color;
Expand Down