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

Author Topic: Is there a way to make a transparency mask for (rendered) textures or sprites?  (Read 13597 times)

0 Members and 3 Guests are viewing this topic.

Lamonte

  • Newbie
  • *
  • Posts: 46
    • View Profile
1. Want to emulate this effect
2. By creating a render window, filling it with black.  Drawing to it and then setting the transparency of the color I drew on the render window (will be updated based sprite position, not really important atm)
3. Display the render window to the screen after everything else is loaded to create said effect.


zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
https://github.com/SFML/SFML/issues/1

Since SFML does not have rendermasks there is no way to correctly simulate that effect. However there is a dirty workaround that partially simulates that effect that is described in this thread.
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

Lamonte

  • Newbie
  • *
  • Posts: 46
    • View Profile
That was actually going to be my 4th question if there was a way to create an image from a render texture, this work around seems doable.

Lamonte

  • Newbie
  • *
  • Posts: 46
    • View Profile
Seems like the CopyToImage() function in C# has a memory leak on windows 7?

http://pastie.org/private/muwqimwmbgxodg30oyr0xq

hmm... just realized in thiat example he's not doing it every frame, trying to figure out a proper way to do this w/out killing stuff.  Because right now this runs every frame which is copying thousands of images a second lol
« Last Edit: September 21, 2013, 06:53:32 am by Lamonte »

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
CopyToImage is a heavy operation and should, if possible, not be called every frame iteration.
Such lighting effect is very well possible with a RenderTexture. You can find a very small example on my GitHub page, you of course have to make it fit your wanted effect. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Lamonte

  • Newbie
  • *
  • Posts: 46
    • View Profile
CopyToImage is a heavy operation and should, if possible, not be called every frame iteration.
Such lighting effect is very well possible with a RenderTexture. You can find a very small example on my GitHub page, you of course have to make it fit your wanted effect. ;)

Tried to emulate your example in C# didn't work out as planned, the rect draws properly, the circles are created properly for the flashlight, but the blendmode isn't working as intended for the render texture.  Below's just sloppy code, but I don't think I missed anything.

    class Program
    {
        public static float mousex = 0f;
        public static float mousey = 0f;
       
        public static RenderStates state;

        static void Main(string[] args)
        {

           
            state.BlendMode = BlendMode.Add;

            RenderWindow window = new RenderWindow(new VideoMode(300, 300), "Flashlight?");
            window.SetFramerateLimit(60);
            window.SetMouseCursorVisible(false);

            //close window
            window.Closed += (s, e) => {
                RenderWindow win = (RenderWindow) s;
                win.Close();
            };

            window.MouseMoved += (s, e) => {
                mousex = e.X;
                mousey = e.Y;
            };

            RenderTexture layer = new RenderTexture(300, 300);
            RenderTexture flashlightTexture = new RenderTexture(60, 60);

            flashlightTexture.Clear();

            for(uint i = 0; i <  6; ++i) {
               
                CircleShape temp = new CircleShape(30f-(i*2f));
                temp.Origin = new Vector2f(30f-(i * 2f), 30f-(i * 2f));
                temp.FillColor = new Color(255, 255, 255, (byte) (61 - (i * 10)));
                temp.Position = new Vector2f(30f, 30f);

                flashlightTexture.Draw(temp, state);
            }

            flashlightTexture.Display();

            Sprite flashlight = new Sprite(flashlightTexture.Texture);
            flashlight.Position = new Vector2f(150.0f, 150.0f);
            flashlight.Origin = new Vector2f(30f, 30f);

            RectangleShape rect = new RectangleShape(new Vector2f(100f, 100f));
            rect.Position = new Vector2f(150f, 150f);
            rect.FillColor = new Color(Color.Red);

            Sprite msprite = new Sprite();
            msprite.Texture = layer.Texture;

           
            while(window.IsOpen()) {
               
                window.DispatchEvents();

                flashlight.Position = new Vector2f(mousex, mousey);
                layer.Clear();
                layer.Draw(flashlight, state);
                layer.Display();

                window.Clear(Color.Blue);
                window.Draw(rect);
                window.Draw(msprite);
                window.Display();

                Console.WriteLine("x: {0}, y: {1}", mousex, mousey);
            }

        }
    }

eXpl0it3r

  • SFML Team
  • Hero Member
  • *****
  • Posts: 11030
    • View Profile
    • development blog
    • Email
Why are you using sf::BlendAdd. everywhere when I was using sf::BlendNone?
BlendNone will apply the content directly, thus making the rendertexture transparent at specific points. ;)
Official FAQ: https://www.sfml-dev.org/faq.php
Official Discord Server: https://discord.gg/nr4X7Fh
——————————————————————
Dev Blog: https://duerrenberger.dev/blog/

Mad

  • Newbie
  • *
  • Posts: 32
    • View Profile
    • Email
Why are you using sf::BlendAdd. everywhere when I was using sf::BlendNone?
BlendNone will apply the content directly, thus making the rendertexture transparent at specific points. ;)

Right!  :) But also state.BlendMode = BlendMode.Add; ist not working!
use
state = new RenderStates( BlendMode.None);
If you use
state = new RenderStates( );
state.BlendMode = BlendMode.None;
it also doen't work. This seems to be a bug in CSFML....
 
best regards,

Mad

FRex

  • Hero Member
  • *****
  • Posts: 1848
  • Back to C++ gamedev with SFML in May 2023
    • View Profile
    • Email
I may be wrong but I think it's caused by default C# struct ctors doing memset 0 on entire thing really so you have to set every field to sane default yourself. (I think Laurent said that..)

So if you want a
sf::RenderStates hehe;
from c++ you must do:
sf.RenderStates hehe = new sf.RenderStates(sf.RenderStates.Default);
« Last Edit: September 22, 2013, 01:26:19 pm 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
Right!  :) But also state.BlendMode = BlendMode.Add; ist not working!
use
state = new RenderStates( BlendMode.None);
If you use
state = new RenderStates( );
state.BlendMode = BlendMode.None;
it also doen't work. This seems to be a bug in CSFML....

This is not a bug in CSFML or even C#. This is the way structs are handled in the CLR. When you use the default empty constructor on structs everything in the struct will be assigned 0/null depending on the member type. Also there is no way to overload the empty constructor in structs so you must call an overloaded constructor with SFML.

sf.RenderStates hehe = new sf.RenderStates(sf.RenderStates.Default);

Actually the way to do this in C# would be

RenderStates states = RenderStates.Default;
« Last Edit: September 22, 2013, 01:38:32 pm by zsbzsb »
Motion / MotionNET - Complete video / audio playback for SFML / SFML.NET

NetEXT - An SFML.NET Extension Library based on Thor

Mad

  • Newbie
  • *
  • Posts: 32
    • View Profile
    • Email
This is not a bug in CSFML or even C#. This is the way structs are handled in the CLR. When you use the default empty constructor on structs everything in the struct will be assigned 0/null depending on the member type. Also there is no way to overload the empty constructor in structs so you must call an overloaded constructor with SFML.

Maybe you misunderstand me. You can call an overloaded constructor, but if it's possible to access a property/var from outside  and assign a value to it (because it is declared as public), the value should be stored, right? :-)
so if I can write this code:
state = new RenderStates( );
state.BlendMode = BlendMode.None;

BlendMode should have the value 'None' and not undefined/default....
maybe it would be better to use a property without a setter.
           
public BlendMode BlendMode
            {
                get
                {
                    return _Value;
                }
            }

so now, you can not set BlendMode without using the constructor.  ;)


« Last Edit: September 22, 2013, 04:26:48 pm by Mad »
best regards,

Mad

zsbzsb

  • Hero Member
  • *****
  • Posts: 1409
  • Active Maintainer of CSFML/SFML.NET
    • View Profile
    • My little corner...
    • Email
Maybe you misunderstand me. You can call an overloaded constructor, but if it's possible to access a property/var from outside  and assign a value to it (because it is declared as public), the value should be stored, right? :-)
so if I can write this code:
state = new RenderStates( );
state.BlendMode = BlendMode.None;

BlendMode should have the value 'None' and not undefined/default....

This doesn't work because SFML.NET is a binding on top of unmanaged memory (accessed through CSFML API). When you create RenderStates with an overloaded constructor SFML.NET internally creates an unmanaged object and then assigns an IntPtr to the handle of this unmanaged object.

The problem is that you can not overload the default empty constructor nor can you disable the default constructor with structs. And with the default empty constructor there is no way to force creation of the unmanaged object so the handle(IntPtr) is initialized to zero.


Quote
maybe it would be better to use a property without a setter.
           
public BlendMode BlendMode
            {
                get
                {
                    return _Value;
                }
            }

so now, you can not set BlendMode without using the constructor.  ;)

Adding properties to structs in C# doesn't work too well and still doesn't solve the above problem.
« Last Edit: September 22, 2013, 04:59:07 pm by zsbzsb »
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
Quote
When you create RenderStates with an overloaded constructor SFML.NET internally creates an unmanaged object and then assigns an IntPtr to the handle of this unmanaged object.
It doesn't. Texture and Shader are IntPtr and always set to null in overloaded constructors(unless it's copy or you passed either, then it's set to that passed one), BlendMode is C# enum and Transform is struct of 9 floats which doesn't hold any unmanaged handle either.

Quote
state = new RenderStates( );
state.BlendMode = BlendMode.None;

BlendMode should have the value 'None' and not undefined/default....
Does that code actually NOT change the value of state.BlendMode? Or do you think that is doesn't? Did you check with Console.WriteLine or debugger?
« Last Edit: September 22, 2013, 05:15:31 pm by FRex »
Back to C++ gamedev with SFML in May 2023

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
The default constructor code doesn't work because all members are set to zero. Therefore, only BlendMode is well defined because you explicitly set it after the constructor. The other members must be considered undefined (although Texture and Shader will probably be fine, Transform will be totally messed up).
Laurent Gomila - SFML developer

Lamonte

  • Newbie
  • *
  • Posts: 46
    • View Profile
Why are you using sf::BlendAdd. everywhere when I was using sf::BlendNone?
BlendNone will apply the content directly, thus making the rendertexture transparent at specific points. ;)

Right!  :) But also state.BlendMode = BlendMode.Add; ist not working!
use
state = new RenderStates( BlendMode.None);
If you use
state = new RenderStates( );
state.BlendMode = BlendMode.None;
it also doen't work. This seems to be a bug in CSFML....

Ah nice this actually worked.  For those asking me why I had to set to "Add", because I was seeing if it worked in general and nothing was working.  So i started changing settings to see if anything would change