[c++ / SFML] [µPaint] A simple drawing program

in #steemstem7 years ago (edited)

alt text

German version: here
A video demonstration: here
This project shows how easy it is to create your own minimalistic drawing program and therefore its aim is to encourage you to further develop it. You could for instance try to add support for drawing circles, rectangles, zoom in / out etc.
You are welcome to post your code in the comments and ask if you have any questions or suggestions.
There will probably be a follow up, that shows a way on how to implement the above ideas.

Setup

First of all c++ and the SimpleFastMultimediaLibrary (SFML) are used to create this minimalistic program. Install guide of SFML for Visual Studio: here

Since steemit doesn't support syntax highlighting (yet), I suggest copying the below code to a program of your choice, that supports it. Like Notepad++.

Code

In order to understand how vertexArrays work see: VertexArray
Basically what is being done is to add a new vertexArray to a vector every time the user releases a mouse button and therefore must have pressed it before. When the user presses a mouse button we add vertices to the current vertexArray with the current mouse_position as its coordinates for as long as the user releases a mouse button.

Peculiarities

alt text

Since the mouse_position is referenced to the monitors coordinate system, we have to compensate for it by subtracting the windows position (left upper corner) from it.
We also have to compensate for the windows border thickness and the title bar thickness in order to draw a line from the actual mouse point (See Border_Offset).

If you want to know how the "µPaint" imgage at the top was created: Play around with the code.
Hint: It only needs 3 changes to be able to recreate it.

Small enhancements

To prevent the number of vertices going to infinity a new vertex is only added, when the mouse has moved

#include "SFML\Graphics.hpp"
#include <iostream>
#include <vector>


int main()
{

    std::vector<sf::VertexArray> vertices; // vector in wich all vertexArrays will be stored
    vertices.push_back(sf::VertexArray()); // The 1. Line
    vertices[0].setPrimitiveType(sf::LinesStrip); // The 1. Line's PrimitiveType: see https://www.sfml-dev.org/tutorials/2.4/graphics-vertex-array.php
    int lines_number = 0; // The index of the current_line
    int locked = false; // When a mouse button is pressed this will change to true until a mouse button is released again

    sf::Color curr_col = sf::Color::Black;
    sf::Vector2i last_Mouse_pos(0,0);
    
    sf::RenderWindow window(sf::VideoMode(1280, 720), "µPaint", sf::Style::Close, sf::ContextSettings(0,0, 0)); // The window everything is rendered to
    window.setFramerateLimit(60);

    sf::Vector2f Border_Offset(-5, -25); // Compensate for the Window frame when calling window.getPosition()

    while (window.isOpen())
    {
        
        // Event processing
        sf::Event event;
        while (window.pollEvent(event))
        {
            
            if (event.type == sf::Event::KeyPressed) // Handling the closure of the renderwindow
                if(event.key.code == sf::Keyboard::Key::Escape)
                    window.close();
            if (event.type == sf::Event::Closed) // Handling the closure of the renderwindow
                window.close();

            if (event.type == sf::Event::MouseButtonPressed) // See "locked" definition
            {
                locked = true;
                
            }

            if (event.type == sf::Event::MouseButtonReleased) // See "locked" definition
            {
                // Add a new Line
                lines_number++; 
                vertices.push_back(sf::VertexArray());
                vertices[lines_number].setPrimitiveType(sf::LinesStrip);

                locked = false; // Reset
            }
        }

        if (locked) // See "locked" definition
        {
            if (last_Mouse_pos != sf::Mouse::getPosition()) // When the Mouse hasn't moved don't add any new Vertex (save memory)
            {
                //.append(Position, Color) : .append(MousePos - WindowPos + MouseOffset, curr_col)
                vertices[lines_number].append(sf::Vertex(sf::Vector2f(sf::Mouse::getPosition().x - window.getPosition().x + Border_Offset.x, sf::Mouse::getPosition().y - window.getPosition().y + Border_Offset.y), curr_col));

                last_Mouse_pos = sf::Mouse::getPosition();
            }
        }
        

        //curr_col = sf::Color::Color(rand() % 255, rand() % 255, rand() % 255);


        std::cout << "vertices in line " << lines_number << ": " <<  vertices[lines_number].getVertexCount() << std::endl;

        window.clear(sf::Color::White); //Clear the window with a specific color
        
        //Draw everything (vertices)
        for (int i = 0; i < vertices.size(); i++)
        {
            window.draw(vertices[i]);
        }

        window.display();
    }


    return 0;
}