• Drawing 2D stuff


    系列文章

    SFML-windows 篇
    SFML-Events explained 篇
    SFML-Keyboard, mouse and joystick 篇
    SFML-Using OpenGL in a SFML window 篇
    SFML-Drawing 2D stuff 篇
    SFML-Shapes 篇
    SFML-Sprites and textures 篇

    Introduction


    正如您在之前的教程中所了解的那样,SFML的窗口模块提供了一种打开OpenGL窗口的简单方法,但在绘制某些东西时,SFML没有帮助,于是只能选择功能强大但复杂的底层OpenGL API。

    幸运的是,SFML提供了一个图形模块,可以比OpenGL更简单的方式绘制2D实体。

    The drawing window

    要绘制图形模块提供的实体,必须使用专门的窗口类:sf::RenderWindow。该类派生自sf::Window,并继承其所有函数。关于sf::Window的所有知识(创建、事件处理、控制帧速率、与OpenGL混合等)也适用于sf::RenderWindow。

    除此之外,sf::RenderWindow还添加了高级函数来帮助您轻松绘制。在本教程中,我们将重点介绍其中两个函数:clear and draw。它们就像其名称所暗示的那样简单:clear用所选颜色清除整个窗口,并用draw绘制您传递给它的任何对象。

    以下是渲染窗口中典型的主循环的外观:

    #include <SFML/Graphics.hpp>
    
    int main()
    {
        // create the window
        sf::RenderWindow window(sf::VideoMode(800, 600), "My window");
    
        // run the program as long as the window is open
        while (window.isOpen())
        {
            // check all the window's events that were triggered since the last iteration of the loop
            sf::Event event;
            while (window.pollEvent(event))
            {
                // "close requested" event: we close the window
                if (event.type == sf::Event::Closed)
                    window.close();
            }
    
            // clear the window with black color
            window.clear(sf::Color::Black);
    
            // draw everything here...
            // window.draw(...);
    
            // end the current frame
            window.display();
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31

    必须在绘制任何内容之前clear,否则之前帧中的内容将显示在您绘制的任何内容后面。唯一的例外是,当您用绘制的内容覆盖整个窗口时,没有像素不会被绘制到。在这种情况下,您可以避免调用clear(尽管它不会对性能产生明显影响)。

    调用显示也是必需的,它将自上次调用以来绘制的内容显示并显示在窗口上。事实上,事物不是直接绘制到窗口,而是绘制到隐藏的缓冲区。当您调用display时,这个缓冲区会被复制到窗口中,这称为双缓冲。

    这种清晰/绘制/显示循环是绘制事物的唯一好方法。不要尝试其他策略,例如保留前一帧的像素,“擦除”像素,或绘制一次并多次调用display。由于双重缓冲,您将得到奇怪的结果。

    现代图形硬件和API实际上是为重复的清晰/绘制/显示周期而设计的,在主循环的每次迭代中,所有内容都会完全刷新。不要害怕每秒60次绘制1000个精灵,你的计算机所能处理的数百万个三角形远超过它。

    What can I draw now?


    现在你有了一个主循环,可以绘制了,让我们看看你可以在那里绘制什么,以及如何绘制。

    SFML提供了四种可绘制实体:其中三种可以随时使用(精灵、文本和形状),最后一种是构建块,可以帮助您创建自己的可绘制实体(顶点数组)。

    虽然它们具有一些共同的属性,但每个实体都有自己的细微差别,因此在专门的教程中进行了解释:

    Sprite tutorial
    Text tutorial
    Shape tutorial
    Vertex array tutorial
    
    • 1
    • 2
    • 3
    • 4

    Off-screen drawing


    SFML还提供了一种绘制纹理的方法,而不是直接绘制到窗口。为此,请使用sf::RenderTexture而不是sf::RenderWindow。它具有相同的绘图功能,继承自它们的公共基础:sf::RenderTarget。

    sf::RenderTexture renderTexture;
    if (!renderTexture.create(500, 500))
    {
        // error...
    }
    
    // drawing uses the same functions
    renderTexture.clear();
    renderTexture.draw(sprite); // or any other drawable
    renderTexture.display();
    
    // get the target texture (where the stuff has been drawn)
    const sf::Texture& texture = renderTexture.getTexture();
    
    // draw it to the window
    sf::Sprite sprite(texture);
    window.draw(sprite);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    getTexture函数返回一个只读纹理,这意味着您只能使用它,而不能修改它。如果在使用之前需要修改它,可以将其复制到您自己的sf::纹理实例中,然后进行修改。

    对于处理视图和OpenGL,sf::RenderTexture也具有与sf::RenderWindow相同的功能(有关更多详细信息,请参阅相应的教程)。如果使用OpenGL绘制渲染纹理,则可以使用create函数的第三个可选参数请求创建深度缓冲区。

    Drawing from threads


    SFML支持多线程绘图,您甚至不需要做任何事情就可以使其工作。唯一要记住的是在另一个线程中使用窗口之前先停用它。这是因为一个窗口(更准确地说是它的OpenGL上下文)不能同时在多个线程中处于活动状态。

    void renderingThread(sf::RenderWindow* window)
    {
        // activate the window's context
        window->setActive(true);
    
        // the rendering loop
        while (window->isOpen())
        {
            // draw...
    
            // end the current frame
            window->display();
        }
    }
    
    int main()
    {
        // create the window (remember: it's safer to create it in the main thread due to OS limitations)
        sf::RenderWindow window(sf::VideoMode(800, 600), "OpenGL");
    
        // deactivate its OpenGL context
        window.setActive(false);
    
        // launch the rendering thread
        sf::Thread thread(&renderingThread, &window);
        thread.launch();
    
        // the event/logic/whatever loop
        while (window.isOpen())
        {
            ...
        }
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
  • 相关阅读:
    自定义类型:结构体、位段、枚举、联合
    由浅入深详解四种分布式锁
    C++算法:图中的最短环
    python爬虫基础-response响应头
    keycloak~token有效期与session有效期的调研
    感性负载在电力系统中的应用和重要性是什么?
    腾讯面试——SNG,QQ音乐
    The Sandbox Alpha 第三季游戏体验推荐|《爱是永恒》
    计算机两种体系结构及指令集
    如何区分快解析内网穿透和Nginx端口映射?
  • 原文地址:https://blog.csdn.net/Phantom_matter/article/details/125548637