Examples and Resources

The following complete program combine the module’s ideas into a small project.

Table of Contents

  1. Example Program: Persistent Neon Paint
  2. Where to Go Next

Example Program: Persistent Neon Paint

Clearing the window every frame is correct for animation, but a painting program needs its marks to persist. A RenderTexture2D is an off-screen GPU drawing surface. This program draws marks into that texture, then displays the saved texture every frame.

#include "raylib.h"

#include <algorithm>
#include <cmath>

int main() {
    constexpr int screenWidth{900};
    constexpr int screenHeight{520};

    InitWindow(screenWidth, screenHeight, "Raylib - Persistent Neon Paint");
    SetTargetFPS(60);

    RenderTexture2D canvas{LoadRenderTexture(screenWidth, screenHeight)};
    if (!IsRenderTextureValid(canvas)) {
        TraceLog(LOG_ERROR, "Could not create the render texture");
        CloseWindow();
        return 1;
    }

    BeginTextureMode(canvas);
    ClearBackground(Color{8, 10, 24, 255});
    EndTextureMode();

    Vector2 previousMouse{GetMousePosition()};
    float brushSize{18.0F};

    while (!WindowShouldClose()) {
        const Vector2 mouse{GetMousePosition()};
        brushSize += GetMouseWheelMove() * 2.0F;
        brushSize = std::clamp(brushSize, 3.0F, 60.0F);

        if (IsKeyPressed(KEY_C)) {
            BeginTextureMode(canvas);
            ClearBackground(Color{8, 10, 24, 255});
            EndTextureMode();
        }

        if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT)) {
            previousMouse = mouse;
        }

        if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
            const float hue{
                static_cast<float>(std::fmod(GetTime() * 70.0, 360.0))
            };
            const Color brushColour{ColorFromHSV(hue, 0.78F, 1.0F)};

            BeginTextureMode(canvas);
            DrawLineEx(previousMouse, mouse, brushSize, Fade(brushColour, 0.72F));
            DrawCircleV(mouse, brushSize / 2.0F, brushColour);
            EndTextureMode();
        }

        previousMouse = mouse;

        BeginDrawing();
        ClearBackground(BLACK);

        Rectangle canvasSource{
            0.0F,
            0.0F,
            static_cast<float>(canvas.texture.width),
            -static_cast<float>(canvas.texture.height)
        };
        DrawTextureRec(canvas.texture, canvasSource, Vector2{0.0F, 0.0F}, WHITE);

        DrawRectangle(0, 0, screenWidth, 48, Fade(BLACK, 0.72F));
        DrawText("Hold left mouse to paint   Wheel: size   C: clear",
                 14, 13, 20, RAYWHITE);
        DrawCircleLinesV(mouse, brushSize / 2.0F, RAYWHITE);

        EndDrawing();
    }

    UnloadRenderTexture(canvas);
    CloseWindow();
    return 0;
}

Render textures use an inverted vertical orientation compared with normal screen drawing. The negative height in canvasSource flips the saved canvas into the expected orientation.

Where to Go Next

When studying an example, identify its initialization, update/input, drawing, and cleanup sections first. Then look up only the unfamiliar functions in the cheatsheet or the pinned 6.0 header.