← ziglang.inraylib-zigGitHub

mesh generation

★★☆☆by Ramon Santamaria (@raysan5)

There is no browser build of this example yet.

Is it the same as C?

//! raylib [models] example - mesh generation
//!
//! Zig-API translation of examples/models/models_mesh_generation.c (raylib 6.2).
//! Example licensed under an unmodified zlib/libpng license.
//! Copyright (c) 2017-2025 Ramon Santamaria (@raysan5)

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

/// Parametric 3d shape names, and where to draw them, by model index.
const labels = [_]struct { text: [:0]const u8, x: i32 }{
    .{ .text = "PLANE", .x = 680 },
    .{ .text = "CUBE", .x = 680 },
    .{ .text = "SPHERE", .x = 680 },
    .{ .text = "HEMISPHERE", .x = 640 },
    .{ .text = "CYLINDER", .x = 680 },
    .{ .text = "TORUS", .x = 680 },
    .{ .text = "KNOT", .x = 680 },
    .{ .text = "POLY", .x = 680 },
    .{ .text = "Custom (triangle)", .x = 580 },
};
const num_models = labels.len; // Parametric 3d shapes to generate

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

    rl.initWindow(screen_width, screen_height, "raylib [models] example - mesh generation");
    defer rl.closeWindow(); // Close window and OpenGL context

    // We generate a checked image for texturing
    const checked = rl.genImageChecked(2, 2, 1, 1, .red, .green);
    const texture = try rl.loadTextureFromImage(checked);
    defer rl.unloadTexture(texture);
    rl.unloadImage(checked);

    const models = [num_models]rl.Model{
        try rl.loadModelFromMesh(rl.genMeshPlane(2, 2, 4, 3)),
        try rl.loadModelFromMesh(rl.genMeshCube(2.0, 1.0, 2.0)),
        try rl.loadModelFromMesh(rl.genMeshSphere(2, 32, 32)),
        try rl.loadModelFromMesh(rl.genMeshHemiSphere(2, 16, 16)),
        try rl.loadModelFromMesh(rl.genMeshCylinder(1, 2, 16)),
        try rl.loadModelFromMesh(rl.genMeshTorus(0.25, 4.0, 16, 32)),
        try rl.loadModelFromMesh(rl.genMeshKnot(1.0, 2.0, 16, 128)),
        try rl.loadModelFromMesh(rl.genMeshPoly(5, 2.0)),
        try rl.loadModelFromMesh(try genMeshCustom()),
    };
    // Unload models data (GPU VRAM)
    defer for (models) |model| rl.unloadModel(model);

    // NOTE: Generated meshes could be exported using exportMesh()

    // Set checked texture as default diffuse component for all models material
    for (models) |model| model.materials.?[0].map(.diffuse).texture = texture;

    // Define the camera to look into our 3d world
    var camera: rl.Camera = .{
        .position = .{ .x = 5.0, .y = 5.0, .z = 5.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,
    };

    // Model drawing position
    const position: rl.Vector3 = .{ .x = 0.0, .y = 0.0, .z = 0.0 };

    var current_model: usize = 0;

    rl.setTargetFPS(60); // Set our game to run at 60 frames-per-second

    // Main game loop
    while (!rl.windowShouldClose()) { // Detect window close button or ESC key
        // Update
        rl.updateCamera(&camera, .orbital);

        if (rl.isMouseButtonPressed(.left)) {
            current_model = (current_model + 1) % num_models; // Cycle between the textures
        }

        if (rl.isKeyPressed(.right)) {
            current_model = (current_model + 1) % num_models;
        } else if (rl.isKeyPressed(.left)) {
            current_model = if (current_model == 0) num_models - 1 else current_model - 1;
        }

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

        rl.clearBackground(.ray_white);

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

            rl.drawModel(models[current_model], position, 1.0, .white);
            rl.drawGrid(10, 1.0);
        }

        rl.drawRectangle(30, 400, 310, 30, rl.fade(.sky_blue, 0.5));
        rl.drawRectangleLines(30, 400, 310, 30, rl.fade(.dark_blue, 0.5));
        rl.drawText("MOUSE LEFT BUTTON to CYCLE PROCEDURAL MODELS", 40, 410, 10, .blue);

        const label = labels[current_model];
        rl.drawText(label.text, label.x, 10, 20, .dark_blue);
    }
}

/// Generate a simple triangle mesh from code
fn genMeshCustom() !rl.Mesh {
    // Vertex data is owned by the mesh (freed by unloadModel), so it comes from raylib's allocator
    const allocator = rl.mem_allocator;

    const vertices = try allocator.alloc(f32, 3 * 3); // 3 vertices, 3 coordinates each (x, y, z)
    const texcoords = try allocator.alloc(f32, 3 * 2); // 3 vertices, 2 coordinates each (x, y)
    const normals = try allocator.alloc(f32, 3 * 3); // 3 vertices, 3 coordinates each (x, y, z)

    vertices[0..9].* = .{
        0, 0, 0, // Vertex at (0, 0, 0)
        1, 0, 2, // Vertex at (1, 0, 2)
        2, 0, 0, // Vertex at (2, 0, 0)
    };
    normals[0..9].* = .{
        0, 1, 0,
        0, 1, 0,
        0, 1, 0,
    };
    texcoords[0..6].* = .{
        0,   0,
        0.5, 1.0,
        1,   0,
    };

    var mesh = std.mem.zeroes(rl.Mesh);
    mesh.triangleCount = 1;
    mesh.vertexCount = mesh.triangleCount * 3;
    mesh.vertices = vertices.ptr;
    mesh.texcoords = texcoords.ptr;
    mesh.normals = normals.ptr;

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

    return mesh;
}
/*******************************************************************************************
*
*   raylib [models] example - mesh generation
*
*   Example complexity rating: [★★☆☆] 2/4
*
*   Example originally created with raylib 1.8, last time updated with raylib 4.0
*
*   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) 2017-2025 Ramon Santamaria (@raysan5)
*
********************************************************************************************/

#include "raylib.h"

#define NUM_MODELS  9               // Parametric 3d shapes to generate

//------------------------------------------------------------------------------------
// Module Functions Declaration
//------------------------------------------------------------------------------------
static Mesh GenMeshCustom(void);    // Generate a simple triangle mesh from code

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

    InitWindow(screenWidth, screenHeight, "raylib [models] example - mesh generation");

    // We generate a checked image for texturing
    Image checked = GenImageChecked(2, 2, 1, 1, RED, GREEN);
    Texture2D texture = LoadTextureFromImage(checked);
    UnloadImage(checked);

    Model models[NUM_MODELS] = { 0 };

    models[0] = LoadModelFromMesh(GenMeshPlane(2, 2, 4, 3));
    models[1] = LoadModelFromMesh(GenMeshCube(2.0f, 1.0f, 2.0f));
    models[2] = LoadModelFromMesh(GenMeshSphere(2, 32, 32));
    models[3] = LoadModelFromMesh(GenMeshHemiSphere(2, 16, 16));
    models[4] = LoadModelFromMesh(GenMeshCylinder(1, 2, 16));
    models[5] = LoadModelFromMesh(GenMeshTorus(0.25f, 4.0f, 16, 32));
    models[6] = LoadModelFromMesh(GenMeshKnot(1.0f, 2.0f, 16, 128));
    models[7] = LoadModelFromMesh(GenMeshPoly(5, 2.0f));
    models[8] = LoadModelFromMesh(GenMeshCustom());

    // NOTE: Generated meshes could be exported using ExportMesh()

    // Set checked texture as default diffuse component for all models material
    for (int i = 0; i < NUM_MODELS; i++) models[i].materials[0].maps[MATERIAL_MAP_DIFFUSE].texture = texture;

    // Define the camera to look into our 3d world
    Camera camera = { { 5.0f, 5.0f, 5.0f }, { 0.0f, 0.0f, 0.0f }, { 0.0f, 1.0f, 0.0f }, 45.0f, 0 };

    // Model drawing position
    Vector3 position = { 0.0f, 0.0f, 0.0f };

    int currentModel = 0;

    SetTargetFPS(60);               // Set our game to run at 60 frames-per-second
    //--------------------------------------------------------------------------------------

    // Main game loop
    while (!WindowShouldClose())    // Detect window close button or ESC key
    {
        // Update
        //----------------------------------------------------------------------------------
        UpdateCamera(&camera, CAMERA_ORBITAL);

        if (IsMouseButtonPressed(MOUSE_BUTTON_LEFT))
        {
            currentModel = (currentModel + 1)%NUM_MODELS; // Cycle between the textures
        }

        if (IsKeyPressed(KEY_RIGHT))
        {
            currentModel++;
            if (currentModel >= NUM_MODELS) currentModel = 0;
        }
        else if (IsKeyPressed(KEY_LEFT))
        {
            currentModel--;
            if (currentModel < 0) currentModel = NUM_MODELS - 1;
        }
        //----------------------------------------------------------------------------------

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

            ClearBackground(RAYWHITE);

            BeginMode3D(camera);

               DrawModel(models[currentModel], position, 1.0f, WHITE);
               DrawGrid(10, 1.0);

            EndMode3D();

            DrawRectangle(30, 400, 310, 30, Fade(SKYBLUE, 0.5f));
            DrawRectangleLines(30, 400, 310, 30, Fade(DARKBLUE, 0.5f));
            DrawText("MOUSE LEFT BUTTON to CYCLE PROCEDURAL MODELS", 40, 410, 10, BLUE);

            switch (currentModel)
            {
                case 0: DrawText("PLANE", 680, 10, 20, DARKBLUE); break;
                case 1: DrawText("CUBE", 680, 10, 20, DARKBLUE); break;
                case 2: DrawText("SPHERE", 680, 10, 20, DARKBLUE); break;
                case 3: DrawText("HEMISPHERE", 640, 10, 20, DARKBLUE); break;
                case 4: DrawText("CYLINDER", 680, 10, 20, DARKBLUE); break;
                case 5: DrawText("TORUS", 680, 10, 20, DARKBLUE); break;
                case 6: DrawText("KNOT", 680, 10, 20, DARKBLUE); break;
                case 7: DrawText("POLY", 680, 10, 20, DARKBLUE); break;
                case 8: DrawText("Custom (triangle)", 580, 10, 20, DARKBLUE); break;
                default: break;
            }

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

    // De-Initialization
    //--------------------------------------------------------------------------------------
    UnloadTexture(texture); // Unload texture

    // Unload models data (GPU VRAM)
    for (int i = 0; i < NUM_MODELS; i++) UnloadModel(models[i]);

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

    return 0;
}

//------------------------------------------------------------------------------------
// Module Functions Definition
//------------------------------------------------------------------------------------
// Generate a simple triangle mesh from code
static Mesh GenMeshCustom(void)
{
    Mesh mesh = { 0 };
    mesh.triangleCount = 1;
    mesh.vertexCount = mesh.triangleCount*3;
    mesh.vertices = (float *)MemAlloc(mesh.vertexCount*3*sizeof(float));    // 3 vertices, 3 coordinates each (x, y, z)
    mesh.texcoords = (float *)MemAlloc(mesh.vertexCount*2*sizeof(float));   // 3 vertices, 2 coordinates each (x, y)
    mesh.normals = (float *)MemAlloc(mesh.vertexCount*3*sizeof(float));     // 3 vertices, 3 coordinates each (x, y, z)

    // Vertex at (0, 0, 0)
    mesh.vertices[0] = 0;
    mesh.vertices[1] = 0;
    mesh.vertices[2] = 0;
    mesh.normals[0] = 0;
    mesh.normals[1] = 1;
    mesh.normals[2] = 0;
    mesh.texcoords[0] = 0;
    mesh.texcoords[1] = 0;

    // Vertex at (1, 0, 2)
    mesh.vertices[3] = 1;
    mesh.vertices[4] = 0;
    mesh.vertices[5] = 2;
    mesh.normals[3] = 0;
    mesh.normals[4] = 1;
    mesh.normals[5] = 0;
    mesh.texcoords[2] = 0.5f;
    mesh.texcoords[3] = 1.0f;

    // Vertex at (2, 0, 0)
    mesh.vertices[6] = 2;
    mesh.vertices[7] = 0;
    mesh.vertices[8] = 0;
    mesh.normals[6] = 0;
    mesh.normals[7] = 1;
    mesh.normals[8] = 0;
    mesh.texcoords[4] = 1;
    mesh.texcoords[5] =0;

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

    return mesh;
}

From raylib 6.2. The original on GitHub.