SFML community forums

Help => Graphics => Topic started by: Omyk on September 11, 2012, 12:19:34 am

Title: sfml view issue
Post by: Omyk on September 11, 2012, 12:19:34 am
Hi, bonjour

I have a question regarding the sf::View feature in sfml 2.0

I am actually trying to make a very low resolution game (1 ingame pixel = 16 pixels) but i encounter an issue.
The way that i am programming this is that i make a scene 4 times smaller than the actual window size and when i need to render it i just use a view which will zoom in 4 times.

everything works fine except the sprite.

What i don't understant is that when i move the sprite, it moves it in the high resolution definition, and not the smaller one i made before rendering.

Another issue is that when i rotate the sprite, it does not rotate a small sprite, but a 4 times bigger copy of it, so the whole low resolution thing is a big fail.

Is there another way to do this to keep everything in low resolution ?

I thought of re-writing another function that can replace the zoom one, it would actually get each pixel from the pixelPtr of the small scene and create a 4x bigger pixelPtr with each pixel from the small array would be equal to 16 in the big one, but that would be kind of slow i guess.

So any answer is welcome, i also speak french, alors n'hésitez pas !

Thank you :)
Title: Re: sfml view issue
Post by: Laurent on September 11, 2012, 12:25:06 am
Quote
What i don't understant is that when i move the sprite, it moves it in the high resolution definition, and not the smaller one i made before rendering.

Another issue is that when i rotate the sprite, it does not rotate a small sprite, but a 4 times bigger copy of it, so the whole low resolution thing is a big fail.
Sorry, but I fail to understand the problems that you describe. Maybe with a screenshot? Or a more detailed explanation? ;D
Title: Re: sfml view issue
Post by: Omyk on September 11, 2012, 12:52:27 am
Okay here's a pic:

(http://i.imgur.com/yblBG.png)

To the left is what i get, to the right is what i would like to have, you see on the left, the pixels are rotated, and that fails the purpose of low-res.

Thank you for helping ! :)
Title: Re: sfml view issue
Post by: eXpl0it3r on September 11, 2012, 01:21:21 am
For me the left pictures looks better than the right one. Why should the image get malformed when rotated? How did you generate the right image?
Title: Re: sfml view issue
Post by: Omyk on September 11, 2012, 01:36:16 am
Look, that's the whole point of having a low resolution game.

The thing that i want to make is actually a game with like 100 * 100 pixel as resolution, but expanded on 400 * 400 for example, so that it looks like a reaaalllly old game, when screens had a really low resolution, and big pixels.

That said, each square in my game is supposed to be a big pixel, and a pixel cannot rotate! and that is why i am having this problem. The image to the left is a wheel with a low resolution, that has been zoomed in 4 times, but when i rotate it, i would like it to look like if you rotated a low resolution image, so it is supposed to be looking like on the right side. The problem i have with rotated pixels are mainly the collision detection that would work on a whole different manner, and also the aestethic, this does not look old if you can rotate pixels.

What i don't understand is that when you create a view on a low resolution sprite, and zoom in, and then if you rotate the low resolution sprite, the view does not display the zoomed in sprite, it creates a new sprite, copy of the other one, zoomed in 4 times and then rotated. This does not give the same result at all!

So what method can i use to get the desired effect ?

to get the right image, i made the window 4 times smaller, to get the authentic low resolution sprite, then i made a print screen, and zoomed in from paint 4 times.

Any solutions please?
Title: Re: sfml view issue
Post by: Omyk on September 11, 2012, 01:37:27 am
tell me if you want me to explain in french, it may be easyer ? ( i am french )
Title: Re: sfml view issue
Post by: FRex on September 11, 2012, 01:44:35 am
Try and draw everthing to a render texture and then use this texture to draw a sprite that you'll scale up 4 times? (wild guess)
Title: Re: sfml view issue
Post by: eXpl0it3r on September 11, 2012, 01:49:13 am
Ah now I understand. ;)

Have tried texture.setSmooth(false)?

When you say the sprite gets copied what do you mean by that? Is that just what you think happens while observing the result, or does that happen in the code?

Maybe if you provide a minimal example one will be able to test it. ;)

Btw there's also a dedicated French forum, but your English is fine, just wanted to point it out. ;)
Title: Re: sfml view issue
Post by: Omyk on September 11, 2012, 02:04:42 am
@Frex

Yes that's what i thought of in the first place: have a final image, then get the pixelptr, and create a new pixelptr from the previous one, but 16 times bigger, and then copy 16 times the same pixel data for each pixel, and then copy that into another image, and finally displaying that image, but that would be REALLY slow wouldn't it ?

@eXpl0it3r

where would i put setsmooth ? are you sure this is what i want? because what i actually do is draw everything on a tiny sprite, and use a view to zoom in 4 times, so i don't think this would change anything ?

And the copy thing is just an observation, because view (what i have seen) does not really zoom in on a sprite, what  it does is (what  think) copy every sprite into a bigger one and displaying that instead, while applying the transformations on  the bigger sprites.

I am sorry i cannot give you code, it's too messy and long, but if you're willing to try for yourself do this:

make a program with a tiny window (say 100 * 100) draw sprites on it (low res) and rotate them.
It would be difficult to see properly because of the smallness of all this, but after, try this:

You make a window 4 times bigger than the original (400*400) but you keep every sprite and what you displayed before in the same resolution. (normally everything that you display will be visible in 1/4th of the screen (top left corner) with the rest black. Ok now create a view, (size 100*100) draw everything on the view, then use a viewport of 1, (that would normally display your sprites on the whole size of the window, (4 times as big as before)
If you don't rotate them, they look fine, but with rotation, you can see that The
resulting sprites != original sprites.

If you don't use the view you get something like the image to the right, but 4 times smaller, if you use the view you get something like the image to the left.

Sorry, i don't know if  i can be more detailed...

for the french forum, i just think that it'd be less populated, and people from france won't answer at this time (2am)
That's why i posted here, and i also thought that Laurent Gomila was french ?

Nevertheless, thanks for helping out :)
Title: Re: sfml view issue
Post by: FRex on September 11, 2012, 02:07:00 am
Quote
Yes that's what i thought of in the first place: have a final image, then get the pixelptr, and create a new pixelptr from the previous one, but 16 times bigger, and then copy 16 times the same pixel data for each pixel, and then copy that into another image, and finally displaying that image, but that would be REALLY slow wouldn't it ?
Create a sprite and scale it 4x x and y, and assign it to render texture. Then draw clear and dislay to texture and only : clear, draw sprite, display window.
Title: Re: sfml view issue
Post by: eXpl0it3r on September 11, 2012, 02:11:40 am
SetSmooth would be applied to the texture, but it's disabled by default, it doesn't help.

I can't experiment around right now but I'll try in the morning if your problem doesn't get solved in the meantime. ;)
Title: Re: sfml view issue
Post by: Omyk on September 11, 2012, 02:17:17 am
hmm, i'll try to rotate the sprite, then scaling it, tomorrow, but honestly i think it would make the same result...
Title: Re: sfml view issue
Post by: Tex Killer on September 11, 2012, 07:41:42 am
You have to rotate the sprite and draw it rotated on some texture... Then you put that texture on a sprite, scale it and draw it scaled on the screen.
Title: Re: sfml view issue
Post by: Laurent on September 11, 2012, 08:16:03 am
You won't be able to get true bigger pixels with just a view. The target (the window) still has more pixels, so it can (and does) render your big pixels perfectly rotated, instead of aligned to your "virtual" big pixels grid.

The render-texture solution should work, and is very easy to write.

Quote
What i don't understand is that when you create a view on a low resolution sprite, and zoom in, and then if you rotate the low resolution sprite, the view does not display the zoomed in sprite, it creates a new sprite, copy of the other one, zoomed in 4 times and then rotated. This does not give the same result at all!
Hmm? No, this is the same sprite, but since you have more pixels it can be rotated perfectly, as I explained above. The view zooms the 2D scene, pixel rasterization happens after zooming the 2D entities. So you don't get bigger pixels, just bigger entities.

Quote
i also thought that Laurent Gomila was french ?
I am. But if you want to speak french you have to post on the french forum ;)
Title: Re: sfml view issue
Post by: Omyk on September 11, 2012, 01:21:22 pm
Sooo, i've tried the rotate + scale after technique but that does not work either...

I wanted to try out another method that i was certain would work, but i have no idea on how to do it.

I was thinking about copying the pixels and scaling them directly in a bigger pixel array, but i just found out that the pixels do not move, because the image always stays the same... Then i tried to get the sprite transform, and apply it to another texture, but there is no such method, only in RenderTexture, but which is protected...

I have no clue on how to do this now...

Can someone give me a clear explanation please or some code part ?

Just another question btw, i wanted to do a wheel, and i wanted to make it spin, but when i use setOrigin, it still isn't precicely in the center... Should i make the wheel size 21 * 21 or 20 * 20?  i thought of 21*21 so that the one pixel in the center would be an axle for spinning so i setOrigin(10, 10) but that doesn't work... Any clue?

Thanks for helping out :)
Title: Re: sfml view issue
Post by: Laurent on September 11, 2012, 02:16:12 pm
Why don't you try the render-texture solution? It's straight-forward to implement and should work perfectly.

Forget solutions that involve manual processing of pixels, it will be too slow.

Quote
Just another question btw, i wanted to do a wheel, and i wanted to make it spin, but when i use setOrigin, it still isn't precicely in the center... Should i make the wheel size 21 * 21 or 20 * 20?  i thought of 21*21 so that the one pixel in the center would be an axle for spinning so i setOrigin(10, 10) but that doesn't work... Any clue?
It should rather be 20x20 if the origin is set to (10, 10). Doesn't it work as expected?
Title: Re: sfml view issue
Post by: Omyk on September 11, 2012, 03:50:39 pm
Thanks for the advice for setOrigin, that worked !

but for the main issue:
I can't try the renderTexture solution, because i don't know what it is, would you be so kind and explain it to me please ?
Title: Re: sfml view issue
Post by: Laurent on September 11, 2012, 04:00:37 pm
Instead of drawing directly to a window, you draw to a smaller sf::RenderTexture (the drawing API is the same as sf::RenderWindow), and then you draw the resulting texture with a scaled sprite on your window.

This way you really scale the final pixels, instead of the entities.
Title: Re: sfml view issue
Post by: Omyk on September 11, 2012, 04:23:15 pm
Awesome, it works !

Here's a code, for those who haven't seen what i wanted to do in the first place!

#include <iostream>
#include <SFML/Graphics.hpp>
#include <SFML/Window.hpp>

#define REAL_WIDTH 20       //size of the original texture
#define REAL_HEIGHT 20
#define VIRTUAL_HEIGHT 400  //desired size for the window (multiple of the real size)
#define VIRTUAL_WIDTH 400

int main()
{
    sf::RenderWindow window(sf::VideoMode(VIRTUAL_WIDTH, VIRTUAL_HEIGHT), "Test");

    sf::Texture real_texture;
    real_texture.loadFromFile("spin.png");  //just make a random small sprite like 10*10
    sf::Sprite real_sprite(real_texture);
    real_sprite.setOrigin(real_sprite.getGlobalBounds().width/2, real_sprite.getGlobalBounds().height/2);
    real_sprite.setPosition(REAL_WIDTH/2, REAL_HEIGHT/2);

    sf::RenderTexture real_target;
    real_target.create(REAL_WIDTH, REAL_HEIGHT);

    sf::Sprite virtual_sprite;
    virtual_sprite.scale(VIRTUAL_WIDTH/REAL_WIDTH, VIRTUAL_HEIGHT/REAL_HEIGHT);
    virtual_sprite.setTexture(real_target.getTexture());

    window.setFramerateLimit(30);
    sf::Event event;

    while(window.isOpen())
    {
        if(sf::Keyboard::isKeyPressed(sf::Keyboard::Escape))
            window.close();

        while(window.pollEvent(event))
        {
            if(event.type == sf::Event::Closed)
                window.close();
        }

        real_target.clear();
        real_target.draw(real_sprite);
        real_target.display();

        //drawing
        window.clear();
        window.draw(virtual_sprite);
        window.display();

        //rotation afterwards
        real_sprite.rotate(5);

    }
    return 0;
}
 

you just need to create a png image for it to work (it's a basic example of a spinning pinwheel) ;)

Once again: thank you very much for your contribution ! :P
Title: Re: sfml view issue
Post by: Laurent on September 11, 2012, 04:27:53 pm
There should be a call to real_target.display() after drawing to the render-texture.

And you don't need to call setTexture again and again, the texture object inside the render-texture is still the same, even if its contents have changed.
Title: Re: sfml view issue
Post by: Omyk on September 11, 2012, 04:37:45 pm
do i need to call real_target.display since i will display it just after with the window ?

and yeah i just remember now, the setTexture is just giving the adress of the texture to display, and the adress will stay the same since the texture is automatically updated with the renderTexture...

Edit: I just changed the code :)
Title: Re: sfml view issue
Post by: Laurent on September 11, 2012, 04:40:12 pm
real_target.display is needed to correctly display what you've just drawn in the texture, the same way window.display is required to see something on screen.

Without this call, the contents of the render-texture should be either missing or upside down.
Title: Re: sfml view issue
Post by: Omyk on September 11, 2012, 04:42:45 pm
Oh yeah i see, that's why the pinwheel was spinning on counterclockwise !