Example 1 — minimal headless mesh render
This pattern establishes the ownership order and keeps the renderer separate from geometry creation.
#include "native_3d_engine_api_v1.h"
#include <stdio.h>
#define GX(call) do { gx3de_result r_=(call); if(r_!=GX3DE_OK) { fprintf(stderr, "%s: %s\n", #call, gx3de_result_name(r_)); return 1; } } while(0)
int main(void) {
gx3de_engine *engine = NULL;
gx3de_scene *scene = NULL;
gx3de_view *view = NULL;
gx3de_target *target = NULL;
gx3de_viewport *viewport = NULL;
GX(gx3de_engine_create(&engine));
GX(gx3de_scene_create(engine, &scene));
gx3de_vec3 v[4] = {{0,0,0},{1,0,0},{0,1,0},{0,0,1}};
uint32_t t[12] = {0,2,1, 0,1,3, 1,2,3, 2,0,3};
gx3de_object *mesh = NULL;
GX(gx3de_object_create_mesh(scene, v, 4, t, 4, &mesh));
GX(gx3de_view_create(scene, &view));
GX(gx3de_view_camera_preset(view, GX3DE_CAMERA_FIT_SCENE, NULL));
GX(gx3de_target_create_headless(engine, 800, 600, &target));
GX(gx3de_viewport_create(target, view, 0, 0, 800, 600, &viewport));
GX(gx3de_target_render(target));
GX(gx3de_target_write_png(target, "tetrahedron.png"));
gx3de_target_destroy(target);
gx3de_scene_destroy(scene);
gx3de_engine_destroy(engine);
return 0;
}
Example 2 — dev-40 sampled scientific density
Use one scientific polydata object with arrays for scalar, radius, opacity and direct RGBA. The renderer derives presentation data without altering the source arrays.
#include "native_3d_engine_api_v1.h"
/* points[], density[], radius[], opacity[], rgba[] are caller arrays */
gx3de_scientific_array_input a[4] = {0};
for (int i=0; i<4; ++i) {
a[i].struct_size = sizeof a[i];
a[i].association = GX3DE_SCI_ASSOC_POINT;
a[i].tuple_count = point_count;
}
a[0].components=1; a[0].name_utf8="density"; a[0].values=density;
a[1].components=1; a[1].name_utf8="radius"; a[1].values=radius;
a[2].components=1; a[2].name_utf8="opacity"; a[2].values=opacity;
a[3].components=4; a[3].name_utf8="rgba"; a[3].values=rgba;
gx3de_scientific_polydata_spec spec = {
.struct_size=sizeof spec, .points=points, .point_count=point_count,
.arrays=a, .array_count=4
};
gx3de_object *cloud = NULL;
gx3de_scientific_create_polydata(scene, &spec, &cloud);
gx3de_scientific_field_roles roles = {
.struct_size=sizeof roles, .scalar_array=0, .vector_array=-1, .radius_array=1
};
gx3de_scientific_field_roles_set(cloud, &roles);
gx3de_scientific_presentation pr = {.struct_size=sizeof pr};
gx3de_scientific_presentation_get(cloud, &pr);
pr.sphere_glyphs = 1;
gx3de_scientific_presentation_set(cloud, &pr);
gx3de_scientific_opacity_array_set(cloud, 2);
gx3de_scientific_color_array_set(cloud, 3); /* direct RGBA, dev-40 */
Example 3 — explicit particle cloud and positional lamp
gx3de_particle p[2] = {
{.position={-1,0,0}, .radius=.20, .color={1,.2,.1},
.flags=GX3DE_PARTICLE_RADIUS|GX3DE_PARTICLE_COLOR},
{.position={ 1,0,0}} /* uses global style */
};
gx3de_particle_cloud_style style = {
.struct_size=sizeof style, .radius=.12, .color={.3,.7,1}, .opacity=1
};
gx3de_particle_cloud *cloud = NULL;
gx3de_particle_cloud_create(scene, &style, p, 2, &cloud);
gx3de_positional_light lamp = {
.struct_size=sizeof lamp, .enabled=1, .position={3,-3,4},
.color={1,1,1}, .intensity=2.0,
.attenuation_constant=1, .attenuation_linear=.025,
.attenuation_quadratic=.007
};
/* slot must be below view_lighting.light_count */
gx3de_view_positional_light_set(view, 0, &lamp);
Shadow caveat
The positional lamp currently shades geometry but does not generate a visible cast-shadow map on the Linux VTK path because the public lamp maps to a 180° positional light. Use a directional light when the current backend must demonstrate cast shadows.
Example 4 — picking to a stable anchor
gx3de_pick_hit hit = {.struct_size=sizeof hit};
gx3de_result r = gx3de_viewport_pick(viewport, mouse_x, mouse_y, &hit);
if (r == GX3DE_OK) {
gx3de_anchor *anchor = NULL;
if (gx3de_pick_make_anchor(viewport, &hit, &anchor) == GX3DE_OK) {
gx3de_view_set_selection(view, anchor);
/* anchor is now scene-owned; it can drive marker/measurement/gizmo state */
}
}
Example 5 — vector field lines
#include "native_3d_field_api_v1.h"
gx3de_vec3 seeds[2] = {{0,0,0},{0,1,0}};
gx3de_field_line_spec s = {
.struct_size=sizeof s,
.seed_kind=GX3DE_FIELD_SEED_POINTS,
.field=image_object,
.vector_array=vector_array_index,
.scalar_array=-1,
.seed_points=seeds, .seed_count=2,
.direction=GX3DE_FIELD_BOTH,
.step_size=.05, .min_vector_magnitude=1e-9,
.max_steps_per_direction=2000,
.max_output_points=200000,
.max_memory_bytes=128ull*1024*1024
};
gx3de_object *lines = NULL;
gx3de_field_line_info info = {.struct_size=sizeof info};
gx3de_field_lines_create(scene, &s, &lines, &info);
Example 6 — deterministic animation frame rendering
#include "native_3d_animation_api_v1.h"
gx3de_animation *timeline = NULL;
gx3de_animation_create(scene, "s", &timeline);
uint64_t f0, f1;
gx3de_animation_frame_add(timeline, 0.0, frame0, NULL, NULL, &f0);
gx3de_animation_frame_add(timeline, 1.0, frame1, NULL, NULL, &f1);
gx3de_animation_mode_set(timeline, GX3DE_ANIM_NEAREST, GX3DE_ANIM_LOOP, 1.0);
gx3de_animation_render_frame_png(timeline, view, 0, 1280, 720, "frame0.png");
gx3de_animation_destroy(timeline);
Two-pass query pattern
uint64_t required = 0;
gx3de_result r = gx3de_curved_texture_seams_get(tex, NULL, 0, &required);
if (r == GX3DE_RANGE && required) {
gx3de_segment3 *s = calloc((size_t)required, sizeof *s);
if (s && gx3de_curved_texture_seams_get(tex, s, required, &required) == GX3DE_OK) {
/* consume exactly required segments */
}
free(s);
}
Error discipline
Do not treat every non-OK status as a generic crash. GX3DE_RANGE is also used for capacity discovery/budgets; NOT_FOUND can represent an empty geometric result or no pick; UNSUPPORTED often means CORE deliberately refused an unsafe or unvalidated combination. Renderer failures should be augmented with the target diagnostic string.