diff --git a/.gitignore b/.gitignore index d456aa4..0c48456 100644 --- a/.gitignore +++ b/.gitignore @@ -2,4 +2,6 @@ *.o *.exe .vscode/ -.idea/ \ No newline at end of file +.idea/ +*.dump +out/ \ No newline at end of file diff --git a/build.rs b/build.rs index 4a188d6..eef26d4 100644 --- a/build.rs +++ b/build.rs @@ -9,8 +9,10 @@ fn main() { .include("./cpp_src/include") .file("./cpp_src/fbx_parse.cpp") .file("./cpp_src/fbx_wrap.cpp") + .file("./cpp_src/db_ops.cpp") .compile("fbx_parse"); // ------------- println!("cargo:rustc-link-search=native=./cpp_src/lib"); println!("cargo:rustc-link-lib=fbxsdk"); + println!("cargo:rustc-link-lib=sqlite3"); } diff --git a/cpp_src/db_ops.cpp b/cpp_src/db_ops.cpp new file mode 100644 index 0000000..fb8a7da --- /dev/null +++ b/cpp_src/db_ops.cpp @@ -0,0 +1,118 @@ +#include +#include +#include + +using namespace std; + +sqlite3 *create_db(const char *db_path, bool overwrite_file) +{ + if (overwrite_file) + { + if (remove(db_path) != 0 && errno != ENOENT) + { + fprintf(stderr, "Failed to remove old DB file: %s\n", strerror(errno)); + return NULL; + } + } + + sqlite3 *db = NULL; + int result_code = sqlite3_open(db_path, &db); + if (result_code != SQLITE_OK) + { + fprintf(stderr, "Failed to open DB: %s\n", sqlite3_errmsg(db)); + sqlite3_close(db); + return NULL; + } + return db; +} + +void create_tables(sqlite3 *db) +{ + const char *sql_meshes = R"( + CREATE TABLE IF NOT EXISTS meshes ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + vertex_count INTEGER NOT NULL, + index_count INTEGER NOT NULL, + fbx_id TEXT UNIQUE NOT NULL + ); + )"; + + const char *sql_materials = R"( + CREATE TABLE IF NOT EXISTS materials ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + name TEXT NOT NULL, + shader_name TEXT, + fbx_id TEXT UNIQUE NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP + ); + )"; + + const char *sql_vertices = R"( + CREATE TABLE IF NOT EXISTS vertices ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + mesh_id INTEGER NOT NULL, + position_x REAL NOT NULL, + position_y REAL NOT NULL, + position_z REAL NOT NULL, + normal_x REAL, + normal_y REAL, + normal_z REAL, + uv_u REAL, + uv_v REAL, + FOREIGN KEY(mesh_id) REFERENCES meshes(id) ON DELETE CASCADE + ); + )"; + + const char *sql_indices = R"( + CREATE TABLE IF NOT EXISTS indices ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + mesh_id INTEGER NOT NULL, + value INTEGER NOT NULL, + FOREIGN KEY(mesh_id) REFERENCES meshes(id) ON DELETE CASCADE + ); + )"; + + const char *sql_material_props = R"( + CREATE TABLE IF NOT EXISTS material_properties ( + id INTEGER PRIMARY KEY AUTOINCREMENT, + material_id INTEGER NOT NULL, + key TEXT NOT NULL, + value TEXT NOT NULL, + type TEXT NOT NULL, + FOREIGN KEY(material_id) REFERENCES materials(id) ON DELETE CASCADE, + UNIQUE(material_id, key) + ); + )"; + + const char *sql[] = {sql_meshes, sql_materials, sql_vertices, sql_indices, sql_material_props}; + for (int i = 0; i < sizeof(sql) / sizeof(sql[0]); ++i) + { + printf("开始执行:%s", sql[i]); + // 检查前置条件:数据库连接和SQL语句必须有效 + if (!db) + { + printf("db 是空的"); + // 处理空连接错误(如log.Fatalf("db connection is NULL")) + return; // 或抛异常终止 + } + if (!sql[i] || strlen(sql[i]) == 0) + { + printf("SQL Query 是空的"); + // 处理空SQL错误(如log.Errorf("sql[%d] is NULL/empty", i)) + continue; // 或终止 + } + + char *err_msg = nullptr; + int ret = sqlite3_exec(db, sql[i], nullptr, nullptr, &err_msg); + printf("db ret: %d, err_msg: %s\n", ret, err_msg); + if (ret != SQLITE_OK) + { + // 必须处理错误:记录具体SQL和错误信息 + // log.Criticalf("SQL error (i=%d): %s, SQL: %s", i, err_msg ? err_msg : "unknown", sql[i]); + sqlite3_free(err_msg); // 释放错误信息 + return; // 或根据场景决定是否继续 + } + // 成功执行无需释放err_msg(sqlite3_exec成功时err_msg为NULL) + } +} diff --git a/cpp_src/fbx_parse.cpp b/cpp_src/fbx_parse.cpp index ec808d2..baed2b8 100644 --- a/cpp_src/fbx_parse.cpp +++ b/cpp_src/fbx_parse.cpp @@ -2,6 +2,7 @@ #include // buz #include +#include using namespace std; @@ -40,8 +41,18 @@ extern "C" { } } - void load_fbx_mesh_to_db(const FttContext* ctx) + void load_fbx_mesh_to_db(FttContext* ctx) { + + // 按fbx名称生成 ${ctx.out_dir}/sqlite3.db + // 初始化db赋值到ctx.db + sqlite3* db = create_db((std::string(ctx->out_dir) + "/db.sqlite3").c_str(), true); + printf("db---> %x\n", db); + ctx->db = db; + // init db tables + create_tables(ctx->db); + + FbxNode* root = get_fbx_root_node(ctx->fbx_file); each_node(ctx, root, 0); } diff --git a/cpp_src/fbx_wrap.cpp b/cpp_src/fbx_wrap.cpp index 6bc780d..91cae15 100644 --- a/cpp_src/fbx_wrap.cpp +++ b/cpp_src/fbx_wrap.cpp @@ -69,6 +69,8 @@ void each_node(const FttContext* ctx, FbxNode* parent_node, int level) int count = load_triangles(attr, triangles); printf("triangles: %ld\n", triangles.size()); // save data to database + sqlite3* db = ctx->db; + // todo save mesh into db } } diff --git a/cpp_src/include/db_ops.h b/cpp_src/include/db_ops.h new file mode 100644 index 0000000..cb99852 --- /dev/null +++ b/cpp_src/include/db_ops.h @@ -0,0 +1,6 @@ +#include + + +sqlite3* create_db(const char* db_path, bool overwrite_file); + +void create_tables(sqlite3* db); \ No newline at end of file diff --git a/cpp_src/include/fbx_wrap.h b/cpp_src/include/fbx_wrap.h index 174beed..fc51a4f 100644 --- a/cpp_src/include/fbx_wrap.h +++ b/cpp_src/include/fbx_wrap.h @@ -23,7 +23,20 @@ void each_node(const FttContext* ctx, FbxNode* parent_node, int level); * @example 层级2的节点打印格式:" |-- NodeName (Type: Mesh, Children: 3)" */ void print_node_info(FbxNode* node, int level); - +/** + * 从FBX文件加载并返回根节点 + * @param fbx_path FBX文件路径(需绝对路径或相对于可执行文件路径) + * @return FbxNode* 成功时返回根节点指针,失败返回nullptr + * @note 内部会初始化FBX SDK环境并自动释放资源 + * @warning 路径无效或文件损坏时返回空指针,需调用方检查 + */ FbxNode* get_fbx_root_node(const char* fbx_path); -int load_triangles(fbxsdk::FbxNodeAttribute* attr, std::vector& triangles); +/** + * 从FBX属性提取三角形数据并填充到向量 + * @param attr FBX节点属性指针(需为Mesh类型,非Mesh类型返回0) + * @param triangles 输出三角形数据的向量引用(会自动清空原有数据) + * @return int 成功提取的三角形数量,失败返回-1(如attr为空或非Mesh类型) + * @note 仅处理三角形网格,四边形等多边形会被自动三角化 + */ +int load_triangles(fbxsdk::FbxNodeAttribute* attr, std::vector& triangles); \ No newline at end of file diff --git a/cpp_src/include/tools.h b/cpp_src/include/tools.h index d829ffb..2f88071 100644 --- a/cpp_src/include/tools.h +++ b/cpp_src/include/tools.h @@ -1,5 +1,12 @@ +#include + typedef struct { char* fbx_file; char* out_dir; -} FttContext; \ No newline at end of file + + sqlite3* db; +} FttContext; + + +void create_tables(sqlite3* db); \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index cddae0a..dda9da7 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,7 +1,8 @@ use std::{ffi::CString, os::raw::c_char}; fn main() { - convert_fbx_to_3dtiles("/root/data/绿科-三维视图-{三维}111.fbx", "/root/data/out"); + convert_fbx_to_3dtiles("/root/data/绿科-三维视图-{三维}111.fbx", + "/root/data/out/lk"); } #[repr(C)] @@ -18,7 +19,7 @@ unsafe extern "C" { fn convert_fbx_to_3dtiles(fbx_path: &str, out_dir: &str) { - + let ctx = &FttContext{ fbx_file: CString::new(fbx_path).unwrap().into_raw(), out_dir: CString::new(out_dir).unwrap().into_raw()