← ziglang.inraylib-zigGitHub

point rendering

★★★☆by Reese Gallagher (@satchelfrost)

There is no browser build of this example yet.

Is it the same as C?

//! raylib [models] example - point rendering
//!
//! Zig-API translation of examples/models/models_point_rendering.c (raylib 6.2).
//! Example contributed by Reese Gallagher (@satchelfrost) and reviewed by Ramon Santamaria (@raysan5)
//! Example licensed under an unmodified zlib/libpng license.
//! Copyright (c) 2024-2025 Reese Gallagher (@satchelfrost)

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

const max_points = 10000000; // 10 million
const min_points = 1000; // 1 thousand

// libc PRNG, as in the C example (rand(), RAND_MAX on glibc)
extern "c" fn rand() c_int;
const rand_max: f32 = 2147483648.0; // (float)RAND_MAX: 2147483647 rounds to 2^31

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

    rl.initWindow(screen_width, screen_height, "raylib [models] example - point rendering");
    defer rl.closeWindow();

    var camera: rl.Camera = .{
        .position = .{ .x = 3.0, .y = 3.0, .z = 3.0 },
        .target = .{ .x = 0.0, .y = 0.0, .z = 0.0 },
        .up = .{ .x = 0.0, .y = 1.0, .z = 0.0 },
        .fovy = 45.0,
        .projection = .perspective,
    };

    const position: rl.Vector3 = .{ .x = 0.0, .y = 0.0, .z = 0.0 };
    var use_draw_model_points = true;
    var num_points_changed = false;
    var num_points: i32 = 1000;

    var mesh = try genMeshPoints(num_points);
    var model = try rl.loadModelFromMesh(mesh);
    defer rl.unloadModel(model);

    rl.setTargetFPS(60);

    // Main game loop
    while (!rl.windowShouldClose()) {
        // Update
        rl.updateCamera(&camera, .orbital);

        if (rl.isKeyPressed(.space)) use_draw_model_points = !use_draw_model_points;
        if (rl.isKeyPressed(.up)) {
            num_points = @min(num_points * 10, max_points);
            num_points_changed = true;
        }
        if (rl.isKeyPressed(.down)) {
            num_points = @max(@divTrunc(num_points, 10), min_points);
            num_points_changed = true;
        }

        // Upload a different point cloud size
        if (num_points_changed) {
            rl.unloadModel(model);
            mesh = try genMeshPoints(num_points);
            model = try rl.loadModelFromMesh(mesh);
            num_points_changed = false;
        }

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

        rl.clearBackground(.black);

        {
            rl.beginMode3D(camera);
            defer rl.endMode3D();

            // The new method only uploads the points once to the GPU
            if (use_draw_model_points) {
                drawModelPoints(model, position, 1.0, .white);
            } else {
                // The old method must continually draw the "points" (lines)
                const count: usize = @intCast(num_points);
                const vertices = mesh.vertices.?[0 .. count * 3];
                const colors = mesh.colors.?[0 .. count * 4];
                for (0..count) |i| {
                    const v = vertices[i * 3 ..][0..3];
                    const c = colors[i * 4 ..][0..4];
                    rl.drawPoint3D(.{ .x = v[0], .y = v[1], .z = v[2] }, .{ .r = c[0], .g = c[1], .b = c[2], .a = c[3] });
                }
            }

            // Draw a unit sphere for reference
            rl.drawSphereWires(position, 1.0, 10, 10, .yellow);
        }

        // Draw UI text
        rl.drawText(rl.textFormat("Point Count: {d}", .{num_points}), 10, screen_height - 50, 40, .white);
        rl.drawText("UP - Increase points", 10, 40, 20, .white);
        rl.drawText("DOWN - Decrease points", 10, 70, 20, .white);
        rl.drawText("SPACE - Drawing function", 10, 100, 20, .white);

        if (use_draw_model_points) {
            rl.drawText("Using: DrawModelPoints()", 10, 130, 20, .green);
        } else {
            rl.drawText("Using: DrawPoint3D()", 10, 130, 20, .red);
        }

        rl.drawFPS(10, 10);
    }
}

/// Generate a spherical point cloud
fn genMeshPoints(num_points: i32) !rl.Mesh {
    const count: usize = @intCast(num_points);
    const vertices: [*]f32 = @ptrCast(@alignCast(rl.memAlloc(@intCast(count * 3 * @sizeOf(f32))) orelse return error.OutOfMemory));
    const colors: [*]u8 = @ptrCast(rl.memAlloc(@intCast(count * 4)) orelse return error.OutOfMemory);

    var mesh = std.mem.zeroes(rl.Mesh);
    mesh.triangleCount = 1;
    mesh.vertexCount = num_points;
    mesh.vertices = vertices;
    mesh.colors = colors;

    // REF: https://en.wikipedia.org/wiki/Spherical_coordinate_system
    for (0..count) |i| {
        const theta = (rl.pi * randFloat()) / rand_max;
        const phi = (2.0 * rl.pi * randFloat()) / rand_max;
        const r = (10.0 * randFloat()) / rand_max;

        vertices[i * 3 ..][0..3].* = .{
            r * @sin(theta) * @cos(phi),
            r * @sin(theta) * @sin(phi),
            r * @cos(theta),
        };

        const color = rl.colorFromHSV(r * 360.0, 1.0, 1.0);
        colors[i * 4 ..][0..4].* = .{ color.r, color.g, color.b, color.a };
    }

    // Upload mesh data from CPU (RAM) to GPU (VRAM) memory
    rl.uploadMesh(&mesh, false);

    return mesh;
}

fn randFloat() f32 {
    return @floatFromInt(rand());
}

/// Draw a model as points
/// WARNING: OpenGL ES 2.0 does not support point mode drawing
fn drawModelPoints(model: rl.Model, position: rl.Vector3, scale: f32, tint: rl.Color) void {
    rl.gl.enablePointMode();
    rl.gl.disableBackfaceCulling();

    rl.drawModel(model, position, scale, tint);

    rl.gl.enableBackfaceCulling();
    rl.gl.disablePointMode();
}

/// Draw a model as points with extended parameters
/// WARNING: OpenGL ES 2.0 does not support point mode drawing
fn drawModelPointsEx(model: rl.Model, position: rl.Vector3, rotation_axis: rl.Vector3, rotation_angle: f32, scale: rl.Vector3, tint: rl.Color) void {
    rl.gl.enablePointMode();
    rl.gl.disableBackfaceCulling();

    rl.drawModelEx(model, position, rotation_axis, rotation_angle, scale, tint);

    rl.gl.enableBackfaceCulling();
    rl.gl.disablePointMode();
}
/*******************************************************************************************
*
*   raylib [models] example - point rendering
*
*   Example complexity rating: [★★★☆] 3/4
*
*   Example originally created with raylib 5.0, last time updated with raylib 5.0
*
*   Example contributed by Reese Gallagher (@satchelfrost) 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) 2024-2025 Reese Gallagher (@satchelfrost)
*
********************************************************************************************/

#include "raylib.h"
#include "rlgl.h"

#include <stdlib.h>             // Required for: rand()
#include <math.h>               // Required for: cosf(), sinf()

#define MAX_POINTS 10000000     // 10 million
#define MIN_POINTS 1000         // 1 thousand

//------------------------------------------------------------------------------------
// Module Functions Declaration
//------------------------------------------------------------------------------------
static Mesh GenMeshPoints(int numPoints); // Generate mesh using points
void DrawModelPoints(Model model, Vector3 position, float scale, Color tint); // Draw a model as points
void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint); // Draw a model as points with extended parameters

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

    InitWindow(screenWidth, screenHeight, "raylib [models] example - point rendering");

    Camera camera = {
        .position   = { 3.0f, 3.0f, 3.0f },
        .target     = { 0.0f, 0.0f, 0.0f },
        .up         = { 0.0f, 1.0f, 0.0f },
        .fovy       = 45.0f,
        .projection = CAMERA_PERSPECTIVE
    };

    Vector3 position = { 0.0f, 0.0f, 0.0f };
    bool useDrawModelPoints = true;
    bool numPointsChanged = false;
    int numPoints = 1000;

    Mesh mesh = GenMeshPoints(numPoints);
    Model model = LoadModelFromMesh(mesh);

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

    // Main game loop
    while (!WindowShouldClose())
    {
        // Update
        //----------------------------------------------------------------------------------
        UpdateCamera(&camera, CAMERA_ORBITAL);

        if (IsKeyPressed(KEY_SPACE)) useDrawModelPoints = !useDrawModelPoints;
        if (IsKeyPressed(KEY_UP))
        {
            numPoints = (numPoints*10 > MAX_POINTS)? MAX_POINTS : numPoints*10;
            numPointsChanged = true;
        }
        if (IsKeyPressed(KEY_DOWN))
        {
            numPoints = (numPoints/10 < MIN_POINTS)? MIN_POINTS : numPoints/10;
            numPointsChanged = true;
        }

        // Upload a different point cloud size
        if (numPointsChanged)
        {
            UnloadModel(model);
            mesh = GenMeshPoints(numPoints);
            model = LoadModelFromMesh(mesh);
            numPointsChanged = false;
        }
        //----------------------------------------------------------------------------------

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

            ClearBackground(BLACK);

            BeginMode3D(camera);
                // The new method only uploads the points once to the GPU
                if (useDrawModelPoints) DrawModelPoints(model, position, 1.0f, WHITE);
                else
                {
                    // The old method must continually draw the "points" (lines)
                    for (int i = 0; i < numPoints; i++)
                    {
                        Vector3 pos = {
                            .x = mesh.vertices[i*3 + 0],
                            .y = mesh.vertices[i*3 + 1],
                            .z = mesh.vertices[i*3 + 2],
                        };
                        Color color = {
                            .r = mesh.colors[i*4 + 0],
                            .g = mesh.colors[i*4 + 1],
                            .b = mesh.colors[i*4 + 2],
                            .a = mesh.colors[i*4 + 3],
                        };

                        DrawPoint3D(pos, color);
                    }
                }

                // Draw a unit sphere for reference
                DrawSphereWires(position, 1.0f, 10, 10, YELLOW);
            EndMode3D();

            // Draw UI text
            DrawText(TextFormat("Point Count: %d", numPoints), 10, screenHeight - 50, 40, WHITE);
            DrawText("UP - Increase points", 10, 40, 20, WHITE);
            DrawText("DOWN - Decrease points", 10, 70, 20, WHITE);
            DrawText("SPACE - Drawing function", 10, 100, 20, WHITE);

            if (useDrawModelPoints) DrawText("Using: DrawModelPoints()", 10, 130, 20, GREEN);
            else DrawText("Using: DrawPoint3D()", 10, 130, 20, RED);

            DrawFPS(10, 10);

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

    // De-Initialization
    //--------------------------------------------------------------------------------------
    UnloadModel(model);

    CloseWindow();
    //--------------------------------------------------------------------------------------
    return 0;
}

//------------------------------------------------------------------------------------
// Module Functions Definition
//------------------------------------------------------------------------------------
// Generate a spherical point cloud
static Mesh GenMeshPoints(int numPoints)
{
    Mesh mesh = {
        .triangleCount = 1,
        .vertexCount = numPoints,
        .vertices = (float *)MemAlloc(numPoints*3*sizeof(float)),
        .colors = (unsigned char*)MemAlloc(numPoints*4*sizeof(unsigned char)),
    };

    // REF: https://en.wikipedia.org/wiki/Spherical_coordinate_system
    for (int i = 0; i < numPoints; i++)
    {
        float theta = ((float)PI*rand())/((float)RAND_MAX);
        float phi = (2.0f*PI*rand())/((float)RAND_MAX);
        float r = (10.0f*rand())/((float)RAND_MAX);

        mesh.vertices[i*3 + 0] = r*sinf(theta)*cosf(phi);
        mesh.vertices[i*3 + 1] = r*sinf(theta)*sinf(phi);
        mesh.vertices[i*3 + 2] = r*cosf(theta);

        Color color = ColorFromHSV(r*360.0f, 1.0f, 1.0f);

        mesh.colors[i*4 + 0] = color.r;
        mesh.colors[i*4 + 1] = color.g;
        mesh.colors[i*4 + 2] = color.b;
        mesh.colors[i*4 + 3] = color.a;
    }

    // Upload mesh data from CPU (RAM) to GPU (VRAM) memory
    UploadMesh(&mesh, false);

    return mesh;
}


// Draw a model points
// WARNING: OpenGL ES 2.0 does not support point mode drawing
void DrawModelPoints(Model model, Vector3 position, float scale, Color tint)
{
    rlEnablePointMode();
    rlDisableBackfaceCulling();

    DrawModel(model, position, scale, tint);

    rlEnableBackfaceCulling();
    rlDisablePointMode();
}

// Draw a model points
// WARNING: OpenGL ES 2.0 does not support point mode drawing
void DrawModelPointsEx(Model model, Vector3 position, Vector3 rotationAxis, float rotationAngle, Vector3 scale, Color tint)
{
    rlEnablePointMode();
    rlDisableBackfaceCulling();

    DrawModelEx(model, position, rotationAxis, rotationAngle, scale, tint);

    rlEnableBackfaceCulling();
    rlDisablePointMode();
}

From raylib 6.2. The original on GitHub.