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

Author Topic: Scaling into a canvas.  (Read 1721 times)

0 Members and 1 Guest are viewing this topic.

Xrey274

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
Scaling into a canvas.
« on: June 02, 2019, 08:50:53 pm »
I am working on a painting program, and I have been wondering how to make canvases that are bigger(resolution wise) than the window(for ex. 8000 x 6000). Pretty much every painting program does this. My idea for now is just using setScale, but won't that ruin the image resolution?

Edit: To clarify the "canvas" is a renderTexture to which things are drawn to.
« Last Edit: June 02, 2019, 08:54:22 pm by Xrey274 »

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Scaling into a canvas.
« Reply #1 on: June 02, 2019, 09:57:07 pm »
You can create render textures that are larger than the window to which they are drawn.
If you only want to show a part of it (to allow full-sized viewing with scrolling, for example), you can set the texture rectangle of the sprite that you use to draw the render texture to the window to any part of the render texture's actual texture.

One thing to note, though, is that graphics cards have a maximum texture size that they can use; each card has their own size (it's generally one of a limited list, though). If the card that runs the application cannot create textures of 8k, your creation of a 8000x6000 texture is doomed to failure. You can check the maximum size allowed by the current graphics card (remember that if you expect others to run this application, you should account for any possible size): sf::Texture::getMaximumSize(). Note that 8k textures are on the top-end of things.

Another approach is to use an sf::Image. This has no real limit to its size (limited possibly by memory availability more than anything else) but the approach can be slower.
You could use a render texture the size of the window and then "save" that part on to that part of the image before scrolling and then update the render texture from image data. Again, this is likely to be too slow but would depend on your requirements and your implementation.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Xrey274

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
Re: Scaling into a canvas.
« Reply #2 on: August 26, 2019, 09:58:07 pm »
Using sf::Image wouldn't work as I would need to add each pixel one by one and that would be way too slow. I'm really curious how big drawing programs(think Krita, GIMP, Photoshop, etc) manage to create files with incredibly high resolution and be able to display it. Do they just scale it?

Xrey274

  • Jr. Member
  • **
  • Posts: 76
    • View Profile
Re: Scaling into a canvas.
« Reply #3 on: August 26, 2019, 10:31:36 pm »
This is my attempt at using a large RenderTexture, which is later scaled to fit properly on the screen. Although it works my problem is with the mouse offset - just can't seem to get it right.

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

sf::CircleShape newCircle(sf::Vector2f pos)
{
        sf::CircleShape circle;

        circle.setPosition(pos);
        circle.setRadius(10);
        circle.setOrigin(circle.getRadius(), circle.getRadius());
        circle.setFillColor(sf::Color::Green);

        return circle;
}

int main()
{
        sf::ContextSettings settings;
        settings.antialiasingLevel = 8;

        sf::RenderWindow window(sf::VideoMode(1920 / 2, 1080 / 2), "RenderTexture", sf::Style::Default, settings);
        window.setFramerateLimit(144);

        sf::RenderTexture canvas;

        canvas.create(3840, 2160);
        canvas.clear(sf::Color::White);

        sf::Event event;

        std::vector<sf::CircleShape> circles;

        bool isMoving = false;

        sf::Clock clock;

        sf::Vector2f offset(canvas.getSize().x / 2, canvas.getSize().y / 2);

        while(window.isOpen())
        {
                sf::Vector2f mouseCoords  = window.mapPixelToCoords(sf::Mouse::getPosition(window), window.getView());
                sf::Vector2f offsetCoords = mouseCoords - offset;

                while(window.pollEvent(event))
                {
                        switch(event.type)
                        {
                                case sf::Event::Closed:
                                        window.close();

                                        break;
                                case sf::Event::Resized:
                                        window.setView(sf::View(sf::FloatRect(0, 0, event.size.width, event.size.height)));

                                        offset = sf::Vector2f((window.getSize().x - (canvas.getSize().x * 0.3333)) / 2, (window.getSize().y - (canvas.getSize().y * 0.3333)) / 2);

                                        break;
                                case sf::Event::MouseButtonPressed:
                                        isMoving = true;

                                        break;
                                case sf::Event::MouseMoved:
                                        if(isMoving == true)
                                        {
                                                circles.push_back(newCircle(offsetCoords));
                                        }

                                        break;
                                case sf::Event::MouseButtonReleased:
                                        isMoving = false;

                                        circles.clear();
                        }
                }

                for(int i = 0; i < circles.size(); ++i)
                {
                        canvas.draw(circles[i]);
                }

                canvas.display();

                window.clear(sf::Color(31, 31, 31));

                sf::Sprite sprite(canvas.getTexture());
                sprite.setScale(0.333, 0.333);

                sprite.setPosition(sf::Vector2f((window.getSize().x - (canvas.getSize().x * sprite.getScale().x)) / 2, (window.getSize().y - (canvas.getSize().y * sprite.getScale().x)) / 2));

                window.draw(sprite);

                window.display();

                circles.clear();

                float currentTime = clock.restart().asSeconds();
        int fps = 1.f / currentTime;

        std::cout<<fps<<std::endl;
        }
}
 
 
« Last Edit: August 26, 2019, 10:34:58 pm by Xrey274 »

Hapax

  • Hero Member
  • *****
  • Posts: 3351
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Scaling into a canvas.
« Reply #4 on: August 28, 2019, 12:15:27 am »
Some of Photoshop's 'live' manipulation can be seen to be graphics card-based whereas others are obviously just lower resolution versions. The graphics card ones can be done on-the-fly and then applied as a single manipulation once completed.

One other thing to note is that it's possible (likely?) that some image manipulation programs use direct pixel (or screen bitmap) manipulation, avoiding things like OpenGL and going straight through the operating system or, even more directly, the graphics driver.


For your program, if you are having trouble working out where your mouse is in relation to a specific render target (window or render texture, for examples), it's likely you need to mapping to and from views. First make sure you know which views are being used for each target (if you haven't set one, you can use getDefaultView()) and then read this (it may fix everything!):
https://www.sfml-dev.org/tutorials/2.5/graphics-view.php#coordinates-conversions
Again, remember that your render texture also has a view.
Also, remember that your 'render sprite' (sprite used to draw the render texture) is transformable so should also be allowed for.

You may also be interested in this short Wiki article (Convert Point Of View) that shows how to convert co-ordinates across different views:
https://github.com/SFML/SFML/wiki/Source%3A-Convert-Point-Of-View
« Last Edit: August 28, 2019, 12:40:02 am by Hapax »
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*