Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: Simple Lib for Hardshadows - WIP, comments and questions wanted  (Read 3723 times)

0 Members and 1 Guest are viewing this topic.

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
Simple Lib for Hardshadows - WIP, comments and questions wanted
« on: January 25, 2014, 11:40:05 pm »
Code:
https://github.com/FRex/HardLight

If 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
}
 
« Last Edit: January 26, 2014, 12:58:36 am by FRex »
Back to C++ gamedev with SFML in May 2023

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Looks very cool   :D

Only thing I can think of to say is that maybe you should turn on anti aliasing for that screenshot  ;)

(and I can't wait to see the code)
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
I'm on a very bad Intel card on a 'Business Laptop', anti aliasing doesn't work at all. :P
I added code so if someone really wants to test it in its half-done state and see the API they can. ;)

After some changes the first post code no longer works (namespace name change + small API change), but there is box2d-like class hlt::LightDef that you fill with info and get a light from it, simply set color, initial position, radius, angle and spread (how wide is the cone) in there and then pass it as first (and only) arg to addLight.
I also made it so that lights that hit no lines don't convert between clipper and sf points at all. But there is still bottleneck in both circl methods (small) and clipper (big). If there are many changing lights and many lines then clipper will take half or more time (according to perf).

Also you can use a global function with smart pointers that just calls light->remove() to remove light from the shadow world (but after calling it the pointer is invalid so it's equivalent to delete, except this removes the light from internal list, doesn't expose how it's allocated and so on ;) ).
« Last Edit: January 28, 2014, 07:15:35 pm by FRex »
Back to C++ gamedev with SFML in May 2023