Files
茂之钳 5e2812a6f3
Build & Test / build-and-test (push) Waiting to run
Build & Test / python-bindings (push) Blocked by required conditions
CI / Build & Test (push) Failing after 33s
CI / Release Build (push) Failing after 35s
feat(v6.2): Blender addon + .NET/C# bindings + developer docs + plugin system
v6.2.1 — Blender Integration Addon:
- 5 files, 1,732 lines: __init__, operators (9 ops), panels (4 panels)
- preferences, vde_bridge (subprocess CLI bridge)
- Import/Export STEP, primitives, boolean, SDF→Mesh

v6.2.2 — .NET/C# Bindings (VdeSharp):
- 8 files: NativeMethods (50+ P/Invoke), BrepModel, MeshData, SdfEngine, Assembly
- C API extended with 20 new functions (STEP I/O, Boolean, SDF, Assembly)
- vde_capi rebuilt as SHARED library
- Example: import STEP → boolean → export

v6.2.3 — Developer Docs + Plugin System:
- 7 docs: architecture, contributing, API overview, building, testing, plugin-system
- plugin_system.h/.cpp: PluginInterface, PluginManager, dlopen/LoadLibrary
- README.md updated with v6 features
- Syntax-check passed (GCC 10.2.1, -Wall -Wextra -Wpedantic)
2026-07-26 22:24:40 +08:00

725 lines
24 KiB
C
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
#pragma once
/**
* @file vde_capi.h
* @brief ViewDesignEngine C API — 跨语言边界接口
*
* 提供稳定的 C ABI 接口,使 Python、Rust、C# 等语言可以通过 FFI 调用
* ViewDesignEngine 的核心功能,无需依赖 C++ ABI。
*
* ## 设计原则
*
* 1. **不透明句柄**: 所有内部对象(网格、曲线、求解器等)通过 `typedef` 前向声明
* 隐藏为不透明指针类型,外部代码只能通过 API 函数操作
* 2. **C 兼容类型**: 仅使用 C 原生类型(int, double, const char*)作为参数和返回值
* 3. **输出通过指针**: 复数返回值(如顶点坐标、包围盒)通过输出参数传递,避免结构体 ABI 问题
* 4. **显式生命周期管理**: 每个 create/load 函数都有对应的 free/destroy 函数
*
* ## 句柄类型
*
* | C 类型 | 内部类型 | 创建方式 | 释放方式 |
* |------------------|--------------------|-----------------------------|-------------------|
* | VdeHandle | VdeContext | vde_create() | vde_destroy() |
* | VdeMeshHandle | HalfedgeMesh | vde_load_mesh(), 工厂函数 | vde_mesh_free() |
* | VdeCurveHandle | NurbsCurve | vde_curve_create_bezier() | vde_curve_free() |
* | VdeSolverHandle | ConstraintSolver | vde_solver_create() | vde_solver_free() |
* | VdeBodyHandle | BrepModel | vde_body_create_*() | vde_body_free() |
*
* ## 布尔操作编码
*
* | 操作 | 整数值 |
* |------|--------|
* | 并集 | 0 |
* | 交集 | 1 |
* | 差集 | 2 |
*
* ## 线程安全性
*
* - 每个 VdeHandle 是独立的上下文,不同句柄之间线程安全
* - 同一句柄上的操作不是线程安全的(调用方负责同步)
*
* @ingroup capi
* @see vde.h C++ 等价接口
*/
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
// ═══════════════════════════════════════════════════════════
// 不透明句柄类型(在 vde.h 中已有前向声明)
// ═══════════════════════════════════════════════════════════
/** @brief 引擎上下文句柄 — 管理错误状态和内部资源 */
#ifndef VDE_HANDLE_DEFINED
typedef struct VdeContext* VdeHandle;
#endif
/** @brief 三角网格句柄 — 顶点+面集合 */
#ifndef VDE_MESH_HANDLE_DEFINED
typedef struct VdeMesh* VdeMeshHandle;
#endif
/** @brief 参数曲线句柄 — NURBS 曲线 */
#ifndef VDE_CURVE_HANDLE_DEFINED
typedef struct VdeCurve* VdeCurveHandle;
#endif
/** @brief 约束求解器句柄 — 二维草图约束 */
#ifndef VDE_SOLVER_HANDLE_DEFINED
typedef struct VdeSolver* VdeSolverHandle;
#endif
/** @brief B-Rep 实体句柄 — 边界表示模型 */
#ifndef VDE_BODY_HANDLE_DEFINED
typedef struct VdeBody* VdeBodyHandle;
#endif
// ═══════════════════════════════════════════════════════════
// 引擎生命周期
// ═══════════════════════════════════════════════════════════
/**
* @brief 创建 ViewDesignEngine 上下文
*
* 初始化一个独立的引擎实例。几乎所有后续操作都需要传入此句柄。
*
* @return 新的引擎句柄,不需要时通过 vde_destroy() 释放
*
* @code{.py}
* // Python ctypes 示例
* ctx = lib.vde_create()
* @endcode
*
* @see vde_destroy 释放上下文
*/
VdeHandle vde_create(void);
/**
* @brief 销毁引擎上下文
*
* 释放上下文及其内部资源。销毁后不能再使用该句柄。
*
* @param ctx 引擎上下文句柄
*
* @see vde_create
*/
void vde_destroy(VdeHandle ctx);
/**
* @brief 获取引擎版本字符串
*
* @return 语义版本号字符串(如 "0.5.0"),静态生命周期,无需释放
*
* @code{.c}
* printf("VDE version: %s\n", vde_version());
* @endcode
*/
const char* vde_version(void);
/**
* @brief 获取最后一次操作的错误描述
*
* 当某操作失败(如加载不存在的文件)时,可通过此函数获取详情。
*
* @param ctx 引擎上下文句柄
* @return 错误描述字符串(上下文的内部缓冲区,静态生命周期)
*
* @note 每次新的失败操作会覆盖此描述。成功操作不会清除它。
*/
const char* vde_last_error(VdeHandle ctx);
// ═══════════════════════════════════════════════════════════
// 网格 I/O
// ═══════════════════════════════════════════════════════════
/**
* @brief 从文件加载三角网格
*
* 支持 OBJ (.obj), STL (.stl), PLY (.ply) 三种格式。
* 格式通过文件扩展名自动检测。
*
* @param ctx 引擎上下文句柄
* @param path 文件路径(UTF-8 编码)
* @return 网格句柄,失败时返回 NULL(通过 vde_last_error() 获取原因)
*
* @code{.c}
* VdeMeshHandle mesh = vde_load_mesh(ctx, "model.obj");
* if (!mesh) {
* fprintf(stderr, "Load failed: %s\n", vde_last_error(ctx));
* return;
* }
* @endcode
*
* @see vde_mesh_free 释放网格
* @see vde_save_mesh 保存网格
*/
VdeMeshHandle vde_load_mesh(VdeHandle ctx, const char* path);
/**
* @brief 将三角网格保存为文件
*
* 当前支持 OBJ 格式输出。
*
* @param ctx 引擎上下文句柄
* @param mesh 网格句柄
* @param path 输出文件路径
* @param format 输出格式(当前仅 "obj" 有效)
* @return 成功返回 1,失败返回 0
*
* @see vde_load_mesh 加载网格
*/
int vde_save_mesh(VdeHandle ctx, VdeMeshHandle mesh, const char* path, const char* format);
// ═══════════════════════════════════════════════════════════
// 网格查询
// ═══════════════════════════════════════════════════════════
/**
* @brief 获取网格的顶点数量
*
* @param mesh 网格句柄(必须有效且非 NULL)
* @return 顶点数
*
* @see vde_mesh_num_faces 面数
*/
size_t vde_mesh_num_vertices(VdeMeshHandle mesh);
/**
* @brief 获取网格的三角面数量
*
* @param mesh 网格句柄
* @return 面数
*
* @see vde_mesh_num_vertices 顶点数
*/
size_t vde_mesh_num_faces(VdeMeshHandle mesh);
/**
* @brief 获取指定索引的顶点坐标
*
* 顶点索引从 0 开始,到 num_vertices - 1。
*
* @param mesh 网格句柄
* @param idx 顶点索引 [0, num_vertices)
* @param out_x [out] 顶点 X 坐标
* @param out_y [out] 顶点 Y 坐标
* @param out_z [out] 顶点 Z 坐标
*
* @pre idx < vde_mesh_num_vertices(mesh)
*/
void vde_mesh_get_vertex(VdeMeshHandle mesh, size_t idx,
double* out_x, double* out_y, double* out_z);
/**
* @brief 获取网格的轴对齐包围盒
*
* @param mesh 网格句柄
* @param out_min_x [out] 最小 X 坐标
* @param out_min_y [out] 最小 Y 坐标
* @param out_min_z [out] 最小 Z 坐标
* @param out_max_x [out] 最大 X 坐标
* @param out_max_y [out] 最大 Y 坐标
* @param out_max_z [out] 最大 Z 坐标
*/
void vde_mesh_get_bounds(VdeMeshHandle mesh,
double* out_min_x, double* out_min_y, double* out_min_z,
double* out_max_x, double* out_max_y, double* out_max_z);
/**
* @brief 释放网格句柄及其资源
*
* 释放后将不能再使用该句柄。
*
* @param mesh 网格句柄
*/
void vde_mesh_free(VdeMeshHandle mesh);
// ═══════════════════════════════════════════════════════════
// 网格处理
// ═══════════════════════════════════════════════════════════
/**
* @brief 网格简化
*
* 通过 edge-collapse 或类似算法减少三角形数量,
* 同时尽可能保留几何特征。
*
* @param ctx 引擎上下文句柄
* @param mesh 输入网格句柄(不修改输入)
* @param target_ratio 目标简化比率 [0, 1]0 = 不变,1 = 最大简化)
* @return 简化后的新网格句柄
*
* @code{.c}
* VdeMeshHandle simple = vde_mesh_simplify(ctx, mesh, 0.5); // 减少 50%
* @endcode
*
* @see vde_mesh_smooth 网格平滑
*/
VdeMeshHandle vde_mesh_simplify(VdeHandle ctx, VdeMeshHandle mesh, double target_ratio);
/**
* @brief 网格平滑(Laplacian 或 Taubin 平滑)
*
* 通过迭代平滑顶点位置改善网格质量,减少噪声。
*
* @param ctx 引擎上下文句柄
* @param mesh 输入网格句柄
* @param iterations 平滑迭代次数
* @return 平滑后的新网格句柄
*
* @see vde_mesh_simplify 网格简化
*/
VdeMeshHandle vde_mesh_smooth(VdeHandle ctx, VdeMeshHandle mesh, int iterations);
/**
* @brief 网格布尔运算
*
* 对两个三角网格执行布尔操作。
*
* @param ctx 引擎上下文句柄
* @param a 网格 A
* @param b 网格 B
* @param operation 布尔操作类型: 0 = 并集, 1 = 交集, 2 = 差集 (A \ B)
* @return 布尔结果的新网格句柄
*
* @warning 两个输入网格必须是水密的(closed manifold),否则结果不可预测。
*
* @code{.c}
* VdeMeshHandle result = vde_mesh_boolean(ctx, box, sphere, 0); // 并集
* @endcode
*/
VdeMeshHandle vde_mesh_boolean(VdeHandle ctx, VdeMeshHandle a, VdeMeshHandle b, int operation);
// ═══════════════════════════════════════════════════════════
// 曲线
// ═══════════════════════════════════════════════════════════
/**
* @brief 创建 Bézier 曲线
*
* @param ctx 引擎上下文句柄
* @param control_points 控制点数组,每 3 个 double 表示一个三维点 (x,y,z)
* @param num_points 控制点数量(次数 = num_points - 1
* @param dim 维度(固定为 3
* @return 曲线句柄
*
* @code{.c}
* double cp[] = {0,0,0, 1,2,0, 3,0,0}; // 3 控制点,2 次 Bézier
* VdeCurveHandle curve = vde_curve_create_bezier(ctx, cp, 3, 3);
* @endcode
*
* @see vde_curve_evaluate 求值
* @see vde_curve_free 释放
*/
VdeCurveHandle vde_curve_create_bezier(VdeHandle ctx, const double* control_points,
int num_points, int dim);
/**
* @brief 在参数 t 处求值曲线
*
* @param curve 曲线句柄
* @param t 参数值 [0, 1]
* @param out_x [out] 曲线上点的 X 坐标
* @param out_y [out] 曲线上点的 Y 坐标
* @param out_z [out] 曲线上点的 Z 坐标
*
* @pre 0 ≤ t ≤ 1
*/
void vde_curve_evaluate(VdeCurveHandle curve, double t,
double* out_x, double* out_y, double* out_z);
/**
* @brief 获取曲线的次数
*
* 对于 Bézier 曲线,次数 = 控制点数 - 1。
*
* @param curve 曲线句柄
* @return 曲线次数
*/
int vde_curve_degree(VdeCurveHandle curve);
/**
* @brief 释放曲线句柄
*
* @param curve 曲线句柄
*/
void vde_curve_free(VdeCurveHandle curve);
// ═══════════════════════════════════════════════════════════
// 碰撞检测
// ═══════════════════════════════════════════════════════════
/**
* @brief 两球体碰撞检测(GJK 算法)
*
* 用于验证和测试 GJK 碰撞检测算法的轻量级接口。
*
* @param ctx 引擎上下文句柄
* @param cx1, cy1, cz1 第一个球体的球心坐标
* @param r1 第一个球体的半径
* @param cx2, cy2, cz2 第二个球体的球心坐标
* @param r2 第二个球体的半径
* @return 碰撞返回 1,不碰撞返回 0
*
* @code{.c}
* int hit = vde_collision_gjk_spheres(ctx, 0,0,0, 1.0, 1.5,0,0, 0.5);
* @endcode
*
* @see vde_collision_ray_mesh 射线-网格相交
*/
int vde_collision_gjk_spheres(VdeHandle ctx,
double cx1, double cy1, double cz1, double r1,
double cx2, double cy2, double cz2, double r2);
/**
* @brief 射线与网格的最近交点查询
*
* 使用 BVH 加速结构加速查询。
*
* @param ctx 引擎上下文句柄
* @param mesh 目标网格句柄
* @param ox, oy, oz 射线起点
* @param dx, dy, dz 射线方向(无需归一化)
* @param out_t [out] 交点参数 t(沿射线的距离)
* @param out_x, out_y, out_z [out] 交点坐标
* @return 命中返回 1,未命中返回 0
*
* @code{.c}
* double t, hx, hy, hz;
* int hit = vde_collision_ray_mesh(ctx, mesh,
* 0,0,-10, // 射线起点
* 0,0,1, // 射线方向 (沿 Z 轴正方向)
* &t, &hx, &hy, &hz);
* if (hit) printf("Hit at (%f,%f,%f), t=%f\n", hx, hy, hz, t);
* @endcode
*
* @see vde_collision_gjk_spheres GJK 球体碰撞
*/
int vde_collision_ray_mesh(VdeHandle ctx, VdeMeshHandle mesh,
double ox, double oy, double oz,
double dx, double dy, double dz,
double* out_t, double* out_x, double* out_y, double* out_z);
// ═══════════════════════════════════════════════════════════
// 约束求解器(二维草图)
// ═══════════════════════════════════════════════════════════
/**
* @brief 创建二维约束求解器
*
* 用于求解草图几何约束(距离、水平、垂直等)。
*
* @return 求解器句柄
*
* @see vde_solver_free 释放
*/
VdeSolverHandle vde_solver_create(void);
/**
* @brief 向求解器添加点
*
* @param solver 求解器句柄
* @param x 初始 X 坐标
* @param y 初始 Y 坐标
* @param fixed 固定点标记(1 = 固定不移动)
* @return 点的 ID(用于后续约束引用)
*
* @see vde_solver_add_line 添加线段
*/
int vde_solver_add_point(VdeSolverHandle solver, double x, double y, int fixed);
/**
* @brief 向求解器添加线段(由两个点定义)
*
* @param solver 求解器句柄
* @param p0 起点 ID
* @param p1 终点 ID
* @return 线段的 ID
*
* @see vde_solver_add_point 添加点
* @see vde_solver_add_horizontal 添加水平约束
* @see vde_solver_add_vertical 添加垂直约束
*/
int vde_solver_add_line(VdeSolverHandle solver, int p0, int p1);
/**
* @brief 添加距离约束(两点之间)
*
* @param solver 求解器句柄
* @param p0 第一个点的 ID
* @param p1 第二个点的 ID
* @param d 目标距离(必须 > 0
*
* @see vde_solver_add_horizontal 水平约束
*/
void vde_solver_add_distance_constraint(VdeSolverHandle solver, int p0, int p1, double d);
/**
* @brief 添加水平约束(线段水平)
*
* @param solver 求解器句柄
* @param line_id 线段 ID
*
* @see vde_solver_add_vertical 垂直约束
* @see vde_solver_add_line 添加线段
*/
void vde_solver_add_horizontal(VdeSolverHandle solver, int line_id);
/**
* @brief 添加垂直约束(线段垂直)
*
* @param solver 求解器句柄
* @param line_id 线段 ID
*
* @see vde_solver_add_horizontal 水平约束
*/
void vde_solver_add_vertical(VdeSolverHandle solver, int line_id);
/**
* @brief 求解约束系统
*
* 通过迭代优化使所有点的位置满足所有约束。
*
* @param solver 求解器句柄
* @param max_iter 最大迭代次数
* @param tol 收敛容差
* @return 收敛返回 1,未收敛返回 0
*
* @code{.c}
* int converged = vde_solver_solve(solver, 100, 1e-6);
* @endcode
*
* @see vde_solver_get_point 获取求解后的点坐标
*/
int vde_solver_solve(VdeSolverHandle solver, int max_iter, double tol);
/**
* @brief 获取求解后的点坐标
*
* @param solver 求解器句柄
* @param idx 点 ID
* @param out_x [out] 求解后 X 坐标
* @param out_y [out] 求解后 Y 坐标
*
* @pre 必须先调用 vde_solver_solve()
*/
void vde_solver_get_point(VdeSolverHandle solver, int idx, double* out_x, double* out_y);
/**
* @brief 释放求解器句柄
*
* @param solver 求解器句柄
*/
void vde_solver_free(VdeSolverHandle solver);
// ═══════════════════════════════════════════════════════════
// B-Rep 建模
// ═══════════════════════════════════════════════════════════
/**
* @brief 创建实心立方体 B-Rep
*
* 以原点为中心的轴对齐立方体。
*
* @param ctx 引擎上下文句柄
* @param w 宽度(X 方向),> 0
* @param h 高度(Y 方向),> 0
* @param d 深度(Z 方向),> 0
* @return B-Rep 实体句柄
*
* @see vde_body_create_cylinder 圆柱体
* @see vde_body_create_sphere 球体
*/
VdeBodyHandle vde_body_create_box(VdeHandle ctx, double w, double h, double d);
/**
* @brief 创建实心圆柱体 B-Rep
*
* 沿 Y 轴、以原点为中心的圆柱体。
*
* @param ctx 引擎上下文句柄
* @param r 截面半径,> 0
* @param h 总高度(从 -h/2 到 +h/2
* @param segs 截面分段数(边数)
* @return B-Rep 实体句柄
*
* @see vde_body_create_box 立方体
*/
VdeBodyHandle vde_body_create_cylinder(VdeHandle ctx, double r, double h, int segs);
/**
* @brief 创建球体 B-Rep
*
* @param ctx 引擎上下文句柄
* @param r 球半径,> 0
* @param su 经度方向分段数
* @param sv 纬度方向分段数
* @return B-Rep 实体句柄
*/
VdeBodyHandle vde_body_create_sphere(VdeHandle ctx, double r, int su, int sv);
/**
* @brief 将 B-Rep 实体转换为三角网格
*
* 以指定的弦高误差对曲面进行 tessellation。
*
* @param ctx 引擎上下文句柄
* @param body B-Rep 实体句柄
* @param deflection 弦高误差(越小 = 越精细,推荐 0.01)
* @return 三角网格句柄
*
* @code{.c}
* VdeBodyHandle body = vde_body_create_box(ctx, 10, 5, 3);
* VdeMeshHandle mesh = vde_body_to_mesh(ctx, body, 0.01);
* vde_save_mesh(ctx, mesh, "box.obj", "obj");
* @endcode
*
* @see vde_body_free 释放 B-Rep 实体
*/
VdeMeshHandle vde_body_to_mesh(VdeHandle ctx, VdeBodyHandle body, double deflection);
/**
* @brief 释放 B-Rep 实体句柄
*
* @param body B-Rep 实体句柄
*/
void vde_body_free(VdeBodyHandle body);
/** @brief 深拷贝 B-Rep 实体 */
VdeBodyHandle vde_body_clone(VdeHandle ctx, VdeBodyHandle body);
// ── B-Rep STEP/IGES I/O ──
/** @brief 从 STEP 文件导入 B-Rep 实体列表。返回数量,每个 body 写入 out_bodies */
int vde_body_load_step(VdeHandle ctx, const char* path, VdeBodyHandle** out_bodies);
/** @brief 从 IGES 文件导入 B-Rep 实体列表 */
int vde_body_load_iges(VdeHandle ctx, const char* path, VdeBodyHandle** out_bodies);
/** @brief 将 B-Rep 实体列表导出为 STEP 文件。成功返回 1 */
int vde_body_save_step(VdeHandle ctx, VdeBodyHandle* bodies, int count, const char* path);
/** @brief 将 B-Rep 实体列表导出为 IGES 文件 */
int vde_body_save_iges(VdeHandle ctx, VdeBodyHandle* bodies, int count, const char* path);
// ── B-Rep Boolean ──
/** @brief B-Rep 布尔运算。op: 0=Union, 1=Intersection, 2=Difference (A\B) */
VdeBodyHandle vde_body_boolean(VdeHandle ctx, VdeBodyHandle a, VdeBodyHandle b, int op);
// ── Mesh face data access ──
/** @brief 获取网格面的顶点索引。返回顶点数,out_indices 需调用 vde_free_buffer 释放 */
int vde_mesh_get_face(VdeMeshHandle mesh, size_t face_idx, int** out_indices);
// ═══════════════════════════════════════════════════════════
// SDF 建模
// ═══════════════════════════════════════════════════════════
/** @brief SDF 节点句柄(不透明) */
#ifndef VDE_SDF_HANDLE_DEFINED
typedef struct VdeSdfNode* VdeSdfHandle;
#endif
/** @brief 创建 SDF 球体节点 */
VdeSdfHandle vde_sdf_sphere(VdeHandle ctx, double radius);
/** @brief 创建 SDF 盒子节点 */
VdeSdfHandle vde_sdf_box(VdeHandle ctx, double hx, double hy, double hz);
/** @brief 创建 SDF 圆柱节点 */
VdeSdfHandle vde_sdf_cylinder(VdeHandle ctx, double radius, double height);
/** @brief SDF 布尔并集 */
VdeSdfHandle vde_sdf_union(VdeHandle ctx, VdeSdfHandle a, VdeSdfHandle b);
/** @brief SDF 布尔交集 */
VdeSdfHandle vde_sdf_intersection(VdeHandle ctx, VdeSdfHandle a, VdeSdfHandle b);
/** @brief SDF 布尔差集 */
VdeSdfHandle vde_sdf_difference(VdeHandle ctx, VdeSdfHandle a, VdeSdfHandle b);
/** @brief SDF 转网格 */
VdeMeshHandle vde_sdf_to_mesh(VdeHandle ctx, VdeSdfHandle sdf, int resolution);
/** @brief 释放 SDF 节点 */
void vde_sdf_free(VdeSdfHandle sdf);
// ═══════════════════════════════════════════════════════════
// 装配体
// ═══════════════════════════════════════════════════════════
/** @brief 装配体句柄 */
#ifndef VDE_ASSEMBLY_HANDLE_DEFINED
typedef struct VdeAssembly* VdeAssemblyHandle;
#endif
/** @brief 创建装配体 */
VdeAssemblyHandle vde_assembly_create(VdeHandle ctx, const char* name);
/** @brief 向装配体根节点添加零件 */
int vde_assembly_add_part(VdeAssemblyHandle assembly, const char* name, VdeBodyHandle body);
/** @brief 获取装配体零件数量 */
int vde_assembly_part_count(VdeAssemblyHandle assembly);
/** @brief 释放装配体(不释放其中的 body,调用方自行管理) */
void vde_assembly_free(VdeAssemblyHandle assembly);
/** @brief 释放 body 句柄数组(由 load_step/load_iges 返回) */
void vde_body_free_array(VdeBodyHandle* bodies, int count);
// ═══════════════════════════════════════════════════════════
// 序列化
// ═══════════════════════════════════════════════════════════
/**
* @brief 将网格序列化为二进制字节流
*
* 返回的缓冲区需要在消费后通过 vde_free_buffer() 释放。
*
* @param ctx 引擎上下文句柄
* @param mesh 网格句柄
* @param out_data [out] 指向序列化字节数组的指针
* @return 字节数
*
* @note 输出的缓冲区由库管理,调用方不得直接 free/delete。
*
* @code{.c}
* uint8_t* data = NULL;
* size_t len = vde_serialize_mesh(ctx, mesh, &data);
* // ... 使用/存储 data ...
* vde_free_buffer(data);
* @endcode
*
* @see vde_deserialize_mesh 反序列化
* @see vde_free_buffer 释放序列化缓冲区
*/
size_t vde_serialize_mesh(VdeHandle ctx, VdeMeshHandle mesh, uint8_t** out_data);
/**
* @brief 从二进制字节流反序列化为网格
*
* @param ctx 引擎上下文句柄
* @param data 序列化数据缓冲区
* @param len 数据长度(字节数)
* @return 反序列化后的网格句柄
*
* @see vde_serialize_mesh 序列化
*/
VdeMeshHandle vde_deserialize_mesh(VdeHandle ctx, const uint8_t* data, size_t len);
/**
* @brief 释放由 vde_serialize_mesh 分配的缓冲区
*
* @param ptr 由 vde_serialize_mesh 返回的缓冲区指针
*/
void vde_free_buffer(uint8_t* ptr);
#ifdef __cplusplus
}
#endif