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

Author Topic: Can't resize the view  (Read 3328 times)

0 Members and 1 Guest are viewing this topic.

awr

  • Newbie
  • *
  • Posts: 15
    • View Profile
Can't resize the view
« on: October 10, 2013, 02:34:29 am »
Hi all,

I'm having trouble getting the view to work correctly in SFML.Net. It seems that it should be relatively straight forward but no matter what I try, I can't get it work properly.

What I want is:http://www.sfml-dev.org/forums/Themes/ds-natural_20/images/bbc/pre.gif
Embed the render window in a .NET picturebox (this works fine)
Display an image that takes up the entirety of the picture box (this also works fine initially) and is centred in the image box
Upon resizing the picturebox (or form), have the image resize with it. I managed to get this to work when shrinking the picture box, but it doesn't work correctly when making it larger (the view area doesn't change).

My code is (this doesn't work but I don't see what's wrong with it):
// initialise SFML:
        private void pictureBox2_Click(object sender, EventArgs e)
        {
            if (SFMLWindow != null)
                return;
            pictureBox2.Show();
            SFMLWindow = new RenderWindow(pictureBox2.Handle);

            view = new SFML.Graphics.View(new FloatRect(0, 0, this.ClientSize.Width, this.ClientSize.Height));
            SFMLWindow.SetView(view);
            RenderLoop();
        }

private void RenderLoop()
        {            
            SFML.Graphics.Image image3 = new SFML.Graphics.Image("testimage.bmp");                          
            int i = 0;
           
            while (FormOpen)
            {
             
                view = new SFML.Graphics.View(new Vector2f(pictureBox2.ClientSize.Width / 2, pictureBox2.ClientSize.Height / 2), new Vector2f(pictureBox2.ClientSize.Width, pictureBox2.ClientSize.Height));
               
               
                SFMLWindow.SetView(view);
// i intentionally create a new sprite each time round as the application is for a video player, which would need a new sprite to be made for each frame
                Sprite testsprite = new Sprite(new Texture(image3));
                testsprite.Texture.Smooth = true;

                testsprite.Scale = new Vector2f((float) this.ClientSize.Width / testsprite.Texture.Size.X, (float) this.ClientSize.Height / testsprite.Texture.Size.Y);

                Console.WriteLine(SFMLWindow.Size);

                Application.DoEvents(); // Required for the form controls to respond
                SFMLWindow.Clear(SFML.Graphics.Color.White);
                SFMLWindow.Draw(testsprite);
 
                //Do your drawing code here
                SFMLWindow.Display();              
                testsprite.Texture.Dispose();
                testsprite.Dispose();
                System.Threading.Thread.Sleep(80);
            }
        }

It doesn't work. Note that even changing the size of the window manually, using
size = new Vector2u((uint)pictureBox2.ClientSize.Width, (uint)pictureBox2.ClientSize.Height);
                SFMLWindow.Size = size;

doesn't work. When I log the size, its always the form's initial size.

Not sure what the issue is. I've used opengl before with Android and had very few issues with getting the view to do what I want. This seems like it should be quite straight forward...

awr

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: Can't resize the view
« Reply #1 on: October 10, 2013, 06:32:40 am »
OK, so as a sanity check, I decided to try it in C++ to see if that works properly. My C++ code:

#include "stdafx.h"
#include <SFML\Graphics.hpp>
#include <string>

int _tmain(int argc, _TCHAR* argv[])
{
        sf::RenderWindow window(sf::VideoMode(600, 300), "SFML works!");
        sf::Texture texture;
        std::string path = "INSERT PATH TO IMAGE HERE";
        texture.loadFromFile(path + "testimage.bmp");
        texture.setSmooth(true);
        sf::Sprite overlay(texture);       
        sf::View view(sf::FloatRect(0, 0, texture.getSize().x, texture.getSize().y));
        float textScale = (float) texture.getSize().x / texture.getSize().y;
        overlay.setPosition(view.getCenter().x - texture.getSize().x / 2, view.getCenter().y - texture.getSize().y / 2);
        window.setView(view);    
    while (window.isOpen())
    {          
        sf::Event event;
        while (window.pollEvent(event))
        {
            if (event.type == sf::Event::Closed)
                window.close();
        }
                float scale = (float) window.getSize().x / window.getSize().y;

                if (scale > textScale)
                {
               
                        view.setSize(texture.getSize().x * scale / textScale, texture.getSize().y);
                        view.setCenter(view.getSize().x / 2 , view.getSize().y / 2);
                        overlay.setPosition(view.getCenter().x - texture.getSize().x / 2, view.getCenter().y - texture.getSize().y / 2);
                        window.setView(view);
                }
                else if (scale < textScale)
                {
                        view.setSize(texture.getSize().x, texture.getSize().y / scale * textScale);
                        view.setCenter(view.getSize().x / 2, view.getSize().y / 2);
                        overlay.setPosition(view.getCenter().x - texture.getSize().x / 2, view.getCenter().y - texture.getSize().y / 2);
                        window.setView(view);
                }
                printf("%f\n", scale);
        window.clear();
                window.draw(overlay);
        window.display();
    }
        return 0;
}
 

And the equivalent code in C#:
        private void RenderLoop()
        {
            SFMLWindow = new RenderWindow(new VideoMode(600, 300), "SFML doesn't work(s)");
            Texture texture = new Texture("testimage.bmp");
            texture.Smooth = true;
            Sprite overlay = new Sprite(texture);
            SFML.Graphics.View view = new SFML.Graphics.View(new FloatRect(0, 0, texture.Size.X, texture.Size.Y));
            float textScale = (float)texture.Size.X / texture.Size.Y;
            overlay.Position = new Vector2f(view.Center.X - texture.Size.X / 2, view.Center.Y - texture.Size.Y / 2);
            SFMLWindow.SetView(view);

            while (SFMLWindow.IsOpen() && FormOpen)
            {
                Application.DoEvents();
                float scale = (float)SFMLWindow.Size.X / SFMLWindow.Size.Y;

                if (scale >= textScale)
                {
                    view.Size = new Vector2f(texture.Size.X * scale / textScale, texture.Size.Y);
                    view.Center = new Vector2f(view.Size.X / 2, view.Size.Y / 2);
                    overlay.Position = new Vector2f(view.Center.X - texture.Size.X / 2, view.Center.Y - texture.Size.Y / 2);
                    SFMLWindow.SetView(view);
                }
                else if (scale < textScale)
                {
                    view.Size = new Vector2f(texture.Size.X, texture.Size.Y / scale * textScale);
                    view.Center = new Vector2f(view.Size.X / 2, view.Size.Y / 2);
                    overlay.Position = new Vector2f(view.Center.X - texture.Size.X / 2, view.Center.Y - texture.Size.Y / 2);
                    SFMLWindow.SetView(view);
                }

                SFMLWindow.SetView(view);
                SFMLWindow.Clear();
                SFMLWindow.Draw(overlay);
                SFMLWindow.Display();
                break;
            }
        }

And the differences in output:
C++ (exactly as I expected it to be):


C# (nothing like I expected it to be):


As you can see, the C++ implementation resizes, keeps proportions in check and adds black bars on top/bottom or on sides depending on the window ratio. Clearly, this isn't working at all in C#.

One thing that I find interesting is that when I log the SFMLWindow's properties, its size, position and view never change. I am using the 2.1 bindings.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32504
    • View Profile
    • SFML's website
    • Email
Re: Can't resize the view
« Reply #2 on: October 10, 2013, 07:42:49 am »
Does calling SFMLWindow.DispatchEvents() help?
Laurent Gomila - SFML developer

awr

  • Newbie
  • *
  • Posts: 15
    • View Profile
Re: Can't resize the view
« Reply #3 on: October 10, 2013, 07:55:34 am »
Hi Laurent,

That did it. I had just implemented a hack where I close and re instantiate the window after every resize but this does the job.

Any reason why DispatchEvents() needs to be called manually?

ALSO, just while you're here and on an unrelated matter, is it possible to add the following constructor to the .NET bindings:
            public unsafe Image(uint width, uint height, byte* pixels) :
                base(IntPtr.Zero)
            {
                SetThis(sfImage_createFromPixels(width, height, pixels));
            }

This allows you to directly pass an unmanaged pointer from C# to SFML, which is what the Image(uint width, uint height, byte[]) constructor does internally.

My usage is for a video player and we're currently using FFMPEG via our unmanaged C++ libraries to do the image decoding. We then get that as an IntPtr in our managed C# application and I'd like to pass that IntPtr directly to SFML.Net. Otherwise, I've got to do a Marshal copy into a managed C# byte array which not only adds extra overhead, it also means the garbage collector will be a lot more active. I've rebuilt the SFML .Net dlls with the above constructor and it works without issue so it'll be helpful if it can be added into the main codebase.

 

anything