21 FEB 2026

rahulmnavneeth

vertex format

homedocs

Location

include/mop/vertex_format.h   — Public types and function declarations
src/core/vertex_format.c       — Standard format construction and query helpers

Overview

MopVertexFormat describes the layout of interleaved vertex data. It enables arbitrary per-vertex attributes (multiple UV sets, bone weights, tangent frames, custom float channels) without changing the fixed MopVertex struct used by existing code. Meshes created with mop_viewport_add_mesh use the implicit standard layout; meshes created with mop_viewport_add_mesh_ex can specify any custom format.

Types

MopAttribSemantic

typedef enum MopAttribSemantic {
    MOP_ATTRIB_POSITION  = 0,
    MOP_ATTRIB_NORMAL    = 1,
    MOP_ATTRIB_COLOR     = 2,
    MOP_ATTRIB_TEXCOORD0 = 3,
    MOP_ATTRIB_TEXCOORD1 = 4,
    MOP_ATTRIB_TANGENT   = 5,
    MOP_ATTRIB_JOINTS    = 6,
    MOP_ATTRIB_WEIGHTS   = 7,
    MOP_ATTRIB_CUSTOM0   = 8,
    MOP_ATTRIB_CUSTOM1   = 9,
    MOP_ATTRIB_CUSTOM2   = 10,
    MOP_ATTRIB_CUSTOM3   = 11,
    MOP_ATTRIB_COUNT     = 12
} MopAttribSemantic;
ValueIDTypical FormatDescription
MOP_ATTRIB_POSITION0float3Vertex position (required)
MOP_ATTRIB_NORMAL1float3Vertex normal direction
MOP_ATTRIB_COLOR2float4RGBA vertex color
MOP_ATTRIB_TEXCOORD03float2Primary UV coordinates
MOP_ATTRIB_TEXCOORD14float2Secondary UV set (lightmaps, etc.)
MOP_ATTRIB_TANGENT5float4Tangent vector (xyz) + handedness (w)
MOP_ATTRIB_JOINTS6ubyte4Bone indices for skeletal animation
MOP_ATTRIB_WEIGHTS7float4Bone weights (should sum to 1.0)
MOP_ATTRIB_CUSTOM08float4Application-defined channel 0
MOP_ATTRIB_CUSTOM19float4Application-defined channel 1
MOP_ATTRIB_CUSTOM210float4Application-defined channel 2
MOP_ATTRIB_CUSTOM311float4Application-defined channel 3
MOP_ATTRIB_COUNT12--Sentinel (total number of semantics)

MopAttribFormat

typedef enum MopAttribFormat {
    MOP_FORMAT_FLOAT  = 0,
    MOP_FORMAT_FLOAT2 = 1,
    MOP_FORMAT_FLOAT3 = 2,
    MOP_FORMAT_FLOAT4 = 3,
    MOP_FORMAT_UBYTE4 = 4,
} MopAttribFormat;
ValueByte SizeComponent CountDescription
MOP_FORMAT_FLOAT41Single 32-bit float
MOP_FORMAT_FLOAT282Two 32-bit floats
MOP_FORMAT_FLOAT3123Three 32-bit floats
MOP_FORMAT_FLOAT4164Four 32-bit floats
MOP_FORMAT_UBYTE444Four packed unsigned bytes

MopVertexAttrib

typedef struct MopVertexAttrib {
    MopAttribSemantic semantic;
    MopAttribFormat   format;
    uint32_t          offset;
} MopVertexAttrib;
FieldTypeDescription
semanticMopAttribSemanticWhat this attribute represents
formatMopAttribFormatData type and component count
offsetuint32_tByte offset of this attribute within one vertex

MopVertexFormat

#define MOP_MAX_VERTEX_ATTRIBS 12

typedef struct MopVertexFormat {
    MopVertexAttrib attribs[MOP_MAX_VERTEX_ATTRIBS];
    uint32_t        attrib_count;
    uint32_t        stride;
} MopVertexFormat;
FieldTypeDescription
attribsMopVertexAttrib[12]Array of attribute descriptors
attrib_countuint32_tNumber of active entries in attribs
strideuint32_tTotal bytes per vertex (distance between vertices)

Functions

mop_vertex_format_standard

MopVertexFormat mop_vertex_format_standard(void);

Returns the format that matches the fixed MopVertex struct layout:

IndexSemanticFormatOffsetSize
0POSITIONfloat3012 bytes
1NORMALfloat31212 bytes
2COLORfloat42416 bytes
3TEXCOORD0float2408 bytes

Total stride: 48 bytes, matching sizeof(MopVertex).

mop_vertex_format_find

const MopVertexAttrib *mop_vertex_format_find(const MopVertexFormat *fmt,
                                               MopAttribSemantic sem);

Searches for an attribute with the given semantic in the format. Returns a pointer to the matching MopVertexAttrib, or NULL if the semantic is not present or fmt is NULL. The search is linear over attrib_count entries.

mop_attrib_format_size

uint32_t mop_attrib_format_size(MopAttribFormat fmt);

Returns the byte size of a given attribute format. Returns 0 for unrecognized format values.

FormatReturns
MOP_FORMAT_FLOAT4
MOP_FORMAT_FLOAT28
MOP_FORMAT_FLOAT312
MOP_FORMAT_FLOAT416
MOP_FORMAT_UBYTE44

Standard MopVertex vs Flex Format

The standard MopVertex struct (position + normal + color + uv) is sufficient for most meshes. Use mop_viewport_add_mesh with MopMeshDesc for these cases -- the engine assumes the standard layout implicitly and no MopVertexFormat allocation is needed.

Use the flex format with mop_viewport_add_mesh_ex and MopMeshDescEx when a mesh requires attributes beyond the standard set:

When using flex format, the engine heap-allocates a copy of the MopVertexFormat and stores it on the mesh. This copy is freed automatically on mesh removal or viewport destruction.

Usage

/* Define a skinned vertex format */
MopVertexFormat skinned = {
    .attrib_count = 6,
    .stride       = 64,
    .attribs = {
        [0] = { MOP_ATTRIB_POSITION, MOP_FORMAT_FLOAT3,  0 },
        [1] = { MOP_ATTRIB_NORMAL,   MOP_FORMAT_FLOAT3, 12 },
        [2] = { MOP_ATTRIB_COLOR,    MOP_FORMAT_FLOAT4, 24 },
        [3] = { MOP_ATTRIB_TEXCOORD0,MOP_FORMAT_FLOAT2, 40 },
        [4] = { MOP_ATTRIB_JOINTS,   MOP_FORMAT_UBYTE4, 48 },
        [5] = { MOP_ATTRIB_WEIGHTS,  MOP_FORMAT_FLOAT4, 52 },
    }
};

/* Look up a specific attribute */
const MopVertexAttrib *weights = mop_vertex_format_find(&skinned,
                                                         MOP_ATTRIB_WEIGHTS);
if (weights) {
    uint32_t size = mop_attrib_format_size(weights->format); /* 16 */
}