ProceduralMesh

SafiEngine::ProceduralMesh generates built-in 3D primitives (box, sphere, plane, cylinder, capsule) as Model objects without loading any external files.

Header: Core/include/Core/ProceduralMesh.h

PrimitiveType

enum class PrimitiveType { Box = 0, Sphere, Plane, Cylinder, Capsule, Count };
ValueDescription
BoxUnit cube centered at origin
SphereUV sphere
PlaneFlat quad on the XZ plane
CylinderCylinder along the Y axis
CapsuleCylinder with hemispherical caps
CountNumber of primitive types (not a valid primitive)

Factory Methods

Create

static std::shared_ptr<Model> Create(PrimitiveType type);

Creates a primitive mesh of the given type using default parameters. Returns a shared_ptr<Model> ready for rendering.

CreateBox

static std::shared_ptr<Model> CreateBox();

Creates a unit cube (1×1×1) centered at the origin.

CreateSphere

static std::shared_ptr<Model> CreateSphere(int segments = 32, int rings = 16);

Creates a UV sphere.

ParameterDefaultDescription
segments32Number of longitudinal subdivisions
rings16Number of latitudinal subdivisions

CreatePlane

static std::shared_ptr<Model> CreatePlane(int subdivX = 1, int subdivZ = 1);

Creates a flat quad on the XZ plane.

ParameterDefaultDescription
subdivX1Subdivisions along the X axis
subdivZ1Subdivisions along the Z axis

CreateCylinder

static std::shared_ptr<Model> CreateCylinder(int segments = 32);

Creates a cylinder along the Y axis.

ParameterDefaultDescription
segments32Number of radial subdivisions

CreateCapsule

static std::shared_ptr<Model> CreateCapsule(int segments = 32, int rings = 8);

Creates a cylinder with hemispherical caps.

ParameterDefaultDescription
segments32Number of radial subdivisions
rings8Number of subdivisions per hemisphere cap

Path Utilities

Procedural primitives use a primitive:<type> path convention (e.g. "primitive:box") so they can be referenced by the asset manager and serialized in scene files.

PrimitiveTypeToPath

static std::string PrimitiveTypeToPath(PrimitiveType type);

Converts a PrimitiveType to its path string (e.g. PrimitiveType::Box"primitive:box").

PathToPrimitiveType

static PrimitiveType PathToPrimitiveType(const std::string &path);

Converts a "primitive:<type>" path back to its PrimitiveType enum value.

IsPrimitivePath

static bool IsPrimitivePath(const std::string &path);

Returns true if the path starts with "primitive:".

PrimitiveTypeName

static const char *PrimitiveTypeName(PrimitiveType type);

Returns the human-readable name of a primitive type (e.g. "Box", "Sphere").

Usage Example

#include "Core/Components.h"
#include "Core/Engine.h"
#include "Core/ProceduralMesh.h"

// Create a box primitive via the asset manager
auto model = engine.GetAssetManager().Load<Model>("primitive:box");

world.entity("Box")
    .set(SafiEngine::Transform{})
    .set(SafiEngine::ModelRenderer{model, "primitive:box"});

// Or create directly with custom parameters
auto sphere = SafiEngine::ProceduralMesh::CreateSphere(64, 32);

world.entity("HiResSphere")
    .set(SafiEngine::Transform{.position = {2.0f, 0.0f, 0.0f}})
    .set(SafiEngine::ModelRenderer{sphere, "primitive:sphere"});
Tip

When using the asset manager's Load<Model> with a primitive:* path, the mesh is cached just like file-based models — multiple entities can share the same primitive without duplicating geometry.