← ziglang.inraylib-zigGitHub

outlines testbed

★★★☆by Matthew Roush (@MatthewRoush)

There is no browser build of this example yet.

Is it the same as C?

//! raylib [shapes] example - outlines testbed
//!
//! Zig-API translation of examples/shapes/shapes_outlines_testbed.c (raylib 6.2).
//! Example contributed by Matthew Roush (@MatthewRoush) and reviewed by Ramon Santamaria (@raysan5)
//! Example licensed under an unmodified zlib/libpng license.
//! Copyright (c) 2026 Matthew Roush (@MatthewRoush)

const std = @import("std");
const rl = @import("raylib");
const gui = @import("raygui");

const color_filled: rl.Color = .dark_blue;
const color_outline: rl.Color = .yellow;

const shape_spacing: f32 = 14.0;
const shape_size: f32 = 46.0;
const box_spacing: f32 = 10.0;

const mouse_camera_zoom_speed: f32 = 0.3;
const keyboard_camera_move_speed: f32 = 10.0;
const keyboard_camera_zoom_speed: f32 = 0.1;

const camera_zoom_min: f32 = 0.1;
const camera_zoom_max: f32 = 1000.0;

/// The shapes are drawn in this order, left to right
const Shape = enum { rectangle, rectangle_rounded, circle, ellipse, circle_sector, ring, triangle, polygon };

/// The line style groups are drawn in this order, top to bottom
const LineStyle = enum {
    lines,
    lines_ex_world,
    lines_ex_screen,

    fn title(style: LineStyle) [:0]const u8 {
        return switch (style) {
            .lines => "Draw*Lines()",
            .lines_ex_world => "Draw*LinesEx() with *world space* pixel thickness",
            .lines_ex_screen => "Draw*LinesEx() with *screen space* pixel thickness",
        };
    }
};

const shape_count: f32 = @floatFromInt(std.enums.values(Shape).len);
const box_width = shape_size * shape_count + shape_spacing * (shape_count - 1) + box_spacing * 2.0;
const box_height = shape_size + box_spacing * 2.0;

const shape_offset = box_spacing * 2.0;
const shape_padding_x = shape_size + shape_spacing;
const shape_padding_y = shape_size + shape_spacing + box_spacing * 2.0;

const triangle_vertex_offsets = [3]rl.Vector2{
    .{ .x = 0.0, .y = shape_size * 0.8 },
    .{ .x = shape_size * 0.6, .y = shape_size },
    .{ .x = shape_size, .y = 0.0 },
};

/// User configurable options while running the program.
const Options = struct {
    line_opacity: f32 = 130,
    line_thickness: f32 = 4.0,
    rectangle_roundness: f32 = 0.4,
    rectangle_segments: f32 = 9,
    ellipse_radius_y: f32 = 0.5,
    circle_start_angle: f32 = 20.0,
    circle_end_angle: f32 = 270.0,
    circle_segments: f32 = 36,
    ring_inner_radius_scale: f32 = 0.3,
    polygon_sides: f32 = 6,
};

/// Draw one shape filled, then outlined in the given line style.
fn drawShape(shape: Shape, style: LineStyle, pos_x: f32, pos_y: f32, opts: Options, thick: f32, outline: rl.Color) void {
    const rec: rl.Rectangle = .{ .x = pos_x, .y = pos_y, .width = shape_size, .height = shape_size };
    const center: rl.Vector2 = .{ .x = pos_x + shape_size / 2.0, .y = pos_y + shape_size / 2.0 };

    const radius_x = shape_size / 2.0;
    const radius_y = radius_x * opts.ellipse_radius_y;

    const ring_outer_radius = shape_size / 2.0;
    const ring_inner_radius = ring_outer_radius * opts.ring_inner_radius_scale;

    const rec_segments: i32 = @intFromFloat(opts.rectangle_segments);
    const circle_segments: i32 = @intFromFloat(opts.circle_segments);
    const polygon_sides: i32 = @intFromFloat(opts.polygon_sides);
    const start_angle = opts.circle_start_angle;
    const end_angle = opts.circle_end_angle;

    switch (shape) {
        .rectangle => {
            rl.drawRectangleRec(rec, color_filled);
            switch (style) {
                .lines => rl.drawRectangleLines(@intFromFloat(pos_x), @intFromFloat(pos_y), @intFromFloat(shape_size), @intFromFloat(shape_size), outline),
                else => rl.drawRectangleLinesEx(rec, thick, outline),
            }
        },
        .rectangle_rounded => {
            rl.drawRectangleRounded(rec, opts.rectangle_roundness, rec_segments, color_filled);
            switch (style) {
                .lines => rl.drawRectangleRoundedLines(rec, opts.rectangle_roundness, rec_segments, outline),
                else => rl.drawRectangleRoundedLinesEx(rec, opts.rectangle_roundness, rec_segments, thick, outline),
            }
        },
        .circle => {
            rl.drawCircleV(center, radius_x, color_filled);
            switch (style) {
                .lines => rl.drawCircleLinesV(center, radius_x, outline),
                else => rl.drawCircleLinesEx(center, radius_x, thick, outline),
            }
        },
        .ellipse => {
            rl.drawEllipseV(center, radius_x, radius_y, color_filled);
            switch (style) {
                .lines => rl.drawEllipseLinesV(center, radius_x, radius_y, outline),
                else => rl.drawEllipseLinesEx(center, radius_x, radius_y, thick, outline),
            }
        },
        .circle_sector => {
            rl.drawCircleSector(center, radius_x, start_angle, end_angle, circle_segments, color_filled);
            switch (style) {
                .lines => rl.drawCircleSectorLines(center, radius_x, start_angle, end_angle, circle_segments, outline),
                else => rl.drawCircleSectorLinesEx(center, radius_x, start_angle, end_angle, circle_segments, thick, outline),
            }
        },
        .ring => {
            rl.drawRing(center, ring_inner_radius, ring_outer_radius, start_angle, end_angle, circle_segments, color_filled);
            switch (style) {
                .lines => rl.drawRingLines(center, ring_inner_radius, ring_outer_radius, start_angle, end_angle, circle_segments, outline),
                else => rl.drawRingLinesEx(center, ring_inner_radius, ring_outer_radius, start_angle, end_angle, circle_segments, thick, outline),
            }
        },
        .triangle => {
            var v: [3]rl.Vector2 = undefined;
            for (&v, triangle_vertex_offsets) |*vertex, offset| vertex.* = .{ .x = pos_x + offset.x, .y = pos_y + offset.y };
            rl.drawTriangle(v[0], v[1], v[2], color_filled);
            switch (style) {
                .lines => rl.drawTriangleLines(v[0], v[1], v[2], outline),
                else => rl.drawTriangleLinesEx(v[0], v[1], v[2], thick, outline),
            }
        },
        .polygon => {
            rl.drawPoly(center, polygon_sides, radius_x, 0.0, color_filled);
            switch (style) {
                .lines => rl.drawPolyLines(center, polygon_sides, radius_x, 0.0, outline),
                else => rl.drawPolyLinesEx(center, polygon_sides, radius_x, 0.0, thick, outline),
            }
        },
    }
}

/// Set the camera zoom while keeping the world point under `zoom_point` fixed on screen.
fn zoomAround(camera: *rl.Camera2D, zoom_point: rl.Vector2, zoom: f32) void {
    const prev_world_zoom_point = rl.getScreenToWorld2D(zoom_point, camera.*);

    camera.zoom = zoom;

    const world_zoom_point = rl.getScreenToWorld2D(zoom_point, camera.*);
    camera.target = rl.math.vector2Add(camera.target, rl.math.vector2Subtract(prev_world_zoom_point, world_zoom_point));
}

pub fn main() void {
    // Initialization
    const screen_width = 800;
    const screen_height = 450;

    rl.initWindow(screen_width, screen_height, "raylib [shapes] example - outlines testbed");
    defer rl.closeWindow(); // Close window and OpenGL context

    var camera: rl.Camera2D = .{
        .offset = .{ .x = 0, .y = 0 },
        .target = .{ .x = 0, .y = 0 },
        .rotation = 0,
        .zoom = 1,
    };

    var opts: Options = .{};

    var disable_mouse_control = false;

    const options_background: rl.Rectangle = .{ .x = 510, .y = 0, .width = 290, .height = 450 };

    const zoom_point: rl.Vector2 = .{
        .x = (@as(f32, screen_width) - options_background.width) / 2.0,
        .y = @as(f32, screen_height) / 2.0,
    };

    gui.setStyle(.label, gui.ControlProperty.text_color_normal, rl.colorToInt(.white));

    rl.setTargetFPS(60);

    // Main game loop
    while (!rl.windowShouldClose()) { // Detect window close button or ESC key
        // Update
        const mouse_pos_screen = rl.getMousePosition();
        const mouse_wheel_vec = rl.getMouseWheelMoveV();

        if (rl.isMouseButtonPressed(.left) and rl.checkCollisionPointRec(mouse_pos_screen, options_background)) disable_mouse_control = true;

        if (rl.isMouseButtonReleased(.left)) disable_mouse_control = false;

        if (!disable_mouse_control) {
            if (mouse_wheel_vec.y != 0.0) {
                // Constant zoom rate
                const zoom = camera.zoom * @exp2(mouse_camera_zoom_speed * mouse_wheel_vec.y);
                zoomAround(&camera, zoom_point, rl.math.clamp(zoom, camera_zoom_min, camera_zoom_max));
            }

            if (rl.isMouseButtonDown(.left)) {
                const mouse_delta = rl.getMouseDelta();
                camera.target.x -= mouse_delta.x / camera.zoom;
                camera.target.y -= mouse_delta.y / camera.zoom;

                // Wrap the mouse around the drawing area
                const mouse_max_x: i32 = @intFromFloat(options_background.x);
                const mouse_max_y: i32 = screen_height;

                const x: i32 = @intFromFloat(mouse_pos_screen.x);
                const y: i32 = @intFromFloat(mouse_pos_screen.y);
                const new_x = @mod(x, mouse_max_x);
                const new_y = @mod(y, mouse_max_y);

                if (new_x != x or new_y != y) rl.setMousePosition(new_x, new_y);
            }
        }

        if (rl.isKeyDown(.a)) camera.target.x -= keyboard_camera_move_speed / camera.zoom;
        if (rl.isKeyDown(.d)) camera.target.x += keyboard_camera_move_speed / camera.zoom;
        if (rl.isKeyDown(.w)) camera.target.y -= keyboard_camera_move_speed / camera.zoom;
        if (rl.isKeyDown(.s)) camera.target.y += keyboard_camera_move_speed / camera.zoom;

        if (rl.isKeyDown(.up)) {
            const zoom = camera.zoom * @exp2(keyboard_camera_zoom_speed);
            zoomAround(&camera, zoom_point, rl.math.clamp(zoom, camera_zoom_min, camera_zoom_max));
        }
        if (rl.isKeyDown(.down)) {
            const zoom = camera.zoom * @exp2(-keyboard_camera_zoom_speed);
            zoomAround(&camera, zoom_point, rl.math.clamp(zoom, camera_zoom_min, camera_zoom_max));
        }

        if (rl.isKeyPressed(.z)) zoomAround(&camera, zoom_point, 1.0);

        if (rl.isKeyPressed(.c)) camera.target = .{ .x = 0, .y = 0 };

        // Draw
        rl.beginDrawing();
        defer rl.endDrawing();

        rl.clearBackground(.{ .r = 50, .g = 50, .b = 55, .a = 255 });

        var outline = color_outline;
        outline.a = @intFromFloat(opts.line_opacity);

        {
            rl.beginMode2D(camera);
            defer rl.endMode2D();

            for (std.enums.values(LineStyle)) |style| {
                const pos_y = shape_offset + shape_padding_y * @as(f32, @floatFromInt(@backingInt(style)));
                const thick = switch (style) {
                    .lines => 0.0, // Draw*Lines() take no thickness
                    .lines_ex_world => opts.line_thickness,
                    .lines_ex_screen => opts.line_thickness / camera.zoom,
                };

                for (std.enums.values(Shape)) |shape| {
                    const pos_x = shape_offset + shape_padding_x * @as(f32, @floatFromInt(@backingInt(shape)));
                    drawShape(shape, style, pos_x, pos_y, opts, thick, outline);
                }

                // Group the shapes
                _ = gui.groupBox(.{ .x = shape_offset - box_spacing, .y = pos_y - box_spacing, .width = box_width, .height = box_height }, style.title());
            }
        }

        rl.drawRectangleRec(options_background, rl.fade(.dark_gray, 0.75));

        rl.drawRectangleRec(.{ .x = options_background.x, .y = 360, .width = options_background.width, .height = 90 }, rl.fade(.black, 0.4));
        rl.drawLineEx(.{ .x = options_background.x, .y = 360 }, .{ .x = options_background.x + options_background.width, .y = 360 }, 1.0, .black);

        const text_x: i32 = @as(i32, @intFromFloat(options_background.x)) + 10;
        rl.drawText("Move with the mouse or WASD keys", text_x, 370, 10, .orange);
        rl.drawText("Zoom with the mouse or UP and DOWN keys", text_x, 390, 10, .orange);
        rl.drawText("Press C to reset position", text_x, 410, 10, .orange);
        rl.drawText("Press Z to reset zoom", text_x, 430, 10, .orange);

        rl.drawLineEx(.{ .x = options_background.x, .y = options_background.y }, .{ .x = options_background.x, .y = options_background.y + options_background.height }, 1.0, .black);

        _ = gui.sliderBar(.{ .x = 605, .y = 10, .width = 150, .height = 25 }, "Line Opacity", rl.textFormat("{d}", .{@as(i32, @intFromFloat(opts.line_opacity))}), &opts.line_opacity, 0, 255);
        _ = gui.sliderBar(.{ .x = 605, .y = 45, .width = 150, .height = 25 }, "Thickness", rl.textFormat("{d:.2}", .{opts.line_thickness}), &opts.line_thickness, -20.0, 40.0);
        _ = gui.sliderBar(.{ .x = 605, .y = 80, .width = 150, .height = 25 }, "Rect Roundness", rl.textFormat("{d:.2}", .{opts.rectangle_roundness}), &opts.rectangle_roundness, -1.0, 2.0);
        _ = gui.sliderBar(.{ .x = 605, .y = 115, .width = 150, .height = 25 }, "Rect Segments", rl.textFormat("{d}", .{@as(i32, @intFromFloat(opts.rectangle_segments))}), &opts.rectangle_segments, -1, 100);
        _ = gui.sliderBar(.{ .x = 605, .y = 150, .width = 150, .height = 25 }, "Ellipse Radius Y", rl.textFormat("{d:.2}", .{opts.ellipse_radius_y}), &opts.ellipse_radius_y, 0.0, 1.25);
        _ = gui.sliderBar(.{ .x = 605, .y = 185, .width = 150, .height = 25 }, "Start Angle", rl.textFormat("{d:.2}", .{opts.circle_start_angle}), &opts.circle_start_angle, -360.0, 360.0);
        _ = gui.sliderBar(.{ .x = 605, .y = 220, .width = 150, .height = 25 }, "End Angle", rl.textFormat("{d:.2}", .{opts.circle_end_angle}), &opts.circle_end_angle, -360.0, 360.0);
        _ = gui.sliderBar(.{ .x = 605, .y = 255, .width = 150, .height = 25 }, "Circle Segments", rl.textFormat("{d}", .{@as(i32, @intFromFloat(opts.circle_segments))}), &opts.circle_segments, -1, 100);
        _ = gui.sliderBar(.{ .x = 605, .y = 290, .width = 150, .height = 25 }, "Ring Radius", rl.textFormat("{d:.2}", .{opts.ring_inner_radius_scale}), &opts.ring_inner_radius_scale, -1.0, 2.0);
        _ = gui.sliderBar(.{ .x = 605, .y = 325, .width = 150, .height = 25 }, "Poly Sides", rl.textFormat("{d}", .{@as(i32, @intFromFloat(opts.polygon_sides))}), &opts.polygon_sides, -1, 100);
    }
}
/*******************************************************************************************
*
*   raylib [shapes] example - outlines testbed
*
*   Example complexity rating: [★★★☆] 3/4
*
*   Example originally created with raylib 6.1, last time updated with raylib 6.1
*
*   Example contributed by Matthew Roush (@MatthewRoush) and reviewed by Ramon Santamaria (@raysan5)
*
*   Example licensed under an unmodified zlib/libpng license, which is an OSI-certified,
*   BSD-like license that allows static linking with closed source software
*
*   Copyright (c) 2026 Matthew Roush (@MatthewRoush)
*
********************************************************************************************/

#include "raylib.h"

#include "raymath.h"

#define RAYGUI_IMPLEMENTATION
#include "raygui.h"                 // Required for GUI controls

#include <stdbool.h>

#define COLOR_FILLED  DARKBLUE
#define COLOR_OUTLINE YELLOW

#define SHAPE_SPACING 14.0f
#define SHAPE_SIZE 46.0f
#define BOX_SPACING 10.0f

#define MOUSE_CAMERA_ZOOM_SPEED 0.3f
#define KEYBOARD_CAMERA_MOVE_SPEED 10.0f
#define KEYBOARD_CAMERA_ZOOM_SPEED 0.1f

#define CAMERA_ZOOM_MIN 0.1f
#define CAMERA_ZOOM_MAX 1000.0f

// The shapes are ordered according to their order in this enum, left to right
enum {
    ORDER_RECTANGLE = 0,
    ORDER_RECTANGLE_ROUNDED,
    ORDER_CIRCLE,
    ORDER_ELLIPSE,
    ORDER_CIRCLE_SECTOR,
    ORDER_RING,
    ORDER_TRIANGLE,
    ORDER_POLYGON,
    COUNT_SHAPES
};

// The line style groups are ordered according to their order in this enum, top to bottom
enum {
    ORDER_LINES = 0,
    ORDER_LINES_EX_WORLD,
    ORDER_LINES_EX_SCREEN,
};

#define BOX_WIDTH (SHAPE_SIZE*COUNT_SHAPES + SHAPE_SPACING*(COUNT_SHAPES - 1) + BOX_SPACING*2.0f)
#define BOX_HEIGHT (SHAPE_SIZE + BOX_SPACING*2.0f)

//------------------------------------------------------------------------------------
// Program main entry point
//------------------------------------------------------------------------------------
int main(void)
{
    // Initialization
    //--------------------------------------------------------------------------------------
    const int screenWidth = 800;
    const int screenHeight = 450;

    InitWindow(screenWidth, screenHeight, "raylib [shapes] example - outlines testbed");

    Camera2D camera = { .zoom = 1 };

    // User configurable options while running the program.
    float lineOpacity          = 130;
    float lineThickness        = 4.0f;
    float rectangleRoundness   = 0.4f;
    float rectangleSegments    = 9;
    float ellipseRadiusY       = 0.5f;
    float circleStartAngle     = 20.0f;
    float circleEndAngle       = 270.0f;
    float circleSegments       = 36;
    float ringInnerRadiusScale = 0.3f;
    float polygonSides         = 6;

    bool disableMouseControl = false;

    const Rectangle optionsBackground = { 510, 0, 290, 450 };

    const Vector2 zoomPoint = {((float)screenWidth - optionsBackground.width)/2.0f, (float)screenHeight/2.0f};

    GuiSetStyle(LABEL, TEXT_COLOR_NORMAL, ColorToInt(WHITE));

    SetTargetFPS(60);
    //--------------------------------------------------------------------------------------

    // Main game loop
    while (!WindowShouldClose())    // Detect window close button or ESC key
    {
        // Update
        //----------------------------------------------------------------------------------
        const Vector2 mousePosScreen = GetMousePosition();
        const Vector2 mouseWheelVec = GetMouseWheelMoveV();

        if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT) && CheckCollisionPointRec(mousePosScreen, optionsBackground)) disableMouseControl = true;

        if (IsMouseButtonReleased(MOUSE_BUTTON_LEFT)) disableMouseControl = false;

        if (!disableMouseControl) {
            if (mouseWheelVec.y != 0.0f) {
                const Vector2 prevWorldZoomPoint = GetScreenToWorld2D(zoomPoint, camera);

                camera.zoom *= exp2f(MOUSE_CAMERA_ZOOM_SPEED*mouseWheelVec.y); // Constant zoom rate
                camera.zoom = Clamp(camera.zoom, CAMERA_ZOOM_MIN, CAMERA_ZOOM_MAX);

                const Vector2 worldZoomPoint = GetScreenToWorld2D(zoomPoint, camera);
                camera.target = Vector2Add(camera.target, Vector2Subtract(prevWorldZoomPoint, worldZoomPoint));
            }

            if (IsMouseButtonDown(MOUSE_BUTTON_LEFT)) {
                const Vector2 mouseDelta = GetMouseDelta();
                camera.target.x -= mouseDelta.x/camera.zoom;
                camera.target.y -= mouseDelta.y/camera.zoom;

                const int mouseMaxX = (int)optionsBackground.x;
                const int mouseMaxY = screenHeight;

                int newX = (int)mousePosScreen.x;
                int newY = (int)mousePosScreen.y;

                // In C, the '%' operator computes the remainder, we want the modulus
                newX = (newX%mouseMaxX + mouseMaxX)%mouseMaxX;
                newY = (newY%mouseMaxY + mouseMaxY)%mouseMaxY;

                if ((newX != (int)mousePosScreen.x) || (newY != (int)mousePosScreen.y)) SetMousePosition(newX, newY);
            }
        }

        if (IsKeyDown(KEY_A)) camera.target.x -= KEYBOARD_CAMERA_MOVE_SPEED/camera.zoom;
        if (IsKeyDown(KEY_D)) camera.target.x += KEYBOARD_CAMERA_MOVE_SPEED/camera.zoom;
        if (IsKeyDown(KEY_W)) camera.target.y -= KEYBOARD_CAMERA_MOVE_SPEED/camera.zoom;
        if (IsKeyDown(KEY_S)) camera.target.y += KEYBOARD_CAMERA_MOVE_SPEED/camera.zoom;

        if (IsKeyDown(KEY_UP))
        {
            const Vector2 prevWorldZoomPoint = GetScreenToWorld2D(zoomPoint, camera);

            camera.zoom *= exp2f(KEYBOARD_CAMERA_ZOOM_SPEED);
            camera.zoom = Clamp(camera.zoom, CAMERA_ZOOM_MIN, CAMERA_ZOOM_MAX);

            const Vector2 worldZoomPoint = GetScreenToWorld2D(zoomPoint, camera);
            camera.target = Vector2Add(camera.target, Vector2Subtract(prevWorldZoomPoint, worldZoomPoint));
        }
        if (IsKeyDown(KEY_DOWN))
        {
            const Vector2 prevWorldZoomPoint = GetScreenToWorld2D(zoomPoint, camera);

            camera.zoom *= exp2f(-KEYBOARD_CAMERA_ZOOM_SPEED);
            camera.zoom = Clamp(camera.zoom, CAMERA_ZOOM_MIN, CAMERA_ZOOM_MAX);

            const Vector2 worldZoomPoint = GetScreenToWorld2D(zoomPoint, camera);
            camera.target = Vector2Add(camera.target, Vector2Subtract(prevWorldZoomPoint, worldZoomPoint));
        }

        if (IsKeyPressed(KEY_Z))
        {
            const Vector2 zoomPoint = {((float)screenWidth - optionsBackground.width)/2.0f, (float)screenHeight/2.0f};
            const Vector2 prevWorldZoomPoint = GetScreenToWorld2D(zoomPoint, camera);

            camera.zoom = 1.0f;

            const Vector2 worldZoomPoint = GetScreenToWorld2D(zoomPoint, camera);
            camera.target = Vector2Add(camera.target, Vector2Subtract(prevWorldZoomPoint, worldZoomPoint));
        }

        if (IsKeyPressed(KEY_C)) camera.target = (Vector2){ 0 };
        //----------------------------------------------------------------------------------

        // Draw
        //----------------------------------------------------------------------------------
        BeginDrawing();

            ClearBackground((Color){ 50, 50, 55, 255 });

            Color colorOutline = COLOR_OUTLINE;
            colorOutline.a = (unsigned char)lineOpacity;

            BeginMode2D(camera);

            const float shapeOffset = BOX_SPACING*2.0f;
            const float shapePaddingX = SHAPE_SIZE + SHAPE_SPACING;
            const float shapePaddingY = SHAPE_SIZE + SHAPE_SPACING + BOX_SPACING*2.0f;

            const float radiusX = SHAPE_SIZE/2.0f;
            const float radiusY = radiusX*ellipseRadiusY;

            const float ringOuterRadius = SHAPE_SIZE/2.0f;
            const float ringInnerRadius = ringOuterRadius*ringInnerRadiusScale;

            const Vector2 triangleVertex0Offset = { 0.0f, SHAPE_SIZE*0.8f };
            const Vector2 triangleVertex1Offset = { SHAPE_SIZE*0.6f, SHAPE_SIZE };
            const Vector2 triangleVertex2Offset = { SHAPE_SIZE, 0.0f };

            // ----------------------------------------
            // Draw*Lines()
            float posY = shapeOffset + shapePaddingY*ORDER_LINES;

            // Rectangle
            float posX = shapeOffset + shapePaddingX*ORDER_RECTANGLE;
            DrawRectangleRec((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, COLOR_FILLED);
            DrawRectangleLines(posX, posY, SHAPE_SIZE, SHAPE_SIZE, colorOutline);

            // Rectangle Rounded
            posX = shapeOffset + shapePaddingX*ORDER_RECTANGLE_ROUNDED;
            DrawRectangleRounded((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, rectangleRoundness, (int)rectangleSegments, COLOR_FILLED);
            DrawRectangleRoundedLines((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, rectangleRoundness, (int)rectangleSegments, colorOutline);

            // Circle
            posX = shapeOffset + shapePaddingX*ORDER_CIRCLE;
            DrawCircleV((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, COLOR_FILLED);
            DrawCircleLinesV((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, colorOutline);

            // Ellipse
            posX = shapeOffset + shapePaddingX*ORDER_ELLIPSE;
            DrawEllipseV((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, radiusY, COLOR_FILLED);
            DrawEllipseLinesV((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, radiusY, colorOutline);

            // Circle Sector
            posX = shapeOffset + shapePaddingX*ORDER_CIRCLE_SECTOR;
            DrawCircleSector((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, circleStartAngle, circleEndAngle, (int)circleSegments, COLOR_FILLED);
            DrawCircleSectorLines((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, circleStartAngle, circleEndAngle, (int)circleSegments, colorOutline);

            // Ring
            posX = shapeOffset + shapePaddingX*ORDER_RING;
            DrawRing((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, ringInnerRadius, ringOuterRadius, circleStartAngle, circleEndAngle, (int)circleSegments, COLOR_FILLED);
            DrawRingLines((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, ringInnerRadius, ringOuterRadius, circleStartAngle, circleEndAngle, (int)circleSegments, colorOutline);

            // Triangle
            posX = shapeOffset + shapePaddingX*ORDER_TRIANGLE;
            DrawTriangle((Vector2){ posX + triangleVertex0Offset.x, posY + triangleVertex0Offset.y },
                         (Vector2){ posX + triangleVertex1Offset.x, posY + triangleVertex1Offset.y },
                         (Vector2){ posX + triangleVertex2Offset.x, posY + triangleVertex2Offset.y },
                         COLOR_FILLED);
            DrawTriangleLines((Vector2){ posX + triangleVertex0Offset.x, posY + triangleVertex0Offset.y },
                              (Vector2){ posX + triangleVertex1Offset.x, posY + triangleVertex1Offset.y },
                              (Vector2){ posX + triangleVertex2Offset.x, posY + triangleVertex2Offset.y },
                              colorOutline);

            // Polygon
            posX = shapeOffset + shapePaddingX*ORDER_POLYGON;
            DrawPoly((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, (int)polygonSides, radiusX, 0.0f, COLOR_FILLED);
            DrawPolyLines((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, (int)polygonSides, radiusX, 0.0f, colorOutline);

            // Group the shapes
            GuiGroupBox((Rectangle){ shapeOffset - BOX_SPACING, posY - BOX_SPACING, BOX_WIDTH, BOX_HEIGHT }, "Draw*Lines()");
            // ----------------------------------------

            // ----------------------------------------
            // Draw*LinesEx() with world space pixel thickness
            posY = shapeOffset + shapePaddingY*ORDER_LINES_EX_WORLD;

            // Rectangle
            posX = shapeOffset + shapePaddingX*ORDER_RECTANGLE;
            DrawRectangleRec((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, COLOR_FILLED);
            DrawRectangleLinesEx((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, lineThickness, colorOutline);

            // Rectangle Rounded
            posX = shapeOffset + shapePaddingX*ORDER_RECTANGLE_ROUNDED;
            DrawRectangleRounded((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, rectangleRoundness, (int)rectangleSegments, COLOR_FILLED);
            DrawRectangleRoundedLinesEx((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, rectangleRoundness, (int)rectangleSegments, lineThickness, colorOutline);

            // Circle
            posX = shapeOffset + shapePaddingX*ORDER_CIRCLE;
            DrawCircleV((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, COLOR_FILLED);
            DrawCircleLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, lineThickness, colorOutline);

            // Ellipse
            posX = shapeOffset + shapePaddingX*ORDER_ELLIPSE;
            DrawEllipseV((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, radiusY, COLOR_FILLED);
            DrawEllipseLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, radiusY, lineThickness, colorOutline);

            // Circle Sector
            posX = shapeOffset + shapePaddingX*ORDER_CIRCLE_SECTOR;
            DrawCircleSector((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, circleStartAngle, circleEndAngle, (int)circleSegments, COLOR_FILLED);
            DrawCircleSectorLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, circleStartAngle, circleEndAngle, (int)circleSegments, lineThickness, colorOutline);

            // Ring
            posX = shapeOffset + shapePaddingX*ORDER_RING;
            DrawRing((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, ringInnerRadius, ringOuterRadius, circleStartAngle, circleEndAngle, (int)circleSegments, COLOR_FILLED);
            DrawRingLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, ringInnerRadius, ringOuterRadius, circleStartAngle, circleEndAngle, (int)circleSegments, lineThickness, colorOutline);

            // Triangle
            posX = shapeOffset + shapePaddingX*ORDER_TRIANGLE;
            DrawTriangle((Vector2){ posX + triangleVertex0Offset.x, posY + triangleVertex0Offset.y },
                         (Vector2){ posX + triangleVertex1Offset.x, posY + triangleVertex1Offset.y },
                         (Vector2){ posX + triangleVertex2Offset.x, posY + triangleVertex2Offset.y },
                         COLOR_FILLED);
            DrawTriangleLinesEx((Vector2){ posX + triangleVertex0Offset.x, posY + triangleVertex0Offset.y },
                                (Vector2){ posX + triangleVertex1Offset.x, posY + triangleVertex1Offset.y },
                                (Vector2){ posX + triangleVertex2Offset.x, posY + triangleVertex2Offset.y },
                                lineThickness, colorOutline);

            // Polygon
            posX = shapeOffset + shapePaddingX*ORDER_POLYGON;
            DrawPoly((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, (int)polygonSides, radiusX, 0.0f, COLOR_FILLED);
            DrawPolyLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, (int)polygonSides, radiusX, 0.0f, lineThickness, colorOutline);

            // Group the shapes
            GuiGroupBox((Rectangle){ shapeOffset - BOX_SPACING, posY - BOX_SPACING, BOX_WIDTH, BOX_HEIGHT }, "Draw*LinesEx() with *world space* pixel thickness");
            // ----------------------------------------

            // ----------------------------------------
            // Draw*LinesEx() with screen space pixel thickness
            posY = shapeOffset + shapePaddingY*ORDER_LINES_EX_SCREEN;

            float constantThickness = lineThickness/camera.zoom;

            // Rectangle
            posX = shapeOffset + shapePaddingX*ORDER_RECTANGLE;
            DrawRectangleRec((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, COLOR_FILLED);
            DrawRectangleLinesEx((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, constantThickness, colorOutline);

            // Rectangle Rounded
            posX = shapeOffset + shapePaddingX*ORDER_RECTANGLE_ROUNDED;
            DrawRectangleRounded((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, rectangleRoundness, (int)rectangleSegments, COLOR_FILLED);
            DrawRectangleRoundedLinesEx((Rectangle){ posX, posY, SHAPE_SIZE, SHAPE_SIZE }, rectangleRoundness, (int)rectangleSegments, constantThickness, colorOutline);

            // Circle
            posX = shapeOffset + shapePaddingX*ORDER_CIRCLE;
            DrawCircleV((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, COLOR_FILLED);
            DrawCircleLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, constantThickness, colorOutline);

            // Ellipse
            posX = shapeOffset + shapePaddingX*ORDER_ELLIPSE;
            DrawEllipseV((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, radiusY, COLOR_FILLED);
            DrawEllipseLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, radiusY, constantThickness, colorOutline);

            // Circle Sector
            posX = shapeOffset + shapePaddingX*ORDER_CIRCLE_SECTOR;
            DrawCircleSector((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, circleStartAngle, circleEndAngle, (int)circleSegments, COLOR_FILLED);
            DrawCircleSectorLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, radiusX, circleStartAngle, circleEndAngle, (int)circleSegments, constantThickness, colorOutline);

            // Ring
            posX = shapeOffset + shapePaddingX*ORDER_RING;
            DrawRing((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, ringInnerRadius, ringOuterRadius, circleStartAngle, circleEndAngle, (int)circleSegments, COLOR_FILLED);
            DrawRingLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, ringInnerRadius, ringOuterRadius, circleStartAngle, circleEndAngle, (int)circleSegments, constantThickness, colorOutline);

            // Triangle
            posX = shapeOffset + shapePaddingX*ORDER_TRIANGLE;
            DrawTriangle((Vector2){ posX + triangleVertex0Offset.x, posY + triangleVertex0Offset.y },
                         (Vector2){ posX + triangleVertex1Offset.x, posY + triangleVertex1Offset.y },
                         (Vector2){ posX + triangleVertex2Offset.x, posY + triangleVertex2Offset.y },
                         COLOR_FILLED);
            DrawTriangleLinesEx((Vector2){ posX + triangleVertex0Offset.x, posY + triangleVertex0Offset.y },
                                (Vector2){ posX + triangleVertex1Offset.x, posY + triangleVertex1Offset.y },
                                (Vector2){ posX + triangleVertex2Offset.x, posY + triangleVertex2Offset.y },
                                constantThickness, colorOutline);

            // Polygon
            posX = shapeOffset + shapePaddingX*ORDER_POLYGON;
            DrawPoly((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, (int)polygonSides, radiusX, 0.0f, COLOR_FILLED);
            DrawPolyLinesEx((Vector2){ posX + SHAPE_SIZE/2.0f, posY + SHAPE_SIZE/2.0f }, (int)polygonSides, radiusX, 0.0f, constantThickness, colorOutline);

            // Group the shapes
            GuiGroupBox((Rectangle){ shapeOffset - BOX_SPACING, posY - BOX_SPACING, BOX_WIDTH, BOX_HEIGHT }, "Draw*LinesEx() with *screen space* pixel thickness");
            // ----------------------------------------

            EndMode2D();

            DrawRectangleRec(optionsBackground, Fade(DARKGRAY, 0.75f));

            DrawRectangleRec((Rectangle){ optionsBackground.x, 360, optionsBackground.width, 90 }, Fade(BLACK, 0.4f));
            DrawLineEx((Vector2){ optionsBackground.x, 360 }, (Vector2){ optionsBackground.x + optionsBackground.width, 360 }, 1.0f, BLACK);

            DrawText("Move with the mouse or WASD keys", (int)optionsBackground.x + 10, 370, 10, ORANGE);
            DrawText("Zoom with the mouse or UP and DOWN keys", (int)optionsBackground.x + 10, 390, 10, ORANGE);
            DrawText("Press C to reset position", (int)optionsBackground.x + 10, 410, 10, ORANGE);
            DrawText("Press Z to reset zoom", (int)optionsBackground.x + 10, 430, 10, ORANGE);

            DrawLineEx((Vector2){ optionsBackground.x, optionsBackground.y }, (Vector2){ optionsBackground.x, optionsBackground.y + optionsBackground.height }, 1.0f, BLACK);

            GuiSliderBar((Rectangle){ 605,  10, 150, 25 }, "Line Opacity"    , TextFormat("%d"  , (int)lineOpacity)      , &lineOpacity         ,  0     , 255);
            GuiSliderBar((Rectangle){ 605,  45, 150, 25 }, "Thickness"       , TextFormat("%.2f", lineThickness)         , &lineThickness       , -20.0f , 40.0f);
            GuiSliderBar((Rectangle){ 605,  80, 150, 25 }, "Rect Roundness"  , TextFormat("%.2f", rectangleRoundness)    , &rectangleRoundness  , -1.0f  , 2.0f);
            GuiSliderBar((Rectangle){ 605, 115, 150, 25 }, "Rect Segments"   , TextFormat("%d"  , (int)rectangleSegments), &rectangleSegments   , -1     , 100);
            GuiSliderBar((Rectangle){ 605, 150, 150, 25 }, "Ellipse Radius Y", TextFormat("%.2f", ellipseRadiusY)        , &ellipseRadiusY      , 0.0f   , 1.25f);
            GuiSliderBar((Rectangle){ 605, 185, 150, 25 }, "Start Angle"     , TextFormat("%.2f", circleStartAngle)      , &circleStartAngle    , -360.0f, 360.0f);
            GuiSliderBar((Rectangle){ 605, 220, 150, 25 }, "End Angle"       , TextFormat("%.2f", circleEndAngle)        , &circleEndAngle      , -360.0f, 360.0f);
            GuiSliderBar((Rectangle){ 605, 255, 150, 25 }, "Circle Segments" , TextFormat("%d"  , (int)circleSegments)   , &circleSegments      , -1     , 100);
            GuiSliderBar((Rectangle){ 605, 290, 150, 25 }, "Ring Radius"     , TextFormat("%.2f", ringInnerRadiusScale)  , &ringInnerRadiusScale, -1.0f  , 2.0f);
            GuiSliderBar((Rectangle){ 605, 325, 150, 25 }, "Poly Sides"      , TextFormat("%d"  , (int)polygonSides)     , &polygonSides        , -1     , 100);

        EndDrawing();
        //----------------------------------------------------------------------------------
    }

    // De-Initialization
    //--------------------------------------------------------------------------------------
    CloseWindow();        // Close window and OpenGL context
    //--------------------------------------------------------------------------------------

    return 0;
}

From raylib 6.2. The original on GitHub.