Add pure C11 loader (tiny_obj_c) with robust tessellation library#430
Merged
Conversation
A from-scratch C11 reimplementation of tinyobjloader: secure, portable, freestanding-capable, dependency-free, fast, and robust. Not header-only (tiny_obj_c.c + tiny_obj_c.h, plus a separate tobj_tess tessellation library). Highlights: - Dual precision: float (_f) and double (_d) families coexist in one build, generated from a single template via token-pasting. - Freestanding / no-dependency: the core links zero libc symbols (verified with nm under -ffreestanding -DTOBJ_NO_LIBC). Injectable allocator, bundled ASCII->float parser, no math.h in the core or default tessellator. - Robust tessellation (tobj_tess): Newell projection with bbox fallback, magnitude-scaled epsilons, convex fan fast path, and a force-clip backstop that always emits n-2 triangles and never crashes/loops on degenerate, concave, collinear, coincident, non-planar, or self-intersecting input. - Primitives: faces (triangulated), lines, points, and free-form patches (cstype/curv/curv2/surf/vp/parm/trim/hole/end) parsed and retained losslessly. - Full material support: Phong + PBR + 13 texture channels with options, unknown-parameter map, map_Kd-without-Kd default, standalone .mtl API, material resolver callback, and a streaming callback API. - Optional perf behind macros (scalar/single-threaded default): multithreaded two-pass parse (byte-identical to single-threaded), SIMD newline scan (AVX2/SSE2/NEON), mmap + file I/O, arena allocator, fast float. - Security: bounds-checked indices, overflow-safe sizing, configurable caps. Validation (all under ASan + UBSan): 84-file corpus loads with 0 failures; acutest drivers tester_c (12) and tess_tester (15) pass; freestanding driver runs with a custom allocator; MT output is byte-identical to single-threaded; libFuzzer runs find no crashes/leaks. CMake and tests/Makefile integration with a fuzzer entry point. Co-Authored-By: Claude Opus 4.8 <[email protected]>
The corpus_loads test referenced sandbox/*.obj, which are local scratch files not tracked in the repo, so they were absent in the clean CI checkout and failed with TOBJ_ERR_IO. Replace them with tracked models/*.obj files. The pathological-geometry triangulation cases remain covered directly by tests/tess_tester.c. Co-Authored-By: Claude Opus 4.8 <[email protected]>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A from-scratch pure C11 reimplementation of tinyobjloader: secure, portable, freestanding-capable, dependency-free, fast, and robust. Not header-only —
tiny_obj_c.c+tiny_obj_c.h, plus a separate reusable tessellation librarytobj_tess.{c,h}. Carries the C++ feature set over to C11 and adds line/point/free-form-patch primitives.Highlights
_f) and double (_d) families coexist in one build, generated from a single template via token-pasting.nmunder-ffreestanding -DTOBJ_NO_LIBC): no malloc/strtod/fopen/memcpy/sqrt/pthread. Injectable allocator, bundled ASCII→float parser, nomath.hin the core or default tessellator.tobj_tess) — Newell projection with bbox fallback, magnitude-scaled epsilons (fixes the C++ absolute-epsilonarea threshold that is meaningless at the ~8000–14000 coordinate magnitudes insandbox/zh2-ill.obj,sandbox/ill-tri.obj,models/issue-295-trianguation-failure.obj), a convex fan fast path, and a force-clip backstop that always emits n−2 triangles and never crashes or loops on degenerate, concave, collinear, coincident, non-planar, or self-intersecting input.l), points (p), and free-form patches (cstype/curv/curv2/surf/vp/parm/trim/hole/end) parsed and retained losslessly (no NURBS evaluation).map_Kd-without-Kddefault, standalone.mtlAPI, material-resolver callback (replaces the virtualMaterialReader), and a streaming callback API.Validation (all under ASan + UBSan)
models/+sandbox/) loads with 0 failures, 1.45M triangles, consistent index counts.tests/tess_tester.c(15 unit/property tests incl. pathological classes, area preservation, determinism) andtests/tester_c.c(12 loader tests: corpus, both precisions, triangulation, BOM/CRLF, vertex colors, lines/points, MTL, garbage) — all pass.-Wall -Wextra -Wpedantic -Wshadowclean (default and all-features).Build / test
Added options in
CMakeLists.txt:TINYOBJLOADER_BUILD_C_LIBRARY(ON),TINYOBJLOADER_C_ENABLE_FILE_IO/MMAP/SIMD/MULTITHREADING,TINYOBJLOADER_C_BUILD_TESTS, plus afuzz_tobj_ctarget underLIB_FUZZING_ENGINE.Known limitation
In the multithreaded path,
curv2→vpindex resolution can differ from single-threaded only whenvplines have inconsistent component counts (a pathological free-form case); it does not affect the corpus or normal use. A reservedtobj_mathopshook is currently unused (the default tessellator needs nosqrt).🤖 Generated with Claude Code