SFML community forums

Help => Graphics => Topic started by: wh1t3crayon on October 22, 2014, 06:33:28 am

Title: Drawing a "flashlight texture" around mouse position?
Post by: wh1t3crayon on October 22, 2014, 06:33:28 am
I'm working on a project for class and I'm trying to design a maze, and the mouse will be your character, but the character has a limited sight distance so I want only the surrounding 50-100 pixels to be drawn from the point of the cursor. Are there any tutorials somebody can point me to/is this even possible?
Title: Re: Drawing a "flashlight texture" around mouse position?
Post by: Ixrec on October 22, 2014, 07:59:51 am
I can think of at least a few ways of doing it.  You could use a black texture with a hole and draw that over everything.  You could draw everything to a rendertexture then use a shader that takes the cursor position as input and darkens everything that's too far away from it.  There's probably also some way of doing this with blend modes.

My personal impression is that for "lighting" effects like this, shaders tend to be the best way to go.  There is a tutorial on SFML shaders, and although it obviously won't cover this exact example, writing a fragment shader that takes a point as input and darkens each pixel based on the distance from it should be fairly straightforward.
Title: Re: Drawing a "flashlight texture" around mouse position?
Post by: eXpl0it3r on October 22, 2014, 08:26:51 am
I've once written a small example for such a thing. You can find it here (https://github.com/eXpl0it3r/Examples/blob/master/SFML/Flashlight.cpp) and it will look something like this:

(https://legacy.sfmluploads.org/cache/pics/265_Flashlight1.png) (https://legacy.sfmluploads.org/cache/pics/266_Flashlight2.png)

Code-wise it's not the best example and as Ixrec the "right way" would be a shader, but if you've no idea how something like this works, my example might give you some basic idea. ;)
Title: Re: Drawing a "flashlight texture" around mouse position?
Post by: Mario on October 22, 2014, 08:47:12 am
It really depends on the minimum requirements you'd like to accept. Right now SFML doesn't support shaders on mobile platforms, while they're available everywhere else.

First, I'd create a render texture big enough to hold your flashlight only. You don't have to render the whole screen/scene if you won't see it anyway. Render the part visible to that texture using an appropriate view.

Clear the screen to black and draw your flashlight area to the correct position. You're now also able to simply use `sf::Sprite::setColor()` to modify the color every frame to create some kind of flicker (in case you'd like to achieve some kind of torch like effect).

I'd only use the shader approach if you'd like to do more than one light source and/or complex shadows.
Title: Re: Drawing a "flashlight texture" around mouse position?
Post by: wh1t3crayon on October 22, 2014, 02:37:32 pm
It really depends on the minimum requirements you'd like to accept. Right now SFML doesn't support shaders on mobile platforms, while they're available everywhere else.

First, I'd create a render texture big enough to hold your flashlight only. You don't have to render the whole screen/scene if you won't see it anyway. Render the part visible to that texture using an appropriate view.

Clear the screen to black and draw your flashlight area to the correct position. You're now also able to simply use `sf::Sprite::setColor()` to modify the color every frame to create some kind of flicker (in case you'd like to achieve some kind of torch like effect).

I'd only use the shader approach if you'd like to do more than one light source and/or complex shadows.

Render Texture sounds like the way to go here because it's a pretty crude application. It's my first time working with a RenderTexture, so I'm a little confused. The documentation says that it is used for off-screen drawing, but if I understand you, then you say to use it as the portion of the screen that is being displayed?

Also how do I make the render texture circular? Would I need to use an algorithim that makes the corners of the rectangles black or is there an easier way?
Title: Re: Drawing a "flashlight texture" around mouse position?
Post by: Ixrec on October 22, 2014, 07:54:25 pm
Render Texture sounds like the way to go here because it's a pretty crude application. It's my first time working with a RenderTexture, so I'm a little confused. The documentation says that it is used for off-screen drawing, but if I understand you, then you say to use it as the portion of the screen that is being displayed?

Also how do I make the render texture circular? Would I need to use an algorithim that makes the corners of the rectangles black or is there an easier way?

Yes, it is used for off-screen drawing, and one common use of off-screen drawing is to get an intermediate result that you can then draw to the screen later.  So if you wanted a 100x100 pixel square flashlight, just make a 100x100 rendertexture, set the right sf::View on it, draw everything, then draw the result onto a certain region of your actual window.

For getting it circular, you'll have to incorporate one of the other methods.  The simplest is probably using a 100x100 image that's black except for a transparent circle.
Title: Re: Drawing a "flashlight texture" around mouse position?
Post by: wh1t3crayon on October 22, 2014, 09:13:17 pm
Render Texture sounds like the way to go here because it's a pretty crude application. It's my first time working with a RenderTexture, so I'm a little confused. The documentation says that it is used for off-screen drawing, but if I understand you, then you say to use it as the portion of the screen that is being displayed?

Also how do I make the render texture circular? Would I need to use an algorithim that makes the corners of the rectangles black or is there an easier way?

Yes, it is used for off-screen drawing, and one common use of off-screen drawing is to get an intermediate result that you can then draw to the screen later.  So if you wanted a 100x100 pixel square flashlight, just make a 100x100 rendertexture, set the right sf::View on it, draw everything, then draw the result onto a certain region of your actual window.

For getting it circular, you'll have to incorporate one of the other methods.  The simplest is probably using a 100x100 image that's black except for a transparent circle.

Ok I think I get it. What do you mean by "right sf::View", as opposed to what else? And is there pseudocode you can give as a quick demonstration?
Title: Re: Drawing a "flashlight texture" around mouse position?
Post by: Ixrec on October 22, 2014, 09:22:07 pm
Basically, I'm assuming you would want your 100x100 flashlight to not always show the same {0,0,100,100} square region of the game world that would get drawn by default.  If you instead want the flashlight to show the {100,100,200,200} region instead, you'll have to move the render texture's view 100 pixels down and 100 pixels to the right before you draw() everything onto it.

For details and code, just read the view tutorial: http://sfml-dev.org/tutorials/2.1/graphics-view.php
Title: Re: Drawing a "flashlight texture" around mouse position?
Post by: wh1t3crayon on October 23, 2014, 05:27:54 am
Basically, I'm assuming you would want your 100x100 flashlight to not always show the same {0,0,100,100} square region of the game world that would get drawn by default.  If you instead want the flashlight to show the {100,100,200,200} region instead, you'll have to move the render texture's view 100 pixels down and 100 pixels to the right before you draw() everything onto it.

For details and code, just read the view tutorial: http://sfml-dev.org/tutorials/2.1/graphics-view.php

Ok, so use sf::View to set the area for the RenderTexture, that makes sense. And I meant pseudocode for the drawing of the full window vs the drawing of the RenderTexture. I'll post what my idea of doing this would be so you can evaluate just how incorrect it is:
sf::RenderWindow window;
window.clear(sf::Color::Black);
        window.draw(everythingThatExistsInWindow);
        sf::View view;
        view.setCenter(mousePosition);
        sf::RenderTexture renderText;
        renderText.setView(view);
        renderText.display();

Does that make sense, or do I have the concept wrong?
Title: Re: Drawing a "flashlight texture" around mouse position?
Post by: Ixrec on October 23, 2014, 07:34:54 am
Here's the tutorial on RenderTexture: http://sfml-dev.org/tutorials/2.1/graphics-draw.php#off-screen-drawing
Title: Re: Drawing a "flashlight texture" around mouse position?
Post by: wh1t3crayon on October 23, 2014, 02:44:54 pm
Ok I tried that, but I'm getting a weird bug. Tiny white dots appear near where my mouse is, and they aren't cleared everytime, rather they stay on screen. Here is the code for drawing:
void Engine::Process(){
        while(window.pollEvent(event)){
                if(event.type == (sf::Event::Closed)){
                        window.close();
                }
        }
        sf::Vector2f mousePos(sf::Mouse::getPosition());
//sf::View
        view.setCenter(mousePos);
}

void Engine::Render(){
//sf::RenderWindow
        window.clear(sf::Color::Black);
//sf::RenderTexture
        flashlight.clear(sf::Color::Black);
//comment the setView() out, program works fine
        flashlight.setView(view);
        flashlight.draw(board.GetWalls()[0].GetWallShape());
    flashlight.draw(board.GetTexts()[0].GetText());
        const sf::Texture &texture = flashlight.getTexture();
        sf::Sprite sprite(texture);
        window.draw(sprite);
        window.display();
}

I'm confused as to why this isn't working, but it did work (displayed only the top left 75 * 75 pixels) without setting the RenderTexture's view.
Title: Re: Drawing a "flashlight texture" around mouse position?
Post by: eXpl0it3r on October 23, 2014, 03:25:56 pm
You never call display() on your render texture.
Title: Re: Drawing a "flashlight texture" around mouse position?
Post by: wh1t3crayon on October 23, 2014, 05:18:44 pm
Adding flashlight.display() before window.display() doesn't change anything. It's weird though, because the program will draw whatever my mouse is near (where the sf::View is), and draws it in the top left corner (the sf::RenderTexture is there, but I want the rendertexture to be following the mouse).
Title: AW: Drawing a "flashlight texture" around mouse position?
Post by: eXpl0it3r on October 23, 2014, 07:01:04 pm
As far as I can tell you're using the view wrong. Check again the official tutorial (and/or my old one on the wiki).

I'm not sure if you've just missed it, but I already linked my "flashlight" example. It too uses a render texture. Once you understand that it should be easy to apply the view stuff.

Mixing two problems will mostly complicate things, so it might be best to focus on ond task at once. ;)
Title: Re: Drawing a "flashlight texture" around mouse position?
Post by: wh1t3crayon on October 24, 2014, 02:40:21 pm
As far as I can tell you're using the view wrong.
Look, deja vu.  ;) Your tutorial helps, but it fails to show how to draw objects inside the flashlight texture. You just set its fill color, but I want sprites from the window to be drawn inside the area.