使用SFML绘制东西

时间:2018-10-31 13:53:26

标签: c++ sfml

我正在尝试为uni项目创建一个乱写的克隆。

我的线条基本上是很多点。如果我画得太快,线会折断,并且我只有一个点。 此外,我不知道如何仅在按下鼠标按钮时绘制线条。 我试图将mouseMoved放入while循环中,直到释放mouseButton为止,但这似乎没有用。我陷入了无限循环。

到目前为止,这是我的代码:

    while (window.isOpen())
    {

        while (window.pollEvent(event))
        {

            int mouseButtonX = event.mouseButton.x;
            int mouseButtonY = event.mouseButton.y;

            int mouseMoveX = event.mouseMove.x;
            int mouseMoveY = event.mouseMove.y;

            setBrushSize(5);

            brush.setRadius(brushSize);
            brush.setPosition(mouseMoveX - brushSize, mouseMoveY - brushSize);
            brush.setFillColor(sf::Color::Transparent);
            brush.setOutlineColor(sf::Color::Green);
            brush.setOutlineThickness(2);

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

            case (sf::Event::KeyPressed):
                if (event.key.control && event.key.code == sf::Keyboard::X) {
                    cout << "closing";

                    window.close();
                }

                if (event.key.code == sf::Keyboard::R) {
                    cout << "printed";
                    brushColor = setBrushColor(255, 0, 0);
                }
                if (event.key.code == sf::Keyboard::G) {
                    brushColor = setBrushColor(0, 255, 0);
                }
                if (event.key.code == sf::Keyboard::B) {
                    brushColor = setBrushColor(0, 0, 255);
                }
                if (event.key.code == sf::Keyboard::C) {
                    for (int i = 0; i < points.size(); i++) {
                        points.clear();
                    }
                    it = 0;
                }
                break;

            case(sf::Event::MouseButtonPressed):
                points.push_back(point);
                points[it].setRadius(brushSize);
                points[it].setFillColor(brushColor);
                points[it].setPosition(mouseButtonX - brushSize, mouseButtonY - brushSize);
                it++;
                cout << "drawPoint: Pressed X = " << mouseButtonX << " Y = " << mouseButtonY << endl;

                break;

            case(sf::Event::MouseMoved):
                points.push_back(point);
                points[it].setRadius(brushSize);
                points[it].setFillColor(brushColor);
                points[it].setPosition(mouseMoveX - brushSize, mouseMoveY - brushSize);
                it++;
                cout << "drawPoint: Moved X = " << mouseMoveX << " Y = " << mouseMoveY << endl;
                break;
            }
        }


        window.clear(sf::Color(255, 247, 204));
        window.draw(SkechyT);
        window.draw(close);
        window.draw(brush);
        window.draw(color);
        window.draw(clear);


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

        //window.draw(point);

        window.display();
    }
}


int getBrushSize() {
    return brushSize;
}

void setBrushSize(int num) {
    brushSize = num;

}

sf::Color setBrushColor(int r, int g, int b) {
    return sf::Color(r, g, b);
}

~Visualizer();

};

1 个答案:

答案 0 :(得分:2)

虽然您可以即时修改sf::VertexArray(基本上是构建矢量绘图应用程序),但也可以将sf::RenderTexture用作实际的绘图画布。

考虑到您尝试绘制许多小点,我认为您的目标是后者。这里重要的是,您不必在绘制调用之间清除渲染纹理,因此可以保留以前绘制的任何内容。

结合最初的目标–绘图–这变得非常容易。

您要做的就是绘制更改(例如,移动光标时),完成渲染纹理(通过调用display()),然后使用任何可绘制对象(例如sf::Sprite)将其呈现。 / p>

我很快将下面的示例拼写成一个例子,该例子应该很好地展示了这个概念(除了真正的主循环之外,您不会遇到无尽的循环):

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

int main(int argc, char **argv) {
    sf::RenderWindow window(sf::VideoMode(800, 600), L"SFML Drawing – C to clear, PageUp/PageDown to pick colors", sf::Style::Default);
    // Set a specific frame rate, since we don't want to
    // worry about vsync or the time between drawing iterations
    window.setVerticalSyncEnabled(false);
    window.setFramerateLimit(100);

    // First we'll use a canvas to basically store our image
    sf::RenderTexture canvas;
    canvas.create(800, 600);
    canvas.clear(sf::Color::White);

    // Next we'll need a sprite as a helper to draw our canvas
    sf::Sprite sprite;
    sprite.setTexture(canvas.getTexture(), true);

    // Define some colors to use
    // These are all with very low alpha so we
    // can (over-)draw based on how fast we move the cursor
    const std::vector<sf::Color> colors = {
        sf::Color(255, 0, 0, 8),
        sf::Color(255, 255, 0, 8),
        sf::Color(0, 255, 0, 8),
        sf::Color(0, 255, 255, 8),
        sf::Color(0, 0, 255, 8),
        sf::Color(255, 0, 255, 8)
    };

    // We'll need something to actually draw
    // For simplicity, I'm just drawing a circle shape
    // but you could also draw a line, rectangle, or something more complex
    const float brush_size = 25;
    sf::CircleShape brush(brush_size, 24);
    brush.setOrigin(brush_size, brush_size); // Center on the circle's center

    sf::Vector2f lastPos;
    bool isDrawing = false;
    unsigned int color = 0;

    // Apply some default color
    brush.setFillColor(colors[color]);

    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            switch (event.type) {
            case sf::Event::Closed:
                window.close();
                break;
            case sf::Event::KeyPressed:
                switch (event.key.code) {
                    case sf::Keyboard::C:
                        // Clear our canvas
                        canvas.clear(sf::Color::White);
                        canvas.display();
                        break;
                    case sf::Keyboard::PageUp:
                        // Get next color
                        color = (color + 1) % colors.size();
                        // Apply it
                        brush.setFillColor(colors[color]);
                        break;
                    case sf::Keyboard::PageDown:
                        // Get previous color
                        color = (color - 1) % colors.size();
                        // Apply it
                        brush.setFillColor(colors[color]);
                        break;
                }
                break;
            case sf::Event::Resized:
                {
                    // Window got resized, update the view to the new size
                    sf::View view(window.getView());
                    const sf::Vector2f size(window.getSize().x, window.getSize().y);
                    view.setSize(size); // Set the size
                    view.setCenter(size / 2.f); // Set the center, moving our drawing to the top left
                    window.setView(view); // Apply the view
                    break;
                }
            case sf::Event::MouseButtonPressed:
                // Only care for the left button
                if (event.mouseButton.button == sf::Mouse::Left) {
                    isDrawing = true;
                    // Store the cursor position relative to the canvas
                    lastPos = window.mapPixelToCoords({event.mouseButton.x, event.mouseButton.y});

                    // Now let's draw our brush once, so we can
                    // draw dots without actually draging the mouse
                    brush.setPosition(lastPos);

                    // Draw our "brush"
                    canvas.draw(brush);

                    // Finalize the texture
                    canvas.display();
                }
                break;
            case sf::Event::MouseButtonReleased:
                // Only care for the left button
                if (event.mouseButton.button == sf::Mouse::Left)
                    isDrawing = false;
                break;
            case sf::Event::MouseMoved:
                if (isDrawing)
                {
                    // Calculate the cursor position relative to the canvas
                    const sf::Vector2f newPos(window.mapPixelToCoords(sf::Vector2i(event.mouseMove.x, event.mouseMove.y)));

                    // I'm only using the new position here
                    // but you could also use `lastPos` to draw a
                    // line or rectangle instead
                    brush.setPosition(newPos);

                    // Draw our "brush"
                    canvas.draw(brush);

                    // Finalize the texture
                    canvas.display();
                    break;
                }
            }
        }

        // Clear the window
        window.clear(sf::Color(64, 64, 64));

        // Draw our canvas
        window.draw(sprite);

        // Show the window
        window.display();
    }

    return 0;
}

运行后,您可以使用鼠标左键开始绘图。 C 将清除画布,并且 Page Up Page Down 允许您选择其他颜色:

Screenshot of the example running

编辑:而且,在上面的示例中,只需画一个sf::VertexArray和两个顶点sf::Lines,而不是绘制一个圆,{ {1}}和lastPos。这样,您将始终画一条连续的线。 (但是显然,一旦完成,您显然必须使用值newPos保存/更新lastPos。)