Code:
https://github.com/FRex/HardLightIf you want to try it the easiest way would be to include the files in own project and link ClipperLib(see link in readme) and SFML yourself. There's also a class I used for debug drawing of polygons, circles, lines, segments, etc. included in repo. I have gcc (GCC) 4.8.2 20131212 (Red Hat 4.8.2-7), I have no idea if it'll work under VS 2012 and 2013, I know 2010 won't because of ranged for and earlier won't because of unique ptr and auto.
Based on first few posts in this thread:
http://en.sfml-dev.org/forums/index.php?topic=14154.msg99291#msg99291 I decided one week ago to implement lightning system that'd do hard shadows, some post of mine there are about my ideas but most changed since, the result came out rather nice IMO. Well, I don't really know what to say : I might soon, after I do more work, post it on github under same license as SFML but there are still some features to add and things to check/clean up so I'm not doing that for now (also I need to relearn how to upload to github from git, and I need to delete my old master branch in which I had the polygons not lines
).
Questions and opinions are very welcome.
Here are line counts, although more than half of is Box2D dynamic tree code that I ripped out(and that still needs cleaning, even after I spent an hour or two getting it self contained, less Cish and not tied to anything else in Box2D).
[frex@localhost shadows]$ cloc src/
14 text files.
14 unique files.
0 files ignored.
http://cloc.sourceforge.net v 1.60 T=0.11 s (125.3 files/s, 25493.7 lines/s)
-------------------------------------------------------------------------------
Language files blank comment code
-------------------------------------------------------------------------------
C++ 7 335 105 1336
C/C++ Header 7 277 154 641
-------------------------------------------------------------------------------
SUM: 14 612 259 1977
-------------------------------------------------------------------------------
Here's a screen of bunch of white lights and shadow lines casting shadows + one red light under cursor that has pi/2 spread code set on it.
Here is the code that I used to that effect, as you can see it's quite intuitive what is going on.
BTW - the LightPainter is not tied in any way to ShadowWorld, you can retrieve the points of final light volume or individual shadows for each light and draw/use them any way you want. This is what LightPainter is doing, iterating over all QueriedLights and drawing with an optional shader using the calculated light volume.
#include <SFML/Graphics.hpp>
#include "ShadowWorld.hpp"
#include "LightPainter.hpp"
int main()
{
sf::RenderWindow app(sf::VideoMode(640u, 480u), "lights");
app.setFramerateLimit(60u);
//prepare shadow world and set its view
ee::ShadowWorld sw;
sw.setViewRect(sf::FloatRect(0.f, 0.f, 640.f, 480.f));
//prepare light painter and set internal texture size
ee::LightPainter lp;
lp.setSize(640u, 480u);
lp.enableFragFromFile("light.frag");
ee::Light * lit = sw.addLight(sf::Vector2f(0.f, 0.f), 100.f);
lit->setColor(sf::Color::Red);
lit->setSpread(ee::halfpi);
bool adding = false;
sf::Vector2f p1;
while (app.isOpen())
{
sf::Event eve;
while (app.pollEvent(eve))
{
switch (eve.type)
{
case sf::Event::Closed:
app.close();
break;
case sf::Event::MouseMoved:
lit->setPosition(sf::Vector2f(eve.mouseMove.x, eve.mouseMove.y));
break;
case sf::Event::MouseButtonPressed:
if (eve.mouseButton.button == sf::Mouse::Left)
{
adding = true;
p1 = sf::Vector2f(eve.mouseButton.x, eve.mouseButton.y);
}
else if (eve.mouseButton.button == sf::Mouse::Right)
{
sw.addLight(sf::Vector2f(eve.mouseButton.x, eve.mouseButton.y), 150.f);
}
break;
case sf::Event::MouseButtonReleased:
if (eve.mouseButton.button == sf::Mouse::Left)
{
sw.addLine(p1, sf::Vector2f(eve.mouseButton.x, eve.mouseButton.y));
adding = false;
}
break;
}//switch eve.type
}//while pollEvent
app.clear(sf::Color::White);
//update shadow world and then render that
sw.update();
lp.render(sw);
//multiply texture of painters render texture with scene
app.draw(sf::Sprite(lp.getCanvas()), sf::BlendMultiply);
//if space pressed draw all lines that participated in last update
if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space))
{
for (unsigned i = 0u; i < sw.getQueriedLinesCount(); ++i)
{
sf::Vertex vert[2];
vert[0].position = sw.getQueriedLine(i).a;
vert[1].position = sw.getQueriedLine(i).b;
app.draw(vert, 2u, sf::Lines);
}
}
if (adding)
{
sf::Vertex vert[2];
vert[0].position = p1;
vert[1].position = sf::Vector2f(sf::Mouse::getPosition(app));
vert[0].color = vert[1].color = sf::Color::Yellow;
app.draw(vert, 2u, sf::Lines);
}
app.display();
}//while app is open
}