Code:
/* create and populate an attribute buffer (example using convenience set data command) */
ngl3Buffer* buffer = ngl3BufferCreate(ctx, sizeof(Vertex) * nVertices, NGL_BUFFER_STREAM, NGL_BUFFER_WRITE);
ngl3BufferSetData(buffer, aVertices, sizeof(Vertex) * nVertices);
/* create and populate an index buffer (example using explicit lock, copy, unlock commands) */
ngl3Buffer* indices = ngl3BufferCreate(ctx, sizeof(uint16_t) * nIndices, NGL_BUFFER_STREAM, NGL_BUFFER_WRITE);
map = ngl3BufferLock(indices, NGL_BUFFER_WRITE);
memcpy(map, aIndices, sizeof(uint16_t) * nIndices);
ngl2BufferRelease(indices, map);
/* create and popular a constant buffer */
ngl3Buffer* constants = ngl3BufferCreate(ctx, sizeof(float) * 16, NGL_BUFFER_ONEFRAME, NGL_BUFFER_WRITE);
ngl3BufferSetData(buffer, gProjectionMatrix, sizeof(float) * 16);
/* define an attribute layout */
ngl3Layout* layout = ngl3LayoutCreate(ctx, 3);
ngl3LayoutAddSemantic(layout, NGL_FLOAT3, "POS0", buffer);
ngl3LayoutAddSemantic(layout, NGL_FLOAT3, "COLOR0", buffer);
ngl3LayoutAddSemantic(layout, NGL_FLOAT2, "TEXCOORD0", buffer);
/* define a constant buffer layout */
ngl3Layout* clayout = ngl3LayoutCreate(ctx, 1);
ngl3LayoutAddSlot(clayout, NGL_FLOAT4x4, 0, constants);
/* define a render target */
ngl3Target* target = ngl3TargetCreate(ctx);
ngl3TargetSetDefaultFramebuffer(target);
ngl3TargetSetDefaultDepthbuffer(target);
/* load shaders (use low-level API -- you should have a standard higher-level effects/technique API as well!) */
ngl3Program* program = ngl3ProgramCreate();
ngl3ProgramLoadFile(program, "foo.vs", NGL_VERTEX_3_0);
ngl3ProgramLoadFile(program, "foo.gs", NGL_GEOMETRY_3_0);
ngl3ProgramLoadFile(program, "foo.fs", NGL_FRAGMENT_3_0);
/* render primitives */
ngl3Render* cmd = ngl3RenderCreate(ctx);
ngl3RenderSetTarget(cmd, target);
ngl3RenderSetConstants(cmd, constants);
ngl3RenderSetAttributes(cmd, layout);
ngl3RenderSetIndices(cmd, indices, nIndices);
ngl3RenderSetProgram(cmd, program);
ngl3RenderSetType(cmd, NGL_TRIANGLES);
ngl3RenderExecute(cmd);
The objects can be reused as much as possible. They're typed, so none of that OpenGL numeric identifier what-was-this-object-again bullshit. Objects that make sense to be write-only are write-only (like layouts). Those small objects that you may create a lot of are just backed by a simple pool allocator.