From 32c449b0a226db05723d6423bbb18feb068b291f Mon Sep 17 00:00:00 2001 From: Warren Moore Date: Sat, 7 Feb 2026 15:50:16 -0800 Subject: [PATCH] Implemented KHR_gaussian_splatting extension --- cgltf.h | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++ cgltf_write.h | 18 +++++++++++++- 2 files changed, 83 insertions(+), 1 deletion(-) diff --git a/cgltf.h b/cgltf.h index 316a11d..c9d371a 100644 --- a/cgltf.h +++ b/cgltf.h @@ -598,6 +598,16 @@ typedef struct cgltf_draco_mesh_compression { cgltf_size attributes_count; } cgltf_draco_mesh_compression; +typedef struct cgltf_gaussian_splatting { + char* kernel; + char* color_space; + char* sorting_method; + char* projection; + cgltf_extras extras; + cgltf_size extensions_count; + cgltf_extension* extensions; +} cgltf_gaussian_splatting; + typedef struct cgltf_mesh_gpu_instancing { cgltf_attribute* attributes; cgltf_size attributes_count; @@ -616,6 +626,8 @@ typedef struct cgltf_primitive { cgltf_draco_mesh_compression draco_mesh_compression; cgltf_material_mapping* mappings; cgltf_size mappings_count; + cgltf_bool has_gaussian_splatting; + cgltf_gaussian_splatting gaussian_splatting; cgltf_size extensions_count; cgltf_extension* extensions; } cgltf_primitive; @@ -3139,6 +3151,55 @@ static int cgltf_parse_json_draco_mesh_compression(cgltf_options* options, jsmnt return i; } +static int cgltf_parse_json_gaussian_splatting(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_gaussian_splatting* out_gaussian_splatting) +{ + CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); + + int size = tokens[i].size; + ++i; + + for (int j = 0; j < size; ++j) + { + CGLTF_CHECK_KEY(tokens[i]); + + if (cgltf_json_strcmp(tokens + i, json_chunk, "kernel") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_gaussian_splatting->kernel); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "colorSpace") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_gaussian_splatting->color_space); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "sortingMethod") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_gaussian_splatting->sorting_method); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "projection") == 0) + { + i = cgltf_parse_json_string(options, tokens, i + 1, json_chunk, &out_gaussian_splatting->projection); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extras") == 0) + { + i = cgltf_parse_json_extras(options, tokens, i + 1, json_chunk, &out_gaussian_splatting->extras); + } + else if (cgltf_json_strcmp(tokens + i, json_chunk, "extensions") == 0) + { + i = cgltf_parse_json_unprocessed_extensions(options, tokens, i, json_chunk, &out_gaussian_splatting->extensions_count, &out_gaussian_splatting->extensions); + } + else + { + i = cgltf_skip_json(tokens, i+1); + } + + if (i < 0) + { + return i; + } + } + + return i; +} + static int cgltf_parse_json_mesh_gpu_instancing(cgltf_options* options, jsmntok_t const* tokens, int i, const uint8_t* json_chunk, cgltf_mesh_gpu_instancing* out_mesh_gpu_instancing) { CGLTF_CHECK_TOKTYPE(tokens[i], JSMN_OBJECT); @@ -3410,6 +3471,11 @@ static int cgltf_parse_json_primitive(cgltf_options* options, jsmntok_t const* t out_prim->has_draco_mesh_compression = 1; i = cgltf_parse_json_draco_mesh_compression(options, tokens, i + 1, json_chunk, &out_prim->draco_mesh_compression); } + else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_gaussian_splatting") == 0) + { + out_prim->has_gaussian_splatting = 1; + i = cgltf_parse_json_gaussian_splatting(options, tokens, i + 1, json_chunk, &out_prim->gaussian_splatting); + } else if (cgltf_json_strcmp(tokens+i, json_chunk, "KHR_materials_variants") == 0) { i = cgltf_parse_json_material_mappings(options, tokens, i + 1, json_chunk, out_prim); diff --git a/cgltf_write.h b/cgltf_write.h index 4c060da..9f3b937 100644 --- a/cgltf_write.h +++ b/cgltf_write.h @@ -89,6 +89,7 @@ cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size si #define CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION (1 << 17) #define CGLTF_EXTENSION_FLAG_TEXTURE_WEBP (1 << 18) #define CGLTF_EXTENSION_FLAG_MATERIALS_DIFFUSE_TRANSMISSION (1 << 19) +#define CGLTF_EXTENSION_FLAG_GAUSSIAN_SPLATTING (1 << 20) typedef struct { char* buffer; @@ -499,7 +500,7 @@ static void cgltf_write_primitive(cgltf_write_context* context, const cgltf_prim } cgltf_write_extras(context, &prim->extras); - if (prim->has_draco_mesh_compression || prim->mappings_count > 0) + if (prim->has_draco_mesh_compression || prim->has_gaussian_splatting || prim->mappings_count > 0) { cgltf_write_line(context, "\"extensions\": {"); @@ -523,6 +524,18 @@ static void cgltf_write_primitive(cgltf_write_context* context, const cgltf_prim cgltf_write_line(context, "}"); } + if (prim->has_gaussian_splatting) + { + context->extension_flags |= CGLTF_EXTENSION_FLAG_GAUSSIAN_SPLATTING; + cgltf_write_line(context, "\"KHR_gaussian_splatting\": {"); + cgltf_write_strprop(context, "kernel", prim->gaussian_splatting.kernel); + cgltf_write_strprop(context, "colorSpace", prim->gaussian_splatting.color_space); + cgltf_write_strprop(context, "sortingMethod", prim->gaussian_splatting.sorting_method); + cgltf_write_strprop(context, "projection", prim->gaussian_splatting.projection); + cgltf_write_extras(context, &prim->gaussian_splatting.extras); + cgltf_write_line(context, "}"); + } + if (prim->mappings_count > 0) { context->extension_flags |= CGLTF_EXTENSION_FLAG_MATERIALS_VARIANTS; @@ -1329,6 +1342,9 @@ static void cgltf_write_extensions(cgltf_write_context* context, uint32_t extens if (extension_flags & CGLTF_EXTENSION_FLAG_MATERIALS_DISPERSION) { cgltf_write_stritem(context, "KHR_materials_dispersion"); } + if (extension_flags & CGLTF_EXTENSION_FLAG_GAUSSIAN_SPLATTING) { + cgltf_write_stritem(context, "KHR_gaussian_splatting"); + } } cgltf_size cgltf_write(const cgltf_options* options, char* buffer, cgltf_size size, const cgltf_data* data)