Mesh Instance Selection¶
This example queries and selects individual instances of one mesh visual.
Preview¶
Run And Adapt¶
Commands below assume a Datoviz source checkout and start at the repository root. Use your configured build environment; Python routes additionally require local bindings.
| Route | Availability | Command or action |
|---|---|---|
| C | Canonical native source | just example-c features/selection_mesh_instances (build and run), or rerun ./build/examples/c/features/selection_mesh_instances |
| Python | Available; direct-engine adaptation | python3 -m examples.python.gallery.features.selection_mesh_instances |
| Browser | Live WebGPU route | Open live example |
This example is approved as a starting point for user code and coding agents. Keep the object lifetimes and data shapes intact while adapting the data and styling.
What To Look For¶
A single cube geometry is reused with an instance_transform array for a 6x4x2 field of differently placed, scaled, and rotated cubes. Move the cursor over the live 3D panel to query the frontmost mesh instance; hover scales the item, click toggles a persistent warning-color tint, and clicking the background clears selection. Drag with the arcball controller to confirm selection follows the instanced mesh in 3D.
Source¶
#!/usr/bin/env python3
"""Instanced mesh item selection with hover and click feedback."""
from __future__ import annotations
import ctypes
import math
import numpy as np
import datoviz as dvz
from examples.python.gallery import common as ex
GRID_X = 6
GRID_Y = 4
GRID_Z = 2
INSTANCE_COUNT = GRID_X * GRID_Y * GRID_Z
QUERY_HOVER_ID = 23
QUERY_CLICK_ID = 24
TAU = 2.0 * math.pi
def _cube_transform(tx, ty, tz, scale, angle_x, angle_z, angle_y):
cx = math.cos(angle_x)
sx = math.sin(angle_x)
cz = math.cos(angle_z)
sz = math.sin(angle_z)
cy = math.cos(angle_y)
sy = math.sin(angle_y)
return np.array(
[
[scale * cz * cy, scale * (cz * sy * sx - sz * cx), scale * (cz * sy * cx + sz * sx), tx],
[scale * sz * cy, scale * (sz * sy * sx + cz * cx), scale * (sz * sy * cx - cz * sx), ty],
[scale * -sy, scale * cy * sx, scale * cy * cx, tz],
[0.0, 0.0, 0.0, 1.0],
],
dtype=np.float32,
).T
def _cube_transforms():
transforms = np.zeros((INSTANCE_COUNT, 4, 4), dtype=np.float32)
spacing = 0.50
half_x = 0.5 * (GRID_X - 1)
half_y = 0.5 * (GRID_Y - 1)
half_z = 0.5 * (GRID_Z - 1)
idx = 0
for z in range(GRID_Z):
for y in range(GRID_Y):
for x in range(GRID_X):
fx = (x - half_x) * spacing + 0.035 * math.sin(1.70 * x + 0.90 * y)
fy = (y - half_y) * spacing + 0.030 * math.cos(1.10 * y + 0.80 * z)
fz = (z - half_z) * spacing + 0.045 * math.sin(0.80 * x - 1.15 * y)
wave = 0.5 + 0.5 * math.sin(TAU * (x / GRID_X + z * 0.11))
scale = 0.62 + 0.30 * wave
angle_x = 0.22 * math.sin(0.95 * x + 1.55 * y + 0.70 * z)
angle_z = 0.10 * x + 0.17 * y
angle_y = 0.24 * z - 0.06 * y + 0.14 * math.cos(1.20 * x + 0.50 * y)
transforms[idx] = _cube_transform(fx, fy, fz, scale, angle_x, angle_z, angle_y)
idx += 1
return transforms
def _selection_cube_mesh(scene):
mesh = dvz.dvz_mesh(scene, 0)
if not mesh:
raise RuntimeError("dvz_mesh() failed")
face_colors = (dvz.DvzColor * 6)(
dvz.DvzColor(76, 201, 240, 255),
dvz.DvzColor(38, 132, 167, 255),
dvz.DvzColor(128, 255, 219, 255),
dvz.DvzColor(42, 176, 142, 255),
dvz.DvzColor(132, 142, 239, 255),
dvz.DvzColor(176, 112, 221, 255),
)
desc = dvz.dvz_geometry_cube_desc()
desc.size = 0.32
desc.face_colors = face_colors
desc.face_color_count = len(face_colors)
geometry = dvz.dvz_geometry_cube(ctypes.byref(desc))
if not geometry:
raise RuntimeError("dvz_geometry_cube() failed")
try:
if dvz.dvz_mesh_set_geometry(mesh, geometry) != 0:
raise RuntimeError("dvz_mesh_set_geometry() failed")
finally:
dvz.dvz_geometry_destroy(geometry)
dvz.dvz_visual_set_query_capabilities(mesh, dvz.DVZ_QUERY_CAPABILITY_ITEM)
transforms = _cube_transforms()
if dvz.dvz_visual_set_data(mesh, b"instance_transform", transforms) != 0:
raise RuntimeError("dvz_visual_set_data(instance_transform) failed")
return mesh
def _handle_hover(state, query) -> None:
if not state["cursor_valid"]:
return
if ex.query_item_hit(query, dvz.DVZ_SCENE_VISUAL_FAMILY_MESH, INSTANCE_COUNT):
latest = state["latest_hover_query"]
same_item = (
latest is not None
and latest.visual_id == query.visual_id
and latest.resolved_id == query.resolved_id
)
if not same_item:
if dvz.dvz_hover_apply_query(state["hover"], query) != 0:
raise RuntimeError("dvz_hover_apply_query() failed")
print(f"hover mesh instance id={query.resolved_id}")
state["latest_hover_query"] = query
state["has_hover_query"] = True
else:
if state["has_hover_query"]:
dvz.dvz_hover_clear(state["hover"])
state["latest_hover_query"] = None
state["has_hover_query"] = False
def _handle_click(state, query) -> None:
if ex.query_item_hit(query, dvz.DVZ_SCENE_VISUAL_FAMILY_MESH, INSTANCE_COUNT):
if dvz.dvz_selection_apply_query(state["selection"], query) != 0:
raise RuntimeError("dvz_selection_apply_query() failed")
print(f"toggle mesh instance id={query.resolved_id}")
else:
dvz.dvz_selection_clear(state["selection"])
def main() -> None:
scene, figure, panel = ex.scene_panel()
ex.manual_camera(panel)
mesh = _selection_cube_mesh(scene)
ex.add_visual(panel, mesh)
selection = ex.create_item_selection(scene)
hover = ex.create_item_hover(scene, 1.24)
state = {
"selection": selection,
"hover": hover,
"cursor_valid": False,
"has_hover_query": False,
"latest_hover_query": None,
}
def configure_view(view) -> None:
arcball = dvz.dvz_view_arcball(view, panel, None)
if not arcball:
raise RuntimeError("dvz_view_arcball() failed")
def on_pointer(event) -> None:
if event.type not in (
dvz.DVZ_POINTER_EVENT_MOVE,
dvz.DVZ_POINTER_EVENT_PRESS,
dvz.DVZ_POINTER_EVENT_CLICK,
):
return
panel_pos = ex.figure_to_panel_px(panel, event.pos[0], event.pos[1])
state["cursor_valid"] = panel_pos is not None
if panel_pos is None:
if state["has_hover_query"]:
dvz.dvz_hover_clear(hover)
state["has_hover_query"] = False
if event.type in (dvz.DVZ_POINTER_EVENT_PRESS, dvz.DVZ_POINTER_EVENT_CLICK):
dvz.dvz_selection_clear(selection)
return
request_id = QUERY_HOVER_ID if event.type == dvz.DVZ_POINTER_EVENT_MOVE else QUERY_CLICK_ID
if request_id == QUERY_CLICK_ID and event.button != dvz.DVZ_POINTER_BUTTON_LEFT:
return
ex.queue_panel_query(
panel,
panel_pos[0],
panel_pos[1],
request_id,
dvz.DVZ_SCENE_TARGET_ITEM,
hit_policy=dvz.DVZ_QUERY_HIT_FRONTMOST,
)
def on_frame(_view, _frame_index: int, _elapsed: float) -> None:
for query in ex.poll_queries(scene):
if query.request_id == QUERY_CLICK_ID:
_handle_click(state, query)
elif query.request_id == QUERY_HOVER_ID:
_handle_hover(state, query)
ex.run_with_input_callbacks(
scene,
figure,
"Mesh Instance Selection",
on_pointer=on_pointer,
on_frame=on_frame,
configure_view=configure_view,
)
if __name__ == "__main__":
main()
/*
* Copyright (c) 2021 Cyrille Rossant and contributors. All rights reserved.
* Licensed under the MIT license. See LICENSE file in the project root for details.
* SPDX-License-Identifier: MIT
*/
/* This example queries and selects individual instances of one retained mesh visual.
*
* What to look for: a single cube geometry is reused with an instance_transform array for a
* 6x4x2 field of differently placed, scaled, and rotated cubes. Move the cursor over the live 3D
* panel to query the frontmost mesh instance; hover scales the item, click toggles a persistent
* warning-color tint, and clicking the background clears selection. Drag with the arcball
* controller to confirm selection follows the instanced mesh in 3D.
*
* Scenario: features_selection_mesh_instances
* Style: features, graphite_cyan, 1280x720 window target
*
* Build: just example-c features/selection_mesh_instances
* Run: ./build/examples/c/features/selection_mesh_instances --live
* Smoke: ./build/examples/c/features/selection_mesh_instances --png
*/
/*************************************************************************************************/
/* Includes */
/*************************************************************************************************/
#include <inttypes.h>
#include <math.h>
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include "_alloc.h"
#include "datoviz/geom.h"
#include "datoviz/scene.h"
#include "example_common.h"
#include "example_style.h"
#include "runner/scenario_runner.h"
/*************************************************************************************************/
/* Constants */
/*************************************************************************************************/
#define WIDTH EXAMPLE_WINDOW_WIDTH
#define HEIGHT EXAMPLE_WINDOW_HEIGHT
#define GRID_X 6u
#define GRID_Y 4u
#define GRID_Z 2u
#define INSTANCE_COUNT (GRID_X * GRID_Y * GRID_Z)
#define QUERY_HOVER_ID 23u
#define QUERY_CLICK_ID 24u
static const float TAU = 6.28318530718f;
/*************************************************************************************************/
/* Forward declarations */
/*************************************************************************************************/
DvzScenarioSpec dvz_example_selection_mesh_instances_scenario(void);
/*************************************************************************************************/
/* Structs */
/*************************************************************************************************/
typedef struct MeshInstanceSelectionState
{
DvzScene* scene;
DvzPanel* panel;
DvzSelection* selection;
DvzHover* hover;
float (*transforms)[16];
DvzQueryResult latest_hover_query;
bool has_hover_query;
bool cursor_valid;
} MeshInstanceSelectionState;
/*************************************************************************************************/
/* Helpers */
/*************************************************************************************************/
/**
* Fill one column-major rotation/scale/translation transform.
*
* @param transform output mat4 storage
* @param tx translation on X
* @param ty translation on Y
* @param tz translation on Z
* @param scale uniform scale
* @param angle_x rotation around X in radians
* @param angle_z rotation around Z in radians
* @param angle_y rotation around Y in radians
*/
static void _cube_transform(
float transform[16],
float tx,
float ty,
float tz,
float scale,
float angle_x,
float angle_z,
float angle_y)
{
if (transform == NULL)
return;
const float cx = cosf(angle_x);
const float sx = sinf(angle_x);
const float cz = cosf(angle_z);
const float sz = sinf(angle_z);
const float cy = cosf(angle_y);
const float sy = sinf(angle_y);
transform[0] = scale * cz * cy;
transform[1] = scale * sz * cy;
transform[2] = scale * -sy;
transform[3] = 0.0f;
transform[4] = scale * (cz * sy * sx - sz * cx);
transform[5] = scale * (sz * sy * sx + cz * cx);
transform[6] = scale * cy * sx;
transform[7] = 0.0f;
transform[8] = scale * (cz * sy * cx + sz * sx);
transform[9] = scale * (sz * sy * cx - cz * sx);
transform[10] = scale * cy * cx;
transform[11] = 0.0f;
transform[12] = tx;
transform[13] = ty;
transform[14] = tz;
transform[15] = 1.0f;
}
/**
* Allocate and fill the cube instance transform grid.
*
* @return heap-allocated transform array, or NULL on failure
*/
static float (*_make_cube_transforms(void))[16]
{
float (*transforms)[16] = (float(*)[16])dvz_calloc(INSTANCE_COUNT, sizeof(*transforms));
if (transforms == NULL)
return NULL;
const float spacing = 0.50f;
const float half_x = 0.5f * (float)(GRID_X - 1u);
const float half_y = 0.5f * (float)(GRID_Y - 1u);
const float half_z = 0.5f * (float)(GRID_Z - 1u);
uint32_t idx = 0;
for (uint32_t z = 0; z < GRID_Z; z++)
{
for (uint32_t y = 0; y < GRID_Y; y++)
{
for (uint32_t x = 0; x < GRID_X; x++)
{
const float fx = ((float)x - half_x) * spacing +
0.035f * sinf(1.70f * (float)x + 0.90f * (float)y);
const float fy = ((float)y - half_y) * spacing +
0.030f * cosf(1.10f * (float)y + 0.80f * (float)z);
const float fz = ((float)z - half_z) * spacing +
0.045f * sinf(0.80f * (float)x - 1.15f * (float)y);
const float wave =
0.5f + 0.5f * sinf(TAU * ((float)x / (float)GRID_X + (float)z * 0.11f));
const float scale = 0.62f + 0.30f * wave;
const float angle_x =
0.22f * sinf(0.95f * (float)x + 1.55f * (float)y + 0.70f * (float)z);
const float angle_z = 0.10f * (float)x + 0.17f * (float)y;
const float angle_y = 0.24f * (float)z - 0.06f * (float)y +
0.14f * cosf(1.20f * (float)x + 0.50f * (float)y);
_cube_transform(
transforms[idx++], fx, fy, fz, scale, angle_x, angle_z, angle_y);
}
}
}
return transforms;
}
/**
* Free the retained state buffers.
*
* @param state mesh-instance selection state
*/
static void _free_state(MeshInstanceSelectionState* state)
{
if (state == NULL)
return;
dvz_free(state->transforms);
dvz_free(state);
}
/**
* Create a muted colored cube mesh for the selection field.
*
* @param scene scene owning the visual
* @return mesh visual, or NULL on error
*/
static DvzVisual* _selection_cube_mesh(DvzScene* scene)
{
if (scene == NULL)
return NULL;
DvzColor face_colors[DVZ_GEOM_CUBE_FACE_COUNT] = {
dvz_color_rgb(76, 201, 240),
dvz_color_rgb(38, 132, 167),
dvz_color_rgb(128, 255, 219),
dvz_color_rgb(42, 176, 142),
dvz_color_rgb(132, 142, 239),
dvz_color_rgb(176, 112, 221),
};
DvzVisual* visual = dvz_mesh(scene, 0);
if (visual == NULL)
return NULL;
DvzGeometry* cube = dvz_geometry_cube(&(DvzGeometryCubeDesc){
DVZ_STRUCT_INIT_FIELDS(DvzGeometryCubeDesc),
.size = 0.32,
.face_colors = face_colors,
.face_color_count = DVZ_GEOM_CUBE_FACE_COUNT,
});
if (cube == NULL)
return NULL;
int rc = dvz_mesh_set_geometry(visual, cube);
dvz_geometry_destroy(cube);
return rc == 0 ? visual : NULL;
}
/**
* Toggle retained selection for one queried mesh instance.
*
* @param state mesh-instance selection state
* @param query mesh item query result
*/
static void _toggle_mesh_selection(
MeshInstanceSelectionState* state, const DvzQueryResult* query)
{
if (state == NULL || query == NULL)
return;
if (
query->status != DVZ_QUERY_STATUS_HIT || !query->hit ||
query->visual_family != DVZ_SCENE_VISUAL_FAMILY_MESH ||
query->resolved_target != DVZ_SCENE_TARGET_ITEM || query->resolved_id >= INSTANCE_COUNT)
return;
if (dvz_selection_apply_query(state->selection, query) != 0)
fprintf(stderr, "dvz_selection_apply_query() failed\n");
fprintf(stdout, "toggle mesh instance id=%" PRIu64 "\n", query->resolved_id);
}
/*************************************************************************************************/
/* Callbacks */
/*************************************************************************************************/
/**
* Queue hover and click queries from panel-local pointer events.
*
* @param event portable pointer event
* @param user_data mesh-instance selection state
*/
static void _selection_mesh_pointer(const DvzScenarioPointerEvent* event, void* user_data)
{
MeshInstanceSelectionState* state = (MeshInstanceSelectionState*)user_data;
if (state == NULL || event == NULL)
return;
if (
event->type != DVZ_SCENARIO_POINTER_MOVE && event->type != DVZ_SCENARIO_POINTER_CLICK)
return;
double x = 0.0;
double y = 0.0;
double panel_pos[2] = {0};
state->cursor_valid = dvz_panel_transform_point(
state->panel, DVZ_PANEL_COORD_FIGURE_PX, DVZ_PANEL_COORD_PANEL_PX,
(const double[2]){event->x, event->y}, panel_pos);
x = panel_pos[0];
y = panel_pos[1];
if (!state->cursor_valid)
{
if (state->has_hover_query)
{
dvz_hover_clear(state->hover);
state->has_hover_query = false;
}
if (event->type == DVZ_SCENARIO_POINTER_CLICK && event->button == DVZ_POINTER_BUTTON_LEFT)
dvz_selection_clear(state->selection);
return;
}
DvzQueryRequest request = dvz_query_request();
request.target = DVZ_SCENE_TARGET_ITEM;
request.hit_policy = DVZ_QUERY_HIT_FRONTMOST;
if (event->type == DVZ_SCENARIO_POINTER_MOVE)
{
request.request_id = QUERY_HOVER_ID;
if (dvz_panel_query_px(state->panel, x, y, &request) != 0)
fprintf(stderr, "dvz_panel_query_px() failed\n");
}
else if (event->type == DVZ_SCENARIO_POINTER_CLICK && event->button == DVZ_POINTER_BUTTON_LEFT)
{
request.request_id = QUERY_CLICK_ID;
if (dvz_panel_query_px(state->panel, x, y, &request) != 0)
fprintf(stderr, "dvz_panel_query_px(click) failed\n");
}
}
/**
* Consume mesh query results and update hover styling.
*
* @param ctx scenario context
* @param user_data mesh-instance selection state
*/
static void _selection_mesh_post_frame(DvzScenarioContext* ctx, void* user_data)
{
(void)ctx;
MeshInstanceSelectionState* state = (MeshInstanceSelectionState*)user_data;
if (state == NULL)
return;
DvzQueryResult query = {0};
while (dvz_scene_poll_query(state->scene, &query))
{
if (query.request_id == QUERY_CLICK_ID)
{
if (
query.status == DVZ_QUERY_STATUS_HIT && query.hit &&
query.visual_family == DVZ_SCENE_VISUAL_FAMILY_MESH &&
query.resolved_target == DVZ_SCENE_TARGET_ITEM &&
query.resolved_id < INSTANCE_COUNT)
{
_toggle_mesh_selection(state, &query);
}
else
{
dvz_selection_clear(state->selection);
}
continue;
}
if (query.request_id != QUERY_HOVER_ID)
continue;
if (!state->cursor_valid)
continue;
if (
query.status == DVZ_QUERY_STATUS_HIT && query.hit &&
query.visual_family == DVZ_SCENE_VISUAL_FAMILY_MESH &&
query.resolved_target == DVZ_SCENE_TARGET_ITEM && query.resolved_id < INSTANCE_COUNT)
{
bool same_item =
state->latest_hover_query.visual_id == query.visual_id &&
state->latest_hover_query.resolved_id == query.resolved_id;
bool hover_changed = !state->has_hover_query || !same_item;
if (hover_changed && dvz_hover_apply_query(state->hover, &query) != 0)
fprintf(stderr, "dvz_hover_apply_query() failed\n");
if (!same_item)
fprintf(stdout, "hover mesh instance id=%" PRIu64 "\n", query.resolved_id);
state->has_hover_query = true;
state->latest_hover_query = query;
}
else
{
if (state->has_hover_query)
dvz_hover_clear(state->hover);
state->has_hover_query = false;
}
}
}
/**
* Handle portable scenario events.
*
* @param ctx scenario context
* @param event portable event
* @param user scenario state
*/
static void _scenario_event(DvzScenarioContext* ctx, const DvzScenarioEvent* event, void* user)
{
(void)ctx;
if (event == NULL)
return;
if (event->kind == DVZ_SCENARIO_EVENT_POINTER)
_selection_mesh_pointer(&event->content.pointer, user);
}
/*************************************************************************************************/
/* Scenario callbacks */
/*************************************************************************************************/
/**
* Initialize the retained mesh instance selection feature scenario.
*
* @param ctx scenario context
* @param out_user scenario state output
* @return true on success
*/
static bool _scenario_init(DvzScenarioContext* ctx, void** out_user)
{
if (ctx == NULL)
return false;
if (out_user != NULL)
*out_user = NULL;
MeshInstanceSelectionState* state =
(MeshInstanceSelectionState*)dvz_calloc(1, sizeof(*state));
if (state == NULL)
return false;
state->transforms = _make_cube_transforms();
if (state->transforms == NULL)
goto error;
ctx->figure = dvz_figure(ctx->scene, ctx->width, ctx->height, 0);
if (ctx->figure == NULL)
goto error;
DvzPanel* panel = dvz_panel_full(ctx->figure);
if (panel == NULL)
goto error;
example_graphite_cyan_set_panel_background(panel);
if (example_set_default_3d_camera(panel, 1.4f) == NULL)
goto error;
DvzVisual* visual = _selection_cube_mesh(ctx->scene);
if (visual == NULL)
goto error;
dvz_visual_set_query_capabilities(visual, DVZ_QUERY_CAPABILITY_ITEM);
DvzMaterialDesc material = example_default_standard_material_desc();
material.light_direction[0] = +0.32f;
material.light_direction[1] = -0.50f;
material.light_direction[2] = +0.80f;
material.standard.roughness = 0.54f;
material.standard.specular = 0.28f;
material.standard.rim_strength = 0.08f;
if (dvz_visual_set_material(visual, &material) != 0)
goto error;
DvzSelection* selection = dvz_selection(
ctx->scene,
&(DvzSelectionDesc){
DVZ_STRUCT_INIT_FIELDS(DvzSelectionDesc),
.mode = DVZ_SELECT_TOGGLE,
.target = DVZ_SCENE_TARGET_ITEM,
});
if (selection == NULL)
goto error;
DvzSelectionVisualStyle selection_style = dvz_selection_visual_style();
selection_style.selected_visual_flags = DVZ_ITEM_STATE_VISUAL_TINT;
selection_style.selected_tint = example_graphite_cyan_color(EXAMPLE_STYLE_COLOR_WARNING);
selection_style.selected_tint_mix = 1.0f;
selection_style.unselected_visual_flags = DVZ_ITEM_STATE_VISUAL_NONE;
if (dvz_selection_set_visual_style(selection, &selection_style) != 0)
goto error;
DvzHover* hover = dvz_hover(
ctx->scene,
&(DvzHoverDesc){
DVZ_STRUCT_INIT_FIELDS(DvzHoverDesc),
.target = DVZ_SCENE_TARGET_ITEM,
.hit_policy = DVZ_QUERY_HIT_FRONTMOST,
});
if (hover == NULL)
goto error;
DvzItemStateVisualStyle hover_style = dvz_item_state_visual_style();
hover_style.visual_flags = DVZ_ITEM_STATE_VISUAL_SCALE;
hover_style.scale = 1.24f;
if (dvz_hover_set_visual_style(hover, &hover_style) != 0)
goto error;
if (dvz_visual_set_data(visual, "instance_transform", state->transforms, INSTANCE_COUNT) != 0)
goto error;
if (dvz_panel_add_visual(panel, visual, NULL) != 0)
goto error;
DvzController* arcball_controller = dvz_arcball(ctx->scene, NULL);
if (arcball_controller == NULL)
goto error;
if (dvz_scenario_bind_controller(ctx, panel, arcball_controller, DVZ_DIM_MASK_XYZ) != 0)
goto error;
state->scene = ctx->scene;
state->panel = panel;
state->selection = selection;
state->hover = hover;
if (out_user != NULL)
*out_user = state;
return true;
error:
_free_state(state);
return false;
}
/**
* Destroy the retained mesh instance selection feature scenario state.
*
* @param ctx scenario context
* @param user scenario state
*/
static void _scenario_destroy(DvzScenarioContext* ctx, void* user)
{
(void)ctx;
_free_state((MeshInstanceSelectionState*)user);
}
/**
* Return the retained mesh instance selection scenario specification.
*
* @return scenario specification
*/
DvzScenarioSpec dvz_example_selection_mesh_instances_scenario(void)
{
return (DvzScenarioSpec){
.id = "features_selection_mesh_instances",
.title = "Mesh Instance Selection",
.width = WIDTH,
.height = HEIGHT,
.fps = 60.0,
.requirements = DVZ_SCENARIO_REQ_QUERY_READBACK | DVZ_SCENARIO_REQ_CONTROLLER |
DVZ_SCENARIO_REQ_ARCBALL | DVZ_SCENARIO_REQ_FRAME_CALLBACKS,
.init = _scenario_init,
.event = _scenario_event,
.post_frame = _selection_mesh_post_frame,
.destroy = _scenario_destroy,
};
}
/*************************************************************************************************/
/* Functions */
/*************************************************************************************************/
/**
* Run the retained mesh instance selection feature example through the native scenario runner.
*
* @param argc command-line argument count
* @param argv command-line argument vector
* @return process exit code
*/
#ifndef DVZ_EXAMPLE_NO_MAIN
int main(int argc, char** argv)
{
DvzScenarioSpec spec = dvz_example_selection_mesh_instances_scenario();
return dvz_scenario_run_native_cli(&spec, argc, argv) == 0 ? 0 : 1;
}
#endif
Example details
- ID:
features_selection_mesh_instances - Category:
feature - Lane:
features - Status:
supported - Source:
examples/c/features/selection_mesh_instances.c - Approved adaptation starter:
yes - Python source:
examples/python/gallery/features/selection_mesh_instances.py - Python adaptation: Available; direct-engine adaptation
- Browser support: Live in browser
- WebGPU live route:
examples/webgpu/live.html?id=features_selection_mesh_instances - Browser capability tags:
mesh,arcball,query-readback,frame-callbacks - Validation:
smoke+interaction+screenshot
Data
| Field | Value |
|---|---|
kind |
synthetic |
