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):
(http://img96.imageshack.us/img96/941/fj1g.png)(http://img401.imageshack.us/img401/6933/xt51.png)
C# (nothing like I expected it to be):
(http://img853.imageshack.us/img853/7561/sfqo.png)(http://img15.imageshack.us/img15/4561/wwxb.png)(http://img208.imageshack.us/img208/3366/fe3p.png)
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.
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.